Jump to content

    

GNU Tools ARM Embedded неопределённые ссылки из файла startup_ARMCM3.S

Доброго времени дня!

Никак не могу найти решение проблемы.

 

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, которые при старте инициализируются или обнуляются, что не так?

 

Спасибо.

 

Share this post


Link to post
Share on other sites

А в линкер-файле эти регионы определены и именуются также ?

Edited by IgorKossak
бездумное цитирование

Share this post


Link to post
Share on other sites

заимствовали стартап файл и линкер-файл от разных проектов? нотация имён необычная.

ищите в 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 = .;) к вашим именам из ассемблерного файла

Edited by IgorKossak
[codebox] для длинного кода. [code]-для короткого!!!

Share this post


Link to post
Share on other sites

Линкер файл я даже не цеплял. Думал, по аналогии с MDK, что по умолчанию что то должно быть. Стартап взят отсюда C:\Program Files (x86)\GNU Tools ARM Embedded\5.4 2016q3\share\gcc-arm-none-eabi\samples\startup, тул скачан с ARMа. Я посмотрел *.ld файл, предлагаемый в тулчейне, там тоже нет этих символов, кроме __bss_start__, этот совпадает. Ok, спасибо за подсказки, пошёл изучать скрипты линкера.

Share this post


Link to post
Share on other sites

Ещё раз благодарю за подсказки, с multi RAM разбрался. А вот как быть с multi ROM? Только когда секция FLASH едина, только тогда правильно выставляестя топ стека и стартовый переход. А вот стоит мне порезать FLASH на куски, то секция векторов прерываний и стартовый код ложатся таки куда надо, а вот топ стека адрес перехода на стартовый код нулевые выходят. И параллельно вопрос- а что в GCC нет возможности одной директивой все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать?

Share this post


Link to post
Share on other sites
А вот стоит мне порезать FLASH на куски, то секция векторов прерываний и стартовый код ложатся таки куда надо, а вот топ стека адрес перехода на стартовый код нулевые выходят.
«Дорогие учёные. У меня который год в подполе происходит подземный стук. Объясните, пожалуйста, как он происходит».

 

И параллельно вопрос- а что в GCC нет возможности одной директивой все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать?
Читайте документацию на линкер. Это все делается в скрипте линкера. Пару раз у меня возникало желание сделать такое, но всякий раз выяснялось, что это тянет за собой кучу других проблем и при другом подходе к решению задачи этого не требуется и проблем не возникает. Опишите более подробно вашу задачу.

Share this post


Link to post
Share on other sites
все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать?

В скрипте линкера. В нужную секцию добавить:

*<имя файла>.o(.text .text* .rodata .rodata.* .constdata .constdata.*)

потом в той секции откуда взят файл:

*(EXCLUDE_FILE(*<имя файла>.o ...) .text*)

Имена секций поправьте сами.

Share this post


Link to post
Share on other sites

Да, по второму вопросу протупил, виноват, исправлюсь. Хотя..., а если это библиотека, я не знаю имён модулей, но хочу разместить её в определённом фрагменте памяти?

А вот по первому

/* 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")*/
}

Вот так мне нужно, но не работает

А вот так работает

