Версия для печати

Архив документации на OpenNet.ru / Раздел "Программирование, языки" (Многостраничная версия)
Вперед Назад Содержание

Редактор связей gnu ld



Описание редактора связей gnu ld

1. Введение

2. Запуск

3. Язык управления линкером


Вперед Назад Содержание
Вперед Назад Содержание

Редактор связей gnu ld



Описание редактора связей gnu ld

1. Введение

2. Запуск

3. Язык управления линкером


Вперед Назад Содержание
Вперед Назад Содержание

1. Введение

LD объединяет несколько объектных и архивных файлов, группирует сегменты данных и очищает таблицу символов.

LD поддерживает "Язык управления линкером", являющийся надмножеством "Языка управления линкером" фирмы AT&T, для обеспечения полного контроля над процессом линковки.

Данная версия LD использует библиотеку BFD для работы с объектными файлами. Это позволяет ld читать, объединять и записывать файлы в различных форматах - для примера, COFF или a.out. Файлы в различных форматах могут быть слинкованы вместе для создания файла в любом формате, поддерживаемом библиотекой BFD. ( См. Главу 5 для более полной информации.)

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


Вперед Назад Содержание
Вперед Назад Содержание

2. Запуск

LD создавался для обеспечения максимально возможного контроля за процессом линковки и совместимости с другими линкерами. В результате в LD большое число опций, управляющих поведением линкера.

2.1 Опции командной строки.

Список опции которые используются в LD:

 ld  [ -o <имя выходного файла> ] <объектный файл>
 [-A<архитектура>] [-b <входной-файл>]
 [-Bstatic] [-Bdynamic] [-Bsymbolic]
 [-c <MRI-имя-файла>] [-d | -dc | -dp]
 [-defsym <символ=выражение>] 
 [-dinamic-linker файл] [-embeded-relocs]
 [-e <вхождение>] [-F] [-F<формат>]
 [-format <входной-файл>] [-g] [-G <значение>]
 [-help] [-i] [-l имя] [-L <католог-поиска>]
 [-M] [-map <файл-карты>] [-m <эмуляция>]
 [-N| -n] [-noinhabit-exec] [-no-keep-memory]
 [-oformat <формат выходного файла>] [-R <имя-файла>]
 [-relax] [-retain-symbols-file <имя-файла>]
 [-r| -Ur] [-rpath <имя-директории>] [-rpath-link <имя-директории>]
 [-S] [-s] [-soname <имя>] [-shared]
 [-sort-common] [-stats] [-Т <командный-файл>]   
 [-Ttext <орг>] [-Tdata <орг>] 
 [-Tbss <орг>] [-t] [-tradional-format]
 [-u <cимвол>] [-V] [-v] [--verbose] [-version]
 [-warn-common] [-warn-constructors] [-warn-once]
 [-y <символ>] [-X] [-x] 
 [-( <архивы> -)]
 [--start-group <архивы> --end-group]
 [-split-by-reloc <число>] [-split-by-file]
 [-whole-archive] 

Такое изобилие опций может показаться отталкивающим, но на самом деле большинство опций используются крайне редко. Например, обычно LD используется для линковки стандартных объектных файлов Юникса на стандартной Юникс системе. На такой системе для линковки файла hello.o в запускаемый файл достачно набрать следующую команду:

 ld -o <имя-выходного-файла> /lib/crt0.o hello.o -lc
В результате выполнения этой команды LD создаст файл <имя-выходного-файла> как результат линковки файлов '/lib/crt0.o' с 'hello.o' и библиотеки 'libc.a', которая должна находится в стандартных директориях поиска. (См. опцию -L).

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

Исключения - опции, которые используются обычно больше одного раза: '-A', '-b' (или -format), '-defsym', '-L', '-l', '-R', '-u' и '-(' (или --start-group).

Имена объектных файлов, которые должны быть слинкованы вместе, могут находится в любом месте командной строки за исключением места между опцией и ее аргументом.

Обычно линкер запускается хотя бы с одним объектным файлом, но при желании можно указать другие формы двоичных файлов, используя опции '-l' и '-R', или используя "язык управления линкером" (далее ЯУЛ). Если никакие двоичные файлы не указаны, линкер выдаст предупреждающее сообщение "No input files" ("никаких входных файлов") и прекратит свое выполнение.

Если линкер не может распознать тип формата объектного файла, он будет считать, что это файл, содержащий команды ЯУЛ (далее скрипт или скрипт файл). Скрипт, определенный таким путем, будет добавлен к главному скрипту LD, используемому для линковки (или любому другому скрипту, используемому по умолчанию, или к скрипту, определенному с помощью опции '-T'). Эта возможность позволяет LD работать с файлами, которые кажутся объектными, а на самом деле являются скриптами.

Для опций, название которых состоит из одной буквы, аргумент опции может идти как сразу после названия опции, так и после пустого символа (например, пробела).

Для опций, имена которых состоят из нескольких букв, аргумент должен идти либо после пустого символа, либо после знака равенства ('='). Перед названием опции может быть как два тире, так и одно. Например, '-oformat' и '--oformat' описывают одинаковые опции.

 -A<архитектура>
В текущей версии ld эта опция используется только для процессоров семейства Intel 960. В конфигурации LD для этого процессора аргумент <архитектура> идентифицирует используемую в системе модификацию процессора и, руководствуясь полученной информацией, включает дополнительные диагностические процедуры и изменяет некоторые значения по умолчанию (более полную информацию см. в параграфе 4.2). В будущих версиях LD будет, вероятно, обеспечена поддержка и других семейств процессоров.

 -b <входной-файл>
LD может быть сконфигурирован для поддержки нескольких форматов объектного файла. Если LD сконфигурирован таким образом, возможно использовать опцию '-b' для указания типа объектного файла для файлов, которые будут описаны после этой опции в командной строке. Даже когда LD сконфигурирован для поддержки нескольких форматов объектных файлов, совсем необязательно каждый раз при запуске LD указывать тип объектного файла, так как по умолчанию LD использует наиболее распространенный в текущей архитектуре формат объектного файла. <входной-файл> - это текстовая строка, содержащая название формата объектного файла, поддерживаемого библиотекой BFD (чтобы получить список поддерживаемых форматов, необходимо запустить команду 'objdump -i'). '-format' имеет такой же эффект, как и команда ЯУЛ 'TARGET' (См. главу 5). Возможно использование этой опции при линковке файлов с нестандартным объектным форматом. Также возможно использование этой опции при линковке файлов с разными форматами путем помещения опции '-b' перед каждой группой объектных файлов одного формата. Формат, используемый по умолчанию, берется из внешней переменной окружения 'GNUTARGET' (См. 2.2). Можно указать используемый формат, используя ЯУЛ команду TARGET (См. 3.6).

 -Bstatic
Не использовать при линковке разделяемые библиотеки. Эта опция имеет смысл только на платформах, поддерживающих разделяемые библиотеки.

 -Bdynamic
Использовать динамические библиотеки. Эта опция имеет смысл только на платформах, поддерживающих разделяемые библиотеки. Эта опция на большинстве платформ обычно установлена по умолчанию.

 -Bsymbolic
При создании разделяемой библиотеки связать ссылки на глобальные имена с описаниями в разделяемой библиотеке. Эта опция имеет смысл только на ELF платформах, которые поддерживают разделяемые библиотеки.

 -c MRI-имя-файла
