0

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?

Lefteris
  • 3,196
  • 5
  • 31
  • 52

1 Answers1

1

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.

Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • Scratch my previous comment. Was from my phone. The function is not a function pointer, but my question omitted some detail.The functions are a part of a library. Which was exported into a dll. The testing cases were without making into a dll but erroneously forgetting a dllimport in the declaration. This caused it to add an __imp_ before the function symbol name. I had noticed it and removed it thinking it will work correctly. Well seems that this way of calling the function is how it's done from the dll. I will accept your answer since your hint of func pointer lead me to the answer – Lefteris Sep 17 '12 at 09:25
  • I just love it how I learn new things when asking something in here. Not always through direct ways :) – Lefteris Sep 17 '12 at 09:28
  • DLL or not, if the machine code does an indirect call, it uses a pointer. – Alexey Frunze Sep 17 '12 at 09:32
  • Well yeah makes sense. My original intention when testing was to not make an indirect call, but due to the forgotten declspec(import) this is what was happening. Now thanks to you I know how function pointer call happens and how to recognize it in assembly. Thanks a lot man. – Lefteris Sep 17 '12 at 09:35