2

I just started learning x86 and don't quite understand how the stack is cleaned up after a call/ret on IA32. I compiled the following code with gcc -m32 -no-pie:

#include <unistd.h>

int main()
{
    char text[108];
    int x = read(0, text, 108);
    return 0;
}

As far as I understand, the compiler makes space for 120 (116 + 4 bytes) on the stack. The first two words ebp-4 and ebp-8 remain unused (for memory alignment maybe?), and ebp-12 is reserved for storing x. ebp-16 to ebp-120 is reserved for the input text. Before calling read three values (4 bytes each) are pushed onto the stack, which are (after RET) later cleaned up with add esp, 16. But shouldn't it be add esp, 12 since we only pushed 3 values? Is it not overwriting the first/last character of "text"? I already drew the stack multiple times on paper, but I still don't see my mistake.

lea     ecx, [esp+4]
and     esp, -16
push    DWORD PTR [ecx-4]
push    ebp
mov     ebp, esp
push    ecx
sub     esp, 116
sub     esp, 4
push    108
lea     eax, [ebp-120]
push    eax
push    0
call    read
add     esp, 16
mov     DWORD PTR [ebp-12], eax
mov     eax, 0
mov     ecx, DWORD PTR [ebp-4]
leave
lea     esp, [ecx-4]
ret

Edit: Shouldn't also at the very end the stack and base pointers be restored, i.e., mov esp, ebp ; pop ebp so that the very last ret can access the stored instruction pointer and jump out of the main function?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Chris
  • 21
  • 2
  • 2
    re: edit: that's exactly what `leave` does; check the ISA manual. https://www.felixcloutier.com/x86/leave – Peter Cordes Jul 16 '20 at 01:40
  • 2
    There's a `sub esp, 4` that's aligning the stack args before the 3 pushes; `add esp,16` is popping that space too. Note that this is un-optimized code so it's over-complicated; with optimization the compiler would (hopefully) have done that `sub` as part of the one reserving space for the array. – Peter Cordes Jul 16 '20 at 01:44
  • Thanks, I completely overlooked that command! – Chris Jul 16 '20 at 01:48
  • Now I see it ... I did not pay attention to the `push ecx`. Now it also makes sense with `sub esp, 4` and increasing it by 16 again. Thanks a lot @PeterCordes! – Chris Jul 16 '20 at 01:58

0 Answers0