四、汇编指令详解

xiaoxiao2021-02-28  5

1、跳转指令      跳转指令用于实现程序流程的跳转,在ARM程序中有两种方法可以实现程序流程的跳转: 1).使用专门的跳转指令。 2).直接向程序计数器PC写入跳转地址值,通过向程序计数器PC写入跳转地址值,可以实现 4GB 的地址空间中的任意跳转,在 跳转之前 结合使用 [ MOV LR, PC ] 等类似指令,可以保存将来的返回地址值,从而实现在 4GB 连续的线性地址空间的子程序调用。       ARM指令集中的跳转指令可以完成从当前指令 向前或后的 32MB 的地址空间的跳转,包括以下 4 条指令:         B 跳转指令         BL 带返回的跳转指令         BLX 带返回和状态切换的跳转指令         BX 带状态切换的跳转指令 ============================== (1)B          B指令的格式为:                     B{条件} 目标地址          B指令是最简单的跳转指令。一旦遇到一个B指令,ARM处理器将立即跳转到给定的目标地址,从那里继续执行。 eg1: B Label ; 程序无条件跳转到标号Label处执行 eg2: CMP R1, #0      B EQ Label ; 当CPSR寄存器中的Z条件码置位时,程序跳转到标号Label处执行。 指令条件 (2)BL          BL 指令的格式:                     BL{条件} 目标地址          BL是另一个跳转指令, 但跳转之前,会在寄存器R14中保存 PC 当前值 ,因此,可以通过将 R14 的内容重新加载到 PC 中,来返回到跳转指令之后的那个指令处执行。该指令是实现子程序调用的一个基本但常用的手段。    BL Label ; 当程序无条件跳转到标号Label处执行时,同时将当前的PC值保存到R14中。 (3)BLX          BLX 指令的格式为:                     BLX 目的地址          BLX指令从ARM指令集跳转到指令集所指定的目标地址, 并将处理器的工作状态有 ARM 状态切换到 Thumb 状态,该指令同时将 PC 的当前内容保存到寄存器 R14 。因此,当子程序使用Thumb指令集,而调用者使用ARM指令集时,可以通过BLX指令实现子程序的调用和处理器和工作状态的切换。同时,子程序的返回可以通过将寄存器R14值复制到PC中来完成。 (4)BX          BX 指令的格式为:                     BX{条件} 目的地址          BX指令跳转到指令中指定的目标地址,目标地址处的指令既可以是ARM指令,也可以是Thumb指令。 2、数据处理指令      数据处理指令可以分为 数据传送指令 算术逻辑运算指令 比较指令 等。      数据传送指令用于在 寄存器 存储器 之间进行数据的双向传输。      算术逻辑运算指令完成常用的算术与逻辑的运算,该类指令不但将运算结果保存在目的寄存器中,同时更新CPSR中的相应条件标志位。 (1)MOV指令          MOV 指令的格式为:                     MOV{条件}{S} 目的寄存器, 源操作数          MOV指令完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器。其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。         MOV R1, R0 ;将寄存器R0的值传送到寄存器R1         MOV PC, R14 ;将寄存器R14的值传送到PC,通常用于子程序返回         MOV R1, R0, LSL #3 ;将寄存器R0的值左移3位后传送到R1 (2)MVN指令      MVN 指令的格式为:                 MVN{条件}{S} 目的寄存器, 源操作数      MVN指令可以完成从另一个寄存器、被移位的寄存器、或将一个立即数加载到目的寄存器。      与MOV指令不同之处是在传送之前按位取反了,即把一个被取反的值传送到目的寄存器中。 其中S选项决定指令的操作是否影响CPSR中条件标志位的值,当没有S时指令不更新CPSR中条件标志位的值。          MVN R0, #0xff ; R0 <= 0xffffff00 (3)CMP指令      CMP 指令的格式为:             CMP{条件} 操作数1, 操作数2      CMP指令用于把一个寄存器的内容和另一个寄存器的内容或立即数进行比较, 同时更新CPSR中条件标志位的值。      该指令进行一次减法运算,但 不存储结果,只更改条件标志位      标志位表示的是操作数1与操作数2的关系(大、小、相等),例如,当操作数1大于操作数2,则此后的有GT后缀的指令将可以执行。      指令示例:     CMP R1, R0 ; 将寄存器R1的值与寄存器R0的值相减,并根据结果设置CPSR的标志位     CMP R1, #100 ; 将寄存器R1的值与立即数100相减,并根据结果设置CPSR的标志位 (4)TST指令      TST 指令的格式为:               TST{条件} 操作数1, 操作数2      TST指令用于把一个寄存器的内容合并另一个寄存器的内容或立即数进行 按位与运算 ,并根据运算结果跟新CPSR中条件标志位的值。 操作数1是要测试的数据,而操作数2是一个位掩码,根据测试结果设置相应标志位。 当位与结果为0时,EQ位被设置。      指令示例:     TST R1, #%1 ;用于测试在寄存器R1中是否设置了最低为(%表示二进制数) (5)ADD指令      ADD 指令的格式为:             ADD{条件}{S} 目的寄存器, 操作数1, 操作数2      ADD指令用于把两个操作数相加,并将结果存放到目的寄存器中。      操作数1应是一个 寄存器 ,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。      指令示例:     ADD R0, R1, R2 ;R0 = R1 + R2     ADD R0, R1, #256 ;R0 = R1 + 256     ADD R0, R2, R3, LSL #1 ;R0 = R2 + (R3 << 1) (6)SUB指令      SUB 指令的格式为:             SUB{条件}{S} 目的寄存器 操作数1, 操作数2          SUB指令用于把操作数1减去操作数2,并将结果存放到目的寄存器中。         操作数1应是一个 寄存器 ,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。         指令示例:     SUB R0, R1, R2 ;R0 = R1 - R2     SUB R0, R1, #256 ;R0 = R1 - 256     SUB R0, R2, R3, LSL #1 ;R0 = R2 - (R3 << 1) (7)AND指令      AND 指令的格式为:                 AND{条件}{S} 目的寄存器 操作数1, 操作数2      AND指令用于在两个操作数上进行 逻辑与 运算,并把结果放置到目的寄存器中。      操作数1应是一个 寄存器 ,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。      该指令常用于屏蔽操作数1的某些位。     AND R0, R0, #3 ; 该指令 保持R0的0、1位,其余位清零。 (8)ORR指令      ORR 指令的格式为:             ORR{条件}{S} 目的寄存器 操作数1, 操作数2      ORR指令用于在在两个操作数上进行 逻辑或 运算,并把结果放置到目的寄存器中。      操作数1应是一个 寄存器 ,操作数2可以是一个寄存器、被移位的寄存器、或一个立即数。      该指令常用于设置操作数1的某些位。     ORR R0, R0, #3 ;该指令设置R0的0、1位,其余位保持不变。 9)BIC指令    BIC 指令的格式为:             BIC{条件}{S} 目的寄存器 操作数1, 操作数2    BIC指令用于清除操作数1中的某些位,并把结果放置到目的寄存器中。 操作数2为32位的掩码,如果掩码中设置了某一位为1,则清楚这一位。 例:         BIC R0, R0, #11 ; 将R0的0,1,3位清零,其余位不变。 (10)MUL指令      MUL 指令的格式为:              MUL{条件}{S} 目的寄存器 操作数1, 操作数2 MUL指令完成将操作数1与操作数2的 乘法 运算,并把结果放置到目的寄存器中,同时可以根据运算结果设置CPSR中相应的条件标志位。 其中,操作数1和操作数2均为32位的有符号数或无符号数。         MUL R0, R1, R2 ;R0 = R1 x R2         MULS R0, R1, R2 ;R0 = R1 x R2, 同时设置CPSR中的相关条件标志位 3、程序状态寄存器访问指令       ARM微处理器支持程序状态寄存器访问指令,用于在程序状态寄存器和通用状态寄存器之间传送数据。 (1)MRS指令                 MRS {条件} 通用寄存器, 程序状态寄存器(CPSR或SPSR)    MRS指令用于 将程序状态寄存器的内容传送到通用状态寄存器中    该指令一般用在以下几种情况:    1)当需要改变程序状态寄存器的内容时,可用MRS将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。 2)当在异常处理或进程切换时,需要保存程序寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。             MRS R0, CPSR ; 传送CPSR的内容到R0             MRS R0, SPSR ; 传送SPSR的内容到R0 (2)MSR指令                 MSR {条件} 程序状态寄存器(CPSR或SPSR)_<域>, 操作数 MSR指令用于 将操作数的内容传送到状态寄存器的特定域中 。其中,操作数可以位通用寄存器或立即数。 <域>用于设置程序状态寄存器中需要操作的位,32位的程序状态寄存器可分为4个域     位[31 : 24] 为条件标志位域,用f表示;     位[23 : 16] 为状态位域,用s表示     位[15 : 8] 为扩展位域,用x表示     位[ 7 : 0] 为控制位域,用c表示 该指令通常用于恢复或改变程序状态寄存器的吧内容,在使用时,一般要在MSR指令中指明将要操作的域。 指令示例:         MSR CPSR, R0 ;传送R0的内容到CPSR         MSR SPSR, R0 ;传送R0的内容到SPSR         MSR CPSR_c, R0 ;传送R0的内容到SPSR,但仅仅修改CPSR中的控制位域。 4、加载/存储指令      ARM微处理器支持加载/存储指令用于在 寄存器和存储器之间 传送数据,      加载指令用于将存储器中的数据传送到寄存器,存储指令则完成相反的操作。 (1)LDR指令          LDR 指令的格式为:             LDR {条件} 目的寄存器, <存储器地址>    LDR 指令用于从 存储器 中将一个32位的字数据传送到目的寄存器中。    该指令通常用于从存储器中读取32位的字数据到通用寄存器,然后对数据进行处理。    示例:     LDR R0, [R1]        将存储器地址为R1的字数据读入寄存器R0。        LDR R0, [R1, R2]        将存储器地址为R1 + R2的字数据读入寄存器R0。        LDR R0, [R1, #8]        将存储器地址为R1 + 8的字数据读入寄存器R0。        LDR R0, [R1, R2]        将存储器地址为R1 + R2的字数据读入寄存器R0,并将新地址R1 + R2写入R1。        LDR R0, [R1, #8]        将存储器地址为R1 + 8的字数据读入寄存器R0,并将新地址R1 + 8写入R1。        LDR R0, [R1], R2        将存储器地址为R1的字数据读入寄存器R0,并将新地址R1 + R2写入R1。        LDR R0, [R1, R2, LSL #2]        将存储器地址为R1 + R2 x 4的字数据读入寄存器R0,并将新地址R1 + R2 x 4写入R1。        LDR R0, [R1], R2, LSR #2        将存储器地址为R1的字数据读入寄存器R0,并将新地址R1 + R2 x 4写入R1。 (2)LDRB指令          LDRB 指令的格式为:         LDRB {条件} 目的寄存器, <存储器地址>    LDR 指令用于从 存储器 中将一个 8 位的 字数据传送到目的寄存器中, 同时将寄存器的高24位清零    该指令通常用于从存储器中读取 8 位的字数据到通用寄存器,然后对数据进行处理。    指令示例:         LDRB R0, [R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零。         LDRB R0, [R1, #8] ;将存储器地址为R1 + 8的字节数据读入寄存器R0,并将R0的高24位清零。 (3)LDRH指令          LDRH 指令的格式为:             LDRH {条件} H 目的寄存器, <存储器地址>    LDRH 指令用于从 存储器 中将一个 16 位的 半字数据传送到目的寄存器中, 同时将寄存器的高16位清零    该指令通常用于从存储器中读取 16 位的半字数据到通用寄存器,然后对数据进行处理。    指令示例:         LDRH R0, [R1] ;将存储器地址为R1的半字节数据读入寄存器R0,并将R0的高16位清零。         LDRH R0, [R1, R2] ;将存储器地址为R1 + R2的半字节数据读入寄存器R0,并将R0的高16位清零。 (4)STR指令          STR 指令的格式为:             STR {条件} 源寄存器, <存储器地址>    STR 指令用于 从源寄存器 中将一个32位的字数据传送 到存储器 中。    指令示例:         STR R0, [R1], #8 ;将R0中的字节数据写入以R1为地址的存储器中,并将新地址R1 + 8写入R1。         STR R0, [R1, #8] ;将R0中的字节数据写入以R1 + 8为地址的存储器中。 5、 批量 加载/存储指令      ARM微处理器所支持的批量数据加载/存储指令可以一次在 一片连续的 存储单元和多个寄存器之间传送数据,      批量加载指令用于将一片连续的 存储器 中的数据传送到多个 寄存器 ,批量数据存储指令则完成 相反 的操作。      常用的加载存储指令如下:     LDM 批量数据加载指令     STM 批量数据存储指令 (1)LDM指令          LDM 指令的格式为:                 LDM {条件}{类型} 基址寄存器{!}, 寄存器列表{^}    LDM {或 STM }指令用于从由 基址寄存器所指示的一片连续存储器 寄存器列表所指示的多个寄存器 之间传送数据,    该指令的常见用途是将多个寄存器的内容入栈或出栈。    其中,{类型}为以下几种情况:     IA     每次传送后地址加1     IB     每次传送前地址加1     DA     每次传送后地址减1     DB     每次传送前地址减1     FD     满递减堆栈     ED      空递减堆栈     FA     满递增堆栈     EA     空递增堆栈 指令示例:         STMFD R13!, {R0, R4-R12, LR} ;将寄存器列表中的寄存器(R0, R4到R12, LR)存入堆栈。         LDMFD R13!, {R0, R4-R12, PC} ;将堆栈内容恢复到寄存器(R0, R4到R12, LR)。     {!}为可选后缀,若选用该后缀,则当数据传送完毕之后,将最后的地址写入基址寄存器,否则基址寄存器的内容不改变。 基址寄存器不允许为R15 ,寄存器列表可以为R0~R15的任意组合。 {^}为可选后缀,当指令为LDM且寄存器列表中包含R15,选用该后缀时表示:除正常的数据传送之外, 还将SPSR复制到CPSR 6、数据交换指令      ARM微处理器所支持数据交换指令能在 存储器和寄存器之间交换数据 。数据交换指令有如下两条: SWP 字数据交换指令 SWPB 字节数据交换指令 (1)SWP指令          SWP 指令的格式如下:                     SWP {条件} 目的寄存器, 源寄存器1, [源寄存器2]    SWP指令用于将源寄存器2所指向的存储器中的字数据传送到目的寄存器中,同时将源寄存器1中的字数据寄存器传送到源寄存器2所指向的存储器中。    显然,当源寄存器1和目的寄存器为同一个寄存器时,指令交换该寄存器和存储器的内容。    指令示例:         SWP R0, R1, [R2];将R2所指向的存储器中的字数据传送到R0,同时将R1中的字数据传送到R2所指向的存储器单元。         SWP R0, R0, [R1] ;该指令完成将R1所指向的存储器中的数据与R0中的数据交换。 7、移位指令       ARM微处理器支持数据的移位操作, 移位操作在ARM指令集中不作为单独的指令使用,它只能作为指令格式中是一个字段 在汇编语言中表示为指令中的选项。      移位操作包括如下6中类型, ASL LSL 是等价的,可以自由互换:         LSL 逻辑左移         ASL 算术左移         LSR 逻辑右移         ASR 算术右移         ROR 循环右移 (1)LSL 操作          LSL 操作的格式为:             通用寄存器, LSL 操作数    LSL 可完成对通用寄存器中的内容进行逻辑左移操作,按操作数所指定的数量向左移位,低位用零来填充。    其中,操作数可以是通用寄存器,也可以是立即数(0~31)。    操作示例:             MOV R0, R1, LSR#2 ;将R1中的内容左移两位后传送到R0中。 (2)ROR 操作          ROR 操作的格式为:             通用寄存器, ROR 操作数    ROR 可完成对通用寄存器中的内容进行循环右移的操作,按操作数所指定的数量向右循环移位, 左端用右端移出的位来填充    其中,操作数可以是通用寄存器,也可以是立即数(0~31)。    显然,当进行32位的循环右移操作时,通用寄存器中的值不改变。    操作示例:             MOV R0, R1, ROR#2 ;将R1中的循环右移两位后传送到R0中。 8、异常产生指令       ARM微处理器所支持的异常指令有如下两条:     SWI 软件中断指令     BKPT 断点中断指令 (1)SWI指令         SWI 操作的格式为:                     SWI {条件} 24位的立即数    SWI 指令用于产生软件中断,以便用户程序能调用操作系统的系统API。    操作系统在SWI的异常处理程序中提供相应的系统服务,指令中24位立即数指定用户程序调用的API类型。    指令示例:         SWI 0x02 ;该指令调用操作系统编号为02的系统例程。 所有练习程序如下:< test1.S > ;寻址方式,使用AXD调试时,可使用单步调试(F10) ;使用AXD的processor views-->register查看寄存器变化 ;使用AXD的processor views-->memory查看内存的值 ;使用AXD的processor views-->disassembly查看反汇编代码 GBLA Test1 ;声明一个全局的数学变量,变量名为Test1 GBLL Test2 ;申明一个全局的逻辑变量,变量名为Test2 Test1 SETA 0x3 ;将变量Test1赋值为3,注意书写格式,需要顶格写 Test2 SETL {TRUE} ;将变量Test2赋值为TRUE ;EQU伪指令 COUNT EQU 0x30003100 ; 定义一个变量,地址为0x30003100 AREA Example1,CODE,READONLY ; 声明代码段Example1 ENTRY ; 标识程序入口 CODE32 ; 声明32位ARM指令 START ;立即寻址 MOV R0,#0 ; R0 <= 0,将立即数0x00存入寄存器R0,可通过AXD的processor views-->register查看 ADD R0,R0,#1 ; R0 <= R0 + 1 ADD R0,R0,#0x3f ; R0 <= R0 + 0x3f ;寄存器寻址 MOV R1,#1 ; R1 <= 1,将立即数0x01存入寄存器R1 MOV R2,#2 ; R2 <= 2,将立即数0x02存入寄存器R2 ADD R0,R1,R2 ; R0 <= R1+R2,将寄存器R1和R2的内容相加,其结果存放在寄存器R0中 ;寄存器间接寻址 LDR R1,=COUNT ; R1 <= COUNT,将存储器地址放入寄存器R0 ;MOV R0,#0x12 ; R0 <= 0x12,MOV指令目地操作数只能是8位 LDR R0,=0x12345678 STR R0,[R1] ; [R1] <= R0,将寄存器R0的内容存入寄存器R1所指向的存储器 ;即设置COUNT为0x12345678, ;STR指令用于从源寄存器中将一个32位的字数据传送到存储器中 ;可通过AXD的processor views-->memory查看0x30003100的值 ;基址变址寻址 LDR R1,=COUNT ;将存储器地址0x30003100放入寄存器R1 LDR R2,=(COUNT+4) ;将存储器地址0x30003104放入寄存器R1 MOV R3,#0x12 ;将立即数0x12存入寄存器R3 STR R3,[R2] ;将寄存器R3的内容存入寄存器R2所指向的存储器 LDR R4,[R1,#4] ;将寄存器R1的内容加上4所指向的存储器的字存入寄存器R4 ;多寄存器寻址 LDR R1,=COUNT ;将存储器地址0x30003100放入寄存器R1 LDMIA R1,{R5,R6} ;R5 <= [R1],R6 <= [R1+4] ;相对寻址 BL NEXT ;跳转到子程序NEXT处执行,注意使用F8(step in) NOP NOP ;跳转指令(B) B label1 ;跳转到子程序label1处执行 NOP NOP NOP NEXT MOV R0,LR NOP NOP NOP MOV PC,LR ;从子程序返回 label1 NOP NOP NOP ;跳转指令(BL) BL lable2 ;跳转到子程序label2处执行 NOP NOP ;MOV指令 MOV R0,#0x12 ;R0=0x12 MOV R1,R0 ;R1=R0 MOV R1,R0,LSL#3 ;R1=R0<<3 ;MVN指令 MVN R0,#0xff ; R0 = 0xfffff00 MVN R0,#0xA0000007 ; 0xA0000007的反码为0x5FFFFFF8 ;CMP指令(使用AXD查看CPSR) MOV R0,#1 MOV R1,#2 CMP R0,R1 ;若R0>R1,则置R0=3,若R0<=R1,则置R1=3 MOVHI R0,#3 ;根据CPSR条件标志位中的HI(无符号大于)判断,若R0>R1,则R0=3 MOVLS R1,#3 ;根据CPSR条件标志位中的LS(无符号小于或等于)判断,R0<=R1,则R1=3 ;TST指令,测试R5的bit23是否为1,若是则置R5=0x01,不是则置R5=0x00 LDR R5,=0xffffffff TST R5,#(1<<23) ;当bit23位为1时,CPSR EQ位被设置 MOVEQ R5,#0x00 MOVNE R5,#0x01 ;ADD指令 MOV R1,#1 MOV R2,#2 MOV R3,#3 ADD R0,R1,R2 ;R0=R1+R2 ADD R0,R1,#256 ;R0=R1+256 ADD R0,R2,R3,LSL#1 ;R0=R2+(R3<<1) ;SUB指令 MOV R1,#100 MOV R2,#8 SUB R0,R1,R2 ;R0=R1-R2 SUB R0,R1,#55 ;R0=R1-256 ;AND指令 MOV R0,#0xff AND R0,R0,#3 ;逻辑与运算,R0 = R0 & 3 ;ORR指令 MOV R0,#0xff ORR R0,R0,#3 ;逻辑或运算,R0 = R0 | 3 ;BIC指令 MOV R0,#0x77 BIC R0,R0,#0x0b ;将R0的bit0,bit1,bit3清零,其余位不变 ;MUL指令 MOV R1,#10 MOV R2,#20 MUL R0,R1,R2 ;R0=R1*R2 ;MRS指令(将CPSR或者SPSR的内容传送到通用寄存器) MRS R0,CPSR ;传送CPSR的内容到R0 MRS R1,SPSR ;传送SPSR的内容到R1 ;LDR指令 LDR R1,=0x30003100 ;R1=0x30003100,使用AXD的processor views-->memory查看内存的值 LDR R0,[R1] ;R0=[R1] LDR R0,[R1,#4] ;R0=[R1+4] ;LDRB,LDRH指令 LDR R1,=0x30003100 LDRB R0,[R1] ;将存储器地址为R1的字节数据读入寄存器R0,并将R0的高24位清零 LDRH R2,[R1] ;将存储器地址为R1的半字数据读入寄存器R2,并将R2的高16位清零 ;STR指令,内存地址0x30003100=0xab LDR R1,=0x30003100 MOV R0,#0xab STR R0,[R1] ;将R0中的字数据写入以R1为地址的存储器中 STR R0,[R1,#8] ;将R0中的字数据写入以R1+8为地址的存储器中 ;LDM,STM指令 LDR R1,=0x30003100 LDMIA R1,{R5,R6} ;R5 = [R1],R6 = [R1+4] MOV R2,#0x33 MOV R3,#0X44 STMIA R1,{R2,R3} ;[R1]=R2,[R1+4]=R2 ;SWP指令 SWP R0,R0,[R1] ; 该指令完成将R1所指向的存储器中的字数据与R0中的字数据交换 ;移位指令 MOV R1,#4 MOV R0,R1,LSL#2 ;R0=R1<<2 MOV R1,#3 MOV R0,R1,ROR#2 ;将R1中的内容循环右移两位后传送到R0中 ;汇编控制伪指令,while指令 WHILE Test1<10 MOV R0,#Test1 MOV R1,#1 Test1 SETA Test1+1 WEND ;汇编控制伪指令,IF指令 IF Test2 = {TRUE} MOV R0,#1 MOV R1,#2 ELSE MOV R0,#0 MOV R1,#0 ENDIF B out lable2 MOV R0,LR ;查看R14 NOP NOP MOV PC,LR ;从子程序返回 out NOP END
转载请注明原文地址: https://www.6miu.com/read-1600103.html

最新回复(0)