在程序集x86中实现memset

时间:2013-12-02 14:44:51

标签: assembly x86 segmentation-fault

我试图在程序集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  

2 个答案:

答案 0 :(得分:3)

你的参数参考位置是4。如果你在函数序言中按ebp,然后更新epb,那么你的函数ebp之后的前两个(4字节)位置将包含ebp(SFP)和ret。您的代码使ret成为字符串副本的目标位置。在所有引用中添加4。

关于如何处理/引用参数可能也存在问题,但是从代码片段中不清楚这一点。

编辑:这不是您的段错误,但您还需要更改返回方式。 edi在rep存储期间更新,因此要返回指向内存区域开头的指针,请从临时存储它的ebx中获取它。

答案 1 :(得分:3)

您的程序中没有使用ebx,为什么要保存?它不需要保存。 ecx是一个易失性寄存器,您无需保存它。

正如gnometorule所提到的,你的proc中的参数都已关闭。

另一个重要因素是你最后没有恢复堆栈指针。当然你pop ebp,但你在哪里mov esp, ebp ???你mov ebp, esp开头,但从不反转它。

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

但为什么甚至为这个微小的过程设置堆栈帧?只需使用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