Search code examples
assemblygnu-assembler

GCC generated assembly - Segfault at C function call


I have been practising x86 assembly lately with the GCC in windows. I am mixing assembly and C code for testing purposes at the moment. I have come across something odd which I can't explain with my current knowledge and so I turn to SO for help.

Let's see a minimal example. We have a test_func() function in C code which we want to turn into assembly and then later call it from C code. This function though is calling other functions from the project and therein lies the problem. Any call to some other C code function from inside assembly will give me a segmentation fault.

The function we want to see in assembly:

#include "rf_string.h"
void test_func()
{//nonsense function, just calling another C function of the project
    RF_String s;
    rfString_Init(&s,"anything");
}

Asking gcc to spit out assembly code for this gives us:

    .file   "to_asm.c"
    .section .rdata,"dr"
    .align 4
LC0:
    .ascii "anything\0"
    .text
    .globl  _test_func
    .def    _test_func; .scl    2;  .type   32; .endef
_test_func:
LFB6:
    .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    subl    $40, %esp
    movl    $LC0, 4(%esp)
    leal    -16(%ebp), %eax
    movl    %eax, (%esp)
    movl    _rfString_Init, %eax
    call    *%eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
LFE6:

Then by saving this into a file called "asm_test.S" and including it into the build process of the project it builds and links fine. So we try to make a simple program to call the function.

int main()
{
    test_func();
    return 0;
}

The problem comes when debugging it. I get a segmentation fault at the call of the other C function from inside assembly code. This will happen for any other function I try to call from assembly code, it has nothing to do specifically with the one I used.

I think it has to do with the function call here:

 movl    %eax, (%esp)
 movl    _rfString_Init, %eax
 call    *%eax

Why is it doing this and what does this mean? Specifically why not simply call the function? Also what is the * before the %eax register? I also need to add that if I replace the last two lines with a simple call to the function like below everything seems to be working perfectly fine which really baffles me.

 call     _rfString_Init

Another minor question is about all these cfi_directives. They seem to be generated for exception handling purposes if I am to judge by answers to questions asked in SO. The question is, as far as the functionality of the code is concerned I can I safely ignore them?


Solution

  • Here:

     movl    _rfString_Init, %eax
     call    *%eax
    

    Note that there's no $ before _rfString_Init (unlike in movl $LC0, 4(%esp)). It means that _rfString_Init is not an immediate constant (e.g. a constant address of a function or an object or just a constant), but rather is a memory variable.

    So, movl loads eax with the contents of the variable named _rfString_Init.

    Then call performs a call to the address contained in eax. The star is some syntactical sugar indicating that control is to be passed indirectly, by reference/pointer.

    So, rfString_Init really is a pointer to a function. Look it up in your C code!

    And, of course, nothing good will happen if you try to transfer control to the bytes contained in the pointer, because it's data, which isn't expected to be interpreted as code. Further, the underlying memory is likely to be configured as non-executable.

    I don't know much about those directives. They can be for debugging as well. Anyway, they don't insert code where you see them.