1、keil5 MDK的編譯工具
armar.exe armasm.exe armcc.exe armlink.exe fromelf.exe
以及動態鏈接庫
armcompiler_libFNP.dll
2、各工具用法
>>>armar.exe
可以在windows下使用命令行切換到該程序所在文件夾(keil5\ARM\ARMCC\bin),執行armar.exe -h進行命令查看。若有gitbash的話直接在該文件夾下右鍵選擇gitbash here,之后運行./armar.exe -h。獲得以下結果(下面是已經翻譯過的,省略部分不重要的)
產品: MDK Professional 5.14 組件: ARM Compiler 5.05 update 1 (build 106) 工具: armar [4d0efa] 文件創建以及維護工具。 庫文件:.lib或者.a 命令格式: armar options archive [ file_list ] 選項: -r 插入在file_list中的文件, 替換掉已經存在的同名成員. -d 刪除在file_list中的成員. -x 在archive中提取file_list中同名的成員. -m 在file_list中移動文件. -p 打印文件到標准輸出設備. -a pos 插入/刪除pos后面的文件. -b pos 插入/刪除pos前面的文件. -u 只更新舊的文件, 與 -r 一起使用. -n 不要向object文件中添加符號表. -s 強制重新生成文檔符號表. -t 打印文檔的內容表. --zs 顯示符號表. --zt 匯總文檔內容 (大小和輸入). -c 當一個新文檔被創建的時候不顯示警告. -C 提取的時候不要覆蓋一個已經存在的文件. -T 截取系統最大長度文件名. -v 提供詳細輸出. --create 強制創建一個新的文檔. --via file 從 via 文件中獲取額外參數. --sizes 列出所有成員大小與庫的總大小. --entries 列出包括入口點的部分. --vsn 打印最新的armar版本. --help 打印幫助信息.例子:
D:\Keil\ARM\ARMCC\bin>armar.exe -r testlib __main.o _rcc.o _it.o //把__main.o _rcc.o _it.o 合並到testlib中 Creating archive 'testlib' D:\Keil\ARM\ARMCC\bin>armar.exe -tv testlib //打印文檔的內容表 rw-rw-rw- 0/ 0 1072 Sep 18 18:09 2016 __main.o (offset 934) rw-rw-rw- 0/ 0 338632 Sep 08 20:23 2016 _rcc.o (offset 2066) rw-rw-rw- 0/ 0 328392 Sep 08 20:23 2016 _it.o (offset 340758) D:\Keil\ARM\ARMCC\bin>armar.exe -d testlib _it.o D:\Keil\ARM\ARMCC\bin>armar.exe -tv testlib rw-rw-rw- 0/ 0 1072 Sep 18 18:09 2016 __main.o (offset 774) rw-rw-rw- 0/ 0 338632 Sep 08 20:23 2016 _rcc.o (offset 1906)
>>fromelf.exe
ARM 映像轉換工具 fromelf [options] input_file 選項: --help 顯示幫助信息 --vsn 顯示版本信息 --output file 輸出文件名. (默認輸出 -text 格式) --nodebug 不要輸出調試信息到映像文件中 --nolinkview 不要輸出段信息到映像文件中 二進制輸出格式: --bin 普通二進制 --m32 摩托羅拉32位Hex碼 --i32 英特爾32位Hex碼 --vhx 定向字節的 Hex 格式 --base addr 為 m32,i32設置基地址(可選的) 輸出格式要求的調試信息 --fieldoffsets Structures/Classes的匯編描述 --expandarrays Arrays inside and outside structures are expanded 其他輸出格式: --elf ELF格式 --text 文本信息 文本信息的標志 -v 詳細信息 -a 打印數據的地址信息 (得到的.axf映像文件) -c 匯編碼 -d 打印數據的段內容 -e 打印例表 -g 打印調試表 -r 打印重定位信息 -s 打印符號表 -t 打印字符表 -y 打印段內容分析 -z 打印代碼與數據的大小信息例子
fromelf.exe --i32 --output=./test_prj.hex --base=0x08000000 ./test_prj.axf
>>armcc.exe
Product: MDK Standard 5.12 Component: ARM Compiler 5.05 (build 41) Tool: armcc [4d0eb9] For support see http://www.arm.com/support Software supplied by: ARM Limited Usage: armcc [options] file1 file2 ... filen 主要選項: --arm 創建 ARM 代碼 --thumb 創建 Thumb 代碼 --c90 切換到C模式 (默認是 .c 文件) --cpp 切換到C++模式 (默認 .cpp 文件) -O0 最小優化級別 -O1 受限的調試級別優化 -O2 高優化 -O3 最大優化 -Ospace 對代碼大小進行優化 -Otime 優化最大優化級別的運行時間 --cpu <cpu> 選擇CPU --cpu list 輸出所有可以選擇的CPU列表 --device 設置目標設備類型 --device list 輸出所有可以選擇的目標設備列表 -o file 最終輸出文件的名字 -c 只進行編譯,不鏈接 --asm 輸出匯編以及obj文件 -S 只輸出匯編文件 --interleave 交叉反匯編 (use with --asm or -S) -E 僅僅預處理C代碼 -D <symbol> 定義<symbol>並且傳入編譯過程 -g 為高級別調試創建表 -I <directory> 在編譯的時候包含<directory>作為頭文件搜索目錄keil中經過配置后的選項:
-c --cpu Cortex-M4.fp -g -O0 --apcs=interwork --split_sections -I../system/usart -I../system/sys -I../system/delay -I../hardware/head -I E:\ProjectFiles\keil5\STM32\test_prj\user\RTE -I D:\msprograms\keil5\ARM\PACK\Keil\STM32F4xx_DFP\1.0.8\Device\Include -I D:\msprograms\keil5\ARM\CMSIS\Include -D__UVISION_VERSION="514" -DSTM32F40_41xxx -o "..\obj\*.o" --omf_browse "..\obj\*.crf" --depend "..\obj\*.d"這種方式編譯就不在贅述,比較簡單,介紹下如何在自制makefile並且進行編譯
1. 首先下載make.exe,鏈接在此:http://www.equation.com/servlet/equation.cmd?fa=make
2. 拷貝到keil的armcc的bin目錄下,在工程文件中編寫makefile
3. 執行make即可實現自制make
>>armlink.exe
Usage: armlink option-list input-file-list where option-list是不區分大小寫的選項列表. input-file-list是輸入對象和庫文件列表. General options (abbreviations shown capitalised): --output file 指定輸出文件名. Options for specifying memory map information: (指定map的信息) --partial 創建一個被分散鏈接的對象文件. --scatter file 按照分散加載文件的描述創建map文件. (Create the memory map as described in file.) --ro-base n 設置執行地址空間域,包含RO段(只讀數據段). --rw-base n 設置執行地址空間域,包含RW/ZI段. Options for controlling image contents: (控制image的內容) --bestdebug 添加調試信息為image提供調試視圖. --datacompressor off 不要壓縮RW數據段. --no_debug 不添加調試信息. --entry 指定輸入段與輸入點. --libpath 指定系統庫文件路徑. --userlibpath 指定用戶庫文件路徑. --no_locals 不要添加局部標號到image的標號列表. --no_remove 不要移除image的未使用段. Options for controlling image related information: --callgraph 創建一個函數靜態調用圖. --info topic 列出image信息. Available topics: (separate multiple topics with comma) common List common sections eliminated from the image. debug List eliminated input debug sections. sizes List code and data sizes for objects in image. totals List total sizes of all objects in image. veneers List veneers that have been generated. unused List sections eliminated from the image. --map 顯示image內存映射. --symbols 列出image中的符號. --xref 列出輸入的段之間所有的交叉引用.最終輸出會放在.map文件里面keil里面的配置
--cpu Cortex-M4.fp *.o --strict --scatter "..\obj\test_prj.sct" --summary_stderr --info summarysizes --map --xref --callgraph --symbols --info sizes --info totals --info unused --info veneers --list "..\obj\test_prj.map" -o ..\obj\test_prj.axf
>>armasm.exe
Usage: armasm [options] sourcefile Options: --list listingfile 生成列表文件 -o outputfile 最終輸出文件名 --depend dependfile 保留 'make' 源文件依賴 --errors errorsfile 把標准錯誤判斷放入errorsfile -I dir[,dir] 添加源文件的搜索目錄 --pd --predefine directive 預執行 SET{L,A,S} 指令 --maxcache <n>最大閃存空間 (default 8MB) --no_esc 忽略C文件 --no_warn 關閉警告信息 -g 輸出調試表 --apcs / //比較復雜,暫不關心 --li ARM小端模式 --bi ARM大端模式 --cpu 設置目標ARMcpu類型 --device 設置目標設備類型 --fpu 設置目標 FP 體系結構版本 --thumb 以 Thumb 指令集編譯 --arm 以 ARM 指令集編譯keil里面的配置
--cpu Cortex-M4.fp -g --apcs=interwork -I E:\ProjectFiles\keil5\STM32\test_prj\user\RTE -I D:\msprograms\keil5\ARM\PACK\Keil\STM32F4xx_DFP\1.0.8\Device\Include -I D:\msprograms\keil5\ARM\CMSIS\Include --pd "__UVISION_VERSION SETA 514" --pd "STM32F40_41xxx SETA 1" --list "..\obj\*.lst" --xref -o "*.o" --depend "*.d"
3、自己寫一個makefile文件進行make
下載make工具。鏈接:http://www.equation.com/servlet/equation.cmd?fa=make
拷貝make.exe到自定義文件目錄,只要能夠找到即可
編寫makefile文件,如下
1 #armasm.exe程序的路徑 2 ASMCOMPILE_PATH = /d/msprograms/keil5/ARM/ARMCC/bin/armasm.exe 3 #匯編編譯選項 4 #--cpu Cortex-M4.fp cpu型號是Cortex-M4.fp 5 #--pd "__UVISION_VERSION SETA 514" 編譯之前將__UVISION_VERSION賦值為514,后者同理 6 ASMCOMPILE_FLAG = --cpu Cortex-M4.fp -g --apcs=interwork --pd "__UVISION_VERSION SETA 514" --pd "STM32F40_41xxx SETA 1" --xref 7 8 #armcc.exe程序的路徑 9 CCOMPILE_PATH = /d/msprograms/keil5/ARM/ARMCC/bin/armcc.exe 10 #匯編編譯選項 11 #--cpu Cortex-M4.fp cpu型號是Cortex-M4.fp 12 #后面的解釋看上面的相關指令選項注釋 13 CCOMPILE_FLAG = --cpu Cortex-M4.fp -g -O0 --apcs=interwork --split_sections -D__UVISION_VERSION="514" -DSTM32F40_41xxx 14 15 #fromelf.exe程序的路徑 16 FROM_ELF_PATH = /d/msprograms/keil5/ARM/ARMCC/bin/fromelf.exe 17 #intel 32位hex格式 18 #輸出文件名為test_prj.hex 19 #基地址為0x08000000 20 FROM_ELF_FLAG = --i32 --output=./test_prj.hex --base=0x08000000 21 22 #頭文件查找目錄,如果要添加直接添加CINCLUDE_FILE +=樣式即可 23 CINCLUDE_FILE += -I../system/sys 24 CINCLUDE_FILE += -I../system/delay 25 CINCLUDE_FILE += -I../hardware/head 26 CINCLUDE_FILE += -I../system/usart 27 CINCLUDE_FILE += -I /e/ProjectFiles/keil5/STM32/test_prj/user/RTE 28 CINCLUDE_FILE += -I /d/msprograms/keil5/ARM/PACK/Keil/STM32F4xx_DFP/1.0.8/Device/Include 29 CINCLUDE_FILE += -I /d/msprograms/keil5/ARM/CMSIS/Include 30 31 #目標文件列表 32 OBJS += ../user/startup_stm32f40_41xxx.o 33 OBJS += ../system/usart/usart.o 34 OBJS += ../system/sys/sys.o 35 OBJS += ../system/delay/delay.o 36 OBJS += ../hardware/src/gpio.o 37 OBJS += ../user/test.o 38 39 LINK_PATH = /d/msprograms/keil5/ARM/ARMCC/bin/armlink.exe 40 41 LINK_FLAG = --cpu Cortex-M4.fp --strict --scatter "test_prj.sct" --summary_stderr --info summarysizes --map --xref --callgraph --symbols --info sizes --info totals --info unused --info veneers --list "..\obj\test_prj.map" 42 43 test_prj.axf : $(OBJS) 44 echo "hellow" 45 $(LINK_PATH) $(LINK_FLAG) -o $@ $^ 46 $(FROM_ELF_PATH) $(FROM_ELF_FLAG) ./test_prj.axf 47 %.o : %.c 48 $(CCOMPILE_PATH) $(CINCLUDE_FILE) $(CCOMPILE_FLAG) -o $@ -c $< --omf_browse $(subst .c,.crf,$<) --depend $(subst .c,.d,$<) 49 %.o : %.s 50 $(ASMCOMPILE_PATH) $(CINCLUDE_FILE) $(ASMCOMPILE_FLAG) -o $@ $< --list $(subst .s,.lst,$<) --depend $(subst .s,.d,$<) 51 52 clean : 53 rm -rf $(OBJS) 54 55 #字符串查找替換 56 #$(subst <from>,<to>,<text>) 57 #把text中的from字符串替換為to字符串 58 #例:$(subst he,HE,hellow) 59 #把hellow中的he替換為HE</text></to></from></code>
4、scatter文件(分散加載文件)
keil建立STM32F407ZG工程之后進行build的時候會相應的生成一個此文件,在編譯與鏈接之前,由此推測在keil中次文件內容應該是由工程配置選項中的單片機型號所對應的信息生成的。
; ************************************************************* ; *** Scatter-Loading Description File generated by uVision *** ; ************************************************************* LR_IROM1 0x08000000 0x00100000 { ; 加載域,也就是代碼文件下載到0x08000000 代碼段最大尺寸為0x00100000(1M) ER_IROM1 0x08000000 0x00100000 { ; 執行域,也就是從0x08000000開始執行,執行空間為0x00100000大小 *.o (RESET, +First) ;所有的.o文件存放位置,First標示該段位於該執行域的最開始,+ 表示連續放置,以RESET段作為開始,RESET在啟動文件里面 *(InRoot$$Sections) ;一些庫文件的加載,啟動文件STM32F4xx.s里面跳轉到__main而不是main函數就有這句話的作用。
而__main函數里面會執行RW,ZI的"解壓縮",也就是把這些數據初始化並且放在它的執行域當中去。
__main是一個庫函數,執行完解壓縮之后才會跳轉到真正的main函數處執行代碼 .ANY (+RO) ;所有的RO數據存放位置,RO數據為常量數據,運行過程不會被改變。
.ANY則是編譯器根據情況可將該段放在該執行域任意位置,+ 表示連續放置 } RW_IRAM1 0x20000000 0x00020000 { ; 變量數據段,從0x20000000開始,最大尺寸為0x00020000,此屬於RAM區 .ANY (+RW +ZI) ;所有的RW以及ZI數據 } }RW:可讀可寫的變量數據,所以不可放在ROM區,也就是單片機的Flash
ZI:初始化為0的變量數據,依然不可放在ROM
RO:只讀數據,放在ROM區,掉電不丟失
5、關於__main
在keil編譯后生成的.map文件當中可以看到類似於下面的信息
---------------------------------------------------------------------- Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name 8 0 0 0 0 68 __main.o 104 0 0 0 0 84 __printf.o 0 0 0 0 0 0 __rtentry.o 12 0 0 0 0 0 __rtentry2.o 6 0 0 0 0 0 __rtentry4.o 52 8 0 0 0 0 __scatter.o 26 0 0 0 0 0 __scatter_copy.o 28 0 0 0 0 0 __scatter_zi.o 44 0 0 0 0 108 _printf_char.o 48 6 0 0 0 96 _printf_char_common.o 36 4 0 0 0 80 _printf_char_file.o 6 0 0 0 0 0 _printf_d.o 120 16 0 0 0 92 _printf_dec.o 178 0 0 0 0 88 _printf_intcommon.o 0 0 0 0 0 0 _printf_percent.o 4 0 0 0 0 0 _printf_percent_end.o 6 0 0 0 0 0 _printf_s.o 82 0 0 0 0 80 _printf_str.o 12 0 0 0 0 72 exit.o 8 0 0 0 0 68 ferror.o 6 0 0 0 0 152 heapauxi.o 2 0 0 0 0 0 libinit.o 6 0 0 0 0 0 libinit2.o 2 0 0 0 0 0 libshutdown.o 2 0 0 0 0 0 libshutdown2.o 8 4 0 0 96 68 libspace.o 24 4 0 0 0 84 noretval__2printf.o 2 0 0 0 0 0 rtexit.o 10 0 0 0 0 0 rtexit2.o 74 0 0 0 0 80 sys_stackheap_outer.o 2 0 0 0 0 68 use_no_semi.o 2 0 0 0 0 68 use_no_semi_2.o 10 0 0 0 0 116 fpinit.o ---------------------------------------------------------------------- 942 42 0 0 100 1472 Library Totals 12 0 0 0 4 0 (incl. Padding) ---------------------------------------------------------------------- Code (inc. data) RO Data RW Data ZI Data Debug Library Name 920 42 0 0 96 1356 c_w.l 10 0 0 0 0 116 fz_wm.l ---------------------------------------------------------------------- 942 42 0 0 100 1472 Library Totals</code>說明該工程用到了兩個庫文件c_w.l與fz_wm.l,在keil的安裝目錄下搜索可以得到它們在\ARM\ARMCC\lib\armlib目錄下。做一個小實驗
把c_w.l文件拷貝到\ARM\ARMCC\bin目錄下,還記得這個目錄里面裝的有armar.exe吧,現在可以派上用場了,在該目錄下打開命令行(shift+鼠標右鍵)。
執行./armar.exe –zt c_w.l可以看到里面所有的.o文件,其中就有__main.o,更多的文件請自行查看。 使用./armar.exe -x c_w.l __main.o提取出來__main.o文件,可以自行查看其反匯編文件
總之__main的作用是做RW,ZI等等數據的重定位以及初始化,之后再次跳轉到真正的main函數處執行用戶代碼。
注:轉載自http://www.2cto.com/kf/201605/504594.html
對原文進行整理,也進行了一些簡單的測試,糾正了幾處翻譯的錯誤。
