提问人:Võ Khắc Bảo 提问时间:8/28/2023 最后编辑:Peter CordesVõ Khắc Bảo 更新时间:8/29/2023 访问量:44
在程序集中获取参数值
Get parameter value in Assembly
问:
我是 Assembly 的初学者,所以我对从另一个函数在函数调用中传递参数感到困惑。具体来说,我有这样的代码: 集会:
bar:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $555, -4(%ebp)
movl 12(%ebp), %eax
movl 8(%ebp), %edx
addl %edx, %eax
movl %eax, -8(%ebp)
leave
ret
foo:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $222, 4(%esp)
movl $111, (%esp)
call bar
leave
ret
原始 C 代码:
void
bar(int a, int b)
{
int x, y;
x = 555;
y = a+b;
}
void
foo(void) {
bar(111,222);
}
在汇编代码中,我不明白为什么在 foo() 中
movl $222, 4(%esp)
movl $111, (%esp)
call bar
可以再次被 bar() 读取:
movl 12(%ebp), %eax
movl 8(%ebp), %edx
我试图分析,但我仍然不明白 foo() 函数中的 esp - 8 个字节是否可以等同于 bar() 函数 esp - 16 个字节中读取的位置?像 12、8、4 这样的偏移数字在这两个函数之间是否相关? 我对此感到非常困惑。如果有人向我解释或给我一个具体的例子来理解这个问题,我将不胜感激。 谢谢
答:
3赞
teapot418
8/28/2023
#1
让我们想象一些样本值,并跟踪 ESP/EBP 会发生什么。另外请记住,推动某些东西(包括隐藏在里面的“”)会降低ESP。push eip
call
bar: ;ESP=88
pushl %ebp ;ESP=84
movl %esp, %ebp ;EBP=84
subl $16, %esp ;ESP=78
movl $555, -4(%ebp)
movl 12(%ebp), %eax ;@96->EAX
movl 8(%ebp), %edx ;@92->EDX
addl %edx, %eax
movl %eax, -8(%ebp)
leave
ret
foo:
pushl %ebp ;starting here:
movl %esp, %ebp ;let's assume ESP=100,EBP=100
subl $8, %esp ;ESP=92
movl $222, 4(%esp) ;222->96
movl $111, (%esp) ;111->92
call bar
leave
ret
评论
0赞
Võ Khắc Bảo
8/28/2023
你的答案很容易理解。谢谢!
0赞
Peter Cordes
8/29/2023
有趣的事实:一些 ABI(如 Linux 上 i386 System V 的现代版本)要求在 a 之前对齐 16 字节的 ESP,因此 ESP % 16 == 12 在函数输入时。但大多数其他 32 位调用约定(包括 *BSD 上的 i386 System V 和 macOS 删除 32 位支持之前的 macOS)只需要 4 字节对齐,因此这些 ESP 值是可能的。(更合理的是,它们像什么,但小数字是一个很好的例子,除了与示例值在同一范围内。call
0x7fff0058
0赞
Peter Cordes
8/29/2023
有趣的事实: / 2x 而不是 2x 是 P5 等 CPU 的旧 GCC 调整的结果,以及 Pentium-M 的堆栈引擎使 push/pop single-uop 之前的早期 P6。相关选项是 和 - 为什么 gcc 使用 movl 而不是 push 来传递函数参数?,其中还提到 GCC 在 2014 年将默认值更改为 favor。sub $8, %esp
mov
push
-maccumulate-outgoing-args
-mpush-args
-mtune=generic
push
评论
call
push ebp
esp
ebp
222
12(%ebp)
4(%esp)