Как я могу запустить этот код сборки на 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