嵌入式Lab2:Arm指令

这个实验的目的是深入理解ARM和Thumb指令的特点,了解编译选项对代码产生的影响。

配合课程

ARM处理器

实验目的

  • 深入理解ARM指令和Thumb指令的区别和编译选项;
  • 深入理解某些特殊的ARM指令,理解如何编写C代码来得到这些指令;
  • 深入理解ARM的BL指令和C函数的堆栈保护;
  • 深入理解如何实现C和汇编函数的互相调用。

实验器材

硬件

  • 实验主板一块(raspberryPi);
  • 5V/1A电源一个;
  • microUSB线一根;

软件

  1. 交叉编译软件(arm-linux-gcc)

操作方法和实验步骤

  1. 实验设备连接示意图

    连接示意图

  2. 同一个程序,用arm指令和thumb指令编译,得到的结果有什么不同
    代码如下:
    //hello.c
    #include <stdio.h>

    int main(){
        printf("Hello World\n");
        return 0;
    }
    

用两种不同的方式编译:


编译程序 hello.c

得到的结果:


指令对比

区别:
  • thumb的指令地址一次只增加2,即每条指令只占16位。相对的,arm每个地址增加4,每条指令占位32位。
  • 在 Thumb 状态下,单寄存器加载和存储指令只能访问寄存器 R0~R7。
  1. 对于 ARM 指令,能否产生条件执行的指令
    可以的,C语言代码:
    //if.c
    #include <stdio.h>
    int main(){
    int i;
    i = 1;
    if(i == 1)i++;
    else i--;
    return 0;
    }
    生成的ARM指令代码<main>函数部分:

    if_arm.S

    其中可以看到bne指令。

  2. 设计 C 的代码场景,观察是否产生了寄存器移位寻址
    C语言代码如下:
    //shift.c
    #include <stdio.h>
    int lShift(int *i, int j){
    return i[j << 2];
    }
    int main(){
    int i[256];
    int j = 18;
    lShift(i, j);
    return 0;
    }
    生成的ARM指令代码主要部分(可以看到ldr指令):

    shift_ARM.S

  3. 设计 C 的代码场景,观察一个复杂的 32 位数是如何装载到寄存器的
    C语言代码如下:
    //load32.c
    #include <stdio.h>
    int main(){
    double i;
    long j;
    i = 204800001.1;
    j = 2048000011;
    return 0;
    }
    生成的ARM代码如下:

    Load32_ARM.S

    可以看出,ARM是将32位数放到堆栈中,然后依次取出放入到寄存器当中。

  4. 写一个 C 的多重函数调用的程序,观察和分析: a. 调用时的返回地址在哪里? b. 传入的参数在哪里? c. 本地变量的堆栈分配是如何做的? d. 寄存器是 caller 保存还是 callee 保存?是全体保存还是部分保存?
    C代码如下:
    //mulFunc.c
    #include <stdio.h>
    int fun1(int i){
    int j = i + 1;
    return j;
    }

    int fun2(int i, int j){
       int x = i + j;
       x = fun1(x);
       return x;
    }
    
    int main(){
       int a = 1, b = 2;
       a = fun2(a, b);
       return 0;
    }
    

得到的ARM汇编代码如下:


mulFunc_ARM.S

a.调用时的返回地址放在lr寄存器当中。
b.传递的参数放在了堆栈中。
c.被调函数首先将传递过来的堆栈指针 sp 拷贝到指针 fp 中,然后将本地变量从 r0 开始存放,当存放到 r2 之后,其余的变量将会通过 r3 存放到堆栈中去,最后将 fp 中保存的指针拷贝回 sp,恢复被调前的堆栈情况,然后返回。
d.参数保存在caller,地址保存在callee,部分保存的

  1. MLA 是带累加的乘法,尝试要如何写 C 的表达式能编译得到 MLA 指令
    C代码如下:
    //mla.c
    #include <stdio.h>
    int mla(int i, int j, int k){
    return i * j + k;
    }

    int main(){
        int i = 2, j = 20, k = 30;
        mla(i, j, k);
        return 0;
    }
    

编译得到的ARM汇编文件(编译时用-O1优化编译)


mla_ARM.S

可以看到mla指令。

  1. BIC是对某一个比特清零的指令,尝试要如何写 C 的表达式能编译得到 BIC 指令
    C代码如下:
    //bic.c
    #include <stdio.h>
    int bic(int i, int j){
    return i&~j;
    }

    int main(){
        int i = 0x8828;
        int j = 20484;
        bic(i, j);
        return 0;
    }
    

汇编得到的ARM指令(要使用-O1编译优化)


bic_ARM.S

可以很明显的看到bic指令。

  1. 编写一个汇编函数,接受一个整数和一个指针做为输入,指针所指应为一个字符串,该汇编函数调用C语言的 printf()函数输出这个字符串的前n个字符,n即为那个整数。在C语言写的main()函数中调用并传递参数给这个汇编函数来得到输出。
    汇编函数代码(cutprint.S):
    .global cutprint
    cutprint:
    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语言主函数代码:
//cutprint.c
#include <stdio.h>

    extern int cutprint(char *, int);
    int main(){
        int a;
        char s[100];
        scanf("%s %d", s, &a);
        a = cutprint(s, a);
        printf("Print %d character.\n", a);
        return 0;
    }

编译后在树莓派的执行结果:


测试1

测试2

测试3
  1. 自选扩展内容1:编写测试程序,测试ARM指令和Thumb指令的执行效率
    测试代码:
    //speed.c
    #include <stdio.h>

       int fibo(int n){
           if(n <= 1) return 1;
           return fibo(n - 2) + fibo(n - 1);
       }
    
       int main(){
           int a;
           scanf("%d", &a);
           printf("%d\n", fibo(a));
           return 0;
       }
    

在编译时,在普通编译之外,还有-O2和-O3编译优化的编译。


编译选项

测试结果

从测试结果中可以看到,arm的执行速度要比thumb的执行速度快一些。

  1. 自选扩展内容2:编写测试程序,测试使用带条件的ARM指令和不使用时的执行效率。
    含带条件的ARM指令(useif.S):
    .global add
    add:
    CMP R0, #0
    ADDNE R0, R0, R1
    MOV pc, lr
    不含的ARM指令(noif.S):

    .global add
    add:
       CMP R0, #0
       ADD R0, R0, R1
       MOV pc, lr
    

测试代码:
//test.c
#include <stdio.h>

        extern int add(int, int);

        int main(){
            int a, b, i, times;
            scanf("%d %d %d", &a, &b, &times);
            for (i=0; i<times; i++)
                a = add(a, b);
            printf("%d\n", a);
            return 0;
        }

编译选项:


编译过程

执行结果

通过比较执行结果可以发现两个程序执行的时间基本上没有什么差别。

讨论与心得

本次实验主要是对代码的编写和对ARM指令的了解,没有涉及过多的硬件上的内容。需要的硬件内容(交叉编译环境以及连接和文件传递)在上次实验已经设计,所以从总体上来说比上一次实验简单。
同时本次使用和让我了解到了ARM指令的一些性质,以及ARM指令和Thumb指令的区别。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容