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

Я разбираю исполняемый файл:

(gdb) disas main
Dump of assembler code for function main:
0x004012d0 <main+0>:    push   %ebp
0x004012d1 <main+1>:    mov    %esp,%ebp
...

Каждый раз, когда адрес памяти одинаков: 0x004012d0.

Не адрес динамически назначается оператором памяти?

UPDATE

Теперь я вижу это виртуальное пространство, и оно может быть рандомизировано на некоторых платформах.

Может кто-нибудь опубликовать дамп gdb, который изменится?

Ответ 1

Это зависит от ОС. В большинстве случаев адрес двоичного файла остается прежним. Это важно для использования ошибок манипуляции памятью, таких как переполнение буфера. Адрес связанных библиотек под Linux всегда будет отличаться из-за ASLR. В Windows Vista и Windows 7 пространство двоичной виртуальной памяти также рандомизируется каждый раз, когда оно выполняется, поэтому адрес функции будет отличаться для каждого прогона.

Ответ 2

Да и нет. Физическая память выделяется ОС, и только ОС знает, где ваша программа находится в физической ОЗУ. Ваша программа видит только виртуальный адрес, который всегда будет таким же, если все загружается в том же порядке.

Ответ 3

Исполняемое перемещение

Некоторые исполняемые файлы устанавливаются так, чтобы они всегда загружались по одному и тому же адресу. Некоторые из них настроены так, что они "перемещаются". Опция, управляющая этим в компоновщике Visual Studio, называется /FIXED. Даже такие исполняемые файлы чаще всего загружаются по предпочитаемому адресу. Более новая ОС (Win7, Vista) рандомизирует адрес загрузки для некоторых исполняемых файлов для повышения безопасности (процесс атаки, загруженный по неизвестному адресу, сложнее) - это называется ASLR. Примечание. Даже исполняемый файл, отмеченный как /FIXED: NO, не считается подходящим для ASLR. Разработчику необходимо явно разрешить ASLR для исполняемого файла.

Виртуальное адресное пространство

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

Ответ 4

Я думаю, что проблема здесь (по крайней мере, в Linux) может быть gdb, пытающейся помочь, из документов:

установить запрет-рандомизацию

установить запрет-рандомизацию на

Эта опция (включена по умолчанию в gdb) отключит собственную рандомизацию виртуального адресного пространства запущенной программы. Эта опция полезна для многократной отладки сессий, чтобы сделать исполнение более воспроизводимым и адреса памяти повторно использовать отладки.

Эта функция реализована только на gnu/Linux. Вы можете получить такое же поведение, используя

         (gdb) set exec-wrapper setarch `uname -m` -R

http://sourceware.org/gdb/current/onlinedocs/gdb/Starting.html

UPDATE: теперь я проверил это, и это похоже на меня (под управлением Linux 2.6.28). Скомпилируйте простую программу Hello World и запустите gdb без аргументов командной строки (мы не хотим загружать программу, прежде чем переопределять параметр запрета-рандомизации), а затем введите:

(gdb) set disable-randomization off
(gdb) file ./a.out
(gdb) break main
(gdb) run
(gdb) disas printf

Адрес printf отличается при каждом запуске программы.

Ответ 5

Это виртуальный адрес. Физический адрес известен ОС, но каждый процесс имеет собственное виртуальное адресное пространство. Перемещаемое изображение, вероятно, будет получать одно и то же отображение каждый раз, особенно основной исполняемый файл. Но это не гарантировано. Например, DLL. DLL могут загружаться в другом порядке, что приводит к разным виртуальным адресам между прогонами, поскольку при загрузке DLL 1 DLL 2 не может быть загружена в этот виртуальный адрес и должен получить свой собственный адрес.

Ответ 6

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

Ответ 7

Это терминология от компьютерной безопасности. В прошлом это был фиксированный адрес (< 1996, в соответствии с LKML, но только недавно этот исполняемый файл начал компилироваться как перемещаемый, чтобы реализовать ASLR (но гораздо дольше, все библиотеки были скомпилированы как перемещаемые, так что библиотеки могут быть перезагружены в разные адреса, если необходимо - читать динамическое перемещение, но из-за порядка загрузки эти основные syscall API обычно загружаются в фиксированный адрес.) Даже сегодня

выполняя gdb/bin/ls и следуя "run", u обнаружит, что адрес по умолчанию не изменяется:

(gdb) разобрать __open Дамп ассемблерного кода для открытия функции:  0xb7f017f0 < +0 > : cmpl $0x0,% gs: 0xc  0xb7f017f8 < +8 > : jne 0xb7f0181c

В любом случае ASLR начинается с PaX - прочитал wiki, он подробно рассмотрел требования реализации ASLR.

Почему ASLR? Чтобы предотвратить 2 типа атаки: http://en.wikipedia.org/wiki/Return-to-libc_attack и http://en.wikipedia.org/wiki/Return-oriented_programming, потому что обе атаки предполагали вашу область кода, если они зафиксированы в памяти.

Ответ 8

Почему OS выбирает другой адрес?

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