Код в вопросе выглядит так, как будто он предназначен для 32-битного Linux, использующего ABI int $0x80
с аргументами в EBX, ECX, EDX.
В коде
x86-64 в MacOS используется инструкция syscall
, с передачей аргумента и возвращаемым значением , аналогичным , что описано в документе x86-64 System V ABI для Linux. Это полностью отличается от int $0x80
, единственное сходство в том, что номер вызова передается в EAX / RAX. Но номера звонков разные: https://sigsegv.pl/osx-bsd-syscalls/ ИЛИ с 0x2000000
.
Аргументы заносятся в те же регистры, что и для вызовов функций. (кроме R10 вместо RCX.)
См. Также базовая сборка не работает на Mac (x86_64 + Lion)? и Как запустить эту простую сборку?
Я думаю, что это гораздо более аккуратная и интуитивно понятная версия того, что было предложено в другом ответе.
OS X использует start
, а не _start
, для точки входа в процесс.
.data
str:
.ascii "Hello world!\n"
len = . - str # length = start - end. . = current position
.text
.globl start
start:
movl $0x2000004, %eax
movl $1, %edi
leaq str(%rip), %rsi
movq $len, %rdx
syscall # write(1, str, len)
movl $0x2000001, %eax
movl $0, %edi
syscall # _exit(0)
Обычно вы опускаете суффикс размера операнда, если регистр это подразумевает. И используйте xor %edi,%edi
для обнуления RDI.
И используйте mov $len, %edx
, потому что вы знаете, что размер меньше 4 ГБ, поэтому будет работать более эффективный 32-разрядный расширенный тип mov-немедленного с нулевым расширением, как если бы вы устанавливали RAX на номер вызова.
Обратите внимание на использование REA-относительного LEA для получения адреса статических данных в регистр. Код x86-64 в MacOS не может использовать 32-битную абсолютную адресацию, потому что базовый адрес, где будет отображаться ваш исполняемый файл, выше 2 ^ 32.
Для 32-разрядных абсолютных адресов нет типов перемещения, поэтому их нельзя использовать. (И вам нужен RIP-относительный, а не 64-битный абсолют, хотя это также поддерживается.)