Как я могу запустить этот код сборки на OS X?
Начиная изучать сборку, мне был предоставлен код сборки Hello World, созданный во время класса в Linux. Я хотел бы заставить его работать для 64-разрядной Mac OS X.
code.asm
SECTION .data
hola: db "Hola!",10
tam: equ $-hola
SECTION .text
global main
main:
mov edx,tam
mov ecx,hola
mov ebx,1
mov eax,4
int 0x80
mov ebx,0
mov eax,1
int 0x80
Это то, что я делаю:
nasm -f macho32 -o object.o code.asm
gcc -m32 -o program object.o
Что мне говорит:
Undefined символы для архитектуры i386: "_main", на которые ссылаются: начало в crt1.10.6.o ld: символ (-ы) не найден для архитектуры i386
В поисках этой ошибки я нашел этот вопрос: nasm и gcc: 32-разрядная ссылка не удалась (64-битная Mac OS X)
Один ответ говорит
Проблема, с которой вы сталкиваетесь, заключается в том, что вы создаете 32-разрядный Linux (ELF) объектный файл, который несовместим с форматом объекта Mac OS X. Попробуйте переключить '-f elf' на '-f macho32'.
Но я определенно использую -f macho32
. Итак, какова будет проблема?
Ответы
Ответ 1
Вам нужно будет:
-
Измените имя метки с main
на _main
(в обоих местах). Именование Symbol работает немного по-другому в Mac OS X.
-
Измените способ передачи аргументов системному вызову. Mac OS X использует другое соглашение о вызовах для ядра Linux; этот код не портативный! Я не знаю, как есть официальная документация о том, как она работает, но просмотр разборки в GDB для стандартной библиотечной функции, такой как _exit()
, может быть поучительным.
Здесь _exit
в моей системе, например:
<_exit+0>: mov $0x40001,%eax
<_exit+5>: call 0x96f124c2 <_sysenter_trap>
<_exit+10>: jae 0x96f10086 <_exit+26>
<_exit+12>: call 0x96f1007d <_exit+17>
<_exit+17>: pop %edx
<_exit+18>: mov 0x15a3bf9f(%edx),%edx
<_exit+24>: jmp *%edx
<_exit+26>: ret
<_exit+27>: nop
Дополнительный бит, установленный в 0x40001
, является... странным, но здесь можно спокойно игнорировать.
Материал, следующий за вызовом _sysenter_trap
, предназначен для обработки ошибок.
_sysenter_trap
:
<_sysenter_trap+0>: pop %edx
<_sysenter_trap+1>: mov %esp,%ecx
<_sysenter_trap+3>: sysenter
<_sysenter_trap+5>: nop
Все рассмотренное, вам, вероятно, лучше не связываться с libSystem (эквивалент OS X для libc) вместо того, чтобы напрямую обращаться к ядру.
Ответ 2
Я тоже пытался научить себя программированию на начальном уровне, и я столкнулся с подобными проблемами. Я изначально скомпилировал с помощью nasm
с elf
, но это не сработало, когда я попытался использовать ld
для связывания объектного файла и создания исполняемого файла.
Я думаю, что ответ на ваш главный вопрос "what would the problem be then?" [to get this to run on 64bit MacOSX]
: Вы используете -f macho32
, но ожидая, что он будет запущен на 64-битной машине, вам нужно изменить параметр команды как -f macho64
. Конечно, это не решит тот факт, что ваш код сборки написан для другой архитектуры (подробнее об этом немного).
Я нашел этот удобный ответ по правильной команде для использования в этом экземпляре для компиляции и ссылки вашего кода (после того, как вы реорганизовали свой код сборки, чтобы вместо этого использовать правильный синтаксис of * nix как duskwuff): nasm -f macho64 main.asm -o main.o && ld -e _main -macosx_version_min 10.8 -arch x86_64 main.o -lSystem
После некоторых поисков, вот что я узнал...
- На Mac 64bit лучше использовать ассемблер
as
вместо nasm
(если вы хотите что-то более родное), но если вам нужен более портативный код (узнайте различия).
-
nasm
не поставляется с установленным по умолчанию способом вывода macho64
- Сборка - это боль в кейстере (это в стороне).
Теперь, когда мой урок обучения не работает...
Вот код, который должен работать на MacOSX 64 с помощью nasm
(если вы обновили nasm
с помощью macho64
, запустите Дастин Шульц):
section .data
hello_world db "Hello World!", 0x0a
section .text
global start
start:
mov rax, 0x2000004 ; System call write = 4
mov rdi, 1 ; Write to standard out = 1
mov rsi, hello_world ; The address of hello_world string
mov rdx, 14 ; The size to write
syscall ; Invoke the kernel
mov rax, 0x2000001 ; System call number for exit = 1
mov rdi, 0 ; Exit success = 0
syscall ; Invoke the kernel
Рабочий код, который я использовал с ассемблером as
, родным для MacOSX64:
.section __TEXT,__text
.global start
start:
movl $0x2000004, %eax # Preparing syscall 4
movl $1, %edi # stdout file descriptor = 1
movq [email protected](%rip), %rsi # The string to print
movq $100, %rdx # The size of the value to print
syscall
movl $0, %ebx
movl $0x2000001, %eax # exit 0
syscall
.section __DATA,__data
str:
.asciz "Hello World!\n"
Команда компиляции: as -arch x86_64 -o hello_as_64.o hello_as_64.asm
Ссылка: ld -o hello_as_64 hello_as_64.o
Выполнить команду: ./hello_as_64
Некоторые полезные ресурсы, которые я нашел в моем путешествии:
as
Ссылка на Assembler OSX: https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/Assembler/Assembler.pdf
Запись 64-битной сборки на Mac OSX: http://www.idryman.org/blog/2014/12/02/writing-64-bit-assembly-on-mac-os-x/
Не удалось связать файл объекта с помощью ld
:
Невозможно связать файл объекта с помощью ld - Mac OS X
OSX i386 SysCalls: http://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/mach/i386/syscall_sw.h
Основные определения системных вызовов OSX: http://www.opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master
OSX Syscall: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/syscall.2.html