Невозможно связать файл объекта с помощью ld - Mac OS X

/*********
exit.asm
*/

[SECTION .text]

global _start


_start:
xor eax, eax
xor ebx, ebx
mov al, 1
int 0x80

//****************************

Сначала я использовал nasm -f elf exit.asm для создания объектного файла.

тогда я выполнил следующую команду "ld" на моей Mac OS X 10.7, у нее есть эти выходы и предупреждение, я попытался запустить ее на моей 32-битной Linux-машине, все прошло отлично, Не могли бы вы объяснить, почему бы линкер не работал на моем Mac?

Спасибо!

Alfred says: ld -o exiter exit.o
ld: warning: -arch not specified
ld: warning: -macosx_version_min not specified, assuming 10.7
ld: warning: ignoring file exit.o, file was built for unsupported file format ( 0x7f 0x45      0x4c 0x46 0x 1 0x 1 0x 1 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 ) which is not the   architecture being linked (x86_64): exit.o
Undefined symbols for architecture x86_64:
  "start", referenced from:
    implicit entry/start for main executable
ld: symbol(s) not found for inferred architecture x86_64

после того, как я укажу свою арку и версию, я получил:

Alfred says: ld -arch x86_64 -macosx_version_min 10.7 -o exiter exit.o
ld: warning: ignoring file exit.o, file was built for unsupported file format ( 0x7f 0x45     0x4c 0x46 0x 1 0x 1 0x 1 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 0x 0 ) which is not the   architecture being linked (x86_64): exit.o
 Undefined symbols for architecture x86_64:
 "start", referenced from:
    implicit entry/start for main executable
 ld: symbol(s) not found for architecture x86_64

Ответ 1

Получение ссылки на программу - это легкая часть:

  • Измените _start на start
  • $ nasm -f macho exit.asm
  • $ ld -arch i386 -o exiter exit.o

Проблема заключается в том, что exit.asm вызывает системный вызов i386 Linux exit() ( EAX= 1), и программа НЕ выйдет с нулевым статусом, как предполагалось в OS X.

Системные вызовы

Системный вызов - это запрос к ядру. exit(), в отличие от sqrt(), должен сделать запрос к программному компоненту с более высокими привилегиями в его реализации, поскольку он завершает запущенную программу. Приложения не могут самостоятельно создавать или завершать процессы. Системные вызовы предоставляют приложениям возможность просить ядро ​​выполнять действия от их имени.

Создание syscall происходит примерно так:

  • Приложения описывают операцию, которую они хотят выполнить, помещая данные в регистры процессора (или память, на которую указывают регистры), например.
    • Значение 1 в EAX - это номер системного вызова exit.
    • Значение 0 в EBX ( EBX было очищено xor) - это первый аргумент для syscall, статус выхода.
  • Приложения выдают команду, которая заставляет управление передавать в ядро, например.
    • int 80 на i386
    • sycall на x86-64
    • svc в режиме Thumb на ARMv7
  • Ядро проверяет запрос и решает его выполнить или отклонить.
  • Ядро передает управление обратно в приложение с возвращаемым значением в согласованном местоположении, например. EAX на i386.

Linux и OS X предоставляют функцию void exit(int) для программ C, но не согласны с подробностями о том, как описать этот запрос ядру. Код в exit.asm находится на том же уровне, что и реализация функции _exit() в libc.

Даже между различными архитектурами, работающими под управлением Linux, номера системных вызовов и соглашения о вызовах различаются. например В x86-64 Linux exit(0) чаще всего выдается следующим образом:

xor rdi, rdi
mov al, 60
syscall

Это можно увидеть, разобрав _exit в /lib64/libc.so.6.

Не может ли мы просто вызвать exit() из libc Вместо?

Вы можете. Но вам нужно связать программу с libc. Это разница между ссылкой exit.asm выше:

$ cc -m32 -nostdlib exit.o -o exiter

и

выход-libc.asm

extern exit
global main
main:
push 0
call exit

который должен быть связан с:

$ cc -m32 exit-libc.o -o exit-libc

Попробуйте это и посмотрите размер файла.

Ответ 2

Mac OS X не использует ELF, поэтому вы захотите создать объект Mach-O для связи с этой системой. На моей машине nasm появляется только поддержка 32-битного вывода, поэтому вам также нужно будет сопоставить эту архитектуру при компоновке.

Мне также пришлось изменить _start на start, чтобы связать его.

Вот рабочий пример с вашим кодом:

$ cat exit.asm 
[SECTION .text]

global start

start:
xor eax, eax
xor ebx, ebx
mov al, 1
int 0x80
$ nasm -f macho exit.asm 
$ ld -arch i386 -macosx_version_min 10.7  -o exiter exit.o 
$ ./exiter 
$ echo $?
236

Обратите внимание, что программа, вероятно, не делает то, что вы хотите в Mac OS X, поскольку она не выполняет системные вызовы так же, как Linux.

Ответ 3

В большинстве случаев, когда вы получаете эту ошибку:

ld: warning: PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not 
allowed in code signed PIE, but used in _start from hello.o. To fix this 
warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie

Это потому, что он ищет вашу функцию "main()" (метку) мне ярлык "start:". Всегда лучше указывать основную метку с помощью "ld -e".

Для nasm:

-o hello.tmp - outfile
-f macho - specify format
Linux - elf or elf64
Mac OSX - macho

Для ld:

-arch i386 - specify architecture (32 bit assembly)
-macosx_version_min 10.6 (Mac OSX - complains about default specification)
-no_pie (Mac OSX - removes ld warning)
-e main - specify main symbol name (Mac OSX - default is start)
-o hello.o - outfile

Для оболочки:

./hello.o - execution

Однострочник:

nasm -o hello.tmp -f macho hello.s && ld -arch i386 -macosx_version_min 10.6 -no_pie -e _main -o hello.o hello.tmp && ./hello.o

Сообщите мне, если это поможет!

Я написал, как это сделать в моем блоге:

http://blog.burrowsapps.com/2013/07/how-to-compile-helloworld-in-intel-x86.html

Для более подробного объяснения я объяснил здесь свой Гитуб:

https://github.com/jaredsburrows/Assembly

Ответ 4

Стандартный mac gcc не будет связывать объекты эльфа. Для людей, которым нужно придерживаться формата эльфа и разрабатывать на Mac, вам нужен кросс-компилятор...

http://crossgcc.rts-software.org/doku.php?id=compiling_for_linux

Затем вы можете продолжить что-то похожее на это...

/usr/local/gcc-4.8.1-for-linux32/bin/i586-pc-linux-ld -m elf_i386 -T link.ld -o kernel kasm.o kc.o