Сначала нужно понять, где заканчивается компиляция и начинается связывание.Компиляция включает в себя получение модуля компиляции (исходный файл C или C ++) и превращение его в объектный файл.Проще говоря, это включает в себя создание фрагментов машинного кода для каждой функции, а также таблицы символов для всех функций и статических (глобальных) переменных.Заполнители используются для любых символов, необходимых модулю компиляции, которые являются внешними по отношению к упомянутому модулю компиляции.
Компоновщик отвечает за загрузку всех объектных файлов и разрешает все символы заполнителя с реальными адресами (илисмещения для машинно-независимого кода).Это помещено в различные разделы, которые могут быть прочитаны динамическим загрузчиком операционной системы при загрузке исполняемого файла.
Так что для подробностей.Чтобы избежать ошибок во время компоновки, компилятор требует, чтобы вы объявили все внешние символы, которые будут использоваться текущим модулем компиляции.Для глобальных переменных необходимо использовать ключевое слово extern
, для функций это необязательно.
Все функции и глобальные переменные, определенные в функции, имеют внешнюю связь (то есть могут ссылаться на другие блоки компиляции), если только это не объявлено с ключевым словом static
(или безымянным пространством имен в C ++).В C ++ vtable также будет иметь символ, необходимый для связывания.
Теперь в C ++, поскольку функции могут быть перегружены, параметры также являются частью имени функции.Поскольку машинный код - это просто адреса и регистры, необходимо добавить дополнительную информацию к имени функции в таблице символов.Эта дополнительная информация о параметрах представлена в виде искаженного имени и гарантирует, что компоновщик ссылается на правильную версию перегруженной функции.
Если вас действительно интересуют подробности, ознакомьтесь с форматом ELF (PDF) , широко используемым в Linux.У Windows другой формат, но можно ожидать, что принципы будут одинаковыми.Имя искажения на платформах Itanuim (и ARM) можно найти здесь .