Serial sys_write syscalls not working as expected, NASM error on OS X?

I am trying to learn macOS build using NASM and I cannot get a trivial program to work. I am trying to change "Hello, World" where two words independently call a macro. My original code looks like this:

%macro printString 2
    mov     rax, 0x2000004 ; write
    mov     rdi, 1 ; stdout
    mov     rsi, %1
    mov     rdx, %2
    syscall
%endmacro     

global start    

section .text    

start:
    printString str1,str1.len    

    printString str2,str2.len    

    mov     rax, 0x2000001 ; exit
    mov     rdi, 0
    syscall    


section .data    

str1:   db      "Hello,",10,
.len:  equ       $ - str1    

str2:   db      "world",10
.len:  equ       $ - str2    

      

Expected Result:

$./hw
Hello,
World
$

      

Instead, I get:

$./hw
Hello,
$

      

What am I missing? How to fix it?

EDIT : I am compiling and running the following commands:

/usr/local/bin/nasm -f macho64 hw.asm
ld -macosx_version_min 10.7.0 -lSystem -o hw hw.o
./hw

      

+3


source to share


1 answer


NASM 2.11.08 and 2.13.02+ have bugs with exit macho64

. What you are seeing appears to be what I have seen specifically since 2.13.02+ lately when using absolute references. The last linked program has incorrect fixes, so the link to str2

is incorrect. The wrong fix makes us print out memory that is not str2

.

NASM has a bug report for this issue on their system. I have added a specific example of this failure based on the code in the question. Hopefully the NASM devs can reproduce the crash and create a fix.

One recommendation is to build NASM 2.13.01 and see if that works.



Another recommendation is to rewrite the code to use relative RIP addressing rather than absolute. RIP relative addressing is the default for most 64-bit programs in later versions of macOS.

In NASM, you can use a directive default rel

in your file to change the default relative addresses from absolute to RIP. To do this, you will have to go from use mov register, variable

to lea register, [variable]

when trying to move the address of a variable into a register. Your revised code might look like this:

default rel

%macro printString 2
    mov     rax, 0x2000004 ; write
    mov     rdi, 1 ; stdout
    lea     rsi, [%1]
    mov     rdx, %2
    syscall
%endmacro

global start

section .text

start:
    printString str1,str1.len

    printString str2,str2.len

    mov     rax, 0x2000001 ; exit
    mov     rdi, 0
    syscall


section .data

str1:   db      "Hello,",10
.len:  equ       $ - str1

str2:   db      "world",10
.len:  equ       $ - str2

      

+6


source







All Articles