How to get the location of a section in C code - c

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.

Related

How to initialize structure in flash at compile time?

I'm working on an embedded C project and would like to initialize, at compile-time, a structure that is stored in flash (0x1200u), but I keep getting weird compile errors.
typedef struct {
float foo[2];
...other stuff...
} MY_STRUCT_DATA_TYPE
#define MY_FLASH_STRUCT ((MY_STRUCT_DATA_TYPE *)(0x1200u)) // <-- error here
MY_FLASH_STRUCT MY_InitdStruct = {
.foo[0] = 0.12345f;
.foo[1] = 0.54321f;
...other stuff...
};
The error I'm getting is "expected '{' before '(' token." Anyone know how to make this work?
Update
Added to linker file...
MEMORY
{
... other stuff ...
m_my_data_section (RW) : ORIGIN = 0x00001200, LENGTH = 0x00000400
... other stuff ...
}
SECTIONS
{
... other stuff ..
.my_data_section :
{
. = ALIGN(4);
KEEP(*(.my_data_section))
. = ALIGN(4);
} > m_my_data_section
... other stuff ...
}
C code...
static volatile const MY_STRUCT_DATA_TYPE __attribute__ ((section (".my_data_section"))) MY_InitdStruct = {
.foo[0] = 0.12345f;
.foo[1] = 0.54321f;
...other stuff...
};
I'm not sure the static or const keywords are necessary, since it's intended only for one-time use to initialize that section of flash memory at compile-time, but it doesn't hurt to restrict the label's usage.
That makes no sense at all, syntactically that is.
What you need to do is figure out how your compiler supports this, since it's not something you can do with just standard C.
With GCC, you use __attribute() to put the symbol in a particular segment, then use the linker script to put that segment in a particular piece of actual memory.
Or, just give your compiler the benefit of the doubt and try a static const structure, that should end up in flash.
In the example you gave, a ";" is missing after the declaration of MY_STRUCT_DATA_TYPE
typedef struct {
float foo[2];
...other stuff...
} MY_STRUCT_DATA_TYPE;
If it's not a copie/paste mistake, it's the kind of error which could lead to the type of error message you have
I'm working on an embedded C project and would like to initialize, at
compile-time, a structure that is stored in flash (0x1200u), but I
keep getting weird compile errors.
That's unsurprising, as C does not support what you're trying to do. You can provide initializers for objects that C allocates, including pointers, but the C language has no concept of objects that exist independently. Indeed, C makes no guarantees whatever about what happens when you do anything with (MY_STRUCT_DATA_TYPE *)(0x1200u) other than convert it back to an integer.
The error I'm getting is "expected '{' before '(' token."
The compiler is complaining because in
MY_FLASH_STRUCT MY_InitdStruct = {
, the expansion of MY_FLASH_STRUCT is not a type, therefore the construct is not a valid declaration. Nor is it a valid assignment, but even if it were, assignment statements are executable, and therefore may appear only inside functions.
Assigning an object to a specific address would be a function of the linker. Whether you can assign an object to the particular address you want is system-dependent, and the mechanism, if any, for doing so depends on your toolchain.

Arm scatter file issue

So I'm relatively new with arm and I'm having problems with scatter files. This next file is what I have in the project I entered:
ROOT 0x00020200 0x000DFDFC
{
ITCM 0x00020200
{
ssw01fiq.o (Startup, +First)
startup.o (+RO)
ssw01irq.o (+RO)
}
EXEC_REST +0
{
* (+RO)
}
DTCM 0x00400000 {startup.o (StartOfRAM, +First)}
SCT +0x348
{
ibmp_slot.o* (+ZI);
}
INIT_CALL +0
{
* (INIT)
}
SRAM +0
{
* (+RW, +ZI)
startup.o* (DummyStack, +Last)
}
JUSTAFTERRAM 0x00410000
{
startup.o* (JustAfterRAM)
}
JUSTAFTERROM 0x00100000
{
startup.o* (JustAfterROM)
}
}
So, what I would like to do is add a new execution region called INIT_CALL and then, on the source code, I will define pointers to init functions and place them at the INIT section (in a simple way this is what is done on the linux kernel...).
For that I use a macro like this:
typedef int (*_init_fn) (void);
#define component_init(__fn) static _init_fn fn __attribute__((section ("INIT"))) = __fn
And in one .c file im using it to initialize some init funtion.
component_init(productUiInitialize);
void dump_fn()
{
printf("Here we have, fn=0x%08X, addr=0x%08X\n", fn, &fn);
}
On the other .c file i do this:
extern int productUiInitialize(void);
_init_fn *test = (_init_fn *)0x00400F78;
void do_init_calls( void )
{
dump_fn();
printf("FUNC=0x%08X, INITCALL=0x%08X, ADDR=0x%08X\n",productUiInitialize, *test, test);
}
So, the outcome is really strange, I see that my pointers are not being well initialized, they have NULL value. I then noticed, if I use const in my define the pointer in the dump_fn function will be ok, so the addr is 0x00400F78 and value is the addr of productUiInitialize. But on the other c file, the value of test is naturally 0x00400F78, but when I dereference it I have NULL (I was expecting to have productUiInitialize).
Am I doing anything wrong at the scatter file?? Some inputs would be really appreciated...
UPDATE: So i recently had some more time to look into this. What i found is that, if i set my INIT section inside SRAM everything works as expected. The problem is, in this case i don't know how to force the init address and the size of my SECTION. Moreover i checked that if i initialized a variable like this in test.c :
_init_fn *fn attribute((section ("INIT"))) = (init *)0x00400F78;
The variable is not correctly initialized. When i print it's value is something else completely different of 0x00400F78. So it seems that if my section is outside the SRAM execution region (where RW and ZI section are) things don't work as i expected. So i have basically two questions, Does anyone knows why of this behavior? Also, is there any possibility of forcing an init address for my section INIT, if i place it inside SRAM execution region?
Thanks in advance!

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;

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.

get function address from name [.debug_info ??]

I was trying to write a small debug utility and for this I need to get the function/global variable address given its name. This is built-in debug utility, which means that the debug utility will run from within the code to be debugged or in plain words I cannot parse the executable file.
Now is there a well-known way to do that ? The plan I have is to make the .debug_* sections to to be loaded into to memory [which I plan to do by a cheap trick like this in ld script]
.data {
*(.data)
__sym_start = .;
(debug_);
__sym_end = .;
}
Now I have to parse the section to get the information I need, but I am not sure this is doable or is there issues with this - this is all just theory. But it also seems like too much of work :-) is there a simple way. Or if someone can tell upfront why my scheme will not work, it ill also be helpful.
Thanks in Advance,
Alex.
If you are running under a system with dlopen(3) and dlsym(3) (like Linux) you should be able to:
char thing_string[] = "thing_you_want_to_look_up";
void * handle = dlopen(NULL, RTLD_LAZY | RTLD_NOLOAD);
// you could do RTLD_NOW as well. shouldn't matter
if (!handle) {
fprintf(stderr, "Dynamic linking on main module : %s\n", dlerror() );
exit(1);
}
void * addr = dlsym(handle, thing_string);
fprintf(stderr, "%s is at %p\n", thing_string, addr);
I don't know the best way to do this for other systems, and this probably won't work for static variables and functions. C++ symbol names will be mangled, if you are interested in working with them.
To expand this to work for shared libraries you could probably get the names of the currently loaded libraries from /proc/self/maps and then pass the library file names into dlopen, though this could fail if the library has been renamed or deleted.
There are probably several other much better ways to go about this.
edit without using dlopen
/* name_addr.h */
struct name_addr {
const char * sym_name;
const void * sym_addr;
};
typedef struct name_addr name_addr_t;
void * sym_lookup(cost char * name);
extern const name_addr_t name_addr_table;
extern const unsigned name_addr_table_size;
/* name_addr_table.c */
#include "name_addr.h"
#define PREMEMBER( X ) extern const void * X
#define REMEMBER( X ) { .sym_name = #X , .sym_addr = (void *) X }
PREMEMBER(strcmp);
PREMEMBER(printf);
PREMEMBER(main);
PREMEMBER(memcmp);
PREMEMBER(bsearch);
PREMEMBER(sym_lookup);
/* ... */
const name_addr_t name_addr_table[] =
{
/* You could do a #include here that included the list, which would allow you
* to have an empty list by default without regenerating the entire file, as
* long as your compiler only warns about missing include targets.
*/
REMEMBER(strcmp),
REMEMBER(printf),
REMEMBER(main),
REMEMBER(memcmp),
REMEMBER(bsearch),
REMEMBER(sym_lookup);
/* ... */
};
const unsigned name_addr_table_size = sizeof(name_addr_table)/sizeof(name_addr_t);
/* name_addr_code.c */
#include "name_addr.h"
#include <string.h>
void * sym_lookup(cost char * name) {
unsigned to_go = name_addr_table_size;
const name_addr_t *na = name_addr_table;
while(to_to) {
if ( !strcmp(name, na->sym_name) ) {
return na->sym_addr;
}
na++;
to_do--;
}
/* set errno here if you are using errno */
return NULL; /* Or some other illegal value */
}
If you do it this way the linker will take care of filling in the addresses for you after everything has been laid out. If you include header files for all of the symbols that you are listing in your table then you will not get warnings when you compile the table file, but it will be much easier just to have them all be extern void * and let the compiler warn you about all of them (which it probably will, but not necessarily).
You will also probably want to sort your symbols by name such that you can use a binary search of the list rather than iterate through it.
You should note that if you have members in the table which are not otherwise referenced by the program (like if you had an entry for sqrt in the table, but didn't call it) the linker will then want (need) to link those functions into your image. This can make it blow up.
Also, if you were taking advantage of global optimizations having this table will likely make those less effective since the compiler will think that all of the functions listed could be accessed via pointer from this list and that it cannot see all of the call points.
Putting static functions in this list is not straight forward. You could do this by changing the table to dynamic and doing it at run time from a function in each module, or possibly by generating a new section in your object file that the table lives in. If you are using gcc:
#define SECTION_REMEMBER(X) \
static const name_addr_t _name_addr##X = \
{.sym_name= #X , .sym_addr = (void *) X } \
__attribute__(section("sym_lookup_table" ) )
And tack a list of these onto the end of each .c file with all of the symbols that you want to remember from that file. This will require linker work so that the linker will know what to do with these members, but then you can iterate over the list by looking at the begin and end of the section that it resides in (I don't know exactly how to do this, but I know it can be done and isn't TOO difficult). This will make having a sorted list more difficult, though. Also, I'm not entirely certain initializing the .sym_name to a string literal's address would not result in cramming the string into this section, but I don't think it would. If it did then this would break things.
You can still use objdump to get a list of the symbols that the object file (probably elf) contains, and then filter this for the symbols you are interested in, and then regenerate the table file the table's members listed.

Resources