Статическая привязка GCC и отдельный загрузчик

Пытаюсь понять процесс статической линковки, загрузки GCC:

У меня есть следующая игрушечная программа

#include "stdio.h"

int main() {

  fprintf(stdout, "Hello World \n");

  return 0 ;
}

Я могу скомпилировать его и запустить файл следующим образом:

       gcc -static -std=gnu99  -Wall -Wno-unused -g test.c -o test;

Но как только я пытаюсь разделить процесс компиляции и компоновки следующим образом:

       gcc -static -std=gnu99  -Wall -Wno-unused -g test.c -c;

       ld -o  test -T link.lds test.o 

где ссылка.lds

SECTIONS

{
   . = 0x10000;
   .text : { *(.text) }
   . = 0x8000000;
   .data : { *(.data) }
   .bss : { *(.bss) }
}

Я получаю сообщение об ошибке "неопределенная ссылка на stdouttest.o: в функции `main':

test.c:(.text+0x7): undefined reference to `stdout'
test.c:(.text+0x1e): undefined reference to `fwrite'

Если я попытаюсь добавить флаг -lc к ld, он скажет мне, что он не найден. Я пытался запустить gcc с параметрами -lc и/или -static-libgcc, но у меня та же проблема.

Что я делаю не так?


person user1018513    schedule 22.10.2014    source источник
comment
У меня нет проблем с запуском gcc -static -std=gnu99 -Wall -Wno-unused -g test.c -c && gcc test.o -o test с gcc-4.4.7   -  person Peixu Zhu    schedule 22.10.2014
comment
Это будет работать нормально. Но я специально смотрю на использование его с загрузчиком (ld)   -  person user1018513    schedule 22.10.2014
comment
затем вы должны связать с -lc, добавив другие посохи, такие как crt1.o, crtn.o, crtbegin.o, crtend.o и т. д., которые сопровождают ваш gcc. вы можете запустить gcc -v test.o, чтобы проверить, как gcc выполняет эту работу.   -  person Peixu Zhu    schedule 22.10.2014
comment
Мне удалось дойти до этого: gcc -static test.c -lc -static-libgcc -c ; ld test.o -o test -lc --entry main --section-start=.txt=0x30000 --section-start=.bss=0x400000 --section-start=.data=0x500000 Но теперь я получаю ./test : бинарный файл не найден. В нем говорится, что файл динамически связан, когда я указываю его как статический. Что касается репликации вывода ld, он опирается на объектный файл в /tmp/...o, который, когда я повторно запускаю команду ld, не существует. Это почему я не использую повторно вывод -v   -  person user1018513    schedule 22.10.2014
comment
Избегайте использования test в качестве имени исполняемого файла, так как это встроенная оболочка. Добавьте -v к своим gcc командам, чтобы понять, что происходит, например. скомпилировать с gcc -v -static -std=gnu99 -Wall -Wno-unused -g test.c -o mytest   -  person Basile Starynkevitch    schedule 22.10.2014
comment
@raison, какой смысл в crtbeginT.o и crtend.o? В данном случае они не нужны. Однако crt1.o, crti.o и crtn.o необходимы. Где описано, что из себя представляет каждый из них?   -  person Z boson    schedule 22.10.2014
comment
dev.gentoo.org/~vapier/crt.txt   -  person Z boson    schedule 22.10.2014
comment
wiki.osdev.org/Calling_Global_Constructors   -  person Z boson    schedule 22.10.2014
comment
@Zboson с gcc-4.4.7, centos 6.5, они необходимы. без crtbegin.o и crtend.o ld сообщит об ошибке требования.   -  person Peixu Zhu    schedule 23.10.2014
comment
@raison, в данном случае с gcc-4.8.2 Linux Mint 17 в них нет необходимости. Но мне больше интересно узнать, для чего они нужны?   -  person Z boson    schedule 23.10.2014


Ответы (2)


Do

gcc -v -static -std=gnu99 -Wall -Wno-unused -g test.c

и найдите тег collect2.

В моем случае это

collect2 --sysroot=/ --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o test /usr/lib/gcc/x86_64-linux-gnu/4.8/. ./../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib -L/lib/ x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux- gnu/4.8/../../.. /tmp/ccoR98Xr.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend .o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o

Вы должны заменить временный объектный файл. В моем случае я заменил /tmp/ccoR98Xr.o на test.o. Тогда сделайте

gcc -c -std=gnu99 -Wall -Wno-unused -g test.c

ld --sysroot=/ --build-id -m elf_x86_64 --hash-style=gnu --as-needed -static -z relro -o test /usr/lib/gcc/x86_64-linux-gnu/4.8/. ./../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/4.8/crtbeginT.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../lib -L/lib/ x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux- gnu/4.8/../../.. test.o --start-group -lgcc -lgcc_eh -lc --end-group /usr/lib/gcc/x86_64-linux-gnu/4.8/crtend.o / usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/crtn.o

  • Он ссылается на объектные файлы: crt1.o, crti.o, crtbeginT.o, crtend.o и crtn.o.
  • Он ссылается на библиотеки: libgcc.a, libgcc_eh.a и libc.a.
  • Вы можете заменить --start-group -lgcc -lgcc_eh -lc --end-group на -lgcc -lc -lgcc_eh -lc, если хотите.

Зная это, мы можем просто это

ln -s `gcc -print-file-name=crt1.o`
ln -s `gcc -print-file-name=crti.o`
ln -s `gcc -print-file-name=crtn.o`
ln -s `gcc -print-file-name=libgcc_eh.a`
ln -s `gcc -print-file-name=libc.a`

gcc -c -std=gnu99 -Wall -Wno-unused -g test.c
ld -m elf_x86_64 -o test crt1.o crti.o test.o libc.a libgcc_eh.a libc.a crtn.o

Я не использовал crtbeginT.o, crtend.o и libgcc.a, потому что без них все работало.

person Z boson    schedule 22.10.2014

Взгляните на это, strace выполняет свою работу (показывает вам секреты), но вскоре вы поймете, что в нем есть множество опций... Вам нужно связать несколько вещей (из GNU C lib), чтобы получить исполняемый файл, а не только ваш объект... Вы можете добавить grep 'exec' в конце концов, чтобы сделать его чище.

Уххх, также вам нужно сделать это:

as obj.s -o obj.o

Используйте ассемблер GNU для преобразования вашего .s в .o, а затем свяжите его с ld.

person Yuhong    schedule 22.10.2014