Для обеспечения соместимости с линкерами, создаными MRI, LD поддерживает скрипты, написанные на ЯУЛ линкеров MRI (См. приложение А). Для использования скриптов, написанных на ЯУЛ LD, используйте опцию '-T'. Если LD не может найти файл <MRI-имя-файла> в текущем каталоге, он ищет его в директориях, указанных опцией '-L'.

 -d
 -dc
 -dp
Эти три опции эквивалентны. Несколько форм поддерживаются для обеспечения совместимости с другими линкерами. Они позволяют отводить место для переменных, даже если формат выходного файла - переместимый. Команда скрипта FORCE_COMMON_ALOCATION имеет такое же действие (см. 3.6).

 -defsym символ=выражение 
Создает глобальный символ в выходном файле, содержащий абсолютный адрес в заданном выражении. Вы можете использовать эту опцию столько раз, сколько Вам необходимо для определения множества символов в командной строке. Поддерживается ограниченный набор арифметических операций. Вы можете задать шестнадцатиричную константу, или имя существующего символа, или использовать плюс или минус для сложения или вычитания шестнадцатиричных констант или символов. Если Вам необходимы более сложные выражения, возможно использование ЯУЛ из скрипта (см. 3.2.6). Замечание: не должно быть пропусков между символом, знаком равенства и выражением.

 -dinamic-linker файл  
Устанавливает имя динамического линкера. Эта опция имеет смысл только при создании динамических ELF файлов. Использование стандартного динамического линкера предпочтительнее; не используйте эту опцию, если Вы не уверены в своих действиях.

 -embedded-relocs
Эта опция имеет смысл, только если линкуется позиционно-независимый код для архитектуры MIPS, созданный с помощью опции '-memembeded-pic' GNU компилятора и ассемблера. Эта опция заставляет линкер создать таблицу, которая может быть использована во время выполнения для перемещения любых данных, которые были статически проинициализированы в указателе (подробности - см. текст в файле 'testsuite/ld-mpic').

 -e вхождение 
Используйте вхождение для уточнения символа, с которого будет начинаться выполнение Вашей программы, отличного от принятого по умолчанию (см. 3.5).

 -F 
 -Fформат
Игнорируется. Некоторые старые линкеры используют эту опцию для определения формата объектного файла как для входных, так и для выходных объектных файлов. Вместо этой опции LD использует опции '-b' или '-format'. Опции '-F' поддерживаются для совместимости со скриптами, написанными для старых линкеров.

 -format <входной-файл>
Синоним опции '-b'.

 -g 
Игнорируется. Поддерживается для обеспечения совместимости с остальными утилитами.

 -G значение 
Устанавливает максимальый размер объектов для оптимизации с использованием регистра GP под форматом объектного файла MIPS ECOFF. Игнорируется для остальных форматов объектного файла.

 -help 
Выводит список опций командной строки и завершает выполнение линкера.

 -i 
Выполняет инкрементальную линковку аналогично опции '-r'.

 -l имя 
Добавляет архивный файл с указанным именем в список файлов для линковки. Эта опция может быть использована неограниченное количество раз. LD будет искать по всем указанным путям архивный файл (библиотеку) с именем lib<имя>.a

 -L <католог-поиска> 
Добавляет каталог поиска в список каталогов, в которых LD будет искать архивные файлы (библиотеки) и управляющие скрипты LD. Вы можете использовать эту опцию неограниченное число раз. Директории просматриваются в том порядке, в котором они указываются в командной строке. Указанные каталоги просматриваются прежде каталогов по умолчанию. Все файлы, указанные в опции '-l', будут искомы во всех директориях, указанных в опции '-L', независимо от порядка, в котором они находились в командной строке. Каталог по умолчанию зависит от типа эмуляции, который в настоящий момент использует LD, и в некоторых случаях от того, как он был сконфигурирован (см. 2.2). Каталоги также могут быть указаны в скрипте линкера с помощью команды SEARCH_DIR. Каталоги, описанные таким путем, просматриваются с той позиции, с которой скрипт встретился в командной строке.

 -M 
Печатает карту линковки - диагностическую информацию о том, куда символы были размещены линкером, а также информацию о глобальных переменных.

 -map <файл-карты>
Напечатать карту линковки в файл с именем <файл-карты> - диагностическую информацию о том, куда символы были размещены линкером, а также информацию о размещении глобальных переменных.

 -m эмуляция 
Включает режим эмуляции. Вы можете получить список доступных эмуляций с помощью опций '--verbose' или '-V'. Эмуляция, принятая по умолчанию, зависит от того, как LD был сконфигурирован.

 -N 
Делает секции текста и данных доступными для чтения и записи. Также не делает постраничного выравнивания сегмента данных. Если формат объектного файла поддерживает магические номера в стиле UNIX-а, то LD помечает выходной файл как OMAGIC.

 -n 
Делает сегмент текста доступным только для чтения и помечает выходной файл как NMAGIC, если это возможно.

 -noinhabit-exec 
Создает выходной файл независимо от появления ошибок в процессе линковки. Обычно линкер не создает выходного файла, если обнаруживает какие-нибудь ошибки в процессе линковки.

 -no-keep-memory
Обычно LD в целях оптимизации кэширует таблицы имен входных файлов в памяти. Эта опция говорит LD не использовать данную оптимизацию и он будет считывать заново таблицы имен по необходимости. Данная опция используется для того, чтобы избежать нехватки памяти при линковки очень больших файлов.

 -о <выходной-файл> 
Задает имя выходного файла. Если эта опция не определена, то по умолчанию используется имя "a.out". Команда ЯУЛ OUTPUT тоже может задавать имя выходного файла.

 -oformat <формат выходного файла>
LD может быть сконфигурирован для поддержки нескольких форматов объектного файла. Если Ваш LD сконфигурирован таким образом, Вы можете использовать опцию '-oformat' для определения формата объектного файла, который будет использоваться в выходном файле. Даже если LD сконфигурирован для поддержки множества форматов объектного файла, обычно Вы не должны определять это, так как LD будет использовать формат объектного файла по умолчанию. <формат выходного файла> - это текстовая строка, содержащая имя формата объектного файла, поддерживаемого библиотекой BFD. Вы можете получить список доступных форматов объектного файла с помощью команды "objdump -i". Команда ЯУЛ OUTPUT_FORMAT может также задавать формат объектного файла, но данная опция переопределяет его (см 5).

 -R имя файла
Читает таблицу имен и их адреса из указанного файла, но не помещает их в выходном файле. Это позволяет создать выходной файл, в котором описанные имена будут находится по абсолютным позициям памяти, определенным в других программах.

 -relax 
Эта опция является архитектурно зависимой. В настоящей момент эта опция поддерживается только на H8/300 и на intel960 (см 4.1, 4.2). На некоторых платформах опция '-relax' совершает глобальную оптимизацию, которая становится возможной когда линкер узнает адреса в программе, такие как адреса меток и т.п. На платформах для которых это не поддерживается опция '-relax' игнорируется.

 -retain-symbols-file <имя-файла>
Использовать только символы описанные в указанном файле, игнорируя все остальные. Используемый файл содержит по одному имени символа на строке. Данная опция особенно необходима в окружениях (таких как VxWorks), где большая таблица имен изменяется во время выполнения программы для оптимизации работы с памятью. Опция '-retain-symbols-file' не игнорирует неопределенные символы и символы, необходимые для перемещения. Вы можете использовать опцию '-retain-symbols-file' только один раз в командной строке. Она переопределяет опции '-s' и '-S'.

 -rpath <имя-директории> 
