Предыстория
В 2011 году было написан некоторый код для микроконтроллера ARM Cortex-M3 производства NXP из серии LPC17xx. В ходе работы потребовался скрипт для компоновщика GNU ld. В качестве образца был взят первый попавшийся под руку (возможно, из тулчейна CodeSourcery). В процессе изменения найденного скрипта он был дополнен и к указанным в нём параметрам были, по возможности, добавлены комментарии. Секции и параметры, оказавшиеся излишними для ARM Cortex-M3, тем не менее не удалялись -- в целях пущей наглядности скрипта. Откомментированный скрипт sections.ld приведён ниже.
NXP LPC17xx позволяет запускать код из оперативной памяти. Для использования этой возможности в sections.ld секции для размещения кода и данных указаны псевдонимами. Реальные имена секций и соответствующая карта памяти определены в сопутствующих скриптах компоновщика text2flash_memory_map.ld и text2ram_memory_map.ld.
Для использования скрипта следует передать gcc следующие параметры:
-
для размещения кода во внутренней флэш-памяти:
-Wl,-Lпуть_к_каталогу_со_скриптами -Wl,-Ttext2flash_memory_map.ld -Wl,-Tsections.ld
-
для размещения кода в оперативной памяти:
-Wl,-Lпуть_к_каталогу_со_скриптами -Wl,-Ttext2ram_memory_map.ld -Wl,-Tsections.ld
Лицензия
Скрипт sections.ld, скорее всего, лицензирован под GPLv2 .
Скрипты text2flash_memory_map.ld и text2ram_memory_map.ld, а также русскоязычные комментарии в sections.ld лицензированы под CC0 .
Скрипты
text2flash_memory_map.ld
MEMORY
{
RomFlash (rx) : ORIGIN = 0x00000000, LENGTH = 256K
RamLocal (wx) : ORIGIN = 0x10000000, LENGTH = 32K
RamAHB_0 (wx) : ORIGIN = 0x2007C000, LENGTH = 16K
RamAHB_1 (wx) : ORIGIN = 0x20080000, LENGTH = 16K
}
REGION_ALIAS ("REGION_TEXT", RomFlash);
REGION_ALIAS ("REGION_DATALOAD", RomFlash);
text2ram_memory_map.ld
MEMORY
{
RomFlash (rx) : ORIGIN = 0x00000000, LENGTH = 256K
RamLocal (wx) : ORIGIN = 0x10000000, LENGTH = 32K
RamAHB_0 (wx) : ORIGIN = 0x2007C000, LENGTH = 16K
RamAHB_1 (wx) : ORIGIN = 0x20080000, LENGTH = 16K
}
REGION_ALIAS ("REGION_TEXT", RamLocal);
REGION_ALIAS ("REGION_DATALOAD", RamLocal);
sections.ld
/* Для кода (потока инструкций) указано выравнивание по слову
* (см. ARMv7-M ARM A3.1, A3.2.1, A4.1, A5.1; описание работы Prefetching Unit).
*
* Для данных указано выравнивание по слову (см. ARM A3.2.1, A3.5.7).
*
* Адрес начала стека должен быть кратен 8-ми (см. ARM B1.5.7, C.1.1).
*
* (В архитектуре ARM-v7M размер слова (word) равен 4-ём байтам [32-м битам]).
*
* Ссылки (здесь и далее):
* [ARM] ARMv7-M Architecture Reference Manual
* (по содержанию версии issue "Derrata 2010_Q3", November 2010)
* [EHABI] Exception Handling ABI for the ARM Architecture
* (по содержанию версии 28th October 2009)
*
* Описание GCC vague linkage (использующего, при необходимости, секции с
* именами gnu.linkonce.*) см. в GCC Manual (гл. Vague linkage).
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH ("arm")
/* CS3 - CodeSourcery Common Startup Code Sequence */
EXTERN (__cs3_reset_cortex_m)
ENTRY (__cs3_reset_cortex_m)
EXTERN (__cs3_interrupt_vector_cortex_m)
PROVIDE (__cs3_stack = ORIGIN(RamLocal) + LENGTH(RamLocal));
EXTERN (__cs3_stack_size)
PROVIDE (__cs3_heap_start = _end);
EXTERN ( __cs3_heap_end)
PROVIDE (__cs3_heap_end = __cs3_stack - __cs3_stack_size);
SECTIONS
{
.text ORIGIN(REGION_TEXT):
{
__cs3_interrupt_vector = __cs3_interrupt_vector_cortex_m;
KEEP(*(.cs3.interrupt_vector))
ASSERT (. != __cs3_interrupt_vector, "No interrupt vector");
__cs3_reset = __cs3_reset_cortex_m;
KEEP(*(.cs3.reset))
ASSERT (. != __cs3_reset, "No reset code");
/* Микроконтроллеры NXP LPC17xx предоставляют механизм Code Read
* Protection (CRP), включающий различные уровни защиты программного кода
* путём ограничения или полного отключения доступа к FLASH-памяти чипа
* и/или отключения ISP (перепрограммирования через встроенный
* bootloader).
*
* Механизм CRP конфигурируется путём записи одной из "магических"
* констант (размером в слово) во FLASH-память, по адресу 0x000002FC.
*
* Константа, помещённая в секцию '.lpc17xx.crp', сконфигурирует CRP. По
* умолчанию, по адресу 0x000002FC будет записан 0 (что не включит никакой
* из уровней защиты).
*/
. = 0x2FC;
KEEP (*(.lpc17xx.crp))
FILL (0x00)
/* 0x2FC + 4 = 0x300 (4 байта -- размер константы, конфигурирующей CRP) */
. = 0x300;
/* .text - основная секция программного кода.
* .text.* - отдельные секции для функций, создаваемые GCC при включении
* опции -ffunction-sections
* .gnu.linkonce.t.* - секции программного кода, используемые GCC для
* vague linkage, если либо формат целевого объектного
* файла отличен от ELF, либо GCC был собран с
* использованием binutils, не поддерживающих секции
* ELF типа "COMDAT group".
*/
*(.text .text.* .gnu.linkonce.t.*)
/* Procedure Linkage Table (PLT) -- используется при динамической
* компоновке (dynamic linkage) для обращения к функциям разделяемого
* объекта (shared object).
*/
*(.plt)
/* Предупреждения при компоновке (секции, специфические для GNU ld).
*
* При включении в компоновку объектного файла с секцией '.gnu.warning',
* GNU ld безусловно выведет содержимое этой секции в виде текста
* предупреждения (warning).
*
* При наличии секции '.gnu.warning.SYMBOL' GNU ld выведет содержимое этой
* секции в виде предупреждения (warning), если и когда будет обнаружена
* неопределённая ссылка (undefined reference) на 'SYMBOL'. Предупреждение
* будет выведено при встрече неопределённого символа с указанным именем в
* объектном файле. В отличии от обычного предупреждения о неопределённом
* символе, это не будет показано при встрече записи таблицы
* переразмещений (relocation entry).
*
* Содержимое секций не включается в выходной файл.
*
* См. http://www.airs.com/blog/archives/54
* (Ian Lance Tailor - Linkers part 17, Warning symbols)
*/
*(.gnu.warning .gnu.warning.*)
/* Секции, создаваемые GNU ld при компоновке для семейства ARM (независимо
* от конкретной целевой архитектуры).
* См. руководство по GNU linker, глава 4.4 ("ld and ARM family")
*
* .glue_7 - секция для программного "клея" между ARM- и Thumb-кодом,
* позволяющего вызывать функций в Thumb-коде из ARM-кода
* .glue_7t - секция для программного "клея" между ARM- и Thumb-кодом,
* позволяющего вызывать функций в ARM-коде из Thumb-кода
* .vfp11_veneer - секция для программного кода, осуществляющего обход
* ошибки, присутствующей в некоторых сопроцессорах VFP11
* (код генерируется компоновщиком; генерация кода
* конфигурируется отдельной опцией компоновщика)
*/
*(.glue_7) *(.glue_7t) *(.vfp11_veneer)
/* .ARM.extab - таблица обработчиков исключительных ситуаций
* (exception-handling table)
*
* Присутствие секции .ARM.extab диктуется стандартом EHABI.
*
* Секция таблицы обработчиков именуется '.ARM.extab' с опциональным
* суффиксом, состоящим из любых символов (EHABI 4.4.1).
*
* .gnu.linkonce.armextab.* - секции, используемые GCC для vague linkage,
* если либо формат целевого объектного файла
* отличен от ELF, либо GCC был собран с
* использованием binutils, не поддерживающих
* секции ELF типа "COMDAT group".
*/
*(.ARM.extab* .gnu.linkonce.armextab.*)
/* Область языко-зависимых данных (language-specific data area) для
* каркасного кода обработки исключений, генерируемого компилятором GCC
* (сами данные также генерируются компилятором GCC).
*
* Секция '.gcc_except_table' тесно связана с секцией
* '.eh_frame'/'.ARM.extab'.
*/
*(.gcc_except_table)
} >REGION_TEXT
/* .init - секция кода, выполняющегося в ходе инициализации программы (перед
* вызовом входной точки программы, т.е. перед вызовом функции
* main).
*
* NB! Вместо помещения инструкций кода в секцию '.init' пользователю
* рекомендуется использовать современный способ инициализации и добавлять
* указатели на функции инициализации в секцию '.init_array' (при помощи
* соответствующих средств компилятора).
*
* Специальная секция с именем '.init' и вышеназванным назначением описана в
* System V gABI. Вызов пользовательского кода, помещённого в секцию
* '.init', возлагается на библиотеку времени выполнения (runtime library)
* -- например, на C runtime. Если в библиотеке не предусмотрен такой вызов,
* то пользовательский код в секции '.init' не выполнится.
*
* В настоящее время секция '.init' используется, в основном, исключительно
* библиотекой C времени выполнения (newlib, glibc) для вызова служебных
* функций инициализации. Это достигается компоновкой со следующими
* объектными файлами из состава C runtime:
* - crti.o -- содержит пролог функции _init, помещаемый в начало секции
* '.init'
* - crtn.o -- содержит эпилог функции _init, помещаемый в конец секции
* '.init'
* - crtbegin.o, crtend.o -- содержат служебные функции, вызов которых
* размещается в секции '.init'
*
* Т.о. служебные функции инициализации (наряду с пользовательским кодом,
* размещённым в секции '.init') выполняются при вызове функции _init.
*
* См. руководство GCC Internals, гл. How initialization functions are
* handled
*/
.init : ALIGN(4)
{
KEEP(*(.init))
} >REGION_TEXT
/* .fini - секция кода, выполняющегося при завершении программы (после
* возврата из входной точки программы, т.е. после возврата из
* функции main).
*
* NB! Вместо помещения инструкций кода в секцию '.fini' пользователю
* рекомендуется использовать современный способ терминации и добавлять
* указатели на функции терминации в секцию '.fini_array' (при помощи
* соответствующих средств компилятора).
*
* Специальная секция с именем '.fini' и вышеназванным назначением описана в
* System V gABI. Вызов пользовательского кода, помещённого в секцию
* '.fini', возлагается на библиотеку времени выполнения (runtime library)
* -- например, на C runtime. Если в библиотеке не предусмотрен такой вызов,
* то пользовательский код в секции '.fini' не выполнится.
*
* В настоящее время секция '.fini' используется, в основном, исключительно
* библиотекой C времени выполнения (newlib, glibc) для вызова служебных
* функций терминации. Это достигается компоновкой со следующими объектными
* файлами из состава C runtime:
* - crti.o -- содержит пролог функции _fini, помещаемый в начало секции
* '.fini'
* - crtn.o -- содержит эпилог функции _fini, помещаемый в конец секции
* '.fini'
* - crtbegin.o, crtend.o -- содержат служебные функции, вызов которых
* размещается в секции '.fini'
*
* Т.о. служебные функции терминации (наряду с пользовательским кодом,
* размещённым в секции '.fini') выполняются при вызове функции _fini.
*
* См. руководство GCC Internals, гл. How initialization functions are
* handled
*/
.fini : ALIGN(4)
{
KEEP(*(.fini))
} >REGION_TEXT
/* .eh_frame_hdr - заголовок секции '.eh_frame', содержащий, в том числе,
* адрес начала секции '.eh_frame' и (опционально) индекс
* записей в таблице данных, расположенной в '.eh_frame'.
*
* NB! Современные версии GCC (>= 4.1) для целевой платформы ARM EABI вместо
* '.eh_frame_hdr' и '.eh_frame' используют секции '.ARM.exidx' и
* '.ARM.extab', определённые стандартом ARM EHABI. Но GCC некоторых ранних
* подверсий 4.4.x/4.5.x создаёт [ненужную] секцию '.eh_frame' при
* определённых обстоятельствах (GCC bug #40521).
*
* Информация в секции '.eh_frame_hdr' (равно как и сама секция)
* генерируется компоновщиком GNU ld при включении опции '--eh-frame-hdr'.
* Сгенерированная секция размещается в отдельном сегменте ELF-файла с типом
* PT_GNU_EH_FRAME.
*
* Для использования '.eh_frame_hdr' исходный код компилятора из состава GCC
* должен быть соответствующим образом сконфигурирован перед постройкой GCC.
* Для актуальных (на момент написания комментария) версий GCC (<= 4.6.0)
* конфигурация производится автоматически с условием, что:
* 1. используемый компоновщик поддерживает создание секции '.eh_frame_hdr',
* 2. стандартная библиотека C для целевой платформы предоставляет функцию
* dl_iterate_phdr,
* 3. конфигуратор GCC (gcc/configure.ac) сумел определить первое и второе
* обстоятельства.
*
* Будучи сконфигурирован с выполнением этих условий, gcc автоматически
* компонует с включением опции '--eh-frame-hdr' и использует информацию
* из '.eh_frame_hdr' во время выполнения программы.
*
* В ином случае, служебная процедура поиска в таблице '.eh_frame',
* генерируемая компилятором GCC, будет выполнять поиск необходимой
* информации без заранее созданного индекса, путём автоматической
* регистрации записей из '.eh_frame' во время запуска программы и
* последующего обхода зарегистрированных записей.
*
* См. http://www.airs.com/blog/archives/166
* (Ian Lance Taylor - GCC exception frames)
*/
.eh_frame_hdr : ALIGN(4)
{
/* Информация в секции '.eh_frame_hdr' (равно как и сама секция)
* генерируется компоновщиком GNU ld при включении опции '--eh-frame-hdr'.
*/
KEEP(*(.eh_frame_hdr))
} >REGION_TEXT
/* .eh_frame - таблицы с данными, необходимыми для раскручивания стека при
* обработке исключительных ситуаций (tables that describe how
* to unwind the stack on exception handling).
*
* NB! Современные версии GCC (>= 4.1) для целевой платформы ARM EABI вместо
* '.eh_frame' используют секцию '.ARM.extab', определённую стандартом ARM
* EHABI. Но GCC некоторых ранних подверсий 4.4.x/4.5.x создаёт [ненужную]
* секцию '.eh_frame' при определённых обстоятельствах (GCC bug #40521).
*/
.eh_frame : ALIGN(4)
{
/* Таблицы с данными, необходимыми для раскручивания стека при обработке
* исключительных ситуаций, генерируются компилятором GCC, размещающим их
* в секции с предопределённым именем '.eh_frame'.
*/
KEEP(*(.eh_frame))
} >REGION_TEXT
/* .ARM.exidx - индекс записей в таблице обработчиков исключительных
* ситуаций (index table for exception-handling table entries).
*
* Присутствие секции .ARM.exidx диктуется стандартом EHABI.
*
* Согласно ARM EHABI 4.4.1 у входных секций .ARM.exidx установлен флаг
* атрибута SHF_LINK_ORDER. Если включить входные секции .ARM.exidx,
* например, в выходную секцию .text, то компоновщик (GNU ld) аварийно
* завершится с ошибкой: ".text has both ordered [`.ARM.exidx.<...>' in
* <...>] and unordered [`.text' in <...>] sections". Поэтому входные секции
* .ARM.exidx выделены в отдельную выходную секцию.
*/
.ARM.exidx : ALIGN(4)
{
/* Символ __exidx_start используется служебной библиотекой libgcc */
PROVIDE_HIDDEN(__exidx_start = .);
/* Секция индекса записей именуется '.ARM.exidx' с опциональным суффиксом,
* состоящим из любых символов (EHABI 4.4.1).
*
* .gnu.linkonce.armexidx.* - секции, используемые GCC для vague linkage,
* если либо формат целевого объектного файла
* отличен от ELF, либо GCC был собран с
* использованием binutils, не поддерживающих
* секции ELF типа "COMDAT group".
*/
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
/* Символ __exidx_end используется служебной библиотекой libgcc. */
PROVIDE_HIDDEN(__exidx_end = .);
} >REGION_TEXT
.rodata : ALIGN(4)
{
/* .rodata - секция константных данных (данных только для чтения, не
* изменяющихся в ходе работы программы)
* .rodata.* - отдельные секции для константных данных, создаваемые GCC
* при включении опции -fdata-sections
* .gnu.linkonce.r.* - секции константных данных, используемые GCC для
* vague linkage, если либо формат целевого объектного
* файла отличен от ELF, либо GCC был собран с
* использованием binutils, не поддерживающих секции
* ELF типа "COMDAT group".
*/
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .preinit_array - секция для указателей на функции пре-инициализации,
* вызываемых перед любыми другими функциями
* инициализации (перед выполнением кода из секции
* '.init' и вызовами функций из секции '.init_array').
*
* Специальная секция с именем '.preinit_array' и вышеназванным
* назначением описана в System V gABI. Вызов функций, указатели на
* которые содержатся в секции '.preinit_array', возлагается на библиотеку
* времени выполнения (runtime library) -- например, на C runtime. Если в
* библиотеке не предусмотрен такой вызов, то функции из секции
* '.preinit_array' не будут вызваны.
*
* Секция '.preinit_array' предназначена для пре-инициализации
* исполняемого файла (executable), выполняемой перед инициализацией
* динамически скомпонованных с ним разделяемых объектов (shared objects).
*
* Символы __preinit_array_start и __preinit_array_end используются
* библиотекой C времени выполнения (newlib, glibc).
*/
. = ALIGN(4);
PROVIDE_HIDDEN(__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN(__preinit_array_end = .);
/* .init_array - секции с указателями на функции инициализации,
* выполняющиеся перед вызовом входной точки программы, т.е.
* перед вызовом функции main.
*
* Специальная секция с именем '.init_array' и вышеназванным назначением
* описана в System V gABI. Вызов функций, указатели на которые содержатся в
* секции '.init_array', возлагается на библиотеку времени выполнения
* (runtime library) -- например, на C runtime. Если в библиотеке не
* предусмотрен такой вызов, то функции из секции '.init_array' не будут
* вызваны.
*
* GCC использует секцию '.init_array' для обеспечения вызова статических
* конструкторов: функций, объявленных с __attribute__((constructor)).
*
* Для статических конструкторов с объявленным приоритетом PRIORITY,
* используются секции с именем '.init_array.PRIORITY'
*
* Также GCC использует секцию '.init_array' для вызова конструкторов
* статических объектов C++.
*
* Символы __init_array_start и __init_array_end используются библиотекой
* C времени выполнения (newlib, glibc).
*/
. = ALIGN(4);
PROVIDE_HIDDEN(__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
PROVIDE_HIDDEN(__init_array_end = .);
/* .fini_array - секции с указателями на функции терминации,
* выполняющиеся по завершению программы (после возврата из
* входной точки программы, т.е. из функции main).
*
* Специальная секция с именем '.fini_array' и вышеназванным назначением
* описана в System V gABI. Вызов функций, указатели на которые содержатся в
* секции '.fini_array', возлагается на библиотеку времени выполнения
* (runtime library) -- например, на C runtime. Если в библиотеке не
* предусмотрен такой вызов, то функции из секции '.fini_array' не будут
* вызваны.
*
* GCC использует секцию '.fini_array' для обеспечения вызова статических
* деструкторов: функций, объявленных с __attribute__((destructor)).
*
* Для статических деструкторов с объявленным приоритетом PRIORITY,
* используются секции с именем '.fini_array.PRIORITY'
*
* Символы __fini_array_start и __fini_array_end используются библиотекой
* C времени выполнения (newlib, glibc).
*/
. = ALIGN(4);
PROVIDE_HIDDEN(__fini_array_start = .);
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
PROVIDE_HIDDEN(__fini_array_end = .);
/* .ctors - секции с указателями на функции инициализации, выполняющиеся
* перед вызовом входной точки программы, т.е. перед вызовом
* функции main.
*
* NB! Секции '.ctors' выполняют ту же функцию, что и секции
* '.init_array', но являются расширением GCC, созданным до введения в
* стандарт System V gABI секции '.init_array'. Начиная с версии 4.7 GCC
* вместо секций '.ctors' использует (по возможности) секции
* '.init_array'.
*
* См. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770
*/
. = ALIGN(4);
PROVIDE_HIDDEN(__ctors_start__ = .);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
PROVIDE_HIDDEN(__ctors_end__ = .);
/* .dtors - секции с указателями на функции терминации, выполняющиеся по
* завершению программы (после возврата из входной точки
* программы, т.е. из функции main).
*
* NB! Секции '.dtors' выполняют ту же функцию, что и секции
* '.fini_array', но являются расширением GCC, созданным до введения в
* стандарт System V gABI секции '.fini_array'. Начиная с версии 4.7 GCC
* вместо секций '.dtors' использует (по возможности) секции
* '.fini_array'.
*
* См. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46770
*/
. = ALIGN(4);
PROVIDE_HIDDEN(__dtors_start__ = .);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
PROVIDE_HIDDEN(__dtors_end__ = .);
. = ALIGN(4);
_etext = .;
__etext = .;
} >REGION_TEXT
.data : ALIGN(4)
{
__sdata = .;
KEEP(*(.jcr))
*(.got.plt) *(.got)
*(.shdata)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN (4);
__edata = .;
} >RamLocal AT>REGION_DATALOAD
.bss : ALIGN(4)
{
__sbss = .;
__bss_start__ = __sbss;
*(.shbss)
*(.bss .bss.* gnu.linkonce.b.*)
/* Common symbols are used for uninitialized global variables in C */
*(COMMON)
. = ALIGN (4);
__ebss = .;
__bss_end__ = __ebss;
} >RamLocal
_end = .;
__end = .;
.heap (NOLOAD) :
{
*(.heap)
} >RamLocal
.stack (__cs3_stack - __cs3_stack_size) (NOLOAD):
{
*(.stack)
} >RamLocal
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF 4 */
.debug_types 0 : { KEEP(*(.debug_types*)) *(.gnu.linkonce.wt.*) }
/* DWARF 5 */
.debug_macro 0 : { *(.debug_macro) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}