Я хочу изучить ассемблер и решил, что компиляция кода C в ассемблер будет хорошим началом. То есть: cc main.c -S
который компилируется
#include <stdio.h>
int main() {
printf("Hello, World!\n");
}
к
.section __TEXT,__text,regular,pure_instructions
.build_version macos, 14, 0 sdk_version 14, 5
.globl _main ; -- Begin function main
.p2align 2
_main: ; @main
.cfi_startproc
; %bb.0:
stp x29, x30, [sp, #-16]! ; 16-byte Folded Spill
.cfi_def_cfa_offset 16
mov x29, sp
.cfi_def_cfa w29, 16
.cfi_offset w30, -8
.cfi_offset w29, -16
adrp x0, l_.str@PAGE
add x0, x0, l_.str@PAGEOFF
bl _printf
mov w0, #0
ldp x29, x30, [sp], #16 ; 16-byte Folded Reload
ret
.cfi_endproc
; -- End function
.section __TEXT,__cstring,cstring_literals
l_.str: ; @.str
.asciz "Hello, World!\n"
.subsections_via_symbols
... Как видите, я использую aarch64. Но проблема не в этом:
as main.s
все еще нет проблем. Но когда я это делаю ld a.out
:
Undefined symbols for architecture arm64:
"_printf", referenced from:
_main in a.out
ld: symbol(s) not found for architecture arm64
Я уже нашел решение этой проблемы в каком-то малоизвестном, почти совершенно несвязанном сообщении в блоге, поэтому:ld a.out -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/ -lSystem
и теперь это работает.
$ ./a.out
Hello, World!
Итак, вот вопрос: откуда мне знать, как определяется _printf? То есть я уже знаю, как поставить syscall
и написать stdout
, но для чего-то более сложного это станет такой рутиной. Весь смысл в том, чтобы я выучил Ассемблер, но динамическое связывание очень затрудняет это. Если бы я мог статически связать это, это сделало бы все намного проще. Есть ли компилятор, который позволяет это? Кстати, я использую clang:
$ cc --version
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin23.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
Я попробовал следующим образом:
$ cc main.c -static
ld: library not found for -lcrt0.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
и
$ cc main.c -lstatic
ld: library 'static' not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
и
$ cc main.c -static -L /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib/
ld: library not found for -lcrt0.o
clang: error: linker command failed with exit code 1 (use -v to see invocation)
и когда я это сделаю
$ cc main.c -static -S
-static
просто игнорируют.
Я пробовал много чего другого; некоторые я не помню, некоторые я не могу записать. Вы уловили суть. Пожалуйста помоги.
если вы хотите изучить ассемблер, то это не программа для сборки unsigned int fun ( unsigned int x) { return x+5; } значительно лучше. и скомпилировать с оптимизацией...
Статическая ссылка в этом не поможет. cc -S
по-прежнему будет выдавать только сборку исходного кода C, который вы на самом деле компилируете, а не код библиотеки, который был давно скомпилирован поставщиком ОС; cc -S
вообще не делает никаких ссылок. Если вы хотите увидеть ассемблерный код printf, вы можете дизассемблировать стандартную динамическую библиотеку C с помощью objdump --disassemble
, но я могу вам сразу сказать, что дизассемблирование такой длинной и сложной функции не будет очень познавательным.
Если вы хотите узнать, как работает printf, начните с чтения исходного кода C типичной реализации, например. github.com/lattera/openbsd/blob/master/lib/libc/stdio/…. Но опять же, если вы хотите выполнить определенную задачу форматирования на ассемблере, вам, вероятно, лучше начать с нуля.
Вы можете дизассемблировать статический объектный файл, выполнив следующие действия:
gcc -march=native -static main.c -o main.o
objdump -drwC -Mintel main.o > main.s
$ gcc -march=native -static main.c -o main.o ld: библиотека не найдена для -lcrt0.o clang: ошибка: команда компоновщика завершилась неудачей с кодом выхода 1 (используйте -v, чтобы увидеть вызов)
Apple не поддерживает статически связанные двоичные файлы в Mac OS X (см. здесь). Возможно, вам придется переключиться на другую ОС, например Linux.
Честно говоря, мне очень хочется, но я не думаю, что Asahi Linux еще существует, а я слишком беден, чтобы позволить себе еще один компьютер...
Обратите внимание: если вы готовы использовать
cc
для ссылки, он должен добавить соответствующие флаги для вас, чтобы вам не пришлось беспокоиться. Тем не менее, я предполагаю, что все компоненты библиотеки C будут находиться рядомprintf
, поэтому то, что у вас есть, должно работать и для других функций. Для сторонних материалов, даже со статическим связыванием, вам все равно нужно будет указать библиотеку, так что это та же проблема.