实现memset:dl注册段错误

时间:2015-03-21 20:50:17

标签: c assembly nasm x86-64 memset

我正在使用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进行备用测试,这似乎运行正常。为什么会这样? (如果您希望我发布该代码,请告诉我。)

2 个答案:

答案 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

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