c-实现memset:dl寄存器segfault



我正在使用NASM在x86-64汇编代码中实现memset。当我尝试将值从rsi移动到dl时,我会得到一个segfault。你能帮我理解为什么吗?

以下是我目前所拥有的:

    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("%sn", buffer);
  }

请注意,我尝试了一个在汇编代码中实现main的替代测试,结果似乎运行良好。为什么会这样?(如果你想让我也发布那个代码,请告诉我。)

esi保存第二个参数,该参数是用于填充内存区域的值。(所以在你的测试中,rsi持有"m",或者更确切地说是它的ASCII代码)

在本说明中:

mov dl, byte [rsi]

您尝试将其用作内存地址,因此您访问的内存位置的地址是ASCII代码'm'。这会导致segfault。

您想要的只是直接使用rsi,例如:

mov rdx, rsi

此外,您当前的代码使用rdx做两件事——计数和要填充的字节。这不起作用——它只有一个寄存器,而且只保存一个值。(注意,dl的意思是"rdx的最低字节"-它不是一个单独的寄存器)

参数为rdi, rsi, rdx, rcx, r8, r9。您正在将rsi指向的字节(char)复制到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

(请注意,此函数假定方向标志已被清除,它应该被清除)。

最新更新