我很难将数据从内存移动到 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
最佳答案
好的,首先,rsi
和 rdi
中的 s
和 d
代表 源和目的地。它可能以另一种方式工作(正如你所拥有的那样),但你会让很多像我这样的 CDO 人感到不安( a):-)
但是,对于您的实际问题,请查看此处:
end_count:
mov [message], rsi
我假设这意味着将最后一个字节0x10
复制到目标中,但有两个问题:
message
是缓冲区的开始,而不是字节应该到达的位置。- 您正在将多字节
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-64
有SSE2
,它可以让你一次复制和检查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/