實驗環境
本實驗基于這樣的開發環境:在Ubuntu18.04.3發行版上使用編譯器arm-linux-gcc(arm-none-linux-gnueabi, 4.3.2 Sourcery G++ Lite 2008q3-72)編譯,并運行于S3C2440 ARM硬件平臺上。S3C2440是一款32位的ARM SoC。
鏈接(linking)
所謂鏈接,就是將各種代碼和數據部分收集起來并組合成一個單一文件的過程,這個單一文件可以被加載到存儲器內并被執行。鏈接既可以執行于編譯時,也可以執行于加載時,也可以執行于運行時。若執行于編譯時,則是由編譯器在將源代碼翻譯成機器碼時負責;若執行于加載時,則是由加載器(loader)把可執行程序加載到存儲器中時負責;若執行于運行時,則是由應用程序負責。通常情況下,鏈接是由鏈接器程序負責自動執行的。
目標文件
目標文件有三種類型:
可重定位目標文件
可執行目標文件
共享目標文件
其中編譯器生成可重定位目標文件(包括共享目標文件)。鏈接器生成可執行目標文件。
在不同的操作系統上,目標文件的格式都不相同。最早從貝爾實驗室誕生的第一個Unix系統使用的是a.out格式,所以直到今天,gcc默認生成的可執行文件的名字仍是a.out文件。System V Unix系統的早期版本使用的格式叫做一般目標文件格式(Common Object File Format,COFF)。Windows NT使用的就是COFF的一個變種,叫做可移植可執行(Portable Executable,PE)格式。而現代Unix系統(如Linux,還有System V Unix的后續版本,各種BSD Unix,以及Sun Solaris等系統),使用的是Unix可執行和可鏈接(Executable and Linkable Format,ELF)格式。
本實驗只討論ELF格式,但原理在本質上是相通的。下面開始介紹ELF格式文件。
ELF可重定位目標文件
上圖展示的是一個典型的ELF可重定位目標文件的格式。
ELF頭、節頭部表
其中第一項的ELF頭,是一個16字節的序列。該序列描述了生成該文件的系統的字的大小和字節順序。而序列剩下的部分則包含了幫助鏈接器語法分析和解釋目標文件的信息。其中包括ELF頭的大小、目標文件的類型(如可重定位、可執行或者是共享的)、機器類型(如IA32)、節頭部表(section header table)的文件偏移,以及節頭部表中的條目大小和數量。不同節的位置和大小是由節頭部表描述的,其中目標文件中每一個節都有一個固定大小的條目(entry)。
在ELF頭和節頭部表之間的部分,都是節(section)。一個典型的ELF可重定位目標文件包括下面要介紹的幾個節。
.text
該節是已編譯程序的二進制機器代碼。
.rodata
只讀數據。比如printf語句中的格式字符串和switch語句的跳轉表。
.data
數據段。存儲的是已初始化過的全局變量。注意,對于C語言的局部變量,在運行時保存在棧中,它既不出現在.data段中,也不出現在.bss段中。
.bss
未初始化的全局變量或者初始化為0的全局變量。在目標文件中,.bss段并不占用實際的空間,只保存描述信息,僅作為一個占位符。未初始化或初始化為0的全局變量不需要占據任何實際的磁盤空間。
.symtab
符號表。存放程序中定義和引用的函數和全局變量的信息。一些程序員錯誤地認為,只有在編譯時使用了-g選項后,目標文件中才會得到符號表信息。實際上,每個可重定位目標文件在.symtab中都有一張符號表。注意,這里和編譯器中的符號表不同,.symtab中不包含局部變量的條目。
.rel.text
這是一個.text段 位置的列表。當鏈接器把這個目標文件和其他文件結合在一起時,需要修改這些位置。一般而言,任何調用外部函數或者引用全局變量的指令都需要修改。另一方面,調用本地函數的指令則不需要修改。需要強調的一點是,對于可執行目標文件,其中并不需要重定位信息,因此通常會省略。
.rel.data
被模塊引用或定義的任何全局變量的重定位信息。
.debug
調試符號表。只有在編譯時添加-g選項才會得到這張表。
.line
原始C源代碼的行號,以及.text段中機器指令之間的映射關系。同樣,只有在編譯時使用-g選項才會得到這張表。
S3C2440地址映射圖
s3c2440的NandFlash啟動與重定位
通常情況下,Nor Flash相對較昂貴,而Nand Flash和SDRAM則相加比較高。所以多數情況下,我們總是使用Nand Flash來存儲代碼并用來執行啟動代碼,同時使用SDRAM作為其余代碼的執行地方。
我們知道,Nand Flash并不支持CPU直接訪問。為了支持Nand方式啟動,S3C2440在SoC芯片內部內置了一塊大小為4KB的SRAM,并將這塊SRAM起名叫做起步石(SteppingStone)。當以Nand方式啟動時,硬件在復位過程中,會自動將Nand Flash前4KB的數據拷貝到起步石中,復位結束后,CPU會跳轉到0x0地址開始執行代碼。
由上圖可知,當我們將SoC的OM1和OM0兩個管腳置為0x00時,SoC就會以Nand方式啟動。此時0x0地址對應的正是起步石SRAM。所以此時就是從起步石開始執行代碼。而這4KB的代碼,我們就稱之為boot code。
Boot Code要做的工作,就是初始化必要的硬件,并將Nand Flash中剩余的代碼全部拷貝至SDRAM內存中,之后跳轉到SDRAM中繼續執行。當跳轉到內存中開始執行后,這4KB的SRAM就可以隨便使用了。
需要注意的是,在以Nand方式啟動時,硬件在自動讀取Nand Flash前4KB的內容時,并沒有使用ECC校驗,所以必須確保Nand Flash上前4KB的代碼沒有位錯誤。
這個流程看似很完美,但我有一點疑惑,就是此時Nand控制器還沒有被初始化,cpu是怎么能夠訪問NandFlash來讀取其上存儲的數據的呢?查看S3C2440的用戶手冊,它說當硬件復位過程中,Nand Flash控制器會通過如下幾個SoC的引腳來獲取外接的Nand Flash芯片的信息:
NCON(Adv flash)
GPG13(Page size)
GPG14(Address cycle)
GPG15(Bus width)
這里我們初步研究了一下為什么在最開始還沒有初始化Nand Flash控制器時,硬件就可以正常訪問Nand Flash的內容,而系統啟動之后,必須要初始化Nand Flash控制器后,才能正常讀取Nand Flash的內容。我把深入探究放在后續的Nand實驗的文章中來探討,這里就先這樣。
從Nand方式的啟動流程中我們可以看出,如果待燒寫的BIN文件的大小小于4KB,那么我們就可以不用考慮把代碼拷貝到SDRAM中的事情。但是如果BIN文件的大小超過了4KB,那么我們就必須將代碼拷貝到SDRAM中。既然是要將代碼拷貝到新的地址空間中,那么顯然這就涉及到了代碼的重定位問題。可見,當以Nand Flash方式啟動時,需要考慮代碼的重定位問題。
s3c2440的NorFlash啟動與重定位
當系統以Nor Flash方式啟動時,由于Nor Flash可以像內存一樣直接讀取其中的數據,所以表面上看起來我們不需要像Nand方式啟動那樣,需要考慮4KB的問題。但是實際不是這樣的。如果我們在代碼中使用了全局變量,顯然此時全局變量的地址也在Nor Flash對應的地址空間內。而Nor Flash是不能像內存一樣直接去進行寫操作的,而必須按照特定的時序來進行寫入,所以對于代碼中的全局變量修改操作,就會修改失敗。而通過上面的介紹我們可知,這些全局變量位于.data段或者.bss段中,我們就需要將這些段重定位到SDRAM中,否則代碼運行就不正常。
下面我們通過實驗來證明:當以Nor Flash方式啟動時,如果代碼中存在對全局變量的修改,同時我們沒有進行重定位操作,那么程序就會工作不正常。
main.c
#include "myprintf.h"
#include "uart.h"
#include "util.h"
char gCh = 'A';
int main(void) {
uart0_init();
printf("%snr", "NorFlash Relocate Test.");
while(1) {
gCh++;
printf("%c", gCh);
wait(800000);
}
return 0;
}
Makefile文件
CROSS_COMPILE_PREFIX=arm-linux-
CFLAGS=-g
TARGET=relocate
$(TARGET).bin : CRT0.o uart.o myprintf.o Ctype.o sdram.o util.o $(TARGET).o main.o
$(CROSS_COMPILE_PREFIX)ld -Ttext 0x0000000 -o $(TARGET).elf $^
$(CROSS_COMPILE_PREFIX)objcopy -O binary -S $(TARGET).elf $@
$(CROSS_COMPILE_PREFIX)objdump -D $(TARGET).elf > $(TARGET).dis
CRT0.o : CRT0.S
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -c -o $@ $^
myprintf.o : myprintf.c stdarg.h
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
uart.o : uart.c stdarg.h s3c2440_soc.h
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
$(TARGET).o : $(TARGET).c
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
main.o : main.c
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
Ctype.o : Ctype.c Ctype.h
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
util.o : util.c util.h
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
sdram.o : sdram.c sdram.h
$(CROSS_COMPILE_PREFIX)gcc $(CFLAGS) -o $@ -c $<
clean:
rm -f *.elf *.dis *.bin *.o
make編譯后我們發現,生成的relocate.bin文件非常之大,有36KB左右。
究其原因,是因為我們添加了一個全局變量,并賦值為’A’,所以分配了.data數據段。我們反匯編后觀察,如下所示:
發現數據段的位置被放置在了0x8e20的位置,該位置對應的十進制大小換算關系如下圖所示:
0x8e20換算成十進制的值正是36384,正好對應文件大小36385字節。所以我們將數據段調整至有效代碼結尾處即可。
我們看到.rodata結尾處地址是0xE20,所以我們將.data段放至0xE40處即可。我們修改Makefile文件,在鏈接時指定數據段位置如下所示:
$(CROSS_COMPILE_PREFIX)ld -Ttext 0x0000000 -Tdata 0xE40 -o $(TARGET).elf $^
之后重新make編譯,我們發現生成的bin文件的大小變為了3649Byte,不足4KB。
我們編譯后的relocate.bin文件燒寫至NorFlash中,之后將撥碼開關調至Nor方式啟動,上電觀察串口輸出,如下圖所示:
由此可見主函數中的gCh++;語句修改全局變量失敗,所以會一直輸出字符A,而沒有依次向后遞增。
為雙重驗證,我們將該BIN文件燒寫至Nand Flash中,并以Nand方式啟動,再次上電觀察現象如下圖所示:
可見,由于當選擇Nand方式啟動時,代碼位于0x0地址開始的4KB的SRAM中,所以修改全局變量成功,并且執行速度明顯加快。可見當以Nor Flash方式啟動時,也要考慮代碼的重定位問題,否則程序執行失敗。
上一篇:s3c2440學習筆記——重定位和鏈接腳本
下一篇:jz2440學習筆記———代碼重定位相關
推薦閱讀
史海拾趣
BENCENT公司在成立之初,面臨著資金短缺、技術瓶頸和市場認知度低等多重挑戰。創始人帶領團隊夜以繼日地研發,通過不斷嘗試和改進,終于成功開發出了一款具有競爭力的電子產品。這款產品憑借其高性能和創新性,在市場上獲得了初步認可,為公司的后續發展奠定了基礎。
品質一直是EICHHOFF公司發展的核心競爭力。為了確保產品質量的穩定性和可靠性,公司建立了一套完善的質量管理體系,并持續進行改進和優化。從原材料采購到生產加工、從產品檢測到售后服務,每一個環節都嚴格按照質量管理體系的要求進行。
此外,EICHHOFF公司還積極引入國際先進的品質管理工具和方法,如六西格瑪、精益生產等,以進一步提高產品質量和生產效率。這些努力使得EICHHOFF的產品在行業中享有很高的聲譽和信譽。
自成立以來,Holt Integrated Circuits便專注于為航空電子行業提供高性能的集成電路解決方案。四十多年來,Holt始終站在技術前沿,為全球超過400家制造商提供模擬和混合信號IC數據總線解決方案。從F-16到A-350等先進飛行器,Holt的IC產品已成為飛行控制、導航、發動機管理、通信、安全系統及機上娛樂系統的核心部件。這種長期且穩定的合作關系,不僅奠定了Holt在航空電子領域的領導地位,也推動了整個行業的技術進步。
多年來,Brainboxes一直致力于技術創新和研發投入。公司擁有一支高素質的軟件和硬件工程師團隊,他們在產品設計和制造方面具有豐富的經驗。憑借先進的設計和制造技術,Brainboxes在業界贏得了多項榮譽,如英國制造聯合會頒布的“2007年度最佳企業”獎和歐洲電子工業獎的“2005年度制造商”。這些榮譽不僅證明了公司的技術實力,也提升了其在全球電子行業中的影響力。
除了航空領域,龐巴迪公司在鐵路運輸方面也取得了重要進展。其生產的CITYFLO系列自動列車控制系統在全球范圍內得到了廣泛應用。該系統采用了先進的電子技術和算法,實現了列車的自動駕駛和精確控制,大大提高了鐵路運輸的安全性和效率。此外,龐巴迪還生產了各種鐵路車輛和相關電子設備,為全球鐵路運輸業的發展做出了重要貢獻。
以上五個故事展示了龐巴迪公司在電子行業發展中的關鍵歷程和成就。從水上飛機到現代商用噴氣客機,從航空電子系統到鐵路運輸控制系統,龐巴迪憑借其卓越的技術實力和創新能力,在電子行業中樹立了杰出的品牌形象。
品質控制一直是Emhiser Research非常重視的方面。公司建立了嚴格的質量管理體系和檢測流程,確保每一件產品都符合高標準的質量要求。同時,公司還注重品牌建設,通過不斷提升產品品質和服務水平來樹立品牌形象。這些努力使得Emhiser Research在客戶中贏得了良好的口碑和信任。
在定時上傳GPRS數據的情況下,當時間間隔小于10S時,向模塊打電話就會出現問題,連RING都接收不到。打電話提示都是:“對不起,您所撥打的電話暫時無法接通,請稍后再撥~~”。但是上傳時間間隔比較大時,就沒有問題,找不到好的解決方法,請大家幫 ...… 查看全部問答∨ |
|
WinCE5.0 下面用 DirectShow 開發的播放器,播放視頻時總是新開一個窗口并且自動最小化 我先創建了一個IGraphBuilder接口,查詢IVideoWindow,然后render一個文件,把IVideoWindow的owner設為一個dialog,把它的風格設為\"WS_CHILD| WS_CLIPSIBLINGS\",然后開始播放。 但是實際的結果是:視頻播放的窗口不是我指定的dialog的子窗口。 ...… 查看全部問答∨ |
rt 請各位前輩向晚輩提供一個 將路由協議嵌入CE的解決方案。 晚輩剛剛接到這樣一項工作。從來沒有接觸過。 想問一下各位前輩,需要學那些東西,做什么準備。 實現的 整個流程大體 上是什么。。。 麻煩給 介紹以下。。。 先謝謝各位前輩了。 ...… 查看全部問答∨ |
請問各位達人: 我要是用DSP將數據寫到FPGA中,就對FPGA輸入的20M信號就有影響,即20M信號就不穩定了。要是不用DSP將數據寫到FPGA中,就不對FPGA輸入的20M信號就有影響。不知這是什么原因,不知有人以前遇到過這種現象嗎?怎樣解決 ...… 查看全部問答∨ |
|
該K1195被設計成一種用于TFT - LCD顯示器模塊,具有兩個特征點的主要電源類型:(1)為TFT - LCD顯示器5通道輸出;(2)包括11通道運放在內。 K1195的特點:(1)供電電壓:15 V;(2)調節閥電源電壓:15 V;(3)驅動電源電壓:15 V;(4)結溫:125℃;( ...… 查看全部問答∨ |
本帖最后由 dontium 于 2015-1-23 13:33 編輯 很早前就想問這個問題,現在低成本的MCU中都有集成多路10位甚至12位AD,可為何沒有單獨的低成本AD芯片,很多AD芯片比集成AD的MCU都貴,大大限制了用戶的選擇范圍。如果說封裝貴,可最起碼應該比MCU便 ...… 查看全部問答∨ |