Assembly 正确还原被调用方保存的寄存器
我试图正确理解我在哪里以及如何将被调用方保存的寄存器(如Assembly 正确还原被调用方保存的寄存器,assembly,scope,x86,cpu-registers,calling-convention,Assembly,Scope,X86,Cpu Registers,Calling Convention,我试图正确理解我在哪里以及如何将被调用方保存的寄存器(如ebx)推到堆栈上或从堆栈中弹出,以恢复它们以供以后使用 此代码是否正确地恢复了ebx寄存器 global main extern printf section .text: print: mov eax, 0x1 add eax, ebx push eax push message call printf add esp, 8 ret
ebx
)推到堆栈上或从堆栈中弹出,以恢复它们以供以后使用
此代码是否正确地恢复了ebx寄存器
global main
extern printf
section .text:
print:
mov eax, 0x1
add eax, ebx
push eax
push message
call printf
add esp, 8
ret
main:
mov ebx, 0x1
push ebx
call print
pop ebx
ret
message db "result = %d", 10, 0
我应该像这样在使用后直接弹出ebx吗
global main
extern printf
section .text:
print:
push ebx
mov ebx, 0x1
mov eax, 0x1
add eax, ebx
push eax
push message
call printf
add esp, 8
pop ebx
ret
main:
call print
ret
message db "result = %d", 10, 0
两种方法都可以,但第二种方法更为传统 规则是这样的:当编译器生成调用函数的代码时,它假定调用后ebx的内容与之前相同。在您的程序中,唯一适用的情况是调用
main
的启动代码。对于两个版本的代码,ebx
在main
返回时与输入时具有相同的值,因此一切正常
如果您的程序中有一个名为print
的C函数,那么第一个版本就不好,需要第二个版本。但是在第一个版本中,print
仅从手动编码的main
函数调用,您知道print
将关闭ebx
,并且您正在采取适当的操作来保存和恢复它,所以这很好
换句话说,在代码的第一个版本中,
print
不符合标准的C调用约定。但是,由于您从未真正从C代码调用它,所以这不一定是个问题。在第二个版本中,它确实符合,这可能在美学上更好,维护起来也不那么混乱。两种方法都可以,但第二种方法更为传统
规则是这样的:当编译器生成调用函数的代码时,它假定调用后ebx的内容与之前相同。在您的程序中,唯一适用的情况是调用main
的启动代码。对于两个版本的代码,ebx
在main
返回时与输入时具有相同的值,因此一切正常
如果您的程序中有一个名为print
的C函数,那么第一个版本就不好,需要第二个版本。但是在第一个版本中,print
仅从手动编码的main
函数调用,您知道print
将关闭ebx
,并且您正在采取适当的操作来保存和恢复它,所以这很好
换句话说,在代码的第一个版本中,
print
不符合标准的C调用约定。但是,由于您从未真正从C代码调用它,所以这不一定是个问题。在第二个版本中,它确实符合要求,这在美学上可能更好,维护起来可能更容易混淆。如果以类似的方式使用,在汇编中还需要push
ed和pop
ped哪些寄存器?只要eax
和ebx
?@kdi_342:任何保留调用的寄存器都应被视为相同的。对于32位x86调用约定,这是除EAX、ECX和EDX之外的所有整数reg。另请参见第一种方法实际上并不好:main在保存/恢复EBX之前写入EBX,这完全没有意义@kdi_342,您已经销毁了调用方的值,如果print
遵循ABI,则call print
将保留该值。但它并没有遵循标准的调用约定:它显然是在使用EBX将arg传递给print
?整个事情非常奇怪,因为任何地方都没有ret
指令,所以两个版本都会循环,直到溢出堆栈并崩溃。@Nate:你在考虑AT&T语法吗addeax,ebx
读取ebx而不写入,因此第一个版本的print
不会对ebx造成冲击。但它确实读过。我不知道该怎么说这个代码,因为它太奇怪了,但是你的答案似乎与代码不一致。是的,你是对的,我没有仔细阅读。当我有更多时间时将尝试修复。如果以类似的方式使用,在汇编中还需要对哪些寄存器进行push
ed和pop
ped?只要eax
和ebx
?@kdi_342:任何保留调用的寄存器都应被视为相同的。对于32位x86调用约定,这是除EAX、ECX和EDX之外的所有整数reg。另请参见第一种方法实际上并不好:main在保存/恢复EBX之前写入EBX,这完全没有意义@kdi_342,您已经销毁了调用方的值,如果print
遵循ABI,则call print
将保留该值。但它并没有遵循标准的调用约定:它显然是在使用EBX将arg传递给print
?整个事情非常奇怪,因为任何地方都没有ret
指令,所以两个版本都会循环,直到溢出堆栈并崩溃。@Nate:你在考虑AT&T语法吗addeax,ebx
读取ebx而不写入,因此第一个版本的print
不会对ebx造成冲击。但它确实读过。我不知道该怎么说这个代码,因为它太奇怪了,但是你的答案似乎与代码不一致。是的,你是对的,我没有仔细阅读。当我有更多的时间时,我会设法解决的。