[轉]keil編譯鏈接過程以及ARMCC、ARMASM、FROMELF、ARMLINK、ARMAR的使用


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.lfz_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

對原文進行整理,也進行了一些簡單的測試,糾正了幾處翻譯的錯誤。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM