x86 asm - 12 байт, вычтенных из esp. Нужно всего 8

Я скомпилировал этот код с помощью gcc (gcc -ggdb -mpreferred-stack-border =2 -o demo demo.c) и декомпилировал его, чтобы посмотреть на сборку (я знаю, что он использует небезопасные функции, это было для упражнения в буфер переполнение):

#include<stdio.h>

CanNeverExecute()
{
        printf("I can never execute\n");
        exit(0);
}

GetInput()
{
        char buffer[8];

        gets(buffer);
        puts(buffer);
}

main()
{
        GetInput();

        return 0;
}

Вот сборка для функции GetInput():

(gdb) disas GetInput
Dump of assembler code for function GetInput:
   0x08048432 <+0>: push   ebp
   0x08048433 <+1>: mov    ebp,esp
   0x08048435 <+3>: sub    esp,0xc
=> 0x08048438 <+6>: lea    eax,[ebp-0x8]
   0x0804843b <+9>: mov    DWORD PTR [esp],eax
   0x0804843e <+12>:    call   0x8048320 <gets@plt>
   0x08048443 <+17>:    lea    eax,[ebp-0x8]
   0x08048446 <+20>:    mov    DWORD PTR [esp],eax
   0x08048449 <+23>:    call   0x8048340 <puts@plt>
   0x0804844e <+28>:    leave  
   0x0804844f <+29>:    ret    
End of assembler dump.

Вот сборка для функции Main():

(gdb) disas main
Dump of assembler code for function main:
   0x08048450 <+0>: push   ebp
   0x08048451 <+1>: mov    ebp,esp
   0x08048453 <+3>: call   0x8048432 <GetInput>
   0x08048458 <+8>: mov    eax,0x0
   0x0804845d <+13>:    pop    ebp
   0x0804845e <+14>:    ret    
End of assembler dump.

Я установил точку останова в строке 13 (получает (буфер))

Из Main() я вижу, что значение ebp помещается в стек. Затем, когда вызывается функция GetInput(), адрес возврата также помещается в стек. После входа в функцию GetInput значение ebp снова помещается в стек. Теперь вот где я запутался:

0x08048435 <+3>: sub esp,0xc

Буферная переменная составляет всего 8 байтов, поэтому 8 байтов следует вычесть из esp, чтобы учесть локальную переменную буфера.

Стек:

    (gdb) x/8xw $esp
    0xbffff404: 0x08048360  0x0804847b  0x002c3ff4  0xbffff418
    0xbffff414: 0x08048458  0xbffff498  0x00147d36  0x00000001
    (gdb) x/x &buffer
    0xbffff408: 0x0804847b

0x08048458 - это адрес возврата, 0xbffff418 - старое значение ebp, а 4 байта буферной переменной - в 0x0804847b, поэтому я предполагаю, что остальные 4 байта равны 0x002c3ff4. Но в стеке, похоже, есть еще 4 байта.

Итак, мой вопрос: почему вычитается 12 байтов, если требуется только 8 байтов? Зачем нужны 4 дополнительных байта?

Спасибо

1 ответ

Решение

Это из-за

mov    DWORD PTR [esp],eax

Видимо, твой puts а также gets реализации требуют, чтобы аргумент был помещен в стек.

Значение [ebp-0xc] на самом деле [esp] вот почему dword зарезервировано впереди.

Почему это так? Делать это таким образом более эффективно, так как вам не нужно pop а также push, но просто двигайся eax на [esp]Таким образом, вы сэкономите хотя бы одну инструкцию. Тем не менее, я думаю, что этот код прошел некоторую оптимизацию, потому что этот код является умным.

Другие вопросы по тегам