实验目的
1 深入理解ARM指令和Thumb指令的区别和编译选项;
2 深入理解某些特殊的ARM指令,理解如何编写C代码来得到这些指令;
3 深入理解ARM的BL指令和C函数的堆栈保护;
4 深入理解如何实现C和汇编函数的互相调用。
实验内容
使用交叉编译工具或本机编译工具,通过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、连线如下:
2、arm 指令和thumb指令
观察是ARM指令
在板子上用vi命令写测试程序如下:
#include<stdio.h>
int main(){
int a=1,b=2;
a=b+a;
return 0;
}
对其进行编译,编译命令如下:
gcc -marm test.c -o test_arm.o
用`objdump -d test_arm.o`进行查看可以得到:
000103e8 <main>:
103e8: e52db004 push {fp} ; (str fp, [sp, #-4]!)
103ec: e28db000 add fp, sp, #0
103f0: e24dd00c sub sp, sp, #12
103f4: e3a03001 mov r3, #1
103f8: e50b3008 str r3, [fp, #-8]
103fc: e3a03002 mov r3, #2
10400: e50b300c str r3, [fp, #-12]
10404: e51b2008 ldr r2, [fp, #-8]
10408: e51b300c ldr r3, [fp, #-12]
1040c: e0823003 add r3, r2, r3
10410: e50b3008 str r3, [fp, #-8]
10414: e3a03000 mov r3, #0
10418: e1a00003 mov r0, r3
1041c: e24bd000 sub sp, fp, #0
10420: e49db004 pop {fp} ; (ldr fp, [sp], #4)
10424: e12fff1e bx lr
可以看到指令本身是32位的,GCC默认使用的是ARM指令。
观察thumb指令:
将上面的编译代码的 –marm 换成 –mthumb发现会出现一下问题:
这是一个bug,还没有解决。
3、对于 ARM 指令,能否产生条件执行的指令
编写测试程序test.c文件,内容如下:
编译并查看结果:
出现cpm指令、ble等条件分支指令的出现,可见ARM是支持的条件执行指令的。
4、设计C的代码场景,观察是否产生了寄存器移位寻址
编写测试程序test1.c如下:
#include <stdio.h>
int main(){
int a[10];
int i=0;
int j=0;
for(i=0;i<4;i++){
a[j]=a[j*2];
}
return 0;
}
编译:编译代码:`gcc -c test1.c`
查看结果:`objdump -d test1.o`
000103e8 <main>:
103e8: e52db004 push {fp} ; (str fp, [sp, #-4]!)
103ec: e28db000 add fp, sp, #0
103f0: e24dd034 sub sp, sp, #52 ; 0x34
103f4: e3a03000 mov r3, #0
103f8: e50b3008