我很难将数据从内存移动到的另一个内存中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)
好的,首先,s并且din rsi和in分别rdi代表源和目标。它可能会以其他方式起作用(如您所愿),但是您会令很多像我这样的CDO人不高兴(a) :-)
但是,对于您的实际问题,请看这里:
end_count:
mov [message], rsi
Run Code Online (Sandbox Code Playgroud)
我认为这意味着将最后一个字节复制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
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-64有SSE2复制和检查一次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)
您还应该知道,还有其他技巧可以用来将指令保存在循环内,例如相对于另一字符串寻址一个字符串(对于加载,使用索引寻址模式,仅递增一个指针)。
但是,我们在此不对其进行详细介绍,因为这样做可能会使答案变得比所需的更为复杂。