我编写了一个简单的汇编程序:
section .data
str_out db "%d ",10,0
section .text
extern printf
extern exit
global main
main:
MOV EDX, ESP
MOV EAX, EDX
PUSH EAX
PUSH str_out
CALL printf
SUB ESP, 8 ; cleanup stack
MOV EAX, EDX
PUSH EAX
PUSH str_out
CALL printf
SUB ESP, 8 ; cleanup stack
CALL exit
我是NASM汇编程序和GCC,用于将目标文件链接到Linux上的可执行文件。
本质上,该程序首先将堆栈指针的值放入寄存器EDX中,然后将该寄存器的内容打印两次。但是,在第二个printf调用之后,打印到标准输出的值与第一个不匹配。
这种行为似乎很奇怪。当我用EBX替换该程序中EDX的所有用法时,输出的整数与预期的相同。我只能推断在printf函数调用期间的某个时刻EDX被覆盖。
为什么会这样呢?以及如何确保将来使用的寄存器不与C lib函数冲突?
按照86 ABI,EBX
,ESI
,EDI
,和EBP
被调用函数保存寄存器EAX
,ECX
并且EDX
是主叫方保存寄存器。
这意味着函数可以自由使用并销毁之前的值EAX
,ECX
和EDX
。出于这个原因,保存的值EAX
,ECX
,EDX
调用函数之前,如果你不希望他们的变化值。这就是“保存呼叫者”的意思。
或者更好的方法是,将其他寄存器用于函数调用后仍需要的值。推/弹出的EBX
在功能的开始/结束大大优于推/弹出的EDX
一环,使一个函数调用里面。如果可能,请为呼叫后不需要的临时使用呼叫集群寄存器。已经存储在内存中的值,因此在重新读取之前不需要写入,也更容易泄漏。
因为EBX
,ESI
,EDI
,和EBP
被调用函数保存寄存器,功能有恢复值到原来的任何那些他们返回之前修改的。
ESP
也被保存,但除非将寄信人地址复制到某个地方,否则您无法搞砸。调用/重拨不匹配的性能非常糟糕,因为现代CPU使用返回地址预测器。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句