久久久91-久久久91精品国产一区二区-久久久91精品国产一区二区三区-久久久999国产精品-久久久999久久久精品

ABB
關(guān)注中國自動(dòng)化產(chǎn)業(yè)發(fā)展的先行者!
橫河電機(jī)25年9月
工業(yè)智能邊緣計(jì)算2025年會(huì)
2025工業(yè)安全大會(huì)
CAIAC 2025
OICT公益講堂
當(dāng)前位置:首頁 >> 案例 >> 案例首頁

案例頻道

一種基于Gcc的控制編程語言編譯方案
  • 企業(yè):控制網(wǎng)     領(lǐng)域:儀器儀表     行業(yè):建筑樓宇    
  • 點(diǎn)擊數(shù):2152     發(fā)布時(shí)間:2008-06-29 09:54:27
  • 分享到:
 
    胡志遠(yuǎn)(1982-)
男,信息產(chǎn)業(yè)部電子六所碩士研究生,(華北計(jì)算機(jī)系統(tǒng)工程研究所,北京  100083),計(jì)算機(jī)應(yīng)用技術(shù)專業(yè),在讀。現(xiàn)于北京和利時(shí)系統(tǒng)工程公司實(shí)習(xí),研究方向?yàn)楣I(yè)控制語言編譯。

摘要:
Gcc是公認(rèn)的功能強(qiáng)大的開源編譯器。本文介紹了一種利用Gcc實(shí)現(xiàn)控制器編程語言編譯功能的方案。

關(guān)鍵詞:
Gcc;編譯

Abstract:
It is well-known that Gcc(Gnu C Compiler)is a powerful “Open Source” compiler. In this paper, we introduce the method to compile the control languages using Gcc.

Key words:
  Gcc;compile

1  引言

    用控制編程語言編寫的算法經(jīng)過編譯后,通常都會(huì)下裝到控制器中由控制器軟件調(diào)度執(zhí)行,而不是由操作系統(tǒng)直接調(diào)度執(zhí)行。因此,對(duì)編譯生成的二進(jìn)制格式有特殊要求。本文將介紹一種利用Gcc編譯器輔助生成項(xiàng)目所需的特殊格式二進(jìn)制目標(biāo)文件的方案。

2  概述

  整體編譯方案如圖1所示。



圖 1  組態(tài)整體編譯方案圖

    首先,控制語言經(jīng)過編譯產(chǎn)生邏輯上等價(jià)的C代碼,然后,編譯模塊對(duì)C文件進(jìn)行編譯處理生成所需特殊格式目標(biāo)文件。

    編譯模塊會(huì)借助Gcc工具鏈對(duì)C文件進(jìn)行編譯連接等處理。實(shí)現(xiàn)方案中關(guān)鍵部分有:

    (1)通過修改匯編指令BL,實(shí)現(xiàn)函數(shù)間接地址跳轉(zhuǎn)。

    (2)通過使用Gcc的擴(kuò)展語法__attribute__,輔助鏈接腳本控制鏈接過程,利用Gcc工具鏈中鏈接器ld對(duì).o文件進(jìn)行鏈接實(shí)現(xiàn)變量指定地址分配。

    (3)通過使用Gcc工具鏈中objdump工具,取得.o文件中重定位信息。

    (4)通過使用Gcc工具鏈中readelf工具,提取.l文件中機(jī)器碼信息以及部分重定位信息。

3  關(guān)鍵技術(shù)介紹



圖 2   編譯模塊處理流程

    上圖展示了編譯模塊內(nèi)部處理方案。下面以圖2中所示處理流程為序,介紹編譯過程中的關(guān)鍵技術(shù)。

3.1  修改函數(shù)調(diào)用指令

    編譯特殊需求:函數(shù)調(diào)用方式要求為間接地址調(diào)用。

    Gcc編譯C代碼生成的匯編文件中函數(shù)調(diào)用采用的是相對(duì)地址偏移跳轉(zhuǎn)方式。ARM匯編中,BL指令為函數(shù)調(diào)用指令,為實(shí)現(xiàn)函數(shù)調(diào)用方式改變,我們必須對(duì)所有BL指令進(jìn)行修改。在匯編這個(gè)環(huán)節(jié)進(jìn)行修改,而不是.o文件,因?yàn)?o文件修改可能會(huì)破壞相對(duì)地址跳轉(zhuǎn)類指令,例如B指令。

    例如:某段C代碼編譯產(chǎn)生的匯編文件中可能出現(xiàn)下面的函數(shù)調(diào)用語句

    bl    Fun_No1

    這種函數(shù)調(diào)用形式實(shí)際上是相對(duì)地址偏移跳轉(zhuǎn),不滿足編譯模塊對(duì)函數(shù)調(diào)用方式的特殊需求,為了實(shí)現(xiàn)函數(shù)間接地址跳轉(zhuǎn),對(duì)函數(shù)調(diào)用匯編語句進(jìn)行修改模擬BL指令動(dòng)作,修改后的匯編形式如下:

       b     .$L0
.$L1:
       .word      52
