pmbotter
pmbotter

Reputation: 503

Mac OS X assembly and sys call causing Bus Error 10

Trying to run assembly on my Macbook Pro (Intel i7, 64-bit) and have encountered a weird bug.

It's a basic "Hello, world!" program only using system calls.

SECTION .text
global start

start:
mov rax, 2
shl rax, 24
add al , 4
mov rdi, 1
mov rsi, Msg
mov rdx, Len
syscall

mov al , 1
mov rdi, 0
syscall

SECTION .data
Msg db `Hello, world!\n`
Len: equ $-Msg

Assembled with NASM 2.11 Console commands:

nasm -f macho64 -o main.o main.s
ld main.o

It prints "Hello, world" and the newline character but then returns a Bus Error: 10 (wrong memory address).

But if I do:

mov rax, 2
shl rax, 24
add al , 1

I don't get a bus error.

QUESTION IS: Why can't I change the first byte of rax for the different call using "mov al, 1"

Upvotes: 0

Views: 2924

Answers (1)

paxdiablo
paxdiablo

Reputation: 882196

The rax register is not preserved by the first syscall so simply setting al to 1 won't give you the right value for the next syscall in rax since it leaves all the upper bits untouched. The method which doesn't give you the bus error is one which re-populates all bits of rax.

Since write is meant to return the number of bytes actually written, that comes back in rax, ensuring that you will need to populate it fully for the next syscall. Support for this use of rax for the return code can be found on the Wikipedia calling convention page which states for the System V AMD64 ABI:

The calling convention of the System V AMD64 ABI[11] is followed on Solaris, GNU/Linux, FreeBSD, Mac OS X, and other UNIX-like or POSIX-compliant operating systems. The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, and R9, while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for floating point arguments. For system calls, R10 is used instead of RCX.[11] As in the Microsoft x64 calling convention, additional arguments are passed on the stack and the return value is stored in RAX.

It's also detailed in the System V Application Binary Interface, AMD64 Architecture Processor Supplement document in Appendix A.

In terms of fixing your code, you would be better off doing the full population sequence (sans unnecessary bit-shifts):

mov rax, 0x2000001
mov rdi, 0
syscall

to exit. In fact, I'd use that method for both system calls to simplify the source:

SECTION .text
global start

start:
mov rax, 0x2000004      ; syscall 4: write (
mov rdi, 1              ;    fd,
mov rsi, Msg            ;    buffer,
mov rdx, Len            ;    size
syscall                 ; )

mov rax, 0x2000001      ; syscall 1: exit (
mov rdi, 0              ;    retcode
syscall                 ; )

SECTION .data
Msg db `Hello, world!\n`
Len: equ $-Msg

Upvotes: 4

Related Questions