【发布时间】:2019-06-27 03:02:50
【问题描述】:
我是 x86 程序集的新手,我正在尝试构建一个 hello world 程序。我正在尝试制作一个子程序,将单个字节写入标准输出,但我遇到了问题。
mov ebx, [esp+1] 行(在我调用子例程时加载传递的字节)会导致段错误。
我已尝试将 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
为什么程序会出现段错误?
【问题讨论】:
-
你标记了这个 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 个字节。如果您想移动一个字节并将值零扩展到 RBX 的所有高位,您可以使用
movzx ebx, byte [rsp+1]。如果您打算只使用一个字节并希望稍后与 BL(RBX 寄存器的低 8 位)进行比较,您可以这样做mov bl, [rsp+1] -
更不用说
[rsp]是返回地址,所以要获取推送参数的第一个字节,他需要使用[rsp+8]。
标签: assembly x86 segmentation-fault x86-64 nasm