ARM体系结构与编程基础知识笔记

1 处理器共有7中运行模式用户模式,快速中断模式,外部中断模式,特权模式,数据访问中止模式,未定义指令中止模式,系统模式,除了用户模式之外的其他6中模式称为特权模式,在这些模式下,程序可以访问所以系统资源,也可以任意进行处理器模式切换,其中,除系统模式外,其他5中特权模式又称为异常模式。

处理器模式可以通过软件控制进行切换,也可以通过外部中断或异常处理处理过程进行切换。大多数的用户程序运行在用户模式下。这是,应用程序不能够访问一些手操作系统保护的系统资源,应用程序也不能直接进行处理器模式的切换。当需要进行处理器模式切换时,应用程序可以产生异常处理,在异常处理过程中进行处理器模式的切换。这种体系结构可以使操作系统控制整个系统的资源。

当应用程序发生异常中断时,处理器进入相应的异常模式。在每一种模式中都有一组寄存器,供相应的异常处理器程序使用,这样就可以保证在进入异常模式时,用户模式下的寄存器(保存了程序运行状态)不被破坏。

系统模式并不是通过异常过程进入的,它和用户模式具有完全一样的寄存器。但是西贡模式属于特权模式,可以访问所有的系统资源,也可以直接进行处理器模式切换。他主要供操作系统任务使用。通常操作系统的任务需要访问所有的系统资源,同时该任务仍然使用用户模式的寄存器组,而不是使用异常模式下相应的寄存器组,这样可以保证当异常中断发生时任务状态不被破坏。

1 在ARM体系中通常有以下3中方式控制程序的执行流程

       、在正常程序执行过程中,每执行一天ARM指令,程序计数器寄存器(PC)的值加4个字节,每执行一天Thumb指令,程序计数器寄存器PC的值加两个字节。整个过程是按顺序执行。

       、当异常中断发生时,系统执行完当前指令,将跳转到相应的异常中断处理程序处执行。在异常中断处理程序执行完成后,程序返回到发生中断的指令的下条指令执行。

实例:8086A的中断系统

8086A处理器是INTEL公司于20世纪70年代末推出的一款16位处理器。该处理器在中断处理上有如下特色,这些特色也为后续INTEL处理器所共有。

[编辑] 引脚

8086A提供两个中断引脚:第17引脚NMI,和第18引脚INTR。前者用于接收非可屏蔽中断,后者则接收可屏蔽中断。通常,INTR引脚与中断控制器(如8259A)相连,后者再分别与各设备的中断请求引脚连接。除了INTR外,8086A还将自身的16位地址总线(配合M/IO引脚并通过译码器)及8位数据总线与8259A连接,并将INTA引脚与8259A的同名引脚相连。

[编辑] 中断向量表

在存储器地址空间中,规定最低的1K空间,即00000H到003FFH为中断向量表。全表共含256个中断向量,每个向量的长度为4字节,包含中断处理程序的起始地址。共有从0255256个中断类型码,每个中断类型码对应的中断向量所在地址为该类型码乘以4。举例而言,如果中断类型码为1,则对应中断向量所在地址为00004H;如果中断类型码为33,则对应中断向量所在地址为00084H。这样,如果已知一个中断类型码,则需要通过两次地址转换(中断类型码到中断向量表地址;中断向量表地址到中断处理程序地址)才能到达中断处理程序。另外应注意每一个中断向量所包含的地址是以低二字节存储偏移量,高二字节存储段地址的形式存储目标地址值的。

在全部256个中断中,前32个(0—31)为硬件系统所预留。后224个可由用户设定。在初始化8259A时,可设定其上各中断引脚(共8条)对应的中断类型码。同时,将对应此中断之处理程序的起始地址保存在该中断类型码乘4的地址位中,作为中断向量。

