2013-07-15 3 views
-1

Я только начал сборку, и я нашел эти инструкции и подобные одни все более кусков кода:Почему мы делаем это с указателем стека?

sub esp , something 
mov esp, dword ptr [esp + something] 

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

+0

Ваш пример выглядит несколько необычным, но эта ссылка объяснит установку фрейма стека: http://en.wikibooks.org/wiki/X86_Disassembly/Functions_and_Stack_Frames – lurker

+0

Также смотрите: http://stackoverflow.com/questions/3699283/ то, что-это-стек-кадр-в-сборке – lurker

ответ

0

Выглядит Intel x86 с первого взгляда. «Кое-что» обычно представляет собой общую длину всех локальных (стековых распределенных) переменных, если это появляется в начале подпрограммы сборки. Так как стек растет вниз, то есть к более низким адресам, это резервирует пространство для них. Вы уверены, что вторая строка - это именно то, что вы написали? esp уже указывает на свободную область, поэтому до того, как ваша программа вызовет себя рекурсивно или вызовет другую функцию, параметры могут быть сдвинуты в стек ниже ваших местных жителей. Я не вижу смысла загружать что-то в esp сразу после того, как он был настроен для размещения локальных варов, если только он не используется, чтобы позволить (следующей) вызывающей стороне обращаться к кадру стека вызывающего, как в Паскале, когда у вас есть вложенные функции.

0

Каждый C (кроме некоторых функций inline, а не только функций C) имеет начало и завершение. Начало обычно выглядит следующим образом:

push ebp 
mov ebp, esp 
sub esp, x 

Первая строка подталкивает старые стековые рамки. Поскольку во время работы программы есть много функций, функции могут сохранять стек стека в стеке при вызове другой функции. Рамка стека (обычно хранится в регистре EBP) - это то, что является основой каждой локальной адресации. Скажем, у вас есть этот код:

int main() { 
    __volatile int localVariable = 0x10; 
    printf("%d"); 
} 

Переменная localVariable может храниться где-то статический (например, по адресу 0x410000), но если был main вызывается снова, то значение по этому адресу будет overwirtten. Поэтому необходимо что-то вроде динамического выделения. Для этого используется рамка стека; сохраняет предыдущий стек стека и «распределяет» место для локальных переменных относительно фактической позиции указателя стека. В этом случае localVariable должен всегда находиться в позиции EBP-sizeof(int).

Вторая и третья строки на самом деле являются частью кода, которая выделяет «новую» память. Третья строка вычитает некоторое значение от ESP (стек растет) -> и поэтому функции не перезаписывают свои переменные; каждая функция имеет свое место для них. Вторая строка сохраняет старый указатель стека, поэтому, когда вызываемая функция возвращается из фрейма стека, она стекает указателем предыдущей функции.

Стандартное окончание функции

mov esp, ebp 
pop ebp 
ret 

или оставить RET leave во втором примере является альтернативой первых двух строк в первом примере, как функции возвращают к выполнению предыдущей функции очень часто.

Адресация EBP - something обычно означает доступ к локальным переменным вызываемой (текущей) функции.

Адресация EBP + someting обычно означает доступ к аргументам, переданным функции.

Я должен заметить, что адрес, хранящийся в EBP, фактически не указывает на аргумент, но возвращает адрес функции, который был нажат командой call при вызове функции. Значение, сохраненное на EBP + 4, может быть первым (старая практика, используемая, например, для функций с переменным числом аргументов, например printf) так же, как и последняя переменная (типичная для Java, которая обрабатывает аргументы счетчика аргументов - Object... values - путем создания нового массива и передачи только ссылка на него).

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