Из пустого в порожнее
2024-12-20 12:25Взялся я поисследовать Си-шный рантайм. Глянуть, что делается в программе до main() и после. Беру пустую программу:
У меня иногда мелькает вопрос, чем занимаются компьютеры, когда мы на них не глядим. Какие-то бесполезные биты на байты множат. 😀
Компилирую, причём линкую статически, чтобы избежать сложностей динамического загрузчика:$ cat empty.c
int main()
{
// empty
}
Глянем размер бинарника. На процессоре x86_64 под Ubuntu получается 667 килобайт:$ cc -static -Os empty.c -o empty
На процессоре arm64 выходит чуть получше, 497 килобайт:$ size empty
text data bss dec hex filename
667574 23384 22440 713398 ae2b6 empty
Такие объёмы настораживают. Хорошо, запустим и посчитаем количество выполненных машинных команд. На процессоре x86_64:$ size empty
text data bss dec hex filename
497904 22180 21616 541700 84404 empty
На процессоре arm64:$ bintrace -o x86.trace ./empty
$ grep '^0x' x86.trace | wc
170979 1371361 10303769
Ну офигеть просто. Больше ста тысяч команд чтобы просто стартонуть Си-шный код. Неладно что-то в Датском королевстве.$ bintrace -o arm64.trace ./empty
$ grep '^0x' arm64.trace | wc
108719 565684 5186654
У меня иногда мелькает вопрос, чем занимаются компьютеры, когда мы на них не глядим. Какие-то бесполезные биты на байты множат. 😀

no subject
Date: 2024-12-21 00:43 (UTC)no subject
Date: 2024-12-21 00:46 (UTC)И в первом случае тоже так ругается, с _exit.
no subject
Date: 2024-12-21 01:31 (UTC)no subject
Date: 2024-12-21 01:42 (UTC)$ cat empty.c int main() {} #include <unistd.h> void exit(int status) { _exit(status); } $ cc -static empty.c -v ... /usr/libexec/gcc/aarch64-linux-gnu/13/collect2 -plugin /usr/libexec/gcc/aarch64-linux-gnu/13/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/aarch64-linux-gnu/13/lto-wrapper -plugin-opt=-fresolution=/tmp/ccDzVNsd.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lc --build-id --hash-style=gnu --as-needed -Bstatic -X -EL -maarch64linux --fix-cortex-a53-843419 -z relro /usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/crt1.o /usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/crti.o /usr/lib/gcc/aarch64-linux-gnu/13/crtbeginT.o -L/usr/lib/gcc/aarch64-linux-gnu/13 -L/usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu -L/usr/lib/gcc/aarch64-linux-gnu/13/../../../../lib -L/lib/aarch64-linux-gnu -L/lib/../lib -L/usr/lib/aarch64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/aarch64-linux-gnu/13/../../.. /tmp/cc1QUvYS.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/aarch64-linux-gnu/13/crtend.o /usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/crtn.o /usr/bin/ld: /usr/lib/gcc/aarch64-linux-gnu/13/../../../aarch64-linux-gnu/libc.a(exit.o): in function `exit': (.text+0x230): multiple definition of `exit'; /tmp/cc1QUvYS.o:empty.c:(.text+0x8): first defined here collect2: error: ld returned 1 exit statusno subject
Date: 2024-12-21 08:48 (UTC)no subject
Date: 2024-12-21 08:56 (UTC)no subject
Date: 2024-12-21 12:58 (UTC)no subject
Date: 2024-12-21 16:43 (UTC)no subject
Date: 2024-12-21 01:50 (UTC)int main() { // empty } // Tell the compiler incoming stack alignment is not RSP%16==8 or ESP%16==12 __attribute__((force_align_arg_pointer)) void _start() { /* main body of program: call main(), etc */ /* exit system call */ asm("movl $1,%eax;" "xorl %ebx,%ebx;" "int $0x80" ); main(); __builtin_unreachable(); // tell the compiler to make sure side effects are done before the asm statement }_start(), правда, срисован с 32-битной версии, но это можно потом поправить.
gcc -static -nostdlib -Os empty.c -o empty
полученый бинарник "работает"
no subject
Date: 2024-12-21 03:33 (UTC)весь Си-шный рантайм отрезан
Date: 2024-12-21 08:45 (UTC)P.S. отвечаю не чтобы поспорить, а потому, что в примере вызов main() не там стоит. Позорник ... :)