嵌入式系统实验二
日期:2016-3-30
一、实验目的
- 深入理解ARM指令和Thumb指令的区别和编译选项;
- 深入理解某些特殊的ARM指令,理解如何编写C代码来得到这些指令;
- 深入理解ARM的BL指令和C函数的堆栈保护;
- 深入理解如何实现C和汇编函数的互相调用。
二、实验器材
硬件
Ÿ 实验主板一块;
Ÿ 5V/1A电源一个;
Ÿ microUSB线一根;
以下为自备(可选)器材:
Ÿ PC(Windows/Mac OS/Linux)一台;
Ÿ USB-TTL串口线一根(FT232RL芯片或PL2303芯片);
Ÿ 以太网线一根(可能还需要路由器等)。
软件
Ÿ 交叉编译软件
三、实验步骤
使用交叉编译工具或本机编译工具,通过 C 代码和反汇编工具研究:
- 生成了 Thumb 指令还是 ARM 指令:如何通过编译参数改变,相同的程序,ARM和Thumb编译的结果有何不同, 如指令本身和整体目标代码的大小等;
①如何通过编译参数改变:
-mthumb:使用这个编译选项生成的目标文件是thumb的。
-mthumb-interwork:指定为thumb的指令使用thumb指令集编译,其余的使用arm,使用这个选项生成的目标文件,允许在thumb和arm之间交叉调用。
②同的程序,ARM和Thumb编译的结果有何不同
可见thumb目标文件大小为8349kb,而arm目标文件大小为8346kb,arm的目标文件比thumb的目标文件大。
- 对于 ARM 指令,能否产生条件执行的指令;
在第1题中的测试程序有if-else语句,可以用来测试。
可以看到对于arm指令,程序中条件判断if语句,在反汇编之后有bne指令,说明可以产生条件判断的指令
为了加强理解,将thumb编译的程序也反汇编了一次
- 设计 C 的代码场景,观察是否产生了寄存器移位寻址;
在反汇编后没有看到寄存器移位寻址。
但在接下来重新编译并在编译是加入-O1进行优化
发现有ldr r0,[r0,r1,lsl #4]指令,所以有寄存器移位寻址指令。
- 设计 C 的代码场景,观察一个复杂的 32 位数是如何装载到寄存器的;
可以看到有指令ldr r3,[pc,#20],20/4+2=7条(此处2考虑了流水线),7条之后读到的指令是.word 0x7831193,正好是长整数2016483646的十六进制。
但此处有疑惑当长整数为1073741824即0x40000000的时候,结果如下,还不能理解:
当长整数为2147483647时,也是:
- 写一个 C 的多重函数调用的程序,观察和分析: a. 调用时的返回地址在哪里? b. 传入的参数在哪里? c. 本地变量的堆栈分配是如何做的? d. 寄存器是 caller 保存还是 callee 保存?是全体保存还是部分保存?
a. 调用时的返回地址在哪里?
答:由函数最后一个汇编指令可看出返回地址在lr寄存器
b. 传入的参数在哪里?
答:这里最多只有两个参数,所以用了r0和r1,实际上r0~r3都可以作为传参寄存器,但当参数大于4个时,需要用压入堆栈的方式来传参。
c. 本地变量的堆栈分配是如何做的?
答: 本地变量首先存在r0、r1和r2中,其他的通过r3压入堆栈中。
d. 寄存器是 caller 保存还是 callee 保存?是全体保存还是部分保存?
答:caller保存参数,callee保存地址;
部分保存,只保存需要保存的。
- MLA 是带累加的乘法,尝试要如何写 C 的表达式能编译得到 MLA 指令。
- BIC是对某一个比特清零的指令,尝试要如何写 C 的表达式能编译得到 BIC 指令。
- 编写一个汇编函数,接受一个整数和一个指针做为输入,指针所指应为一个字符串,该汇编函数调用C语言的 printf()函数输出这个字符串的前n个字符,n即为那个整数。在C语言写的main()函数中调用并传递参数给这个汇编函数 来得到输出。
把二进制文件反汇编:
把可执行文件通过samb共享到acadia板子上并运行:
的确输出了“Hello,welcome to here!”的前十位。
四、实验感想
通过这一次的实验,熟悉了arm的一些基本指令,了解了arm和thumb指令的一些特点。因为是第一次接触,所以这一次的实验过程中还是遇到了很多问题,各种arm指令的含义以及如何产生等。但是最后完成了还是蛮开心的