无效的 base/index 表达式

Invalid base/index expressions

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

movw    [=11=]xd000, -2(%sp)
movw    [=11=], -4(%sp)
movw    , -6(%sp)

编译为

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$

产生以下错误:

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

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

16 位的寻址模式寄存器选择非常有限。参见 https://whosebug.com/tags/x86/info /

[reg1 + reg2 + displacement]的任何子集都有效,其中reg1可以是BX或BP,and/or reg2可以是SI或DI。

16bit 不能使用 SIB 字节,所以所有 1 和 2 reg 寻址模式都必须编码到 mod/rm 字节中。这样就没有多少空间了。

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 位寻址。

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

例如:

movw    %sp, %bp
subw    , %sp
movw    [=10=]xd000, -2(%bp)
movw    [=10=], -4(%bp)
movw    , -6(%bp)