Последовательная sys write syscalls не работает, как ожидалось, ошибка NASM на OS X?


Я пытаюсь изучить сборку MacOS с помощью NASM, и я не могу заставить работать тривиальную программу. Я пробую вариант "Привет, мир", где два слова независимо вызываются макросом. Мой исходный код выглядит следующим образом:

%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    

Ожидаемый результат должен быть:

$./hw
Hello,
World
$

Вместо этого я получаю:

$./hw
Hello,
$

Что я упускаю? Как мне это исправить?

EDIT : я компилирую и запускаю следующие команды:

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

1 ответ:

NASM 2.11.08 и 2.13.02+ имеют ошибки с выводом macho64. То, что вы наблюдаете, похоже на то, что я видел специально с 2.13.02+ недавно при использовании абсолютных ссылок. Последняя связанная программа имеет неверные исправления, поэтому ссылка на str2 неверна. Неправильное исправление заставляет нас печатать память, которая не является str2.

NASM имеетотчет об ошибке об этой проблеме в своей системе. Я добавил конкретный пример этого сбоя, основанный на коде в вопрос. Будем надеяться, что разработчики NASM смогут воспроизвести сбой и создать исправление.

Update : по состоянию на июнь 2018 года я считаю, что в NASM достаточно повторяющихся ошибок и регрессий, поэтому я не рекомендую NASM на данный момент для разработки Macho-64.


Еще одна рекомендация, которую я имею для разработки Macho-64, - использовать относительную адресацию RIP, а не абсолютную. Относительная адресация RIP используется по умолчанию для 64-разрядных программ более поздних версий из Макоса.

В NASM вы можете использовать директиву default rel в вашем файле, чтобы изменить значение по умолчанию с абсолютного на относительный адрес RIP. Чтобы это сработало, вам придется перейти от использования mov register, variable к lea register, [variable] при попытке переместить адрес переменной в регистр. Ваш пересмотренный код может выглядеть следующим образом:

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