Компиляция без libc - PullRequest
       31

Компиляция без libc

52 голосов
/ 31 марта 2010

Я хочу скомпилировать мой C-код без (g) libc. Как я могу деактивировать его и какие функции зависят от него?

Я попробовал -nostdlib, но это не помогает: код компилируется и выполняется, но я все еще могу найти имя libc в hexdump моего исполняемого файла.

Ответы [ 2 ]

67 голосов
/ 31 марта 2010

Если вы скомпилируете свой код с помощью -nostdlib, вы не сможете вызывать какие-либо функции библиотеки C (конечно), но вы также не получите обычный код начальной загрузки C. В частности, реальной точкой входа программы в Linux является не main(), а функция с именем _start(). Стандартные библиотеки обычно предоставляют версию этого, которая выполняет некоторый код инициализации, а затем вызывает main().

Попробуйте скомпилировать это с помощью gcc -nostdlib -m32:

void _start() {

    /* main body of program: call main(), etc */

    /* exit system call */
    asm("movl $1,%eax;"
        "xorl %ebx,%ebx;"
        "int  $0x80"
    );
}

Функция _start() всегда должна заканчиваться вызовом exit (или другим невозвращаемым системным вызовом, таким как exec). Приведенный выше пример вызывает системный вызов напрямую с помощью встроенной сборки, поскольку обычный exit() недоступен.

6 голосов
/ 31 марта 2010

Самый простой способ - это скомпилировать код C в объектные файлы (gcc -c, чтобы получить несколько *.o файлов) и затем связать их напрямую с компоновщиком (ld). Вам нужно будет связать ваши объектные файлы с несколькими дополнительными объектными файлами, такими как /usr/lib/crt1.o, чтобы получить работающий исполняемый файл (между точкой входа, видимой ядром, и функцией main(), есть немного работа, которую нужно сделать). Чтобы узнать, с чем связываться, попробуйте установить связь с glibc, используя gcc -v: это должно показать вам, что обычно входит в исполняемый файл.

Вы обнаружите, что gcc генерирует код, который может иметь некоторые зависимости от нескольких скрытых функций. Большинство из них находятся в libgcc.a. Также могут быть скрытые вызовы memcpy(), memmove(), memset() и memcmp(), которые находятся в libc, поэтому вам, возможно, придется предоставить свои собственные версии (что не сложно, по крайней мере, пока вы не слишком требовательны к производительности).

Вещи могут иногда становиться понятнее, если вы посмотрите на произведенную сборку (используйте флаг -S).

...