Добавляет директорию в список директорий, в которых ищутся разделяемые библиотеки. Эта опция используется при линковке файла в формате ELF с разделяемыми объектами. Все аргументы опции '-rpath' объединяются и передаются линкеру времени выполнения, который использует эту информацию для обнаружения разделяемых объектов при запуске программ. Опция '-rpath' также используется для обнаружения разделяемых объектов, которые нужны непосредственно во время линковки (см. описание опции '-rpath-link'). Если опция '-rpath' не используется при линковке файлов в формате ELF, вместо нее используется содержимое внешней переменной окружения LD_RUN_PATH, если она определена.

Опция '-rpath' может быть использована в SunOS. По умолчанию SunOS линкер времени выполнения будет производить поиск по информации данной опцией '-L'. Но если задана опция '-rpath', поиск будет производиться исключительно при использовании данных опции '-rpath', игнорируя опцию '-L'. Это может быть весьма полезно при использовании gcc, добавляющего много опций '-L', которые могут указывать на файловые системы, смонтированные на NFS.

 -rpath-link <имя-директории> 
При использовании объектного формата ELF или операционной системы SunOS, одна разделяемая библиотека для своей работы может потребовать другую. Такое случается, когда при запуске LD используется опция '-shared', и разделяемая библиотека указана как один из входных файлов.

Когда линкер встречает такую зависимость при неразделяемой линковке, он будет пытаться автоматически найти требуемую разделяемую библиотеку и включить ее в процесс линковки, если она не была указана раньше. В таком случае опция '-rpath-link' определяет набор директорий, которые будут просматриваться первыми. При передаче нескольких имен директорий Вы можете использовать либо опцию '-rpath-link' несколько раз в командной строке, либо разделять имена директорий с помощью двоеточия. Линкеры используют следующие пути поиска для обнаружения требуемых разделяемых библиотек:

  1. Все директории, заданные опцией '-rpath-link'
  2. Все директории, заданные опцией '-rpath'. Отличие между опциями '-rpath' и '-rpath-link' заключается в том, что директории, заданные опцией '-rpath' включаются в выходной файл и используются во время исполнения, тогда как данные опции '-rpath-link' используются только во время линковки.
  3. В случае использования формата объектного файла ELF, когда опции '-rpath' и '-rpath-link' не были использованы, поиск производится по информации, хранящейся во внешней переменной окружения LD_RUN_PATH.
  4. В операционной системе SunOS, если опция '-rpath' не была использована, поиск директорий производится согласно информации опции '-L'.
  5. Для родного линкера просматривается содержимое переменной LD_LIBRARY_PATH.
  6. По умолчанию поиск проводится в директориях '/lib' и '/usr/lib' Если требуемая разделяемая библиотека не была найдена, линкер выдаст предупреждающее сообщение и продолжит процесс линковки.
 -r 
Создать перемещаемый выходной файл, то есть создать файл, который впоследствии может быть использован в качестве входного файла LD. Обычно это называется частичной линковкой. В частности, в операционных системах, которые поддерживают стандартные магические номера UNIX-а, эта опция также устанавливает магический номер выходного файла в OMAGIC, если эта опция не использовалась, на выходе линкера получится законченный файл. При линковке C++ программ эта опция также запретит линкеру устанавливать обращение конструктора; чтобы отменить это, используйте опцию '-Ur'. Эта опция аналогична опции '-i'.

 -S 
Не помещать отладочную информацию в выходной файл. Однако таблица символов будет записана.

 -s 
Не выводить никакой дополнительной информации в выходной файл, как отладочной, так и таблицы символов.

 -soname <имя> 
При создании разделяемого файла в формате ELF установить внутренее поле DT_SONAME в указанное имя. Когда запускаемый файл линкуется с разделяемым объектом, содержащим информацию в поле DT_SONAME, во время выполнения он будет вызывать динамический линковщик для загрузки разделяемого объекта, определенного полем DT_SONAME, вместо того, чтобы использовать имя файла, указанного линкеру.

 -shared 
Создать разделяемую библиотеку; в настоящий момент это поддерживается только для объектных файлов в формате ELF или операционной системы SunOS. В SunOS линкер будет автоматичеки создавать разделяемую библиотеку, если не используется опция '-e', и не нашлось никаких неопределенных символов в процессе линковки.

 -sort-common 
Обычно когда LD помещает глобальные общие символы в соответствующие секции, он сортирует их по размеру. Сначала идут однобайтовые символы, потом двухбайтовые, потом четырехбайтовые, а потом все остальные. Это позволяет избежать разночтений между символами и конструкциями выравнивания. Данная опция отключает такую сортировку.

 -split-by-reloc <число>
Пытается создать дополнительные секции в выходном файле так, чтобы ни одна выходная секция в файле не содержала большее число перемещений, чем было указано в аргументе к данной опции. Эта опция очень полезна при создании больших файлов для загрузки в некоторые ядра реального времени c форматом объектного файла COFF, так как формат COFF не позволяет описать более 65535 перемещений в одной секции. (Замечание: Это не будет работать в форматах файлов, которые не поддерживают независимых секций). Линкер не будет объединять несколько отдельных секций для переопределения, так что если одна секция содержит большее число перемещений, чем было указано, выходная секция также будет содержать больше перемещений.

 -split-by-file
Аналогична предыдущей опции, но создает новые секции для каждого входного файла.

 -stats
Вычисляет и выводит на дисплей статистическую информацию о работе линкера, такую, как использование памяти и время выполнения.

 -Tbss
 -Tdata <орг>
 -Ttext <орг>
Использовать <орг> как адрес, с которого начинается сегмент bss, data или text у выходного файла. <орг> должен быть задан как шестнадцатиричное число. Для совместимости со старыми линкерами вы можете опустить символы '0x', обычно идущие вместе с шестнадцатиричными числами.

 -Т <командный-файл>
 -T<командный-файл>
Читать команды ЯУЛ из указанного файла. Эти команды замещают скрипт LD, принятый по умолчанию, а не являются дополнением к нему, поэтому в файле должно быть определено все необходимое для описания целевого формата объектного файла (см. 3). Если файл не найден в текущем каталоге, LD ищет его в директориях, указанных опцией '-L'. При использовании нескольких опций '-T' в командной строке их данные объединяются.

 -t
Выводить имена входных файлов линкера по мере их обработки.

 -tradional-format 
Для некоторых архитектур выход LD может отличаться от выхода стандартного линкера, существующего на этих архитектурах. Эта опция заставляет LD не делать этих отличий. Для примера, в операционной системе SunOS LD объединяет повторяющиеся вхождения в таблице строк. Это позволяет уменьшить формат выходного файла с полной отладочной информацией почти на 30%. К сожалению стандартный отладчик DBX, поставляющийся вместе с операционной системой SunOS, не понимает результирующую программу. Однако GDB работает без ошибок. При использовании опции '-traditional-format' LD не будет объединять повторяющиеся вхождения.

 -u <cимвол> 
Описывает символ как неопределенный. Это позволяет избежать проблем при использовании дополнительных модулей стандартных библиотек. Вы можете использовать опцию '-u' несколько раз в командной строке.

 -Ur
Для всего, кроме программ C++, эта опция эквивалентна опции '-r'; она создает перемещаемый выходной файл, то есть файл, который может быть входным к LD. При линковке C++ программ опция '-Ur' вычисляет обращения к конструкторам. В отличие от опции '-r', нельзя использовать опцию '-Ur' с файлами которые сами были слинкованы с опцией '-Ur', так как таблица конструкторов может быть построена только один раз, и туда нельзя ничего добавлять. Используйте '-Ur' только для последней частичной линковки, а опцию '-r' для остальных.

 --verbose 
