Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: u149796Ответов: 2

Я хочу скомпилировать свой 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

gcccglibcdemolibc

Ответы

Ответ 1 · рейтинг 80 · ataylor

Если вы скомпилируете свой код с помощью -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).

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы