William
William

Reputation: 77

implementing memset in assembly x86

I'm trying to implement memset in assembly x86. both with a copy by byte and by word, so I'd get two functions: kmemset and kmemsetw that I expose to my C code this way:

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);  

problem is when I test it, I get a segmentation fault. I tried to debug with gdb but it doesn't seem to be able to step into the asm code. I would be happy if anyone could comment on the code. (kmemset is pretty similar so I didn't include it).

.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  

Upvotes: 3

Views: 11024

Answers (2)

Gunner
Gunner

Reputation: 5884

Your not using ebx in your procedure, why save it? It does not need to be saved. ecx is a volatile register, you do not need to save it.

As gnometorule, mentioned, your parameters in your proc are off.

Another biggie is that you do not restore the stack pointer at the end. Sure you pop ebp, but where do you mov esp, ebp??? You mov ebp, esp at the beginning, but never reverse it.

If you look at memset, it returns the pointer passed to the proc. So, this is wrong: mov eax, edi it should be: mov eax, [ebp + 8]. rep stos? increments the pointer in edi so if you return edi, the returned pointer is wrong.

But why even set up a stack frame for this tiny proc? Just use esp, since we need to save edi to the stack, the params in esp will be offset the same as if we set up a stack frame:

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

using stosw will be a bit different.

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

Upvotes: 4

gnometorule
gnometorule

Reputation: 2139

Your argument reference locations are off by 4. If you push ebp in the function prologue, followed by updating epb, then the top two (4 byte) locations after your function ebp will contain ebp (SFP) and ret. Your code makes ret the destination location for your string copy. Add 4 to all references.  

There might be issues too with how you hand on/reference arguments, but this is unclear from the code snippet. 

Edit: This isn't your segfault, but you need to also change how you return. edi is updated during the rep stores, so to return a pointer to the beginning of the memory region, take it from ebx where you temp stored it.

Upvotes: 2

Related Questions