/* 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")
}

Edited by vovo

Share this post


Link to post
Share on other sites
Вот так мне нужно, но не работает
Но вы так и не сказали, зачем вам это нужно.

 

Зачем вы дважды указываете адрес - при задании региона и при объявлении выходной секции?

Замените

    .text0 0x0:
    {
        ......
    } > FLASH1

на

    .text0:
    {
        ......
    } > FLASH1

и с остальными секциями аналогично.

Share this post


Link to post
Share on other sites
Да, по второму вопросу протупил, виноват, исправлюсь. Хотя..., а если это библиотека, я не знаю имён модулей,

Что значит не знаете? Можете узнать с помощью *ar если не путаю, но не хотите напрягаться и гуглить.

Share this post


Link to post
Share on other sites
Но вы так и не сказали, зачем вам это нужно.

 

Зачем вы дважды указываете адрес - при задании региона и при объявлении выходной секции?

Замените

    .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 чипа, его трогать нельзя, в первом сегменте, лежат данные, изменяемые программой по внешним воздействиям, в последующих сегментах остальной код программы, причём желательно его также разместить по необходимым адресам.

Edited by vovo

Share this post


Link to post
Share on other sites
Попробовал, в строке где скобка открывающая, линкер выдаёт ошибку синтаксиса.
Извиняюсь. Пробел перед двоеточием, после ".text0" поставьте.

 

Мне не совсем понятен настойчивый вопрос про цель всего этого, но отвечу: в нулевом сегменте лежит код, на который смотрит bootloader чипа, его трогать нельзя, в первом сегменте, лежат данные, изменяемые программой по внешним воздействиям, в последующих сегментах остальной код программы, причём желательно его также разместить по необходимым адресам.
Вот-вот-вот. Я примерно это и предполагал. Не нужно совершенно разные вещи (bootloader и приложение) запихивать в один проект. Сделайте два совершенно отдельных проекта, у каждого секцию .text разместите куда нужно, ссылки на необходимые адреса другого проекта сделайте через extern в коде и символы в скрипте линкера. И ничего не придется переносить. Потому что при текущем подходе вы столкнетесь с необходимостью иметь две копии библиотечных функций (чтобы обновлять их вместе с приложением и чтобы загрузчик работал пока приложения нет), потом вдруг выяснится, что вы, развивая приложение, случайно что-то поменяли в загрузчике и приложение уже месяц как несовместимо с проданными год назад устройствами, но прекрасно совместимо с текущим загрузчиком и поэтому вы целый месяц ничего не замечали. Чтобы выпустить обновление для рассылки заказчикам вам придется каким-то образом отделять мух от котлет из результатов сборки проекта вырезать загрузчик не повредив приложение.

 

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

 

P.S. И постарайтесь избегать избыточного цитирования, оно является нарушением Правил форума.

Share this post


Link to post
Share on other sites
Извиняюсь. Пробел перед двоеточием, после ".text0" поставьте.

Про пробел я и сам уже понял, но это не спасает

P.S. И постарайтесь избегать избыточного цитирования, оно является нарушением Правил форума.

С таким движком форума впервые общаюсь.

 

Не нужно совершенно разные вещи (bootloader и приложение) запихивать в один проект

загрузчик это не проект, он прошит в ROM чипа, при наличие программы (по оценке сектора 0 и тела программы) он её запускает, но для этого а адресе 0x00000000 должен быть адрес вершины стека, а в адресе 0x00000004 адрес перехода на начало программы. Вот их то в таком случае ликер и не помещает образ. Если область флеша одна, линкер правильно размещает начальные адреса, размещает данные с адреса 0х1000 по 0х2000, но заполняет нулями и главное включает в образ, что при программировании приводит к уничтожению этих данных. С ARM компилятором всё великолепно получается, но требуется переход на GCC.

 

Share this post


Link to post
Share on other sites
загрузчик это не проект, он прошит в ROM чипа, при наличие программы (по оценке сектора 0 и тела программы) он её запускает, но для этого а адресе 0x00000000 должен быть адрес вершины стека, а в адресе 0x00000004 адрес перехода на начало программы. Вот их то в таком случае ликер и не помещает образ.
Теперь понятно. Попробуйте назвать выходную секцию не ".text0", а ".text.0".

 

 

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

Share this post


Link to post
Share on other sites

Хорошая ссылка, гораздо гораздее чем штатный pdf, спасибо.

А ларчик открылся весьма просто - надо было всего лишь явно указать startup модуль в первом регионе)))

Спасибо всем кто участвовал))), пока вроде всё намазывается, если что, ещё вас помучаю.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this