INTEL 后续的 32 CPU 中,使用中断描述符表来代替中断向量表。中断描述符表的起始地址由中断描述符表寄存器( IDTR )来定位,因此不再限于底部 1K 位置。另一方面,中断描述符表的每一个项目——称作门描述符——除了含有中断处理程序地址信息外,还包括许多属性/类型位。门描述符分为三类:任务门、中断门和自陷门。CPU对不同的门有不同的调用(处理)方式。

[编辑] 中断处理过程

在实际运行中,一旦设备通过某引脚N向8259A发出中断指令,后者便向8086A的INTR引脚发送中断信号。8086A通过INTA引脚通知8259A中断有效(这个过程实际上还包括对8259A的选址),后者即通过地址总线将对应引脚N的中断类型码(已预先存好,见上节)发送给CPUCPU得到中断类型码后,先进行现场保护,主要包括:

状态寄存器FLAGS压栈(同时堆栈寄存器SP-2);

关闭中断(将FLAGS寄存器的IF位置零);

将当前代码段寄存器CS和程序计数器IP压栈(同时堆栈寄存器SP-4)。

现场保护完成后, CPU 开始按照前述的两步骤翻译中断程序入口地址。在得到中断处理程序地址之后但调用中断处理程序之前, CPU 会再检查一下 NMI 引脚是否有信号,以防在刚才的处理过程中忽略了可能的 NMI 中断。 NMI 的优先级始终高于 INTR  。

中断处理程序虽然是由程序员编写,但须循一定规范。作为例程,中断处理程序应该先将各寄存器信息(除了IPCS,此二寄存器现已指向当前中断程序)压入堆栈予以保存,这样才能在中断处理程序内部使用这些寄存器。在程序结束时,应该按与压栈保护时相反的顺序弹出各寄存器的值。中断程序的最后一句始终是IRET指令,这条指令将栈顶6个字节分别弹出并存入IPCSFLAGS寄存器,完成了现场的还原。

当然,如果是操作系统的中断处理程序,则未必——通常不会——还原中断前的状态。这样的中断处理程序通常会在调用完寄存器保存例程后,调用进程调度程序(多由高级语言编写),并决定下一个运行的进程。随后将此进程的寄存器信息(上次中断时保存下来的)存入寄存器并返回。在中断程序结束之后,主程序也发生了改变。

[编辑] 相关指令

一些与中断控制相关的指令包括:

CLI 关闭中断(实为将FLAGS的IF位置0)。

STI 开启中断(实为将FLAGS的IF位置1)。

INT n 调用中断子程序,n为中断类型码。DOS系统有一个系统调用API即为INT 21H。

INT0 先判别FLAGSOF位是否为1,如是则直接调用类型为4的中断子程序,用以处理溢出中断。

IRET 将栈顶6个字节分别弹出并存入IPCSFLAGS寄存器,用以返回中断现场。

 

 

2 ARM指令的分类

       、ARM指令集可以分为跳转指令,数据处理指令,程序状态寄存器PSR传输指令,Load/Store指令,协处理器指令和异常中断产生指令6类。

       、ARM指令字长为固定的32位。

2.1 数据处理指令的操作数的寻址方式

       、通常数据处理指令格式

              <opcode>{<cond>}{S} <Rd>,<Rn>,<shifter_operand>

其中<shifter_operand> 表示第二个操作数,通常有下面3中格式

            、立即数方式:每个立即数由一个8位的常数循环右移偶数位得到。其中循环右移的位数由一个4位二进制的两倍表示。如果立即数记作<immediate> ,8位常数记作immed_84位的循环右移值记作rotate_imm,则有:

<immediate> = immed_8 循环右移(2 * rotate_imm)

