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?
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.