Вывести версию LD и список поддерживаемых эмуляций линкера; также вывести имена входных файлов, которые могут и не могут быть открыты.

 -v 
 -V
Вывести номер версии LD. Опция '-V' также выводит список поддерживаемых эмуляций.

 -version
Вывести номер версии LD и завершиться.

 -warn-common 
Предупреждать, когда общий символ комбинируется с другим общим символом или с определением символа. Линкеры UNIX-а позволяют эту немного избыточную практику, но на других платформах линкеры иногда не позволяют совершать эту операцию. Эта опция позволяет Вам найти потенциальную проблему, возникающую при объединении глобальных символов. К сожалению, некоторые библиотеки Си используют эту практику, так что Вы можете получить предупреждение как для символов в библиотеках, так и в своих программах.

Всего существует три типа глобальных символов:

 'int i=1;'
Описание, которое идет в секцию инициализированных данных в выходном файле.

 'extern int i;'
Неопределенная ссылка, которая не занимает пространства. Где-нибудь должно существовать другое определение этого символа.

 'int i;' 
Общий символ. Если существует несколько общих символов для переменной, она идет в секцию неинициализированных данных в выходном файле. Линкер объединяет несколько общих символов, описывающих одну переменную, в один символ. Если они разного размера, он выбирает наибольший. Линкер превращает общий символ в декларацию, если там находится описание той же самой переменной.

Опция '-warn-common' может выдавать пять типов предупреждений; каждое предупреждение состоит из двух строк: первая строка описывает символ, который сейчас обрабатывается, вторая строка описывает предыдущий символ с таким же именем. Один или оба из двух символов будут общим символом.

  1. Превращения общего символа в ссылку, потому что уже существует описаниe символа:
     файл(секция): warning: common of 'символ' 
     overridden by definition
     файл(секция): warning: defined here
    
  2. Превращение общего символа в ссылку, потому что позднее встретилось описание символа. Это практически аналогично предыдущему случаю, за исключением того, что символы встретились в другом порядке:
     файл(секция): warning: definition of 'символ' 
     overriding common
     файл(секция): warning: common is here 
    
  3. Объединение общего символа с предыдущим общим символом такого же размера:
     файл(секция): warning: multiple common 
     of 'символ'
     файл(секция): warning: previous common is here
    
  4. Объединение общего символа с предыдущим большим общим символом
     файл(секция): warning: common of 'символ' 
     overridden by larger common
     файл(секция): warning: larger common is here
    
  5. Объединение общего символа с предыдущим общим символом меньшего размера. Это аналогично предыдущему случаю, за исключением того, что символы встречаются в другом порядке.
     файл(секция): warning: common of 'символ' 
     overridding smaller common
     файл(секция): warning: smaller common is here 
    

 -warn-constructors
Предупреждать, если используются глобальные конструкторы. Эта опция полезна для весьма ограниченного числа объектных форматов. Для форматов, таких, как СOFF или ELF, линкер не может определить использование глобальных конструкторов.

 -warn-once
Предупреждать об обнаружении неопределенного символа только однажды, а не каждый раз при нахождении неопределенного символа в модуле. Для каждой библиотеки, написанной в командной строке, включать каждый объектный файл библиотеки в линковку, а не искать в библиотеке только необходимые объектные файлы. Обычно это используется для превращения библиотеки в разделяемую библиотеку, заставляя каждый объект быть включенным в результирующую разделяемую библиотеку.

 -X 
Удалять все временные локальные символы. Для большинства архитектур это все локальные символы, имена которых начинаются с буквы 'L'.

 -x
Удалять все локальные символы.

 -y <символ>
Печатать имя каждого линкуемого файла, в котором этот символ появляется. Эта опция может быть использована неограниченное количество раз. Данная опция полезна, когда у Вас есть неопределенный символ, а Вы не знаете, где находится ссылка на него.

 -( <архивы> -)
 --start-group <архивы> --end-group
Аргументом данной опции является список имен библиотек. Это могут быть либо точные имена файлов, либо опции '-l'. Указанные библиотеки многократно просматриваются, пока не остается ни одной новой неопределенной ссылки. Обычно архивы (библиотеки) просматриваются только один раз - в том порядке, в каком они были указаны в командной строке. Если символ в библиотеке требует ссылки на неопределенный символ, находящий в библиотеке, указанной позднее в командной строке, то линкер не сможет обработать эту ссылку. Группировка библиотек заставляет их все просматриваться многократно, пока все возможные ссылки не будут обработаны. Использование этой опции значительно замедляет работу линкера, поэтому ее рекомендуется использовать только тогда, когда у Вас есть несколько библиотек, которые ссылаются друг на друга.

2.2 Внешние переменные окружения

Вы можете изменить поведение LD с помощью внешней переменной окружения GNUTARGET.

GNUTARGET определяет формат объектного файла, если Вы не использовали опции командной строки '-b' и '-format'. Ее значение должно быть одним из возможных названий форматов объектных файлов, обрабатываемых библитекой BFD (см. 5). Если в окружении нет переменной GNUTARGET, LD использует формат объектного файла, принятый по умолчанию. Если GNUTARGET установлена в DEFAULT, тогда BFD пытается определить формат входного файла путем анализа входных файлов. Обычно этот метод успешен, но возможны некоторые затруднения, так как не существует большой уверенности, что магические числа, используемые для определения формата объектного файла, уникальны. Тем не менее, конфигурационная процедура для BFD на каждой системе помечает формат, принятый по умолчанию для этой системы, первым в списке форматов объектных файлов, среди которых производится поиск, поэтому ошибки при определении формата объектного файла довольно редки.


Вперед Назад Содержание
Назад Содержание

3. Язык управления линкером

Язык управления линкером предоставляет полный контроль над процессом линковки, обеспечивая необходимое пользователю соответствие между входными и выходными файлами. С его помощью можно управлять:

Вы можете представить командный файл (обычно называемый скриптом) линкеру, либо явно с помощью опции '-T', либо неявно, как обычный файл. Если линкер открывает файл, который не может распознать как файл с поддерживаемым объектным форматом или как библиотеку, он сообщает об ошибке.

3.1 Скрипты линкера

Язык управления линкером (ЯУЛ) LD - это набор команд; некоторые из этих команд устанавливают отдельную опцию, некоторые используются для выбора группы входных файлов или для установки имени выходного файла. Два типа управления имеют фундаментальное значение в процессе линковки.

Самая фундаментальная команда LD - это команда SECTIONS (см. 3.4). Каждый осмысленный скрипт линкера должен иметь команду SECTIONS: она определяет "карту" выходного файла и изобилует множеством деталей. Ни одна другая команда ЯУЛ не является необходимой в таком большинстве случаев, как эта.

Команда MEMORY дополняет команду SECTIONS описывая доступную память в целевой архитектуре. Эта команда не является обязательной. Если Вы не будете использовать команду MEMORY, тогда LD выделит необходимый блок доступной памяти для всего вывода (см. 3.3).

Вы можете вставлять комментарии в скрипты линкера, как в языке C, используя для начала комментария символы '/*' и для завершения - символы '*/'. Как и в языке C комментарии синтаксически эквивалентны пробелу.

3.2 Выражения

Множество полезных команд используют арифметические выражения. Синтаксис выражений в ЯУЛ индентичен синтаксису выражений в языке Cи со следующими особенностями:

