我在linux 64位上使用NASM汇编程序。有一些变量和寄存器我无法理解。我创建了一个名为“msg”的变量:
msg db "hello, world"
现在,当我想写到标准输出时,我将msg
移动到rsi
寄存器,但是我不理解mov
指令的位.rsi寄存器由64位组成,而msg变量有12个符号,每个符号8位,这意味着msg变量的大小为12 * 8
位,明显大于64位。
那么,如何才能做出这样的指示:
mov rsi, msg
,而不溢出分配给rsi的内存。
或者rsi寄存器是否包含字符串的第一个符号的存储位置,并且在写入1符号之后,它更改为下一个符号的内存位置?
对不起,如果我写的都是胡说八道,我是刚开始组装的,我只是一时搞不懂。
发布于 2017-11-05 16:09:45
在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
。
发布于 2017-11-05 15:41:35
免责声明:我不熟悉您正在处理的程序集的风格,因此下面的内容更一般。特别的味道可能比我习惯的有更多的特色。通常,程序集处理的是单字节/字实体,其大小取决于处理器。我在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中的指针一样,您将需要对字符串的终止有某种指示,或者另一个指示字符串大小的值,这样您就知道什么时候停止。
https://stackoverflow.com/questions/47123137
复制相似问题