例:1020=0x3FC,表示为<shifter_operand>就是(#0xFF,30),即8位立即数FF循环右移30位。

这里的0x3fc 到 0xFF,30  是怎么个过程

0X3FC=00000000,00000000,00000011,11111100,共32位。

0XFF =00000000,00000000,00000000,11111111,也是32位。

你看一下,0X3FC循环左移30位,也就是循环右移2位,是不是等于0XFF.

之前说的合法和不合法,指的是:

在32位的二进制中,第一个“1”和最后一个“1”,

跨度大于8位,就是不合法。(比如0x101,分开来,跨度是9个位置了)

跨度小于8为,就合法。(比如0xF000000F,虽然本来是跨度很大的,如果循环左移或右移4位,跨度刚好是8个位置。)

2.2 字及无符号字节的Load/Store指令的寻址方式

       、load指令用于从内存中读取数据放入寄存器中,Store刚好相反。

       、各种类型的load/Store指令的寻址方式由两方面组侧很难过。一部分为一个的基址存器:另一部分为一个地址偏移量。基址寄存器可以为人一个通用寄存器,地址偏移量可以有以下3种格式。立即数,寄存器,寄存器及一个移位常数。Rnaddress_mode一起构成第二个操作数的内存地址。

2.3 杂类load/Store指令的寻址方式

32位固定指令中的S,H位控制着操作数是字还是字节

2.4 批量load/Store指令的寻址方式

一条批量load/Store 指令可以实现在一组寄存器和一块连续的内存单元之间传输数据,通常所说的多寄存器寻址,也就是一次可以传送几个寄存器的值,允许一条指令最多传送16个寄存器,其语法格式如下:

      LDM/STM{<cond>} <addressing_mode>  <Rn>{!},<register>{^}

其中指令中寄存器和内存单元的对应关系满足这样的规则,即编号低的寄存器对应于内存中低地址单元,编号高的寄存器对应于内存中高地址单元,<Rn>中存放地址块的最低地址值。

<addressing_mode>表示地址的变化方式,有以下4种方式。

 

                                    P     U

IA (Increment After)事后递增方式    0    1

IB 事先递增方式                        1

DA 事后递增方式                        0

DB (Decrement Before)事先递减方式      0

3 ARM指令集介绍

       、ARM指令集可以分为6类,即跳转指令,数据处理指令,程序状态寄存器(PSR)传输指令,load/store指令,协处理器指令,异常中断产生指令。

·3.1 ARM中有两种方式可以实现程序的跳转:一种是跳转指令,另一种是直接向PC寄存器(R15)中写入目标地址值。

          、通过直接向PC寄存器中写入目标地址值可以实现在4GB的地址空间中任意跳转,这种跳转指令又称为长跳转。如果在长跳转指令之前使用MOV LR,PC等指令,可以保存将来返回的地址值,就实现了在4GB的地址空间中的子程序调用。

      、ARM的跳转指令可以从当前指令向前或向后的32MB的地址空间跳转。这类跳转指令有以下4种:

       ·B 跳转指令     

       ·BL 带返回的跳转指令

       ·BLX 带返回和状态切换的跳转指令

       ·BX 带状态切换的跳转指令

      、1 BBLB指令和BL指令均可以跳转到指令中的目标地址,这两个指令和目标地址处的指令都属于ARM指令集。二者也都可以根据CPSR中条件标志位的值与指令中的执行条件决定是否执行跳转操作。二者不同之处在于,B指令仅仅执行跳转操作,BL指令同时还将PC寄存器的值保存到LR寄存器中。

·3.2 数据处理指令又可大致分为3类:数据传送指令,如MOV;算术逻辑运算指令,如ADD,SUB,AND等;比较指令,如TST。

      、数据传送指令用于向寄存器中传入一个常数。该指令包括一个目标寄存器和一个源操作数,源操作数的计算方法在2.2节已详细描述。

      、算术逻辑运算指令通常包括一个目标寄存器和两个源操作数。其中一个源操作数为寄存器的值,另外一个源操作的计算方法已在2,2中描述。算术逻辑运算指令将运算结果存入目标寄存器,同时更新CPSR中相应的条件标志位。

      、比较指令不保存运算结果,只更新CPSR中相应的条件标志位。

  、MOV 指令可以完成的功能     重点功能

      1 PC寄存器作为目标寄存器时可以实现程序跳转。这种跳转可以实现子程序调用以及 从子程序中返回。

      2 PC寄存器作为目标寄存器且指令中S位被设置时,指令在执行跳转操作的同时,即那个当前处理器模式的SPSR寄存器内容复制到CPSR中。这样指令MOVS PCLR可以实现从某些异常中断中返回。

      、MVN指令用途

       1 向寄存器传送一个负数

       2求一个数的反码

       3 生成位掩码。

      、SUB指令实现两个操作数相减当SUBS指令与跳转指令联合使用时可以实现程序中循环。这时不需要CMP指令。

      、RSB逆向减法指令

       1 RSB Rd,Rx,#0 ; Rd = -Rx

       AND 可以使某些位置0 ORR 可以使某些位置1 EOR指令可以用于将寄存器中某些位的值取反。将某一位与0做逻辑异或操作,该位值不变,将某一位与1做逻辑异或操作,该位值将被求反。

      BIC指令可用于将寄存器中某一些位的值设置成0。将某一位与0BIC操作,该位值被设置成0,将某一位与1BIC操作,该位值不变。 

      、CMP指令与SUNS指令的区别在于CMP指令不保存操作结果。

      、TST位测试指令:TST指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位做逻辑与操作,根据操作结果更新CPSR中相应的条件标志位。TST指令通常用于测试寄存器中某一(些)位是1还是0

      TEQ相等测试指令:TEQ指令将<shifter_operand>表示的数值与寄存器<Rn>的值按位做逻辑异或操作,根据操作结果更新CPSR中相应的条件标志位。

3.3 状态寄存器访问

ARM中有两条指令用于在状态寄存器和通用寄存器之间传送数据。

              、程序不能通过直接修改CPSR中的T控制位直接将程序状态切换到Thumb状态,必须通过BX等指令完成程序状态的切换。通常修改状态寄存器是通过“读取-修改-写回”的操作序列来实现的。

状态寄存器访问指令包括以下两条:

        、MRS 状态寄存器到通用寄存器的传送指令。

              ·指令的使用

                     1 用于将状态寄存器的内容读到通用寄存器中

                            2 当异常中断允许嵌套时,需要在进入异常中断之后,嵌套中断发生之前保存当前处理器模式对应的SPSR。这时需要先通过MRS指令读出SPSR的值,再用其他指令将SPSR值保存起来。

                     3 在进程切换时也需要保存当前状态寄存器值。

       、MSR 通用寄存器到状态寄存器的传送指令。

  ·3.4 批量load/store内存访问指令

              LDM 指令将数据从连续的内存单元中读取到指令中寄存器列表中的各寄存器中。它主要用于块数据的读取,数据栈操作以及从子程序中返回的操作。

        、LDM(3) (带状态寄存器的批量内存字数据读取指令)指令将数据从连续的内存单元中读取到指令中寄存器列表中的各寄存器中。它同时将当前处理器模式对应的SPSR寄存器内容复制到CPSR寄存器中。

        STM2)(用户模式的批量内存字数据写入指令)指令将指令中寄存器列表中的各寄存器(用户模式对应的寄存器)数值写入到连续的内存单元中。它主要用于数据块的写入,数据栈操作以及进入子程序时保存相关的寄存器的操作。

        ·指令使用

             本指令主要用于从异常中断模式下返回,如果在用户模式或系统模式下使用该指令,会产生不可预知的结果。本指令后面不能紧跟访问备份寄存器的指令,最后跟一条NOP指令。指令中的基址寄存器是指令执行时的当前处理器模式对应的物理寄存器,而不是用户模式对应的寄存器。

