您需要在寻址模式中使用指针宽度寄存器。 x86 没有内存间接寻址模式,只有寄存器间接寻址模式。 Referencing the contents of a memory location. (x86 addressing modes)。您可以在一条指令中执行的操作的限制来自机器代码可以表示的内容。汇编器不是编译器。每行都必须作为一条机器指令工作。
理想情况下,将pixel_x 保存在寄存器而不是内存中;这就是寄存器的用途。
假设是 32 位代码,
movzx eax, byte [pixel_x]
movzx eax, byte [bytemap + eax] ; AL = EAX = bytemap[pixel_x]
如果您想在寄存器中使用 pixel_x 值以供以后使用,当然可以使用不同的 reg,例如 EBX。
或者在这种情况下,imul eax,eax 因为数组条目只是索引平方;你不需要查找表。
在 64 位代码中,您将使用 default rel,因此 movzx eax, byte [pixel_x] 使用 RIP 相对寻址模式。您可能需要将bytemap 的地址放入代码where static addresses aren't guaranteed to fit in a 32-bit sign-extended displacement 中的单独寄存器中。
在 16 位代码中(可以假设 386 兼容),您需要处理 16 位寻址模式的限制:只有 BX、BP、SI 和 DI 可以是基址或索引寄存器。 NASM x86 16-bit addressing modes
movzx bx, byte [pixel_x]
movzx ax, byte [bytemap + bx] ; AL = AX = bytemap[pixel_x]
如果(不太可能)您的代码需要在 8086 到 286 上运行,则需要模拟 movzx。
在 16 位模式的现代 x86 上,使用 EBX 和 EAX 作为movzx 的目标可能有助于提高性能,但会增加代码大小。如果您正在编写 16 位代码,您可能不关心速度,只关心代码大小。如果性能很重要,您可以切换到保护模式或长模式。
movzx 是加载单个字节的最佳/最有效方式,零扩展至完整寄存器以避免部分寄存器性能问题,如错误依赖。仅当您真正想要合并到 EAX/RAX 的低字节时才使用mov al, [mem]。
对于字节存储,你仍然只是读取部分寄存器,如mov [mem], al。
阅读部分 regs 很好,只是当您可以使用 movzx 代替时,通常避免编写它们。 add al, [mem] 之类的东西在大多数 CPU 上也很有效。 Why doesn't GCC use partial registers?
一般来说,使用部分寄存器并不是灾难,只要使用movzx 或movsx 而不是mov,就可以轻松避免它。