嵌入式系统裸机程序开发与调试
文章目錄
- 🌹1.GUN工具的使用
- 🚀1.1符號(hào)顯示器nm
- 💒1.2objdump:信息查看器
- 🎪1.3objcopy:段剪輯器
- ??2.程序編譯過(guò)程
- ?2.1程序鏈接過(guò)程
- 2.2指定頭文件
- 🎪2.3 指定庫(kù)文件
- ?3.裸機(jī)開(kāi)發(fā)流程
🌹1.GUN工具的使用
GUN是一個(gè)開(kāi)源的組織,給我們帶來(lái)了很多開(kāi)源軟件和編譯工具,如我們常用的
- C編譯器 :gcc
- 預(yù)處理器 :cpp
- C++編譯器 g++
- 匯編器 :as
- 鏈接器 :ld
- 二進(jìn)制工具集 :objcopy
二進(jìn)制工具集的含義:他們專門(mén)用于控制和將二進(jìn)制目標(biāo)代碼從一種格式轉(zhuǎn)換為另一種格式,這些工具被稱作為objcopy和objdump,許多l(xiāng)inux機(jī)器使用的底層軟件在編譯階段都非常依賴這些工具。調(diào)試的時(shí)候也需要他們。objcopy用于從一個(gè)文件拷貝目標(biāo)代碼到另一個(gè)文件,并在這個(gè)過(guò)程中進(jìn)行轉(zhuǎn)換。這樣外面可以在不同的目標(biāo)代碼格式之間進(jìn)行自動(dòng)的轉(zhuǎn)換并操縱這個(gè)過(guò)程中的內(nèi)容。他們可以任何方式來(lái)操作二進(jìn)制文件。
🚀1.1符號(hào)顯示器nm
可通過(guò)arm-linux-gcc -v 查看是否有arm-linux-gcc這個(gè)編譯器
顯示符號(hào) $nm -n main_elf
顯示內(nèi)容:
?第一列為符號(hào)地址
?第二列為符號(hào)所在段
?第三列為符號(hào)名稱
比如我執(zhí)行arm-linux -nm -n demo,demo是我的一個(gè)可執(zhí)行程序,會(huì)出現(xiàn)如下信息
這些符號(hào)的含義如下圖所示:
這個(gè)符號(hào)顯示器很有用,可以看到絕大部分的信息,但是局部變量是看不到的,因?yàn)樗峙湓跅@锩?/p>
💒1.2objdump:信息查看器
objdump 有點(diǎn)像那個(gè)快速查看之類的工具,就是以一種可閱讀的格式讓你更多地了解二進(jìn)制文件可能帶有的附加信息。對(duì)于一般只想讓自己程序跑起來(lái)的程序員,這個(gè)命令沒(méi)有更多意義,對(duì)于想進(jìn)一步了解系統(tǒng)的程序員,應(yīng)該掌握這種工具,至少你可以自己寫(xiě)寫(xiě)shellcode了,或者看看人家給的 exploit 中的 shellcode 是什么東西。
? 查看所有段信息 $objdump -h main_elf
? 查看文件頭信息 $objdump -f main_elf
? 查看反匯編 $objdump -d main_elf
? 查看內(nèi)嵌反匯編 $objdump -S -d main_elf
我一一演示一遍這些命令的使用
🎪1.3objcopy:段剪輯器
objcopy被用來(lái)復(fù)制一個(gè)目標(biāo)文件的內(nèi)容到另一個(gè)文件中,可以使用不同于源文件的格式來(lái)輸出目的文件,即可以進(jìn)行格式轉(zhuǎn)換
去除elf格式信息
$objcopy -O binary -S main_elf main.bin
??2.程序編譯過(guò)程
程序編譯4步驟:
(1)預(yù)處理
C/C++源文件中,以“#”開(kāi)頭的命令被稱為預(yù)處理命令,如包含命令“#include”、宏定義命令“#define”、條件編譯命令“#if”、“#ifdef”等。預(yù)處理就是將要包含(include)的文件插入原文件中、將宏定義展開(kāi)、根據(jù)條件編譯命令選擇要使用的代碼,最后將這些東西輸出到一個(gè)“.i”文件中等待進(jìn)一步處理。
(2)編譯
編譯就是把C/C++代碼(比如上述的“.i”文件)“翻譯”成匯編代碼。
(3)匯編
匯編就是將第二步輸出的匯編代碼翻譯成符合一定格式的機(jī)器代碼,在Linux系統(tǒng)上一般表現(xiàn)為ELF目標(biāo)文件(OBJ文件)。“反匯編”是指將機(jī)器代碼轉(zhuǎn)換為匯編代碼,這在調(diào)試程序時(shí)常常用到。
(4)鏈接
鏈接就是將上步生成的OBJ文件和系統(tǒng)庫(kù)的OBJ文件、庫(kù)文件鏈接起來(lái),最終生成了可以在特定平臺(tái)運(yùn)行的可執(zhí)行文件。
- 一個(gè)標(biāo)準(zhǔn)應(yīng)用程序通常都由鏈接器采用默認(rèn)鏈接腳本(arm-linux-ld --verbose)將“用戶程序” 和“庫(kù)” 共同鏈接生成可執(zhí)行程序
?2.1程序鏈接過(guò)程
鏈接過(guò)程中需要一個(gè)標(biāo)號(hào)(_start)作為程序入口
標(biāo)號(hào)(_start)的作用是: 將用戶程序從匯編帶到了C語(yǔ)言程序入口, 即main()函數(shù), 從此開(kāi)始我們的應(yīng)用程序之旅
2.2指定頭文件
頭文件在哪里?
-
系統(tǒng)目錄
-
系統(tǒng)目錄在哪?工具鏈里的某個(gè)include目錄
-
怎么確定?
echo 'main(){}'| gcc -E -v - // 它會(huì)列出頭文件目錄、庫(kù)目錄(LIBRARY_PATH) -
可以不使用系統(tǒng)include目錄嗎?可以,編譯時(shí)指定參數(shù)-nostdinc
-
-
可以自己指定頭文件目錄
🎪2.3 指定庫(kù)文件
庫(kù)文件在哪里?
-
系統(tǒng)目錄
-
系統(tǒng)目錄在哪?工具鏈里的某個(gè)lib目錄
-
怎么確定?
echo 'main(){}'| gcc -E -v - // 它會(huì)列出頭文件目錄、庫(kù)目錄(LIBRARY_PATH) -
可以不使用系統(tǒng)lib目錄嗎?可以,編譯時(shí)指定參數(shù)-nostdlib
-
-
可以自己指定庫(kù)文件目錄
- 指定庫(kù)文件
?3.裸機(jī)開(kāi)發(fā)流程
*假設(shè)你寫(xiě)了一個(gè)程序名字為uart_test.c
使用命令編譯:arm-linux-gcc uart_test.c -c -o uart.o
鏈接并強(qiáng)行指定main入口為0x48000000:arm-none-linux-gnueabi-ld uart.o -o uart-test -e main -Ttext=0x48000000
把elf文件變?yōu)閎in結(jié)尾的二進(jìn)制文件arm-none-linux-gnueabi-objcopy -O binary -S uart
把生成的.bin結(jié)尾的文件放到windows
linux板子終端進(jìn)入uboot修改環(huán)境變量執(zhí)行setenv loadaddr 0x48000000修改并通過(guò)saveenv進(jìn)行保存,注意環(huán)境變量的地址為你強(qiáng)行指定main函數(shù)的地址
在uboot敲loadb命令等待文件傳輸
打開(kāi)超級(jí)終端serucecrt把.bin文件傳輸?shù)桨遄永?/p>
通過(guò)go 0x48000000 執(zhí)行main函數(shù),這時(shí)一個(gè)完整的程序就可以執(zhí)行了,可以在里面執(zhí)行最簡(jiǎn)單的點(diǎn)燈操作,如下圖所示
總結(jié)
以上是生活随笔為你收集整理的嵌入式系统裸机程序开发与调试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 图片转成pdf下载
- 下一篇: 华旭金卡js调用身份证阅读器和易联众社保