Имя:    Пароль:      Помнить меня       
Unsorted   ~  Software  ~  Development and Design  ~  Выделение памяти в Linux программирование на С
Crazy_Nat
Сообщение  27 Май 2011, 0:32  Ссылка : Ответить с цитатой
Возраст: 36 Пол: Мужской 
C нами с 14.01.2007
Репутация: 89.7

Буду рад если мне кто нибудь сможет помочь!
Есть системный вызов brk() который устанавливает новое значения брейк адреса. Есть системный вызов sbrk() который позволяет увеличивать или уменьшать брейк адрес (я так понял что это надстройка над brk()). Чтобы получить текущее значение брейк адреса нужно сделать вызов sbrk(0), т.е. с аргументом 0. С этим все понятно, разобрался и исвоился.
Не могу понять собственно говоря одного: по мануалу sbrk(0) возвращает текущий брейк-адрес, который следует после последнего адреса сегмента данных.
Цитата:
brk() and sbrk() change the location of the program break, which defines the end of the process's data segment (i.e., the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.

Так же есть еще способ получения конечных адреса сегментов процесса:
Цитата:

etext, edata, end - end of program segments

SYNOPSIS top

extern etext;
extern edata;
extern end;

DESCRIPTION top

The addresses of these symbols indicate the end of various program segments:

etext This is the first address past the end of the text segment (the program
code).

edata This is the first address past the end of the initialized data segment.

end This is the first address past the end of the uninitialized data
segment (also known as the BSS segment).

следовательно в только что запущенном процессе sbrk(0) и &end должны совпадать? Но у меня не совпадают. Кроме того если брейк-адрес указывает на конец сегмента данных, то, по идее, можно обращаться по всем адресам до него. Но при попытке обращения выдает ошибку сегментации.
пример программы:
#include <unistd>
#include <stdio>

extern etext;
extern edata;
extern end;

int main()
{
	void *e, *s, *t, *d;

	d = &edata;
	t = &etext;
	e = &end;
	s = sbrk(0);
	printf("edata\t%p\netext\t%p\nend\t%p\nsbrk\t%p\n",d,t,e,s);
	printf("%p\t%d\n",s,*((int *) s - 1));	
	return 0;
}

результат выполнения:
edata	0x804a018
etext	0x8048538
end	0x804a020
sbrk	0x95e1000
Segmentation fault

В интернете так и не нашел ответы на эти вопросы. Находил что системный вызов sbrk() может использовать стандартная библиотека ввода вывода. Писал код без неё и проверял отладчиком - результат тот же.
Собственно вопросы:
1. Почему не совпадают end и sbrk(0)?
2. Почему если sbrk(0) возвращает указатель на первый адрес после конца сегмента неинициализированных данных, нельзя обратиться к памяти адресами раньше?
Извините если коряво написал и объяснил то что хочу понять Юзер
В начало
Профиль : Личное Сообщение
Рыся
Сообщение  27 Май 2011, 10:23  Ссылка : Ответить с цитатой
Пол: Мужской  Доверенный пользователь
C нами с 15.04.2005
Репутация: 133.2

Дело в том, что "process data segment" это не обязательно сегмент данных Вашей программы. Процесс это более общее понятие. В адресное пространство процесса отображаются так же динамические библиотеки и другая служебная и не очень информация. То есть карта памяти может выглядеть так:
myprogram
  .etext
  .edata
  .bss
library1.so
  .etext
  .edata
  .eexport
  .bss
libraryN.so
  .etext
  .eexport
sbrk() -->

sbrk() соответственно будет указывать на конец сегмента последней библиотеки (или "чего то") отображённой в память процесса. А может просто так хочется левой пятке менеджера памяти linux - например из-за выравнивания или каких-то ограничений с адресацией страниц. Стандарт не запрещает и не регламентирует конкретный адрес. Он гарантирует, что указатель находится ЗА сегментом данных, но насколько далеко — неизвестно.
Цитата:
At the start of program execution, the program break will be somewhere near &end (perhaps at the start of the following page). However, the break will change as memory is allocated via brk(2) or malloc(3). Use sbrk(2) with an argument of zero to find the current value of the program break.


Маленькая программка для демонстрации sbrk().
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/time.h
#include sys/resource.h

extern char etext, edata, end; /* The symbols must have some type,
                                          or "gcc -Wall" complains */

int
main(int argc, char *argv[])
{
  struct rlimit rl;

  int result;

  result = getrlimit(RLIMIT_DATA, &rl);

  printf("RLimit (%i):\n", result);
  printf("  soft   %lu\n", rl.rlim_cur);
  printf("  hard   %lu\n", rl.rlim_max);

  printf("First address past:\n");
  printf("    program text (etext)      %p\n", &etext);
  printf("    initialized data (edata)  %p\n", &edata);
  printf("    uninitialized data (end)  %p\n", &end);

  void *smem_begin;
  void *smem_end;
  const intptr_t smem_size = 1024 * 1024; /* 1 MB space */

  printf("    sbrk(0) initial           %p\n", sbrk(0));

  smem_begin = sbrk(smem_size); /* try to alloc */
  printf("    sbrk(0) (+1MB) begin      %p\n", smem_begin);

  smem_end = sbrk(0);
  printf("    sbrk(0) (+1MB) end        %p\n", smem_end);

  /* fill allocated memory (no segfault?) */
  memset(smem_begin, 0, smem_size);

  printf("Press any key to continue...\n");
  getchar();

  exit(EXIT_SUCCESS);
}

