assembly - NASM:通过寄存器从内存移动到内存

标签 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

最佳答案

好的,首先,rsirdi 中的 sd 代表 目的地。可能以另一种方式工作(正如你所拥有的那样),但你会让很多像我这样的 CDO 人感到不安( a):-)

但是,对于您的实际问题,请查看此处:

end_count:
    mov [message], rsi

假设这意味着将最后一个字节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
<小时/>

为了完整起见,如果您不想复制换行符(尽管这几乎是您现在所拥有的,只是删除了错误的缓冲区破坏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
<小时/>

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

<小时/>

(b) 或者,可以更有效地完成不复制换行循环,同时在底部仍然有一个分支。

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

但这展示了一种高效的循环结构,避免了将新的 AL 合并到 RAX 底部的错误依赖,从而允许乱序执行提前运行并更早地“看到”循环退出分支。

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

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

但是,我们不会在这里详细介绍它们,因为这可能会使答案变得比需要的更加复杂。

关于assembly - NASM:通过寄存器从内存移动到内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58576125/

相关文章:

c - 如何在 Assembly 中正确写入字节数组?

c - movq 指令出现段错误?

assembly - x86-64下汇编指令switch case部分疑惑

linux - SECTION .DATA 中变量的段错误

assembly - 通过堆栈进行 32 位扩展乘法

opencv - OpenCV 2.0 是否针对 AMD 处理器进行了优化?

c - x86 程序集中 '_emit 0Fh, _emit 31h' 是什么意思?

assembly - 为什么这不打印 X?集会

windows - 汇编编程和过程调用的问题

c - 为什么我的 char[30] 堆栈增加到 0x38