Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OS/X 64-bit assembly code generates bus error

I am trying to learn NASM on my 64-bit Macbook Pro. I have the following code where I am trying to assign the value of a variable to an initialised variable.

global start
default rel

section .data
a:      dq      1

section .bss

b:      resq    1

section .text

    start:
        mov rax, a
        mov [b], rax

The code compiles and links but produces a bus error when run. Does anyone have any ideas on how to overcome this?

like image 961
soarjay Avatar asked Jan 06 '23 21:01

soarjay


1 Answers

To answer the specific question about the BUS ERROR, it occurs because you haven't properly exited your application and the processor started executing what was in memory after the last instruction in your code. That eventually lead to a fault. Likely the BUS ERROR occurred once the processor reached the end of the executable page containing your code and started executing the .data section. .data section is non-executable so likely caused the error you observed. This is just an educated guess as it is highly dependent on the contents and layout of memory.

It appears you are bypassing the C runtime, so you can't use RET to return back to the OS. You'll need to invoke one of the 64-bit OS/X SYSCALLs.

A list of the 64-bit OS/X System Calls can be found on Apple's site. You can learn the basics from this tutorial (in the 64-bit section). The exit system call has an entry:

1    AUE_EXIT   ALL   { void exit(int rval); } 

From the tutorial, the parameter passing convention is described as:

  • arguments are passed on the registers rdi, rsi, rdx, r10, r8 and r9 syscall number in the rax register
  • the call is done via the syscall instruction
  • what OS X contributes to the mix is that you have to add 0x20000000 to the syscall number (still have to figure out why)

The complete calling convention is described in the 64-bit System V ABI. One other important note about SYSCALLs is:

  • A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.

With all this in mind we want to call 1 AUE_EXIT ALL { void exit(int rval); } . The system call number is in the first column. On 64-bit OS/X we add 0x2000000 to it and pass it in RAX. The exit system call takes one parameter, so it is passed in RDI. This is the exit value. Code that would use the exit system call and return 0 could look like this:

mov eax, 0x2000001 
xor edi, edi ; Return exit value 0 to system 
syscall

Debugging

As @paulsm4 correctly pointed out in his deleted answer:

Finally, I'm not sure where your "bus error" is coming from. But a debugger would tell you

To find SIGBUS and SIGSEGV errors it is best to use a debugger to step through the assembly instructions and find where the failure is at. In this case you would have discovered that an unexpected instruction was being called after mov [b], rax.

The most common command line debugger available on OS/X is LLDB. You can find more information on it usage in the LLDB tutorial.

like image 141
Michael Petch Avatar answered Jan 12 '23 00:01

Michael Petch