2013-08-25 2 views
1

Я пытался понять разобранный код следующей функции.Демонтаж функции C

void func(char *string) { 
    printf("the string is %s\n",string); 
} 

Демонтированный код приведен ниже.

1) 0x080483e4 <+0>:  push %ebp 
2) 0x080483e5 <+1>:  mov %esp,%ebp 
3) 0x080483e7 <+3>:  sub $0x18,%esp 
4) 0x080483ea <+6>:  mov $0x80484f0,%eax 
5) 0x080483ef <+11>: mov 0x8(%ebp),%edx 
6) 0x080483f2 <+14>: mov %edx,0x4(%esp) 
7) 0x080483f6 <+18>: mov %eax,(%esp) 
8) 0x080483f9 <+21>: call 0x8048300 <[email protected]> 

Может ли кто-нибудь сказать мне, что означает линии 4-7 (не буквальное объяснение). Также почему 24 байта выделены в стеке в строке 3?

+0

Вы знакомы с тем, как работает стек, например. при использовании 'push' /' pop'? – DCoder

+0

Я думаю, что знаю, что – user146297

+4

Тогда эти строки довольно просты - вместо того, чтобы «нажимать» значение на стек, GCC вручную переместил указатель стека и переместил это значение в новую вершину стека. Посмотрите раздел «Аргументы» [этой статьи] (http://codearcana.com/posts/2013/05/21/a-brief-introduction-to-x86-calling-conventions.html), он объясняет это в некоторые подробности.Что касается «почему 24 байта стека», это внутреннее решение компилятора, которое может быть связано с * стеком выравнивания *, * стека канарейки * или просто случайным решением. – DCoder

ответ

5

В основном то, что происходит здесь:

4) 0x080483ea <+6> : mov $0x80484f0,%eax 

Загрузите адрес "the string is %s\n" в eax.

5) 0x080483ef <+11>: mov 0x8(%ebp),%edx 

Move аргумент string в edx.

6) 0x080483f2 <+14>: mov %edx,0x4(%esp) 

Нажмите значение edx или string в стек, второй аргумент printf

7) 0x080483f6 <+18>: mov %eax,(%esp) 

Пуш значение eax или "the string is %s\n" в стек, первый аргумент printf, а затем он будет вызывать printf.

sub $0x18,%esp не требуется, поскольку функция не имеет локальных переменных, gcc, похоже, делает дополнительное пространство, но, честно говоря, я не знаю почему.

+0

Спасибо за ваш ответ. строка аргумента означает адрес строки здесь? Кроме того, что касается (sub $ 0x18,% esp), я думаю, что вы правы, поскольку разбор различных функций с произвольным отсутствием printf показал, что printf не влияет на отсутствие переменных, зарезервированных в стеке. Или, возможно, это связано с файловыми каналами стека, поскольку @Dcoder указал – user146297

+0

@ user146297 Что касается строки, да, адрес строки. Такое поведение ненужных «sub XXX,% esp» долгое время беспокоило меня, я не мог найти ответа на него. –

+1

Без sub, 'mov% edx, 0x4 (% esp)' приведет к повреждению стека. –

1

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

Первоначально эта функция нажимает ebp на стек, чтобы он мог быть сохранен, когда функция заканчивается, устанавливает esp = ebp, чтобы отметить начало его кадра и выделить 28 байтов. Почему 28? Для выравнивания. Он уже выделил 4 байта для ebp. 4 + 28 = 32.

Строки 4-7 подготовят звонок к printf. Он ожидает, что его аргументы будут находиться в кадре вызывающего абонента. Когда мы читаем mov 0x8(%ebp), %edx, мы принимаем наш аргумент char* string из кадра вызывающего. printf будет делать то же самое.

Обратите внимание, что в вашей сборке нет leave и ret инструкции по очистке стека и возврату вызывающего абонента.

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