Hello World с помощью ассемблера x86 на Mac 0SX
Я пытаюсь погрузиться в какое-то программирование сборки x86 на моем Mac, но у меня возникают проблемы с созданием исполняемого файла. Проблема, похоже, на этапе связывания.
helloWorld.s:
.data
HelloWorldString:
.ascii "Hello World\n"
.text
.globl _start
_start:
# load all the arguments for write()
movl $4, %eax
movl $1, %ebx
movl $HelloWorldString, %ecx
movl $12, %edx
# raises software interrupt to call write()
int $0x80
# call exit()
movl $1, %eax
movl $0, %ebx
int $0x80
Соберите программу:
as -o helloWorld.o helloWorld.s
Свяжите объектный файл:
ld -o helloWorld helloWorld.o
Ошибка, которую я получаю в этой точке:
ld: could not find entry point "start" (perhaps missing crt1.o) for inferred architecture x86_64
Любые советы о том, что я делаю неправильно/пропущен, были бы очень полезными. спасибо
Ответы
Ответ 1
Скорее всего, вам будет проще строить с помощью gcc, а не пытаться микроуправлять ассемблер и компоновщик, например.
$ gcc helloWorld.s -o helloWorld
(Вы, вероятно, захотите изменить _start
на _main
, если вы пройдете этот маршрут.)
Кстати, поучительно начинать с рабочей программы на C и изучать сгенерированный asm из этого. Например.
#include <stdio.h>
int main(void)
{
puts("Hello world!\n");
return 0;
}
при компиляции с помощью gcc -Wall -O3 -m32 -fno-PIC hello.c -S -o hello.S
генерирует:
.cstring
LC0:
.ascii "Hello world!\12\0"
.text
.align 4,0x90
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $24, %esp
movl $LC0, (%esp)
call _puts
xorl %eax, %eax
leave
ret
.subsections_via_symbols
Возможно, вы захотите использовать это как шаблон для своих собственных "Hello world" или других экспериментальных программ asm, особенно учитывая, что он уже строит и запускает:
$ gcc -m32 hello.S -o hello
$ ./hello
Hello world!
Один заключительный комментарий: остерегайтесь брать примеры из Linux-ориентированных книг или учебников asm и пытаться применить их под OS X - есть важные отличия!
Ответ 2
Попробуйте:
ld -e _start -arch x86_64 -o HelloWorld HelloWorld.S
тогда:
./HelloWorld
Информация:
-e <entry point>
-arch <architecture>, You can check your architecture by uname -a
-o <output file>
Ответ 3
hello.asm
.data
HelloWorldString:
.ascii "Hello World!\n"
.text
.globl start
start:
; load all the arguments for write()
movl $0x2000004, %eax
movl $1, %ebx
movq [email protected](%rip), %rsi
movq $100, %rdx
; raises software interrupt to call write()
syscall
; call exit()
movl $0x2000001, %eax
movl $0, %ebx
syscall
Затем запустите:
$ as -arch x86_64 -o hello.o hello.asm
$ ld -o hello hello.o
$ ./hello
Это рабочее решение для ассемблеров Mac OS X Mach-0, основанных на GNU
Ответ 4
Код в вопросе выглядит так для 32-битного Linux, использующего ABI int $0x80
с аргументами в EBX, ECX, EDX.
В коде x86-64 в MacOS используется инструкция syscall
с передачей аргументов и возвращаемым значением, аналогичным 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-битный абсолют, хотя это также поддерживается.)