В каком сегменте памяти мы найдем адрес памяти функции в C - PullRequest
2 голосов
/ 22 апреля 2020

Указатели на функции указывают адрес функции в C. Это означает, что функция имеет адрес памяти, и она будет частью любого сегмента памяти. Я только что напечатал адрес функции и указывает на сегмент кода. Все ли функции, написанные в C, имеют свои адреса в сегменте кода?

#include <stdio.h>

void func()
{
        printf("hi!!!\n");
}

int main()
{
        void (*fptr)();
        fptr = func;
        printf("fptr pointing func addr : %p and &fptr : %p\n", fptr, &fptr);
        fptr();
        while (1) {
                sleep(1); /* Sleep for accessing procfs of the process */
        }
        return 0;
}

Вывод программы:

[revarath@bgl-vms-vm0251 basic]$ ./a.out &
[1] 20168
[revarath@bgl-vms-vm0251 basic]$ fptr pointing func addr : 0x4005ad and &fptr : 0x7fff301e6b80
hi!!!
c = 10

Поиск PID для доступа к procfs :

[revarath@bgl-vms-vm0251 basic]$ ps -ef | grep a.out
revarath 20168 24339  0 04:55 pts/2    00:00:00 ./a.out
revarath 20180 24339  0 04:56 pts/2    00:00:00 grep --color=auto a.out

Вывод карты памяти:

[revarath@bgl-vms-vm0251 basic]$ cat /proc/20168/maps
00400000-00401000 r-xp 00000000 00:2c 124964755                          /ws/revarath-bgl/backup/tests/basic/a.out
00600000-00601000 r--p 00000000 00:2c 124964755                          /ws/revarath-bgl/backup/tests/basic/a.out
00601000-00602000 rw-p 00001000 00:2c 124964755                          /ws/revarath-bgl/backup/tests/basic/a.out
.......
7fff301c8000-7fff301e9000 rw-p 00000000 00:00 0                          [stack]

Мое веселье c адрес: 0x4005ad лежит в памяти регион 00400000-00401000

Информация о моем процессоре : многоядерный Intel

[revarath@bgl-vms-vm0251 basic]$ lscpu
Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                8

Компилятор:

gcc
gcc version 4.8.5 20150623 (Red Hat 4.8.5-36)

Правильно ли говорить, что адрес памяти функции лежит в OR или указывает на сегмент кода?

1 Ответ

2 голосов
/ 22 апреля 2020

Здесь можно найти больше ответов на юридические вопросы (например, не полагайтесь на системные реализации в вашем коде и смотрите отказ от ответственности ниже), но в основном да, вот как это работает.

Все скомпилированный код из вашей программы, включая функцию, которую вы проиллюстрировали, является частью сегмента кода (также смущенно известного как «текстовый» сегмент) в результирующем двоичном изображении. Загрузчик ОС разделит эти байты скомпилированного кода в этом сегменте памяти в процессе, и если вы таким образом берете адрес функции c, вы увидите соответствующий код, находящийся где-то в этом сегменте. То же самое будет верно для main, et c.


То, как скомпилированная программа попадает в память и исполняется, намного менее волшебно, чем может показаться. Если оставить в стороне механизмы безопасности современной ОС, например, c, это выглядит примерно так:

  1. Toolchain превращает весь ваш код C в поток исполняемых байтов. Каждая скомпилированная функция обязательно начинается с определенного смещения в этот поток байтов.
  2. «Образ» (исполняемый файл) содержит в себе различные сегменты: сегмент кода, набор глобальных переменных с их инициализированными значениями, сегмент , указывающий на некоторые изначально нулевые значения, которые должны появиться при запуске программы, но которые не должны быть явно включены в изображение, и т. Д. c.
  3. Загрузчик в ОС разбирает файлы изображений и отбрасывает различные части в память так, как он хочет, с помощью соответствующих флагов исполняемого файла / чтения / записи, исправляет ссылки на stati c и затем переходит управление первым байтом вашей функции main (посредством скрытого от вас C материала времени выполнения).

Когда вы получаете адрес своей функции, там нет маги c, это указатель на первый байт скомпилированных инструкций для этой функции.

Профессиональная разработка программного обеспечения Отказ от ответственности Как видно из комментариев к этому ответу и вопросу, в реальном диком мире существует множество вариантов работы компоновщиков и загрузчиков; Есть системы, которые на самом деле не делают это таким образом. Конечно, вы бы никогда не написали широко переносимый код C, который делал бы предположения о сегментах памяти. Но в педагогических целях, если вы пользуетесь одной из знаменитых традиционных настольных ОС, она * squints * в основном работает более или менее так, как вы себе представляете. (Если вы сможете найти старую копию «Современных операционных систем» Таненбаума, даже старое первое издание, она осветит множество, казалось бы, непрозрачных тем в этой вене.)

...