Использование линкера VisualDSP++ Печать
Добавил(а) microsin   

Процесс линковки привязывает код и данные к памяти процессора (к абсолютным адресам его карты памяти). Для простой однопроцессорной архитектуры при линковке генерируется один файл .dxe. Одиночное вовлечение линкера в процесс привязки может создать несколько исполняемых файлов (.dxe) многопроцессорной (multiprocessor, MP) или многоядерной (multi-core, MC) архитектур. Линковка также может сгенерировать файл общей памяти (shared memory, .sm) для системы MP или MC. Большой исполняемый файл может быть поделен на меньший исполняемый файл и файл оверлея (overlay, .ovl), который содержит вызываемый при необходимости код (сбрасываемый во внутреннюю память процессора). Линкер выполняет эту задачу (здесь приведен перевод Главы 2 "Linker" руководства [1]).

Вы можете запустить линкер из командной строки или из интегрированной среды разработки и отладки (Integrated Development and Debugging Environment, IDDE) VisualDSP++.

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

Эта глава включает следующие секции:

• Работа линкера.
• Рабочее окружение линкера в операционной системе Windows.
• Сообщения об ошибках и предупреждения линкера.
• Линковка описания целевого процессора (Link Target Description).
• Справочник по командной строке линкера.

[Работа линкера]

Рис. 2-1 иллюстрирует базовую операцию линковки. Этот рисунок показывает несколько входных объектных файлов (.doj), которые связываются в один исполняемый (executable, .dxe) файл. Файл настроек линкера (linker description file, .ldf) управляет процессом линковки.

Linker Utilities Manual Linking Object Files fig2 1

Рис. 2-1. Линковка объектных файлов в исполняемый файл.

Когда разрабатывается новый проект, используйте Project Wizard (для процессоров Blackfin) или Expert Linker (процессоры SHARC и TigerSHARC) для генерации файла LDF проекта. Для дополнительной информации см. Главу 4 "Expert Linker" или online help для "Project Wizard".

В многопроцессорной системе генерируется файл .dxe для каждого процессора. Например, для двухпроцессорной системы Вы должны генерировать два файла .dxe. Процессоры в многопроцессорной архитектуре могут иметь общую память (share memory). Когда это указано операторами файла .ldf, linker генерирует исполняемый файл shared memory (.sm), код которого используется несколькими процессорами.

Файлы оверлея, еще один вывод от линкера, поддерживают приложения, которые требуют больше инструкций программы и данных, чем может вместить внутренняя память. Для дополнительной информации см. раздел "Управление памятью с использованием оверлеев" ("Memory Management Using Overlays" из Главы 5 даташита [1]).

Из Википедии:

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

Метод предполагает разделение программы на фрагменты, называемые оверлеями (overlays). Размер каждого оверлея ограничен, согласно размеру доступной памяти. Место в памяти, куда будет загружен оверлей называется регионом (region, destination region). Хотя часто программы используют только один блок памяти для загрузки различных оверлеев, возможно определение нескольких регионов различного размера. Менеджер оверлеев, иногда являющийся частью ОС, подгружает запрашиваемый оверлей из внешней памяти (НЖМД, флеш-память, ППЗУ) в регион. Некоторые редакторы связей (линкеры) поддерживают работу с оверлеями.

Программирование с применением оверлеев требует от программиста внимательного отношения к размеру каждой части программы. Из-за этого часто используются низкоуровневые языки и ассемблер, которые позволяют ограничивать размеры программы и оверлеев. Программирование при помощи оверлеев является более сложным, чем при использовании виртуальной памяти."

Подобно объектным файлам, исполняемые файлы делятся на выходные секции с уникальными именами. Выходные секции определены стандартным форматом файла Executable and Linking Format (ELF), которому удовлетворяет система разработки VisualDSP++.

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

Исполняемый файл (файлы) .dxe дополнительные файлы (.sm и .ovl) не загружаются в процессор, и не прошиваются в EPROM. Они используются для отладки приложения.

Управление работой линкера. Операции линкера направляются следующими опциями и командами:

• Ключи (опции) командной строки линкера. Подробнее см. раздел "Справочник по командной строке линкера".
• Рабочее окружение IDDE: настройки на страничке "Link" диалогового окна свойств проекта (Project Options). См. секцию "Сборки проекта".
• Команды LDF. Для получения подробного описания см. раздел "Команды LDF".

Опции линкера управляют тем, как линкер обработает объектные и библиотечные файлы. Эти опции указывают разные критерии, такие как директории поиска файлов, генерация выходного map-файла, удаление ненужного кода (dead code elimination).

Команды LDF в файле настроек линкера (linker description file, .ldf) определяют целевую карту памяти и размещение секций программы в памяти процессора. Текст этих команд дают информацию, необходимую для линковки Вашего кода.

Окно проекта VisualDSP++ отображает файл .ldf как файл исходного кода, хотя этот файл предоставляет входные команды для линкера.

С использованием директив в файле .ldf, линкер:

• Читает входные секции и объектных файлах и привязывает из к выходным секциям в исполняемом файле. В выходную секцию может быть помещено больше одной входной секции.
• Привязывает каждую выходную секцию в исполняемом файле к сегменту памяти. Сегмент памяти представляется непрерывным диапазоном адресов целевого процессора. В один сегмент памяти может быть помещено больше одной выходной секции.

Правила процесса линковки. Процесс линковки соблюдает следующие правила:

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

Обзор файла LDF. Всякий раз, когда Вы линкуете функции C/C++ или подпрограммы ассемблера, используется одинаковый механизм. После преобразования файлов исходного кода в объектные файлы (это делает компилятор), линкер использует директивы в файле .ldf, чтобы комбинировать объекты в исполняемом (.dxe) файле, который может быть загружен в симулятор для тестирования.

Структура исполняемого файла удовлетворяет стандарту Executable and Linkable Format (ELF).

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

Когда разрабатывается новый проект, используется Project Wizard (процессор Blackfin) или Expert Linker (процессоры SHARC и TigerSHARC), чтобы сгенерировать файл LDF для проекта. Для дополнительной информации см. Главу 4 “Expert Linker” или выполните поиск в online help строки "Project Wizard".

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

За дополнительной информацией обратитесь к статье [6].

[Рабочее окружение линкера в операционной системе Windows]

Под этим имеется в виду окна приглашения командной строки Windows (cmd.exe) и среда разработки VisualDSP++ IDDE. При минимальном использовании через командную строку может быть запущена какая-нибудь из утилит разработки (как например линкер), и в той же командной строке (standard output) можно увидеть результат выполненной операции утилиты.

Интегрированная среда разработки VisualDSP++ предоставляет рабочее окружение, которое упрощает процесс сборки программного обеспечения для процессора. Из VisualDSP++ Вы указываете опции сборки в диалоге настроек проекта (Project Options), и модифицируете файлы проекта, включая linker description file (.ldf). Опция Type позволяет выбрать, что будет собрано - файл библиотеки (.dlb), исполняемый файл (.dxe), или файл образа (образ загрузки .ldr или другой). В выходном окне (окно Output) будут появляться сообщения об ошибках и предупреждениях.

Сборки проекта. Линкер запускается из командной строки операционной системы, инициированной из VisualDSP++ IDDE или окна командной строки, запущенной пользователем. Система VisualDSP++ IDDE предоставляет интуитивно-понятный интерфейс программирования для процессора. Когда Вы открываете VisualDSP++, её рабочая область содержит все необходимое для сборки проекта DSP, управления им и отладки кода. Вы можете просто создать или отредактировать файл .ldf, который отображает код или данные на определенные сегменты памяти целевого процессора (для которого предназначен проект приложения).

Для получения информации о рабочем окружении VisualDSP++ обратитесь к соответствующему руководству (VisualDSP++ User’s Guide) или online Help. Online Help предоставляет мощные возможности поиска. Чтобы получить информацию по элементу кода, параметру или ошибке выберите текст в окне редактора VisualDSP++ IDDE или окне Output, и нажмите на клавиатуре кнопку F1.

В среде VisualDSP++ укажите настройки инструментария для сборок проекта. Используйте меню Project, чтобы открыть диалог настроек проекта (окно Project Options). Страницы этого диалога позволят Вам выбрать целевой процессор, тип и имя выходного файла, а также инструменты VisualDSP++, доступные для использования с выбранным процессором.

Страничка Link диалога Project Options используется для выбора и/или установки функциональных опций линкера (рис. 2-2).

Linker Utilities Manual Project Options Link fig2 2

Рис. 2-2. Страничка Project Options –> Link, раздел General (общие настройки линковки).

На страничке настроек Link есть четыре раздела - General, LDF Preprocessing, Elimination и Processor. Рис. 2-2 показывает пример открытого раздела Project Options -> Link -> General. Большинство опций диалога соответствуют опциям командной строки компилятора, которые описаны в секции "Справочник по командной строке линкера".

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

Для разных процессорных архитектур могут быть доступны разные опции странички настроек Link. Используйте в VisualDSP++ контекстный online Help, чтобы получить информацию об элементах управления диалога опций проекта (в частности по опциям линкера). Для этого кликните на кнопку с символом "?", и затем кликните на нужное поле, галочку, выпадающий список или кнопку, по которым нужно получить информацию.

Expert Linker. Среда VisualDSP++ IDDE предоставляет интерактивный инструмент Expert Linker, чтобы отобразить код или данные на определенные сегменты памяти процессора. Когда разрабатывается новый проект, используйте Expert Linker для генерации LDF.

Окно Expert Linker графически отображает информацию .ldf - объектные файлы, макросы LDF, библиотеки и описание целевой памяти. В Expert Linker используйте операции "перетащить и бросить" (drag-and-drop), чтобы организовать объектные файлы в графическом представлении карты памяти. Когда Вы удовлетворили конфигурации памяти, генерируется исполняемый файл (.dxe).

Окно Expert Linker открывается двойным щелчком по файлу .ldf проекта, имя которого отображается в дереве файлов (папка Linker Files).

На рис. 2-3 показано окно Expert Linker, которое состоит из 2 панелей: Input Sections (входные секции) и Memory Map (выходные секции, карта памяти). За подробной информацией обратитесь к Главе 4 "Expert Linker".

Linker Utilities Manual Expert Linker Window fig2 3

Рис. 2-3. Окно Expert Linker.

[Сообщения об ошибках и предупреждения линкера]

Сообщения линкера записываются в окно Output среды VisualDSP++, или в standard output консоли операционной системы Windows (когда линкер запускается из командной строки). Сообщения описывают проблемы, с которыми столкнулся линкер при обработке файла .ldf. Предупреждения (Warnings) показывают ошибки обработки, которые недостаточно серьезные, чтобы не дать линкеру сгенерировать формально корректный выходной файл (как например сообщения о неиспользуемых символах в Вашем коде). Ошибки (Errors) будут выданы, когда линкер столкнулся с ситуацией, которая не дает ему возможности сгенерировать выходной файл.

Обычно эти сообщения включают имя файла .ldf, номер строки, к которой относится сообщение, 6-символьный код и краткое описание причины ошибки или предупреждения. Пример:

