无效的基/索引表达式

Max*_*nov 4 x86 assembly real-mode gnu-assembler

尝试使用基索引表达式在 16 位实模式下操作内存会导致编译错误:

movw    $0xd000, -2(%sp)
movw    $0, -4(%sp)
movw    $1, -6(%sp)
Run Code Online (Sandbox Code Playgroud)

编译为

gcc -c -Wa,--32 $(DIR_BS_SRC)/mbr.S -o $(DIR_BS_SRC)/mbr.o
ld -nostdlib --oformat binary --Ttext 0x7c00 $(DIR_BS_SRC)/mbr.o -o $(DIR_B$
Run Code Online (Sandbox Code Playgroud)

产生以下错误:

bootsector/src/mbr.S:20: Error: `-2(%sp)' is not a valid base/index expression
bootsector/src/mbr.S:21: Error: `-4(%sp)' is not a valid base/index expression
bootsector/src/mbr.S:22: Error: `-6(%sp)' is not a valid base/index expression
Run Code Online (Sandbox Code Playgroud)

我认为这是有效的语法,即使在 16 位实模式下也是如此?

Ros*_*dge 6

SP 在 16 位寻址模式下不能用作基址寄存器或变址寄存器。与 32 位寻址模式不同,允许的模式对于可以使用哪些寄存器有很大的限制。

您仅限于以下模式(%bx)(%bp)(%si)(%di)(%bx,%si)(%bx,%di)(%bp,%si)(%bp,%di)这些都可以有一个可选的 8 位或 16 位位移。(严格来讲(%bp)必须有位移,但如果不提供位移,汇编器将使用0位移)注意,以BP为基址的寻址模式也默认为堆栈段(SS)而不是数据段(DS) 。

您的情况的部分解决方案是使用 BP 作为基础,首先从 SP 复制值。或者,您可以使用 ESP 作为基础,并在允许的情况下使用 32 位寻址。

然而,您所尝试的仍然存在根本问题。您试图将值存储在堆栈指针下方的地址处。这些地址将被未来的推送和调用以及不可预测的中断覆盖。即使您已禁用中断并且没有使用任何使用堆栈的指令,为您正在使用的内存正确分配堆栈上的空间仍然是一个好主意。

例如:

movw    %sp, %bp
subw    $6, %sp
movw    $0xd000, -2(%bp)
movw    $0, -4(%bp)
movw    $1, -6(%bp)
Run Code Online (Sandbox Code Playgroud)