Я хочу скомпилировать свой C-код без (g)libc. Как его отключить и какие функции от него зависят?
Я попробовал -nostdlib, но это не помогает: код компилируется и работает, но я все еще могу найти имя libc в шестнадцатеричном дампе моего исполняемого файла.
-nostdlib должен это сделать, какую версию платформы/компилятора вы используете? Carl Norum 31.03.2010
не помогает, так как это не отключило библиотеку, или вы не могли ничего скомпилировать с этим флагом? Josh Lee 31.03.2010
Вы, вероятно, также хотите -nostartupfiles. 31.03.2010
blog.ksplice.com/2010/03/libc-free-world имеет очень хорошее описание точного управления программным выводом gcc. Редактировать: они (ksplice) только что выпустили часть 2 вышеупомянутого руководства/руководства. См. здесь: blog.ksplice.com/2010/04/libc -free-world-2 В основном это относится к настройкам компоновщика для удаления лишнего мусора из файлов. Adam Shiemke 31.03.2010
Опция -nostartupfiles отсутствует. Вы, вероятно, имеете в виду -nostartfiles, что уже подразумевается -nostdlib. ataylor 31.03.2010
Вот отличная статья об оптимизации двоичных файлов elf, в которой рассказывается об удалении исполняемых файлов из stdlib: [Учебник Whirlwind по созданию действительно крошечных исполняемых файлов ELF для Linux](muppetlabs.com/~breadbox/software/tiny/teensy.html) Michał Trybus 04.04.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() недоступен.
Ответ 2 · рейтинг 9 · Thomas Pornin
Самый простой способ - скомпилировать код C в объектные файлы (gcc -c, чтобы получить несколько *.o файлов), а затем напрямую связать их с компоновщиком (ld). Вам придется связать ваши объектные файлы с несколькими дополнительными объектными файлами, такими как /usr/lib/crt1.o, чтобы получить работающий исполняемый файл (между точкой входа, видимой ядром, и функцией main() есть немного работы) . Чтобы узнать, с чем связываться, попробуйте связать glibc, используя gcc -v: это должно показать вам, что обычно входит в исполняемый файл.
Вы обнаружите, что gcc генерирует код, который может иметь некоторые зависимости от нескольких скрытых функций. Большинство из них находятся в libgcc.a. Также могут быть скрытые вызовы memcpy(), memmove(), memset() и memcmp(), которые находятся в libc, поэтому вам, возможно, придется предоставить свои собственные версии (что несложно, по крайней мере, если вы не слишком требовательны к производительности).
Временами все может проясняться, если вы посмотрите на созданную сборку (используйте флаг -S).