👁🗨Hello world~Компоновщик: Как из кода получается программаЧасть 2: Основные типы данных• В прошлый раз мы узнали что такое компоновщик, сегодня начинаем разбираться в его внутренностях. Этот пост будет длинным.• Компоновщик работает с небольшим количеством базовых типов данных: символы, перемещения (релокации) и содержимое (секции). Они определяются во входных объектных файлах.• Символ — это именованные сущности, которые представляют функции, переменные и другие объекты в программе.• Например, в объектном файле, сгенерированном из кода на C, будет символ для каждой функции, а также для каждой глобальной и статической переменной. Значение такого символа просто смещение внутри содержимого, такой тип называется определённым символом.• Символы также используются для указания ссылки на имя, определённое в другом объектном файле. Такая ссылка называется неопределённым символом (существуют и другие типы символов). В процессе компоновки, компоновщик назначает адрес каждому определённому символу и разрешает каждый неопределённый символ, находя соответствующий определённый символ с таким же именем.• Перемещения (релокации) — это инструкции для линкера о том, как исправить адреса в коде после размещения секций в памяти. Большинство релокаций ссылаются на символ и на смещение внутри содержимого. Простая и часто используемая релокация выглядит так: "установи это место в содержимом в значение этого символа плюс этот аддитив". В процессе компоновки, компоновщик выполняет все указанные релокационные вычисления.• Содержимое (секции) — это то, как должна выглядеть память во время выполнения программы. Оно имеет размер, массив байтов и тип. В него входят: • Машинный код, сгенерированный компилятором и ассемблером (текст, .text). • Значения инициализированных переменных (данные, .data). • Статические безымянные данные, такие как строковые константы и таблицы переходов (только для чтения, .rodata). • Неинициализированные переменные, в этом случае массив байтов обычно опускается и считается заполненным нулями (BSS, .bss).• Все эти типы вы могли видеть, если пытались дизассемблировать любую программу.• Компилятор и ассемблер формируют нужное содержимое, но компоновщик, по сути, не анализирует его, а работает с ним как с сырыми данными. Компоновщик читает содержимое из каждого файла, объединяет его, сортируя по типам, применяет релокации и записывает результат в исполняемый файл.• Уже на этом этапе можно понять основные шаги, которые выполняет любой компоновщик: • Чтение входных объектных файлов. • Построение таблицы символов. • Определение расположения содержимого в выходном исполняемом файле. • Чтение данных содержимого и релокаций. • Запись полной таблицы символов (но это не обязательно).• Удачи!• Поддержать автора монеткой: @v_meshke
Оставить комментарий/отзыв