ARM 汇编基础教程番外篇 ——配置实验环境
?
From:https://zhuanlan.zhihu.com/p/29145513
?
win10 arm 匯編環(huán)境
Windows 平臺下搭建 ARM 匯編集成環(huán)境:https://jingyan.baidu.com/article/4b52d70288bfcdfc5c774ba5.html
?
要調(diào)試 ARM 程序,我們需要:
- 能運行 ARM 程序的運行環(huán)境。
- 支持 ARM 架構(gòu)的調(diào)試器。
本篇教程將基于 x86 平臺的 Ubuntu 20,介紹如何搭建 ARM 的交叉編譯、運行和調(diào)試環(huán)境。
?
?
?
交叉編譯環(huán)境
?
Ubuntu 20 的源中提供了多個 arm-gcc 的軟件包,以 gcc 5 為例可以通過 "apt search"?命令找到 "gcc-5-arm-linux-gnueabi"?和 "gcc-5-arm-linux-gnueabihf"?兩個軟件包。這兩個軟件包安裝的編譯工具是一樣的,只是與浮點數(shù)相關(guān)的默認編譯選項不同。由于我們虛擬的環(huán)境沒有 FPU,只需要安裝 "gcc-5-arm-linux-gnueabi"?就可以了。
安裝完成后可以在 "/usr/bin/arm-linux-gnueabi-*" 找到相關(guān)的編譯工具鏈,包含常用的 gcc、as 和 ld 等。
只要使用如下兩條命令,就可以實現(xiàn)對 ARM 匯編的編譯:
$ arm-linux-gnueabi-as [source file] –o [object file] $ arm-linux-gnueabi-ld [object file] –o [executable file]可以使用如下命令編譯經(jīng)典的 "hello world"?程序,用于后續(xù)章節(jié)的實驗:
$ arm-linux-gnueabi-gcc-5 hello.c –g –o hello -static示例截圖:
?
?
arm-linux-gcc 安裝方法
?
From:Ubuntu 18.04安裝arm-linux-gcc交叉編譯器 :https://www.cnblogs.com/tansuoxinweilai/p/11602830.html
方法 一:
我們都知道 Ubuntu 有一個專門用來安裝軟件的工具 apt,我們可以用它來全自動安裝 arm-linux-gcc。
首先 Ctrl+Alt+T 彈出終端,使用如下命令進行 arm-linux-gcc 的安裝:
sudo apt-get install gcc-arm-linux-gnueabihf使用如下命令進行 arm-linux-g++ 的安裝:
sudo apt-get install g++-arm-linux-gnueabihf如果要卸載時使用如下命令進行移除,arm-linux-gcc 的卸載:
sudo apt-get remove gcc-arm-linux-gnueabihfarm-linux-g++ 的卸載:
sudo apt-get remove g++-arm-linux-gnueabihf?
方法 二:
64 位的 Ubuntu 系統(tǒng),那就安裝64位的arm-linux-gcc交叉編譯器,直接安裝就能成功:
例如:arm-linux-gcc-4.6.4-arm-x86_64.tar.bz2??
下載地址:https://pan.baidu.com/s/1xuh8M8bQHfZt_w6h4vRKeg??提取碼:uk85?
1. 先把下載好的安裝包移動到根目錄下的tmp目錄中( /tmp )
2. 使用 tar 命令解壓安裝包,即在Terminal中輸入以下命令:( 前面的 sudo 表示使用 root 權(quán)限執(zhí)行該命令 )
注意是大寫的字母 C,此命令會把安裝包解壓到根目錄下的 opt 的 TuxamitoSoftToolchains里面(/opt/TuxamitoSoftToolchains)
如圖逐層查看找到 gcc-4.6.4 所在的位置:/opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi
3. 解壓完成后,再在(/usr/local)中創(chuàng)建一個新目錄 arm,即在 Terminal 中輸入以下命令:
sudo mkdir /usr/local/arm創(chuàng)建 arm 目錄成功后,還需要給它解放全部權(quán)限,即在 Terminal 中輸入以下命令:
sudo chmod 777 /usr/local/arm4. 在解壓出來的目錄中找到并把整個 gcc-4.6.4目錄復(fù)制到剛剛建好的arm目錄中,命令如下:
先 cd 切換到 gcc-4.6.4 所在目錄(切換后先ls看一下有沒有 gcc-4.6.4 目錄):
cd /opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/再執(zhí)行 cp 復(fù)制命令,-r 表示整個目錄以及里面的任何東西
sudo cp -r gcc-4.6.4 /usr/local/arm5.打開(/etc/profile)配置環(huán)境變量和庫變量,目的是以后可以在任何位置使用該交叉編譯器,命令如下:
sudo vi /etc/profile用 vi 或者 vim 打開后,在文件最后添加兩行,并輸入以下代碼:第一行是添加執(zhí)行程序的環(huán)境變量,第二行是庫文件的路徑
export PATH=$PATH:/usr/local/arm/gcc-4.6.4/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/arm/gcc-4.6.4/lib然后保存退出即可。
6. 使用 source 命令重新加載生效該配置文件
source /etc/profile7.檢驗是否安裝成功,在 Terminal 輸入以下命令輸出版本信息:
arm-linux-gcc -v結(jié)果如圖所示:得到剛剛安裝的4.6.4版
再隨便寫一個 1.c 文件,能編譯成功說明已經(jīng)完美安裝。例如:
arm-linux-gcc 1.c -o pp再 file 命令查看編譯后的是不是 arm 的可執(zhí)行文件:
file pp可以看到編譯后的可執(zhí)行文件是在 32-bit 的 ARM 架構(gòu)上運行的。
?
注意:有些做完上述步驟還是不能用arm-linux-gcc的話,出現(xiàn)如下圖所示錯誤:
這和時候需要在 “/home/用戶名” 目錄下的 ".bashrc" 隱藏文件下加上和 “/etc/profile” 一樣的兩句
export PATH=$PATH:/usr/local/arm/gcc-4.6.4/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/arm/gcc-4.6.4/lib這個 ".bashrc" 是一個隱藏文件,需要? ls -a 命令才能看見!用戶名就是你自己的linux登錄賬號。
同樣用 vi或者vim打開它,在最后添加兩行:
?
?
?
運行環(huán)境
?
QEMU 來創(chuàng)建一個,[教程在這]:https://blog.csdn.net/zerokkqq/article/details/79621769
?
1. qemu-user-static
最簡單的運行環(huán)境是使用 qemu-user-static 模擬運行靜態(tài)編譯的可執(zhí)行程序。
我們可以使用如下命令模擬運行上一節(jié)創(chuàng)建的 hello 程序:
# 首先安裝 qemu-user-static,若已安裝可以忽略這一步 $ sudo apt install qemu-user-static # 直接執(zhí)行 hello 程序 $ qemu-arm-static hello # 啟動 gdbserver 等待 gdb 連接 $ qemu-arm-static –g [gdbserver port] hello上述命令運行后會啟動一個 qemu 自帶的 gdbserver,監(jiān)聽你通過 "-g"?選項指定的端口。可以在另一個窗口中啟動 gdb 進行遠程調(diào)試(遠程調(diào)試的細節(jié),將在第三章介紹)。
?
Linux 下 ARM 程序的編譯運行及調(diào)試:https://www.jianshu.com/p/dc8e263d6466
-
安裝 qemu
sudo apt-get install qemu qemu-arm-static qemu-kvm-extras
-
arm 程序的編譯運行
- 編譯:arm-linux-gcc -o hello-arm hello.c
- 運行:qemu-arm hello-arm
-
安裝 gdb-multiarch
sudo apt-get install gdb-multiarch
-
arm 程序的調(diào)試
- 利用 gdb 對 qemu-arm 運行的程序進行遠程 gdb 調(diào)試,首先是在終端中輸入如下指令等待調(diào)試:qemu-arm -g 1234 hello-arm
- 再打開另外一個終端,并在其中利用 arm-linux-gdb 進入調(diào)試器,并通過端口 1234 連接到 qemu-arm 等待調(diào)試的程序:gdb-multiarch hello-arm
?
?
2. 虛擬 Raspberry
ARM匯編學(xué)習(xí)(一)搭建ARM匯編模擬環(huán)境(?圖文教程?):https://www.veryarm.com/65170.html
qemu-user-static 的方式比較簡單,但功能也很局限,Azeria-labs 的教程中介紹了另一種方法,使用 qemu 創(chuàng)建一臺虛擬樹莓派。首先你需要安裝 qemu-system :
$ sudo apt install qemu-system為了虛擬一臺樹莓派,你還需要下載專為樹莓派定制的debian鏡像(raspbian)和支持樹莓派的內(nèi)核文件。
raspbian鏡像下載地址:https://www.raspberrypi.org/downloads/raspbian/
樹莓派內(nèi)核下載地址:https://github.com/dhruvvyas90/qemu-rpi-kernel
?
Raspbian 的鏡像有兩個版本,一個帶圖形界面的完整版和一個沒有圖形界面的 lite 版本,對于我們的實驗而言 lite 版本就足夠了。內(nèi)核文件有多個,選擇內(nèi)核版本最新的那個就可以了。下載完上述文件后,創(chuàng)建一個“arm_vm”目錄,將上述文件一起放置在該目錄下。然后執(zhí)行如下命令:
$ unzip <image-file>.zip $ fdisk –l <image-file>你應(yīng)該可以看到,類似如下內(nèi)容:
Disk 2017-08-16-raspbian-stretch-lite.img: 1.7 GiB, 1854418944 bytes, 3621912 sectorsUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisklabel type: dosDisk identifier: 0xee397c53Device Boot Start End Sectors Size Id Type2017-08-16-raspbian-stretch-lite.img1 8192 93813 85622 41.8M c W95 FAT32 (LBA)2017-08-16-raspbian-stretch-lite.img2 94208 3621911 3527704 1.7G 83 Linux注意標紅的部分,可以看到文件系統(tǒng)從94208扇區(qū)開始。我們將這個值乘以512,本例中為“94208 * 512=48234496”,這就是文件系統(tǒng)其實位置的偏移字節(jié)數(shù),在下面的命令中我們會用到:
$ sudo mkdir /mnt/raspbian $ sudo mount -v -o offset=48234496 -t ext4 [path-of-your-img-file.img] /mnt/raspbian $ sudo vi /mnt/raspbian/etc/ld.so.preload 將上述文件中的所有內(nèi)容用“#”注釋掉,保存修改并退出。 $ sudo vi /mnt/raspbian/etc/fstab如果fstab文件中有出現(xiàn)mmcblk0字符串,那么將“/dev/mmcblk0p1”替換為“/dev/sda1”,將“/dev/mmcblk0p2”替換為“/dev/sda2”,保存后退出。至此,系統(tǒng)配置的修改完成,可以將“/mnt/raspbian”卸載掉。
$ sudo umount /mnt/raspbian你可以進入“arm_vm”目錄,使用如下腳本啟動虛擬機:
#!/usr/bin/env bashqemu-system-arm -kernel kernel-qemu-4.4.34-jessie \ -cpu arm1176 \ -m 256 \ -M versatilepb \ -serial stdio \ -append "root=/dev/sda2 rootfstype=ext4 rw" \ -drive format=raw,file=2017-08-16-raspbian-stretch-lite.img \ -redir tcp:5022::22 \# 為ssh預(yù)留 -redir tcp:3011::3011 \# 為gdbserver預(yù)留,用于遠程調(diào)試 -no-reboot 1> /dev/null 2>&1 &虛擬機啟動后默認的登錄密碼是“raspberry”。為了更方便的使用虛擬機,我們需要開啟ssh服務(wù),并設(shè)置開機啟動。
$ sudo service ssh start $ sudo update-rc.d ssh enable此時,你應(yīng)該已經(jīng)可以使用如下命令,通過ssh訪問虛擬機了:
$ ssh pi@127.0.0.1 -p 5022我們可以使用scp命令通過ssh,將上一節(jié)編譯的hello程序上傳到虛擬機中執(zhí)行:
scp -P 5022 hello pi@127.0.0.1:/tmp進入虛擬機的tmp目錄,可以看到我們上傳的hello程序嘗試執(zhí)行,應(yīng)該會輸出久違的“hello world!”,說明我們的交叉編譯環(huán)境搭建是正確的。至此我們的虛擬樹莓派環(huán)境搭建完畢。
?
?
調(diào)試環(huán)境
調(diào)試環(huán)境的搭建是最重要的也是坑最多的。為了模擬真實IoT安全實戰(zhàn)中遠程調(diào)試的場景,我們將介紹如何交叉編譯gdbserver并上傳至虛擬機進行遠程調(diào)試。為了獲得類似pwndbg那樣強大的調(diào)試效果,我們將介紹如何安裝使用專為IoT安全設(shè)計的gef增強腳本。
?
1. gdb-multiarch
在使用gdb進行調(diào)試之前,我們需要先安裝gdb-multiarch。顧名思義,它是gdb支持多中硬件體系架構(gòu)的版本。之所以要安裝gdb-multiarch,是因為Ubuntu默認安裝的gdb只支持x86/x64架構(gòu),你可以啟動gdb然后輸入命令“set
architecture arm”查看,gdb會提示錯誤。
?
2. 編譯 gdbserver
在分析IoT設(shè)備的安全性時,我們往往需要上傳gdbserver進行遠程調(diào)試。在我們的實驗環(huán)境中(事實上我們的Raspbian系統(tǒng)自帶gdb),我們也可以模擬搭建一個遠程調(diào)試環(huán)境。首先,我們需要獲取gdb的源碼(包含了gdb源碼和gdbserver源碼),版本需要與我們本地的gdb版本一致,因為gdbserver需要與gdb版本保持一致,否則容易出現(xiàn)非預(yù)期的問題。你可以在這個地址,找到gdb各版本的源碼:http://ftp.gnu.org/gnu/gdb/。
?
下載解壓后進入“gdb-<version>/gdb/gdbserver”目錄,使用如下命令編譯安裝:
$CC="arm-linux-gnueabi-gcc-5" CXX="arm-linux-gnueabi-g++-5" ./configure --target=arm-linux-gnueabi --host="arm-linux-gnueabi" --prefix="setup-directory" $ make install然后,在你通過“--prefix”選項指定的路徑下,就可以找到編譯完成的gdbserver了。使用file命令查看,應(yīng)該可以看到類似如下輸出:
$ file arm-linux-gnueabi-gdbserver arm-linux-gnueabi-gdbserver:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=32ad2025951ee428276ac2fbadb199bfd39e2278, not stripped使用scp將gdbserver上傳到我們的虛擬樹莓派中并啟動:
$ ln -s arm-linux-gnueabi-gdbserver gdbserver $ gdbserver 0.0.0.0:2333 hello Process hello created; pid = 702 Listening on port 2333至此,我們的遠程調(diào)試環(huán)境搭建完畢,下一節(jié),我們將引入gef增強腳本。
?
3. gef 增強腳本
gef是一個支持多種硬件體系結(jié)構(gòu)的gdb增強腳本,非常適合IoT安全領(lǐng)域應(yīng)對多變的硬件平臺。你可以參考github主頁(https://github.com/hugsy/gef)的README,進行安裝配置。不過需要注意的是,gef依賴的第三方模塊keystone-engine需要手動安裝,因為pip源提供的安裝是無效的。建議先通過pip安裝,如果安裝后gef的部分功能仍無法使用,可以卸載通過pip安裝的第三方模塊,在github上(https://github.com/keystone-engine/keystone)下載最新源碼,手動編譯安裝(參見:http://www.keystone-engine.org/docs/)。
安裝完成后開啟gdb調(diào)試,你將看到類似如下的界面:
首先設(shè)置目標硬件體系架構(gòu)為arm:
gef> set architecture arm
我們使用gef-remote命令連接gdbserver,如果使用gdb自帶的“target remote”命令會出現(xiàn)一些非預(yù)期的問題(參見:https://github.com/hugsy/gef/issues/7)。
gef> gef-remote –q 127.0.0.1:2333
你應(yīng)該能看到類似如下的輸出:
至此,我們的調(diào)試環(huán)境配置完畢了。
?
?
擴展閱讀
?
[1] gef官方文檔,http://gef.readthedocs.io/en/master/
[2] gdb調(diào)試利器,http://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html
[3] gdb中應(yīng)該知道的幾個調(diào)試方法,https://coolshell.cn/articles/3643.html
本文由看雪翻譯小組 ljcnaix 原創(chuàng) 轉(zhuǎn)載請注明來自看雪社區(qū)
?
?
?
ARM匯編 與 ARM GNU匯編 區(qū)別
?
ARM 匯編 與 ARM GNU匯編 區(qū)別:https://blog.csdn.net/tabactivity/article/details/90054443
?
一、ARM匯編開發(fā)的兩種的方式
ARM 匯編開發(fā),有兩種開發(fā)方式,一種是使用 ARM 匯編,一種是使用 ARM GNU 匯編。兩種匯編開發(fā),使用的匯編指令是完全一樣的,區(qū)別是宏指令,偽指令,偽操作不一樣。其實兩種開發(fā)方式的區(qū)別在于所使用的編譯工具不一樣。
對于 ARM 匯編,使用的是 ARM 公司開發(fā)的編譯器,而 ARM GNU 匯編,是使用 GNU 為 ARM 指令集開發(fā)的編譯器,也就是arm-gcc。
?
二、ARM的編譯開發(fā)環(huán)境
兩種常用的 ARM 的編譯開發(fā)環(huán)境
-
DS5:ARM 提供的集成開發(fā)軟件。使用的是 ARM 提供的工具鏈進行程序編譯
-
GNU 開發(fā)環(huán)境: 由 GNU 的匯編器 as,交叉編譯器 gcc,和 鏈接器ld 等組成
?
三、偽操作,宏指令,偽指令
- 偽操作:ARM 匯編語言程序里的一些特殊指令助記符,其作用主要是完成匯編程序做各種準備工作,在源程序進行匯編時由匯編程序處理,而不是在計算機運行期間由機器執(zhí)行。如程序段的定義,就屬于偽操作。
- 宏指令:一段獨立的程序代碼,可插在源程序中,通過偽操作來定義。
- 偽指令:ARM 匯編語言程序里的一些特殊指令助記符,不在處理器運行期間執(zhí)行,在匯編時,被合適的ARM的機器指令代替,從而實現(xiàn)真正的指令操作。
?
四、ARM 匯編偽操作
| 偽操作 | 語法格式 | 作用 |
| GBLA | GBLA ?Varible | 聲明一個全局的算術(shù)變量,并將其初始化為0 |
| GBLL | GBLL ?Varible | 聲明一個全局的邏輯變量,并將其初始化成{FALSE} |
| GBLS | GBLS ?Varible | 聲明一個全局的字符串變量,并將其初始化成空串 |
| LCLA | LCLA ?Varible | 聲明一個局部的算術(shù)變量,并將其初始化為0 |
| LCLL | LCLL ?Varible | 聲明一個局部的邏輯變量,并將其初始化成{FALSE} |
| LCLS | LCLS ?Varible | 聲明一個局部的字符串變量,并將其初始化成空串 |
| SETA | SETA ?Varible ?expr | 給一個全局或局部算術(shù)變量賦值 |
| SETL | SETL ?Varible ?expr | 給一個全局或局部邏輯變量賦值 |
| SETS | SETS ?Varible ?expr | 給一個全局或局部字符串變量賦值 |
| RLIST | name LIST {list of registers} | 為一個通用寄存器列表定義名稱 |
| CN | name CN expr | 為一個協(xié)處理器的寄存器定義名稱 |
| CP | name CP expr | 為一個協(xié)處理器定義名稱 |
| DN/SN | name DN/SN expr | DN/SN為一個雙精度/單精度的VFP寄存器定義名稱 |
| FN | name FN ?expr | 為一個FPA浮點寄存器定義名稱 |
| LTORG | LTONG | 聲明一個數(shù)據(jù)緩沖池(文字池)的開始 |
| MAP | MAP expr {, base-register} | 定義一個結(jié)構(gòu)化的內(nèi)存表(storage map)的首地址 |
| FIELD | {label} ?FIELF ?expr | 定義一個結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域 |
| SPACE | {label} ?SPACE ?expr | 分配一塊連續(xù)內(nèi)存單元,并用0初始化 |
| DCB | {label} ?DCB ?expr {,expr}.. | 分配一塊字節(jié)內(nèi)存單元,并用expr初始化 |
| DCD/ DCDU | {label} DCD/DCDU expr {,expr}… | 分配一塊字內(nèi)存單元, 并用expr初始化 |
| DCDO | {label} ?DCDO ?expr {,expr}… | 分配一塊字對齊的字內(nèi)存單元, 并用expr初始化 |
| DCFD/DCFDU | {label} ? DCFD{U} ? fpliteral ,{,fpliteral}… | 為雙精度的浮點數(shù)分配字對齊的內(nèi)存單元 |
| DCFS/DCFSU | {label} ? ?DCFS{U} ?fpliteral ,{,fpliteral}… | 為單精度的浮點數(shù)分配字對齊的內(nèi)存單元 |
| DCI | {label} DCI expr, {expr}… | ARM代碼分配一段字對齊的內(nèi)存單元,填充expr(二進制指令碼),THUMB代碼中,分配一段半字對齊的半字內(nèi)存單元。 |
| DCQ/ DCQU | {label} DCQ{U} ?{-} literal, {, {-} literal}… | 分配一段以雙字(8個字節(jié))為單位的內(nèi)存 |
| DCW/DCWU | {label} DCW{U} ?{-} literal, {, {-} literal}… | DCW用于分配一段半字對齊的半字內(nèi)存單元 |
?
-
1、AREA:創(chuàng)建一段新的程序代碼或數(shù)據(jù)區(qū)。? ? ? ??
?? ??? ?格式 : ??AREA ?name, {,attr,} …
? ? ? ? 其中,name是程序段名, atrr是段名屬性
? ? ? ? 對于屬性,有以下一些:
? ? ? ? ? ? ? ? CODE: 用于定義代碼段,默認為是READONLY
? ? ? ? ? ? ? ? DATA: 用于定于數(shù)據(jù)段,默認為READWRITE
? ? ? ? ? ? ? ? READONLY: 指定本段的內(nèi)容只讀
? ? ? ? ? ? ? ? READWRITE: ?指定本段的內(nèi)容可讀可寫
? ? ? ? ? ? ? ? ALIGN: ?指定對齊為2次冪
? ? ? ? ? ?COMMON: 定義通用的段。不包含任何用戶的代碼和數(shù)據(jù)。各源文件中同名的COMMON屬性段共享同一段存儲單元 - 2、ALIGN:指定對齊
? ? ? ? ? ? ALIGN ?4 ?表示4字節(jié)地址對齊
? ? ? ? ? ? ALIGN ?8 ?表示8字節(jié)地址對齊
? ? ? ? ? ? 注意:在AREA中使用和單獨使用ALIGN的區(qū)別,在于格式和對齊的計算不一樣。 - 3、ENTRY:指定匯編程序的入口。
? ? ? ? 一個程序至少有一個入口點,也可以有多個入口點,但是在一個源文件中,最多只能有一個ENTRY。
? ? ? ? 當(dāng)多個源文件均有ENTRY時,由鏈接器指定程序真正的入口。 - 4、END:表示源程序的結(jié)束。所以匯編語言源文件必須以END結(jié)束,匯編器遇到END, 將結(jié)束編譯。
- 5、EXPORT
? ? ? ? 格式: EXPORT ?標號 ?[,WEAK]
? ? ? ? 聲明一個全局標號,其他源文件可以使用這個標號。WEAK表示碰上其他同名標號時,其他標號優(yōu)先。 -
6、IMPORT
? ? ? ? 格式: ??IMPORT 標號,[,WEAK]
? ? ? ? 表示該引用的標號在其他源文件中,單要在當(dāng)前文件中引用。
? ? ? ? WEAK表示找不到該標號時,也不報錯,一般該標號置為0,如果是B 或BL指令用到該標號,該指令置為nop。
? ? ? ? 該標號會加入到當(dāng)前源文件的符號表中。 - 7、EXTERN:和 IMPORT 一樣,不同在于,如果當(dāng)前文件沒有引用該標號,該標號不會加入到當(dāng)前源文件的符號表中。
- 8、GET ( 或 INCLUDE ):將一個源文件包含到當(dāng)前的源文件中
- 9、EQU:對一個常量標號賦值
? ? ? ? 格式: ?name ??EQU ??expression
? ? ? ? 其中: name符號名, expression寄存器相關(guān)或者程序相關(guān)的固定值
? ? ? ? 如:num ??EQU ??2 ?; ?為符號賦予數(shù)字2
? ? ? ? EQU,等同于C語言中用#define定義一個常量 - 10、SPCAE:用于分配一片連續(xù)內(nèi)存單元,并用0初始化。SPACE 可用 % 代替。
? ? ? ? 格式: {label} SPACE expr
? ? ? ? label : 是一個標號, 可選
? ? ? ? expr: ??分配的內(nèi)存字節(jié)數(shù)
? ? ? ? 如:stack SPACE 100 ; 分配100個字節(jié)內(nèi)存單元,并用0初始化。標號stack是這片空間的起始地址 - 11、DCB:用于分配段字節(jié)內(nèi)存單元,并用偽操作中的expr初始化。
? ? ? ? 格式: {label} DCB expr {,expr}
? ? ? ? label: 是一個標號,可選
? ? ? ? expr: 可以是-128~255的數(shù)值或者字符串
? ? ? ? 如:string ?DCB ?"HELLO" ??;為HELLO字符串分配空間, string是這塊空間的起始地址 - 12、DCD 及 DCDU:用于分配段字內(nèi)存單元(分配的內(nèi)存都是字對齊,DCDU并不嚴格字對齊),并用偽操作中的expr初始化。 DCD 可用 & 代替。
? ? ? ? 格式: {label} DCD expr, {,expr}
? ? ? ? label: 是一個標號,可選,表示這塊內(nèi)存單元的首地址
? ? ? ? expr: 數(shù)字表達式或程序中的標號
? ? ? ? 如:data DCD ?1,2,3,4 ????;分配字對齊的字單元空間,初始化為1,2,3,4
?
?
五、ARM匯編偽指令
?
ARM偽指令包括: ADR, ADRL,LDR ,NOP
THUMB偽指令包括:ADR, LDR, NOP
| 偽指令 | 語法格式 | 作用 |
| ADR | ADR{cond} register, expr | 將基于PC或基于寄存器的地址值讀取到寄存器中。小范圍的地址讀取 |
| ADRL | ADRL{cond} register, expr | 將給予PC或基于寄存器的地址值讀取到寄存器中。中等范圍的地址讀取 |
| LDR | LDR {cond} register, =[expr|label] | 將一個32位的立即數(shù)或者一個地址值讀取到寄存器中。大范圍的地址讀取 |
| NON | NOP | 在匯編時,被替換成空操作 |
?
六、ARM GNU 編譯環(huán)境
?
| 偽操作 | 語法格式 | 作用 |
| .byte | .byte expr {,expr}… | 分配一段字節(jié)內(nèi)存單元,并用expr初始化 |
| .hword/.short | .hword expr {,expr}… | 分配一段半字內(nèi)存單元,并用expr初始化 |
| .ascii | .ascii expr {,expr}… | 定義字符串expr |
| .asciz/.string | .asciz expr {,expr}… | 定義字符串expr(會增加/0為結(jié)束符) |
| .floar/.single | .float expr {,expr}… | 定義32bit IEEE浮點數(shù)expr |
| .double | .doubel expr {,expr}… | 定義64bit IEEE浮點數(shù)expr |
| .word/.long/.int | .word expr {,expr}… | 分配一段字內(nèi)存單元,并用expr初始化 |
| .fill | .fill ?repeat {,size} {,value} | 分配一段字節(jié)內(nèi)存單元,用sieze長度value填充repeat次 |
| .zero | .zero size | 分配一段字節(jié)內(nèi)存單元,并用0填充內(nèi)存 |
| .space/.skip | .space size, {,value} | 分配一段內(nèi)存單元,用value將內(nèi)存初始化 |
| .section | .section expr | 定義一個段 |
| .text | .text {subsection} | 代碼段, |
| .data | .data{subsection} | 數(shù)據(jù)段 |
| .bss | .bss{subsection} | bss段 |
| .cond 16/.thumb | .code 16/.thumb | 表示之后的匯編指令使用THUMB指令集 |
| .code 32/.arm | .code 32/.arm | 表示之后的匯編指令使用ARM指令集 |
| .end | .end | 標記匯編文件的結(jié)束 |
| .include | .include "filename" | 將一個源文件包含到當(dāng)前源文件中 |
| .align/.balign | .align {alignment} {,fill},{max} | 通過填充字節(jié)使當(dāng)前位置滿足一定的對齊格式 |
?
七、兩種開發(fā)環(huán)境的區(qū)別
?
兩種開發(fā)環(huán)境下的匯編代碼,有較多不同的點,主要是符號及偽操作的不同。
| ARM匯編的偽操作符 | GNU匯編的偽操作符 |
| INLCUDE | .include |
| NUM ? ?EQU ? 25 | .equ ?NUM, ?25 |
| EXPORT | .global |
| IMPORT | .extern |
| DCD | .long |
| IF: ?DEF: | .ifdef |
| ELSE | .else |
| ENDIF | .endif |
| OR | | |
| SHL | << |
| RN | .req |
| GBLA | .global |
| NUM ?SETA 16 | .equ ? NUM , 16 |
| MACRO | .macro |
| MEND | .endm |
| END | .end |
| AREA WORD, CODE, READONLY | .text |
| AREA BLOCK, DATE, READWRITE | .data |
| CODE32 | .arm |
| CODE16 | .thumb |
| LTORG | .ltorg |
| % | .fill |
| ENTRY | ENTRY: |
| ldr x0,=0xff | ldr x0,=0xff |
原文鏈接:http://www.lujun.org.cn/?p=3943
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的ARM 汇编基础教程番外篇 ——配置实验环境的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Inspeckage,安卓动态分析工具
- 下一篇: 《MFC初探》之变量类型