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

    

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 модуль в первом регионе)))

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

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация