Assembly 以64位代码从[esp]加载时出现SEGFULT

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

我对x86汇编相当陌生,我正在尝试构建一个hello world程序。我正试图制作一个子程序,将一个字节写入标准输出,但遇到了一个问题

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]
。相关: