|
|
Возраст: 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) возвращает указатель на первый адрес после конца сегмента неинициализированных данных, нельзя обратиться к памяти адресами раньше?
Извините если коряво написал и объяснил то что хочу понять
|
|
|
|
|
|
|
|
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.
|
_____________________________ Время не существует, у него нет физического носителя в природе. Его выдумал человек, чтобы измерять скорость.
|
|
|
|
|
|
|
Возраст: 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. С выделенной областью разобрался, а вот было интересно и непонятно что находится до него...
В линуксах еще молодой и неопытный
|
|
|
|
|
|
|
|
C нами с 15.04.2005 Репутация: 133.2
|
|
|
|
|
|
|
|
Возраст: 36 C нами с 14.01.2007 Репутация: 89.7
|
|
Рыся, Спасибо большое, при чтении не обратил внимания на это "ключевое" предложение, извиняюсь за невнимательность.
|
|
|
|
|
|
|
|
|