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

У меня иногда мелькает вопрос, чем занимаются компьютеры, когда мы на них не глядим. Какие-то бесполезные биты на байты множат. 😀

Date: 2024-12-21 00:43 (UTC)
archaicos: Шарж (Default)
From: [personal profile] archaicos
А если _Exit() из stdlib.h?

Date: 2024-12-21 01:31 (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Это проблемы статической линковки. Если libc.a упомянута явно, то это multiple definition, а если -lc, то вроде не должно.

Date: 2024-12-21 08:48 (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Выходит, писать на "голом Си" (алгоритмический язык), вызывая лишь те внешние функции/системные вызовы, которые хочется, и отказаться от всего остального библиотечного скарба, больше нельзя? Досадно.

Date: 2024-12-21 12:58 (UTC)
dmarck: (Default)
From: [personal profile] dmarck
-nostdinc -nostdlib ещё существуют, но это сущий адЪ

Date: 2024-12-21 16:43 (UTC)
spamsink: (Default)
From: [personal profile] spamsink
Они, собственно, и не для этого. Хочется-то stdlib оставить, а только от stdio избавиться.

Date: 2024-12-21 01:50 (UTC)
From: [personal profile] h1uke
вот так получается:


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

$ size empty
   text    data     bss     dec     hex filename
   152     0        0       152     98  empty


полученый бинарник "работает"

From: [personal profile] h1uke
ну, не "весь", а "стандартный". Очень часто именно это и нужно.

P.S. отвечаю не чтобы поспорить, а потому, что в примере вызов main() не там стоит. Позорник ... :)