實驗步驟
使用交叉編譯工具或本機編譯工具,通過 C 代碼和反彙編工具研究:
1. 生成了 Thumb 指令還是 ARM 指令:如何通過編譯參數改變,相同的程序,ARM和Thumb編譯的結果有何不同, 如指令本身和整體目標代碼的大小等;
2. 對於 ARM 指令,能否產生條件執行的指令;
3. 設計 C 的代碼場景,觀察是否產生了寄存器移位尋址;
4. 設計 C 的代碼場景,觀察一個複雜的 32 位數是如何裝載到寄存器的;
5. 寫一個 C 的多重函數調用的程序,觀察和分析: a. 調用時的返回地址在哪裏? b. 傳入的參數在哪裏?c. 本地變量的堆棧分配是如何做的? d. 寄存器是 caller保存還是 callee 保存?是全體保存還是部分保存?
6. MLA 是帶累加的乘法,嘗試要如何寫 C 的表達式能編譯得到MLA 指令。
7. BIC是對某一個比特清零的指令,嘗試要如何寫 C 的表達式能編譯得到BIC 指令。
8. 編寫一個彙編函數,接受一個整數和一個指針做爲輸入,指針所指應爲一個字符串,該彙編函數調用C語言的printf()函數輸出這個字符串的前n個字符,n即爲那個整數。在C語言寫的main()函數中調用並傳遞參數給這個彙編函數 來得到輸出。
實驗報告要求
1. 畫出你所實際實施的連接示意圖;
同lab1
2. 給出所用的器材的列表;
l Raspberry Pi 一塊;
l 5V/1A 電源;
l MicroUSB 線一根;
l USB-TTL 串口線一根;
l PC(Ubuntu14.04)一臺;
l 以太網線一根;
l 路由器;
3. 給出各項測試所用的C代碼和產生的彙編代碼情況,並解釋彙編代碼;
1)生成了 Thumb 指令還是 ARM 指令:如何通過編譯參數改變,相同的程序,ARM和Thumb編譯的結果有何不同, 如指令本身和整體目標代碼的大小等;
測試C代碼:
#include<stdio.h>
int main(void){
int a = 0;
a += 1;
return 0;
}
編譯生成ARM指令:
gcc -c test.c
反彙編結果查看命令:
objdump -d test.o
可以發現,ARM指令本身是32位的,最左列地址每次以4字節增加,整體目標代碼852K。gcc編譯默認使用ARM編譯。
編譯生成Thumb指令:
gcc -c -mthumb -msoft-float test.c
odjump -d test.o
可以發現,Thumb指令是16位的,最左列地址每次以2字節增加,整體目標代碼是820K,比ARM指令生成的略小。
2)對於 ARM 指令,能否產生條件執行的指令;
C測試代碼:
#include<stdio.h>
int f(int a, int b){
if(a>b) a++;
else b++;
return a;
}
int main(void){
int t = f(1,2);
}
可以發現,彙編代碼中有cmp,ble等條件分支指令,說明ARM指令支持條件執行。
3)設計 C 的代碼場景,觀察是否產生了寄存器移位尋址;
C測試代碼:
#include<stdio.h>
int main(void){
int a[4] = {0,1,2,3};
int i;
for(i = 0; i < 2; i++){
a[3] += a[i*2];
}
}
4)設計 C 的代碼場景,觀察一個複雜的 32 位數是如何裝載到寄存器的;
C測試代碼:
#include<stdio.h>
int main(void){
int a= 0x12345678;
return 0;
}
可以發現,32位數被存在命令段,通過ldr、sdr指令加載。
5)寫一個 C 的多重函數調用的程序,觀察和分析: a. 調用時的返回地址在哪裏?b. 傳入的參數在哪裏? c. 本地變量的堆棧分配是如何做的?d. 寄存器是 caller 保存還是 callee保存?是全體保存還是部分保存?
C測試代碼:
#include<stdio.h>
int f1(int u, int v, int x, int y, int z){
u *= 2;
return u;
}
int f(int a, int b, int c, int d){
a = a+b+c+d;
b = b+c+d;
c = c+d;
int t = f1(a,b,c,d, a+b+c+d);
return t;
}
int main(void){
f(1,2,3,4);
}
a. 調用時返回地址放在鏈接寄存器lr中。
b. 傳入的參數放在r0,r1,r2,r3四個寄存器中,多餘的參數放在堆棧中。
c. 本地變量存放在堆棧高地址,傳進來的參數放在堆棧低地址。
d. 寄存器r0,r1,r2,r3是caller保存,寄存器r4以上由callee保存。
6)MLA 是帶累加的乘法,嘗試要如何寫 C 的表達式能編譯得到 MLA 指令。
C測試代碼:
#include<stdio.h>
inr f1(int a, int b, int c){
return a*b+c;
}
int main(void){
f1(1,2,3);
}
反彙編結果:
gcc -c mla.c -O3
-O3 是用來表示優化指令,有O1,O2,O3三檔優化。這裏要出現MLA,必須要用優化可以發現使用了MLA指令。
7)BIC是對某一個比特清零的指令,嘗試要如何寫 C 的表達式能編譯得到BIC 指令。
C測試代碼:
#include<stdio.h>
int f(int a, int b){
int t = a & ~b;
return t;
}
int main(void){
f(0x83, 0x0F);
}
反彙編:
gcc -c bic.c -O3
可以發現使用了bic指令,進行了高4位比特清零。
8)編寫一個彙編函數,接受一個整數和一個指針作爲輸入,指針所指應爲一個字符串,該彙編函數調用C語言的printf()函數輸出這個字符串的前n個字符,n即爲那個整數。在C語言寫的main()函數中調用並傳遞參數給這個彙編函數來得到輸出。
C語言實現爲:
void f(char* a, int n){ int i; for( i = 0; i < n; i++) printf(“%c”, a[i]); } |