linker -proc ADSP-unknown a.doj [Error li1010] The processor 'ADSP-unknown' is
unknown or unsupported.

Вы можете получить описание сообщений линкера путем выбора шести символов кода сообщения (например li1010) и нажатия клавиши F1.

В среде VisualDSP++ закладка Build окна Output отображает статус сборки проекта и сообщения об ошибках. В большинстве случаев двойной клик на сообщение откроет окно редактора исходного файла с курсором в том месте, которое вызвало проблему.

Некоторые ошибки сборки, такие как ссылка не определенный символ (undefined symbol), не коррелируют непосредственно с исходными файлами. Эти ошибки часто связаны с упущениями в файле .ldf. Например, если входная секция из объектного файла не размещена файлом .ldf, то произойдет ошибка перекрестной ссылки (cross-reference error) на каждом объекте, который относится к меткам, задающим размещение в отсутствующей секции. Исправьте эту проблему путем пересмотра файла .ldf и указания в нем всех секций, которые требуют размещения (как вариант, исправьте исходный код, чтобы задать в нем другие, существующие секции для размещения объектов кода). Для дополнительной информации обратитесь к online Help.

[Линковка описания целевого процессора (Link Target Description)]

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

• Физическая карта памяти.
• Размещение программы в карте памяти системы.

Если в проекте нет файла .ldf, то линкер использует файл .ldf по умолчанию для процессора, который соответствует опции -proc < processor > командной строки линкера (или выбранному процессору в выпадающем списке Processor, который находится в диалоге Project Options проекта VisualDSP++ IDDE).

Удостоверьтесь, что понимаете архитектуру памяти процессора, которая описана в соответствующем даташите на аппаратуру процессора (Hardware Reference) и его даташите.

Этот раздел содержит следующие секции:

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

Представление архитектуры памяти. Команда MEMORY{} файла .ldf используется для представления архитектуры памяти Вашей процессорной системы. Линкер использует эту информацию для размещения исполняемого файла в память системы.

Чтобы оформить команду MEMORY{}, рассмотрите следующие вопросы:

• Использование памяти - список вариантов, которыми Ваша программа использует память системы. Типичное использование сегментов памяти включает таблицы векторов прерываний, данные инициализации, код программы, данные, область кучи и область стека. Подробнее см. "Указание отображения на память".
• Характеристики памяти - список типов памяти в Вашей процессорной системе, диапазон их адресов и ширину слова для каждого типа памяти. Тип памяти определяется как RAM или ROM.
• Команда MEMORY{} - создайте (или проверьте) В файле .ldf команду MEMORY{}, чтобы скомбинировать информацию из предыдущих двух пунктов, и декларировать сегменты памяти Вашей системы.

Для полной информации см. описание команды MEMORY{} в [6].

[Указания линкеру для отображения на память]

Встраиваемое программное обеспечение должно удовлетворять ограничениям, которые накладывает ширина шины данных процессора и возможности его адресации. Следующую информацию описывает файл .ldf для некого гипотетического проекта. Этот файл задает несколько сегментов памяти, что поддерживается командой SECTIONS{}, как это показано в её описании (см. [6]).

При выделении памяти важны следующие вопросы:

• Использование памяти и сегменты памяти по умолчанию.
• Обзор характеристик памяти.
• Команда линкера MEMORY{} в LDF.

Использование памяти и сегменты памяти по умолчанию. Имена входных секций генерируются компилятором автоматически, или указываются в исходном коде ассемблера. Файл .ldf определяет имена сегментов памяти и имена выходных секций. По умолчанию файл .ldf обрабатывает все генерируемые компилятором входные секции (см. столбец "Входная секция" в таблицах 2-1, 2-2 и 2-3). Сгенерированный файл .dxe имеет соответствующую выходную секцию для каждой входной секции. Хотя программисты обычно не используют метки выходных секций, эти метки используются другими нижележащими инструментами.

Используйте утилиту ELF file dumper (elfdump.exe), чтобы получить дамп содержимого выходной секции (например, data1) исполняемого файла. Информацию по этой утилите см. в разделе "elfdump - ELF File Dumper".

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

За подробностями обратитесь к файлу .ldf по умолчанию для Вашего процессора и к руководству по аппаратуре для этого процессора (Hardware Reference). Также см. "Wildcard Characters".

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

Таблица 2-1 показывает отображение секций в файле .ldf по умочланию для процессора ADSP-21161 (в качестве простого примера семейства процессоров SHARC).

Таблица 2-1. Привязка секций в файле Default SHARC LDF.

Входная секция Выходная секция Сегмент памяти
seg_pmco seg_pmco seg_pmco
seg_dmda seg_dmda seg_dmda
seg_pmda seg_pmda seg_pmda
seg_rth seg_rth seg_rth
seg_init seg_init seg_init
seg_init_code seg_init_code seg_init_code
seg_argv seg_argv seg_argv
seg_ctdm
seg_ctdml
dxe_ctdm mem_ctdm
seg_vtbl seg_vtbl seg_dmda
seg_sram seg_sram seg_sram
.bss .bss seg_dmda
.gdt
.gdtl
seg_dmda seg_dmda
.frt seg_dmda seg_dmda
.cht seg_dmda seg_dmda
.edt seg_dmda seg_dmda
.rtti seg_dmda seg_dmda
Только для проектов VDK:
seg_stack stackseg seg_stack
Только для процессоров ADSP-213xx/ADSP-214xx:
seg_stak stackseg seg_stak
seg_ext_code seg_ext_code seg_ext_code
seg_heap heap seg_heap
seg_ext_data seg_ext_data seg_ext_data
seg_sdram seg_sdram_data seg_ext_dmda
seg_flash seg_flash seg_flash
Только для процессоров ADSP-214xx:
seg_ext_code seg_ext_code seg_ext_swco
seg_swco seg_swco seg_int_code

Чтобы получить больше информации о выделении стека и кучи см. "Memory Usage" (использование памяти) в руководстве "VisualDSP++ C/C++ Compiler Manual for SHARC Processors". В файле .ldf по умолчанию для процессоров ADSP-210xx, ADSP-211xx, ADSP-212xx, ADSP-213xx, ADSP-214xx используется несколько входных секций и сегментов памяти, что должно присутствовать и в пользовательском файле .ldf. Ниже эти секции описаны подробнее.

.bss
Эта секция содержит глобальные данные, инициированные нулями (zero-initialized data). Линкер поместит содержимое этой секции данных в seg_dmda.

.rtti
Эта секция используется поддержкой идентификации типов C++ кода реального времени выполнения (C++ run-time type identification), когда эта функция разрешена.

seg_rth
Эта секция содержит таблицу векторов прерываний. По умолчанию она находится в файле начального запуска (start-up file, например 060_hdr.doj).

seg_init
Эта секция содержит информацию по месту размещения и размеру стека и кучи; также здесь содержатся сжатые данные, созданные утилитой инициализации памяти (см. описание опции -meminit).

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

seg_pmco
Эта секция представляет место по умолчанию для кода программы.

seg_pmda
Эта секция представляет место по умолчанию для глобальных данных программы, которые квалифицированы ключевым словом "pm". Например:

int pm xyz[100];  // размещено в секции seg_pmda

seg_argv
Эта секция содержит аргументы командной строки, которые используются как часть оптимизации по данным профайлера (profile-guided optimization, PGO [2, 3]).

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

seg_dmda
Эта секция по умолчанию служит местом размещения для глобальных данных и данных, квалифицированных ключевым словом "dm". Пример:

int abc[100];     // размещено в seg_dmda
int dm def[100];  // размещено в seg_dmda

В LDF-ах по умолчанию (не для проектов VDK) для процессоров ADSP-21020, ADSP-2106x, ADSP-2116x и ADSP-2126x стек run-time и куча также размещены в этой секции.

seg_stack (только для проектов VDK)
В этой секции размещен стек run-time. Здесь размещаются локальные переменные, параметры функций и т. п.

seg_stak (не для проектов VDK)
В LDF-ах для процессоров ADSP-2136x, ADSP-2137x и ADSP-2147x, ADSP-2148x эта секция служит местом, где размещен стек run-time. Здесь размещаются локальные переменные, параметры функций и т. п. В LDF-ах процессоров ADSP-21020, ADSP-2106x, ADSP-2116x и ADSP-2126x стек run-time stack находится в seg_dmda.

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

seg_sram
Эта секция представляет память SDRAM.

seg_heap
В LDF-ах по умолчанию для процессоров ADSP-2136x, ADSP-2137x, ADSP-2147x, ADSP-2148x эта секция является областью, для кучи. Из этой области динамически выделяется память специальными функциями и операторами (new, malloc(), и т. д.). В LDF-ах по умолчанию для процессоров ADSP-21020, ADSP-2106x, ADSP-2116x и ADSP-2126x функции выделения памяти и операторы создания объектов берут память из seg_dmda. Также и в LDF-ах проектов VDK эта секция представляет область, из которой берут память функции динамического выделения памяти и операторы создания объектов.

seg_flash
В LDF-ах для процессоров ADSP-213xx, ADSP-214xx эта секция представляет память flash.

seg_ext_swco
В LDF-ах для процессоров ADSP-214xx эта секция представляет внешнюю память, которая содержит инструкции короткого слова (short-word instructions, использование переменного набора инструкций).

seg_ext_nwco
В LDF-ах для процессоров ADSP-214xx эта секция представляет внешнюю память, которая содержит инструкции слова нормальной длины (normal-word instructions, использование обычного набора инструкций).

seg_ext_dmda
В LDF-ах для процессоров ADSP-214xx эта секция представляет внешнюю память, используемую для глобальных данных, квалифицированных ключевым словом "dm".

seg_ext_pmda
В LDF-ах для процессоров ADSP-214xx эта секция представляет внешнюю память, используемую для глобальных данных, квалифицированных ключевым словом "pm".

[Другие сегменты памяти]

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

seg_ctdml
Символ ___ctor_NULL_marker (находится в библиотеке C++ run-time) помечает конец списка глобальных и статических конструкторов, и этот символ размещен в этой секции данных. Линкер гарантирует, что содержимое этой секции данных представляет последние элементы в seg_ctdml.

.gdt, .gdtl, .frt, .cht и .edt
Эти секции данных для хранения данных, используемых в обработке исключений (exceptions, нештатные ситуации). Линкер размещает содежимое этих секций данных в seg_dmda. См. врезку "Специальные табличные входные секции Blackfin".

В таблице 2-2 показано отображение секций в файле .ldf по умолчанию для процессора ADSP-TS101 (используемого в качестве упрощенного примера как представителя семейства процессоров TigerSHARC).

Таблица 2-2. Привязка секций в LDF-файле по умолчанию для TigerSHARC.

Входная секция Выходная секция Сегмент памяти
program code M0Code
data1 data1 M1Data
data2 data2 M2Data
mem_argv mem_argv M1Data
bsz bsz M1Data
bsz_init bsz_init M1Data
ctor data1 M1Data
ctor0 data1 M1Data
ctor1 data1 M1Data
ctor2 data1 M1Data
ctor3 data1 M1Data
ctor4 data1 M1Data
.gdt
.gdtl
data1 M1Data
.frt data1 M1Data
.cht data1 M1Data
.edt data1 M1Data
.rtti data1 M1Data
vtbl vtbl M2DataA