.$L0:
       ldr   r8,.$L1
       ldr   r8,[r8]
       mov lr,pc
       mov pc,r8

    .word      52為Fun_No1的函數(shù)指針地址,該地址需要進(jìn)行重定位,此處重定位信息提取將在提取機(jī)器碼部分介紹。
 兩條ldr指令將指針指向地址取出,然后賦給pc實(shí)現(xiàn)函數(shù)間接地址調(diào)用。其中標(biāo)號(hào).$L0中使用符號(hào)$可以保證標(biāo)號(hào)的唯一性,C語言中標(biāo)示符中不可能出現(xiàn)$符號(hào)。

    說明: BL(Branch and Link)指令,該指令執(zhí)行引起地址跳轉(zhuǎn)到一個(gè)目的地址,并且將函數(shù)返回地址存儲(chǔ)到LR寄存器中;LR寄存器,即Link Register(R14),該寄存器保存BL指令下一條指令的地址,函數(shù)從子例程返回后從該地址開始繼續(xù)執(zhí)行;PC寄存器,即Program Counter,可以在大多數(shù)指令中做為一個(gè)指令指針,總是指向當(dāng)前執(zhí)行指令后的第二條指令。所有的ARM指令均四字節(jié)長。并且總是對(duì)齊到四字節(jié)邊界,所以PC中最低兩位總是0。[1]

3.2 提取重定位信息

    編譯特殊需求:搜集目標(biāo)代碼中的重定位信息。

    編譯模塊生成的目標(biāo)代碼下裝到控制器后需要重定位才能進(jìn)行IEC運(yùn)算,由于在鏈接后,Gcc在反編譯目標(biāo)代碼已經(jīng)無法提取重定位信息,所以要在鏈接前提取重定位信息。在連接的過程中,目標(biāo)代碼的長度和執(zhí)行順序都沒有變化,只是操作變量或指針的地址進(jìn)行了重新填充,所以在連接前提取的重定位信息對(duì)鏈接后的代碼同樣適用。

    在鏈接前,通過調(diào)用Gcc工具鏈中的反編譯程序objdump,以-r作為命令行參數(shù)可得到當(dāng)前代碼中需要進(jìn)行重定位的位置信息。即以”objdump -r *.o -o *.r”為參數(shù)啟用新進(jìn)程執(zhí)行反編譯程序objdump,生成包含重定位信息的.r文件。整理.r文件中所有的重定位信息得到最終目標(biāo)文件中的一部分重定位數(shù)據(jù)。另外一部分重定位信息在提取機(jī)器碼階段獲得,在后面內(nèi)容中會(huì)介紹。下面舉例說明.r文件中的重定位信息:

    執(zhí)行命令objdump –r Test.o結(jié)果如下:

Test.o:     file format elf32-bigarm
 
RELOCATION RECORDS FOR [.text]:
OFFSET        TYPE                    VALUE
00000030      R_ARM_ABS32    AT_VAR
00000064      R_ARM_PC24      .text
... ...

    說明:由于AutoThinker對(duì)應(yīng)的控制器程序不支持代碼段重定位,只支持?jǐn)?shù)據(jù)段的重定位,所以在提取重定位信息的時(shí)候,只需要提取數(shù)據(jù)段重定位數(shù)據(jù)。例子中TYPE為R_ARM_ABS32的行記錄了數(shù)據(jù)段重定位信息,該行中OFFSET項(xiàng)表明Test.o文件中代碼段偏移0x00000030處開始的四字節(jié)數(shù)據(jù)需要進(jìn)行重定位處理。

3.3 鏈接

    編譯模塊特殊需求:實(shí)現(xiàn)變量指定地址分配。

    簡單的講,鏈接器的工作就是解析未定義的符號(hào)引用,將目標(biāo)文件(這里指.o文件)中的占位符替換為符號(hào)的地址。目標(biāo)文件是包括機(jī)器碼和鏈接器可用信息的程序模塊。鏈接器將完成程序中各目標(biāo)文件的地址空間的組織。

    每個(gè)鏈接都被一個(gè)鏈接腳本所控制,這個(gè)腳本是用鏈接命令語言書寫的。

    鏈接腳本的一個(gè)主要目的是描述輸入文件中的節(jié)如何被映射到輸出文件中,并控制輸出文件的內(nèi)存排布。幾乎所有的鏈接腳本只做這兩件事情。但是,在需要的時(shí)候, 鏈接腳本還可以指示鏈接器執(zhí)行很多其他的操作。[2]

    鏈接器一般都有自己默認(rèn)的鏈接腳本,要控制鏈接器的行為,可以過使用'-T'命令行選項(xiàng)來提供自己的鏈接腳本。

    使用'SECTIONS'命令來描述輸出文件的內(nèi)存布局。下面內(nèi)容摘自我們編寫的鏈接腳本myld.lds。

