IAR equivalent symbol to __bss_end__ - linker

I want to know where is the end of my static data in RAM of Cortex-M. GCC CMSIS linker scripts provide a symbol for __bss_end__ and I simply take its address. Is there an IAR equivalent? Or do I have to make a dummy section with a single variable and place it after readwrite?
This is my (very standard) IAR linker script:
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ROM_end__ = (0x00000000+0x00010000-1);
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = (0x20000000+0x00002000-1);
/*-Sizes-*/
if ( !isdefinedsymbol( __ICFEDIT_size_cstack__ ) )
{ define symbol __ICFEDIT_size_cstack__ = 0x400; }
if ( !isdefinedsymbol( __ICFEDIT_size_heap__ ) )
{ define symbol __ICFEDIT_size_heap__ = 0x800; }
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
initialize by copy { readwrite };
keep { section .intvec };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { readwrite,
block CSTACK,
block HEAP };

If you create a block, put the data in it and place the block you can use __section_begin() and __section_end() to get pointers to the beginning and the end of this block.
Example linker configuration:
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x00000000;
define symbol __ICFEDIT_region_ROM_end__ = (0x00000000+0x00010000-1);
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = (0x20000000+0x00002000-1);
/*-Sizes-*/
if ( !isdefinedsymbol( __ICFEDIT_size_cstack__ ) )
{ define symbol __ICFEDIT_size_cstack__ = 0x400; }
if ( !isdefinedsymbol( __ICFEDIT_size_heap__ ) )
{ define symbol __ICFEDIT_size_heap__ = 0x800; }
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
define block RWDATA { readwrite }; /* Create block for readwrite to find its boundaries */
initialize by copy { readwrite };
keep { section .intvec };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { block RWDATA, block CSTACK, block HEAP };
And the code to access the information
#include <stdio.h>
#pragma language = extended
#pragma section = "RWDATA"
int main(void)
{
char const *rw_start = __section_begin("RWDATA");
char const *rw_end = __section_end("RWDATA");
printf("rw_start = %x, rw_end = %x\n", rw_start, rw_end);
}

Related

How to put a symbol in a particular location of the elf file generated - linker script?

I am trying to define a user-defined section inside the linker file.
/* Specify the memory areas */
MEMORY
{
m_text (RX) : ORIGIN = 0x00003000, LENGTH = 0x000FD000
}
SECTIONS
{
....
.tog 0xFFFF0:
{
. = ALIGN(4);
. = . + 8;
. = ALIGN(4);
} > m_text
}
In the code, I have placed the
unsigned int togganta __attribute__((section("tog "))) = 0;
However, when I do a hexadump using xxd I see this symbol togganta inside the binary address - 00f78580. I expected it to be at the address 0xFFFF0. what am I missing here?

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};

Understanding section headers ELF

static inline Elf32_Shdr *elf_sheader(Elf32_Ehdr *hdr) {
return (Elf32_Shdr *)((int)hdr + hdr->e_shoff);
}
static inline Elf32_Shdr *elf_section(Elf32_Ehdr *hdr, int idx) {
return &elf_sheader(hdr)[idx];
}
Okay the first function here returns a pointer to a elf section header by using hdr_shoff because that is the offset to first section header . Now the second function is used to access more section headers ( if there be any ) just by using array indexing .
static inline char *elf_str_table(Elf32_Ehdr *hdr) {
if(hdr->e_shstrndx == SHN_UNDEF) return NULL;
return (char *)hdr + elf_section(hdr, hdr->e_shstrndx)->sh_offset;
}
static inline char *elf_lookup_string(Elf32_Ehdr *hdr, int offset) {
char *strtab = elf_str_table(hdr);
if(strtab == NULL) return NULL;
return strtab + offset;
}
I am having problems with the above two function used for accessing section names . e->shstrndx is the index of the string table . So in elf_str_table we first check it against SHN_UNDEF . But in the return I don't understand that hdr->e_shstrndx is the index to a string table , how is that index added to the starting address of the elf_section header giving another elf section header ( as we are using it access sh_offset ) . My confusion is that e->shstrndx is an index to a string table but how is it that this index along with elf_section returning a pointer to struct Elf32_Shdr ?
Reference : http://wiki.osdev.org/ELF_Tutorial#Accessing_Section_Headers
You said yourself that elf_section returns a section header based on an index.
e_shstrndx is the index of the section header that contains the offset of the section header string table.
So, you use e_shstrndx as a parameter for elf_section to get that section header :
Elf32_Shdr* shstr = elf_section(hdr, hdr->e_shstrndx);
Then get the offset from that section header :
int strtab_offset = shstr->sh_offset;
And use it to get the actual string table :
char* strtab = (char*) hdr + strtab_offset;
From this string table, you can then get the names of sections based on their offset :
char* str = strtab + offset;

How to initialize void* data struct member with another struct member in C99?

let's assume that we have below struct definitions:
typedef struct {
uint8_t a ;
} deepest_t ;
typedef struct {
deepest_t* deepest_ptr ;
} deeper_t ;
typedef struct {
deeper_t* deeper_ptr ;
} deep_t ;
typedef struct {
void* data ;
} data_container_t ;
and following initializations:
deepest_t deepest = {
.a = 5,
} ;
deeper_t deeper = {
.deepest_ptr = &deepest,
} ;
deep_t deep = {
.deeper_ptr = &deeper,
} ;
and now question, could you please tell me how to initialize void* data by usage of the designated initializer in order to void* data will point the deepest_t deepest. I've tried such a solution, but compiler is screaming that it is not a const value :
data_container_t data_container = {
.data = &(((deeper_t*) deep.deeper_ptr)->deepest_ptr),
} ;
In here I believe you are keeping the address of deepest_ptr ..
data_container_t data_container = {
.data = &(((deeper_t*) deep.deeper_ptr)->deepest_ptr),
} ;
So to retrieve it, you can do this ..
deepest_t * d = *((deepest_t**)(data_container.data));
printf(" %ud \n", (*d).a);
Since you can't use void* until you cast it ..
Here's a live execution
If the initializer is used to initialize a variable of static storage duration, it should be a constant expression, and therefore you cannot do that.
If it is used to initialize a local non-static variable you are fine with this initializer:
data_container_t data_container = {
.data = (deep.deeper_ptr)->deepest_ptr,
};
That assuming you want what you say in your text ("point the deepest_t deepest").
What a constant expression is you can read it here:
Details of what constitutes a constant expression in C?

IAR Relocation failed error

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.

Resources