IAR Relocation failed error - linker

There is a project which successfully compiled linked and run on the device.
But after telling the linker that it should put the part of the application code to the ROM memory, instead of SDRAM, I am getting the following error at the linking step:
Error[Lp002]: relocation failed: value out of range or illegal:
0x60000545
Kind : R_ARM_PREL31[0x2a]
Location: 0xa0000030
Module: I:\Project\Debug\Obj\fileOper.o
Section: 128 (.ARM.exidx)
Offset: 0x0
Target : 0x00000574
"SECTION_FILEOP_87"
Module: I:\Project\Debug\Obj\fileOper.o
Section: 104 (SECTION_FILEOP)
Offset: 0x4f4
I have read the C/C++ guide from IAR. But it doesn't provide well enough explanations regarding this error. So even reading the manual I can't get the reason of this error. Can anybody help to resolve this problem?
Actually the IAR C/C++ developers guide says:
For each instruction that cannot be relocated correctly, ILINK will
generate a relocation error. This can occur for instructions where the
target is out of reach or is of an incompatible type, or for many
other reasons.
Then it provides the error as an example which is different than in my case.
EDIT 1: I have created the small project which reproduce the same errors and it consists of fileOper.cpp and main.cpp files only.
The ICF file used to tell linker how to put sections to memory:
define symbol intvec_start = 0x10000000;
/-Memory Regions-/
/-FLASH ROM-/
define symbol FLASH_ROM_start = 0x00000000;
define symbol FLASH_ROM_end = 0x0007FFFF;
/*Internal RAM*/
define symbol RAM_start = 0x10000000;
define symbol RAM_end = 0x10017FFF;
/*SDRAM*/
define symbol SDRAM_start = 0xA0000000;
define symbol SDRAM_end = 0xA1FFFFFF;
/-Sizes-/
define symbol size_stack = 0x4000;
define symbol size_heap = 0x2000;
define memory mem with size = 4G;
define region FLASH_region = mem:[from FLASH_ROM_start to
FLASH_ROM_end];
define region RAM_region = mem:[from RAM_start to RAM_end];
define region SDRAM_region = mem:[from SDRAM_start to SDRAM_end];
define block CSTACK with alignment = 8, size = size_stack { };
define block HEAP with alignment = 8, size = size_heap { };
initialize by copy with packing = zeros { readwrite };
do not initialize { section .noinit };
place at address mem: intvec_start { section .intvec };
place at start of FLASH_region { readonly section .cstartup };
place in RAM_region { block CSTACK };
place in SDRAM_region { readonly }
except {readonly section FILEOP };
place in SDRAM_region { readwrite };
place in SDRAM_region { block HEAP};
place in FLASH_region { readonly section FILEOP };
fileOper.cpp: I have changed it, but it still reproduce the same error.
#include "fileOperbug.h"
#include <string>
char *fgets( char *str, int num, std::string *stream ) {
char *pointer = 0;
return pointer;
}
std::string *fopen(const char *name, const char *mode) {
std::string *str = new std::string();
str->assign("");
return str;
}

I have resolved the problem.
While using IAR Embedded workbench:
Project options -> C/C++ Compiler -> Language 1 tab.
There at the "C++ dialect" there was a checkbox named "with exceptions" at it was checked.
The error at linking stage happens when "with exceptions" checkbox is checked.
All code that uses exceptions must be loaded to ROM. Otherwise the "with exceptions" should be unchecked.

Related

How to get the location of a section in C code

In the linker script, I have defined
MEMORY {
sec_1 : ORIGIN = 0x1B800, LENGTH = 2048
......
}
How can I read the start address of this section in C? I would like to copy it in a variable in the C code
Basically to achieve this, you have two tasks to fulfill:
Tell the linker to save the start address of the section. This can be achieved by placing a symbol in the linker script at the beginning of your section.
Tell the compiler to save initialize a constant with an address filled in later by the linker
As for the first step: In your section sec_1 you have to place a symbol that will be placed at the start of that section:
SECTIONS
{
...
.sec_1 :
{
__SEC_1_START = ABSOLUTE(.); /* <-- add this */
...
} > sec_1
...
}
Now that the linker produces bespoke symbol, you have to make it accessible from the compiler side. In order to do so, you need somewhere some code like this:
/* Make the compiler aware of the linker symbol, by telling it, there
is something, somewhere that the linker will put together (i.e. "extern") */
extern int __SEC_1_START;
void Sec1StartPrint(void) {
void * const SEC_1_START = &__SEC_1_START;
printf("The start address for sec_1 is: %p", SEC_1_START);
}
By calling Sec1StartPrint() you should get an address output that matches your *.map file the linker created.

in gcc linker, arrays with a specific section attribute placed in the section in reverse order of appearance in the source code

I tried to do a simple test and came across with this problem.
I have a linker script that says below
. = 0x70000000;
.compnn_stcweights : {
*(.compnn_weights)
}
this means any data with section attribute ".compnn_weights" should be placed in virtual address 0x70000000. and I have a header file
unsigned short __attribute__ ((__section__(".compnn_stcweights"))) stcWeight0[] = {
...
};
unsigned short __attribute__ ((__section__(".compnn_stcweights"))) stcWeight1[] = {
...
};
...
unsigned short __attribute__ ((__section__(".compnn_stcweights"))) stcWeight74[] = {
...
};
but after compiling, when I open the .map file, I see below.
.compnn_stcweights
0x70000000 0x764f23a ./obj/aiwareAbc.o
0x70000000 stcWeight74
0x7001fffe stcWeight73
0x700b09fe stcWeight72
...
0x7763b3fa stcWeight3
0x7764467a stcWeight2
0x776457ba stcWeight1
0x7764ea3a stcWeight0
Why are the stcWeightsX arrays placed int section in reverse order? I want stcWeight0 to appear first in the section. Is there a way I can fix this?

GCC ARM : vtable not initialized

I'm using arm-none-eabi-g++ to compile for an ARM Cortex M microcontroller. My code statically instantiates some modules, initialize them, and execute them sequentially in a loop. Each module (ModuleFoo, ModuleBar...) is a class which herits from a common Module class. The Module class defines two virtual functions, init() and exec(), which are implemented in every derived module. There are no explicit constructors, neither in the base nor the derived classes. Finally, I have a Context struct which is passed around and contains a list of pointers to the modules (Module* modules[]).
I had the following code which worked :
int main() {
ModuleFoo foo;
ModuleBar bar;
Context context;
const int N_MODULES = 2;
context.modules[0] = &foo; // Indexes are actually an enum but I stripped it to make it shorter
context.modules[1] = &bar;
for (int i = 0; i < N_MODULES; i++) {
context.modules[i]->init(context);
}
while (1) {
for (int i = 0; i < N_MODULES; i++) {
context.modules[i]->exec(context);
}
}
}
So far, so good (at least I think so, in any case it worked).
Now, I want to make the system more maintainable by moving all the code related to "which modules are used in a particular configuration" to a separate config.cpp/config.h file :
config.cpp :
ModuleFoo foo;
ModuleBar bar;
void initContext(Context& context) {
context.nModules = 2;
context.modules[0] = &foo;
context.modules[1] = &bar;
}
main.cpp :
#include "config.h"
int main() {
Context context;
initContext(context);
for (int i = 0; i < context.nModules; i++) {
context.modules[i]->init(context);
}
while (1) {
for (int i = 0; i < context.nModules; i++) {
context.modules[i]->exec(context);
}
}
}
The problem appears when init() is called on the first module (the MCU HardFaults). This is because, according to GDB, the vtable pointer is not initialized :
(gdb) p foo
$1 = {
<Module> = {
_vptr.Module = 0x0 <__isr_vector>,
_enabled = false
},
I rolled back with Git to check, with the previous code structure the vtable pointer was correctly initialized. And according to the linker's map file and GDB, the vtable exists (at around the same address as before):
.rodata 0x0000000000008e14 0x2c ModuleFoo.o
0x0000000000008e14 typeinfo name for ModuleFoo
0x0000000000008e1c typeinfo for ModuleFoo
0x0000000000008e28 vtable for ModuleFoo
The pointer is simply not set. The only difference I see between the two versions is that in the first one the modules are instanciated on the stack, whereas on the second they are instanciated globally in the bss :
.bss 0x00000000200015fc 0x22c config.o
0x00000000200015fc foo
0x000000002000164c bar
Could this be the problem?
In any case, thanks for taking the time to read this far!
**EDIT : **
The problem was coming from the startup code and the linker script. I used the sample files provided with Atmel's ARM GCC toolchain, which seem to be poorely written and, most importantly, didn't call __libc_init_array() (which is used to call global constructors). I switched to using the startup/linker script from ASF, and it works way better. Thanks #FreddieChopin !
Show us the startup code you are using. Most likely you did not enable global constructors, which can be done by calling __libc_init_array() function. You can test this theory, by manually calling this function at the beginning of main() - it should work fine then. If it does, then you should add that function to your startup code (Reset_Handler).
Quick test:
int main() {
extern "C" void __libc_init_array();
__libc_init_array();
// rest of your code...
To do it properly, find the place where your startup code calls main() (usually sth like ldr rX, =main and blx rX or maybe directly as bl main) and right before that do exactly the same but with __libc_init_array instead of main.

How to place a variable or function at specific location in IAR compiler?

I am using IAR Embedded Workbench for Renesas Syenrgy (ARM cortex M4) 7.40.5.9722
Code flash size : 1MB
Consider following example:
void function (void)
{
unsigned char a;
a = a+1;
}
I want to put this function at a specific location in flash.
What is method for defining a user defined section for this code.
I have gone through the IAR compiler user guide and implemented a method as mentioned below:
#pragma default_function_attributes = # "MY_FUNC"
void function (void)
{
unsigned char a;
a = a + 1;
}
#pragma default_function_attributes =
And in .icf file, i have added the section as follows :
define symbol region_VECT_start = 0x00000000;
define symbol region_VECT_end = 0x000003FF;
define symbol region_ROMREG_start = 0x00000400;
define symbol region_ROMREG_end = 0x000004FF;
define symbol region_FLASH_start = 0x00000500;
define symbol region_FLASH_end = 0x000BFFFF; // Fklsh end address is modified from 0x000FFFFF to 0x000BFFFF
define symbol region_MY_FUNC_start = 0x000C0000; // This statement is added
define symbol region_MY_FUNC_end = 0x000FFFFF; // This statement is added
define symbol region_RAM_start = 0x20000000;
define symbol region_RAM_end = 0x2002FFFF;
define symbol region_DF_start = 0x40100000;
define symbol region_DF_end = 0x40103FFF;
define symbol region_QSPI_start = 0x60000000;
define symbol region_QSPI_end = 0x63FFFFFF;
/* Stack and heap sizes are defined in bsp_cfg.h */
define memory mem with size = 4G;
define region VECT_region = mem:[from region_VECT_start to region_VECT_end];
define region ROMREG_region = mem:[from region_ROMREG_start to region_ROMREG_end];
define region FLASH_region = mem:[from region_FLASH_start to region_FLASH_end];
define region RAM_region = mem:[from region_RAM_start to region_RAM_end];
define region DF_region = mem:[from region_DF_start to region_DF_end];
define region QSPI_region = mem:[from region_QSPI_start to region_QSPI_end];
define region MY_FUNC = mem:[from region_MY_FUNC_start to region_MY_FUNC_end]; // New section is added
With these changes, the code is compiling properly.
But, "function" is not placed at required location 0x000C0000
Why is this?
You can place _Pragma("location=\"__your_section__\"") in front of the function.
And then in the linker file (for example):
define block __your_section_block__ size = 0x100 { section __your_section__ };
And make sure you add the line to the linker:
place in MY_FUNC { block __your_section_block__ };
You should change the definition of "MY_FUNC" to "MY_FUNC_region" in the .icf file to avoid confusions:
define region MY_FUNC_region = mem:[from region_MY_FUNC_start to region_MY_FUNC_end];
And then add the following line to place the "MY_FUNC" code inside the "MY_FUNC_region":
place in MY_FUNC_region { readonly section MY_FUNC };
(Not entirely sure if "readonly" keyword is absolutely needed but works for me)
Or, alternatively:
place at address mem:region_MY_FUNC_start { readonly section MY_FUNC};

How do you get the start and end addresses of a custom ELF section?

I'm working in C on Linux. I've seen the usage of of the gcc __section__ attribute (especially in the Linux kernel) to collect data (usually function pointers) into custom ELF sections. How is the "stuff" that gets put in those custom sections retrieved and used?
As long as the section name results in a valid C variable name, gcc (ld, rather) generates two magic variables: __start_SECTION and __stop_SECTION. Those can be used to retrieve the start and end addresses of a section, like so:
/**
* Assuming you've tagged some stuff earlier with:
* __attribute((__section__("my_custom_section")))
*/
struct thing *iter = &__start_my_custom_section;
for ( ; iter < &__stop_my_custom_section; ++iter) {
/* do something with *iter */
}
I couldn’t find any formal documentation for this feature, only a few obscure mailing list references. If you know where the docs are, drop a comment!
If you're using your own linker script (as the Linux kernel does) you'll have to add the magic variables yourself (see vmlinux.lds.[Sh] and this SO answer).
See here for another example of using custom ELF sections.
Collecting the information together from various answers, here is a working example of how to collect information into a custom linker section and then read the information from that section using the magic variables __start_SECTION and __stop_SECTION in your C program, where SECTION is the name of the section in the link map.
The __start_SECTION and __stop_SECTION variables are made available by the linker so explicit extern references need to be created for these variables when they are used from C code.
There are also some problems if the alignment used by the compiler for calculating pointer/array offsets is different than the alignment of the objects packed in each section by the linker. One solution (used in this example) is to store only a pointer to the data in the linker section.
#include <stdio.h>
struct thing {
int val;
const char* str;
int another_val;
};
struct thing data1 = {1, "one"};
struct thing data2 = {2, "two"};
/* The following two pointers will be placed in "my_custom_section".
* Store pointers (instead of structs) in "my_custom_section" to ensure
* matching alignment when accessed using iterator in main(). */
struct thing *p_one __attribute__((section("my_custom_section"))) = &data1;
struct thing *p_two __attribute__((section("my_custom_section"))) = &data2;
/* The linker automatically creates these symbols for "my_custom_section". */
extern struct thing *__start_my_custom_section;
extern struct thing *__stop_my_custom_section;
int main(void) {
struct thing **iter = &__start_my_custom_section;
for ( ; iter < &__stop_my_custom_section; ++iter) {
printf("Have thing %d: '%s'\n", (*iter)->val, (*iter)->str);
}
return 0;
}
Linker can use the symbols defined in the code, and can assign their initial values if you use the exact name in the linker script:
_smysection = .;
*(.mysection)
*(.mysection*)
_emysection = .;
Just define a variable in C code:
const void * _smysection;
And then you can access that as a regular variable.
u32 someVar = (u32)&_smysection;
So the answer above, __start_SECTION and __stop_SECTION will work, however for the program to be able to use the information from the linker you to need to declare those variables as extern char* __start_SECTION. Enjoy!
extern char * __start_blobby;
...
printf("This section starts at %p\n", (unsigned int)&__start_blobby);
...
HI: like this.
extern const struct pseudo_ta_head __start_ta_head_section;
extern const struct pseudo_ta_head __stop_ta_head_section;
const struct pseudo_ta_head *start = &__start_ta_head_section;
const struct pseudo_ta_head *end = &__stop_ta_head_section;

Resources