· 3.5 信号量操作指令。

        、信号量用于进程间的同步和互斥。对信号量的操作通常要求是一个原子操作,即在一条指令中完成信号量的读取和修改操作。ARM提供了如下两条指令完成信号量的操作:

              1 SWP 交换指令。

                     ·SWP指令用于将一个内存字单元(该单元地址放在寄存器<Rn>中)的内容读取到一个寄存器<Rn>中,同时将另一个寄存器<Rm>的内容写入到该内存单元中。当<Rn>和<Rm>为同一个寄存器时,指令交换该寄存器和内存单元的内容。

       2 SWPB 字节交换指令。

            ·SWPB 指令用于讲一个内存字节单元(该单元地址房子寄存器<Rn>中)的内容读取到一个寄存器<Rm>中,寄存器<Rd>的高24位设置为0,同时将另一个寄存器<Rm>的低8位数值写入到该内存单元中。当<Rn><Rm>为同一个寄存器时,指令交换该寄存器和内存字节单元的内容。本指令用于实现信号量操作。

·3.6 异常中断产生指令

       、ARM有两条异常中断产生指令,软中断指令SWI用于产生SWI异常中断,ARM正是通过这种机制实现在用户模式对操作系统中特权模式的程序的调用;断点中断指令BKPT在ARMv5以上的版本引入,主要用于产生软件断点,供调试程序使用。

       、SWI 软中断指令

       、BKPT 断点中断指令。

              1 SWI软中断指令,用于产生软中断。SWI {<cond>} <immed_24>。

                     ·其中<cond>为指令执行的条件码。当<cond>忽略时指令为无条件执行。

                            ·<immed_24>为24位的立即数。该立即数倍操作系统用来判断用户程序请求

的服务类型。

                     ·指令使用

                                   本指令主要用于用户程序调用操作系统的系统服务。操作系统在SWI的异常中断处理程序中提供相关的系统服务,并定义了参数传递的方法。通常有以下两种方法:

              1 指令中24位的立即数指定了用户请求的服务类型,参数通过通用寄存器传递。

              2 指令中的24位立即数被忽略,用户请求的服务类型由寄存器R0的数据决定,参数通过其他的通用寄存器传递。

·3.7 一些基本的ARM指令功能段。

              、通过一些代码段的分析,进一步理解相关的ARM指令的用法,逐步学习如何使用ARM指令编写高效率的程序。

              ·算术逻辑运算指令的应用。

              ·跳转指令的应用

              ·load/store指令的应用

              ·批量load/store指令的应用

              ·信号量指令的应用

              ·与系统相关的一些指令的应用

        1 条件执行

              ·求最大公约数。

                     C语言:

                            int gcd(int a, int b)

                            {

                                   While(a != b)

                                          If( a >b)

                                                 a = a – b;

                                          else

                                                 b = b – a;

                                   return a;

                             }

对应ARM的代码段如下。代码执行前R0中存放a,R1中存放b;代码执行后R0中存放a和b的最大公约数。

                            gcd

                            CMP Ro,R1                 ;比较a和b的大小

                            SUBGT R0,R0,R1         ;if(a > b)a = a – b; (a=b不做事)

                            SUBLT R1,R1,R0;         ; if (a>b) b = b – a;

                            BNE gcd

                            MOV PC ,LR

     

      2 条件判断语句

              if (a == 0 || b == 1)

                     c = d + e;

              对应ARM的代码段如下。代码执行前R0中存放a,R1中存放b;代码执行后R2存放d和e的和。

              CMP R0, #0     ; 判断R0是否等于0

              CMPNE R1 , #1  ;如果不等于0 判断R1是否等1

              ADDEQ  R2 , R3 ,R4   ;R0=0或R1=1时,R2= R3+R4             

      3 子程序进入和退出时数据的保存和恢复

在调用字程序时,通常利用寄存器R0-R3传递参数和返回结果,这几个参数由子程序的调用者来保存,其他的子程序将要用到的寄存器低子程序入口处保存,在子程序返回前恢复这些寄存器。下面代码段就是这个过程的示例:

              Function

              STMFD R13!, {R4 – R12,R14} ; 保存所有的本地寄存器,返回地址并更新栈指针

              …

              Insert the function body here   ; 恢复本地寄存器,PC寄存器,并更新栈指针。

              …

              LDMFD R13! , {R4 – R12, PC};

                      

       

4 ARM汇编语言程序设计

·ARM汇编语言程序中语句由指令,伪操作和宏指令组成。宏指令也是通过伪操作定义的。伪操作不像机器指令那样在计算机运行期间由机器执行,它是在汇编程序对源程序汇编期间由汇编程序处理的。宏是一段独立的程序代码。在程序中通过宏指令调用该宏。当程序被汇编时,汇编程序将对每个宏调用做展开,用宏定义体取代源程序中的宏指令。以下类型的ARM伪操作和宏指令。

       ·符号定义伪操作

       ·数据定义伪操作

       ·汇编控制伪操作

       ·框架描述伪操作

       ·信息报告伪操作

       ·其他伪操作

4.1 符号定义伪操作:用于定义ARM汇编程序中的变量,对变量进行复制以及定义寄存器名称。包括以下伪操作。

·GBLA,GBLL及GBLS声明全局变量

       、GBLA,GBLL及GBLS伪操作用于声明一个ARM程序中的全局变量,并将其初始化。

       、GBLA伪操作声明一个全局的算术变量,并将其初始化成0

       、GBLL 伪操作声明一个全局的逻辑变量,并将其初始化成{FALSE}

       、GBLS 伪操作声明一个全局的串变量,并将其初始化成空串“”。

       ·LCLA,LCLL,及LCLS声明局部变

       、GBLA,GBLL及GBLS伪操作用于声明一个ARM程序中的全局变量,并将其初始化。

       ·SETA , SETL , 及SETS 给变量赋值

              、SETA , SETL , 及SETS伪操作用于给一个ARM程序中的变量赋值。

              、SETA伪操作给一个算术变量赋值

              、SETL 伪操作给一个逻辑变量赋值

              、SETS 伪操作给一个串变量赋值

       ·RLIST 为通用寄存器列表定义名称

              、RLIST为一个通用寄存器列表定义名称

              Name RLIST {list-of-registers}

                     ·其中,name是寄存器列表名称,{list-of-registers}为通用寄存器列表

                     ·使用说明,RLIST伪操作用于给一个通用寄存器列表定义名称。定义的名称可以在LDM/STM指令中使用。在LDM/STM指令中,寄存器列表中的寄存器的访问次序总是先访问编号较低的寄存器,再访问编号较高的寄存器,而不管寄存器列表中各寄存器的排列顺序。

       ·CN 为协处理器的寄存器定义名称

       ·CP 为协处理器定义名称

       ·DN及SN 为VFP的寄存器定义名称

       ·FN 为FPA的浮点寄存器定义名称

4.2 数据定义伪操作

       ·LTORG 声明一个数据缓冲池(literal pool)的开始。

       ·MAP 定义一个结构化的内存表的首地址。

       ·FIELD 定义结构化的内存表中的一个数据域

       ·SPACE 分配一块内存单元,并用0初始化。 %的同义词

       ·DCB 分配一段字节的内存单元,并用指定的数据初始化。 = 的同义词

       ·DCD及DCDU 分配一段字的内存单元,并用指定的数据初始化。 &的同义词

       ·DCDO 分配一段字的内存单元,并将单元的内容初始化成该单元相对于静态基值寄存器的偏移量。

       ·DCFD及DCFDU 分配一段双字内存单元,并用双精度的浮点数据初始化。

       ·DCFS及DCFSU 分配一段字的内存单元,并用单精度的浮点数据初始化。

       ·DCI 分配一段字节的内存单元,用指定的数据初始化,指定内存单元中存放的是代码,而不是数据。

       ·DCQ及DCQU 分配一段双字的内存单元,并用64位的整数数据初始化。

       ·DCW及DCWU 分配一段半字的内存单元,并用指定的数据初始化。

       ·DATA 带代码段中使用数据,现已不再使用,仅用于保持向前兼容。

4.3 汇编控制伪操作

汇编控制伪操作包括下面的伪操作:

       ·IF , ELSE ENDIF

              IF , ELSE ENDIF伪操作能够根据条件把一段源代码包括在汇编语言程序内或者将其排除在程序之外。 [ IF伪操作的同义词,|FALSE伪操作的同义词,] ENDIF

伪操作的同义词。

       ·WHILE及WEND

       ·MACRO及MEND

              、MACRO伪操作标识宏定义的开始,MEND标识宏定义的结束。用MACRO及MEND定义一段代码,称为宏定义体,这样在程序中就可以通过宏指令调用该代码段。

       ·MEXOT 用于从宏中跳转出去。

4.4 栈中数据帧描述伪操作

       ·栈中数据帧描述伪操作主要用于调试,这里不介绍这部分内容。

4.5 信息报告伪操作

信息报告伪操作包括伪操作:

       ·ASSERT    

              、在汇编编译器对汇编程序的第二遍扫描中,如果其中ASSERTION中条件不成立,ASSERT伪操作将报告该错误信息。

              、使用说明:ASSERT伪操作用于保证源程序被汇编时满足相关条件,如果条件不满足,ASSERT伪操作报告错误类型,并终止汇编。

       ·INFO

              、INFO伪操作支持在汇编处理器过程的第一遍扫描或者第二遍扫描时报告诊断信息。

              、INFO伪操作用于用户自定义的错误信息。

       ·OPT

              、通过OPT伪操作可以在源程序个设置列表选项。 格式:OPT n ;

       ·TTL及SUBT

              、TTL在列表文件的每一页的开头插入一个标题,该作用在其后的每一页,知道遇到新的TTL伪操作;SUBT在列表文件的每一页的开头插入一个子标题,该作用在其后的每一页,知道遇到新的SUBT伪操作。

4.6 其他的伪操作

这些杂类的伪操作包括:

       ·ALIGN

              、ALIGN 伪操作通过添加补丁字节使当前位置满足一定的对齐方式

       ·AREA

              、AREA伪操作用于定义一个代码段或者数据段

       ·CIDE16及CODE32

              、CIDE16告诉汇编编译器后面的指令序列为16位的Thumb指令。

              、CODE32告诉汇编编译器后面的指令序列为32位的ARM指令。

              、这两个伪操作只是告诉编译器后面的指令类型,该伪操作本身并不进行程序状态的切换。

       ·END

              、END伪操作告诉编译器已经到了源程序结尾

       ·ENTRY

              、ENTRY 伪操作指定程序的入口点。

              、格式:ENTRY

                     AREA example CODE, READONLY

                     ENTRY        ;应用程序的入口点

                     …

                     END          ;本源程序结束

              、使用说明:一个程序(可以包含多个源文件)中至少要有一个ENTRY(可以有多个ENTRY),但一个源文件中最多只能有一个ENTRY(可以没有ENTRY)

       ·EQU

              EQU伪操作为数字常量,基于寄存器的值和程序中的标号定义一个字符名称。*EQU的同义词。adde1 EQU 0x1C,CODE32 ; 定义addr1符号值为绝对地址值0x1C,而且该处为ARM指令。

       ·EXPORT 或GLOBAL

              、EXPORT声明一个符号可以被其他文件引用。相当于声明了一个全局变量。GLOBAL是EXPORT的同义词

              、使用说明,使用EXPORT伪操作声明一个源文件中的符号,使得该符号可以被其他的源文件引用。 

       ·EXTERN

              、EXTERN伪操作告诉编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号。如果本源文件没有实际引用该符号,该符号都将不会被加入到本源文件的符号表中。

       ·GET 或 INCLUDE

              、GET伪操作将一个源文件包含到当前源文件中,并将被包含的文件在当前位置进行汇编处理。INCLUDE是GET的同义词

              、语法格式:GER filename; 其中,filename为被包含的源文件的名称。这里可以使用路径信息。

                        、使用说明:通常可以在一个源文件中定义宏,用EQU定义常量的符号名称,用MAPFIELD定义结构化的数据类型,这样的源文件类似于C众的.H文件。然后用GET伪操作将这个源文件包含到他们的源文件中,类似于再C中的“include *.h”

                        、注意:GET伪操作不能用来保护目标文件。包含目标文件需要使用INCBIN伪操作。

       ·IMPORT

              、IMPORT伪操作告诉编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本院文件中可能引用该符号,而且不论本源文件是否实际引用该符号,该符号都将被加入到本源文件的符号表中。

       ·INCBIN

              、INCBIN伪操作讲一个文件包含到当前源文件中,包含的文件不进行汇编处理。

       ·KEEP

              、KEEP伪操作告诉编译器将局部符号包含在目标文件的符号表中。

              、使用KEEP伪操作可以将局部符号也包含到目标文件的符号表中,从而使得调试 