Целые числа

Восьмиричное целое - это число, начинающееся с '0', после которого идет 0 или более восьмеричных цифр ("01234567").

 _as_octal = 0157255;
Десятичное число начинается с ненулевой цифры, за которой следует 0 или более десятичных цифр ("0123456789").

 _as_decimal = 57055;
Шестнадцатиричное число начинается с '0x' или '0X', за которыми следует 1 или более шестнадцатиричных цифр ("0123456789abcdefABCDEF").

 _as_hex = 0xdead;

Для того, чтобы записать отрицательное число, используйте префиксный оператор '-' (см. 3.2.4).

 _as_neg = -57005;
Кроме того, суффиксы 'K' и 'M' могут быть использованы для умножении константы на 1024 или на 1024*1024. Например, следующие константы равны:

 _fourk_1 = 4K;
 _fourk_2 = 4096;
 _fourk_3 = 0x1000;

Имена символов

Без использования двойных кавычек, имена символов могут начинаться с буквы, подчеркивания или точки и могут содержать любые буквы, подчеркивания, точки и тире. Имена символов, не заключенные в двойные кавычки, не должны конфликтовать с названиями команд ЯУЛ. Если Вы хотите использовать в имени пробелы или необычные буквы, Вы должны заключить это имя в двойные кавычки.

 "SECTION" = 9;
 "with a space" = "also with a space" + 10;
Так как имена могут содержать много неалфавитных знаков, рекомендуется разделять имена пробелами. Для примера, 'a-b' - это один символ, а 'a - b' это выражение.

Счетчик позиций

Специальная переменная линкера "." ("точка") всегда содержит текущую позицию вывода. Так как она всегда указывает на позицию выходной секции, она должна всегда прояляться внутри команды SECTIONS. Она может использоваться в любом месте выражения как обычный символ, но присваивания ей значения имеют побочный эффект. Если вы присвоите "точке" значение, это вызовет изменение счетчика позиций. Иногда это используется для создания дыр в выходных секциях. Счетчик позиций никогда не должен уменьшаться.

 SECTION 
 { 
   ouptut; 
   {
   file1(.text) 
   . = . + 1000;
   file2(.text)
   . += 1000;
   file3(.text)
   } = 0x1234;
 }
В предыдущем примере file1 располагается в начале выходной секции, после него идет пустое пространство размером в тысячу байт. Потом идет file2, после которого также пропуск размером 1000 байт перед file3. Строка '=0x1234' определяет, какие данные записывать в дырки (см. 3.4.4).

Операторы

Линкер распознает стандартный арифметический набор языка Cи с обычным приоритетом операций.

        Приоритет                 Ассоциативность         Операторы
         высшый
           1                         левая                 - ~ ! 
           2                         левая                 * / %
           3                         левая                  + -
           4                         левая                 >> << 
           5                         левая              == != > < <= >=   
           6                         левая                    & 
           7                         левая                    | 
           8                         левая                    &&
           9                         левая                    ||
           10                        правая                   ?:      
           11                        правая            &= += -= *= /=    
         низший                                         (См. 3.2.6).

Вычисления

Линкер использует "ленивые вычисления" для выражений. Он вычисляет значение для выражения, только когда это крайне необходимо. Линкеру необходимо значение начального адреса и длин регионов памяти для выполнения любой линковки. Эти значения вычисляются при первой же возможности, когда линкер читает скрипт. Тем не менее, если другие значения (например, значения символов) неизвестны или не являются необходимыми до окончания размещения секций, то их значения вычисляются позднее, когда другая информация (например, размеры выходных секций) доступна для использования в выражениях, присваивающих значения символам.

Присваивание: определение символов

Вы можете создавать глобальные символы и присваивать им значения (адреса), используя любой оператор присваивания языка Cи:

 символ = выражение ;
 символ &= выражение ;
 символ += выражение ;       
 символ -= выражение ; 
 символ *= выражение ;
 символ /= выражение ;
Две вещи отличают присваивание от других операторов в выражениях ЯУЛ.

Присваивание может появляться:

Первые два случая эквивалентны по производимым действиям, оба определяют символ с абсолютным адресом, последний случай определяет символ, адрес которого зависит от данной секции (см. 3.4).

Когда линкер вычисляет выражение и присваивает его значение переменной, ей дается либо абсолютный, либо относительный тип. Выражение абсолютного типа - это выражение, в котором символ имеет значение, идентичное тому значению, которое он будет иметь в выходном файле. Выражение относительного типа - это выражение, значение которого является фиксированным смещением от начала секции.

Тип выражения зависит от его позиции в скрипт файле. Символ, значение которому присваивается в описании секции, является относительным. Символ, присваивание которому производится в любом другом месте, создается как абсолютный. Так как символ, создаваемый внутри описания секции, создается относительным к началу секции, он будет перемещаемый, если затребован перемещаемый формат объектного файла. Символ может быть создан абсолютным, даже когда присваивание ему значения происходит внутри описания секции с помощью использования функции ABSOLUTE. Для примера, чтобы создать абсолютный символ, адрес которого указывает на последний байт выходной секции с названием '.data', нужно написать:

 SECTIONS{...
   .data :
     { 
       *(.data)
       _edata = ABSOLUTE(.) ;
     }
 ...}
Линкер пытается отложить вычисление присваивания до того момента, пока все переменные в выражении не станут известны (см. 3.2.5). Для примера, размер секции не может быть известен до ее размещения, так что присваивания, зависящие от этого, не будут совершены до размещения секций. Некоторые выражения, например те, которые зависят от счетчика позиций ('.'), должны быть вычислены во время размещения секций. Если результат выражения необходим, а его вычисление не является возможным, линкер сообщает об ошибке. Для примера следующие команды:

 SECTIONS{...
   text 9+this_isnt_constant :
     { ...
     }
 ...}
Вызовут сообщение об ошибке: "Non constant expression for initial address" (Выражение для вычисления начального адреса не является константой).

Иногда желательно описать символ только в том случае, если он не используется, и если он не определен другим объектом, включенным в линковку. К примеру, традиционные линкеры определяют символ 'etext'. Тем не менее, ANSI-C требует, чтобы пользователь мог использовать 'etext' в качестве имени функции без возникновения ошибки. Ключевое слово PROVIDE может быть использовано для определения такого символа. Оно используется в виде PROVIDE(символ = выражение).

Арифметические функции

ЯУЛ предоставляет большее количество функций для использования внутри скриптов.

 ABSOLUTE(exp)
Возвращает абсолютное (неперемещаемое, неотрицательное) значение выражения exp. Обычно используется для присваивания абсолютных значений выражениям и символам внутри описания секции, где значения символов обычно относительны.

 ADDR(section)
Возвращает абсолютный адрес указанной секции. Вы должны определить положение этой секции до использования функции ADDR. В следующем примере переменным symbol_1 и symbol_2 присваиваются одинаковые значения.

 SECTION {... 
   .ouptut1 : 
     {
     start_of_output_1 = ABSOLUTE(.) ;
     ...
     }
   .output;
     { 
     symbol_1 = ADDR(.output1);
     symbol_2 = start_of_output_1;
     } 
 ...}
 ALIGN(exp)
Возвращает значение счетчика позиций, выравненное на границу следующего за exp выражения. Значение параметра функции должно быть кратно 2. Это эквивалентно следующему выражению:

   (. + exp - 1) & ~(exp - 1)