Несколько входных секций и сегментов памяти, которые используются в LDF-ах по умолчанию для процессоров ADSP-TSxxx, должны присутствовать и в LDF-ах пользовательских проектов. Ниже эти секции описаны подробнее.

Для дополнительной информации по выделению стека и кучи см. раздел "Allocation of memory for stacks and heaps in LDFs" в руководстве "C/C++ Compiler and Library Manual for TigerSHARC Processors".

bsz
Это секция BSS-стиля, для размещения глобальных данных, инициализированных нулями.

bsz_init
Эта секция содержит данные инициализации для кода run-time (для дополнительной информации см. описание ключа командной строки -meminit).

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

Когда все секции ctor соединены друг с другом, они формируют таблицу, содержащую список всех конструкторов для всех глобальных объектов C++. Эта таблица используется только в момент запуска (startup), и может быть поэтому размещена в ПЗУ (ROM). При линковке важно, чтобы все секции ctor объединялись друг за другом (чтобы между ними не было других секций), и библиотека run-time обычного проекта (не VDK) или библиотека VDK run-time размещалась в первой секции ctor. Имейте в виду, что LDF-файлы по умолчанию размещают символ ___ctor_NULL_marker в секции с именем ctorl, которая должна быть последней из входных секций ctor. Последняя буква в имени этой секции - маленькая "L".

data1
Эта секция служит местом по умолчанию для глобальных данных программы.

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

mem_argv
Эта секция содержит аргументы командной строки, которые используются как часть оптимизации по данным профайлера (profile-guided optimization, PGO).

program
Эта секция представляет по умолчанию место для кода программы.

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

[Другие сегменты памяти]

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

ctorl
Эта секция содержит терминатор для секции таблицы ctor. Она должна быть отображена сразу после секций ctor.

.gdt, .gdtl, .frt, .cht, .edt и .rtti

Эти секции данных для хранения данных, используемых для обработки исключений. Линкер размещает содержимое этих секций в seg_dmda. См. врезку "Специальные табличные входные секции Blackfin".

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

См. [6] для получения дополнительной информации по файлам .ldf и указаниям по их настройке. Перед изменением файла .ldf по умолчанию рассмотрите возможность использования утилиты Expert Linker, которая доступна в среде VisualDSP++ IDDE. Генерация и конфигурирование пользовательского файла .ldf доступны при создании нового проекта (в среде VisualDSP++ через диалог свойств проекта Project Options).

program
Эта секция служит по умолчанию местом размещения для кода программы.

data1
Эта секция служит по умолчанию местом размещения для глобальных данных программы.

cplb_code
В этой секции библиотека run-time размещает подпрограммы обслуживания буфера кэширования (cacheability protection lookaside buffer, CPLB). Обычно эта секция отображается на L1 Instruction SRAM. В частности, если возможна замена CPLB, эта секция должна быть отображена на память, которая гарантированно всегда доступна; это означает, что она должна быть адресована заблокированными (locked) CPLB.

constdata
Эта секция используется для глобальных данных, которые декларируются как константы, и для литеральных констант, таких как строки и инициализаторы массивов.

cplb_data
В этой секции сохраняются таблицы конфигурации CPLB. В частности, файлы cplbtabx.doj (где x показывает target, т. е. целевой процессор) отображаются файлами .ldf с размещением в этой секции.

L1_DATA_A
Эта секция используется, чтобы данные можно было отобразить исключительно на L1 Data A SRAM с помощью директивы SECTION. По умолчанию компилятор здесь не генерирует данные. Эта секция аналогична L1_code, но L1_code не относится непосредственно только к области L1 Data A SRAM.

L1_DATA_B
Эта секция такая же, как L1_DATA_A, отличие только в том, что относится она к L1 Data B SRAM.

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

ctor
Эта секция содержит адреса функций конструкторов C++, которые вызываются перед main() для создания статических объектов. Отображение ctorl должно идти непосредственно за отображением ctor.

bsz
Эта секция используется для отображения глобальных данных, инициализированных нулями. Эта секция не содержит реальных данных, она просто заполняется нулями при загрузке кода в систему отладчиком (или симулятором) VisualDSP++ IDDE или через командную строку, или когда образ загрузки (файл .ldr) обрабатывается загрузчиком.

bsz_init
Эта секция содержит инициализационные данные run-time (см. описание опции командной строки -meminit). Подразумевается, что эта секция отображается на память только для чтения (read-only memory). Когда файл .dxe обрабатывается утилитой Memory Initializer, и программа запускается, другие секции данных (такие как data1 и constdata) инициализируются путем копирования данных из этой секции.

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

heap
Эта секция представляет область, где размещена куча системы. Сюда помещаются динамически выделяемые данные.

noncache_code
Эта секция отображается на области памяти, которые не могут кэшироваться, и содержат код программы. Эта секция используется, когда когда у Вас есть функция, которая включает кэш, чтобы гарантировать, что эта функция сама не попадет в кэш (поскольку выполнение кода из адреса памяти кэша вызовет hardware exception).

sdram0
В большинстве файлов .ldf и конфигураций LDF эта секция позволяет отобразить код или данные непосредственно на внешнюю память с помощью директивы SECTION. Это может использоваться для размещения во внешней памяти (обычно это L3 SDRAM) больших, не часто используемых данных или функций, чтобы освободить ценную внутреннюю память (L1 SRAM).

sdram0_bank{1|2|3}
Эта секция используется для отображения кода и данных в отдельные банки данных SDRAM, когда массив SDRAM разбит в файлах .ldf по умолчанию (обычно такое разделение отражает физическую организацию используемых микросхем SDRAM, что позволяет более эффективно использовать память).

sdram_bcz
Эта секция такая же, как секция bsz, отличие только в том, что данные размещаются в SDRAM, когда SDRAM разрешена.

sdram_shared
Эта секция используется для отображения кода и данных в часть памяти, которая используется совместно (shared memory) между core A и core B в многоядерных системах.

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

[Другие сегменты памяти]

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

ctorl
Эта секция содержит терминатор для секции таблицы ctor. Она должна быть отображена сразу после секций ctor.

.gdt, .gdtl, .frt, .cht, .edt и .rtti
Эти секции данных для хранения данных, используемых для обработки исключений. См. врезку "Специальные табличные входные секции Blackfin".

Следующие "табличные" секции данных используются для хранения данных при обработке исключений (handling exceptions). Обычно линкер отображает эти секции в память только для чтения (read-only memory). Чаще всего это FLASH или SDRAM.

.gdt
Секция .gdt (global dispatch table, глобальная таблица диспетчеризации) используется библиотекой обработки исключений C++ (C++ exception library), чтобы определить область кода, которому принадлежит определенный адрес. Эта секция должна быть непрерывной в памяти.

.gdtl
Эта секция содержит терминатор для табличной секции .gdt. Она должна быть отображена непосредственно после секции .gdt.

.edt
Секция .edt (exception dispatch table, таблица диспетчеризации исключений) используется библиотекой обработки исключений C++, чтобы отобразить код из блоков try в блоки catch.

.cht
Секция .cht (catch handler types table, таблица типов обработки catch) используется для отображения информации типов реального времени выполнения (RTTI type information). Библиотека обработки исключений C++ использует это, чтобы определить типы, которые соответствуют элементам catch для блока try.

.frt
Секция .frt (function range table, таблица диапазона функции) используется в библиотеке обработки исключений C++ во время обработки исключения, чтобы отмотать стек активных функций.

primio_atomic_lock
Эта секция используется управляющей переменной, которая используется для гарантирования атомарности операций файлового ввода/вывода (atomic file I/O). Она должна быть в общей памяти (shared memory), и не должна кэшироваться.

mc_data
Эта секция используется для хранилища, относящегося к определенному ядру в многоядерных (multi-core, MC) системах.

.rtti
Эта секция используется C++ для хранения информации о типах реального времени выполнения (C++ run-time type identification), когда эта функция разрешена (используется обычно для отладки).

cplb
Эта секция используется в файлах .ldf из соображений совместимости с традиционным кодом.

Эти секции обычно не используются компилятором Blackfin и библиотеками.

L1_data
Эта секция используется, чтобы позволить отобразить глобальные данные исключительно на быстрое внутреннее ОЗУ данных (L1 data SRAM) с помощью директивы #pragma section или ключевого слова section. Эта входная секция отображает данные на оба банка внутренней памяти A и B, присутствующих в целевом процессоре.

L1_data_a
Эта секция обычно не используется компилятором Blackfin и библиотеками. Она отображает данные на банк A внутренней памяти данных L1 процессора.

L1_data_b
Эта секция подобна L1_data_a, отличие только в том, что данные отображаются на банк B внутренней памяти данных L1 процессора.

L1_code
Эта секция используется, чтобы позволить отобразить код исключительное на быстрое внутреннее ОЗУ кода (L1 code SRAM) с помощью директивы #pragma section или ключевого слова section.

L1_bcz
Эта секция используется для отображения глобальных данных, инициализированных нулем, на быстрое внутреннее ОЗУ данных (L1 data SRAM) с помощью директивы #pragma section или ключевого слова section.

L2_bcz
Эта секция используется для отображения глобальных данных, инициализированных нулем, на внутреннее ОЗУ данных L2 тех целевых процессоров, у которых есть такой тип памяти. Отображение также осуществляется с помощью директивы #pragma section или ключевого слова section.

L2_sram
Эта секция может использоваться для отображения кода и данных на память L2 для не многоядерных (non-multicore) процессоров, на борту которых есть L2 SRAM.

l2_sram
Эта секция может использоваться на многоядерных системах для отображения кода и данных на память L2 процессоров, на борту которых есть L2 SRAM.

L2_sram_a
Эта секция используется для отображения кода и данных на память L2, зарезервированную для ядра A (core A) процессора в многоядерной (multicore) системе.

L2_sram_b
Эта секция используется для отображения кода и данных на память L2, зарезервированную для ядра B (core B) процессора в многоядерной (multicore) системе.

l2_shared
Эта секция используется для отображения кода и данных на память L2, которая совместно используется (shared memory) между ядрами core A и core B на многоядерной (multicore) системе.

Обзор характеристик памяти. Эта секция дает базовую информацию о памяти (включая адреса и диапазоны адресов) для примеров целевых архитектур процессоров.

Некоторые порции памяти процессора зарезервированы. За дополнительной информацией обратитесь к аппаратному руководству процессора (Hardware Reference).

