Lab2: ARM指令


實驗步驟

使用交叉編譯工具或本機編譯工具,通過 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]);

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章