先说说RealViewMDK build project的连接选项,点击小魔棒,切到Linker,可知armlink的选项:
-device DARMSTM *.o --strict --scatter "TEST.sct" --autoat --summary_stderr --info summarysizes --map --xref --callgraph --symbols --info sizes --info totals --info unused --info veneers --list ".\TEST.map" -o "TEST.axf"
--map --xref --callgraph --symbols会生成object文件的信息到--list ".\TEST.map中。TEST.axf是生成的ELF文件。对它执行
fromelf -c TEST.axf > disasm.txt
进行反汇编并保存结果到disasm.txt。至此。我们得到TEST.map和disasm.txt,再加上STM32F10x.s TEST.sct,开始我的分析。
scatter文件包含以下几行:
LR_IROM1 0x08000000 0x00020000 { ; load region size_region
ER_IROM1 0x08000000 0x00020000 { ; load address = execution address
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM1 0x20000000 0x00005000 { ; RW data
.ANY (+RW +ZI)
}
}
TEST.axf的image结构也截出来
Memory Map of the image
Image Entry point : 0x080000ed
Load Region LR_IROM1 (Base: 0x08000000, Size: 0x00000dac, Max: 0x00020000, ABSOLUTE)
Execution Region ER_IROM1 (Base: 0x08000000, Size: 0x00000d9c, Max: 0x00020000, ABSOLUTE)
Base Addr Size Type Attr Idx E Section Name Object
0x08000000 0x000000ec Data RO 3 RESET stm32f10x.o
0x080000ec 0x00000000 Code RO 136 * .ARM.Collect$$$$00000000 entry.o(mc_w.l)
0x080000ec 0x00000004 Code RO 412 .ARM.Collect$$$$00000001 entry2.o(mc_w.l)
0x080000f0 0x00000004 Code RO 415 .ARM.Collect$$$$00000004 entry5.o(mc_w.l)
0x080000f4 0x00000008 Code RO 416 .ARM.Collect$$$$00000007 entry7.o(mc_w.l)
0x080000fc 0x00000004 Code RO 413 .ARM.Collect$$$$00002712 entry2.o(mc_w.l)
可见程序上电后,从RESET这个section开始执行。它在STM32F10x.s中,
AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
主要定义了一个Vectors table,最开始部分初始化主堆栈指针MSP,
Stack_Size EQU 0x00000200
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
之后执行Reset_Handler,
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
LDR R0, =__main
BX R0
ENDP
可见是跳转到__main,通过TEST.map中的symbols信息,很容易找到其位置
Image Symbol Table
Local Symbols
Symbol Name Value Ov Type Size Object(Section)
...
Global Symbols
Symbol Name Value Ov Type Size Object(Section)...
__main 0x080000ed Thumb Code 0 entry.o(.ARM.Collect$$$$00000000)
再结合Memory Map of the image的信息,一切都对的上了。不多说,单刀直入,由disasm.txt中的汇编看流程:
.ARM.Collect$$$$00000000
.ARM.Collect$$$$00000001
__main
_main_stk
0x080000ec: f8dfd00c .... LDR sp,__lit__00000000 ; [0x80000fc] =
.ARM.Collect$$$$00000004
_main_scatterload
0x080000f0: f000fd36 ..6. BL __scatterload ; 0x8000b60
__lit__00000000
0x080000fc: 20000310 ... DCD 536871696
接着跳转到__scatterload,
__scatterload
__scatterload_rt2
0x08000b60: 4c06 .L LDR r4,[pc,#24] ; [0x8000b7c] = 0x8000d7c
0x08000b62: 4d07 .M LDR r5,[pc,#28] ; [0x8000b80] = 0x8000d9c
0x08000b64: e006 .. B 0x8000b74 ; __scatterload + 20
0x08000b66: 68e0 .h LDR r0,[r4,#0xc]
0x08000b68: f0400301 @... ORR r3,r0,#1
0x08000b6c: e8940007 .... LDM r4,{r0-r2}
0x08000b70: 4798 .G BLX r3
0x08000b72: 3410 .4 ADDS r4,r4,#0x10
0x08000b74: 42ac .B CMP r4,r5
0x08000b76: d3f6 .. BCC 0x8000b66 ; __scatterload + 6
0x08000b78: f7fffabc .... BL __main_after_scatterload ; 0x80000f4
0x08000b7c: 08000d7c |... DCD 134221180
0x08000b80: 08000d9c .... DCD 134221212
Region$$Table$$Base
0x08000d7c: 08000d9c .... DCD 134221212
0x08000d80: 20000000 ... DCD 536870912
0x08000d84: 00000010 .... DCD 16
0x08000d88: 08000ba4 .... DCD 134220708
0x08000d8c: 08000dac .... DCD 134221228
0x08000d90: 20000010 ... DCD 536870928
0x08000d94: 00000300 .... DCD 768
0x08000d98: 08000bb4 .... DCD 134220724
Region$$Table$$Limit
分析:
1. 加载[0x8000b7c] = 0x8000d7c到r4
2. 加载[0x8000b80] = 0x8000d9c到r5
3. 跳转到0x8000b74
4. 比较r4和r5,运算r4-r5
5. 若借位(carry clear),跳转到0x8000b66。否则继续往下执行
6. 0x08000b66处,加载RW输出域的地址到r0=08000ba4
7. 设置r0的最低bit,将结果保存到r3
8. 加载[0x08000d7c]3个32bits数据到r0-r2,作为参数传递给子程序
9. 跳转到r3
10.接下来,
i.__scatterload_copy
__scatterload_copy
0x08000ba4: e002 .. B 0x8000bac ; __scatterload_copy + 8
0x08000ba6: c808 .. LDM r0!,{r3}
0x08000ba8: 1f12 .. SUBS r2,r2,#4
0x08000baa: c108 .. STM r1!,{r3}
0x08000bac: 2a00 .* CMP r2,#0
0x08000bae: d1fa .. BNE 0x8000ba6 ; __scatterload_copy + 2
0x08000bb0: 4770 pG BX lr
实现的是拷贝r0指向的域到r1指向的域,共r2个字。此处RW共16个字。
11. 接下来又是一个循环针对,
i.__scatterload_zeroinit
__scatterload_zeroinit
0x08000bb4: 2000 . MOVS r0,#0
0x08000bb6: e001 .. B 0x8000bbc ; __scatterload_zeroinit + 8
0x08000bb8: c101 .. STM r1!,{r0}
0x08000bba: 1f12 .. SUBS r2,r2,#4
0x08000bbc: 2a00 .* CMP r2,#0
0x08000bbe: d1fb .. BNE 0x8000bb8 ; __scatterload_zeroinit + 4
0x08000bc0: 4770 pG BX lr此处拷贝ZI数据,共16#16*3 = 768 = r2个字。
12. 跳转到__main_after_scatterload,
__main_after_scatterload
_main_init
0x080000f4: 4800 .H LDR r0,[pc,#0] ; [0x80000f8] = 0x8000121
0x080000f6: 4700 .G BX r0
$d
0x080000f8: 08000121 !... DCD 134218017
可见它又向08000121处跳转
13. 接着向main函数跳转,进入主函数执行
.text
main
0x08000120: b570 p. PUSH {r4-r6,lr}
0x08000122: 2600 .& MOVS r6,#0
0x08000124: 2009 . MOVS r0,#9
0x08000126: f000fa27 ..'. BL Stm32_Clock_Init ; 0x8000578
因为在编译时给armcc指定-D:__MICROLIB,所以__user_initial_stackheap并没有定义。所以下文叙述的内容不适用于这种情况
http://blog.csdn.net/wangfoquan/article/details/7650988">http://blog.csdn.net/wangfoquan/article/details/7650988
对应STM32F10x.s如下语句
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, =(Stack_Mem + Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ALIGN
ENDIF