Search code examples
cassemblyx86nasminline-assembly

x86 function returning char* in C


I want to write a function in x86 which will be called from C program.
The function should look like this:

char *remnth(char *s, int n);

I want it to remove every nth letter from string s and return that string. Here's my remnth.s file:

section.text
global remnth

remnth:
; prolog
    push ebp
    mov ebp, esp

; procedure
    mov eax, [ebp+8]; Text in which I'm removing every nth letter
    mov ebx, [ebp+12]; = n
    mov ecx, [ebp+8] ; pointer to next letter (replacement)


lopext:
    mov edi, [ebp+12]     ; edi = n  //setting counter
    dec edi               ; edi--  //we don't go form 'n' to '1' but from 'n-1' to '0'
lop1:
    mov cl, [ecx]         ; letter which will be a replacement
    mov byte [eax], cl    ; replace
    test cl,cl            ; was the replacement equal to 0?
    je exit               ; if yes that means the function is over
    inc eax               ; else increment pointer to letter which will be replaced
    inc ecx               ; increment pointer to letter which is a replacement
    dec edi               ; is it already nth number?
    jne lop1              ; if not then repeat the loop
    inc ecx               ; else skip that letter by proceeding to the next one
    jmp lopext            ; we need to set counter (edi) once more 

exit:
; epilog

    pop ebp     
    ret   

The problem is that when I'm calling this function from main() in C I get Segmentation fault (core dumped)

From what I know this is highly related to pointers, in this case I'm returning *char, and since I've seen some functions that returns int and they worked just fine, I suspect that I forgot about something important with returning a *char properly.

This is what my C file looks like:

#include <stdio.h>

extern char *remnth(char *s,int n);

int main()
{
    char txt[] = "some example text\0";

    printf("orginal = %s\n",txt);
    printf("after = %s\n",remnth(txt,3));

    return 0;
}

Any help will be appreciated.


Solution

  • You're using ecx as a pointer, and cl as a work register. Since cl is the low 8 bits of ecx, you're corrupting your pointer with the mov cl, [ecx] instruction. You'll need to change one or the other. Typically, al/ax/eax/rax is used for a temporary work register, as some accesses to the accumulator use shorter instruction sequences. If you use al as a work register, you'll want to avoid using eax as a pointer and use a different register instead (remembering to preserve its contents if necessary).