/usr/lib/libc.so
- это скрипт компоновщика, который сообщает компоновщику, что нужно извлечь общую библиотеку /lib/libc.so.6
, а нераспределенная часть /usr/lib/libc_nonshared.a
.
__libc_csu_init
и __libc_csu_fini
взята из/usr/lib/libc_nonshared.a
.Они не найдены, потому что ссылки на символы в не-общих библиотеках должны появляться до архива, который определяет их в строке компоновщика.В вашем случае /usr/lib/crt1.o
(который ссылается на них) появляется после /usr/lib/libc.so
(который их вытягивает), поэтому он не работает.
Исправление порядка в строке ссылкипродвинет вас немного дальше, но тогда вы, вероятно, получите новую проблему, где __libc_csu_init
и __libc_csu_fini
(которые теперь найдены) не могут найти _init
и _fini
.Чтобы вызвать функции библиотеки C, вы также должны связать /usr/lib/crti.o
(после crt1.o
, но до библиотеки C) и /usr/lib/crtn.o
( после библиотеки C), чтосодержать код инициализации и финализации.
Добавление их должно дать вам успешно связанный исполняемый файл.Он все еще не будет работать, потому что он использует динамически связанную библиотеку C без указания, что такое динамический компоновщик.Вам также нужно сообщить компоновщику что-то вроде -dynamic-linker /lib/ld-linux.so.2
(по крайней мере для 32-битного x86; имя стандартного динамического компоновщика различается для разных платформ).
Если вы все это сделаете(по сути, согласно ответу Роба), вы получите то, что работает в простых случаях.Но вы можете столкнуться с дополнительными проблемами с более сложным кодом, поскольку GCC предоставляет некоторые из своих собственных библиотечных процедур, которые могут понадобиться, если ваш код использует определенные функции.Они будут похоронены где-то глубоко внутри каталогов установки GCC ...
Вы можете увидеть, что делает gcc
, запустив его с параметром -v
(который покажет вам команды, которые он вызываетзапускается) или параметр -###
(который просто печатает команды, которые он будет выполнять, со всеми аргументами в кавычках, но фактически ничего не запускает).Вывод будет сбивать с толку, если только вы не знаете, что он обычно вызывает ld
косвенно через один из своих собственных компонентов, collect2
(который используется для склеивания вызовов конструктора C ++ в нужной точке).