| AT&T syntax | "C"-ish equivalent | |
| movl %eax, %edx | edx = eax; | register mode |
| movl $0x123, %edx | edx = 0x123; | immediate |
| movl 0x123, %edx | edx = *(int32_t*)0x123; | direct |
| movl (%ebx), %edx | edx = *(int32_t*)ebx; | indirect |
| movl 4(%ebx), %edx | edx = *(int32_t*)(ebx+4); | displaced |
| Example instruction | What it does |
| pushl %eax |
subl $4, %esp movl %eax, (%esp) |
| popl %eax |
movl (%esp), %eax addl $4, %esp |
| call 0x12345 |
pushl %eip (*) movl $0x12345, %eip (*) |
| ret | popl %eip (*) |
+------------+ | | arg 2 | \ +------------+ >- previous function's stack frame | arg 1 | / +------------+ | | ret %eip | / +============+ | saved %ebp | \ %ebp-> +------------+ | | | | | local | \ | variables, | >- current function's stack frame | etc. | / | | | | | | %esp-> +------------+ /
pushl %ebp movl %esp, %ebp
movl %ebp, %esp popl %ebp
ebp) is not strictly needed
because a compiler can
compute the address of its return address and function arguments based
on its knowledge of the current depth of the stack
pointer (in esp).
eip. The current value of *(ebp+4) provides
the return address of the caller. The current value of
*((*ebp) + 4) (where *ebp contains the saved ebp
of the caller) provides the return address of the caller's caller,
the current value of *(*(*ebp) + 4) provides the
return address of the caller's caller's caller, and so on . . .