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 . . .