В качестве примера архитектуры памяти SHARC, процессор ADSP-21161 содержит большой двухпортовый массив внутренней памяти с временем доступа за 1 такт, одновременным и независимым со стороны ядра (core processor) и аппаратуры ввода/вывода (I/O processor). Двухпортовая (dual-ported) память (в комбинации с тремя отдельными шинами процессора на кристалле) позволяет за 1 такт осуществить 2 перемещения данных от ядра и 1 перемещение данных от процессора ввода/вывода. Используя шину ввода/вывода (I/O bus), процессор ввода/вывода предоставляет перемещения данных между внутренней памятью процессора и коммуникационными портами (аппаратные линки для подключения периферийных устройств, последовательные порты и внешний порт), не мешая ядру процессора обращаться к памяти. Процессор предоставляет доступ к внешней памяти через внешний порт процессора (external port).

Процессор содержит 1 мегабит встроенной памяти SRAM, организованной блоками по 0.5 мегабит. Каждый блок может быть сконфигурирован для различных комбинаций хранения кода и данных. Ко всей памяти доступ может осуществляться словами по 16, 32, 48 или 64 бита. Память может быть сконфигурирована, чтобы каждый блок содержал максимум 16 килослов 32-битных данных, 8 килослов 64-битных данных, 32 килослова 16-битных данных, 10.67 килослова 48-битных инструкций (или 40-битных данных), или комбинациями различных размеров слов блоками до 0.5 мегабит. Это дает общую максимальную емкость внутренней памяти: 32 килослова 32-битных данных, 16 килослов 64-битных данных, 64 килослова 16-битных данных и 21 килослов 48-битных инструкций (или 40-битных данных).

Процессор использует 16-битный формат хранения с плавающей точкой, который эффективно удваивает количество данных, которое может быть сохранено в кристалле процессора. Одна инструкция преобразует формат из 32-битной floating-point в 16-бит floating-point.

Хотя каждый блок памяти может хранить в себе комбинации кода и данных, доступы наиболее эффективны, когда один блок для передачи данных использует шину DM (обычно Block 1), и другой блок (обычно Block 0) хранит инструкции и данные, используя шину PM. Использование шин DM и PM таким образом, что каждой из шин выделен отдельный блок, гарантирует обработку двух передач по этим шинам за 1 такт. В этом случае инструкция должна быть доступна в кэше.

Внутренняя память. Процессоры ADSP-21161 имеют 2 мегабита внутреннего пространства памяти; адресовать можно 1 мегабит. 1 мегабит памяти делится на 2 блока по 0.5 мегабит: Block 0 и Block 1. Дополнительная область размером в 1 мегабит резервируется. Таблица 2-3 показывает максимальное количество слов данных или слов инструкций, которое может уместиться в каждом внутреннем блоке памяти 0.5 мегабит.

Таблица 2-3. Слова в отдельном 0.5 мегабитном внутреннем блока памяти.

Тип слова Бит в слове Минимальное количество слов на 0.5-мегабитный блок
Инструкция 48 10.67 килослов
Длинное слово данных (long) 64 8 килослов
Обычное слово данных расширенной точности (extended-precision) 40 10.67 килослов
Обычное слово данных 32 16 килослов
Короткое слово данных (short) 16 32 килослова

Внешняя память. Несмотря на то, что внутренняя память процессора поделена на блоки, внешняя память процессора поделена на банки. Блоки внутренней памяти и области внешней памяти могут адресоваться любым генератором адреса для данных (data address generator, DAG). Размеры банков внешней памяти фиксированного размера могут быть сконфигурированы для разных конфигураций тактов ожидания (waitstate) и доступа.

Процессор может адресовать до 254 мегаслов пространства внешней памяти. Внешняя память подключается к внешнему порту процессора (external port), который расширяет 24-битную шину адреса и 32-битную шину данных процессора. Процессор может делать доступы к внешней памяти разрядностью 8, 16, 32 или 48 бит для инструкций и доступы разрядностью 8, 16 или 32 бита для данных. Таблица 2-4 показывает типы доступа и слова для обращений к внешней памяти. Контроллер DMA процессора автоматически упаковывает внешние данные в подходящую ширину слова во время перемещения данных.

Внешняя шина данных может быть расширена до 48 бит, если link-порты запрещены, и в регистре SYSCON разрешен соответствующий режим упаковки инструкции полной ширины (full-width instruction packing mode, IPACK). Убедитесь, что link-порты запрещены, когда код выполняется из внешней 48-битной памяти.

Таблица 2-4. Перемещения слов память Internal - память External.

Тип слова Тип передачи
Упакованная инструкция Упаковка 32-, 16- или 8-в-48 бит
Обычное слово данных 32-битное слово в 32-битной передаче
Короткое слово данных (short) Не поддерживается

Общее адресуемое адресное пространство для внешнего банка памяти фиксированного размера зависит от того, какая память используется - SDRAM или не-SDRAM (такая как SRAM, SBSRAM). Каждый внешний банк памяти для SDRAM может адресовать 64 мегаслов. Для не-SDRAM каждый банк может адресовать до 16 мегаслов. Остальные 48 мегаслов остаются зарезервированными. Зарезервированные адреса для обращений к не-SDRAM зеркалируются на первые 16 мегаячеек в банке.

В качестве примера архитектуры памяти TigerSHARC, процессор ADSP-TS101 имеет 3 внутренних блока памяти: M0, M1 и M2. Каждый блок памяти состоит из 2 мегабит области памяти, и конфигурируется как 64 килослова (каждое шириной 32 бита). На кристалле процессора имеется 3 раздельные 128-разрядные шины данных, каждая из которых подключена к одному из блоков памяти. Блоки памяти могут попеременно (interchangeably) хранить инструкции и данные, с одним доступом к блоку памяти на такт. Если программист гарантирует, что программа и данные находятся в разных блоках памяти, то доступ к данным может происходить одновременно с выборкой инструкции (program fetch). Таким образом, в одном такте может произойти до трех 128-битных перемещения данных в ядре (два перемещения данных и одно перемещение инструкции).

Link Target Description. Процессор ввода/вывода (I/O Processor) может использовать в любой момент времени только одну внутреннюю шину, и процессор ввода/вывода конкурирует с ядром за использование внутренней шины. Таким образом, в одном такте процессор может выбрать четыре 32-битных инструкции, или сохранить 256 бит данных (четыре 64-битных слова, восемь 32-битных слова, шестнадцать 16-битных слова или тридцать два 8-битных слова). 32-битная адресная шина процессора TigerSHARC предоставляет адресное пространство в 4 гигаслова. Это адресное пространство является общим для кластера процессоров TigerSHARC, которые используют одну и ту же общую шину кластера.

Зоны в пространстве памяти строятся из следующих регионов:

• Регион пространства внешнего банка памяти (External memory bank space) - используется для стандартной адресации внешней по отношению к кристаллу процессора памяти (включая SDRAM, MB0, MB1 и host).
• Внешнее мультипроцессорное пространство (External multiprocessor space) - встроенная в кристалл процессора память всех других процессоров TigerSHARC, соединенных в мультипроцессорную систему.
• Внутреннее адресное пространство (Internal address space) - регион для стандартной внутренней адресации.

В системе примера процессор ADSP-TS101 имеет внутренние адреса памяти от 0x0 до 0x17FFFF, см. таблицу 2-5.

Таблица 2-5. Структура памяти процессора ADSP-TS101.

Блок Диапазон Размер слова
Блок памяти M0 0x0000 0000 - 0x0000 FFFF 32-битные инструкции.
  0x0001 0000 - 0x0007 FFFF Зарезервировано.
Блок памяти M1 0x0008 0000 - 0x0008 FFFF 32-битные инструкции.
  0x0009 0000 - 0x0009 FFFF Зарезервировано.
Блок памяти M2 0x0010 0000 - 0x0010 FFFF 32-битные инструкции.
  0x0011 0000 - 0x0017 FFFF Зарезервировано.
Внутренние регистры 0x0018 0000 - 0x0018 07FF Управление, статус, регистры ввода/вывода. Это не может использоваться в LDF-файлах. Внутренние регистры это память, доступная только в пространстве MP.
  0x0018 0800 - 0x01BF FFFF Зарезервировано.
  0x01C0 0000 - 0x03FF FFFF Широковещание и MP (не используется в LDF).
SDRAM 0x0400 0000 - 0x07FF FFFF 32-битные инструкции.

Подробности по характеристикам памяти различных представителей процессоров семейства Blackfin можно найти в соответствующем даташите на аппаратуру процессора (Hardware Reference), загруженном с сайта компании Analog Devices. Воспользуйтесь строкой поиска в Google такого вида (на примере процессора ADSP-BF504F):

ADSP-BF50x Hardware Reference site:analog.com

[Команда линкера MEMORY{} в файле LDF]

С использованием информации из секций этой статьи "Использование памяти и сегменты памяти по умолчанию" и "Обзор характеристик памяти", Вы можете командой MEMORY{} описать память целевого процессора любой архитектуры (листинги 2-1, 2-2 и 2-3 предоставляют примеры для определенных процессоров).

Листинг 2-1. Код команды MEMORY{} процессора ADSP-21161.

MEMORY
{
seg_rth        { TYPE(PM RAM) START(0x00040000) END(0x000400ff)
                 WIDTH(48) }
seg_init       { TYPE(PM RAM) START(0x00040100) END(0x000401ff)
                 WIDTH(48) }
seg_int_code   { TYPE(PM RAM) START(0x00040200) END(0x00040287)
                 WIDTH(48) }
seg_pmco       { TYPE(PM RAM) START(0x00040288) END(0x000419ff)
                 WIDTH(48) }
seg_pmda       { TYPE(PM RAM) START(0x00042700) END(0x00043fff)
                 WIDTH(32) }
seg_dmda       { TYPE(DM RAM) START(0x00050000) END(0x00051fff)
                 WIDTH(32) }
seg_heap       { TYPE(DM RAM) START(0x00052000) END(0x00052fff)
                 WIDTH(32) }
}

Листинг 2-2. Код команды MEMORY{} процессора ADSP-TS101.

/* Файл TS101_memory.ldf */
MEMORY
{/* Внутренние блоки памяти размером 0x10000 (64K байт) */
M0Code   {TYPE(RAM) START(0x00000000) END(0x0000FFFF) WIDTH(32)}
M1Data   {TYPE(RAM) START(0x00080000) END(0x0008BFFF) WIDTH(32)}
M1Stack  {TYPE(RAM) START(0x0008C000) END(0x0008FFFF) WIDTH(32)}
M2Data   {TYPE(RAM) START(0x00100000) END(0x0010BFFF) WIDTH(32)}
M2Heap   {TYPE(RAM) START(0x0010C000) END(0x0010C7FF) WIDTH(32)}
M2Stack  {TYPE(RAM) START(0x0010C800) END(0x0010FFFF) WIDTH(32)}
SDRAM    {TYPE(RAM) START(0x04000000) END(0x07FFFFFF) WIDTH(32)}
MS0      {TYPE(RAM) START(0x08000000) END(0x0BFFFFFF) WIDTH(32)}
MS1      {TYPE(RAM) START(0x0C000000) END(0x0FFFFFFF) WIDTH(32)}
}

Листинг 2-3. Код команды MEMORY{} процессора ADSP-BF533.

