Bus Error: Native x86 Build with GCC on Mac OS X

I get a "Bus Error" message when I try to run this code compiled with gcc 4.2.1 on Snow Leopard

#include <stdio.h> /*__declspec(naked)*/ void doStuff(unsigned long int val, unsigned long int flags, unsigned char *result) { __asm{ push eax push ebx push ecx push edx mov eax, dword ptr[esp + 24]//val mov ebx, dword ptr[esp + 28]//flags //mov ecx, dword ptr[esp + 32]//result and eax, ebx mov result, eax pop edx pop ecx pop ebx pop eax ret } } int main(int argc, char *argv[]) { unsigned long val = 0xAA00A1F2; unsigned long flags = 0x00100001; unsigned char result = 0x0; doStuff(val, flags, &result); printf("Result is: %2Xh\n", result); return 0; } 

I use the following command to compile gcc -fasm-blocks -m32 -o so so.c without any errors or warnings. I am trying to follow some assembly instructions in the doStuff () function and assign a response to the result. What am I doing wrong?

Note. This worked fine in Visual Studio on Windows, but I had to comment on declspec (bare) to get gcc to compile it on Mac.

+4
source share
2 answers

The reason you get a bus error is because you are calling ret in your build code. ret forces the program control to pass the return address at the top of the stack that you control with push and pop . I highly recommend looking at what ret does in the Intel instruction set reference.

Below is the code that I compiled and successfully ran on an iMac running Mac OS X 10.6.7.

 #include <stdio.h> /*__declspec(naked)*/ void doStuff(unsigned long int val, unsigned long int flags, unsigned char *result) { __asm { push eax push ebx push ecx mov eax, dword ptr[ebp + 8] //val mov ebx, dword ptr[ebp + 12] //flags mov ecx, dword ptr[ebp + 16] //result and eax, ebx mov [ecx], eax pop ecx pop ebx pop eax } } int main(int argc, char *argv[]) { unsigned long val = 0xAA00A1F2; unsigned long flags = 0x00100002; unsigned char result = 0x0; doStuff(val, flags, &result); printf("Result is: %2Xh\n", result); return 0; } 

Noticeable changes:

  • Removing ret in an inline assembly
  • Using ebp instead of esp to reference doStuff options
  • Changing flags to 0x00100002

Change (1) corrects the bus error, (2) made the parameter reference a bit more consistent, and (3) is just a quick way to make sure the function is working properly.

Finally, I highly recommend that you check out GNU Debugger, GDB, if you haven't already. More information about this can be found on the project page http://www.gnu.org/software/gdb/ , as well as information about the implementation and tutorial of the Mac at http://developer.apple.com/library/mac/# documentation / DeveloperTools / gdb / gdb / gdb_toc.html .

EDIT: Added basic info / link to GDB,

+5
source

Compilers add prologs and epilogues to function calls; these prologs and epilogues take care of setting up stack frames, reserving stack space for local variables, destroying stack frames and returning to the caller.

A typical prolog for a function without local variables when using a frame pointer might look like this:

 push ebp mov ebp, esp 

This saves the caller's frame pointer on the stack and makes the current frame pointer equal to the stack pointer during function entry.

The corresponding epilogue will be:

 pop ebp ret 

which restores the previous frame pointer and returns to the caller.

If you tell gcc not to use frame pointers ( -fomit-frame-pointer ), the corresponding prolog will be empty and the epilogue will only contain ret .

This __declspec(naked) is probably similar to gcc __attribute__((naked)) ( gcc function attributes ), which only works for some architectures, not x86. So, on gcc, you'd better leave the compiler returning to the caller, as Dean Puchek advised you.

+1
source

All Articles