Jus*_*tin 19 x86 assembly instructions mov
我正在尝试学习汇编(所以忍受我),我在这一行得到了一个编译错误:
mov byte [t_last], [t_cur]
Run Code Online (Sandbox Code Playgroud)
错误是
error: invalid combination of opcode and operands
Run Code Online (Sandbox Code Playgroud)
我怀疑这个错误的原因只是因为一个mov指令不可能在两个内存地址之间移动,但是半小时的谷歌搜索并且我无法确认这一点 - 是这样的吗?
另外,假设我是对的,这意味着我需要使用寄存器作为复制内存的中间点:
mov cl, [t_cur]
mov [t_last], cl
Run Code Online (Sandbox Code Playgroud)
什么是推荐使用的寄存器(或者我应该使用堆栈)?
Fed*_*oca 27
你的怀疑是正确的,你不能从记忆转移到记忆.
任何通用寄存器都可以.如果您不确定其中的内容并在完成后将其恢复,请记住推送寄存器.
16位非常简单,只需执行以下操作:
push di
push si
push cx
mov cx,(number of bytes to move)
lea di,(destination address)
lea si,(source address)
rep movsb
pop cx
pop si
pop di
Run Code Online (Sandbox Code Playgroud)
注意:如果您需要保存寄存器的内容,则推送和弹出是必要的.
没错,x86 机器代码无法使用两个显式内存操作数(在 中指定的任意地址[])对指令进行编码
推荐的寄存器是什么
您不需要保存/恢复的任何寄存器。
在所有主流的 32 位和 64 位调用约定中,EAX、ECX 和 EDX 都是 call-clobbered,所以 AL、CL 和 DL 是不错的选择。对于字节或字复制,您通常希望movzx加载到 32 位寄存器,然后是 8 位或 16 位存储。这避免了对寄存器旧值的错误依赖。mov如果您主动想要合并到另一个值的低位,请仅使用窄的 16 位或 8 位负载。x86movzx是类似于 ARM 的指令ldrb。
movzx ecx, byte [rdi] ; load CL, zero-extending into RCX
mov [rdi+10], cl
Run Code Online (Sandbox Code Playgroud)
在 64 位模式下,SIL、DIL、r8b、r9b 等也是不错的选择,但需要在商店的机器代码中使用 REX 前缀,因此有一个较小的代码大小原因可以避免它们。
出于性能原因,通常避免编写 AH、BH、CH 或 DH,除非您已阅读并理解以下链接,并且任何错误的依赖项或部分寄存器合并停顿都不会成为问题或根本不会发生在您的代码中.
(或者我应该使用堆栈代替)?
首先,您根本无法推送单个字节,因此您无法从堆栈中进行字节加载/字节存储。对于 word、dword 或 qword(取决于 CPU 模式),您可以push [src]/ pop [dst],但这比通过寄存器复制要慢得多。它在从最终目的地读取数据之前引入了额外的存储/重新加载存储转发延迟,并需要更多的 uops。
除非堆栈上的某个地方是所需的目的地,并且您无法将该局部变量优化到寄存器中,在这种情况下,push [src]可以将其复制到那里并为其分配堆栈空间。
请参阅x86 标签 wiki中的https://agner.org/optimize/和其他 x86 性能链接
小智 6
从技术上来说,从一个记忆转移到另一个记忆是可能的。
尝试使用MOVS(移动字符串),并设置[E]SI和[E]DI,具体取决于您是否要传输字节、字等。
mov si, t_cur ; Load SI with address of 't_cur'
mov di, t_last ; Load DI with address of 't_last'
movsb ; Move byte from [SI] to [DI]
; Some dummy data
t_cur db 0x9a ; DB tells NASM that we want to declare a byte
t_last db 0x7f ; (See above)
Run Code Online (Sandbox Code Playgroud)
但请注意,这比执行两次MOV效率低,但它确实在一条指令中执行复制。
以下是MOVS的使用方式及其工作原理: https://www.felixcloutier.com/x86/movs :movsb:movsw:movsd:movsq
MOVS指令几乎从不单独使用,大部分情况下与REP前缀结合使用。
现代 CPU 具有相当高效的实现,rep movs接近使用 AVX 向量加载/存储指令的循环速度。
; - Assuming that 't_src' and 't_dst' are valid pointers
mov esi, t_src ; Load ESI with the address of 't_src'
mov edi, t_dst ; Load EDI with the address of 't_dst'
mov ecx, 48 ; Load [ER]CX with the count (let's say 48 dwords = blocks)
rep movsd ; Repeat copying until ECX == 0
Run Code Online (Sandbox Code Playgroud)
从逻辑上讲,复制发生在 48 个 4 字节双字块的副本中,但真正现代的 CPU(快速字符串/ERMSB)将使用 16 或 32字节块来提高效率。
本手册解释了如何使用 REP及其工作原理: https://www.felixcloutier.com/x86/rep :repe:repz:repne:repnz
| 归档时间: |
|
| 查看次数: |
28572 次 |
| 最近记录: |