我在linux 64位上使用NASM汇编程序。 我无法理解变量和寄存器。 我创建了一个名为" msg":
的变量 msg db "hello, world"
现在,当我想写入stdout时,我将msg
移动到rsi
寄存器,但是我不理解mov
指令按位... rsi寄存器由64位组成,而msg变量有12个符号,每个符号为8位,这意味着msg变量的大小为12 * 8
位,显然大于64位。
那么如何制作如下指令呢?
mov rsi, msg
,没有溢出为rsi分配的内存。
或者rsi寄存器是否包含字符串第一个符号的内存位置,写入1个符号后它会改变到下一个符号的内存位置?
很抱歉,如果我写完全废话,我是新组装的,我暂时无法掌握它。
答案 0 :(得分:4)
在NASM语法中(与MASM语法不同)mov rsi, symbol
将符号的地址放入RSI。
mov rsi, [symbol]
将从symbol
开始加载8个字节。你可以选择一个有用的地方来加载8个字节,就像你写这样的指令一样。
mov rsi, msg ; rsi = address of msg
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 most x64 instructions zero the upper part of a 32 bit register
在写入1个符号后,它会改变到下一个符号的存储位置吗?
不,如果你想要,你必须inc rsi
。没有魔力。指针只是你操纵的整数,就像任何其他整数一样,字符串只是内存中的字节。
访问寄存器并不会对它们进行神奇的修改。
有lodsb
和pop
等指令从内存加载并递增指针(rsi
或rsp
),但x86没有任何指针前/后递增/递减寻址模式,因此即使您需要,也无法使用mov
获得该行为。使用add
/ sub
或inc
/ dec
。
答案 1 :(得分:0)
免责声明:我不熟悉您正在处理的装配风格,因此以下内容更为通用。特定的味道可能具有比我以前更多的功能。通常,汇编处理单字节/字实体,其大小取决于处理器。我已经在8位和16位处理器上完成了相当多的工作,所以这就是我的答案来源。
关于汇编的一般声明: 汇编就像一个高级语言,除了你必须处理更多的细节。因此,如果您习惯于在C语言中使用某些操作,则可以从那里开始,然后再进一步中断操作。
例如,如果您已声明要添加的两个变量,那么在C中这很容易:
x = a + b;
在装配中,你必须进一步打破它:
mov R1, a * get value from a into register R1
mov R2, b * get value from b into register R2
add R1,R2 * perform the addition (typically goes into a particular location I'll call it the accumulator
mov x, acc * store the result of the addition from the accumulator into x
根据程序集和处理器的风格,您可以直接引用添加说明中的变量,但就像我说的那样我必须查看您正在使用的特定风格。
评论您的具体问题: 如果你有一串字符,那么你必须使用某种循环单独移动每个字符。我会设置一个寄存器来包含字符串的起始地址,然后在移动每个字符后递增该寄存器。它的作用类似于C中的指针。您需要对字符串的终止或其他告诉字符串大小的值有一些指示,因此您知道何时停止。