Поскольку вы не указали опцию -c (только для компиляции), вы попросили gcc скомпилировать два исходных файла и связать их со стандартной библиотекой (libc) и запуском c во время выполнения (обычно crt0) для создать работающую программу. crt0 пытается войти в вашу программу, вызывая main (), который является неопределенным символом, который компоновщик не может найти. Он не может найти его, потому что у вас нет main () ни в одном из ваших файлов .c, верно?
Итак, к вашему актуальному вопросу: «Почему символы общей библиотеки не разрешаются во время ссылки?» Ответ таков: что вы подразумеваете под «временем ссылки»? По определению, динамически связанная программа не «связана» до тех пор, пока не запустится (или, может быть, даже тогда, в зависимости от вашей системы.)
В системе Linux вы можете увидеть, от каких динамических библиотек зависит программа, с помощью команды ldd (в Mac OS используйте 'otool -L'). Вывод ldd скажет вам, от каких динамических библиотек зависит программа, какие были найдены в пути поиска библиотек, а какие нет (если таковые имеются).
Когда ваша динамическая программа запускается, динамический компоновщик, который был связан с ней, находит и загружает динамические библиотеки, от которых зависит программа, и «исправляет» ссылки на внешние символы. Если что-то из этого не получится, ваша программа не запустится. Один из всех ранее неразрешенных символов был разрешен, динамический компоновщик возвращается, и среда выполнения C вызовет вашу функцию main (). (В Mac OS оно несколько иное, но похоже, что связывание происходит после запуска вашей программы.)