工作更加方便。

       ·NOFP

       ·REQURE

       ·REQUIRE 及PRESERVE8

              、REQUIRE伪操作指示当前代码中的要求数据栈8字节对齐     

       ·RN

              、RN伪操作为一个特定的寄存器定义名称。

              、使用说明:RN伪操作用于给一个寄存器定义名称,方便程序员记忆该寄存器的功能。

       ·ROUT

              、ROUT伪操作用于定义局部变量的有效范围

              、使用说明:当没有使用ROUT 伪操作定义局部变量的作用范围时局部变量的作用范围为其所在的段(AREA)。ROUT伪操作作用的范围为本ROUT伪操作和下一个ROUT(指同一个段中的ROUT伪操作)伪操作之间。

4.7 ARM汇编语言伪指令

ARM中伪指令不是真正的ARM指令或者Thumb指令,这些伪指令在汇编编译器对源程序进行汇编处理时被替换成对应的ARM或者Thumb指令(序列)。ARM伪指令包括ADR, ADRL, LDR和NOP。

       ·ADR(小范围的地址读取伪指令)

             、该指令将基于PC的地址值或基于寄存器的地址值读取到寄存器中。

       ·ADRL(中等范围的地址读取伪指令)

       ·LDR大范围的地址读取伪指令

              、LDR伪指令将一个32位的常数或者一个地址值读取到寄存器中

                        LDR伪指令的主要两种用途:当需要读取到寄存器中的数据超过了MOVMVN指令可以操作的范围时,可以使用LDR伪指令将该数据读取到寄存器中;将一个基于PC的地址值或者尾部的地址值读取到寄存器中,由于这种地址值是在连续时确定的,所以这种代码不是位置无关的。同时LDR位置处的PC值到数据缓冲区的目标数据所在的地址的偏量要小于4KB

      ·NOP空操作。NOP伪指令不影响CPSR中的条件标志位。

4.8 ARM汇编语言程序格式

本小节介绍ARM汇编语言程序的基本格式以及子程序间调用的格式。ARM汇编语言以段为单位组织源文件。段是相对独立的,具有特定名称的,不可分割的指令或者数据序列。段又可以分为代码段和数据段,代码段存放执行代码,数据段存放代码运行时需要用到的数据。

一个ARM源程序至少需要一个代码段,大的程序可以包含多少个代码段和数据段。

、RM汇编语言源程序经过汇编处理器后生成一个可执行的映像文件(类似于WINDOWS系统下的EXE文件)。该可执行的映像文件通常包括下面3个部分:

       ·一个或多个代码段。代码段通常是只读的。

       ·零个或多个包含初始值的数据段。这些数据段通常是可读写的。

       ·零个或多个不包含初始值的数据段。这些数据段被初始化为0,通常是可读写的。

       、连接器根据一定的规则将各个段安排到内存中的相应位置。源程序中段之间的相邻关系与执行的映像文件中段之间的相邻关系并不一定相同。

·汇编语言子程序调用

在ARM汇编语言中,子程序调用时通过BL指令完成的。BL指令的语法格式如下:

       BL subname 其中subname是调用的子程序的名称。 

      ·BL指令完成两个操作:将子程序的返回地址放在LR寄存器中,同时将PC寄存器值设置成目标子程序的第一条指令地址。在子程序返回时可以通过将LR寄存器的值传送的PC寄存器中来实现。子程序在调用时通常使用寄存器R0-R3来传递参数和返回结果。


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值