Access symbols defined in the linker script by application

元气小坏坏 提交于 2020-07-04 06:39:21

问题


In my linker script file, I have defined two symbols

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 

and then I have exported them as well as shown below

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;

From the applciation code, I try to access these symbols

extern const unsigned int _region_RAM_start__;
extern const unsigned int _region_RAM_end__;
....
int GetRAMSize()
{
    int size = 0;
    unsigned int address_1 = _region_RAM_start__;
    unsigned int address_2 = _region_RAM_end__;
    size = address_2 - address_1 + 1U;
    return size;
}

Now, I expected the return value to be 0x00100000, however, all I get is 0. So, when I turned to the debugger, I noticed that _region_RAM_start__ and _region_RAM_end__ have the values 0xC0000000 and 0xC00fffff respectively, but address_1 and address_2 have the value 0.

The compiler optimization is set to "None". This has been bugging me for a while now. Is there something very obvious I am missing here (other than I should not be doing this in the first place)?

Solution Thanks to n.m. for the answer

  unsigned int address_1 = (unsigned int) (&_region_RAM_start__);

Otherwise address_1 and address_2 both contain garbage values (i.e. values available at the address 0xC0000000 and 0xC00fffff respectivly, but garbage from the point of view of this code)


回答1:


That's a bit old but i will answer it anyways…

From the ld manual:

Accessing a linker script defined variable from source code is not intuitive. In particular a linker script symbol is not equivalent to a variable declaration in a high level language, it is instead a symbol that does not have a value.

Before going further, it is important to note that compilers often transform names in the source code into different names when they are stored in the symbol table. For example, Fortran compilers commonly prepend or append an underscore, and C++ performs extensive name mangling. Therefore there might be a discrepancy between the name of a variable as it is used in source code and the name of the same variable as it is defined in a linker script. For example in C a linker script variable might be referred to as:

extern int foo;

But in the linker script it might be defined as:

_foo = 1000;

In the remaining examples however it is assumed that no name transformation has taken place.

When a symbol is declared in a high level language such as C, two things happen. The first is that the compiler reserves enough space in the program's memory to hold the value of the symbol. The second is that the compiler creates an entry in the program's symbol table which holds the symbol's address. ie the symbol table contains the address of the block of memory holding the symbol's value. So for example the following C declaration, at file scope:

int foo = 1000;

creates a entry called "foo" in the symbol table. This entry holds the address of an int sized block of memory where the number 1000 is initially stored.

When a program references a symbol the compiler generates code that first accesses the symbol table to find the address of the symbol's memory block and then code to read the value from that memory block. So:

foo = 1;

looks up the symbol foo in the symbol table, gets the address associated with this symbol and then writes the value 1 into that address. Whereas:

int * a = & foo;

looks up the symbol foo in the symbol table, gets it address and then copies this address into the block of memory associated with the variable "a".

Linker scripts symbol declarations, by contrast, create an entry in the symbol table but do not assign any memory to them. Thus they are an address without a value. So for example the linker script definition:

foo = 1000;

creates an entry in the symbol table called @samp{foo} which holds the address of memory location 1000, but nothing special is stored at address 1000. This means that you cannot access the value of a linker script defined symbol - it has no value - all you can do is use the address of a linker script defined symbol.

Hence when you are using a linker script defined symbol in source code you should always take the address of the symbol, and never attempt to use its value. For example suppose you want to copy the contents of a section of memory called .ROM into a section called .FLASH and the linker script contains these declarations:

start_of_ROM   = .ROM;
end_of_ROM     = .ROM + sizeof (.ROM);
start_of_FLASH = .FLASH;

Then the C source code to perform the copy would be:

extern char start_of_ROM, end_of_ROM, start_of_FLASH;

memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);

Note the use of the "&" operators. They are correct.




回答2:


Since they are generic address symbols you are trying to access and not necessarily pointers to a specific type, you don't want to declare them unsigned int, rather declare them as

extern void _region_RAM_START;

then &_region_RAM_START will have the appropriate type 'void *'.




回答3:


Below code should works as expected:

extern const volatile unsigned int _region_RAM_start__;

extern const volatile unsigned int _region_RAM_end__;

....
int GetRAMSize()

{

int size = 0;

unsigned int address_1 = &_region_RAM_start__;

unsigned int address_2 = &_region_RAM_end__;

size = address_2 - address_1 + 1U;

return size;

}


来源:https://stackoverflow.com/questions/8398755/access-symbols-defined-in-the-linker-script-by-application

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!