Перейти к содержанию
    

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

 

Спасибо.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Изменено пользователем IgorKossak
бездумное цитирование

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

ищите в 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
[codebox] для длинного кода. [code]-для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

все функции одного файла исходника отправить в свою секцию, только каждой функции __attribute__ прикручивать?

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Изменено пользователем vovo

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот так мне нужно, но не работает
Но вы так и не сказали, зачем вам это нужно.

 

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

Замените

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

на

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но вы так и не сказали, зачем вам это нужно.

 

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

Замените

    .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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

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

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Извиняюсь. Пробел перед двоеточием, после ".text0" поставьте.

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

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

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

 

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...