2010-09-13 2 views
4

Я написал эту небольшую программу сегодня, и я был потрясен результатами. Вот программаКак основная функция всегда загружается по тому же адресу, в то время как переменные имеют разный адрес большую часть времени?

 

int main(int argc, char **argv) 
{ 
int a; 
printf("\n\tMain is located at: %p and the variable a is located at address: %p",main,&a); 
return 0; 
} 

на моей машине основная функция всегда загружается по адресу «0x80483d4» и адрес переменной продолжает варьирования Как же это происходит? Я читал в операционных системах, что в рамках схемы виртуализации ОС продолжает перемещать адрес инструкций. Так почему же каждый раз, когда я запускаю эту программу, основная часть загружается по тому же адресу?

спасибо заранее, ребята.

+4

http://xkcd.com/221/ – pmg

+0

Эта ссылка может быть полезно: http://en.wikipedia.org/wiki/Address_space_layout_randomization. Я думаю, что адрес точки входа не рандомизирован. – PeterK

+0

@pmg: +1 для этого xkcd linky ...:) – t0mm13b

ответ

7

В системах ELF, таких как Linux, адреса, на которых загружаются сегменты обычных исполняемых файлов (ELF type ET_EXEC), во время компиляции. Общие объекты (тип ELF ET_DYN), такие как библиотеки, построены независимо от положения, причем их сегменты загружаются в любом месте адресного пространства (возможно, с некоторыми ограничениями на некоторые архитектуры). Можно создать исполняемые файлы таким образом, чтобы они были фактически ET_DYN - они известны как «независимые от позиции исполняемые файлы» (PIE), но не являются общепринятой техникой.

Что вы видите, так это то, что ваша функция main() находится в текстовом сегменте фиксированного адреса вашего скомпилированного исполняемого файла. Попробуйте также распечатать адрес библиотечной функции, такой как printf(), после ее определения через dlsym() - если ваша система поддерживает и включает рандомизацию размещения адресного пространства (ASLR), тогда вы должны увидеть адрес изменения этой функции от запуска до запуска вашей программы. (Если вы просто печатаете адрес библиотечной функции, помещая ссылку непосредственно в свой код, то на самом деле вы можете получить адрес батута функции поиска процедуры (PLT), который статически компилируется по фиксированному адресу в исполняемом файле .)

Переменная, которую вы видите, меняет адрес из run-to-run, потому что это автоматическая переменная, созданная в стеке, а не в статически выделенной памяти. В зависимости от ОС и версии адрес базы стека может переходить от запуска к run даже без ASLR. Если вы переместите объявление переменной глобально вне своей функции, вы увидите, что оно ведет себя так же, как и ваша функция main().

Вот полный пример - компилировать с чем-то вроде gcc -o example example.c -dl:

#include <stdio.h> 
#include <dlfcn.h> 

int a = 0; 

int main(int argc, char **argv) 
{ 
    int b = 0; 
    void *handle = dlopen(NULL, RTLD_LAZY); 
    printf("&main: %p; &a: %p\n", &main, &a); 
    printf("&printf: %p; &b: %p\n", dlsym(handle, "printf"), &b); 
    return 0; 
} 
+0

Да, да! Ничего себе, ты многое очистил. Один вопрос по-прежнему остается в моем сознании, но предположим, что после компиляции функция func() должна быть загружена по адресу «X» в памяти, теперь, что, если перед исполнением это место «X» должно было быть занято каким-то другим программа? Что произойдет в этом случае? Будет ли перенесена программа? Должна ли она ждать? – user446236

+0

В большинстве современных ОС ядро ​​предоставляет каждому процессу собственное виртуальное адресное пространство. Что касается каждого отдельного процесса, он имеет весь диапазон адресов, доступных для пользовательского контекста. Это предотвращает случайное столкновение, которое вы описываете, а также предотвращает вредоносное взаимодействие программ друг с другом. И если вам нравится мой ответ, пожалуйста, поддержите и примите :-). – llasram

+0

О да! Как я мог забыть об этом? HAHAHAHAHA благодарит много людей, которых вы прояснили каждый дюйм сомнения! Реквизит! – user446236

0

main(...) - это исходный код начальной загрузки, в котором операционная система загружается и выполняется каждый раз. Посмотрите на CRT (C Runtime Library), которая будет содержать код для этого в зависимости от вашего компилятора.

Другое дело иметь в виду, что адрес - я бы не стал беспокоиться об этом слишком много, пока работает код C. Это шаблон случайности, по заказу зависит от ряда факторов, таких как загрузка ОС, используемые драйверы, аппаратное обеспечение, программное обеспечение AntiVirus и т. Д.

Кроме того, в отношении кода, если вы добавляете статические переменные, функции , указатели, которые изменят компоновку двоичного кода, и еще важно, адреса тех символов, которые загружаются во время выполнения, будут разными.

+0

Привет! Я добавил еще одну функцию, определенную пользователем, в одну и ту же программу, и она также загружается по одному и тому же адресу памяти между последовательными запусками программы! О, и я выполнил программу более 4-5 раз. Адрес функций меняется после перекомпиляции кода, но после этого он придерживается нового значения! Странно, не так ли? – user446236

+1

CRT интересен, но здесь не уместен - 'main()' определен в предоставленном коде. – llasram

 Смежные вопросы

  • Нет связанных вопросов^_^