Assembly 以64位代码从[esp]加载时出现SEGFULT
我对x86汇编相当陌生,我正在尝试构建一个hello world程序。我正试图制作一个子程序,将一个字节写入标准输出,但遇到了一个问题 行Assembly 以64位代码从[esp]加载时出现SEGFULT,assembly,x86,segmentation-fault,x86-64,nasm,Assembly,X86,Segmentation Fault,X86 64,Nasm,我对x86汇编相当陌生,我正在尝试构建一个hello world程序。我正试图制作一个子程序,将一个字节写入标准输出,但遇到了一个问题 行mov ebx[esp+1](在调用子程序时加载传递的字节)导致segfault 我已经尝试过对ebx寄存器进行异或运算,以确保它是空的,以确保它不会干扰系统调用 _start: push 32h call _writeByte ; This just jumps to an exit routine jmp _exit
mov ebx[esp+1]
(在调用子程序时加载传递的字节)导致segfault
我已经尝试过对ebx寄存器进行异或运算,以确保它是空的,以确保它不会干扰系统调用
_start:
push 32h
call _writeByte
; This just jumps to an exit routine
jmp _exit
_writeByte:
; This line causes the problem. If I remove it the program works fine
mov ebx, [esp+1]
xor ebx, ebx
mov eax, 1
mov edi, 1
mov esi, tmp
mov edx, 1
syscall
ret
为什么程序会出错?我处于x64模式,就像一群人在评论中建议的那样,使用
mov ebx,[rsp+8]
工作,因为esp
只是寄存器中较低的4个字节。堆栈位于虚拟地址空间的低位4 GiB之外,因此ESP!=RSP和[esp]
将是一个未映射的页面
请注意,x86-64调用约定传递寄存器中的前几个参数,而不是堆栈上的参数,因此您通常根本不想这样做(除非您的函数有很多参数)。您标记了这个x86-64。您是否处于64位模式?您应该使用
rsp
而不是esp
,因为后者只是低32位,可能会指向无效地址。ebx
是一个32位寄存器。如果要加载单个字节,请使用bl
或bh
。问题可能是未对齐的读取,但对此不确定。另外,esp
指向当前的回信地址。添加1
不足以进入参数。仅处理为什么mov ebx,[esp+1]
失败。在64位代码中,堆栈指针可能跨越大于等于4gb的地址。在大多数(并非所有)操作系统(包括Linux和MacOS)上的64位代码中,堆栈指针位于大于等于4gb的地址,因此堆栈的内存地址应使用RSP(而不是ESP)。当然,在下一条指令中,当您将整个64位寄存器RBX设置为零时,该行没有太大作用。mov到EBX当然将移动4个字节,而不仅仅是1个字节。如果您希望移动一个字节,并将值0扩展到RBX的所有高位,则可以使用movzx EBX,byte[rsp+1]
。如果您打算只使用一个字节,并希望稍后与BL(RBX寄存器较低的8位)进行比较,您可以只执行mov BL、[rsp+1]
操作,更不用说[rsp]
是返回地址,因此要获取推送参数的第一个字节,他需要使用[rsp+8]
。相关: