zoukankan      html  css  js  c++  java
  • 第二季-专题3-汇编语言得玩转

    专题3-汇编语言得玩转

     

    第1课-汇编概述

    1.为什么学习汇编指令

    以后的工作中我们用的都是中高端的处理器,基本不会用汇编去编程完成这个产品。但是在bootloader和内核的编程中我们都是要用汇编语言的,这期间c语言的运行环境还没有搭建。在对效率有有特殊要求的地方我们还是需要汇编语言的。

    2.分类

    目前常用的ARM的汇编指令有两种:

    (1)ARM标准汇编:适用于ARM公司的汇编器,适合在windows平台下使用,如ADS中使用。ADS是基于windows的集成程序。

    (2)GNU汇编:适用于GNU交叉编译器工具链中的汇编器,适合linux开发平台。我们使用的是GNU汇编

    3.汇编程序框架

    .sectiom.data

    <初始化的数据>

    .section.bss

    <未初始化的数据>

    .section.text      /*代码段*/

    .global _start     /*全局访问*/

    _start:

    <汇编代码>

    简化:

    .text

    .global _start

    _start:

    <汇编代码>

    4.编程准备

    (1)首先在相应的文档里面建立一个名字为start.s的文件,文件内容如下:

    .text

    .global _start                  //定义全局变量

    _start:                       //程序入口

    mov r1,#1             /*将1这个立即数,放在r1寄存器里面*/

    mov r2,#2

    mov r3,#3

    (2)建立一个Makefile,内容如下:

    all:start.o

    arm-linux-ld -Ttext 0x20000000 -o start.elf $^    /*指明程序运行的起止地址*/

    %.o : %.S

    Arm-linux-gcc -g -o $@ $^ .c

    Clean

        rm *.o *.elf

             /*针对210的开发板,代码段的指定开头就是20000000,对于6410是50000000,2440是30000000*/

             连接器脚本对整个程序的地址进行排布,可以在开头进行运行地址的设置。

             以Jlink的方式连接开发板与电脑,运行Jlink发现联接上了,启动我们自己安装的eclipse软件,编译我们编译的软件。按上面章节的方法,进行一系列的配置与初始化调试。

    第二课-指令分类学习

    GUN汇编和ARM标准汇编是有区别的,一般来说GUN是小写的,标准ARM是大写的。

    1. 算数和逻辑指令

    (1)mov装载

    mov{条件}[S]  <dest>, <op_1>

    C语言转换:dest = op_1

             mov从一个寄存器、被位移的寄存器、或一个立即数装载到目的寄存器。

             dest必须是通用寄存器,op_1可以是通用寄存器、状态寄存器也可以是数字。

    注:汇编语言的注释是@符号后面加注释的。

    (2)mvn取反装载

    mvn{条件}[S]  <dest>, <op_1>

    C语言转换:dest = !op_1

             mvn从一个寄存器、被位移的寄存器、或一个立即数装载到目的寄存器。不同之处是在传送之前位被取反了,是把取反的值传给一个寄存器。这是逻辑操作不是算数操作,这个取反的值加1才是它的取负的值。

             mov R0, #4            R0变成-5

             mov R0, #0            R0变成-1

    (3)sub相减

    sub{条件}[S]  <dest>, <op_1> <op_2>

             dest= op_1- op_2

             sub用来执行减法操作,操作数1是一个寄存器,操作数2可以是一个寄存器、被位移的寄存器或者是一个立即数。

    (4)add相加

    add{条件}[S]  <dest>, <op_1> <op_2>

    dest= op_1+op_2

             add用来执行加法操作,操作数1是一个寄存器,操作数2可以是一个寄存器、被位移的寄存器或者是一个立即数。

    (5)and逻辑与

    and{条件}[S]  <dest>, <op_1> <op_2>

    dest= op_1&op_2

    and用来执行逻辑与操作。操作数1是一个寄存器,操作数2可以是一个寄存器、被位移的寄存器或者是一个立即数。

    (6)bic位清除

    bic{条件}[S]  <dest>, <op_1> <op_2>

    dest= op_1and(!op_2)

             在一个字中清除位的一种方法,与or位设置是相反的操作。操作数2是一个32位的位操作符(mask)。如果在操作码中设置了某一位,就清除这一位。未设置操作码的位保持不变。

             bic r0, r0, #1011        表示清除r0中的第0、1、3位,其余的位不变

    2. 比较指令

    (1)cmp比较

    cmp{条件}[S]  <op_1> <op_2>

    status= op_1-op_2

             status为1表示操作数1大,为-1表示操作数2大,为0表示一样大。它改变的是CPSR寄存器的31位(M位)于30位(N位)。

    例子

    mov r1, #2

    cmp r1, #1

    cpsr为200001d3 

    mov r1, #2

    cmp r1, #1

             cpsr为800001d3

    mov r1, #2

    cmp r1, #2

             cpsr为600001d3

    (2)tst按位与

    tst{条件}[S]  <op_1> <op_2>

    status= op_1 AND op_2

             按位与之后的结果是0,CPSR的30位(Z位)置1,否则CPSR的30位(Z位)不置1。

    例子

    mov r1, #0b101

    tst  r1, #0b001

    cpsr为200001d3

    mov r1, #0b101

    tst  r1, #0b101

    cpsr为600001d3

    3. 跳转指令

             汇编的程序需要分支指令完成C语言中的if…else操作

    (1)b分支

    b{条件} <地址>

    存储在分支指令中的实际的值是相当于当前的r15的一个偏移量,并不是一个绝对地址。它的值由汇编器来计算,它是24位有符号量,左移两位后有符号扩展为32位,表示的有效偏移量是26位(+/-32M)。

    例子:

    mov r1,#6

    mov r2,#5

    cmp r1,r2

    bgt branch1:

    add r3, r1, r2

    b end

    branch1:

    sub r3,r1,r2

    end:

    nop

    EQ : 等于

    如果一次比较之后设置了 Z 标志。

    NE : 不等于

    如果一次比较之后清除了 Z 标志。

    VS : 溢出设置

    如果在一次算术操作之后设置了 V 标志,计算的结果不适合放入一个 32bit 目标寄存器中。

    VC : 溢出清除

    如果清除了 V 标志,与 VS 相反。

    HI : 高于(无符号)

    如果一次比较之后设置了 C 标志并清除了 Z 标志。

    LS : 低于或同于(无符号)

    如果一次比较操作之后清除了 C 标志或设置了 Z 标志。

    PL : 正号

    如果一次算术操作之后清除了 N。出于定义‘正号’的目的,零是正数的原因是它不是负数...

    MI : 负号

    如果一次算术操作之后设置了 N 标志。

    CS : 进位设置

    如果一次算术操作或移位操作之后设置了 C 标志,操作的结果不能表示为 32bit。你可以把 C 标志当作结果的第 33 位。

    CC : 进位清除

    与 CS 相反。

    GE : 大于或等于(有符号)

    如果一次比较之后...
    设置了 N 标志并设置了 V 标志
    或者...
    清除了 N 标志并清除了 V 标志。

    GT : 大于(有符号)

    如果一次比较之后...
    设置了 N 标志并设置了 V 标志
    或者...
    清除了 N 标志并清除了 V 标志
    并且...
    清除了 Z 标志。

    LE : 小于或等于(有符号)

    如果一次比较之后...
    设置了 N 标志并清除了 V 标志
    或者...
    清除了 N 标志并设置了 V 标志
    并且...
    设置了 Z 标志。

    LT : 小于(有符号)

    如果一次比较之后...
    设置了 N 标志并清除了 V 标志。
    或者...
    清除了 N 标志并设置了 V 标志。

    AL : 总是

    缺省条件,所以不用明显声明。

    NV : 从不

    不是特别有用,它表示应当永远不执行这个指令。是穷人的 NOP。
    包含 NV 是为了完整性(与 AL 相对),你不应该在你的代码中使用它。

    (2)bl带链接返回的分支

             b指令在跳转之前不能将返回地址保存,bl就可以将返回地址保存,可以起到类似C语言的对函数进行封装的效果。

    例如:

    mov r1, #6

    cmp r1, #5

    bl func1:

    mov r1, #2

    cmp r1, #3

    func1:

    mov r1, #r2

    mov r2, #3

    mov pc, lr

    4. 移位指令

    (1)lsl逻辑(算数)左移

    例如:

    mov r1, #0b1

    mov r1,r1, lsl#2

    对r1左移两位,将结果再存在r1中,r1从0b1变成0b100

    (2)ror循环右移

    例如:

    mov r1, #0b11

    mov r1,r1, ror#1

             r1的值从0b11变成0b1000000000000000000000000000001,一共32位。

    5. 程序状态字访问指令

             程序状态寄存器所用的访问指令和前面的指令不能是一样的,对它们的修改,需要将CPSR或者SPSR中的指令搬移到通用寄存器,改好后再搬回程序状态寄存器。

    msr(搬入)和mrs(搬出)两条指令:

    例子:

    mrs r0, cpsr

    orr r0, 0b100

    msr cpsr, r0

             将cpsr的第三位设置为1

    6. 存储器访问指令

    (1)ldr将内存中的值导入寄存器

    str    rd, [Rbase]          存储 rd 到 Rbase 所包含的有效地址。

       str    rd, [Rbase, Rindex]  存储 rd 到 Rbase + Rindex 所合成的有效地址。

       str    rd, [Rbase, #index]  存储 rd 到 Rbase + index 所合成的有效地址。

                                   index 是一个立即值。

                                   例如,rTR rd, [R1, #16] 将把 rd 存储到 r1+16。

       str    rd, [Rbase, Rindex]! 存储 rd 到 Rbase + Rindex 所合成的有效地址,

                                   并且把这个新地址写回到 Rbase。

       str    rd, [Rbase, #index]! 存储 rd 到 Rbase + index 所合成的有效地址,

                                   并且并且把这个新地址写回到 Rbase。

       str    rd, [Rbase], Rindex  存储 rd 到 Rbase 所包含的有效地址。

                                   把 Rbase + Rindex 所合成的有效地址写回 Rbase。

       str    rd, [Rbase, Rindex, lsl #2]

                                   存储 rd 到 Rbase + (Rindex * 4) 所合成的有效地址。

       str    rd, place            存储 rd 到 PC + place 所合成的有效地址。

    (2)str将寄存器中的值保存到内存

    第3课-伪指令

    一.ARM机器码

             汇编程序通过汇编器转化成机器码,机器码才能够在嵌入式芯片上运行。Arm机器码是32位的整数,机器码被分成不同大小的段,每个段都有各自独特的功能

             mov r0, r1的机器码是e1a00001

    二进制是:1110 00 0 1101 0 0000 0000 000000000001

             moveq r0, #255的机器码是03a000ff

    二进制是:0000 00 1 1101 0 0000 0000 000011111111

             对于mov指令它的机器码格式如下:

            

             第一段前4位表示条件,1110表示无条件,0000表示等于的条件

             第二段是保留位,是00

             第三段表示0-11存的是立即数的话就是1,存的是寄存器的话就是0

             第四段opcode,它的作用是区分指令,mov指令就是1101

             第五段是S,程序运行后影响CPSR寄存器就是1,不影响就是0

             第六段是Rn,

             第七段是目的寄存器,我们用的是r0,用的是0来标号,r1是0001

             第八段是源操作数,寄存器r1是00000000001,#255是00001111111

             这样我们可以观测到,第八段中存放数的大小是有限的,这样引出伪指令的概念。

    二.定义类伪指令

             伪指令本身并没有对应的机器码,它只是在编译而定时候起作用,或者转化为其他的实际指令来运行。

    (1)       global标明全局符号

    (2)       data标明数据段

    (3)       ascii标明字符串指令

    (4)       byte标明字节的指令

    (5)       word标明字的指令

    例子:

    .data

    hello:

    .ascii “hellloworld”

    bh:

    .byte 0x1

    ADD

    .word 0xff

    (6)       equ相当于宏定义

    .equ DA,0x89

    mov r0, DA

    (7)       align对齐,在文件前面加上.align就会表示按四字节对齐

    三.操作类伪指令

    (1)nop

    空操作,主要的作用是延时的作用。

    (2)ldr(与存储器的访问指令不同)

    mov r0, 0x1ff运行的时候会出错,因为mov指令只能处理8位的二进制数,0x1ff是9位,机器码的0-11位中有四位是存储左移与右移操作的,所以存储的内容不能超过8位。

    它可以在r0里面填充超过8位的立即数,但是格式特殊:

    ldr r0, =0x1ff

    第4课-协处理访问指令

    一.什么是协处理器

             协处理器用于执行特定的处理任务,如:数学协处理器可以控制数字处理,以减轻处理器的负担。ARM可支持最多16个协处理器,其中CP15是最重要的一个。

    1. CP15的作用

    CP15是系统控制协处理器,提供了额外的寄存器,通过这些寄存器,可以达到配置与控制caches、MMU以及时钟参数。

    1. CP15寄存器

    CP15提供了16组寄存器,具体的使用可以在Arm公司提供的芯片手册中找到。我们通过它提供的16组寄存器,可以访问cp15寄存器。

    二.协处理器访问

    1. mcr

    r表示通用寄存器,c表示协处理器寄存器

    2.mrc

    格式:

     

    例子:读取mainID

             mrc p15, 0, r0, c0, c0, 0             表示读取mianID寄存器的值

             

  • 相关阅读:
    【线型DP】【LCS】洛谷P4303 [AHOI2006]基因匹配
    【状压DP】SCOI2005-洛谷P1896-互不侵犯 (状压例题)
    【01背包】百度之星--度度熊剪纸条
    【线型DP】CF1012C Hills 小山坡
    【经典DP】洛谷P2285 [HZOI]2004 打鼹鼠
    【盗版动归】Codeforces998C——Convert to Ones 归一操作
    MySQL使用笔记(1)
    大学物理——光的干涉和衍射(2)
    大学物理——光的干涉和衍射(1)
    hdu5747 Aaronson 贪心
  • 原文地址:https://www.cnblogs.com/free-1122/p/11451986.html
Copyright © 2011-2022 走看看