实验步骤
使用交叉编译工具或本机编译工具,通过 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]); } |