Вот как это работает в Linux:
1) Нет, вам не нужно ничего делать. Однако вы можете ограничить экспорт переменных с помощью аргумента командной строки gcc -fvisibility
и явно пометить экспортированные записи атрибутом видимости.
2) Исполняемый файл будет иметь таблицу всех функций, которые он импортирует (это все функции с видимостью по умолчанию). Загрузчик / компоновщик выберет адрес для загрузки библиотек и заполнит эту таблицу непосредственно перед запуском, вызовы этих функций являются косвенными вызовами. (Обратите внимание, что это относится и к общим объектам)
3) Статическое связывание выполняется во время соединения (то есть после компиляции). Фактические адреса подставляются в сборку и являются прямыми вызовами.
Примечание: есть вещь, называемая PIC (позиционно-независимый код). AFAIK, это касается ссылок на данные / функции в одном и том же общем объекте, поэтому компоновщик не должен перезаписывать половину кода библиотеки при загрузке библиотеки, так как код не делает никаких абсолютных ссылок на ее собственные данные. Вы можете попробовать поэкспериментировать с этим.