树莓派上关于ARM指令的验证

来源:互联网 发布:淘宝异地客服找工作 编辑:程序博客网 时间:2024/05/18 01:55

made by Rk

本文由浙江大学《嵌入式系统》课程提供强力支持。

感谢翁恺老师 @翁恺BA5AG

/*************************************************************/

通过C代码和反汇编工具研究以下几点:

生成了Thumb指令还是ARM指令,如何通过编译参数改变;
对于ARM指令,能否产生条件执行的指令;
设计C的代码场景,观察是否产生了寄存器移位寻址;
设计C的代码场景,观察一个复杂的32位数是如何装载到寄存器的;
写一个C的多重函数调用的程序,观察和分析:
调用时的返回地址在哪里?
传入的参数在哪里?
本地变量的堆栈分配是如何做的?
寄存器是caller保存还是callee保存?是全体保存还是部分保存?
MLA是带累加的乘法,尝试要如何写C的表达式能编译得到MLA指令。


为了实验代码的完整可用,新建一个文件夹arm。



生成了Thumb指令还是ARM指令,如何通过编译参数改变

1、编写下列指令:
#include <stdio.h>int main(){        int t = 0;        t++;        return 0;}

2、编译
gcc -c arm_1.cobjdump -d arm_1.o

可以看到结果如下:
pi@raspberrypi ~/code/arm $ objdump -d arm_1.oarm_1.o:     file format elf32-littlearmDisassembly of section .text:00000000 <main>:   0:e52db004 push{fp}; (str fp, [sp, #-4]!)   4:e28db000 addfp, sp, #0   8:e24dd00c subsp, sp, #12   c:e3a03000 movr3, #0  10:e50b3008 strr3, [fp, #-8]  14:e51b3008 ldrr3, [fp, #-8]  18:e2833001 addr3, r3, #1  1c:e50b3008 strr3, [fp, #-8]  20:e3a03000 movr3, #0  24:e1a00003 movr0, r3  28:e28bd000 addsp, fp, #0  2c:e8bd0800 pop{fp}  30:e12fff1e bxlr

指令程度为32位,gcc默认使用arm指令集。

3、使用Thumb编译
gcc -c -mthumb -msoft-float arm_1.c 
查看编译生成结果:
pi@raspberrypi ~/code/arm $ objdump -d arm_1.oarm_1.o:     file format elf32-littlearmDisassembly of section .text:00000000 <main>:   0:b580      push{r7, lr}   2:b082      subsp, #8   4:af00      addr7, sp, #0   6:2300      movsr3, #0   8:607b      strr3, [r7, #4]   a:687b      ldrr3, [r7, #4]   c:3301      addsr3, #1   e:607b      strr3, [r7, #4]  10:2300      movsr3, #0  12:1c18      addsr0, r3, #0  14:46bd      movsp, r7  16:b002      addsp, #8  18:bd80      pop{r7, pc}  1a:46c0      nop; (mov r8, r8)

指令长度是16位(最左一列以2Byte递增)

对于ARM指令,能否产生条件执行的指令;

1、编写arm_branch.c源文件:
#include <stdio.h>int f(int a, int b) {int t;if (a > b)t = a - b--;if (a == b - 10)t = a + b++;return t;}int main() {f(10, 20);return 0;}

2、查看编译结果
pi@raspberrypi ~/code/arm $ objdump -d arm_branch.oarm_branch.o:     file format elf32-littlearmDisassembly of section .text:00000000 <f>:   0:e52db004 push{fp}; (str fp, [sp, #-4]!)   4:e28db000 addfp, sp, #0   8:e24dd014 subsp, sp, #20   c:e50b0010 strr0, [fp, #-16]  10:e50b1014 strr1, [fp, #-20]  14:e51b2010 ldrr2, [fp, #-16]  18:e51b3014 ldrr3, [fp, #-20]  1c:e1520003 cmpr2, r3  20:da000006 ble40 <f+0x40>  24:e51b2010 ldrr2, [fp, #-16]  28:e51b3014 ldrr3, [fp, #-20]  2c:e0633002 rsbr3, r3, r2  30:e50b3008 strr3, [fp, #-8]  34:e51b3014 ldrr3, [fp, #-20]  38:e2433001 subr3, r3, #1  3c:e50b3014 strr3, [fp, #-20]  40:e51b3014 ldrr3, [fp, #-20]  44:e243200a subr2, r3, #10  48:e51b3010 ldrr3, [fp, #-16]  4c:e1520003 cmpr2, r3  50:1a000006 bne70 <f+0x70>  54:e51b2014 ldrr2, [fp, #-20]  58:e51b3010 ldrr3, [fp, #-16]  5c:e0823003 addr3, r2, r3  60:e50b3008 strr3, [fp, #-8]  64:e51b3014 ldrr3, [fp, #-20]  68:e2833001 addr3, r3, #1  6c:e50b3014 strr3, [fp, #-20]  70:e51b3008 ldrr3, [fp, #-8]  74:e1a00003 movr0, r3  78:e28bd000 addsp, fp, #0  7c:e8bd0800 pop{fp}  80:e12fff1e bxlr00000084 <main>:  84:e92d4800 push{fp, lr}  88:e28db004 addfp, sp, #4  8c:e3a0000a movr0, #10  90:e3a01014 movr1, #20  94:ebfffffe bl0 <f>  98:e3a03000 movr3, #0  9c:e1a00003 movr0, r3  a0:e8bd8800 pop{fp, pc}

可以看到bne等条件分支指令的出现,可见ARM是支持的条件执行指令的。


设计C的代码场景,观察是否产生了寄存器移位寻址;

1、编译生成测试代码:
#include <stdio.h>int main() {        int t[10];        int i = 0;        int j = 0;        for(j=0; j<4; j++) {                t[8] = t[i*2];        }        printf("%d", t[8]);                return 0;}

2、查看编译结果:
pi@raspberrypi ~/code/arm $ objdump -d arm_shift.oarm_shift.o:     file format elf32-littlearmDisassembly of section .text:00000000 <main>:   0:e92d4800 push{fp, lr}   4:e28db004 addfp, sp, #4   8:e24dd030 subsp, sp, #48; 0x30   c:e3a03000 movr3, #0  10:e50b300c strr3, [fp, #-12]  14:e3a03000 movr3, #0  18:e50b3008 strr3, [fp, #-8]  1c:e3a03000 movr3, #0  20:e50b3008 strr3, [fp, #-8]  24:ea00000b b58 <main+0x58>  28:e51b300c ldrr3, [fp, #-12]  2c:e1a02083 lslr2, r3, #1  30:e3e0302f mvnr3, #47; 0x2f  34:e1a02102 lslr2, r2, #2  38:e24b1004 subr1, fp, #4  3c:e0812002 addr2, r1, r2  40:e0823003 addr3, r2, r3  44:e5933000 ldrr3, [r3]  48:e50b3014 strr3, [fp, #-20]  4c:e51b3008 ldrr3, [fp, #-8]  50:e2833001 addr3, r3, #1  54:e50b3008 strr3, [fp, #-8]  58:e51b3008 ldrr3, [fp, #-8]  5c:e3530003 cmpr3, #3  60:dafffff0 ble28 <main+0x28>  64:e59f201c ldrr2, [pc, #28]; 88 <main+0x88>  68:e51b3014 ldrr3, [fp, #-20]  6c:e1a00002 movr0, r2  70:e1a01003 movr1, r3  74:ebfffffe bl0 <printf>  78:e3a03000 movr3, #0  7c:e1a00003 movr0, r3  80:e24bd004 subsp, fp, #4  84:e8bd8800 pop{fp, pc}  88:00000000 .word0x00000000

可以看到其中有左移指令:
lslr2, r3, #1


设计C的代码场景,观察一个复杂的32位数是如何装载到寄存器的;

1、编写测试代码
#include <stdio.h>int main() {        unsigned int a = 0x12345678;        a++;        return 0;}


2、编译查看结果:
pi@raspberrypi ~/code/arm $ objdump -d arm_big_num.oarm_big_num.o:     file format elf32-littlearmDisassembly of section .text:00000000 <main>:   0:e52db004 push{fp}; (str fp, [sp, #-4]!)   4:e28db000 addfp, sp, #0   8:e24dd00c subsp, sp, #12   c:e59f3020 ldrr3, [pc, #32]; 34 <main+0x34>  10:e50b3008 strr3, [fp, #-8]  14:e51b3008 ldrr3, [fp, #-8]  18:e2833001 addr3, r3, #1  1c:e50b3008 strr3, [fp, #-8]  20:e3a03000 movr3, #0  24:e1a00003 movr0, r3  28:e28bd000 addsp, fp, #0  2c:e8bd0800 pop{fp}  30:e12fff1e bxlr  34:12345678 .word0x12345678

可以看到ARM指令将大数字存在命令段,通过ldr指令去加载,而非MIPS等指令集使用lui和ori来实现32位大数字的实现。

写一个C的多重函数调用的程序,观察和分析:

调用时的返回地址在哪里?

传入的参数在哪里?

本地变量的堆栈分配是如何做的?

寄存器是caller保存还是callee保存?是全体保存还是部分保存?

1、编写测试代码
#include <stdio.h>int f2(int a, int b, int c, int x, int y, int z, int p, int q, int r) {        int temp = 0;        temp = a*x + b*y + c*z + p*q +r;        return temp;}int f3(int a,int b,int c,int d,int e,int f,int g,int h,int i,int j,int k)  {      int t1=a+b;      int t2=c+d;        int t3=e+f;      int t4=g+h;      int t5=i+j;        f2(1,2,3,4,5,6,7,8,9);      int t6=t1*t2;      int t7=t3*t4;      int t8=t6-t7;      int t9=t8*t5*k;        return t9;}  int f1(int a, int b, int c) {        int temp = 0;        temp = f2(a, b, c, 4, 5, 6, 7, 8, 9);        return temp;}int main() {        int a,b,c;        a = 0;        b = 1;        c = 2;        printf("%d", f1(a,b,c));        f3(11,10,9,8,7,6,5,4,3,2,1);        return 0;}

2、编译查看结果
pi@raspberrypi ~/code/arm $ gcc -c arm_multi_call.cpi@raspberrypi ~/code/arm $ objdump -d arm_multi_call.oarm_multi_call.o:     file format elf32-littlearmDisassembly of section .text:00000000 <f2>:   0:e52db004 push{fp}; (str fp, [sp, #-4]!)   4:e28db000 addfp, sp, #0   8:e24dd01c subsp, sp, #28   c:e50b0010 strr0, [fp, #-16]  10:e50b1014 strr1, [fp, #-20]  14:e50b2018 strr2, [fp, #-24]  18:e50b301c strr3, [fp, #-28]  1c:e3a03000 movr3, #0  20:e50b3008 strr3, [fp, #-8]  24:e51b3010 ldrr3, [fp, #-16]  28:e51b201c ldrr2, [fp, #-28]  2c:e0020392 mulr2, r2, r3  30:e51b3014 ldrr3, [fp, #-20]  34:e59b1004 ldrr1, [fp, #4]  38:e0030391 mulr3, r1, r3  3c:e0822003 addr2, r2, r3  40:e59b300c ldrr3, [fp, #12]  44:e59b1010 ldrr1, [fp, #16]  48:e0010391 mulr1, r1, r3  4c:e51b3018 ldrr3, [fp, #-24]  50:e59b0008 ldrr0, [fp, #8]  54:e0030390 mulr3, r0, r3  58:e0813003 addr3, r1, r3  5c:e0822003 addr2, r2, r3  60:e59b3014 ldrr3, [fp, #20]  64:e0823003 addr3, r2, r3  68:e50b3008 strr3, [fp, #-8]  6c:e51b3008 ldrr3, [fp, #-8]  70:e1a00003 movr0, r3  74:e28bd000 addsp, fp, #0  78:e8bd0800 pop{fp}  7c:e12fff1e bxlr00000080 <f3>:  80:e92d4800 push{fp, lr}  84:e28db004 addfp, sp, #4  88:e24dd050 subsp, sp, #80; 0x50  8c:e50b0030 strr0, [fp, #-48]; 0x30  90:e50b1034 strr1, [fp, #-52]; 0x34  94:e50b2038 strr2, [fp, #-56]; 0x38  98:e50b303c strr3, [fp, #-60]; 0x3c  9c:e51b2030 ldrr2, [fp, #-48]; 0x30  a0:e51b3034 ldrr3, [fp, #-52]; 0x34  a4:e0823003 addr3, r2, r3  a8:e50b3008 strr3, [fp, #-8]  ac:e51b2038 ldrr2, [fp, #-56]; 0x38  b0:e51b303c ldrr3, [fp, #-60]; 0x3c  b4:e0823003 addr3, r2, r3  b8:e50b300c strr3, [fp, #-12]  bc:e59b2004 ldrr2, [fp, #4]  c0:e59b3008 ldrr3, [fp, #8]  c4:e0823003 addr3, r2, r3  c8:e50b3010 strr3, [fp, #-16]  cc:e59b200c ldrr2, [fp, #12]  d0:e59b3010 ldrr3, [fp, #16]  d4:e0823003 addr3, r2, r3  d8:e50b3014 strr3, [fp, #-20]  dc:e59b2014 ldrr2, [fp, #20]  e0:e59b3018 ldrr3, [fp, #24]  e4:e0823003 addr3, r2, r3  e8:e50b3018 strr3, [fp, #-24]  ec:e3a03005 movr3, #5  f0:e58d3000 strr3, [sp]  f4:e3a03006 movr3, #6  f8:e58d3004 strr3, [sp, #4]  fc:e3a03007 movr3, #7 100:e58d3008 strr3, [sp, #8] 104:e3a03008 movr3, #8 108:e58d300c strr3, [sp, #12] 10c:e3a03009 movr3, #9 110:e58d3010 strr3, [sp, #16] 114:e3a00001 movr0, #1 118:e3a01002 movr1, #2 11c:e3a02003 movr2, #3 120:e3a03004 movr3, #4 124:ebfffffe bl0 <f2> 128:e51b3008 ldrr3, [fp, #-8] 12c:e51b200c ldrr2, [fp, #-12] 130:e0030392 mulr3, r2, r3 134:e50b301c strr3, [fp, #-28] 138:e51b3010 ldrr3, [fp, #-16] 13c:e51b2014 ldrr2, [fp, #-20] 140:e0030392 mulr3, r2, r3 144:e50b3020 strr3, [fp, #-32] 148:e51b201c ldrr2, [fp, #-28] 14c:e51b3020 ldrr3, [fp, #-32] 150:e0633002 rsbr3, r3, r2 154:e50b3024 strr3, [fp, #-36]; 0x24 158:e51b3024 ldrr3, [fp, #-36]; 0x24 15c:e51b2018 ldrr2, [fp, #-24] 160:e0030392 mulr3, r2, r3 164:e59b201c ldrr2, [fp, #28] 168:e0030392 mulr3, r2, r3 16c:e50b3028 strr3, [fp, #-40]; 0x28 170:e51b3028 ldrr3, [fp, #-40]; 0x28 174:e1a00003 movr0, r3 178:e24bd004 subsp, fp, #4 17c:e8bd8800 pop{fp, pc}00000180 <f1>: 180:e92d4800 push{fp, lr} 184:e28db004 addfp, sp, #4 188:e24dd030 subsp, sp, #48; 0x30 18c:e50b0010 strr0, [fp, #-16] 190:e50b1014 strr1, [fp, #-20] 194:e50b2018 strr2, [fp, #-24] 198:e3a03000 movr3, #0 19c:e50b3008 strr3, [fp, #-8] 1a0:e3a03005 movr3, #5 1a4:e58d3000 strr3, [sp] 1a8:e3a03006 movr3, #6 1ac:e58d3004 strr3, [sp, #4] 1b0:e3a03007 movr3, #7 1b4:e58d3008 strr3, [sp, #8] 1b8:e3a03008 movr3, #8 1bc:e58d300c strr3, [sp, #12] 1c0:e3a03009 movr3, #9 1c4:e58d3010 strr3, [sp, #16] 1c8:e51b0010 ldrr0, [fp, #-16] 1cc:e51b1014 ldrr1, [fp, #-20] 1d0:e51b2018 ldrr2, [fp, #-24] 1d4:e3a03004 movr3, #4 1d8:ebfffffe bl0 <f2> 1dc:e50b0008 strr0, [fp, #-8] 1e0:e51b3008 ldrr3, [fp, #-8] 1e4:e1a00003 movr0, r3 1e8:e24bd004 subsp, fp, #4 1ec:e8bd8800 pop{fp, pc}000001f0 <main>: 1f0:e92d4810 push{r4, fp, lr} 1f4:e28db008 addfp, sp, #8 1f8:e24dd034 subsp, sp, #52; 0x34 1fc:e3a03000 movr3, #0 200:e50b3010 strr3, [fp, #-16] 204:e3a03001 movr3, #1 208:e50b3014 strr3, [fp, #-20] 20c:e3a03002 movr3, #2 210:e50b3018 strr3, [fp, #-24] 214:e59f4078 ldrr4, [pc, #120]; 294 <main+0xa4> 218:e51b0010 ldrr0, [fp, #-16] 21c:e51b1014 ldrr1, [fp, #-20] 220:e51b2018 ldrr2, [fp, #-24] 224:ebfffffe bl180 <f1> 228:e1a03000 movr3, r0 22c:e1a00004 movr0, r4 230:e1a01003 movr1, r3 234:ebfffffe bl0 <printf> 238:e3a03007 movr3, #7 23c:e58d3000 strr3, [sp] 240:e3a03006 movr3, #6 244:e58d3004 strr3, [sp, #4] 248:e3a03005 movr3, #5 24c:e58d3008 strr3, [sp, #8] 250:e3a03004 movr3, #4 254:e58d300c strr3, [sp, #12] 258:e3a03003 movr3, #3 25c:e58d3010 strr3, [sp, #16] 260:e3a03002 movr3, #2 264:e58d3014 strr3, [sp, #20] 268:e3a03001 movr3, #1 26c:e58d3018 strr3, [sp, #24] 270:e3a0000b movr0, #11 274:e3a0100a movr1, #10 278:e3a02009 movr2, #9 27c:e3a03008 movr3, #8 280:ebfffffe bl80 <f3> 284:e3a03000 movr3, #0 288:e1a00003 movr0, r3 28c:e24bd008 subsp, fp, #8 290:e8bd8810 pop{r4, fp, pc} 294:00000000 .word0x00000000



可以发现:
函数调用后的返回地址存放在LR寄存器中。
传入的参数存放在R0 R1 R2 R3四个寄存器中,多余的参数放在堆栈中。
本地变量存放在堆栈高地址,传进来的参数存放在堆栈低地址。
R0到R3由caller保存,R4以上由callee保存。

MLA是带累加的乘法,尝试要如何写C的表达式能编译得到MLA指令。

1、编写函数如下:
#include <stdio.h>int f1(int a, int b, int c) {        return a*b + c;}int main() {        f1(1,2,3);        return 0;}

2、编译查看结果:


可以看到MLA命令得到了使用。

原创粉丝点击