Функция ALIGN не изменяет значение счетчика позиций. В качестве примера выравняем текущую секцию на границу следующих 0x2000 байт после предыдущей секции и установим переменную внутри секции на границу следующих 0x2000 байт после входной секции.

 SECTION {... 
   .data ALIGN(0x2000):  {
     *(.data)
     variable = ALIGN(0x8000);
   } 
 ...}
Первое использование функции ALIGN в этом примере указывает положение этой секции, потому что оно используется в качестве атрибута начала секции в описании секции (см. 3.4.4). Второе использование просто определяет значение переменной. Встроенная функция NEXT тесно связана с описываемой функцией.

 DEFINED(<символ>)
Возвращает 1, если символ находится в глобальной таблице символов линкера и определен, в противном случае возвращает 0. Вы можете использовать эту функцию для присваиванию символам значений по умолчанию. Для примера, следующий фрагмент показывает, как установить глобальному символу BEGIN значение первой позиции в секции '.text'; но если символ с таким названием уже существует, его значение не изменяется.

 SECTION {... 
   .text : {
     begin = DEFINED(begin) ? begin : . ;
     ...
   }
 ...}
 NEXT(exp)
Возвращает следующий размещенный адрес, который является числом, кратным exp. Эта функция тесно связана с функцией ALIGN. Если вы не используете команду MEMORY для определения множественных участков памяти в выходном файле, эти две функции эквивалентны.

 SIZEOF(section)
Возвращает размер секции в байтах, если эта секция была размещена. В следующем примере переменным symbol_1 и symbol_2 присваиваются одинаковые значения.

 SECTIONS {...
   .output {
      .start = . ;
      ...
      .end = . ; 
      }
   symbol_1 = .end - .start;
   symbol_2 = SIZEOF(.output);
 ...} 
 SIZEOF_HEADERS
 sizeof_headers
Возвращает размер заголовка выходного файла в байтах. Вы можете использовать это значение, как начальный адрес первой секции, если Вы хотите облегчить постраничность.

3.3 Размещение памяти

Конфигурация линкера по умолчанию разрешает размещенение свободной памяти. Вы можете переопределить эту конфигурацию, используя команду MEMORY. Команда MEMORY описывает расположение и размер блоков памяти, как Вам это удобно. Необходимо использовать ее очень осторожно. Вы можете описать, какие участки памяти могут быть использованы линкером, и каких он должен избегать. Линкер не тасует секции, чтобы они помещались в доступные регион памяти, но перемещает требуемые секции в правильные регионы, исправляя ошибки, когда регионы заполняются.

Скрипт может содержать максимум одну команду MEMORY, тем не менее Вы можете определить любое необходимое Вам число блоков памяти внутри этой команды. Синтаксис этой команды таков:

 MEMORY 
   { 
     <имя> (<аттр>) : ORIGIN=origin, LENGTH =len     
     ...
   }
 <имя> 
Имя, используемое внутри линкера для ссылки на регионы. Вы можете использовать любое имя символа по Вашему желанию. Имена районов располагаются в отдельном хранилище имен и не будут конфликтовать с названиями символов, файлов или секций. Используйте различные имена для описания нескольких районов.

 <аттр> 
Необязательный список атрибутов, разрешенный для совместимости с линкером AT&T, но не используемый LD, кроме проверки на правильность атрибутов. Возможный список атрибутов должен быть создан с использованием набора символов ("LIRWX"). Если Вы не будете использовать список атрибутов, Вы можете также не писать круглые скобки.

 origin 
Начальный адрес региона физической памяти. Это выражение, которое должно быть сосчитано до операции по размещению памяти. Ключевое слово ORIGIN можно сократить до org или o (но не ORG).

 len     
Размер региона в байтах. Ключевое слово LENGHT можно сократить до len или l.

Например, для того, чтобы определить два региона в памяти, доступные для размещения: первый, начинающийся с 0 размером 256 килобайт и второй, начинающийся с адреса 0x40000000 размером 4 мегабайта:

 MEMORY 
   {
   rom : ORIGIN = 0, LENGTH = 256K
   ram : org = 0x40000000, l = 4M
   }
Как только вы определили регион памяти под названием mem, Вы можете напрямую описать специфические выходные секции в нем, используя в окончании команды ключевое слово '>mem' внутри команды SECTION (см. 3.4.4). Если размер объединенных выходных секций в регионе больше размера региона, линкер выводит сообщение об ошибке.

3.4 Описание выходных секций

Команда SECTIONS непосредственно указывает место расположения выходных секций, их порядок в результирующем файле и некоторые тонкости их размещения. Вы можете использовать только одну команду SECTIONS в скрипте, но Вы можете определить столько выражений внутри нее, сколько захотите. Выражения внутри команды SECTIONS могут делать одну из трех вещей:

Возможно использование первых двух операций - определения точки входа и описания значений символов вне команды SECTIONS (см. 3.5 и 3.2.6). Их место расположения определяется Вашим выбором для удобства чтения скрипт файла, так что символы и точка входа могут быть описаны в значащих для Вас местах.

Если Вы не используете команду SECTIONS, линкер размещает каждую входную секцию в выходную секцию с тем же названием в том порядке, в каком секции впервые встретились во входных файлах. Например, если все входные секции присутствуют в первом файле, порядок секции в выходном файле будет идентичен их порядку в первом входном файле.

Описание секций

Наиболее часто используемые выражения в команде SECTIONS - это описания секций, которые определяют их свойства в выходных секциях: расположение, выравнивание, содержание, образец заполнения и целевой регион памяти. Большинство из этих описаний необязательны. Простейшая форма описания секции приведена ниже:

 SECTIONS { ...  
   secname  : { 
     contents 
   } 
 ... }
secname - это имя выходной секции, а contens - это описание того, что туда пойдет, например, описание входных файлов или секций во входных файлах (см. 3.4.2). Как Вы можете догадаться, число пробелов может быть любым по Вашему усмотрению. Название секции должно отвечать ограничениям формата Вашего объектного файла; в форматах, которые поддерживают ограниченное число секций, таких как 'a.out', имя должно быть одним из имен, поддерживаемых форматом файла (a.out, например, разрешает только следующие имена секций: .text, .data, .bss). В форматах объектных файлов, которые поддерживают любое число секций, но с цифрами вместо имен, например 'Oasys', имя должно быть строкой цифр, заключенной в двойные кавычки. Имя секции может состоять из любой последовательности симолов, но любое имя, которое не удовлетворяет стандартому синтаксису имен LD, должно быть заключено в двойные кавычки (см. 3.2.2).

