您一直在尝试转换使用的32位Linux代码 int0x80 到64位代码。虽然这可以适用于很多情况,但它并不适用于所有情况。 int 0x80 是32位系统调用接口,但内核中内置了IA32兼容性(大多数发行版的默认设置),您仍然可以使用 int 0x80 。问题是这样的 的 只要 强> 当内核处理你的寄存器时,会识别出低32位的寄存器 int 0x80 请求。
int0x80
int 0x80
您的第一个问题中的代码没有出现任何问题,但此代码不起作用。原因是RSP中的堆栈指针通常是一个无法用32位值寻址的地址。当你这样做 mov rax,rsp RSP的完整64位值被移动到RAX,但是 sprint 的 int 0x80 调用只能看到RAX的底部32位(EAX寄存器)。
mov rax,rsp
sprint
解决这个问题的方法是使用64位 syscall 接口。不幸的是,传入的系统调用号和寄存器参数已经改变。 Ryan Chapman的博客 有一个很好的64位表 syscall 系统呼叫号码及其参数。
syscall
该 sys_write 系统调用号和表中的参数是:
sys_write
根据这些信息,您可以进行转换 sprint 使用 syscall 通过这样做接口:
sprint: push r11 ; R11 and RCX are clobbered by syscall as well push rcx push rdx push rsi push rdi push rax call slen mov rdx, rax ; RDX = number of characters to print pop rax mov rsi, rax ; RSI = address of characters to print mov rdi, 1 ; RDI = file descriptor (1=STDOUT) mov rax, 1 ; System call number 1 = sys_write syscall ; 64-bit system call (rather than int 0x80) pop rdi pop rsi pop rdx pop rcx pop r11 ret
这样效率很低,可以清理。我以这种方式呈现它,以便您可以从原始代码的角度理解更改。我评论了相关的方面。
的 注意 强> :你应该真的转换所有 int 0x80 打电话给 syscall 使用Ryan Chapman的桌子作为指导。我把它作为OP的练习。