; Standard prolog: stack frame setup
push ebp ; save the old frame pointer
mov ebp, esp ; set the frame pointer to the current top of the stack
sub esp, 0x10 ; make space for 16 bytes of local variables
; Do the stuff
mov eax, [ebp+8] ; copy the first parameter in eax
imul eax, [ebp+0xc] ; multiply eax with the second parameter
mov [ebp-4], eax ; move the result to the first local variable
mov eax, [ebp-4] ; move it back to eax (?) => set it as return value
; Standard cdecl epilog - clean up locals & return
leave ; restore the old frame pointer
; same as: mov esp, ebp
; pop ebp
ret ; return
(很抱歉将其更改为 Intel 表示法,但 AT&T 语法对我来说似乎是一团乱麻,尤其是用于取消引用和偏移的可怕表示法1)
要理解这一点,请参考这个方便的图表,该图表显示了在函数 prolog 之后的 x86 上的 cdecl 函数调用中堆栈通常的样子:
请记住,括号中的表达式是指针解引用操作。
本质上,这是对
的(相当幼稚的)翻译
int multiply(int a, int b) {
// \ \ &b == ebp+12
// \ &a == ebp+8
int c = a*b;
// \ \ multiplication performed in eax
// \ &c == ebp-4
return c;
// \ return value left in eax
}
(使用 cdecl 调用约定,调用者负责清理堆栈中的参数)
这可能是由禁用优化的编译器生成的。更紧凑的版本是:
mov eax, [esp+4]
imul eax, [esp+8]
ret
(因为一切都可以在没有局部变量的情况下完成,甚至不需要设置堆栈帧)
编辑
刚刚检查,您的代码与 gcc 在-O0 生成的完全匹配,而我的代码几乎与在-O3 生成的相同。
注意事项
-
记录:当你看到
displacement(%register, %offset_register, multiplier)
(除了%register之外的每个组件都是可选的)在AT&T语法中它实际上意味着
[register + displacement + offset_register*multiplier]
括号表示“取此处存储的值”。
此外,几乎所有参数都在 AT&T 语法中交换(在 Intel 语法中,目标操作数在左侧,即 mov 读起来像赋值 - mov ebp, esp => ebp = esp)。