NASM:通过寄存器在内存之间移动

2 assembly x86-64 nasm

我很难将数据从内存移动到的另一个内存中bss。我的实现有些起作用,但是当移动一些奇怪的字符出现在前几个字节中时,我的字符串的一半也丢失了,而另一半还不错。

这是我打印输出时获得的值message==?F@elcome to the new life

我需要所有帮助,我想念什么?我检查了一百遍代码。

    section .data
hello:       db  "Hello, Welcome to the new life! Lets begin the journey.",10
hello_len:   equ  $ - hello

    section .bss
message: resb 255

    section .text

mov rdi, hello
mov rsi, message

msg_into_message:
    cmp byte [rdi], 10          ; hello ends with a new line char
    je end_count
    mov al, byte [rdi]
    mov byte [rsi], al
    inc rsi
    inc rdi
    jmp msg_into_message

end_count:
    mov [message], rsi
    ret

    ; Prints message
    mov rsi, message
    mov rdx, hello_len
    call pre_print
    syscall
Run Code Online (Sandbox Code Playgroud)

pax*_*blo 5

好的,首先,s并且din rsi和in分别rdi代表目标。可能会以其他方式起作用(如您所愿),但是您会令很多像我这样的CDO人不高兴(a) :-)

但是,对于您的实际问题,请看这里:

end_count:
    mov [message], rsi
Run Code Online (Sandbox Code Playgroud)

认为这意味着将最后一个字节复制0x10到目标中,但是有两个问题:

  1. message是缓冲区的开始,而不是字节应到达的位置。
  2. 您正在将多字节rsi变量复制到此处,而不是所需的字节。

这两点意味着,正如您的症状所暗示的,您在前几个字节中添加了一些奇怪的值。

也许更好的方法如下:

    mov rsi, hello            ; as Gordon Moore intended :-)
    mov rdi, message

put_str_into_message:
    mov al, byte [rsi]        ; get byte, increment src ptr.
    inc rsi

    mov byte [rdi], al        ; put byte, increment dst ptr.
    inc rdi

    cmp al, 10                ; continue until newline.
    jne put_str_into_message

    ret
Run Code Online (Sandbox Code Playgroud)

为了完整起见,如果您希望复制换行符(尽管这几乎是您现在拥有的,只是mov消除了错误的缓冲区损坏)(b)

put_str_into_message:
    mov al, byte [rsi]        ; get byte.
    cmp al, 10                ; stop before newline.
    je  stop_str

    mov byte [rdi], al        ; put byte, increment pointers.
    inc rsi
    inc rdi

    jmp put_str_into_message

stop_str:
    ret
Run Code Online (Sandbox Code Playgroud)

(a) CDO是强迫症,但字母排列正确:-)


(b)或者可以更有效地完成“请勿复制换行”循环,同时在底部仍保留一个分支。

在一次循环一个字节是仍然非常低效的(x86-64SSE2复制和检查一次16个字节,它可以让)。由于您将长度作为汇编时间常数hello_len,因此可以使用它来高效地复制大块(如果缓冲区大小不是16的倍数,则可能需要在末尾进行特殊处理),或者使用rep movsb

但这展示了一种有效的循环结构,避免了将新内容合并AL到底部的错误依赖RAX,从而使无序exec可以提前运行并更早地“看到”循环出口分支。

strcpy_newline_end:
    movzx  eax, byte [rsi]    ; get byte (without false dependency).
    cmp    al, 10
    je    copy_done           ; first byte isn't newline, enter loop.

copy_loop:                    ; do:
    mov    [rdi], al          ;    put byte.
    inc    rsi                ;    increment both pointers.
    inc    rdi
    movzx  eax, byte [rsi]    ;    get next byte.
    cmp    al, 10
    jne   copy_loop           ; until you get a newline.

; After falling out of the loop (or jumping here from the top)
; we've loaded but *not* stored the terminating newline

copy_done:
    ret
Run Code Online (Sandbox Code Playgroud)

您还应该知道,还有其他技巧可以用来将指令保存在循环内,例如相对于另一字符串寻址一个字符串(对于加载,使用索引寻址模式,仅递增一个指针)。

但是,我们在此不对其进行详细介绍,因为这样做可能会使答案变得比所需的更为复杂。