Линкер не будет создавать выходных секций, которые ничего в себе не содержат. Например:

 .foo { *.(foo } 
создаст секцию '.foo' в выходном файле, только в том случае, если секция '.foo' существует хотя бы в одном входном файле.

Расположение секций

В описании секции Вы можете определить содержимое выходной секции путем перечисления нескольких входных файлов, путем перечисления нескольких секций входных файлов или путем комбинации этих двух способов. Вы также можете разместить контрольные данные в секции и описать символы, зависящие от начала секции.

Содержимое описания секции может включать любые типы описанных ниже выражений; Вы можете включать их в описание секции столько раз, сколько необходимо, разделяя отдельные выражения пробелом.

 <имя-файла>
Вы можете просто помещать имя входного файла в текущем описании секции для того, чтобы его содержимое попало в выходную секцию. Если имя файла уже было упомянуто в описании другой секции с указанием всех секций файла, будет сгенерировано сообщение об ошибке; в противном случае в текущей выходной секции будут расположены только те секции файла, которые не были ранее затребованы.

Для того чтобы определить список файлов, нужно набрать

    .data : { afile.o bfile.o cfile.o } 
Этот пример также показывает, что множество выражений может быть включено в описание секции, так как каждое имя файла является отдельным выражением.

 <имя-файла>(<секция>)
 <имя-файла>(<секция>, <секция>, ...)
 <имя-файла>(<секция> <секция> ...)
Вы можете назвать одну или более секций из Ваших входных файлов для включения в текущую выходную секцию. Если Вы хотите описать список секций входных файлов внутри скобок, Вы можете разделить имена секций с помощью запятых или пробелов. Вместо точного наименования входных файлов в скрипте Вы можете ссылаться на файлы в командной строке LD, используя '*' вместо имени отдельного файла перед скобками, внутри которых находится список секций.

Если Вы уже включили несколько файлов с помощью их имени, '*' ссылается на все оставшиеся файлы, т.е. те файлы, имя которых во входном файле не было еще определено.

Например, чтобы скопировать секции с номерами от одного до четырех из файла в формате 'Oasys' в секцию '.text' файла в формате 'a.out', и секции 13 и 14 в секцию '.data', необходимо дать следующие команды:

 SECTIONS {
   .text :{
     *("1" "2" "3" "4")
   }
    .data :{ 
     *("13" "14")
   }
 }
'[секция...]' более не используется в качестве альтернативного пути для определения секций из всех неразмещенных входных файлов. Так как некоторые операционные системы (VMS) разрешают квадратные скобки в именах файлов, эта нотация больше не поддерживается.

 <имя-файла>(COMMON)
 * (COMMON) 
Указывает, где в выходном файле помещать неинициализированные данные. * (COMMON) указывает на все неинициализированные данные из всех входных файлов(т.е. на те, которые не были размещены). <имя-файла>(COMMON) указывает на неинициализированные данные из отдельного файла. Оба этих выражения являются специальными случаями общих механизмов определения и размещения секций входных файлов: LD разрешает Вам ссылаться на неинициализированные данные так, как если бы они находились в секции COMMON независимо от формата входных файлов.

Например, следующий скрипт разделяет выходной файл на три секции с названиями: '.text', '.data', '.bss', беря из каждого входного файла соответствующие секции:

 SECTIONS { 
   .text : { *(.text) } 
   .data : { *(.data) }
   .bss :  { *(.bss)  *(COMMON) }
 }
Следующий пример читает все секции из файла 'all.o' и помещает их в начале выходной секции 'outputa', которая начинается с позиции 0x10000. Все секции с названием '.input1' из файла 'foo.o' идут далее в той же выходной секции. Все секции '.input2' из файла 'foo.o' записываются в выходную секцию 'outputb', следующую за секцией '.input1' из файла 'foo1.o'. Все секции называющиеся '.input1' и '.input2' из остальных файлов записываются в выходную секцию 'outputc'.

 SECTIONS { 
   outputa 0x10000 :
     { 
     all.o
     foo.o (.input1) 
     }
   outputb : 
     { 
     foo.o (.input2)
     foo1.o (.input1) 
     } 
   outputc : 
     { 
     *(.input1) 
     *(.input2) 
     } 
 } 

Описание секций данных

Нижеследующий набор команд используется для управления размещением секций данных в выходном файле. Вы можете помещать секции данных как из входных файлов, так и непосредственно описывая их на языке управления линкером в скрипт файлах. Большинство этих дополнительных команд включает в себя выражения (см. 3.2). Все эти команды показаны отдельно для простоты восприятия информации, но такая изоляция не является необходимой в описании секции с помощью команды SECTIONS. Вы можете спокойно смешивать их с любыми командами и выражениями, которые мы уже описали.

 CREATE_OBJECT_SYMBOLS 
Создает символ для каждого входного файла в текущей секции и устанавливает адрес первого байта данных, записанного из того входного файла. Например, с файлом в формате 'a.out' возможно иметь символ для каждого входного файла. Вы можете совершить это, описав выходную секцию 'a.text' как в нижеследующем примере:

 SECTIONS { 
   .text 0x2020 : 
      { 
     CREATE_OBJECT_SYMBOLS 
     *(.text) 
     _etext = ALING(0x2000); 
     } 
   ...
 }

Пусть 'sample.ld' - файл, содержащий этот скрипт, и 'a.o', 'b.o', 'c.o' и 'd.o' - четыре входных файла с содержимым, похожим на нижеследующий пример:

 /* a.c */ 
 
 afunction() { } 
 int adata=1;
 int abss; 
Команда 'ld -M -T sample.ld a.o b.o c.o d.o' создаст файл карты, содержащий символы соответственно именам объектных файлов:

 00000000 A __DYNAMIC 
 00004020 B _abss
 00004000 D _adata 
 00002020 T _afunction 
 00004024 B _bbss 
 00004008 D _bdata 
 00002038 T _bfunction
 00004028 B _cbss 
 00004010 D _cdata 
 00002050 T _cfunction
 0000402c B _dbss
 00004018 D _ddata
 00002068 T _dfunction
 00004020 D _edata
 00004030 B _end 
 00004000 T _etext
 00002020 t a.o
 00002038 t b.o
 00002050 t c.o 
 00002068 t d.o
 
 <символ> = <выражение>
 <символ> f = <выражение>
<символ> - это любое имя символа (см. 3.2.2). "f=" ссылается на любой из операторов '&=', '+=', '-=', '*=', '/=', которые объединяют арифметическую операцию и присваивание. Когда Вы присваиваете значение символу внутри некоторого описания секции, значение зависит от начала секции (см. 3.2.6). Если Вы напишете:

 SECTIONS { 
   abs = 14; 
   ...
   .data : { ... rel = 14; ... } 
   abs2= 14+ ADDR(.data);
   ... 
 } 
abs и rel не равны; rel имеет значение равное abs2.

 BYTE(<выражение>)
 SHORT(<выражение>)
 LONG(<выражение>)
 QUAD(<выражение>)
Путем включения одного из этих четырех выражений в описание секции Вы можете точно разместить один, два, четыре или восемь байт по текущему адресу секции. QUAD поддерживается только на 64-битной архитектуре.

Многобайтовые последовательности размещаются в том порядке, который определен для формата выходного файла (см. 5).

 FILL(<выражение>)
Определяет образец заполнения для текущей секции. Все остальные неуказанные регионы памяти внутри секции (например регионы, которые Вы пропускаете путем присваивания нового значения счетчику позиций) заполняются двумя последними значащими байтами из аргумента функции FILL. Выражение FILL покрывает адреса памяти после того места, в котором оно встретилось в описании секции. Путем включения нескольких выражений FILL, Вы можете определять различные образцы заполнения в разных частях выходной секции.

Дополнительные атрибуты секции

Перед Вами полный синтаксис описания секции, включающий все дополнительные порции:

 SECTIONS { 
 ...
 secname start BLOCK(align) (NOLOAD) : AT (ldadr) 
   { contents } > region =fill
 ...
 }
Названия секций и содержимое необходимы (см. 3.4.1 и 3.4.2). Остальные элементы start, BLOCK(align), (NOLOAD), AT(ldadr), >region и =fill не обязательны.

Вы можете заставить выходную секцию загружаться по указанному адресу путем определения начала непосредственно после названия секции. 'start' может быть представлен любым выражением. Следующий пример генерирует секцию output по адресу 0x40000000:

 SECTIONS { 
   ... 
   output 0x40000000: { 
     ... 
     } 
   ...
 }
  
 BLOCK(align)
Вы можете включить функцию BLOCK для увеличения счетчика позиций, так что секция будет располагаться с указанным выравниванием. Параметр функции BLOCK может быть выражением.

 (NOLOAD)
Используйте '(NOLOAD)' для запрета загрузки секции в память при каждом обращении. В нижеследующем примере сегмент ROM начинается с абсолютной позиции '0', и его не нужно загружать в каждый объектный файл. Пример:

 SECTIONS { 
   ROM  0  (NOLOAD)  : { ... } 
   ...
 }
 
 AT(ldadr) 
Выражение ldadr, которое следует за ключевым словом AT, определяет адрес загрузки секции. По умолчанию, если Вы не использовали ключевое слово AT, адрес загрузки равен адресу перемещения. Эта возможность создана для облегчения построения образов ROM. Например, в следущем примере команда SECTIONS создает две выходные секции: одна называется '.text' и начинается с адреса 0x1000, а другая называется '.mdata' и загружается в конце секции '.text' несмотря на то, что адрес ее перемещения равен 0x2000. Символ '.data' описан со значением 0x2000:

 SECTIONS
   { 
   .text 0x1000 : { *(.text) _etext = . ; } 
   .mdata 0x2000 : 
     AT ( ADDR(.text) + SIZEOF (.text) )
     { _data = . ; *(.data); _edata= . ; } 
   .bss 0x3000 : 
     { _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;}
 } 
Инициализационный код времени выполнения (для Cи программ обычно crt0), при использовании его с образами ROM, созданными таким путем, вынужден включать что-то похожее на нижеследующий пример для копирования инициализированных данных из образа ROM на адрес времени выполнения:

 char *scr = _etext;
 char *dst = _data; 
 
 /* Данные находятся в конце секции текст; скопировать их. */
 while (dst < _edata) { 
   *dst++ = *scr++;
 } 
 
 /* Обнулить bss */ 
 for (dst = _bstart; dst< _bend; dst++)
   *dst = 0;
 
 >region
Присвоить текущей секции предыдущий регион памяти (см. 3.3).

 =fill 
Включая '=fill' в описание секции, Вы определяете базовое значение заполнения в этой секции. Вы можете использовать любое выражение для определения заполнения. Все неразмещенные дырки в текущей выходной секции при записи в выходной файл будут заполнены двумя последними значащими байтами выражения. Вы также можете изменить значение заполнения с помощью функции FILL внутри содержимого описания секции.

3.5 Точка входа

ЯУЛ включает команду специально для определения первой запускаемой инструкции в выходном файле (его точку входа); аргумент команды - это имя символа:

   ENTRY(<символ>) 
Как присваивание символов команда ENTRY может быть помещена в качестве независимой команды в скрипт файле или внутри описания секции в команде SECTIONS - как Вам больше нравится.

ENTRY - один из нескольких путей указания точки входа. Вы можете использовать любой из описанных ниже способов (способы расположены в порядке уменьшения приоритета; методы, расположенные в списке выше, переопределяют методы, лежащие в списке ниже):

Например, Вы можете использовать эти правила для создания точки входа с присваиваемым выражением. Если символ start не определен в Ваших входных файлах, Вы можете просто определить его, присваивая ему необходимое значение:

 start = 0x2020; 
В примере переменной start присваивается абсолютное значение, но Вы можете присвоить ей любое выражение. Например, если Ваш входной файл использует какое-либо другое имя символа для точки вхождения, Вы можете присвоить значение этого символа символу start:

 start = other_symbol ;

3.6 Команды опций

ЯУЛ включает в себя несколько команд, которые имеют специальное назначение. Они идентичны опциям командной строки.

 CONSTRUCTORS 
Это команда связывает записи конструкторов и деструкторов в стиле языка C++. Детали представления конструктора отличаются в разных объектных форматах, но обычно список конструкторов и деструкторов располагается в специальных секциях. Команда CONSTRUCTORS определяет, где линкер должен помещать информацию из этих секций относительно остального выхода линкера. Данные конструкторов помечены символом __CTOR_LIST__ в начале и __CTOR_LIST_END в конце. Данные деструктора разделяются аналогично между __DTOR_LIST__ и __DTOR_LIST_END (компилятор должен обработать данные этих секций для правильной работы программы).

 FLOAT
 NOFLOAT
Эти ключевые слова используются некоторыми старыми линкерами для распознавания математических библиотек. LD не использует эти ключевые слова, предполагая вместо этого, что каждая необходимая процедура в библиотеках использует стандартные механизмы для линковки библиотеки; но для правильной работы со скрипт файлами, оставшимися от старых линкеров, ключевые слова FLOAT и NOFLOAT распознаются и игнорируются.

 FORCE_COMMON_ALLOCATION 
Эта команда имеет эффект, аналогичный опции командной строки '-d'. Она используется для того, чтобы LD присваивал значения общим символам, даже если используется перемещаемый формат объектного файла. (См. '-r')

 INPUT(<файл>, <файл>, ...)
 INPUT(<файл> <файл> ...)
Используйте эту команду для включения двоичных файлов в линковку, без включения их в описание конкретной секции. Необходимо описывать полное имя каждого файла, включая '.a', если оно присутствует.

LD ищет каждый файл по путям, указанным для поиска библиотек, как для файлов, имена которых Вы описали в командной строке (см. 2.1).

Если Вы использовали '-l<файл>', LD трансформирует это имя в 'lib<файл>.a', как и опцию командной строки '-l'.

 GROUP(<файл>, <файл>, ...)
 GROUP(<файл> <файл> ...)
Эта команда похожа на команду INPUT, за исключением того, что указанные файлы должны быть библиотеками, и они будут просматриваться многократно до тех пор, пока не будет создано ни одной новой неопределенной ссылки (см. 2.1).

 OUTPUT(<имя-файла>)
Используйте эту команду для определения имени выходного файла. Действие описываемой команды аналогично действию опции командной строки '-o <имя-файла>', которая может переопределить данную команду. Вы можете использовать эту команду для переопределения имени файла по умолчанию и делания его отличным от 'a.out'.

 OUTPUT_ARCH(<имя-bfd>)
Указывает архитектуру машины, выбирая из одной поддерживаемой BFD (см. 5). В большинсте случаев эта команда не является необходимой; как правило, архитектура определяется во время конфигурации библиотеки BFD.

 OUTPUT_FORMAT(<имя-bfd>) 
Когда LD отконфигурирован для поддержки нескольких объектных форматов, Вы можете использовать эту команду для определения конкретного формата выходного файла. <имя-bfd> - это одна из архитектур, поддерживаемая библиотекой BFD (см. 5). Действие этой команды идентично действиям опции командной строки '-oformat'. Эта команда влияет только на выходной файл. Для изменения формата входных файлов используйте команду TARGET.

 SEARCH_DIR(<путь>)
Действие этой команды идентично действию опции командной строки '-L<путь>'.

 STARTUP(<имя-файла>)
Делает указанный файл первым входным файлом в процессе линковки.

 TARGET(<формат>)
Когда LD отконфигурирован для поддержки нескольких форматов объектного файла, Вы можете использовать эту команду для изменения форматов входных файлов. Действие этой команды аналогично действиям опции командной строки '-b' и '-format'. Если команда TARGET используется, а команда OUTPUT_FORMAT нет, последний аргумент команды TARGET используется в качестве формата выходного файла (см. 5).


Вперед Назад Содержание