jcxz 304 April 15 Posted April 15 · Report post Вопрос знатокам GCC и в частности - его компоновщика ld: Необходимо расположить некую секцию гарантированно самой последней в том регионе памяти, куда она компонуется. Чтобы после неё в этом регионе не было других секций. Сделал скрипт: ENTRY(AppStart) MEMORY { RAM_regionA (rx) : ORIGIN = 0x20000000, LENGTH = 0x020000 /* DTCM (code) */ RAM_regionB (rwx) : ORIGIN = 0x20020000, LENGTH = 0x020000 /* SRAM1 (data) */ RAM_regionC (rx) : ORIGIN = 0x20040000, LENGTH = 0x03C000 /* SRAM1 (data) */ RAM_regionD (rwx) : ORIGIN = 0x2007C000, LENGTH = 0x004000 /* SRAM2 */ } SECTIONS { .text : { . = ALIGN(4); __checksum_begin = .; KEEP(*(.intvkt)) __checksum = .; KEEP(*(.checksum)) KEEP(*(.codehead)) KEEP(*(.intvktTail)) KEEP(*(.codeSignature)) *(.text*) *(.rodata*) *(.glue_7) *(.glue_7t) . = ALIGN(4); _sfb_idata = .; . = ALIGN(4); KEEP(*(.codeKeys)) } > RAM_regionA ... .codetail : { KEEP(*(.codetail)) __checksum_end = .; } > RAM_regionA } где на месте многоточия определено ещё множество других выходных секций. Требуется чтобы .codetail была гарантированно последней в регионе RAM_regionA. Сейчас я вижу, что она идёт последней среди секций описанных в скрипте: .codetail 0x200072e8 0x10 *(.codetail) .codetail 0x200072e8 0x10 B:/UPDATER.GCC/OUT.OUT/misca.obj 0x200072e8 codetail 0x200072f8 __checksum_end = . но... затем, в этот же регион ld вставляет ряд стабов: LOAD linker stubs .raw 0x200072f8 0x0 .raw 0x200072f8 0x0 B:/UPDATER.GCC/OUT.OUT/misca.obj .ARM.extab 0x200072f8 0x0 .ARM.extab 0x200072f8 0x0 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libg.a(libc_a-memcpy.o) .ARM.extab 0x200072f8 0x0 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libg.a(libc_a-strlen.o) .ARM.exidx 0x200072f8 0x8 .ARM.exidx 0x200072f8 0x8 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libg.a(libc_a-memcpy.o) .ARM.exidx 0x20007300 0x0 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libg.a(libc_a-strlen.o) 0x8 (size before relaxing) .ARM.extab.text.__udivmoddi4 0x20007300 0x0 .ARM.extab.text.__udivmoddi4 0x20007300 0x0 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libgcc.a(_udivmoddi4.o) .ARM.exidx.text.__udivmoddi4 0x20007300 0x0 .ARM.exidx.text.__udivmoddi4 0x20007300 0x0 C:/PRG/GCC/ARM/lib/gcc/arm-none-eabi/14.2.1/thumb/v7e-m+dp/hard/libgcc.a(_udivmoddi4.o) 0x8 (size before relaxing) .rel.dyn 0x20007300 0x0 .rel.iplt 0x20007300 0x0 B:/UPDATER.GCC/OUT.OUT/aes256.obj и .codetail становится уже не самой последней. Как сделать, чтобы все сгенерённые компоновщиком секции, идущие в данный регион, также вставлялись выше .codetail? В скрипте имеются также и другие описанные регионы памяти, в которые идёт компоновка других секций. PS: В IAR это решается элементарно: достаточно указать "last section .codetail". Неужели в GCC ld подобной возможности нет? Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 15 Posted April 15 · Report post On 4/15/2025 at 2:39 PM, jcxz said: Необходимо расположить некую секцию гарантированно самой последней в том регионе памяти, куда она компонуется. Чтобы после неё в этом регионе не было других секций. Секции размещаются в памяти в той последовательности, в которой они описаны в скрипте компоновщика. On 4/15/2025 at 2:39 PM, jcxz said: но... затем, в этот же регион ld вставляет ряд стабов: Возможно у вас стабы не описаны в вашем скрипте и поэтому линковщик сам их пихает по своему разумению. Опишите их у себя. Spoiler /* Entry Point */ ENTRY(Reset_Handler) /* Highest address of the user mode stack */ _estack = 0x20020000; /* end of RAM */ /* Generate a link error if heap and stack don't fit into RAM */ _Min_Heap_Size = 0x800; /* required amount of heap */ _Min_Stack_Size = 0x800; /* required amount of stack */ /* Specify the memory areas */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K SETTINGS_FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 16K SERVICE_FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 2K FLASH (rx) : ORIGIN = 0x08020800, LENGTH = 448K } /* Define output sections */ SECTIONS { .settings (NOLOAD): { . = ALIGN(2048); _settings = .; KEEP(*(.settings)) KEEP(*(.settings*)) . = ALIGN(2048); } >SETTINGS_FLASH /* The startup code goes first into FLASH */ .isr_vector (READONLY) : { . = ALIGN(4); _image_start = .; KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >SERVICE_FLASH .text_len : { . = ALIGN(8); _text_len = .; KEEP(*(.text_len)) KEEP(*(.text_len*)) LONG((_image_end - _image_start) / 4); /* application size, in 4-byte words */ . = ALIGN(8); } >SERVICE_FLASH .version (READONLY) : { . = ALIGN(8); _version = .; KEEP(*(.version)) KEEP(*(.version*)) . = ALIGN(8); } >SERVICE_FLASH .b_data (READONLY) : { . = ALIGN(8); _b_data = .; KEEP(*(.b_data)) KEEP(*(.b_data*)) . = ALIGN(8); } >SERVICE_FLASH .b_version (READONLY) : { . = ALIGN(8); _b_data = .; KEEP(*(.b_version)) KEEP(*(.b_version*)) . = ALIGN(8); } >SERVICE_FLASH /* The program code and other data goes into FLASH */ .text : { . = ALIGN(8); *(.text) /* .text sections (code) */ *(.text*) /* .text* sections (code) */ *(.glue_7) /* glue arm to thumb code */ *(.glue_7t) /* glue thumb to arm code */ *(.eh_frame) KEEP (*(.init)) KEEP (*(.fini)) . = ALIGN(8); _etext = .; /* define a global symbols at end of code */ } >FLASH /* Constant data goes into FLASH */ .rodata : { . = ALIGN(8); *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(8); } >FLASH .ARM.extab : { . = ALIGN(8); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(8); } >FLASH .ARM : { . = ALIGN(8); __exidx_start = .; *(.ARM.exidx*) __exidx_end = .; . = ALIGN(8); } >FLASH .preinit_array : { . = ALIGN(8); PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array*)) PROVIDE_HIDDEN (__preinit_array_end = .); . = ALIGN(8); } >FLASH .init_array : { . = ALIGN(8); PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array*)) PROVIDE_HIDDEN (__init_array_end = .); . = ALIGN(8); } >FLASH .fini_array : { . = ALIGN(8); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(8); } >FLASH /* used by the startup to initialize data */ _sidata = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code */ .data : { . = ALIGN(8); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(8); _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH _siccmram = LOADADDR(.ccmram); /* CCM-RAM section * * IMPORTANT NOTE! * If initialized variables will be placed in this section, * the startup code needs to be modified to copy the init-values. */ .ccmram : { . = ALIGN(8); _sccmram = .; /* create a global symbol at ccmram start */ *(.ccmram) *(.ccmram*) . = ALIGN(8); _eccmram = .; /* create a global symbol at ccmram end */ } >CCMRAM AT> FLASH .crc (READONLY) : { KEEP(*(.crc)) KEEP(*(.crc*)) _image_end = .; } >FLASH /* Uninitialized data section */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON) . = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ __bss_end__ = _ebss; } >RAM /* User_heap_stack section, used to check that there is enough RAM left */ ._user_heap_stack : { . = ALIGN(8); PROVIDE ( end = . ); PROVIDE ( _end = . ); . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(8); } >RAM /* Remove information from the standard libraries */ /DISCARD/ : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } .ARM.attributes 0 : { *(.ARM.attributes) } } Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 15 Posted April 15 · Report post .подправил предыдущее сообщение Quote Share this post Link to post Share on other sites More sharing options...
jcxz 304 April 15 Posted April 15 · Report post 2 часа назад, dimka76 сказал: Возможно у вас стабы не описаны в вашем скрипте и поэтому линковщик сам их пихает по своему разумению. Опишите их у себя. Я предполагал такой ответ... А откуда я знаю - какие имена стабов и veener-ов может сгенерить компоновщик или компилятор? Пускай даже сейчас я могу по .map-у посмотреть. Но завтра что-то добавлю в проект или новая версия GCC выйдет и нужно каждый раз проверять - не появилось ли новых секций с неизвестными ранее именами? Нужно - чтобы все секции с неизвестными именами (не фигурирующими явно нигде в скрипте), но подходящие по атрибутам (ro, rxo, ...) попадали в определённую секцию. Туда где "...". А .codetail - была после них. В IAR такое делается элементарно. Неужто во всеми хвалимом GCC такой ерунды нет??? Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 15 Posted April 15 · Report post On 4/15/2025 at 5:31 PM, jcxz said: Нужно - чтобы все секции с неизвестными именами (не фигурирующими явно нигде в скрипте), но подходящие по атрибутам (ro, rxo, ...) попадали в определённую секцию. Туда где "...". А .codetail - была после них. Судя по примеру из вашего первого поста, вам надо найти до куда считать CRC. В GCC есть стандартные и непоколебимые имена секций text, data, bss Все эти стабы попадают между секциями text и data. Конец вашей прошивки это конец секции data. Вот и размещайте вашу секцию .codetail после секции data. On 4/15/2025 at 5:31 PM, jcxz said: В IAR такое делается элементарно. Неужто во всеми хвалимом GCC такой ерунды нет??? У всех компиляторов есть свои преимущества и недостатки. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 304 April 16 Posted April 16 · Report post 4 часа назад, dimka76 сказал: Судя по примеру из вашего первого поста, вам надо найти до куда считать CRC. Не только. Мне нужно найти границы RO-образа прошивки. 4 часа назад, dimka76 сказал: В GCC есть стандартные и непоколебимые имена секций text, data, bss Все эти стабы попадают между секциями text и data. Конец вашей прошивки это конец секции data. Вот и размещайте вашу секцию .codetail после секции data. Серьёзно??? А ничего что .data - это RW-секция??? А значит - она никак не может быть "концом прошивки". Если же вы имели в виду .rodata, то советую ещё раз и внимательнее перечитать мой первый пост. Особенно обратить внимание на приведённые там результаты компоновки. Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 65 April 16 Posted April 16 · Report post 16 hours ago, jcxz said: Требуется чтобы .codetail была гарантированно последней в регионе RAM_regionA. Включите для этой секции выравнивание размеров с секцию. Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 16 Posted April 16 · Report post On 4/16/2025 at 3:59 AM, jcxz said: Не только. Мне нужно найти границы RO-образа прошивки. Серьёзно??? А ничего что .data - это RW-секция??? А значит - она никак не может быть "концом прошивки". Нет, в секции .data хранятся значения для инициализируемых переменных. Таким образом, инициализируемые переменные занимают две области памяти: RO для исходных значений и RW для собственно самих переменных. .bss секция это как раз чисто RW. Это глобальные переменные, которые явно не проинициализированы и которые инициализируются нулями. И секции .ARM.extab, .ARM, .fini, .fini_array и прочие, которые присутствуют в приведенном мною выше скрипте, это не случайные секции и они есть и будут всегда и компилятор вам ничего больше лишнего не напихает, кроме как необходимых секций. Вот тут есть кое что про секции https://stackoverflow.com/questions/40532180/understanding-the-linkerscript-for-an-arm-cortex-m-microcontroller Quote Share this post Link to post Share on other sites More sharing options...
jcxz 304 April 16 Posted April 16 · Report post 5 часов назад, tonyk_av сказал: Включите для этой секции выравнивание размеров с секцию. Уже давно включено - ничего не изменилось. Да и как может помочь выравнивание? 3 часа назад, dimka76 сказал: Нет, в секции .data хранятся значения для инициализируемых переменных. Серьёзно??? Что это за такая уникальная версия GCC у вас, у которой в .data хранятся инициализаторы переменных? В своём GCC по .map-у (и другим файлам) вижу, что .data - это RW-секция с инициализированными (не 0-и) данными. А инициализаторы - в .rodata. Да и в инете во всех примерах это видно. 3 часа назад, dimka76 сказал: .bss секция это как раз чисто RW. Это глобальные переменные, которые явно не проинициализированы и которые инициализируются нулями. Азы мне не нужно рассказывать. 3 часа назад, dimka76 сказал: И секции .ARM.extab, .ARM, .fini, .fini_array и прочие, которые присутствуют в приведенном мною выше скрипте, это не случайные секции и они есть и будут всегда и компилятор вам ничего больше лишнего не напихает Уверены? Откуда такая уверенность??? Просматривая множество примеров в инете, встречал и другие названия автогенерируемых GCC секций. А какие автогенерируемые секции появятся в следующих версиях GCC? 3 часа назад, dimka76 сказал: Вот тут есть кое что про секции https://stackoverflow.com/questions/40532180/understanding-the-linkerscript-for-an-arm-cortex-m-microcontroller Вы бы хоть свои же ссылки читали. Читаем написанное там вслух: Цитата The data section is put into flash. Why is that interesting? Because the .data sections are read/write. They're put into flash so that they are there when the power is turned on. The startup code copies them to RAM. А подобного я уже массу в инетике перечитал. Удовлетворительного ответа не нашёл. После чего и создал тему. Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 16 Posted April 16 · Report post On 4/16/2025 at 12:42 PM, jcxz said: Серьёзно??? Что это за такая уникальная версия GCC у вас, у которой в .data хранятся инициализаторы переменных? В своём GCC по .map-у (и другим файлам) вижу, что .data - это RW-секция с инициализированными (не 0-и) данными. А инициализаторы - в .rodata. Да и в инете во всех примерах это видно. Ладно, инициализаторы хранятся не в .data, но и не в .rodata. Смотрим скрипт линкера. /* Constant data goes into FLASH */ .rodata : { . = ALIGN(8); *(.rodata) /* .rodata sections (constants, strings, etc.) */ *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ . = ALIGN(8); } >FLASH .fini_array : { . = ALIGN(8); PROVIDE_HIDDEN (__fini_array_start = .); KEEP (*(SORT(.fini_array.*))) KEEP (*(.fini_array*)) PROVIDE_HIDDEN (__fini_array_end = .); . = ALIGN(8); } >FLASH /* used by the startup to initialize data */ //----->>> ОБРАТИТЕ ВНИМАНИЕ НА ЭТУ СТРОЧКУ !!! _sidata = LOADADDR(.data); /* Initialized data sections goes into RAM, load LMA copy after code */ .data : { . = ALIGN(8); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */ . = ALIGN(8); _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH .crc : { KEEP(*(.crc)) KEEP(*(.crc*)) _image_end = .; } >FLASH Теперь смотрим startup void __attribute__((naked, noreturn)) Reset_Handler() { unsigned long *pulSrc, *pulDest; pulSrc = &_sidata; for(pulDest = &_sdata; pulDest < &_edata; ) *(pulDest++) = *(pulSrc++); for(pulDest = &_sbss; pulDest < &_ebss; ) *(pulDest++) = 0; SystemInit(); __libc_init_array(); (void)main(); for (;;) ; } И смотрим откуда и куда копируются инициализаторы. Т.о. я описал секцию .crc после секции .data и этим гарантировал, что _image_end указывает на конец "прошивки". Еще приведу выдержку из map файла .rodata.main.str1.1 0x08007c17 0x1c1 release/obj/main.o 0x1c4 (size before relaxing) 0x08007dd8 . = ALIGN (0x8) .ARM.extab 0x08007dd8 0x0 ........................ .preinit_array 0x08007de0 0x0 ........................................ .init_array 0x08007de0 0x0 ..................................... .fini_array 0x08007de0 0x0 ................................................ 0x08007de0 _sidata = LOADADDR (.data) ...................................... .crc 0x08008248 0x4 ............................................... 0x0800824c _image_end = . Здесь видно где заканчивается секция .rodata, на что указывает _sidata, где начинается завершающая секция .crc и на что указывает _image_end Quote Share this post Link to post Share on other sites More sharing options...
sasamy 11 April 16 Posted April 16 · Report post 23 hours ago, jcxz said: Как сделать, чтобы все сгенерённые компоновщиком секции, идущие в данный регион, также вставлялись выше .codetail? попрорбуйте принудительно переместить указатель в конец Quote .codetail : { KEEP(*(.codetail)) __checksum_end = .; . = ORIGIN(RAM_regionA) + LENGTH(RAM_regionA); } > RAM_regionA Quote Share this post Link to post Share on other sites More sharing options...
tonyk_av 65 April 16 Posted April 16 · Report post 2 hours ago, jcxz said: Просматривая множество примеров в инете, встречал и другие названия автогенерируемых GCC секций. Это они? .ARM.extab : { . = ALIGN(4); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } >SECTOR_5_7 Quote Share this post Link to post Share on other sites More sharing options...
dimka76 70 April 16 Posted April 16 · Report post On 4/16/2025 at 2:39 PM, sasamy said: попрорбуйте принудительно переместить указатель в конец Не получится LENGHT() вернет размер всего региона памяти, а не размер занятой памяти. Quote LENGTH(memory) Return the length of the memory region named memory Quote Share this post Link to post Share on other sites More sharing options...
jcxz 304 April 16 Posted April 16 · Report post 2 часа назад, sasamy сказал: попрорбуйте принудительно переместить указатель в конец Что это даст? Зачем перемещать его за границу памяти? 2 часа назад, tonyk_av сказал: Это они? .ARM.extab : { . = ALIGN(4); *(.ARM.extab* .gnu.linkonce.armextab.*) . = ALIGN(4); } >SECTOR_5_7 И такие. И другие встречал. Quote Share this post Link to post Share on other sites More sharing options...
mantech 94 April 16 Posted April 16 · Report post В 15.04.2025 в 14:39, jcxz сказал: PS: В IAR это решается элементарно Если не секрет, почему тогда отказались от ИАРа? Мне в свое время пришлось, т.к. заказчик требовал лиц. чистоту, но не хотел платить 3000$ за лицензию, даже в складчину со мной, ну времена еще были не те))) Так бы никогда с ИАРа не съехал - он гораздо удобнее... Quote Share this post Link to post Share on other sites More sharing options...