MEMORY /* Определение/метка системной памяти */
{ /* Список глобальных сегментов памяти */
   MEM_L2_CODE
      { TYPE(RAM) START(0xF0000000) END(0xF002FFFF) WIDTH(8) }
   MEM_L1_DATA_A
      { TYPE(RAM) START(0xFF800000) END(0xFF803FFF) WIDTH(8) }
   MEM_L1_DATA_B
      { TYPE(RAM) START(0xFF900000) END(0xFF903FFF) WIDTH(8) }
   MEM_HEAP
      { TYPE(RAM) START(0xF0030000) END(0xF0037FFF) WIDTH(8) }
   MEM_STACK
      { TYPE(RAM) START(0xF0038000) END(0xF003DFFF) WIDTH(8) }
   MEM_ARGV
      { TYPE(RAM) START(0xF003FE00) END(0xF003FFFF) WIDTH(8) }
   MEM_SDRAM0
      { TYPE(RAM) START(0x00000004) END(0x07FFFFFF) WIDTH(8) }
}

Приведенные выше примеры относятся к предыдущему обсуждению того, как писать команду MEMORY{}, и для последующего обсуждения команды SECTIONS{}. Команда SECTIONS{} не атомарна; она может быть сочетаться с другими директивами, включая информацию счетчика размещения (location counter). Вы можете определить новые символы внутри файла .ldf. Эти примеры определяют начальный адрес стека, самый большой возможный адрес стека, и также начальное место размещения кучи и её размер. Эти новые созданные символы вводятся в таблицу символов исполняемых файлов.

[Адрес элемента (Entry Address)]

В релизах до VisualDSP++ 4.5 адрес входа в программу заполнялся из глобального символа start (без нижнего подчеркивания), если он присутствовал. Символ "start" должен был быть глобальным символом или символом LDF.

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

• Опцией командной строки -entry, где аргументом опции является символ.
• Командой ENTRY(символ) в файле .ldf. Если присутствуют оба варианта, и -entry, и ENTRY(), то они должны быть одинаковые. Способы -entry и ENTRY() не переназначают установки друг друга: если они не совпадают, то линкер определит ошибку.
• Если опция командной строки -entry или команда ENTRY() отсутствуют, то используется значение глобального символа файла start, или символ LDF start, если они присутствуют.
• Если ни один из способов указания адреса не использован, то адрес входа равен 0.

Мультипроцессорные/многоядерные приложения. Опция командной строки -entry применена для multiprocessor/multi-core файла .ldf, то она накладывает одинаковый адрес элемента для всех процессоров. Если адреса элементов отличаются (в многопроцессорных системах), то используйте команды ENTRY() в файле .ldf, и не используйте опцию командной строки -entry.

Если опция командной строки -entry указана, то произойдет ошибка в случае, когда любой из процессоров использует команду ENTRY() с другой спецификацией.

Символы группового замещения (Wildcard Characters). Линкер поддерживает использование wildcards в спецификациях имени входной секции файла .ldf. Символы wildcard * and ?, предоставленные в имени входной секции, дают возможность указать несколько входных секций.

* соответствует любому количеству символов
? соответствует любому одному символу

Для получения информации по используемым символам wildcard (и примерам использования) см. описание команды INPUT_SECTIONS().

[Размещение кода в целевом процессоре]

Используйте команду SECTIONS{}, чтобы отобразить код и данные на физическую память процессора в системе, где он применяется. Чтобы написать команду SECTIONS{}, выполните следующее:

1. Перечислите все входные секции, определенные в файлах исходного кода.

