I want to place a constant at absolute address, but linker issue:
[Error li1173] Failed to extract symbol '_Firmware_Crc' needed for absolute placement.
Symbol is embedded in object (.epcrodata, .epcrodata.end).
.
My source file ver.c looks as:
const unsigned short Firmware_Crc = 0xffff;
My .ldf file contains:
PROCESSOR p0
{
...
RESOLVE(_Firmware_Crc, CRC_ADDR)
KEEP(_start, _main, ___inits, _Firmware_Crc)
SECTIONS
{
...
ASYNC0_constdata
{
INPUT_SECTION_ALIGN(4)
INPUT_SECTIONS($OBJECTS{requiredForROMBoot}(constdata) $LIBRARIES{requiredForROMBoot}(constdata))
INPUT_SECTIONS($OBJECTS(constdata) $LIBRARIES(constdata))
INPUT_SECTION_ALIGN(2)
INPUT_SECTIONS_PIN_EXCLUSIVE(ver.doj(constdata))
} > MEM_ASYNC0
...
CRC_ADDR is equal to 0x2000FFFE (last two bytes of 64Kb, because my firmware has size less then 64Kb)
What do I wrong? And what a misterious object .epcrodata?
P.S. I examined assembler file ver.s produced by compilator. This is a piece of it:
.section/DOUBLE32 constdata;
.align 4;
.epcrodata:
.type .epcrodata,STT_OBJECT;
_Firmware_Crc:
.global _Firmware_Crc;
.type _Firmware_Crc,STT_OBJECT;
.byte =
0xFF,0xFF;
.epcrodata.end:
So my constant is placed inside of .epcrodata. But what I should do to fix this problem?
I have made many attempts varying file and compiling and linking my project. At end I changed my file to: typedef struct FIRMWARE_CRC_S { char reserve[16]; }FIRMWARE_CRC_T; const FIRMWARE_CRC_T Firmware_Crc = { "1234" }; And the problem has gone. I tried with other sizes of array less then 16 and the error rised in all cases. When array size >=16 error not appear. Why this happens?
Hi,
when you receive the li1170 error, the linker_log.xml file will contain detailed analysis of the problem. It may be that there is a missing .end label for a section in your assembly file, for example. Can you please take a look at the linker_log.xml file produced when the error is generated, and post the output here.
thanks,
Craig.
Thank you for answer on my post.
As I wrote yesterday, my source file is writen on C. So it is the compiler that inserts assembler labels in asm file when compiling.
File ver.c:
typedef struct FIRMWARE_CRC_S
{
unsigned short crc16;
}FIRMWARE_CRC_T;
typedef struct FIRMWARE_INFO_S
{
char ver;
char bank_;
char name[3];
char reserve[11];
} FIRMWARE_INFO_T;
const FIRMWARE_CRC_T Firmware_Crc =
{
0xffff
};
const LOAD_FIRMWARE_INFO_T Firmware_Info =
{
PRJ_MAIN_VER*16 + PRJ_SUB_VER,
FIRMWARE - 1,
"AS",
"1234567890"
};
As you can see there is also an object Firmware_Info. It has size 16 bytes and not rize this linker error.
I have attached asm file produced by compiler and linker_log.xml file to this post.
P.S.
CraiG, you are right that there is a missing .end label:
.section/DOUBLE32 constdata;
.align 4;
.epcrodata:
.type .epcrodata,STT_OBJECT;
_Firmware_Crc:
.global _Firmware_Crc;
.type _Firmware_Crc,STT_OBJECT;
.byte =
0xFF,0xFF;
.epcrodata.end:
(it is a piece of file ver.s produced by compiler, attached to my previous post)
but why compiler do so?
By default the compiler gathers small bits of data into a single larger section that it addresses from a base symbol. This is because it take two instructions to load an address on Blackfin so there's a performance advantage to be achieved by being able to address lots of variables from a single pointer rather than having to re-load a pointer for each. That's what's happing here. The variable is less than 12 bytes in size (the threshold size used in the compiler above which symbols are created in their own area) so it gets placed within ".epcrodata" and ".epc_rodata.end" and accesses to it and any other similar const data will be addressed from ".epcrodata".
To disable this default behaviour and make the compiler place your variable in it's own area so that the linker can resolve it add #pragma symbolic_ref before the definition in C.
We'll add some additional information to the help information for li1173 to suggest this as the cause.
Regarrds,
Stuart.
Thank you very much. You answer helped me. And I have found that this pragma is described in compiler's manual.