做者 : 韓曙亮html
博客地址 : http://blog.csdn.net/shulianghan/article/details/42408137 linux
轉載請著名出處編程
本博客相關文檔下載 : 緩存
-- ARM 彙編手冊 : http://download.csdn.net/detail/han1202012/8328375sass
-- ARM 手冊 : http://download.csdn.net/detail/han1202012/8324641app
-- ARM 9 芯片文檔 : http://download.csdn.net/detail/han1202012/8332389框架
-- ARM 11 芯片文檔 : http://download.csdn.net/detail/han1202012/8332403eclipse
彙編位置 : 工具
-- 啓動代碼 : Bootloader 初始化時對 CPU 和 協處理器 等進行初始化, 此時沒有創建起 C 語言運行環境, 這個時候使用匯編語言執行初始化操做;學習
-- 效率要求 : 彙編效率高, Linux 內核中, 對效率有特殊要求的地方須要彙編;
ARM 標準彙編簡介 :
-- 使用場景 : 適用於ARM公司的彙編器, 適合在 Windows 平臺使用, 如ADS;
GNU 彙編簡介 :
-- 使用場景 : 適用於 Linux 平臺交叉編譯工具鏈的彙編器;
ARM 彙編框架 :
-- ARM 彙編框架示例 :
.section .data < 初始化的數據> .section .bss < 未初始化的數據> .section .text .global _start _start: <彙編代碼>-- 程序入口 : "_start:" 是彙編程序的入口, 至關於 main();
-- 標註入口 : 使用 ".global _start" 標註程序入口, 外部才能夠識別這是程序入口;
-- 標明代碼段 : ".section .text" 標明這是一個代碼段;
-- 標明 bss 段 : 使用 ".section .bss" 標明bss段, 若是沒有 bss 段 和 數據段, 直接從 .text 開始;
程序代碼 :
-- 定義代碼段 : .text ;
-- 定義程序入口 : .globl _start;
-- 代碼示例 :
.text .globl _start _start: mov r1,#1 mov r2,#2 mov r3,#3
Makefile 代碼 :
-- 連接 elf 格式文件 : 設置程序起始位置 6410板子是 0x50008000 地址;
-- 在 arm-linux-ld 指定程序起始地址 : 在 -Ttext 50008000 便可;
-- 若是使用連接器腳本指定地址 : 注意第三行指定程序起始地址;
SECTIONS { . = 0x50008000; . = ALIGN(4); .text : { led.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); .bss (NOLOAD) : { *(.bss) . = ALIGN(4); } }
-- 代碼示例 :
all:start.o arm-linux-ld -Ttext 0x50008000 -o start.elf $^ %.o:%.S arm-linux-gcc -g -o $@ $^ -c clean: rm -rf *.o *.elf
JLink 調試啓動 :
-- 確保驅動安裝 : 注意 要安裝 Windows 驅動;
-- 鏈接 JLink : 虛擬機右下角鏈接 JLink;
-- 啓動 JLinkGDBServer :
[root@localhost JLink_Linux_V434a]# ./JLinkGDBServer SEGGER J-Link GDB Server V4.34a JLinkARM.dll V4.34a (DLL compiled Aug 31 2011 11:51:40) Listening on TCP/IP port 2331 J-Link connected Firmware: J-Link ARM V8 compiled Aug 24 2011 17:23:32 Hardware: V8.00 S/N: 17935099 Feature(s): RDI,FlashDL,FlashBP,JFlash J-Link found 2 JTAG devices, Total IRLen = 5 JTAG ID: 0x07B76F0F (ARM11)
搭建 eclipse 調試環境 :
-- 導入工程 : 選擇 Makefile Project With Existing Code;
-- 選擇導入的代碼位置 :
-- clean 代碼 : 選擇 "Project" --> "Clean";
-- build 工程 : 選擇 "菜單" --> Project --> Build All 選項便可;
-- 配置 Debug 調試參數 :
-- 執行調試 : F6 單步調試走兩步, 能夠再 Register 視圖中查看寄存器的值, 能夠看到 r1 和 r2 被賦值爲 1 和 2 了;
ARM 彙編手冊 :
-- CSDN 下載地址 : http://download.csdn.net/detail/han1202012/8328375.
GNU 彙編 與 ARM 標準彙編區別 : 上面的手冊是 ARM 標準彙編手冊, 咱們寫的是 GNU 彙編手冊, 有必定區別;
-- 大小寫區別 : ARM 標準彙編 都是大寫的, GNU 彙編能夠是小寫字母;
MOV 指令簡介 : 賦值操做;
-- 語法格式 : MOV <dest>, <op1>;
-- 語法解析 : dest 是目的寄存器, op1 能夠是當即數, 也能夠是寄存器, 地址等, 等價於 dest = op1;
彙編程序註釋 : 彙編中使用 "@" 符號添加註釋;
示例代碼 :
.text .global _start _start: @mov 指令範例 mov r1, #8 @將 8 賦值給 r1 mov r2, r1 @將 r1 中的值賦值給 r2 mov r3, #10 @將 10 賦值給 r3 寄存器
MVN 指令簡介 : 取反賦值操做;
-- 語法格式 : MVN <dest>, <op1>;
-- 語法解析 : 將操做數 op1 取反後 賦值給 dest;
指令示例 :
-- 代碼 :
.text .global _start _start: @mvn 指令範例 mvn r1, #0b10 @0b10 二進制數取反, 賦值給 r1 mvn r2, #5 @5 十進制數取反, 賦值給 r2 mvn r3, r1 @將 r1 寄存器的值, 賦值給 r3
SUB 指令簡介 : 減法操做;
-- 語法格式 : SUB <dest>, <op1>, <op2>;
-- 語法解析 : dest 存放減法結果, op1 是減數, op2 是被減數, dest = op1 - op2;
-- 注意 : dest op1 都不能使用當即數, op2 可使用當即數;
代碼示例 :
.text .global _start _start: @sub 指令範例 @sub r1, #4, #2 錯誤示例, 減數不能是當即數, 必須是寄存器 mov r2, #4 sub r1, r2, #4 mov r0, #1 sub r3, r1, r0
ADD 指令簡介 : 加法操做;
-- 語法格式 : ADD <dest>, <op1>, <op2>;
-- 語法解析 : dest 存放加法結果, op1 和 op2 是相加的兩個數, dest = op1 + op2;
-- 注意 : dest op1 都不能使用當即數, op2 可使用當即數;
代碼示例 :
@add 指令範例 mov r2, #1 add r1, r2, #3
AND 指令簡介 : 邏輯與操做;
-- 語法格式 : AND <dest>, <op1>, <op2>;
-- 語法解析 : dest 存放邏輯與結果, op1 和 op2 是相與的兩個數, dest = op1 & op2;
-- 注意 : dest op1 都不能使用當即數, 必須使用寄存器, op2 可使用當即數;
代碼示例 :
.text .global _start _start: @and 指令範例 mov r1, #5 and r2, r1, #0 mov r1, #5 mov r2, r1, #1
BIC 指令簡介 : 位清除指令操做;
-- 語法格式 : AND <dest>, <op1>, <op2>;
-- 語法解析 : dest 存放位清除結果, op1 是被清除的對象, op2 是掩碼;
-- 示例 : "bic r0, r0, #0b1011", 清除 r0 中的 第0, 1, 3 位, 其他位保持不變, 結果放入 r0 中;
-- 注意 : dest op1 都不能使用當即數, 必須使用寄存器, op2 可使用當即數;
-- 二進制表示 : 掩碼中 % 在標準彙編中表示二進制, 可是在 GNU 彙編中沒法使用, GNU 彙編中使用 0b 表明二進制;
代碼示例 :
.text .global _start _start: @bic 指令範例 mov r1, #0b101011 bic r2, r1, #0b101 @將r1 的 0, 2 位清除
CMP 指令簡介 : 比較指令;
-- 語法格式 : CMP <op1>, <op2>;
-- 語法解析 : 比較結果有三種 op1 > op2 (CPSR N = 0), op1 = op2 (CPSR Z = 1), op1 < op2 (CPSR N = 1), 結果放入 CPSR 寄存器;
代碼示例 :
.text .global _start _start: @cmp 指令範例 mov r1, #2 cmp r1, #1 mov r1, #2 cmp r1, #3 mov r1, #2 cmp r1, #2
TST 指令簡介 : 比較指令;
-- 語法格式 : TST <op1>, <op2>;
-- 語法解析 : op1 和 op2 按位與操做, 結果影響 CPSR 寄存器, 若是結果 不爲 0, CPSR 的 Z = 0, 若是結果爲0, Z = 1;
代碼示例 :
.text .global _start _start: @cmp 指令範例 mov r1, #0b101 tst r1, #0b001 @按位與結果是 0b1, 結果不爲0, CPSR Z = 0 mov r1, #0b101 tst r1, #0b10 @按位與結果是 0, 結果不爲
B 指令簡介 : 分支指令;
-- 語法格式 : B{條件} 地址;
-- 語法解析 : 若是知足條件, 就跳轉到 地址 位置, 若是不知足條件, 就執行下面的語句, 若是沒有條件, 就是 100% 執行;;
代碼示例 :
-- 條件分析 : gt 是大於條件, 若是 r1 > r2 就走條件分支, 不然就繼續執行下一條;
.text .global _start _start: @b 分支指令範例 mov r1, #6 mov r2, #5 cmp r1, r2 @比較 r1 和 r2 中的值 @b 後能夠跟一個條件, {條件} 在 {} 中就是可加可不加, 若是沒有條件就是無條件100%執行 @gt 是大於條件指令, 若是條件知足會跳轉到 branch1, 若是不知足就執行下面的指令 bgt branch1 add r3, r1, r2 b end @這裏爲了避免執行 branch1 操做, 直接跳轉到 end 執行 branch1: sub r3, r1, r2 end: nop
BL 指令簡介 : 帶鏈接的分支指令;
-- 語法格式 : BL{條件} 地址;
-- 語法解析 : 若是知足條件, 就跳轉到 地址 位置, 若是不知足條件, 就執行下面的語句, 若是沒有條件, 就是 100% 執行;;
代碼示例 :
.text .global _start _start: @bl 帶鏈接的分支指令範例 mov r1, #2 cmp r1, #1 @此時跳轉到 func1, func1 執行完程序沒法返回, 若是 使用 bl 跳轉, 程序會返回 @b func1 @此時使用 bl 跳轉到 func1 執行, func1 執行完畢後會返回執行下面的語句 bl func1 mov r1, #2 cmp r1, #3 func1: mov r1, #2 cmp r1, #2 mov r1, #4 cmp r1, #6
LSL 指令簡介 : 邏輯左移指令;
-- 語法格式 : Rx, LSL#2;
-- 語法解析 : 將 Rx 寄存器中的值, 左移2 位;
代碼示例 :
.text .global _start _start: @lsl 左移指令範例 mov r1, #0b1 @將 r1 中的值, 左移 2 位, 放入 r1 寄存器中 mov r1, r1, lsl#2
ROR 指令簡介 : 循環右移指令;
-- 語法格式 : Rx, ROR#2;
-- 語法解析 : 將 Rx 寄存器中的值 循環右移 2 位;
代碼示例 :
.text .global _start _start: @ror 循環右移指令範例 mov r1, #0b11 @結果是 ob1000...0001 mov r1, r1, ror#1
程序狀態字 : CPSR 和 SPSR;
-- 注意 : 程序狀態字 不能使用 通用寄存器的語句 如 MOV 等訪問, 必須使用 程序狀態寄存器的 專用指令 讀寫;
代碼示例 :
.text .global _start _start: @mrs 指令範例 @rs 是 將 s -> r, sr 是 r -> s mrs r0, cpsr @將 cpsr 中的數據搬移到 r0 中 orr r0, #0b100 @將 cpsr 中的第三位置爲1 msr cprs, r0
STR 指令簡介 : 將 寄存器中的值 保存到 內存中;
-- 語法格式 : str r0, 地址;
-- 語法解析 : 將 R0 寄存器中的值 保存到 內存地址中;;
代碼示例 :
.text .global _start _start: @str 指令範例 mov r0, #0xff @將 r1 值改成 50000000 (OK-6410) str r0, [r1]
-- 調試 : 添加地址監控, 在 Memory 視圖中進行監控;
LDR 指令簡介 : 將 寄存器中的值 保存到 內存中;
-- 語法格式 : ldr r0, 地址;
-- 語法解析 : 將 內存地址中 存放的值 加載入 r0 中;
代碼示例 :
@ldr 指令範例 mov r0, #0xff @將 r1 值改成 50000000 (OK-6410) str r0, [r1] ldr r0, [r1]
以上全部代碼示例 : 便於調試學習;
.text .global _start _start: @ldr 指令範例 mov r0, #0xff @將 r1 值改成 50000000 (OK-6410) str r0, [r1] ldr r0, [r1] @str 指令範例 mov r0, #0xff @將 r1 值改成 50000000 (OK-6410) str r0, [r1] @mrs msr 指令範例 @rs 是 將 s -> r, sr 是 r -> s mrs r0, cpsr @將 cpsr 中的數據搬移到 r0 中 orr r0, #0b100 程序入口, 用法 ".globol _start", 注意前面加上點;@將 cpsr 中的第三位置爲1 msr cprs, r0 @ror 循環右移指令範例 mov r1, #0b11 @結果是 ob1000...0001 mov r1, r1, ror#1 @lsl 左移指令範例 mov r1, #0b1 @將 r1 中的值, 左移 2 位, 放入 r1 寄存器中 mov r1, r1, lsl#2 @bl 帶鏈接的分支指令範例 mov r1, #2 cmp r1, #1 @此時跳轉到 func1, func1 執行完程序沒法返回, 若是 使用 bl 跳轉, 程序會返回 @b func1 @此時使用 bl 跳轉到 func1 執行, func1 執行完畢後會返回執行下面的語句 bl func1 mov r1, #2 cmp r1, #3 func1: mov r1, #2 cmp r1, #2 mov r1, #4 cmp r1, #6 @b 分支指令範例 mov r1, #6 mov r2, #5 cmp r1, r2 @比較 r1 和 r2 中的值 @b 後能夠跟一個條件, {條件} 在 {} 中就是可加可不加, 若是沒有條件就是無條件100%執行 @gt 是大於條件指令, 若是條件知足會跳轉到 branch1, 若是不知足就執行下面的指令 bgt branch1 add r3, r1, r2 b end @這裏爲了避免執行 branch1 操做, 直接跳轉到 end 執行 branch1: sub r3, r1, r2 end: nop @cmp 指令範例 mov r1, #0b101 tst r1, #0b001 @按位與結果是 0b1, 結果不爲0, CPSR Z = 0 mov r1, #0b101 tst r1, #0b10 @按位與結果是 0, 結果不爲 @cmp 指令範例 mov r1, #2 cmp r1, #1 mov r1, #2 cmp r1, #3 mov r1, #2 cmp r1, #2 @bic 指令範例 mov r1, #0b101011 bic r2, r1, #0b101 @將r1 的 0, 2 位清除 @and 指令範例 mov r1, #5 and r2, r1, #0 mov r1, #5 mov r2, r1, #1 @add 指令範例 mov r2, #1 add r1, r2, #3 @mov 指令範例 mov r1, #8 @將 8 賦值給 r1 mov r2, r1 @將 r1 中的值賦值給 r2 mov r3, #10 @將 10 賦值給 r3 寄存器 @mvn 指令範例 mvn r1, #0b10 @0b10 二進制數取反, 賦值給 r1 mvn r2, #5 @5 十進制數取反, 賦值給 r2 mvn r3, r1 @將 r1 寄存器的值, 賦值給 r3 @sub 指令範例 @sub r1, #4, #2 錯誤示例, 減數不能是當即數, 必須是寄存器 mov r2, #4 sub r1, r2, #4 mov r0, #1 sub r3, r1, r0
參考文檔 : ARM 文檔 Page 110, 上面有提供下載.
彙編程序執行流程 : 彙編代碼 --> 彙編器 --> 機器碼 --> CPU 運行;
反彙編示例 : 找到一個 elf 文件, 使用 arm-linux-objdump 反彙編;
-- 命令 : 使用 arm-linux-objdump -S -D start.elf 命令進行反彙編, 其中 "50008000: e3a01001 mov r1, #1 ; 0x1" 中的 "e3a01001" 就是機器碼, 以下圖標註部分;
-- 反彙編部分結果 :
[root@localhost 04_assembly]# arm-linux-objdump -S -D start.elf start.elf: file format elf32-littlearm Disassembly of section .text: 50008000 <_start>: .text .globl _start _start: mov r1,#1 50008000: e3a01001 mov r1, #1 ; 0x1 mov r2,#2 50008004: e3a02002 mov r2, #2 ; 0x2 mov r3,#3 50008008: e3a03003 mov r3, #3 ; 0x3 Disassembly of section .debug_aranges:
機器碼格式 : 截圖自 arm 文檔 P110;
-- ARM 機器碼位數 : 32位;
-- 機器碼分段 :
代碼準備 :
-- 彙編代碼 :
.text .globl _start _start: mov r0, r1 moveq r0, #0xff
-- Makefile 腳本 :
all:start.o arm-linux-ld -Ttext 0x50008000 -o start.elf $^ %.o:%.S arm-linux-gcc -g -o $@ $^ -c clean: rm -rf *.o *.elf
反彙編 elf 文件 :
-- 反彙編內容 : 省略下面的大部分;
[root@localhost 04_assembly]# arm-linux-objdump -S -D start.elf start.elf: file format elf32-littlearm Disassembly of section .text: 50008000 <_start>: .text .globl _start _start: mov r0, r1 50008000: e1a00001 mov r0, r1 moveq r0, #0xff 50008004: 03a000ff moveq r0, #255 ; 0xff Disassembly of section .debug_aranges:
彙編對應機器碼 :
-- "mov r0, r1" : 十六進制 0xe1a00001, 二進制 11100001101000000000000000000001;
-- "moveq r0, #0xff" : 十六進制 0x03a000ff, 二進制 00000011101000000000000011111111;
機器碼解析 :
第一條 : 1110 00 0 1101 0 0000 0000 000000000001
第二條 : 0000 00 1 1101 0 0000 0000 000011111111
-- 條件位對比 (第一段 31 ~ 28) : 第一條是 1110 對應 AL 老是執行, 第二條是 0000 對應 EQ;
-- 保留位對比 (第二段 27 ~ 26) : 第一條 00, 第二條 00, 明顯都同樣;
-- I 操做數類型標識位 (第三段 25) : 標誌最後一個存當即數 仍是寄存器, 若是是 0 表示寄存器, 若是是 1 表示當即數;
-- 操做碼位 (第四段 24 ~ 21) : 區分不一樣指令, 1101 是 MOV 指令;
-- S 狀態寄存器改變標識 (第五段 20) : 是否影響 CPSR 寄存器, 若是 S = 0 不影響, 若是 S = 1 影響;
-- Rn 源操做寄存器 (第六段 19 ~ 16) : MOV 和 MVN 不使用 Rn 位, 寄存器編號;
-- Rd 目的操做寄存器 (第七段 15 ~ 12) : 寄存器編號;
-- shifter_operand 源操做書 (第八段 11 ~ 0) : 源操做數, 這個與 I 位結合起來, 若是 I = 0, 該位表示寄存器編號, 若是 I = 1, 該位表示 當即數大小, 當即數是有範圍的, 若是超出會報錯, 這裏就須要使用僞指令了;
相關文檔 :
-- 位數文檔 : P116, The ARM Instruction Set, A3.4.1 Instruction encoding;
-- MOV 和 MVN 指令 : 機器碼格式 "<opcode1>{<cond>}{S} <Rd>, <shifter_operand>", 沒有 Rn 字段, 該字段沒用;
-- 條件位文檔 : Page 112, The ARM Instruction Set, A3.2.1 Condition code 0b1111;
僞指令簡介 : 僞指令沒有對應的機器碼, 這種指令只在編譯時起做用, 僞指令須要轉化成 其它彙編指令運行, 如 定義 宏, 不會產生機器碼;
globol 僞指令介紹 :
-- 僞指令做用 : 用於定義 程序入口, 用法 ".globol _start", 注意前面加上點;
-- 代碼示例 :
.text .global _start _start: @lsl 左移指令範例 mov r1, #0b1 @將 r1 中的值, 左移 2 位, 放入 r1 寄存器中 mov r1, r1, lsl#2
僞指令介紹 :
-- 僞指令做用 : data 用於定義 數據段, 標明後面的數據存放到數據段中; acsii 標明字符串變量類型, byte 標明 byte 類型變量, word 標明 word 類型變量;
代碼示例 :
-- 彙編代碼 : start.S ;
.data @定義數據變量 hello: @標明變量地址, 字符串變量 .ascii "Hello World !" bh: @標明變量地址, byte 變量 .byte 0x1 ADD: @標明變量地址, word 變量 .word 0xff .text .global _start _start: mov r0, #0xff-- make 腳本 : Makefile;
all: start.o arm-linux-ld -Ttext 0x50008000 -o start.elf start.o start.o : start.S arm-linux-gcc -g -o start.o -c start.S .PHONY: clean clean: rm *.o *.elf *.bin
分析 elf 文件 : 使用 arm-linux-readelf -a start.elf 命令分析 start.elf 文件;
-- .data 段地址 : 注意 [2] 中 .data 地址爲 0x50010004;
-- 數據變量 :
-- elf 文件分析全文 :
octopus@octopus:~/arm/demo$ arm-linux-readelf -a start.elf ELF Header: Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 Class: ELF32 Data: 2's complement, little endian Version: 1 (current) OS/ABI: UNIX - System V ABI Version: 0 Type: EXEC (Executable file) Machine: ARM Version: 0x1 Entry point address: 0x50008000 Start of program headers: 52 (bytes into file) Start of section headers: 33100 (bytes into file) Flags: 0x5000002, has entry point, Version5 EABI Size of this header: 52 (bytes) Size of program headers: 32 (bytes) Number of program headers: 2 Size of section headers: 40 (bytes) Number of section headers: 11 Section header string table index: 8 Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .text PROGBITS 50008000 008000 000004 00 AX 0 0 4 [ 2] .data PROGBITS 50010004 008004 000012 00 WA 0 0 1 [ 3] .debug_aranges PROGBITS 00000000 008018 000020 00 0 0 8 [ 4] .debug_info PROGBITS 00000000 008038 000048 00 0 0 1 [ 5] .debug_abbrev PROGBITS 00000000 008080 000014 00 0 0 1 [ 6] .debug_line PROGBITS 00000000 008094 000037 00 0 0 1 [ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 0080cb 000014 00 0 0 1 [ 8] .shstrtab STRTAB 00000000 0080df 00006c 00 0 0 1 [ 9] .symtab SYMTAB 00000000 008304 000180 10 10 13 4 [10] .strtab STRTAB 00000000 008484 000087 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings) I (info), L (link order), G (group), x (unknown) O (extra OS processing required) o (OS specific), p (processor specific) There are no section groups in this file. Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x008000 0x50008000 0x50008000 0x00004 0x00004 R E 0x8000 LOAD 0x008004 0x50010004 0x50010004 0x00012 0x00012 RW 0x8000 Section to Segment mapping: Segment Sections... 00 .text 01 .data There is no dynamic section in this file. There are no relocations in this file. There are no unwind sections in this file. Symbol table '.symtab' contains 24 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 50008000 0 SECTION LOCAL DEFAULT 1 2: 50010004 0 SECTION LOCAL DEFAULT 2 3: 00000000 0 SECTION LOCAL DEFAULT 3 4: 00000000 0 SECTION LOCAL DEFAULT 4 5: 00000000 0 SECTION LOCAL DEFAULT 5 6: 00000000 0 SECTION LOCAL DEFAULT 6 7: 00000000 0 SECTION LOCAL DEFAULT 7 8: 50010004 0 NOTYPE LOCAL DEFAULT 2 hello 9: 50010011 0 NOTYPE LOCAL DEFAULT 2 bh 10: 50010011 0 NOTYPE LOCAL DEFAULT 2 $d 11: 50010012 0 NOTYPE LOCAL DEFAULT 2 ADD 12: 50008000 0 NOTYPE LOCAL DEFAULT 1 $a 13: 50008004 0 NOTYPE GLOBAL DEFAULT ABS __exidx_end 14: 50010016 0 NOTYPE GLOBAL DEFAULT ABS _bss_end__ 15: 50010016 0 NOTYPE GLOBAL DEFAULT ABS __bss_start__ 16: 50008004 0 NOTYPE GLOBAL DEFAULT ABS __exidx_start 17: 50010016 0 NOTYPE GLOBAL DEFAULT ABS __bss_end__ 18: 50008000 0 NOTYPE GLOBAL DEFAULT 1 _start 19: 50010016 0 NOTYPE GLOBAL DEFAULT ABS __bss_start 20: 50010018 0 NOTYPE GLOBAL DEFAULT ABS __end__ 21: 50010016 0 NOTYPE GLOBAL DEFAULT ABS _edata 22: 50010018 0 NOTYPE GLOBAL DEFAULT ABS _end 23: 50010004 0 NOTYPE GLOBAL DEFAULT 2 __data_start No version information found in this file. Attribute Section: aeabi File Attributes Tag_CPU_arch: v4 Tag_ARM_ISA_use: Yes
equ 僞指令介紹 :
-- 僞指令做用 : 該指定做用是定義常量;
-- 代碼示例 :
.text .global _start _start: @定義一個宏變量 .equ DA, 0x68 @將 DA 值賦值給 r0 寄存器 mov r0, #DA
align 僞指令介紹 :
-- 僞指令做用 : 標明數據對齊;
對齊代碼示例 :
-- 含有對齊的代碼 :
.data @定義數據變量 hello: @標明變量地址, 字符串變量 .ascii "Hello World !" bh: @標明變量地址, byte 變量 .byte 0x1 ADD: @標明變量地址, word 變量 .word 0xff .text .global _start _start: @定義一個宏變量 .equ DA, 0x68 @將 DA 值賦值給 r0 寄存器 mov r0, #DA
-- 不含對齊的代碼 :
.data @定義數據變量 hello: @標明變量地址, 字符串變量 .ascii "Hello World !" .align 4 bh: @標明變量地址, byte 變量 .byte 0x1 ADD: @標明變量地址, word 變量 .word 0xff .text .global _start _start: @定義一個宏變量 .equ DA, 0x68 @將 DA 值賦值給 r0 寄存器 mov r0, #DA
代碼 elf 內容對比 : 這裏省略大部分, 只給出內存對應地址, 查看對齊內容;
-- 沒有對齊的代碼 : 0x50010011 明顯不能被 4 整除;-- 對齊的代碼 : 0x50010020 能夠被4整除, 此時已經進行了對齊;
機器碼 shifter_operand 段解析 :
-- 段解析 : 其中 4 位存放位移值, 8 位存放數值, 所以 當即數不能超過 8位, 最大 0xFF;
-- 缺陷 : 沒法使用 大的數字;
-- 示例 :
.text .global _start _start: mov r0, #0xFFF-- 編譯錯誤 :
octopus@octopus:~/arm/demo$ make arm-linux-gcc -g -o start.o -c start.S start.S: Assembler messages: start.S:5: Error: invalid constant (fff) after fixup make: *** [start.o] 錯誤 1
ldr 僞指令 :
-- 做用 : 能夠 向寄存器中賦值 大當即數;
-- 語法格式 : "ldr r0, =0xFFF", 注意 不使用 # , 使用 = 後面加上當即數;
-- 代碼示例 : 此時能編譯成功, 0xfff 被賦值給 r0 寄存器;
.text .global _start _start: ldr r0, =0xFFF-- 反彙編 elf 代碼 :
octopus@octopus:~/arm/demo$ arm-linux-objdump -S -D start.elf start.elf: file format elf32-littlearm Disassembly of section .text: 50008000 <_start>: .text .global _start _start: ldr r0, =0xFFF 50008000: e51f0004 ldr r0, [pc, #-4] ; 50008004 <_start+0x4> 50008004: 00000fff .word 0x00000fff Disassembly of section .debug_aranges: ... ...-- 分析反彙編代碼 : "50008000: e51f0004 ldr r0, [pc, #-4] ; 50008004 <_start+0x4>" 代碼代表 ldr r0, =0xFFF 是使用 ldr 讀取內存指令, 從 pc - 4 地址上讀取該地址存儲的值, "50008004: 00000fff .word 0x00000fff" 代表 系統將 0xFFF 定義在了 pc -4 內存地址中;
nop 僞指令 :
-- 做用 : 進行延時, 在一些對時序要求較高的程序中, 使用該指令進行一個時鐘的延時;
-- 代碼示例 :
.text .global _start _start: nop-- 反彙編 : nop 僞指令執行了 "mov r0, r0" 這個無心義的操做;
octopus@octopus:~/arm/demo$ arm-linux-objdump -S -D start.elf start.elf: file format elf32-littlearm Disassembly of section .text: 50008000 <_start>: .text .global _start _start: nop 50008000: e1a00000 nop (mov r0,r0) Disassembly of section .debug_aranges: ... ...
協處理器簡介 :
-- 做用 : 執行特定處理任務, 減輕處理器負擔;
-- 數學協處理器 : 主要進行數字處理;
-- 協處理器支持 : ARM 芯片最多支持 16 個協處理器, 最重要的協處理器 是 CP15;
CP15 協處理器做用 : CP15 是系統控制寄存器, 經過這些寄存器, 配置與控制 緩存, MMU, 保護系統, 時鐘模式 和 其它系統參數;
-- 如何訪問 CP15 : 經過訪問 CP15 中的寄存器控制上面的參數, CP15 提供了 16 組寄存器;
-- 文檔 :
mcr 指令解析 : 詳情見 ARM11 文檔, P145, 3.2;
-- 做用 : 將本地寄存器中的數據 賦值給 CP15 的寄存器;
-- 語法格式 : "MCR{cond} P15,<Opcode_1>,<Rd>,<CRn>,<CRm>,<Opcode_2>";
-- 語法解析 : CRn 表示 CP15 寄存器屬於哪一組, CRm 也是組名;
-- 代碼示例 :
.text .global _start _start: @"MCR{cond} P15,<Opcode_1>,<Rd>,<CRn>,<CRm>,<Opcode_2>" @讀取 MainID 寄存器 mcr p15, 0, r0, c0, c0, 0
-- 文檔截圖 :
-- CP15 寄存器訪問 : 若是讀取 MainID 寄存器, 就取前面的哪些 CRn Op1 CRm Op2 等參數;
做者 : 韓曙亮
博客地址 : http://blog.csdn.net/shulianghan/article/details/42408137
本博客相關文檔下載 :
-- ARM 彙編手冊 : http://download.csdn.net/detail/han1202012/8328375
-- ARM 手冊 : http://download.csdn.net/detail/han1202012/8324641
-- ARM 9 芯片文檔 : http://download.csdn.net/detail/han1202012/8332389
-- ARM 11 芯片文檔 : http://download.csdn.net/detail/han1202012/8332403