Decentralized loading actually dictates how a Microcontroller (or machine) prepares the operating environment before and after the official power-on execution, which refers primarily to how variable addresses are allocated.
It may be inappropriate to say how variable addresses are allocated, but I really can't find a noun to describe this scenario: Relocate variables from flash or rom to ram space.
"Relocation" is referred as the following considerations:
The following describes this "relocating process" in as much detail as possible.
#### a. First, generate a .S file, which is disassembly
**The following are examples of KEIL! **
-Use the fromelf.exe tool that comes with KEIL (this tool is located in the KEIL installation directory, for example: `D:\MDK-ARM V5.25\Keil_v5\ARM\ARM\ARMCC\bin` and `D:\MDK- ARM V5.25\Keil_v5\ARM\ARM\ARMCLANG\bin`, these two are tools under two different compilation chains. For Cortex-M, there is no difference between the two. For details, you can Baidu: "** The difference between armcc and armclang. **”).
-Then compile and link in KEIL IDE to generate an .axf file.
-Use the command: **fromelf -c !L --output @LS** to generate the .S file (note that when generating the .axf file, check the debugging information, so that the generated .S file is easier to read. The method is shown below). About why you want to check Debug Infomation, you can learn the format content of the following axf file, and about the usage and format of fromelf file, you can go to Baidu.
**If you follow my procedure exactly, you will get a .S file with the same name as the .axf file. **
We are using KEIL for example
D:\MDK-ARM V5.25\Keil_v5\ARM\ARM\ARMCC\bin
and D:\MDK- ARM V5.25\Keil_v5\ARM\ARM\ARMCLANG\bin
, these two are tools under two different compilation chains. For Cortex-M, there is no difference between the two.If you follow my procedure exactly, you will get a .S file with the same name as the .axf file.
For the power-on process under bare metal, I will not set the program separately for bare metal. Here is just a brief description of the process:
__main()
function will be executed (this is not the main()
function we saw, this is a built-in function of the compiler, used to call some initialization operation functions, and then call our main Function, return the right to use).__main()
function, there are generally two functions: __scatterload()
and __rt_entry()
, one for scatter loading and one for system library initialization (such as __rt_lib_init()
, The dynamic loading process is implemented in this function).main()
function is called by __rt_entry()
to jump to c language.$Sub$$main
and $Super$$main
, these two are used to call some operations before the main()
function.!!!main
__main
0x000000c0: f000f802 .... BL __scatterload ; 0xc8
0x000000c4: f000f883 .... BL __rt_entry ; 0x1ce
!!!scatter
__scatterload
__scatterload_rt2
__scatterload_rt2_thumb_only
0x000000c8: a00a .. ADR r0,{pc}+0x2c ; 0xf4
0x000000ca: e8900c00 .... LDM r0,{r10,r11}
0x000000ce: 4482 .D ADD r10,r10,r0
0x000000d0: 4483 .D ADD r11,r11,r0
0x000000d2: f1aa0701 .... SUB r7,r10,#1
__scatterload_null
0x000000d6: 45da .E CMP r10,r11
0x000000d8: d101 .. BNE 0xde ; __scatterload_null + 8
0x000000da: f000f878 ..x. BL __rt_entry ; 0x1ce
0x000000de: f2af0e09 .... ADR lr,{pc}-7 ; 0xd7
0x000000e2: e8ba000f .... LDM r10!,{r0-r3}
0x000000e6: f0130f01 .... TST r3,#1
0x000000ea: bf18 .. IT NE
0x000000ec: 1afb .. SUBNE r3,r7,r3
0x000000ee: f0430301 C... ORR r3,r3,#1
0x000000f2: 4718 .G BX r3
$d
0x000000f4: 00037f6c l... DCD 229228
0x000000f8: 00037f8c .... DCD 229260
;;中间的代码省略...
Region$$Table$$Base
0x00038060: 00000055 U... DCD 85
0x00038064: 00000002 .... DCD 2
0x00038068: 00001b38 8... DCD 6968
0x0003806c: 00037f63 c... DCD 229219
0x00038070: 00000819 .... DCD 2073
0x00038074: 00001b3a :... DCD 6970
0x00038078: 0000f5d0 .... DCD 62928
0x0003807c: 00037eeb .~.. DCD 229099
The above code is directly from the process of __main()
jumps to the __main()
function, first execute the __scatterload()
function, here is the process of scatter loading.
The following is the analysis:
__main()
function (actually in the assembly world, this is a label. There is not much difference between a function and a variable. It is nothing more than some binary data with special meaning in the address space).0x000000c0: f000f802 .... BL __scatterload; 0xc8
, you only need to see BL 0xc8
, the other information is all mixed information (I said that the generated .axf needs to be With debugging information, you will see the words BL __scatterload; 0xc8
here, __scatterload()
is actually extracted from the symbol table in the .axf file).__scatterload()
function (the code below is exactly the same as the one in the previous section).!!!main
__main
0x000000c0: f000f802 .... BL __scatterload ; 0xc8
0x000000c4: f000f883 .... BL __rt_entry ; 0x1ce
!!!scatter
__scatterload
__scatterload_rt2
__scatterload_rt2_thumb_only
0x000000c8: a00a .. ADR r0,{pc}+0x2c ; 0xf4
0x000000ca: e8900c00 .... LDM r0,{r10,r11}
0x000000ce: 4482 .D ADD r10,r10,r0
0x000000d0: 4483 .D ADD r11,r11,r0
0x000000d2: f1aa0701 .... SUB r7,r10,#1
__scatterload_null
0x000000d6: 45da .E CMP r10,r11
0x000000d8: d101 .. BNE 0xde ; __scatterload_null + 8
0x000000da: f000f878 ..x. BL __rt_entry ; 0x1ce
0x000000de: f2af0e09 .... ADR lr,{pc}-7 ; 0xd7
0x000000e2: e8ba000f .... LDM r10!,{r0-r3}
0x000000e6: f0130f01 .... TST r3,#1
0x000000ea: bf18 .. IT NE
0x000000ec: 1afb .. SUBNE r3,r7,r3
0x000000ee: f0430301 C... ORR r3,r3,#1
0x000000f2: 4718 .G BX r3
$d
0x000000f4: 00037f6c l... DCD 229228
0x000000f8: 00037f8c .... DCD 229260
;;中间的代码省略...
Region$$Table$$Base
0x00038060: 00000055 U... DCD 85
0x00038064: 00000002 .... DCD 2
0x00038068: 00001b38 8... DCD 6968
0x0003806c: 00037f63 c... DCD 229219
0x00038070: 00000819 .... DCD 2073
0x00038074: 00001b3a :... DCD 6970
0x00038078: 0000f5d0 .... DCD 62928
0x0003807c: 00037eeb .~.. DCD 229099
It is very clear to see the code from 0x000000c8
to 0x000000d2
, which actually obtains the start address of the data block Region$$Table$$Base
(r10 is the start address, r11 is the end address + 1, r7 is the starting address -1. It just uses the relocation technology to know the address of Region$$Table$$Base
when linking, and then come back to modify the value at $d
, so this code uses relative Address offset, in short, is the 0 filled in $d
when compiling, and the real value is only known when linking).
Then execute sequentially to __scatterload_null()
, __scatterload_nul()
l is essentially a loop, as if it is executed using the data in Region$$Table$$Base
, in order to facilitate understanding, I wrote a similar function in C code:
Check out the next article.