• Для файлов на ассемблере - перечислите каждую директиву .SECTION, встречающуюся в коде ассемблера, идентифицирующую её тип памяти (PM или CODE, DM или DATA), и обратите внимание на места, когда размещение кода критично для его функционирования. Эти порции .SECTIONS включают таблицы векторов прерываний, буферы данных, и встроенного в кристалл кода или данных (см. "Указание двух буферов в разных сегментах памяти" для информации, специфической для процессоров TigerSHARC).
• Для файлов на C/C++ - компилятор генерирует секции с именем "program" или "code" для кода, и именами "data1" и "data2" для данных. Эти секции соответствуют Вашему исходному коду, когда Вы не указываете секцию памяти путем расширения определения объектов необязательным ключевым словом section() (или соответствующей директивой #pragma section).

2. Сравните список входных секций с сегментами памяти, указанными в команде MEMORY{}. Идентифицируйте сегмент памяти, куда должна быть размещена каждая область .SECTION.

3. Скомбинируйте информацию из этих двух списков, чтобы записать одну или больше команд SECTIONS{} в файле .ldf.

Команды SECTIONS{} должны появляться в контексте команды PROCESSOR{} или SHARED_MEMORY().

В листинге 2-4 представлена команда SECTIONS{}, которая будет работать с командой MEMORY{} из листинга 2-1.

Листинг 2-4. Команда SECTIONS{} в LDF процессора ADSP-21161.

SECTIONS
{
   /* Начало выходных секций */
   seg_rth { // Хедер run-time и таблица прерываний
      INPUT_SECTIONS( $OBJS(seg_rth) $LIBS(seg_rth))
   } >seg_rth
   seg_init { // Инициализация
      ldf_seginit_space = . ;
      INPUT_SECTIONS( $OBJS(seg_init) $LIBS(seg_init))
   } >seg_init
   seg_init_code { // Данные инициализации
      INPUT_SECTIONS( $OBJS(seg_init_code)
      $LIBS(seg_init_code))
   } >seg_init_code
   seg_pmco { // Код PM
      INPUT_SECTIONS( $OBJS(seg_pmco) $LIBS(seg_pmco))
   } >seg_pmco
   seg_pmda { // Данные PM
      INPUT_SECTIONS( $OBJS(seg_pmda) $LIBS(seg_pmda))
   } >seg_pmda
   .bss ZERO_INIT {
      INPUT_SECTIONS( $OBJS(.bss) $LIBS(.bss))
   } >seg_dmda
   seg_dmda { // Данные DM
      INPUT_SECTIONS( $OBJS(seg_dmda) $LIBS(seg_dmda))
   } >seg_dmda
   heap {
      // Выделение кучи для приложения
      ldf_heap_space = .;
      ldf_heap_length = MEMORY_SIZEOF(seg_heap);
      ldf_heap_end = ldf_heap_space + ldf_heap_length - 1;
   } > seg_heap;
} // Конец секций

Листинг 2-5 представляет команду SECTIONS{}, которая должна работать с командой MEMORY{} из листинга 2-2.

Листинг 2-5. Команда SECTIONS{} в LDF процессора ADSP-TS101.

SECTIONS
{  /* Список секций для процессора P0 */
   sec_rth {INPUT_SECTIONS ( $OBJECTS(rth))} > seg_rth
   sec_code {INPUT_SECTIONS ( $OBJECTS(code)} > seg_code
   sec_code2 {INPUT_SECTIONS ( $OBJECTS(y_input)} > seg_code
   sec_data1 {INPUT_SECTIONS ( $OBJECTS(data1))} > seg_data1
}

Листинг 2-6 представляет команду SECTIONS{}, которая должна работать с командой MEMORY{} из листинга 2-3.

Листинг 2-6. Команда SECTIONS{} в LDF процессора ADSP-BF535.

SECTIONS
{  /* Список секций для процессора P0 */
   L1_code
   {
      INPUT_SECTION_ALIGN(2)
      /* Выравнивание всех секций кода на границу 2 байта */
      INPUT_SECTIONS( $OBJECTS(program) $LIBRARIES(program))
      INPUT_SECTION_ALIGN(1)
      INPUT_SECTIONS( $OBJECTS(data1) $LIBRARIES(data1))
      INPUT_SECTION_ALIGN(1)
      INPUT_SECTIONS( $OBJECTS(constdata)
      $LIBRARIES(constdata))
      INPUT_SECTION_ALIGN(1)
      INPUT_SECTIONS( $OBJECTS(ctor) $LIBRARIES(ctor) )
   } >MEM_L2_CODE
 
   program
   {
      /* Выравнивание всех секций кода на границу 4 байта */
      INPUT_SECTION_ALIGN(4)
      INPUT_SECTIONS( $OBJECTS(program) $LIBRARIES(program))
      INPUT_SECTIONS( $OBJECTS(data1) $LIBRARIES(data1))
      INPUT_SECTIONS( $OBJECTS(cplb) $LIBRARIES(cplb))
      INPUT_SECTIONS( $OBJECTS(cplb_code)
      $LIBRARIES(cplb_code))
      INPUT_SECTIONS( $OBJECTS(cplb_data)
      $LIBRARIES(cplb_data))
      INPUT_SECTIONS( $OBJECTS(constdata)
      $LIBRARIES(constdata))
      INPUT_SECTIONS( $OBJECTS(voldata) $LIBRARIES(voldata))
   } >MEM_PROGRAM
 
   stack
   {
      ldf_stack_space = .;
      ldf_stack_end =
      ldf_stack_space + MEMORY_SIZEOF(MEM_STACK) - 4;
   } >MEM_STACK
 
   heap
   {  /* Выделение кучи для приложения */
      ldf_heap_space = .;
      ldf_heap_end =
      ldf_heap_space + MEMORY_SIZEOF(MEM_HEAP) - 1;
      ldf_heap_length = ldf_heap_end - ldf_heap_space;
   } >MEM_HEAP
   
   argv
   { /* Выделение пространства для argv для приложения */
      ldf_argv_space = .;
      ldf_argv_end =
      ldf_argv_space + MEMORY_SIZEOF(MEM_ARGV) - 1;
      ldf_argv_length =
      ldf_argv_end - ldf_argv_space;
   } >MEM_ARGV
} /* Конец SECTIONS */

Определение 2 буферов в разных сегментах памяти. На процессорах TigerSHARC линкер поддерживает оптимизированное размещение в памяти с помощью директивы ассемблера .SEPARATE_MEM_SEGMENTS.

• Директива ассемблера .SEPARATE_MEM_SEGMENTS (или директива компилятора #pragma separate_mem_segments) задает размещать 2 буфера так, чтобы каждый из них размещался в разных сегментах памяти. Пример:

.SECTION data1;
.VAR buf1;
.VAR buf2;
.EXTERN buf3;
.SEPARATE_MEM_SEGMENTS(buf1, buf2);
.SEPARATE_MEM_SEGMENTS(buf1, buf3);

• Набор доступных сегментов памяти для каждого буфера определяется с использованием функции отображения линкера "one-to-many" (один ко многим) для входной секции (секций) чтобы разместить буферы в нескольких сегментах памяти. Пример:

data2 {
   INPUT_SECTIONS( $OBJECTS(data1) )
} >M2DataA 
 
data4 {
   INPUT_SECTIONS( $OBJECTS(data1) )
} >M4DataA

• Линкер пытается удовлетворить ограничение по размещению путем выделения буферов в разных сегментах памяти.

1. Если линкер не сможет удовлетворить условия размещения, то он выдаст предупреждение.
2. Все символы, которые упомянуты в .SEPARATE_MEM_SEGMENTS, будут отображены линкером самыми первыми до всего остального (за исключением абсолютного размещения).
3. Ссылка на символ в .SEPARATE_MEM_SEGMENTS является слабой ссылкой. Если такой символ определен в библиотеке, то линкер не берет этот символ из библиотеки (кроме случая, когда на этот символ есть прямая или косвенная ссылка из объектного файла).
4. Линкер игнорирует случаи, где символ, упомянутый в директиве ассемблера .SEPARATE_MEM_SEGMENTS, не определен, или не определен во входной секции (например, как символ LDF).

Для дополнительной информации см. раздел с описанием директив #pragma в Главе 1 руководства "VisualDSP++ 5.0 C/C++ Compiler and Library Manual for TigerSHARC Processors".

Линковка с атрибутами (обзор). В файле .ldf атрибуты используются для создания виртуальных подмножеств из обычных входных источников. Атрибуты связаны с файлами .doj, включая код, находящийся в библиотеке. Будучи созданными, эти подмножества существуют во время линковки и могут использоваться в любом месте библиотеки или списке объектов, нормально появляющемся в файле .ldf.

Атрибуты используются в файле .ldf используются для уменьшения обычного набора входных файлов до удобных для обслуживания, управляемых подмножеств. Входные данные существуют в 2 формах (объекты и библиотеки), обе они появляются в списках файла .ldf. На эти списки могут быть наложены фильтры для просеивания нежелательных в данный момент объектов.

Атрибут это пара строк имя/значение. Допустимым именем атрибута является допустимый идентификатор языка C.

Имена атрибутов и значения атрибутов чувствительных к регистру (case-sensitive). Имена файлов Windows могут могут использоваться как значения, если позаботиться о непротиворечивости таких атрибутов.

Атрибут связывается с объектом (.doj), но не с библиотекой (.dlb), не с именем символа, и не с именем секции ELF. Объект имеет ноль или большее количество связанных с ним атрибутов. Имеющийся объект может иметь больше одного связанного с ним атрибута с таким же именем.

С использованием атрибутов может быть применен процесс фильтрации, чтобы удалить из рассмотрения некоторые объекты, тем самым те же объекты не подключаются где-то еще через другие фильтры (или через не фильтрованные привязки). Работа фильтра осуществляется с помощью фигурных скобок, и он может использоваться для определения sub-списков и sub-библиотек. Это может также использоваться в командах INPUT_SECTIONS (см. описание этой команды).

Линкер читает файл .ldf и использует команды фильтра {...} (например команды INPUT_SECTIONS), чтобы удалить из рассмотрения некоторые входные объекты перед разрешением символов. Линкер не меняет свое поведение, если в файле .ldf нет команд фильтра.

Поддержка оптимизации по информации профайлера (Profile-Guided Optimization, PGO). Архитектуры SHARC, TigerSHARC и Blackfin поддерживают специальный вид оптимизации, PGO. Это процесс сбора информации о работающем приложении путем запуска приложения с разными входными данными, и после этого выполнение повторной оптимизации с учетом собранной информации.

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

Файлы .ldf и VisualDSP++ IDDE работают совместно для предоставления аргументов командной строки. При нормальных условиях работы типичная embedded-программа не интересуется аргументами командной строки, и ничего подобного не получает. В этих нормальных ситуациях заголовок run-time привлекает функцию для обработки глобальной строки __argv_string[] и обнаруживает, что она пустая.

Для поддержки PGO может использоваться LDF-опция IDDE_ARGS для определения сегмента памяти с именем MEM_ARGV, и __argv_string[] непосредственно отображается на начало этой секции. Система VisualDSP++ IDDE следует соглашению, что аргументы командной строки могут могут быть переданы в приложение путем записи строки аргумента в память, указанную началом MEM_ARGV.

Для дополнительной информации о PGO см. руководство "VisualDSP++ 5.0 C/C++ Compiler and Library Manual" для подходящей архитектуры процессора.

Передача аргументов для симуляции и эмуляции. Символ _argv_string это строка, заканчивающаяся нулем (ASCIIZ, null-terminated string), и если она содержит что-либо кроме null, то это содержимое будет разделено каждым символом пробела, и результат помещен в массив argv[], который передается в функцию main при запуске системы (startup).

[Справочник по командной строке линкера]

В этой секции документации предоставлена следующая справочная информация:

• "Синтаксис командной строки линкера".
• "Опции командной строки линкера".

Когда Вы используете линкер в среде VisualDSP++ IDDE, настройки раздела Link диалога свойств проекта (Project Options) соответствуют опциям командной строки линкера. Здесь предоставлено подробное описание опций командной строки линкера и её синтаксис. Для дополнительной информации см. онлайн Help среды VisualDSP++.

Синтаксис командной строки линкера. Запуск линкера осуществляется следующими нормализованными форматами командной строки.

linker -proc processor -switch [-switch ...] object [object ...]
linker -T target.ldf -switch [-switch ...] object [object ...]

Команда линкера требует обработки опции -proc тип_процессора или -T < имя_файла_ldf >. Если в командной строке нет опции -proc тип_процессора, то файл .ldf, указанный опцией -T, должен содержать команду -ARCHITECTURE. Командная строка линкера может содержать обе эти опции, но команда ARCHITECTURE() файла .ldf должна соответствовать опции -proc тип_процессора.

Используйте опцию -proc тип_процессора вместо устаревшей опции командной строки -Darchitecture, чтобы выбрать целевой процессор. См. таблицу 2-7 для дополнительной информации.

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

Ниже приведено несколько примеров команд линкера.

linker -proc ADSP-21161 p0.doj -T target.ldf -t -o program.dxe
linker -proc ADSP-TS201 p0.doj -T target.ldf -t -o program.dxe
linker -proc ADSP-BF535 p0.doj -T target.ldf -t -o program.dxe

Командная строка линкера (кроме имен файлов) чувствительна к регистру символов (case sensitive). Например, действие опции -t отличается от опции -T.

Линкер может управляться компилятором через опцию командной строки -flags-link, которая явно передает опции линкеру. Для дополнительной информации см. Главу 1 руководства "VisualDSP++ 5.0 C/C++ Compiler and Library Manual" для подходящего процессора.

Когда используется командная строка линкера, изучите следующие темы:

• Объектные файлы командной строки.
• Имена файлов командной строки.
• Типы объектных файлов.

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

• Стандартные объектные файлы (.doj), производимые ассемблером.
• Один или большее количество библиотек (архивов), каждая с расширением .dlb. Примеры включают библиотеки C run-time и библиотеки математики, поставляемые вместе с VisualDSP++. Вы можете создать библиотеки общих или специализированных объектов. Специальные библиотеки доступны из алгоритмов DSP вендоров. Для дополнительной информации см. Главу 6 "Archiver" в руководстве [1].
• Исполняемый файл (.dxe), который является результатом линковки. Обратитесь к описанию $COMMAND_LINE_LINK_AGAINST в разделе "Встроенные макросы LDF".

Имена объектных файлов. Имя объектного файла может включать:

• Диск, путь до директории, имя файла и расширение файла.
• Путь до директории может быть абсолютным или относительным по отношению к каталогу, из которого запущен линкер.
• Длинные имена файлов заключаются в прямые кавычки.

Если файл существует перед началом линковки, то линкер открывает этот файл, чтобы проверить его тип перед обработкой. Таблица 2-6 перечисляет допустимые расширения файла, используемые линкером.

Имена файлов командной строки. Некоторые опции командной строки линкера получают имя файла как параметр. Таблица 2-6 перечисляет типы файлов, имена и расширения, которые линкер ожидает в аргументах имен файла. Линкер следует соглашению расширений файлов из таблицы 2-6.

Таблица 2-6. Соглашение о расширениях файла.

Расширение Описание файла
.dlb Библиотечный файл (archive, архив кода)
.doj Файл объектного кода
.dxe Исполняемый файл
.ldf Linker Description File (файл команд для линкера)
.ovl Файл оверлея
.sm Файл общей памяти (shared memory, применяется в многопроцессорных MP и многоядерных MC системах)

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

1. Указанный путь – если командная строка включает информацию об относительных или абсолютных путях, то линкер в этом месте ищет места размещения файлов.
2. Указанные директории – если Вы не включили информацию пути в командной строке, и файл не находится в директории по умолчанию, линкер ищет файл в директориях поиска, указанных опцией командной строки -L (path), и тогда директории поиска указываются командами SEARCH_DIR в файле .ldf. Директории перебираются при поиске в том порядке, в каком они появляются в командной строки или в файле .ldf.
3. Директория по умолчанию – если Вы не включили информацию пути в файле .ldf, указанном опцией командной строки -T, линкер ищет файл .ldf в текущей рабочей директории. Если Вы используете файл .ldf по умолчанию (опуская информацию LDF в командной строке, и указав вместо этого опцию -proc < тип_процессора >), то линкер ищет LDF в директории, специфичной для указанного процессора; например, в папке $ADI_DSP/Blackfin/ldf (здесь $ADI_DSP это каталог установки VisualDSP++).

Для дополнительной информации о путях поиска файлов, см. "Встроенные макросы LDF".

Когда в качестве параметров командой строки предоставляются имена входных и выходных файлов:

• Используйте пробел для разделения имен файлов в списке входных файлов.
• Заключите в прямые кавычки имена файлов, которые содержат пробелы; например, "long file name".
• Используйте подходящее расширение для каждого файла. Перед запуском обработки линкер открывает существующие файлы и проверяет их тип. Когда линкер создает файл, он использует расширение файла, чтобы определить тип создаваемого файла.

Типы объектных файлов. Линкер обрабатывает объект (файл) по типу файла. Тип файла определяется по следующим правилам:

• Существующие файлы открываются и анализируется, чтобы определить их тип. Имена файлов могут быть любыми.
• Файлы, созданные во время линковки, получает имена с подходящим расширением, и форматируются соответствующим образом. Выходной файл с информацией отображения (map-файл) генерируется только в формате XML, и получает расширение .xml. Исполняемый файл записывается в формате ELF и получает расширение .dxe.

Линкер обрабатывает объектные (.doj) файлы и библиотечные (.dlb) файлы, которые появляются в командной строке как объектные файлы для линковки. Линкер рассматривает исполняемые файлы (.dxe) и файлы общей памяти (shared memory, с расширением .sm) в командной строке как результат процесса линковки.

Для дополнительной информации об объектах см. описание макроса $COMMAND_LINE_OBJECTS. Для информации по исполняемым файлам см. описание макроса $COMMAND_LINE_LINK_AGAINST. Оба описаны в разделе документации "Встроенные макросы LDF".

Если объекты линковки не указаны в командной строке или в файле .ldf, то линкер генерирует информационные сообщения или сообщения об ошибке.

[Опции командной строки линкера]

Эта секция описывает ключи командной строки линкера. Таблица 2-7 описывает каждый ключ с учетом чувствительности к регистру, эквивалентные ключи, переназначаемые ключи или противоречащие друг другу, и ограничения на имена и пробельные разделители для параметров.

Линкер предоставляет ключи (опции) для выбора операций и режимов. Стандартный синтаксис ключа: -ключ [аргумент_ключа].

Правила:

• Ключи могут использоваться в командной строке в любом порядке. Элементы в квадратных скобках [ ] являются необязательными. Элементы с наклонным текстом определяются пользователем, и описаны для каждого ключа.
• Имена путей могут быть отностельными или абсолютными.
• Имена файлов, содержащие пробелы или двоеточия (?..) должны быть заключены в двойные кавычки, хотя такие относительные пути, как ../../test.dxe, не требуют для себя кавычек.

Разные ключи требуют (или запрещают) пробелы между ключом и его параметром.

Пример:

linker -proc ADSP-BF535 p0.doj p1.doj p2.doj -T target.ldf -t -o program.dxe

Обратите внимание на разницу между ключами -T и -t. Этот пример вызова линкера имеет следующие ключи (опции) командной строки:

-proc ADSP-BF535
Указывает процессор.

p0.doj, p1.doj и p2.doj
Линкует между собой 3 объектных файла в исполняемый файл.

-T target.ldf
Использует вторичный файл LDF, чтобы указать размещение объектов в исполняемой программе.

-t
Включает информацию трассировки, что в виде эха выводит имя объекта в stdout по мере его обработки.

-o program.dxe
Указывает выходное имя линкуемого выполняемого файла.

Если ввести команду linker без опций командной строки, то будет показана общая информация по опциям командной строки. Результат запуска без опций будет тот же, как и запуск команды linker -help.

Общее описание опций линкера. Таблица 2-7 кратко описывает каждый ключ линкера. Каждый отдельный ключ описан подробно после этой таблицы. См. "Сборки проекта" для получения информации по диалогу настройки опций проекта (Project Options) среды VisualDSP++.

Таблица 2-7. Общее описание ключей командной строки линкера.

Ключ (опция)       Описание
@file Содержимое указанного файла file используется как расширение командной строки.
-DprocessorID Указывает идентификатор целевого процессора. Это устаревшая опция, вместо неё рекомендуется использовать -proc processorID.
-L path Добавляет имя пути path к каталогам поиска библиотек для объектов.
-M Генерирует информацию о зависимостях друг от друга разных частей кода (dependencies).
-MM Собирает и генерирует информацию о зависимостях (dependencies).
-Map file Выводит в файл карту линковки (отображение символов и секций на абсолютные адреса памяти).
-MDmacro[=def] Определяет для препроцессора макрос с именем macro и назначает (опционально) ему значение def.
-MUDmacro Отменяет определение макроса для препроцессора.
-S Не вставляет отладочную информацию в выходной файл.
-T filename Идентифицирует по имени filename используемый файл LDF.
-Werror number Повышает указанное по номеру number предупреждающее сообщение до уровня ошибки.
-Wwarn number Понижает указанное по номеру сообщение об ошибке до уровня предупреждающего сообщения.
-Wnumber Селективно запрещает одно или большее количество предупреждений по указанным номерам. Например, -W1010 запрещает выдачу предупреждающего сообщения li1010.
-e Выкидывает из исполняемого файла не используемые символы.
-ek secName Указывает имя секции secName, для которой не работает выбрасывание не используемых символов.
-es secName Указывает список входных секций secName, для которых применяется алгоритм выбрасывания не используемых символов.
-ev Удаляет не используемые символы с выдачей подробных сообщений.
-entry Указывает адрес элемента, где аргументом может быть либо символ, либо адрес.
-flag-meminit Передает опцию (с разделителем - запятой) в утилиту Memory Initializer.
-flag-pp Передает опцию (с разделителем - запятой) в препроцессор.
-h
-help
Выводит список ключей (опций) командной строки (подсказка и выход).
-i path Подключает для препроцессора директорию path поиска файлов #include.
-ip Заполняет фрагментированную память отдельными объектами данных, которые туда помещаются.
-jcs2l Преобразует не достающие по диапазону "короткие" инструкции переходов и вызовов (jump, call) в "дальнюю" форму. Это дает возможность линкеру преобразовать не короткие по адресу ветвления в последовательности косвенного вызова (indirect call) и перехода (indirect jump).
-jcs2l+ Устаревшая опция, то же самое, что и -jcs2l.
-keep symName Предохраняет символ symName от уничтожения (если он не используется).
-meminit Делает пост-обработку для инициализации памяти в исполняемом файле (в противовес инициализации памяти ROM-загрузчиком или отладчиком).
-nomemcheck Выключает проверку памяти LDF.
-o filename Задает имя выходного генерируемого исполняемого файла.
-od filename Задает имя выходной директории.
-pp Останавливает работу после препроцессинга.
-proc processor Выбор целевого процессора для генерации кода.
-reserve-null Указывает линкеру не использовать (резервировать) 4 адресуемые единицы памяти (слова), расположенные по адресу 0.
-s Выбрасывает символьную информацию из выходного файла.
-save-temps Сохраняет временные выходные файлы.
-si-revision ver Задает версию ver для ревизии кристалла (silicon revision) указанного процессора.
-sp Пропускает препроцессинг.
-t Выводит имена объектов линковки.
-tx Выводит полные имена объектов линковки.
-v
-verbose
Выводит подробную информацию состояния.
-version Выводит версию линкера и завершает работу.
-warnonce Для каждого символа предупреждающее сообщение будет выдаваться только 1 раз.
-xref Указывает линкеру генерировать файл с информацией о перекрестных ссылках (cross-reference file).

Примечание: в столбце "Ключ (опция)" значение параметра (аргумента) опции указано наклонным шрифтом.

Следующие секции предоставляют подробное описание ключей (опций) командной строки линкера.

@filename
Ключ @ указывает линкеру рассматривать содержимое файла с именем filename в качестве входного для командной строки линкера. Ключ @ позволяет обойти ограничение на длину командной строки, накладываемое рабочим окружением Windows. Содержимое файла filename может не начинаться с имени программы "linker" (таким образом это не может быть полной строкой запуска линкера). Пробел (включая перевод на новую строку "newline") служит для разделения элементов командной строки (ключей/опций).

-Dprocessor
Ключ -Dprocessor (указание типа процессора) задает целевой процессор (архитектуру); например, -DADSP-BF533.

Ключ -proc processor (см. далее) является предпочтительной опцией для замены -Dprocessor.

В опции -D не разрешены пробелы до типа процессора processor. Параметр архитектуры чувствителен к регистру, и должен быть доступен в инсталляции VisualDSP++. Этот ключ (или ключ -proc processor) должен использоваться, если в командной строке не указан файл .ldf (см. описание опции -T). Этот ключ (или ключ -proc processor) должен использоваться, если указанный файл .ldf не имеет в себе команду ARCHITECTURE(). Противоречие в архитектуре между этим ключом командной строки и файлом .ldf приведет к ошибке.

-L path
Ключ -L path (директория поиска) добавляет имя пути для поиска библиотек и объектов. Этот ключ чувствителен к регистру символов, и использование пробелов является важным. Параметр path разрешает поиск любого файла, включая сам файл .ldf.

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

Пути, указанные в этой опции, используются для поиска перед путями, указанными в команде SEARCH_DIR{} файла LDF.

-M
Ключ -M (только генерация правил make) указывает линкеру проверить зависимости (dependency) и вывести результат в stdout.

-MM
Ключ -MM (генерация правил make и сборка) указывает линкеру генерировать выходной файл, который подойдет утилите make, описывающий зависимости (dependencies) исходного файла. Линкер проверяет зависимость, выводит результат в stdout, и выполняет сборку. Различие в действии между -MM и -M только в том, что с опцией -MM продолжается линковка. Для дополнительной информации см. описание ключа -M.

-Map filename
Ключ -Map filename (генерация карты памяти отображения объектов, memory map) указывает линкеру вывести карту памяти всех размещенных символов программы. Имя map-файла соответствует аргументу filename. Линкер генерирует map-файл только в формате XML. Например, если аргумент имени файла test, то имя выходного файла будет test.map.xml.

Открытие файла .xml в веб-браузере предоставляет организованный вид на map-файл (подробнее про просмотр map-файла см. [4]). С помощью гиперссылок в этом открытом файле можно быстро найти соответствующую информацию. Поскольку формат файлов .xml может быть расширен между релизами VisualDSP++, то map-файл зависит от частной инсталляции VisualDSP++ (хотя компания Analog Devices на момент написания статьи больше не продвигает VisualDSP++, заменив её на среду разработки CrossCore Embedded Studio). Таким образом, map-файл в формате .xml может использоваться только на том компьютере, на котором он был сгенерирован. Чтобы просмотреть map-файл на другом компьютере, он должен быть преобразован в формат HTML с помощью утилитой командной строки xmlmap2html.exe. Эта утилита делает возможность просмотра карты памяти (map-файла) виртуально на любом компьютере в любом браузере.

XSLT это язык для трансформации документов XML. Система VisualDSP++ включает в себя следующие XSLT-файлы для трансформации и отображения в браузере map-файлов XML, сгенерированных линкером.

• System/linker_map_ss1.xsl
Не отображает символы, которые начинаются с точки. Этот файл используется по умолчанию.

• /System/linker_map_ss2.xsl
Приводит к отображению всех символов.

Обратите внимание, что компилятор и библиотеки могут использовать такие символы для локальных данных и кода.

-MDmacro[=def]
Ключ -MDmacro[=def] (определение макроса) декларирует и назначает значение def в качестве подстановки macro в качестве макроса препроцессора. Например, -MDTEST=BAR обработает код за директивой #ifdef TEST==BAR в файле LDF (и соответственно не будет обработан код за директивой #ifdef TEST==XXX).

Если =def не указан, этот макрос декларируется и устанавливается в "1", чтобы гарантировать, что будет обработан код после #ifdef TEST. Этот ключ может повторяться в командной строке несколько раз.

-MUDmacro
Ключ -MUDmacro (отмена определения макроса macro) удаляет макрос препроцессора, где macro задает удаляемый макрос. Например, -MUDTEST отменяет определение макроса TEST. Этот ключ обрабатывается после обработки всех ключей -MDmacro. Ключ -MUDmacro может быть повторен в командной строке несколько раз.

-S
Ключ -S (strip debug symbol) указывает линкеру опускать отладочную информацию исходного кода из выходного файла. Сравните этот ключ с ключом -s.

-T filename
Ключ -T filename (файл команд линкера) указывает линкеру использовать filename в качестве имени файла .ldf. Файл .ldf, указанный за ключом -T, должен содержать в себе команду ARCHITECTURE(), если командная строка не содержит ключ -proc < processor >. Линкер требует ключ -T, когда код линкуется для процессора, поддержка которого не предоставляется инсталляцией VisualDSP++. В таких случаях процессор идентификатор процессора (processor ID) не появляется в поле Target processor диалога опций проекта (Project Options).

Файл с именем filename должен существовать и быть найденным (например, путь до него указан с помощью опции -L). Перед filename должен быть пробел. На имя файла не вводятся ограничения, т. е. оно может быть любым, но допустимым для файловой системы, и содержимое файла правильное. Например, имя a.b работает, если это нормальный файл .ldf, где .ldf является допустимым расширением для такого файла, но оно не требуется.

-Werror [number]
Ключ -Werror указывает линкеру считать указанное предупреждающее (warning) сообщение ошибкой. Аргумент number задает номер обрабатываемого сообщения.

-Wwarn [number]
Ключ -Wwarn указывает линкеру обрабатывать сообщение об ошибке как предупреждающее сообщение (warning). Аргумент number задает номер обрабатываемого сообщения.

-Wnumber[,number]
Ключ -Wnumber или -wnumber (подавление предупреждения, warning suppression) селективно запрещает выдачу указанных предупреждающих сообщений по одному или большему количеству номеров. Например, -W1010 запрещает сообщение li1010. Опционально этот ключ принимает список сообщений следующим образом: [,number ...].

-e
Ключ -e указывает линкеру удалить не используемые символы из исполняемого файла.

-ek sectionName
Ключ -ek sectionName (нет удаления elimination) указывает секцию, к которой не применяется алгоритм устранения не используемых символов. Этот ключ и LDF-команда KEEP_SECTIONS() могут использоваться для указания имени секции, в которой не будет работать функция elimination.

-es sectionName
Ключ -es sectionName (удаление в перечисленной секции) указывает секцию, к которой применяется алгоритм elimination (удаления не используемых символов). Этот ключ ограничивает elimination только на перечисленные секции. Ключ -es может использоваться в командной строке несколько раз. При отсутствии ключа -es или команды ELIMINATE_SECTIONS() в файле LDF, линкер применяет elimination ко всем секциям. Оба этих ключа и LDF-команда ELIMINATE_SECTIONS() могут использоваться для указания секций, из которых будет удалены (eliminated) не используемый код и неиспользуемые данные.

Чтобы правильно работали библиотеки C/C++ run-time, должны быть сохранены следующие символы с помощью команды KEEP() файла LDF: ___ctor_NULL_marker и ___lib_end_of_heap_descriptions.

-entry
Ключ -entry показывает адрес элемента (entry address), где аргумент может быть либо символом, либо адресом.

-ev
Ключ -ev указывает линкеру удалять (eliminate) не используемые символы и сообщать о каждом удаленном символе.

-flags-meminit -opt1[,-opt2...]
Ключ -flags-meminit передает список опций, разделенных запятыми, в утилиту инициализатора памяти (Memory Initializer; для дополнительной информации см. Главу 7 "Memory Initializer" руководства [1]).

-flags-pp-opt1[,-opt2...]
Ключ -flags-pp передает каждую опцию из списка (с разделителем-запятой) в препроцессор.

Используйте -flags-pp с осторожностью. Например, если разрешен стандартный синтаксис комментария pp (pp legacy comment syntax), то символы комментария станут недоступными для синтаксиса не комментария.

-h[elp]
Ключ -h или -help указывает ассемблеру вывести в stdout список ключей (опций) командной строки с общим описанием синтаксиса.

-i|I directory
Ключ -idirectory или -Idirectory (подключить директорию, include directory) указывает линкеру добавить указанную директорию к путям поиска для подключаемых файлов.

Чтобы добавить несколько директорий, повторите ключ, или укажите список директорий с разделителем в виде точки с запятой (;). Последняя точка с запятой не обязательна.

-ip
Ключ -ip (индивидуальное размещение, individual placement) указывает линкеру заполнить фрагментированную память индивидуальными объектами данных, которые там поместятся. Когда указан ключ -ip в командной строке линкера (или с помощью диалога опций проекта VisualDSP++ IDDE), переназначается поведение по умолчанию линкера для размещения блоков данных в идущих друг за другом адресах. Ключ -ip позволяет индивидуальное размещение группирования данных в памяти процессора, чтобы позволить более эффективную упаковку данных.

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

-jcs2l
Ключ -jcs2l (jump/call от короткого short к длинному long) указывает линкеру преобразовать не достающие по диапазону адреса инструкции вызова функций (call) и инструкции перехода (jump) в последовательность кода, который использует косвенные (indirect) переходы или вызовы. Из-за того, что косвенная последовательность использует регистр P1, расширение будет применено только к инструкциям, использующим коды операций CALL.X или JUMP.X.

Ключ -jcs2l используется только для процессоров Blackfin.

Следующая таблица показывает, как линкер Blackfin обрабатывает преобразования jump/call.

Инструкция Без опции -jcs2l С опцией -jcs2l
JUMP.S Короткий переход
JUMP Короткий или длинный переход
JUMP.L Длинный переход
JUMP.X Короткий или длинный переход Короткий или длинный переход, или переход с косвенной адресацией (indirect).
CALL Обычный вызов
CALL.X Обычный вызов Обычный или косвенный (indirect) вызов.

Обратитесь к руководству по системе команд целевой архитектуры (для процессора Blackfin см. [5]) для получения дополнительной информации по инструкциям перехода и вызова.

-jcs2l+
Устаревший эквивалент ключа -jcs2l.

Ключ -jcs2l+ используется только для процессоров Blackfin.

-keep symbolName
Ключ -keep symbolName (сохранение неиспользуемых символов) указывает линкеру сохранить символ, который иначе был бы уничтожен (eliminated). Это указывает линкеру (когда разрешены -e или -ev) сохранить перечисленные символы в исполняемом файле, даже если они не используется в программе (если на них нет ссылок).

-meminit
Ключ -meminit (завершающая обработка исполняемого файла) указывает линкеру выполнить post-process файла .dxe с помощью утилиты Memory Initializer (для дополнительной информации см. Главу 7 "Memory Initializer" руководства [1]). Это действие приводит к тому, что секции, указанные в файле .ldf, будут инициализированы во время выполнения кода (run-time) с помощью библиотеки C run-time. По умолчанию, если это флаг не указан, все секции инициализируются в момент загрузки кода (load time; например, через отладчик VisualDSP++ IDDE или через boot loader процессора). Подробнее см. описание команды SECTIONS{} для получения информации по инициализации секции. Для информации о предопределенном макросе __MEMINIT см. описание __MEMINIT__.

-nomemcheck
Ключ -nomemcheck (memory checking off) позволяет Вам выключить проверку памяти.

-o filename
Ключ -o filename (выходной файл) устанавливает значение макроса $COMMAND_LINE_OUTPUT_FILE, который обычно используется как параметр LDF-команды OUTPUT(), которая задает имя выходного файла. Если в командной строке нет ключа -o, то макрос $COMMAND_LINE_OUTPUT_FILE получит значение "a.dxe".

-od directory
Ключ -od указывает линкеру присвоить значение LDF-макросу $COMMAND_LINE_OUTPUT_DIRECTORY. Этот ключ позволяет Вам сделать изменение командной строки, которое распространится на многие места без изменения LDF. Подробнее см. "Встроенные макросы LDF" [6].

-pp
Ключ -pp (завершить после обработки препроцессором, end after preprocessing) указывает линкеру остановиться после прохода препроцессора, завершить после этого работу без ликовки. Результат (обработанный препроцессором LDF) напечатается в файл с тем же именем, что и .ldf, но с расширением .is. Этот файл находится в той же директории, что и файл .ldf.

-proc processor
Ключ -proc (целевой процессор, target processor) указывает линкеру генерировать код, подходящий для указанного типа процессора. Пример:

linker -proc ADSP-BF533 p0.doj p1.doj p2.doj -o program.dxe

См. также описание опции -si-revision version для дополнительной информации о том, как указать ревизию кремния (silicon revision) требуемого процессора.

-reserve-null
Ключ -reserve-null указывает линкеру зарезервировать в памяти 4 адресуемых ячейки (words) по адресу 0x0. Это полезно для программ C/C++, чтобы избежать размещения кода или данных по адресу нулевого указателя (NULL pointer).

-s
Ключ -s (strip all symbols) указывает линкеру опустить из выходного файла все символьную информацию.

Некоторая функциональность отладчика (включая "run to main"), все функции stdio, и возможность остановки по окончании выполнения программы полагаются на способность отладчика найти определенные символы в исполняемом файле. Этот ключ удалит такие символы.

-save-temps
Ключ -save-temps указывает линкеру сохранить временные (промежуточные) выходные файлы.

-si-revision version
Ключ -si-revision version (версия кристалла процессора) указывает линкеру собрать программу с учетом определенной ревизии аппаратуры кристалла. Когда учет целевой ревизии разрешен, это позволяет применить способы обхода ошибок (errata workarounds), обнаруженных в определенной версии кристалла. Параметр версии представляет ревизию силикона процессора, который указан ключом -proc. Пример:

linker -proc ADSP-BF533 -si-revision 0.1

Если используется версия силикона "none", то в коде не разрешено применение обхода ошибок. Если указать версию силикона "any", то это разрешает применение всех errata workarounds для целевого процессора.

Если ключ -si-revision не используется, то линкер делает сборку для самой последней silicon revision силикона целевого процессора, при этом разрешены все errata workarounds для последней silicon revision.

Если silicon revision установлена в "any", то макрос __SILICON_REVISION__ устанавливается в значение 0xffff. Если ключ -si-revision установлен в "none", то линкер не будет устанавливать макрос __SILICON_REVISION__.

Линкер передает ключ -si-revision < silicon version >, когда запускается другой инструментарий VisualDSP++, например когда линкер привлекает работу ассемблера. В примере ниже линкер Blackfin:

linker -proc ADSP-BF533 -si-revision 0.1

... запустит ассемблер командой:

easmblkfn -proc ADSP-BF533 -si-revision 0.1

-sp
Ключ -sp (пропуск обработки препроцессором) указывает линкеру связывать код без предварительной обработки файла .ldf.

-t
Ключ -t (trace, трассировка) указывает линкеру вывести имена объектов линковки в стандартный вывод по мере их обработки.

-tx
Ключ -tx (full trace, полная трассировка) указывает линкеру выводить полные имена объектов линковки (полный путь файла с директорией) в стандартный вывод по мере их обработки.

-v[erbose]
Ключ -v или -verbose (verbose, подробно) указывает линкеру отобразить версию и информацию командной строки для каждой фазы линковки.

-version
Ключ -version (показать версию) указывает линкеру вывести информацию о его версии.

-warnonce
Ключ -warnonce (single symbol warning, предупреждение одного символа) указывает линкеру предупредить только один раз о каждом не определенном символе, вместо того, чтобы сообщать о каждой ссылке на этот символ.

-xref
Ключ -xref указывает линкеру сгенерировать файл перекрестных ссылок в формате XML (cross-reference file xref.xml) в выходной директории линкера. Файл XML может быть открыт для просмотра браузером (или программами для просмотра XML, см. [4]).

Этот ключ линкера отличается от ключа -xref драйвера компилятора.

[Ссылки]

1. VisualDSP++ 5.0 Linker and Utilities Manual site:analog.com.
2PGO Linker: инструмент размещения кода для процессоров Blackfin.
3. Оптимизация системы на процессоре Blackfin.
4Q070. VisualDSP: как посмотреть MAP-файл линкера?
5. Blackfin: система команд (ассемблер) - часть 1.
6. Linker Description File.