我正在使用memset
在x86-64汇编代码中实现NASM
。当我尝试将值从rsi
移到dl
时,我会遇到段错误。你能帮我理解为什么吗?
这是我到目前为止所做的:
global my_memset
my_memset:
push rbp
mov rbp, rsp
xor rax, rax
xor rcx, rcx
mov dl, byte [rsi] ;segfault
mov rax, rdi
cmp rdx, 0
jz end
while:
inc rcx
mov byte [rdi], dl
inc rdi
cmp rcx, rdx
jne while
end:
mov rsp, rbp
pop rbp
ret
我正在用一个非常简单的main
函数来练习它:
void *my_memset(void *data, int value, int size);
int main()
{
char buffer[100];
my_memset(buffer, 'm', 100);
printf("%s\n", buffer);
}
请注意,我尝试使用汇编代码中实现的main
进行备用测试,这似乎运行正常。为什么会这样? (如果您希望我发布该代码,请告诉我。)
答案 0 :(得分:2)
esi
包含第二个参数,即填充内存区域的值。 (所以在你的测试中,rsi保持'm',或者更确切地说是它的ASCII代码)
在这条指令中:
mov dl, byte [rsi]
您尝试将其用作内存地址,因此您可以访问地址为“m”的ASCII代码的内存位置。这导致了一个段错误。
您想要的是直接使用rsi
,例如:
mov rdx, rsi
此外,您当前的代码使用rdx
两件事 - 计数和要填充的字节。那不行 - 它只有一个寄存器,只有一个值。 (请注意,dl
表示“rdx
的最低字节” - 它不是单独的寄存器)
答案 1 :(得分:1)
参数为rdi, rsi, rdx, rcx, r8, r9
。您正在将char
指向的字节(rsi
)复制到dl
,而不是寄存器的值。您可以将整个寄存器移至rdx
:
mov rdx, rsi
但您已使用rdx
作为计数限制注册,因此我建议您将值移至rax
并存储al
。
尽管如此,在这种情况下,使用字符串指令rep stosb
,使用最短的代码并且确实比你的更高效,使你的函数成为
my_memset:
mov rax, rsi ; move the byte to al
mov rcx, rdx ; move the counter to rcx
rep stosb ; repeat store byte from al to [rdi]
; and increase rdi (if direction flag cleared)
; decrease rcx and if rcx is zero, break out
ret
(注意此函数假定方向标志已清除,它应该是。)