assembly - 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
解决方案
好的,首先,and s
ind
代表源和rsi
目标。它可能会以另一种方式工作(正如你所拥有的那样),但你会让很多像我这样的 CDO 人感到不安(a) :-)rdi
但是,对于您的实际问题,请看这里:
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 个字节)。由于您将长度作为 assemble-time constant 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
您还应该知道,您还可以使用其他技巧来将指令保存在循环中,例如相对于另一个字符串寻址(使用索引寻址模式进行加载,只增加一个指针)。
但是,我们不会在这里详细介绍它们,因为它可能会使答案变得比它需要的更复杂。
推荐阅读
- lua - LuA如何在不更改键的情况下从最小值对表进行排序
- android - React Native 位置权限在 Android 10 中不起作用,但在 Android 9 中起作用
- xamarin.forms - MasterDetailPage SlideOut 和 Slide In Button 未显示在 Master 详细信息中。使用 Button 向右滑动和向左滑出
- angular - 角嵌套formGroups
- javascript - 使用 axios 发布和获取请求的不同标头,创建?
- java - 我如何在同一页面中使用两个微调器
- excel - VBA 将图像保存为 eps 或其他矢量文件
- c++ - 何时准确检查 std::ifstream::good()?
- c++ - 这个函数在哪里找到一个 Sphenic 数?
- java - 为什么标识值必须是 Stream.reduce 中组合器函数的标识?