Как работает связывание и искажение имени? - PullRequest
0 голосов
/ 30 июня 2011

Давайте возьмем этот пример кода

//header
struct A { };
struct B { };
struct C { };
extern C c;

//code
A myfunc(B&b){ A a; return a; }
void myfunc(B&b, C&c){}
C c;

Позволяет делать эту строку построчно, начиная с раздела кода.Когда компилятор видит первый метод myfunc, он не заботится об A или B, потому что его использование является внутренним.Каждый файл C ++ будет знать, что он принимает, что он возвращает.Хотя для каждой из двух перегрузок должно быть имя, как это выбирается и как компоновщик узнает, что и что означает?Следующим является C c;Однажды у меня была ошибка, когда компоновщик не смог бы восстановить, поэтому мне был предоставлен доступ к C в других файлах C ++.Это было потому, что cpp не знал, что c был extern, и мне пришлось пометить его как extern в заголовке, прежде чем я смог успешно соединиться.Теперь я не уверен, имеет ли тип класса какое-либо отношение к компоновщику и переменной C. Я не знаю, как будет задействован RTTI, но я знаю, что C должен быть виден другими файлами.

Какработа компоновщика и искажение имени и тому подобное.

Ответы [ 2 ]

2 голосов
/ 30 июня 2011

Сначала нужно понять, где заканчивается компиляция и начинается связывание.Компиляция включает в себя получение модуля компиляции (исходный файл C или C ++) и превращение его в объектный файл.Проще говоря, это включает в себя создание фрагментов машинного кода для каждой функции, а также таблицы символов для всех функций и статических (глобальных) переменных.Заполнители используются для любых символов, необходимых модулю компиляции, которые являются внешними по отношению к упомянутому модулю компиляции.

Компоновщик отвечает за загрузку всех объектных файлов и разрешает все символы заполнителя с реальными адресами (илисмещения для машинно-независимого кода).Это помещено в различные разделы, которые могут быть прочитаны динамическим загрузчиком операционной системы при загрузке исполняемого файла.

Так что для подробностей.Чтобы избежать ошибок во время компоновки, компилятор требует, чтобы вы объявили все внешние символы, которые будут использоваться текущим модулем компиляции.Для глобальных переменных необходимо использовать ключевое слово extern, для функций это необязательно.

Все функции и глобальные переменные, определенные в функции, имеют внешнюю связь (то есть могут ссылаться на другие блоки компиляции), если только это не объявлено с ключевым словом static (или безымянным пространством имен в C ++).В C ++ vtable также будет иметь символ, необходимый для связывания.

Теперь в C ++, поскольку функции могут быть перегружены, параметры также являются частью имени функции.Поскольку машинный код - это просто адреса и регистры, необходимо добавить дополнительную информацию к имени функции в таблице символов.Эта дополнительная информация о параметрах представлена ​​в виде искаженного имени и гарантирует, что компоновщик ссылается на правильную версию перегруженной функции.

Если вас действительно интересуют подробности, ознакомьтесь с форматом ELF (PDF) , широко используемым в Linux.У Windows другой формат, но можно ожидать, что принципы будут одинаковыми.Имя искажения на платформах Itanuim (и ARM) можно найти здесь .

0 голосов
/ 30 июня 2011
...