C макет памяти программы - PullRequest
2 голосов
/ 30 марта 2020

Я знакомлюсь с C и перебираю схему памяти программы. Мне удалось получить некоторую информацию о том, где переменные go внутри памяти, но у меня все еще есть некоторые, которые остаются для меня неясными. * 10 в качестве хоста

Допустим, у меня есть следующая программа:

int foo(); // (??)
void point(void* p); // (??)
int data1; // bss segment
int data2 = 3; // data segment
int main(){
  char str[3] = {'a','b','c'}; // text segment(??)
  char *str1 = "word"; // str1 - stack, *str1 = 'w' - text segment (??)

  point(&data1); // call stack

  return 0;
}

void point(void* p){

 long dist1 = (size_t)&data2 - (size_t)p; // call stack - inside point's AF: dist1, p
 printf("%ld\n", dist1); /* is a long integer generally enough to hold addresses (or difference of 
                           addresses). is it legal to calculate differences of addresses of different 
                           segments? */  

}

int foo(){
  return 0;
}

Мне нужна помощь с вопросами, добавленными в комментарии, и, возможно, подтверждение за то, что я уже сделал.

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 30 марта 2020

Давайте скомпилируем вашу программу с gcc -O0 program.c -o program, затем разберем ее с objdump -D program. Для удобства я пошел дальше и сделал это ( AT & T синтаксис , Intel синтаксис ). Вы можете видеть, что foo находится в разделе .text, и он был заменен заглушкой, которая по сути ничего не делает и просто выходит из функции. Поскольку point было определено после объявления, оно эквивалентно определению прямо в объявлении, а также находится в разделе .text с фактической реализацией. Вы можете видеть, что вы правы, что data1 находится в .bss и что data2 находится в .data. Что касается массива {'a', 'b', 'c'} в main, вы можете видеть, что он немного странный.

 6c1:   c6 45 f5 61             mov    BYTE PTR [rbp-0xb],0x61
 6c5:   c6 45 f6 62             mov    BYTE PTR [rbp-0xa],0x62
 6c9:   c6 45 f7 63             mov    BYTE PTR [rbp-0x9],0x63

Значения фактически загружаются одно за другим в массив, поэтому я думаю, вы могли бы сказать, что он хранится в разделе .text. Вы можете заметить, что строка "word" на самом деле не находится в разборке. Однако, если вы сделаете readelf -x .rodata program, вы найдете его в разделе .rodata.

Hex dump of section '.rodata':
  0x000007d0 01000200 776f7264 00256c64 0a00     ....word.%ld..

Вы также можете видеть, что, хотя переменные не указаны по имени, они расположены на стековый фрейм функции , заданный смещением базового указателя rbp. Для 64-разрядных двоичных файлов адрес составляет 8 байтов, а для 32-разрядных двоичных файлов адрес составляет 4 байта.

1 голос
/ 30 марта 2020

Это полностью определяется реализацией.

Что касается адресов, большинство систем предоставляют intptr_t и uintptr_t, которые являются целочисленными типами, подходящими для хранения адреса. Вы можете делать с ним все, что угодно, поскольку это просто целое число, но если вы приведете его обратно к указателю, его достоверность зависит от вас (т.е. приведение к intptr_t и возврат в порядке, точно так же, как выполнение эквивалента правильной арифметики указателя c, но не намного).

Существует также ptrdiff_t, который содержит разность указателей; обычно это то же самое, что и intptr_t, но всегда доступно. Тем не менее, вы можете сделать что-нибудь с ним, так как это целое число; смысл операции зависит от вас. Но вычитание самих указателей допустимо только в том случае, если они указывают на разные элементы одного и того же массива. 1

Относительно разделов, функциональных тел go в .text или эквивалентный; Заголовки функций не go нигде сами по себе, но если функция экспортируется (по умолчанию Linux), компоновщик добавляет необходимые данные в программный файл, который использует динамический компоновщик / загрузчик c для построения реального таблицы прыжков. Локальные переменные go в стеке потоков. Константы могут оказаться в data, rodata или даже text (особенно на x64). bss - это несохраненный раздел, т. Е. В файле присутствует только его описание, но при запуске программы он выделяется и (обычно) заполняется нулями.

...