Hello World с использованием ассемблера x86 на Mac 0SX - PullRequest
14 голосов
/ 27 ноября 2010

Я пытаюсь погрузиться в программирование ассемблера 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

Любой совет относительно того, что я делаю неправильно или отсутствует, был бы очень полезен.спасибо

Ответы [ 4 ]

19 голосов
/ 27 ноября 2010

Вероятно, вам будет проще собрать с помощью gcc, чем пытаться микроуправлять ассемблером и компоновщиком, например,

$ gcc helloWorld.s -o helloWorld

(возможно, вы захотите изменить _start на _main если вы идете по этому пути.)

Кстати, может быть полезно начать с работающей программы на Си и изучить сгенерированный 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 - есть важные различия!

4 голосов
/ 04 марта 2012

Попробуйте:

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>
2 голосов
/ 07 марта 2016

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 HelloWorldString@GOTPCREL(%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

1 голос
/ 09 июля 2019

Код в вопросе выглядит так, как будто он предназначен для 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-битный абсолют, хотя это также поддерживается.)

...