SECTIONS
{     
           . = 0x3008;
           .data : { *(.data) }
           MySection  0x00203008 : { *(MySection)}
              … …
. = 0x0100000;
           .text ALIGN(0x00100000) : { *(.text) }
}

    說明:腳本中命令指示,data段載入到地址0x3008處,text段載入到地址0x100000處,腳本中MySection為我們自己定義的段,對(duì)應(yīng)于C代碼語句:

    AT_VAR_T  Var_Test  __attribute__((section("MySection")));[3]

    AT_VAR_T類型變量Var_Test將載入到地址0x00203008開始處。__attribute__為Gcc語法擴(kuò)展。一般情況下編譯器將數(shù)據(jù)存放到data段或bss段中,當(dāng)我們有特殊需求,需要將某些變量放到特定段中的時(shí)候可以使用Gcc__attribute__擴(kuò)展語法。上面的C語句定義了新的段MySection,配合鏈接腳本myld.lds的定位功能我們就實(shí)現(xiàn)了變量的指定地址分配。

    執(zhí)行鏈接操作的命令如下:

    ld –T myld.lds Test.o –o Test.l

    ld使用myld.lds作為鏈接腳本,將Test.o文件進(jìn)行鏈接,生成文件Test.l。

3.4  提取機(jī)器碼

    編譯特殊需求:以函數(shù)為單位提取出編譯生成得二進(jìn)制機(jī)器碼。

    借助Gcc工具鏈中的readelf工具,我們可以從鏈接后的.l文件中提取每個(gè)函數(shù)對(duì)應(yīng)的二進(jìn)制機(jī)器碼。

    執(zhí)行命令readelf -S -s Test.l結(jié)果如下:

Section Headers:
  [Nr] Name         Type              Addr              Off         Size        ES   Flg Lk Inf Al
  … …
  [ 5] .text           PROGBITS    00100000       008000    000070    00  AX  0   0  4
  … …
 
Symbol table '.symtab' contains 22 entries:
   Num:    Value  Size   Type              Bind   Vis                  Ndx Name
       … …
    18:  00100044       0     NOTYPE  LOCAL  DEFAULT    8       .$L1
… …
    21: 0010005c         20    FUNC    GLOBAL     DEFAULT    5    main

    Section Headers部分第五行顯示.text段Addr屬性為0x00100000,該值與鏈接腳本中text段載入地址一致;.text段Off屬性為0x008000,該值表明Test.l中偏移0x8000處為text段內(nèi)容。

    Symbol table部分第21行內(nèi)容表示,main函數(shù)載入地址0x10005c,函數(shù)長度20。結(jié)合Section Header中獲得信息,我們可以知道Test.l文件中偏移0x805c(計(jì)算公式:函數(shù)載入地址-text段載入地址+text段在.l文件中的偏移。即,0x10005c - 0x100000 + 0x8000)處開始20個(gè)字節(jié)內(nèi)容為main函數(shù)函數(shù)體對(duì)應(yīng)的機(jī)器碼。

    Symbol Table部分第18行內(nèi)容表示C代碼中標(biāo)號(hào)$L1對(duì)應(yīng)機(jī)器碼的載入地址為0x100044,結(jié)合Section Headers中信息,可以知道該標(biāo)號(hào)相對(duì)text段的偏移為0x44,該標(biāo)號(hào)指示位置需要進(jìn)行重定位。此部分重定位信息與objdump提取的重定位信息相結(jié)合就得到了我們所需要的全部重定位信息。

4  結(jié)束語

    在嵌入式應(yīng)用中,往往對(duì)編譯功能有種種的特殊需求。通過運(yùn)用Gcc工具鏈中的各種編譯工具,我們可以定制程序編譯過程,以滿足特殊的編譯需求。

參考文獻(xiàn)

    [1]      ARM Limited.  ARM Architecture Reference Manual. June 2000.

    [2]      Free Software Foundation, Inc.ld.info. 2004.

    [3]      Richard M. Stallman and the GCC Developer Community.Using the GNU Compiler Collection. 2005.

熱點(diǎn)新聞

推薦產(chǎn)品

x
  • 在線反饋
1.我有以下需求:



2.詳細(xì)的需求:
姓名:
單位:
電話:
郵件:
主站蜘蛛池模板: 欧亚毛片| 国产欧美二区| 99re九精品视频在线视频| 手机看片福利日韩欧美看片| 欧美在线一级毛片视频| 国产高清在线看免费视频观| 久久国产精品自在自线| 香蕉97| 中文字幕一区在线观看| 国产一级视频播放| 性刺激视频在线观看免费| 成年午夜视频免费观看视频| 久久国产亚洲精品| 日韩第六页| 亚洲精品国产成人中文| 日本a级特黄特黄刺激大片| 亚洲免费成人| 欧美中文字幕第一页| 国产国产人成免费视频77777 | 一级全免费视频播放| 中国一级毛片免费观看| 亚洲综合色网| 国产三级在线免费| 国产高清在线精品一区在线| 俄罗斯aa毛片极品| 黄色片在线观看网站| 4444亚洲国产成人精品| 久久久网站亚洲第一| 欧美亚洲视频在线观看| 91pao强力打造免费高清| 一级成人 理伦片| 久久一级| 亚洲一区在线视频| 在线免费黄| 成人免费在线网站| 成人网免费观看| 同性男男黄h片在线播放免费| 污的网址| 成人免费福利网站在线看| 伊在人香蕉99久久| 伦理片一区|