I am trying to place a variable named secret_key at location 0x08002000
in STM32Nucleo-board which has STM32L476RG on board with 1MB flash.
Question 1: Why am i unable to place code in custom ROM (SECRET_IROM1
)section?
Question 2: What is the mistake i am doing?
I am still newbie to Linker topic.
I am able to do it(still do not undestnad, why other RO section also follows my new address of secret_key variable) if i define the address which is in the default section for RO
in the scatter file. If i create a new section, mapping is not happening. I can see the address assigned as expected but the value of the secret_key is not visible at that location.
below image shows what happens when i declare the address out of range from the default section.
Code section where variable is declared:
unsigned long long int array4[6]={0};
unsigned long long int array[6]={12};
unsigned long long int arra2[4] = {0x1111111111111111,0x2222222222222222,0x3333333333333333,0x4444444444444444};
const long secret_key[3] __attribute__((section(".ARM.__at_0x8001800"))) = {0xABABABAB,0xCDCDCDCD, 0xEFEFEFEF};
extern int addsum(int, int);
int main()
{
long long int array3[100] = {1,2,3,4,5,6,7};
array[1] = arra2[1] - array[0]+array3[1]*2+array3[2]*2+addsum(array[1],array[2])+array4[2]+(int)secret_key[0];
while(1);
}
Scatter file contents below:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000 { ; load region size_region
ER_IROM1 0x08000000 0x00002000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
SECRET_IROM1 0x08002000 0x00000030 { ; load address = execution address
*(.ARM.__at_0x8001800) ; secret key
}
RW_IRAM1 0x20000000 0x00000100 { ; RW data
project2.o (+RW)
}
RW_IRAM2 0x20000100 0x00000100 { ; RW data
project2.o (+ZI)
}
RW_IRAM3 0x20000200 0x00000300 { ; RW data
project.o (+ZI)
}
RW_IRAM4 0x20000500 0x00000200 { ; RW data
project.o (+RW)
}
RW_IRAM5 0x20000700 0x00001000 { ; RW data
.ANY (+RW,+ZI)
}
}
Second case: where it doesn't work
Code here:
unsigned long long int array4[6]={0};
unsigned long long int array[6]={12};
unsigned long long int arra2[4] = {0x1111111111111111,0x2222222222222222,0x3333333333333333,0x4444444444444444};
const long secret_key[3] __attribute__((section(".ARM.__at_0x8002100"))) = {0xABABABAB,0xCDCDCDCD, 0xEFEFEFEF};
extern int addsum(int, int);
int main()
{
long long int array3[100] = {1,2,3,4,5,6,7};
array[1] = arra2[1] - array[0]+array3[1]*2+array3[2]*2+addsum(array[1],array[2])+array4[2]+(int)secret_key[0];
while(1);
}
associated scatter file here:
; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00100000 { ; load region size_region
ER_IROM1 0x08000000 0x00001800 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
SECRET_IROM1 0x08002100 0x00000030 { ; load address = execution address
*(.ARM.__at_0x8002100) ; secret key
}
RW_IRAM1 0x20000000 0x00000100 { ; RW data
project2.o (+RW)
}
RW_IRAM2 0x20000100 0x00000100 { ; RW data
project2.o (+ZI)
}
RW_IRAM3 0x20000200 0x00000300 { ; RW data
project.o (+ZI)
}
RW_IRAM4 0x20000500 0x00000200 { ; RW data
project.o (+RW)
}
RW_IRAM5 0x20000700 0x00001000 { ; RW data
.ANY (+RW,+ZI)
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Results of suggestion fron Jeroen3
I am expecting the values loaded into the variable secret_key to be visible in the flash memory region, but it is not.
Best Answer
secretkey.c:
__attribute__((used))
to prevent it from being removed if it isn't used anywhere.secretkey.h:
scatterfile.sct:
Make a region and a C file, then add the RO (read only) part of that C file to the region. Nothing else.
You now have two load regions (
lr_
), these blocks of memory (regions) are programmed into flash by the programmer.LR_IROM1
andLR_SECRET_IROM1
.Inside the load regions are execution regions. This is where the code references the objects from.
ER_IROM1
,RW_IRAM1
andSECRET_IROM1
.Most often the addresses of the load and execution region are identical.
But you can have a load region for flash, and an execution region for sram.
For example with pre-initialized variables. This means the linker then must insert the scatter loading algorithm. This copies the data from the flash location where the data is programmed in flash, to the intended usable location in sram. (i.e. where the code thinks the variables are)
This algorithm is called from the startup.s file, and it makes the jump to
int main(void)
, for Keil this algorithm is started by calling__main
instartup.s
.But when the execution region already equals the load region, no copying is required. Such as with the actual code, and your now with constant.
In my earlier version (and the part in your question), the constant was put inside an execution region, meaning it was programmed using
.ANY (+RO)
and then copied to the intended location. Except the code can't write to flash, thus nothing would be changed there.See also, ARM® Compiler armlink User Guide: 8.2 Syntax of a scatter file
I'd also recommend looking at the memory
.map
file the linker outputs. You can use it to verify how your image is put together. I made a small tool for this.The tickbox is in
target settings -> listing -> linker listing
.Your RAM regions are a bit strange. I do not think there is an advantage in using multiple 256 sized regions.
Instead, you could use all SRAM regions:
- 96 kByte at 0x20000000
- 32 kByte at 0x10000000