lynxy@vmubuntu:~$ gcc -Wall a.c
lynxy@vmubuntu:~$ ./a.out 
RLimit (0):
  soft   18446744073709551615
  hard   18446744073709551615
First address past:
    program text (etext)      0x400906
    initialized data (edata)  0x601050
    uninitialized data (end)  0x601060
    sbrk(0) initial           0x1e01000
    sbrk(0) (+1MB) begin      0x1e01000
    sbrk(0) (+1MB) end        0x1f01000
Press any key to continue...
Видим что 1 МБ памяти таки выделяется: 0x1f01000-0x1e01000 = 0x100000. А нам не всё ли равно, по каким он адресам?

Карта памяти процесса a.out:
lynxy@vmubuntu:~$ pmap -x `ps -a | grep a.out | awk '{print $1}'`
10448:   ./a.out
Address           Kbytes     RSS   Dirty Mode   Mapping
0000000000400000       0       4       0 r-x--  a.out
0000000000600000       0       4       4 r----  a.out
0000000000601000       0       4       4 rw---  a.out
0000000001e01000       0    1024    1024 rw---    [ anon ]
00007fdc2dd0f000       0     268       0 r-x--  libc-2.12.1.so
00007fdc2de89000       0       0       0 -----  libc-2.12.1.so
00007fdc2e088000       0      16      16 r----  libc-2.12.1.so
00007fdc2e08c000       0       4       4 rw---  libc-2.12.1.so
00007fdc2e08d000       0      12      12 rw---    [ anon ]
00007fdc2e092000       0     108       0 r-x--  ld-2.12.1.so
00007fdc2e290000       0      12      12 rw---    [ anon ]
00007fdc2e2ae000       0      12      12 rw---    [ anon ]
00007fdc2e2b2000       0       4       4 r----  ld-2.12.1.so
00007fdc2e2b3000       0       4       4 rw---  ld-2.12.1.so
00007fdc2e2b4000       0       4       4 rw---    [ anon ]
00007fffb9247000       0      12      12 rw---    [ stack ]
00007fffb92f7000       0       4       0 r-x--    [ anon ]
ffffffffff600000       0       0       0 r-x--    [ anon ]
----------------  ------  ------  ------
total kB            4940    1496    1112
Из неё видно, что так просто хочет левая пятка менеджера памяти (0000000001e01000 0 1024 1024 rw—- [ anon ]). Ничего конкретного по его работе я сказать не могу, никогда не интересовался, но видимо так как он это делает и есть добро Смайлик

Но у меня один вопрос: нафига sbrk() (который уже вынесли из стандарта POSIX) если есть malloc/mmap и прочая?

P.S. Насортедовский тег code почему-то режет конструкции #include stdio.h до #include stdio и #include sys/blah.h до #include sys — надо разбираться. В тексте программы я убрал угловые скобки в #include.

_____________________________
Время не существует, у него нет физического носителя в природе. Его выдумал человек, чтобы измерять скорость.
В начало
Профиль : Фотоальбом : Блог : Личное Сообщение : E-mail : JabberID
Crazy_Nat
Сообщение  27 Май 2011, 11:14  Ссылка : Ответить с цитатой
Возраст: 36 Пол: Мужской 
C нами с 14.01.2007
Репутация: 89.7

Рыся, спасибо за развернутый ответ. Вроде понятно.
А можно пожалуйста источник цитаты, на такое нигде не наталкивался, поэтому и зашел в тупик...
Рыся писал(а):
Цитата:
At the start of program execution, the program break will be somewhere near &end (perhaps at the start of the following page). However, the break will change as memory is allocated via brk(2) or malloc(3). Use sbrk(2) with an argument of zero to find the current value of the program break.

Рыся писал(а):
Но у меня один вопрос: нафига sbrk() (который уже вынесли из стандарта POSIX) если есть malloc/mmap и прочая?

Пишу диплом по алгоритмам динамического выделению памяти и ее фрагментации. malloc() также использует sbrk() и mmap() внутри себя. По сути malloc это обретка sbrk. С выделенной областью разобрался, а вот было интересно и непонятно что находится до него...
В линуксах еще молодой и неопытный Юзер
В начало
Профиль : Личное Сообщение
Рыся
Сообщение  27 Май 2011, 11:39  Ссылка : Ответить с цитатой
Пол: Мужской  Доверенный пользователь
C нами с 15.04.2005
Репутация: 133.2

Crazy_Nat, http://www.kernel.org/doc/man-pages/online/pages/man3/end.3.html, в секции NOTES.

_____________________________
Время не существует, у него нет физического носителя в природе. Его выдумал человек, чтобы измерять скорость.
В начало
Профиль : Фотоальбом : Блог : Личное Сообщение : E-mail : JabberID
Crazy_Nat
Сообщение  27 Май 2011, 12:06  Ссылка : Ответить с цитатой
Возраст: 36 Пол: Мужской 
C нами с 14.01.2007
Репутация: 89.7

Рыся, Спасибо большое, при чтении не обратил внимания на это "ключевое" предложение, извиняюсь за невнимательность.
В начало
Профиль : Личное Сообщение
Показать сообщения:   

Unsorted   ~  Software  ~  Development and Design  ~  Выделение памяти в Linux

Ответить на тему

Перейти:  





Powered by phpBB   © Unsorted Team  support@unsorted.me  promo@unsorted.me  Полезные скрипты