我正在尝试在程序集 x86 中实现 memset。都有一个按字节和按字的副本,所以我会得到两个函数:kmemsetkmemsetw,我以这种方式公开给我的 C 代码:

extern uint8_t* kmemset(uint8_t* dest, uint8_t val, uint8_t size);
extern uint16_t* kmemsetw(uint16_t* dest, uint16_t val, uint8_t size);

问题是当我测试它时,出现段错误。我试图用 gdb 调试,但它似乎无法进入 asm 代码。如果有人可以对代码发表评论,我会很高兴。 ( kmemset 非常相似,所以我没有包括它)。
.intel_syntax noprefix
.section .text
.align 16
.global kmemsetw
.type kmemsetw, @function

kmemsetw:
    push ebp
    mov ebp, esp
    push edi
    push ecx
    push ebx
    xor eax, eax
    mov ebx, [ebp+4]
    mov ax, [ebp+8]
    mov ecx, [ebp+12]
    mov edi, ebx
    rep stosw
    mov eax, edi
    pop ebx
    pop ecx
    pop edi
    pop ebp
    ret

最佳答案

你在你的程序中没有使用 ebx ,为什么要保存它?它不需要保存。 ecx 是一个 volatile 寄存器,你不需要保存它。

正如提到的 gnometorule,您的 proc 中的参数已关闭。

另一个大问题是你没有在最后恢复堆栈指针。当然你 pop ebp ,但是你在哪里 mov esp, ebp ???您在开始时使用 mov ebp, esp,但永远不要反转它。

如果您查看 memset ,它会返回传递给 proc 的指针。所以,这是错误的:mov eax, edi 应该是: mov eax, [ebp + 8]rep stos? 增加 edi 中的指针,因此如果您返回 edi ,则返回的指针是错误的。

但是为什么还要为这个小小的 proc 设置一个堆栈框架呢?只需使用 esp ,因为我们需要将 edi 保存到堆栈中, esp 中的参数将被偏移,就像我们设置一个堆栈帧一样:

kmemset:
    push    edi             ; proc uses edi, so save it.

    mov     ecx, [esp + 16] ; size_t num
    mov     al, [esp + 12]  ; int value
    mov     edi, [esp + 8]  ; void * ptr
    rep     stosb

    mov     eax, [esp + 8]  ; return pointer
    pop     edi             ; restore edi
    ret                     ; let caller adjust stack

使用 stosw 会有点不同。
SomeProc:
    push    ebp
    mov     ebp, esp
    push    edi

    ; params are at:
     ;~ ebp + 8
     ;~ ebp + 12
     ;~ ebp + 16
     etc...
    ; ...
    ; ...
    ; ...

    pop     edi
    ; the following 2 lines
    ; can be replaced with
    ; leave
    mov     esp, ebp
    pop     ebp
    ret

关于assembly - 在程序集 x86 中实现 memset,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20331000/

10-11 15:35