|
|
|
GNU Tools ARM Embedded неопределённые ссылки из файла startup_ARMCM3.S |
|
|
|
Apr 7 2017, 12:46
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Доброго времени дня! Никак не могу найти решение проблемы.
linking... ./gnu/startup_armcm3.o: In function `Reset_Handler': E:\ARM_F/SRC/startup_ARMCM3.S:172: undefined reference to `__copy_table_start__' E:\ARM_F/SRC/startup_ARMCM3.S:173: undefined reference to `__copy_table_end__' E:\ARM_F/SRC/startup_ARMCM3.S:204: undefined reference to `__data_start__' E:\ARM_F/SRC/startup_ARMCM3.S:205: undefined reference to `__data_end__' E:\ARM_F/SRC/startup_ARMCM3.S:233: undefined reference to `__zero_table_start__' E:\ARM_F/SRC/startup_ARMCM3.S:234: undefined reference to `__zero_table_end__' collect2.exe: error: ld returned 1 exit status
Toolchain GNU Tools ARM Embedded\5.4 2016q3
Файл startup_ARMCM3.S взят из папки c тулчейном. Включён взамен стартового файла рабочего проекта, собранного на ARM MDK. Проект на GCC успешно компилится но не хочет собираться по указанным выше причинам. Вопрос - чего в супе не хватает? Это ведь области RAM, которые при старте инициализируются или обнуляются, что не так? Спасибо.
|
|
|
|
|
Apr 7 2017, 13:49
|
Местный
Группа: Свой
Сообщений: 243
Регистрация: 5-10-06
Из: Зеленоград
Пользователь №: 21 007
|
заимствовали стартап файл и линкер-файл от разных проектов? нотация имён необычная. ищите в ld-файле что-то вида: Код _etext = .; .data : /* AT makes the LMA follow on in the binary image */ { . = ALIGN(4); _sidata = _etext; /* start of initialized data label */ _sdata = .; /* start of .data label */ KEEP( *(.data) ) KEEP( *(.data.*) ) . = ALIGN(4); _edata = .; /* end of .data label */ } > RAM AT > FLASH
/* .bss section - uninitialized data */ .bss : { . = ALIGN(4); _sbss = .; /* start of .bss label (for startup) */ *(.bss) *(.bss.*) *(COMMON) . = ALIGN(4); _ebss = .; /* end of .bss label (for startup) */ _end = .; /* end of used ram (start of free memory, for malloc) */ __end = .; /* the same */ end = .; /* the same */ } > RAM и приводите имена в ссылках на память (строчки вида _end = . к вашим именам из ассемблерного файла
Сообщение отредактировал IgorKossak - Apr 7 2017, 14:02
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
|
|
|
|
|
Apr 7 2017, 14:04
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Линкер файл я даже не цеплял. Думал, по аналогии с MDK, что по умолчанию что то должно быть. Стартап взят отсюда C:\Program Files (x86)\GNU Tools ARM Embedded\5.4 2016q3\share\gcc-arm-none-eabi\samples\startup, тул скачан с ARMа. Я посмотрел *.ld файл, предлагаемый в тулчейне, там тоже нет этих символов, кроме __bss_start__, этот совпадает. Ok, спасибо за подсказки, пошёл изучать скрипты линкера.
|
|
|
|
|
Apr 11 2017, 07:50
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Ещё раз благодарю за подсказки, с multi RAM разбрался. А вот как быть с multi ROM? Только когда секция FLASH едина, только тогда правильно выставляестя топ стека и стартовый переход. А вот стоит мне порезать FLASH на куски, то секция векторов прерываний и стартовый код ложатся таки куда надо, а вот топ стека адрес перехода на стартовый код нулевые выходят. И параллельно вопрос- а что в GCC нет возможности одной директивой все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать?
|
|
|
|
|
Apr 11 2017, 09:09
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (vovo @ Apr 11 2017, 10:50) А вот стоит мне порезать FLASH на куски, то секция векторов прерываний и стартовый код ложатся таки куда надо, а вот топ стека адрес перехода на стартовый код нулевые выходят. «Дорогие учёные. У меня который год в подполе происходит подземный стук. Объясните, пожалуйста, как он происходит». QUOTE (vovo @ Apr 11 2017, 10:50) И параллельно вопрос- а что в GCC нет возможности одной директивой все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать? Читайте документацию на линкер. Это все делается в скрипте линкера. Пару раз у меня возникало желание сделать такое, но всякий раз выяснялось, что это тянет за собой кучу других проблем и при другом подходе к решению задачи этого не требуется и проблем не возникает. Опишите более подробно вашу задачу.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 11 2017, 09:50
|
Знающий
Группа: Свой
Сообщений: 558
Регистрация: 26-11-14
Из: Зеленоград
Пользователь №: 83 842
|
Цитата(vovo @ Apr 11 2017, 10:50) все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать? В скрипте линкера. В нужную секцию добавить: *<имя файла>.o(.text .text* .rodata .rodata.* .constdata .constdata.*) потом в той секции откуда взят файл: *(EXCLUDE_FILE(*<имя файла>.o ...) .text*) Имена секций поправьте сами.
|
|
|
|
|
Apr 11 2017, 10:54
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Да, по второму вопросу протупил, виноват, исправлюсь. Хотя..., а если это библиотека, я не знаю имён модулей, но хочу разместить её в определённом фрагменте памяти? А вот по первому CODE /* Linker script to configure memory regions. * Need modifying for a specific board. * FLASH.ORIGIN: starting address of flash * FLASH.LENGTH: length of flash * RAM.ORIGIN: starting address of RAM bank 0 * RAM.LENGTH: length of RAM bank 0 */ MEMORY { FLASH1 (rx) : ORIGIN = 0x0, LENGTH = 0x1000 FLASH2 ® : ORIGIN = 0x1000, LENGTH = 0x1000 FLASH3 (rx) : ORIGIN = 0x2000, LENGTH = 0x80000 - 0x2000 RAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 8K */ RAM2 (rwx) : ORIGIN = 0x2007c000, LENGTH = 0x8000 /* 8K */ }
/* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. * It references following symbols, which must be defined in code: * Reset_Handler : Entry of reset handler * * It defines following symbols, which code can use without definition: * __exidx_start * __exidx_end * __copy_table_start__ * __copy_table_end__ * __zero_table_start__ * __zero_table_end__ * __etext * __data_start__ * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __data_end__ * __bss_start__ * __bss_end__ * __end__ * end * __HeapLimit * __StackLimit * __StackTop * __stack */ ENTRY(Reset_Handler)
SECTIONS { .text0 0x0: { KEEP(*(.isr_vector)) KEEP(*(.Reset_Handler_s)) KEEP(*(.init)) KEEP(*(.fini)) } > FLASH1 .dfdata 0x1000: { /*. = 0x1000;*/ *(.ARM.__AT_0x00001000) } > FLASH2 .text 0x2000 : { /*. = 0x2000;*/ *(.text*)
/* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors)
/* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*)) } > FLASH3
__exab_start = .; .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH3 __exab_end = .;
__exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH3 __exidx_end = .;
/* To copy multiple ROM to RAM sections, * uncomment .copy.table section and, * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ /* .copy.table : { . = ALIGN(4); __copy_table_start__ = .; LONG (__etext) LONG (__data_start__) LONG (__data_end__ - __data_start__) LONG (__etext2) LONG (__data2_start__) LONG (__data2_end__ - __data2_start__) __copy_table_end__ = .; } > FLASH3 */
/* To clear multiple BSS sections, * uncomment .zero.table section and, * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ /* .zero.table : { . = ALIGN(4); __zero_table_start__ = .; LONG (__bss_start__) LONG (__bss_end__ - __bss_start__) LONG (__bss2_start__) LONG (__bss2_end__ - __bss2_start__) __zero_table_end__ = .; } > FLASH3 */
__etext = .; .data : AT (__etext) { __data_start__ = .; *(vtable) *(.data*)
. = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ __data_end__ = .;
} > RAM
.bss_RAM2 : ALIGN(4) { PROVIDE(__start_bss_RAM2 = .) ; *(LWIP_ram_heap*) *(.bss.$RamAHB32*) . = ALIGN (. != 0 ? 4 : 1) ; /* avoid empty segment */ PROVIDE(__end_bss_RAM2 = .) ; } > RAM2 .bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) *(COMMON) . = ALIGN(4); __bss_end__ = .; } > RAM .heap (COPY): { __end__ = .; PROVIDE(end = .); *(.heap*) __HeapLimit = .; } > RAM2
/* .stack_dummy section doesn't contains any symbols. It is only * used for linker to calculate size of stack sections, and assign * values to stack symbols later */ .stack_dummy (COPY): { *(.stack*) } > RAM2
/* Set stack top to end of RAM, and stack limit move down by * size of stack_dummy section */ __StackTop = ORIGIN(RAM) + LENGTH(RAM); __StackLimit = __StackTop - SIZEOF(.stack_dummy); PROVIDE(__stack = __StackTop); /* Check if data + heap + stack exceeds RAM limit */ /*ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")*/ }
Вот так мне нужно, но не работает А вот так работает CODE /* Linker script to configure memory regions. * Need modifying for a specific board. * FLASH.ORIGIN: starting address of flash * FLASH.LENGTH: length of flash * RAM.ORIGIN: starting address of RAM bank 0 * RAM.LENGTH: length of RAM bank 0 */ MEMORY { FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x80000 /* 128K */ RAM (rwx) : ORIGIN = 0x10000000, LENGTH = 0x8000 /* 8K */ RAM2 (rwx) : ORIGIN = 0x200c7000, LENGTH = 0x8000 /* 8K */ }
/* Linker script to place sections and symbol values. Should be used together * with other linker script that defines memory regions FLASH and RAM. * It references following symbols, which must be defined in code: * Reset_Handler : Entry of reset handler * * It defines following symbols, which code can use without definition: * __exidx_start * __exidx_end * __copy_table_start__ * __copy_table_end__ * __zero_table_start__ * __zero_table_end__ * __etext * __data_start__ * __preinit_array_start * __preinit_array_end * __init_array_start * __init_array_end * __fini_array_start * __fini_array_end * __data_end__ * __bss_start__ * __bss_end__ * __end__ * end * __HeapLimit * __StackLimit * __StackTop * __stack */ ENTRY(Reset_Handler)
SECTIONS { .text : { KEEP(*(.isr_vector)) *(.text*)
KEEP(*(.init)) KEEP(*(.fini))
/* .ctors */ *crtbegin.o(.ctors) *crtbegin?.o(.ctors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) *(SORT(.ctors.*)) *(.ctors)
/* .dtors */ *crtbegin.o(.dtors) *crtbegin?.o(.dtors) *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) *(SORT(.dtors.*)) *(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*)) } > FLASH
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } > FLASH
__exidx_start = .; .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } > FLASH __exidx_end = .;
/* To copy multiple ROM to RAM sections, * uncomment .copy.table section and, * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ .copy.table : { . = ALIGN(4); __copy_table_start__ = .; LONG (__etext) LONG (__data_start__) LONG (__data_end__ - __data_start__) LONG (__etext2) LONG (__data2_start__) LONG (__data2_end__ - __data2_start__) __copy_table_end__ = .; } > FLASH
/* To clear multiple BSS sections, * uncomment .zero.table section and, * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ .zero.table : { . = ALIGN(4); __zero_table_start__ = .; LONG (__bss_start__) LONG (__bss_end__ - __bss_start__) LONG (__bss2_start__) LONG (__bss2_end__ - __bss2_start__) __zero_table_end__ = .; } > FLASH
__etext = .; .data : AT (__etext) { __data_start__ = .; *(LWIP_ram_heap) __data_end__ = .;
} > RAM
__etext2 = __etext + SIZEOF(.data); .data2 : AT (__etext2) { __data2_start__ = .; *(vtable) *(.data*)
. = ALIGN(4); /* preinit data */ PROVIDE_HIDDEN (__preinit_array_start = .); KEEP(*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4); /* init data */ PROVIDE_HIDDEN (__init_array_start = .); KEEP(*(SORT(.init_array.*))) KEEP(*(.init_array)) PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4); /* finit data */ PROVIDE_HIDDEN (__fini_array_start = .); KEEP(*(SORT(.fini_array.*))) KEEP(*(.fini_array)) PROVIDE_HIDDEN (__fini_array_end = .);
KEEP(*(.jcr*)) . = ALIGN(4); /* All data end */ __data2_end__ = .;
} > RAM2
.bss : { . = ALIGN(4); __bss_start__ = .; *(.bss*) . = ALIGN(4); __bss_end__ = .; } > RAM
.bss2 : { . = ALIGN(4); __bss2_start__ = .; *(COMMON) . = ALIGN(4); __bss2_end__ = .; } > RAM2 .heap (COPY): { __end__ = .; PROVIDE(end = .); *(.heap*) __HeapLimit = .; } > RAM2
/* .stack_dummy section doesn't contains any symbols. It is only * used for linker to calculate size of stack sections, and assign * values to stack symbols later */ .stack_dummy (COPY): { *(.stack*) } > RAM2
/* Set stack top to end of RAM, and stack limit move down by * size of stack_dummy section */ __StackTop = ORIGIN(RAM) + LENGTH(RAM); __StackLimit = __StackTop - SIZEOF(.stack_dummy); PROVIDE(__stack = __StackTop); /* Check if data + heap + stack exceeds RAM limit */ ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") }
Сообщение отредактировал vovo - Apr 11 2017, 11:15
|
|
|
|
|
Apr 11 2017, 11:20
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (vovo @ Apr 11 2017, 13:54) Вот так мне нужно, но не работает Но вы так и не сказали, зачем вам это нужно. Зачем вы дважды указываете адрес - при задании региона и при объявлении выходной секции? Замените CODE .text0 0x0: { ...... } > FLASH1 на CODE .text0: { ...... } > FLASH1 и с остальными секциями аналогично.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 11 2017, 13:13
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Цитата(Сергей Борщ @ Apr 11 2017, 14:20) Но вы так и не сказали, зачем вам это нужно. Зачем вы дважды указываете адрес - при задании региона и при объявлении выходной секции? Замените Код .text0 0x0: { ...... } > FLASH1 на Код .text0: { ...... } > FLASH1 и с остальными секциями аналогично. Попробовал, в строке где скобка открывающая, линкер выдаёт ошибку синтаксиса. Код c:/program files (x86)/gnu tools arm embedded/5.4 2016q3/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe:./SRC/gcc.ld:55: syntax error Мне не совсем понятен настойчивый вопрос про цель всего этого, но отвечу: в нулевом сегменте лежит код, на который смотрит bootloader чипа, его трогать нельзя, в первом сегменте, лежат данные, изменяемые программой по внешним воздействиям, в последующих сегментах остальной код программы, причём желательно его также разместить по необходимым адресам.
Сообщение отредактировал vovo - Apr 11 2017, 13:22
|
|
|
|
|
Apr 11 2017, 15:20
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (vovo @ Apr 11 2017, 16:13) Попробовал, в строке где скобка открывающая, линкер выдаёт ошибку синтаксиса. Извиняюсь. Пробел перед двоеточием, после ".text0" поставьте. QUOTE (vovo @ Apr 11 2017, 16:13) Мне не совсем понятен настойчивый вопрос про цель всего этого, но отвечу: в нулевом сегменте лежит код, на который смотрит bootloader чипа, его трогать нельзя, в первом сегменте, лежат данные, изменяемые программой по внешним воздействиям, в последующих сегментах остальной код программы, причём желательно его также разместить по необходимым адресам. Вот-вот-вот. Я примерно это и предполагал. Не нужно совершенно разные вещи (bootloader и приложение) запихивать в один проект. Сделайте два совершенно отдельных проекта, у каждого секцию .text разместите куда нужно, ссылки на необходимые адреса другого проекта сделайте через extern в коде и символы в скрипте линкера. И ничего не придется переносить. Потому что при текущем подходе вы столкнетесь с необходимостью иметь две копии библиотечных функций (чтобы обновлять их вместе с приложением и чтобы загрузчик работал пока приложения нет), потом вдруг выяснится, что вы, развивая приложение, случайно что-то поменяли в загрузчике и приложение уже месяц как несовместимо с проданными год назад устройствами, но прекрасно совместимо с текущим загрузчиком и поэтому вы целый месяц ничего не замечали. Чтобы выпустить обновление для рассылки заказчикам вам придется каким-то образом отделять мух от котлет из результатов сборки проекта вырезать загрузчик не повредив приложение. Загрузчик надо делать отдельным проектом и при необходимости объединять с приложением слиянием выходных .hex-файлов. P.S. И постарайтесь избегать избыточного цитирования, оно является нарушением Правил форума.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 11 2017, 17:04
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Цитата(Сергей Борщ @ Apr 11 2017, 18:20) Извиняюсь. Пробел перед двоеточием, после ".text0" поставьте. Про пробел я и сам уже понял, но это не спасает Цитата(Сергей Борщ @ Apr 11 2017, 18:20) P.S. И постарайтесь избегать избыточного цитирования, оно является нарушением Правил форума. С таким движком форума впервые общаюсь. Цитата(Сергей Борщ @ Apr 11 2017, 18:20) Не нужно совершенно разные вещи (bootloader и приложение) запихивать в один проект загрузчик это не проект, он прошит в ROM чипа, при наличие программы (по оценке сектора 0 и тела программы) он её запускает, но для этого а адресе 0x00000000 должен быть адрес вершины стека, а в адресе 0x00000004 адрес перехода на начало программы. Вот их то в таком случае ликер и не помещает образ. Если область флеша одна, линкер правильно размещает начальные адреса, размещает данные с адреса 0х1000 по 0х2000, но заполняет нулями и главное включает в образ, что при программировании приводит к уничтожению этих данных. С ARM компилятором всё великолепно получается, но требуется переход на GCC.
|
|
|
|
|
Apr 11 2017, 19:08
|
Гуру
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095
|
QUOTE (vovo @ Apr 11 2017, 20:04) загрузчик это не проект, он прошит в ROM чипа, при наличие программы (по оценке сектора 0 и тела программы) он её запускает, но для этого а адресе 0x00000000 должен быть адрес вершины стека, а в адресе 0x00000004 адрес перехода на начало программы. Вот их то в таком случае ликер и не помещает образ. Теперь понятно. Попробуйте назвать выходную секцию не ".text0", а ".text.0". QUOTE (vovo @ Apr 11 2017, 20:04) размещает данные с адреса 0х1000 по 0х2000, но заполняет нулями и главное включает в образ, что при программировании приводит к уничтожению этих данных. Для этого есть атрибут секции NOLOAD (пока на форуме проблемы с редиректом скопируйте ссылку вручную).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 12 2017, 14:37
|
Группа: Участник
Сообщений: 9
Регистрация: 25-02-09
Пользователь №: 45 366
|
Хорошая ссылка, гораздо гораздее чем штатный pdf, спасибо. А ларчик открылся весьма просто - надо было всего лишь явно указать startup модуль в первом регионе))) Спасибо всем кто участвовал))), пока вроде всё намазывается, если что, ещё вас помучаю.
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|