我在 64 位 linux 上使用 NASM 汇编程序。
有一些我无法理解的变量和寄存器。
我创建了一个名为“msg”的变量:
msg db "hello, world"
现在,当我想写入标准输出时,我将
msg
移动到 rsi
寄存器,但是我不理解 mov
指令按位... rsi 寄存器由 64 位组成,而 msg 变量有 12 个符号,每个符号为 8 位,这意味着 msg 变量的大小为 12 * 8
bits ,显然大于 64 位。那么这怎么可能做出如下指令:
mov rsi, msg
,不会溢出为 rsi 分配的内存。或者 rsi 寄存器是否包含字符串的第一个符号的内存位置,在写入 1 个符号后,它会更改为下一个符号的内存位置?
对不起,如果我写的完全是胡说八道,我是组装新手,我只是暂时无法掌握它。
最佳答案
在 NASM 语法中(与 MASM 语法不同),mov rsi, symbol
将符号的地址放入 RSI。 (使用 64 位绝对立即数效率低下;使用 RIP 相对 LEA 或 mov esi, symbol
代替。 How to load address of function or label into register in GNU Assembler )mov rsi, [symbol]
将从 symbol
开始加载 8 个字节。当您编写这样的指令时,您可以选择一个有用的位置来加载 8 个字节。
mov rsi, msg ; rsi = address of msg. Use lea rsi, [rel msg] instead
movzx eax, byte [rsi+1] ; rax = 'e' (upper 7 bytes zeroed)
mov edx, [msg+6] ; rdx = ' wor' (upper 4 bytes zeroed)
请注意,您可以使用
mov esi, msg
,因为符号地址始终适合 32 位(在默认的“小”代码模型中,所有静态代码/数据都位于低 2GB 的虚拟地址空间中)。 NASM 使用汇编时常量(如 mov rax, 1
)为您进行了这种优化,但可能无法使用链接时常量。 Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?不,如果你想要,你必须
inc rsi
。没有魔法。指针只是可以像任何其他整数一样操作的整数,而字符串只是内存中的字节。访问寄存器不会神奇地修改它们。
有像
lodsb
和 pop
这样的指令,它们从内存中加载并递增一个指针(分别是 rsi
或 rsp
),但是 x86 没有任何前/后递增/递减寻址模式,因此您甚至无法使用 mov
获得这种行为如果你想要的话。使用 add
/sub
或 inc
/dec
。关于string - 无法理解寄存器和变量之间的汇编 mov 指令,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47123137/