我是汇编的新手,我必须在汇编 x86-64 中编写 memmove 函数,它说:
memmove(( 函数将 n 个字节从内存区域 src 复制到内存区域 dest。内存区域可能会重叠:复制就像 src 中的字节首先复制到不重叠 src 或 dest 的临时数组中,然后将字节从临时数组复制到 dest。
尽管如此,我找不到在程序集中保存临时字符串的方法,这就是我发布此内容的原因。
我试图输入寄存器rax
但我得到了一个分段错误:
mov r8b, byte [rsi + rcx] ; rsi is source string
mov byte [rax + rcx], r8b
顺便说一下,我正在构建中使用nasm -f elf64 memmove.asm
谢谢。
机器指令 MOVSB 将成为您复制内存区域的朋友。它从 RSI 寻址的内存中复制一个字节 到RDI寻址的内存,然后将两个寄存器修改为下一个元素(字节(。
SECTION .data
Memory DB '0123456789'
Src1st EQU Memory+0
SrcLast EQU Memory+4
Dest1st EQU Memory+3
DestLast EQU Memory+7
SECTION .text
LEA RSI,[Src1st]
LEA RDI,[Dest1st]
CLD
我们可以这样在 MOVSB 之前可视化内存布局
RSI RDI
| |
0 1 2 3 4 5 6 7 8 9
_________ Src
_________ Dest
MOVSB之后
RSI RDI
| |
0 1 2 0 4 5 6 7 8 9
使用指令前缀 REP,它是重复的 RCX 时间。 后
MOV RCX,DestLast-Dest1st+1
REP MOVSB
RSI RDI
| |
0 1 2 0 1 2 0 1 8 9
当 Src 和 Dest 区域重叠时,这不会按预期工作 - 而不是0120123489我们得到了0120120189。 当目标字段高于源(RDI>RSI(时,我们必须向后复制(设置方向标志( 并从指向字段末尾的寄存器开始。
LEA RSI,[SrcLast]
LEA RDI,[DestLast]
MOV RCX,DestLast-Dest1st+1
RSI RDI
| |
0 1 2 3 4 5 6 7 8 9
后
STD
REP MOVSB
RSI RDI
| |
0 1 2 0 1 2 3 4 8 9
源字段逐字复制到目标,无需临时数组,不会浪费内存和时钟。方向标志应在向后复制后重置为其默认状态,这是大多数操作系统和库函数接口所期望的。