RPi——ARM指令验证
2016-04-05 21:14
330 查看
实验目的
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 str r3, [fp, #-8] 103fc: e3a03000 mov r3, #0 10400: e50b300c str r3, [fp, #-12] 10404: e3a03000 mov r3, #0 10408: e50b3008 str r3, [fp, #-8] 1040c: ea00000d b 10448 <main+0x60> 10410: e51b300c ldr r3, [fp, #-12] 10414: e1a03083 lsl r3, r3, #1 10418: e1a03103 lsl r3, r3, #2 1041c: e24b2004 sub r2, fp, #4 10420: e0823003 add r3, r2, r3 10424: e5132030 ldr r2, [r3, #-48] ; 0xffffffd0 10428: e51b300c ldr r3, [fp, #-12] 1042c: e1a03103 lsl r3, r3, #2 10430: e24b1004 sub r1, fp, #4 10434: e0813003 add r3, r1, r3 10438: e5032030 str r2, [r3, #-48] ; 0xffffffd0 1043c: e51b3008 ldr r3, [fp, #-8] 10440: e2833001 add r3, r3, #1 10444: e50b3008 str r3, [fp, #-8] 10448: e51b3008 ldr r3, [fp, #-8] 1044c: e3530003 cmp r3, #3 10450: daffffee ble 10410 <main+0x28> 10454: e1a00003 mov r0, r3 10458: e24bd000 sub sp, fp, #0 1045c: e49db004 pop {fp} ; (ldr fp, [sp], #4) 10460: e12fff1e bx lr 可以看到有逻辑左移指令:lsl
5、设计 C 的代码场景,观察一个复杂的 32 位数是如何装载到寄存器的;
测试代码test2.c如下:
#include <stdio.h> int main(){ unsigned a=0x12345678; a++; return 0; }
编译:`gcc -c test2.c` 使用objdump结果如下(`objdump -d test2.o`): 000103e8 <main>: 103e8: e52db004 push {fp} ; (str fp, [sp, #-4]!) 103ec: e28db000 add fp, sp, #0 103f0: e24dd00c sub sp, sp, #12 103f4: e59f301c ldr r3, [pc, #28] ; 10418 <main+0x30> 103f8: e50b3008 str r3, [fp, #-8] 103fc: e51b3008 ldr r3, [fp, #-8] 10400: e2833001 add r3, r3, #1 10404: e50b3008 str r3, [fp, #-8] 10408: e1a00003 mov r0, r3 1040c: e24bd000 sub sp, fp, #0 10410: e49db004 pop {fp} ; (ldr fp, [sp], #4) 10414: e12fff1e bx lr 10418: 12345678 .word 0x12345678 可以看见ARM指令将大数字存在命令段[pc,#28],通过ldr指令去加载,而非MIPS等指令集使用lui和ori来实现32位大数字的实现。
6、写一个 C 的多重函数调用的程序,观察和分析
a. 调用时的返回地址在哪里? b. 传入的参数在哪里? c. 本地变量的堆栈分配是如何做的? d. 寄存器是 caller 保存还是 callee 保存?是全体保存还是部分保存? 测试代码test3.c如下:
编译,查看结果如下: test4.o: file format elf32-littlearm Disassembly of section .text: 00000000 <f2>: 0: e52db004 push {fp} ; (str fp, [sp, #-4]!) 4: e28db000 add fp, sp, #0 8: e24dd01c sub sp, sp, #28 c: e50b0010 str r0, [fp, #-16] 10: e50b1014 str r1, [fp, #-20] ; 0xffffffec 14: e50b2018 str r2, [fp, #-24] ; 0xffffffe8 18: e50b301c str r3, [fp, #-28] ; 0xffffffe4 1c: e3a03000 mov r3, #0 20: e50b3008 str r3, [fp, #-8] 24: e51b3010 ldr r3, [fp, #-16] 28: e51b201c ldr r2, [fp, #-28] ; 0xffffffe4 2c: e0020392 mul r2, r2, r3 30: e51b3014 ldr r3, [fp, #-20] ; 0xffffffec 34: e59b1004 ldr r1, [fp, #4] 38: e0030391 mul r3, r1, r3 3c: e0822003 add r2, r2, r3 40: e51b3018 ldr r3, [fp, #-24] ; 0xffffffe8 44: e59b1008 ldr r1, [fp, #8] 48: e0030391 mul r3, r1, r3 4c: e0822003 add r2, r2, r3 50: e59b300c ldr r3, [fp, #12] 54: e59b1010 ldr r1, [fp, #16] 58: e0030391 mul r3, r1, r3 5c: e0822003 add r2, r2, r3 60: e59b3014 ldr r3, [fp, #20] 64: e0823003 add r3, r2, r3 68: e50b3008 str r3, [fp, #-8] 6c: e51b3008 ldr r3, [fp, #-8] 70: e1a00003 mov r0, r3 74: e24bd000 sub sp, fp, #0 78: e49db004 pop {fp} ; (ldr fp, [sp], #4) 7c: e12fff1e bx lr 00000080 <f3>: 80: e92d4800 push {fp, lr} 84: e28db004 add fp, sp, #4 88: e24dd050 sub sp, sp, #80 ; 0x50 8c: e50b0030 str r0, [fp, #-48] ; 0xffffffd0 90: e50b1034 str r1, [fp, #-52] ; 0xffffffcc 94: e50b2038 str r2, [fp, #-56] ; 0xffffffc8 98: e50b303c str r3, [fp, #-60] ; 0xffffffc4 9c: e51b2030 ldr r2, [fp, #-48] ; 0xffffffd0 a0: e51b3034 ldr r3, [fp, #-52] ; 0xffffffcc a4: e0823003 add r3, r2, r3 a8: e50b3008 str r3, [fp, #-8] ac: e51b2038 ldr r2, [fp, #-56] ; 0xffffffc8 b0: e51b303c ldr r3, [fp, #-60] ; 0xffffffc4 b4: e0823003 add r3, r2, r3 b8: e50b300c str r3, [fp, #-12] bc: e59b2004 ldr r2, [fp, #4] c0: e59b3008 ldr r3, [fp, #8] c4: e0823003 add r3, r2, r3 c8: e50b3010 str r3, [fp, #-16] cc: e59b200c ldr r2, [fp, #12] d0: e59b3010 ldr r3, [fp, #16] d4: e0823003 add r3, r2, r3 d8: e50b3014 str r3, [fp, #-20] ; 0xffffffec dc: e59b2014 ldr r2, [fp, #20] e0: e59b3018 ldr r3, [fp, #24] e4: e0823003 add r3, r2, r3 e8: e50b3018 str r3, [fp, #-24] ; 0xffffffe8 ec: e3a03005 mov r3, #5 f0: e58d3000 str r3, [sp] f4: e3a03006 mov r3, #6 f8: e58d3004 str r3, [sp, #4] fc: e3a03007 mov r3, #7 100: e58d3008 str r3, [sp, #8] 104: e3a03008 mov r3, #8 108: e58d300c str r3, [sp, #12] 10c: e3a03009 mov r3, #9 110: e58d3010 str r3, [sp, #16] 114: e3a00001 mov r0, #1 118: e3a01002 mov r1, #2 11c: e3a02003 mov r2, #3 120: e3a03004 mov r3, #4 124: ebfffffe bl 0 <f2> 128: e51b3008 ldr r3, [fp, #-8] 12c: e51b200c ldr r2, [fp, #-12] 130: e0030392 mul r3, r2, r3 134: e50b301c str r3, [fp, #-28] ; 0xffffffe4 138: e51b3010 ldr r3, [fp, #-16] 13c: e51b2014 ldr r2, [fp, #-20] ; 0xffffffec 140: e0030392 mul r3, r2, r3 144: e50b3020 str r3, [fp, #-32] ; 0xffffffe0 148: e51b201c ldr r2, [fp, #-28] ; 0xffffffe4 14c: e51b3020 ldr r3, [fp, #-32] ; 0xffffffe0 150: e0633002 rsb r3, r3, r2 154: e50b3024 str r3, [fp, #-36] ; 0xffffffdc 158: e51b3024 ldr r3, [fp, #-36] ; 0xffffffdc 15c: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8 160: e0030392 mul r3, r2, r3 164: e59b201c ldr r2, [fp, #28] 168: e0030392 mul r3, r2, r3 16c: e50b3028 str r3, [fp, #-40] ; 0xffffffd8 170: e51b3028 ldr r3, [fp, #-40] ; 0xffffffd8 174: e1a00003 mov r0, r3 178: e24bd004 sub sp, fp, #4 17c: e8bd8800 pop {fp, pc} 00000180 <f1>: 180: e92d4800 push {fp, lr} 184: e28db004 add fp, sp, #4 188: e24dd030 sub sp, sp, #48 ; 0x30 18c: e50b0010 str r0, [fp, #-16] 190: e50b1014 str r1, [fp, #-20] ; 0xffffffec 194: e50b2018 str r2, [fp, #-24] ; 0xffffffe8 198: e3a03000 mov r3, #0 19c: e50b3008 str r3, [fp, #-8] 1a0: e3a03005 mov r3, #5 1a4: e58d3000 str r3, [sp] 1a8: e3a03006 mov r3, #6 1ac: e58d3004 str r3, [sp, #4] 1b0: e3a03007 mov r3, #7 1b4: e58d3008 str r3, [sp, #8] 1b8: e3a03008 mov r3, #8 1bc: e58d300c str r3, [sp, #12] 1c0: e3a03009 mov r3, #9 1c4: e58d3010 str r3, [sp, #16] 1c8: e51b0010 ldr r0, [fp, #-16] 1cc: e51b1014 ldr r1, [fp, #-20] ; 0xffffffec 1d0: e51b2018 ldr r2, [fp, #-24] ; 0xffffffe8 1d4: e3a03004 mov r3, #4 1d8: ebfffffe bl 0 <f2> 1dc: e50b0008 str r0, [fp, #-8] 1e0: e51b3008 ldr r3, [fp, #-8] 1e4: e1a00003 mov r0, r3 1e8: e24bd004 sub sp, fp, #4 1ec: e8bd8800 pop {fp, pc} 000001f0 <main>: 1f0: e92d4800 push {fp, lr} 1f4: e28db004 add fp, sp, #4 1f8: e24dd030 sub sp, sp, #48 ; 0x30 1fc: e3a03000 mov r3, #0 200: e50b3008 str r3, [fp, #-8] 204: e3a03001 mov r3, #1 208: e50b300c str r3, [fp, #-12] 20c: e3a03002 mov r3, #2 210: e50b3010 str r3, [fp, #-16] 214: e51b0008 ldr r0, [fp, #-8] 218: e51b100c ldr r1, [fp, #-12] 21c: e51b2010 ldr r2, [fp, #-16] 220: ebfffffe bl 180 <f1> 224: e1a03000 mov r3, r0 228: e59f0060 ldr r0, [pc, #96] ; 290 <main+0xa0> 22c: e1a01003 mov r1, r3 230: ebfffffe bl 0 <printf> 234: e3a03007 mov r3, #7 238: e58d3000 str r3, [sp] 可以发现: 函数调用后的返回地址存放在LR寄存器中。 传入的参数存放在R0 R1 R2 R3四个寄存器中,多余的参数放在堆栈中。 本地变量存放在堆栈高地址,传进来的参数存放在堆栈低地址。 R0到R3由caller保存,R4以上由callee保存。
7、MLA 是带累加的乘法,尝试要如何写 C 的表达式能编译得到 MLA 指令。
测试代码test5.c如下:
查看编译结果:
使用 -o1 进行优化,查看结果:
可以看到MLA命令得到了使用。 未使用 -o1 优化时的结果: 00000000 <f1>: 0: e52db004 push {fp} ; (str fp, [sp, #-4]!) 4: e28db000 add fp, sp, #0 8: e24dd014 sub sp, sp, #20 c: e50b0008 str r0, [fp, #-8] 10: e50b100c str r1, [fp, #-12] 14: e50b2010 str r2, [fp, #-16] 18: e51b3008 ldr r3, [fp, #-8] 1c: e51b200c ldr r2, [fp, #-12] 20: e0020392 mul r2, r2, r3 24: e51b3010 ldr r3, [fp, #-16] 28: e0823003 add r3, r2, r3 2c: e1a00003 mov r0, r3 30: e24bd000 sub sp, fp, #0 34: e49db004 pop {fp} ; (ldr fp, [sp], #4) 38: e12fff1e bx lr 0000003c <main>: 3c: e92d4800 push {fp, lr} 40: e28db004 add fp, sp, #4 44: e3a00001 mov r0, #1 48: e3a01002 mov r1, #2 4c: e3a02003 mov r2, #3 50: ebfffffe bl 0 <f1> 54: e3a03000 mov r3, #0 58: e1a00003 mov r0, r3
8、BIC是对某一个比特清零的指令,尝试要如何写 C 的表达式能编译得到 BIC 指令。
测试代码test6.c如下:
#include<stdio.h> int bitand(int x){ return x&0xeeeeeeee; } int main(){ bitand(99); return 0; }
编译,查看结果:
使用 -o1 优化后的结果 编译命令:`gcc -c test6.c -o1` 查看结果:`objdump -d test6.o` 00000000 <bitand>: 0: e3c00411 bic r0, r0, #285212672 ; 0x11000000 4: e3c00811 bic r0, r0, #1114112 ; 0x110000 8: e3c00c11 bic r0, r0, #4352 ; 0x1100 c: e3c00011 bic r0, r0, #17 10: e12fff1e bx lr 00000014 <main>: 14: e3a00000 mov r0, #0 18: e12fff1e bx lr 可见BIC指令。
9、编写一个汇编函数,接受一个整数和一个指针做为输入,指针所指应为一个字符串,该汇编函数调用C语言的 printf()函数输出这个字符串的前n个字符,n即为那个整数。在C语言写的main()函数中调用并传递参数给这个汇编函数 来得到输出。
测试代码(分为汇编代码和C代码test7)如下: 汇编代码(test7.s)如下:
.global test7 test7: push {R5, R6, R7, lr} MOV R5, R0 MOV R6, R1 MOV R7, #0 CMP R7, R6 BGE exit begin: LDR R0, =char LDR R1, [R5, R7] CMP R1, #0 BEQ exit bl printf ADD R7, R7, #1 CMP R7, R6 BLT begin exit: LDR R0, =newline bl printf MOV R0, R7 pop {R5, R6, R7, pc} .data char: .asciz "%c" newline: .asciz "\n"
C代码如下(test7.c)如下:
#include <stdio.h> extern int test7(char*, int); int main(){ int a; char s[100]; scanf("%s %d", s, &a); a = test7(s, a); printf("Print %d character.\n", a); return 0; }
编译命令:`gcc test7.c test7.s -o test7 -g -marm` 运行:./test7
其中test7.s的逻辑类似如下:
int test7(cahr *s, int a){ int i = 0; for (i; i<a; i++) printf(“%c”, s[i]); return i; }
10、自扩展内容:编写测试程序,测试使用带条件的ARM指令和不使用时的执行效率。
noif.s汇编代码:
.global add add: CMP R0, #0 ADD R0, R0, R1 MOV pc, lr
useif.s汇编代码:
.global add add: CMP R0, #0 ADDNE R0, R0, R1 MOV pc, lr
C代码(test.c):
#include <stdio.h> extern int add(int, int); int main(){ int a, b, i, times; scanf("%d %d %d", &a, &b, ×); for (i=0; i<times; i++) a = add(a, b); printf("%d\n", a); return 0; }
testif.in文件:
1 2 20000000
编译运行查看结果:
经过多次比对,虽然时间略有波动。但是总体而言,两程序执行时间基本没有区别,即ADDNE与ADD的执行基本没有时间差。
相关文章推荐
- 修改Android Studio的背景颜色
- 烦人的字符转化
- 关于使用2d照片进行3d建模
- 『NYIST』第八届河南省ACM竞赛训练赛[正式赛一]CF-236B. Easy Number Challenge
- 导航加下划线和数据的刷新
- 安卓开发中服务器与客户端的通信
- ios界面跳转
- 2016年阿里实习5面面经
- ELF Hook原理
- Android总结篇系列:Android广播机制
- P2P通信原理与实现
- Java中的static关键字解析
- 构建之法阅读笔记04
- 即时聊天社交软件(二)
- 栈帧分析
- 转:tslib1.4 移植全过程
- 2014总结
- MFC采用MSComm控件通信时,出现error LNK2001:无法解析的外部符号问题的解决方法
- LeetCode 8 String to Integer (atoi)
- 【小镇的技术天梯】lanmp服务器集群搭建(1)nginx的反向代理