Я хочу скомпилировать свой C-код без (g) libc. Как его деактивировать и какие функции зависят от него?
Я попробовал -nostdlib, но это не помогает: код компилируется и запускается, но я все еще могу найти имя libc в hexdump моего исполняемого файла.
Я хочу скомпилировать свой C-код без (g) libc. Как его деактивировать и какие функции зависят от него?
Я попробовал -nostdlib, но это не помогает: код компилируется и запускается, но я все еще могу найти имя libc в hexdump моего исполняемого файла.
Если вы скомпилируете свой код с помощью -nostdlib, вы не сможете называть какие-либо функции библиотеки C (конечно), но вы также не получите обычный загрузочный код C. В частности, реальная точка входа в программу на linux не является основной(), а скорее функцией, называемой _start(). Стандартные библиотеки обычно предоставляют версию этого, которая запускает некоторый код инициализации, а затем вызывает main().
Попробуйте выполнить компиляцию с помощью gcc -nostdlib:
void _start() {
/* main body of program: call main(), etc */
/* exit system call */
asm("movl $1,%eax;"
"xorl %ebx,%ebx;"
"int $0x80"
);
}
Функция _start() всегда должна заканчиваться вызовом для выхода (или другим неотправляемым системным вызовом, таким как exec). Вышеприведенный пример вызывает системный вызов непосредственно с встроенной сборкой, поскольку обычный выход() недоступен.
http://blog.ksplice.com/2010/03/libc-free-world/ имеет очень хорошее описание точного управления программным выходом gcc.
Изменить: они (ksplice) просто выставляют часть 2 вышеупомянутого учебника/руководства. См. Здесь: http://blog.ksplice.com/2010/04/libc-free-world-2/ В основном это касается настроек компоновщика, чтобы удалить ненужный пух из файлов.
Вот превосходная статья об оптимизации двоичных файлов эльфов, которая охватывает снятие stdlib с исполняемых файлов: Учебное пособие по созданию виртуозных программ для создания действительно исполняемых файлов ELF для Linux
Самый простой способ - скомпилировать C-код для объектных файлов (gcc -c
, чтобы получить некоторые файлы *.o
), а затем связать их напрямую с компоновщиком (ld
). Вам нужно будет связать ваши объектные файлы с несколькими дополнительными объектными файлами, такими как /usr/lib/crt1.o
, чтобы получить рабочий исполняемый файл (между точкой входа, как видно из ядра, и функцией main()
, есть немного работа, которую нужно сделать). Чтобы узнать, с чем нужно связываться, попробуйте установить связь с glibc, используя gcc -v
: это должно показать вам, что обычно входит в исполняемый файл.
Вы обнаружите, что gcc генерирует код, который может иметь некоторые зависимости к нескольким скрытым функциям. Большинство из них находятся в libgcc.a
. Также могут быть скрытые вызовы memcpy()
, memmove()
, memset()
и memcmp()
, которые находятся в libc, поэтому вам, возможно, придется предоставить свои собственные версии (что не сложно, по крайней мере, до тех пор, пока вы не слишком придирчивы к производительности).
Время может быть понятным, если вы посмотрите на произведенную сборку (используйте флаг -S
).