ARM伪指令和伪操作

(一)GNU汇编书写格式
注释符:@和#
语句分离符: ;
立即数前缀: #或$

段内标号的地址值在汇编时确定
段外标号的地址值在连接时确定

局部标号:主要在局部范围内使用而且局部标号可以重复出现。它由两部分组成,开头是一个直接的数字局部标号,如99,后面加 ‘ : ’,如 66:
在跳转时,根据所加后缀不一样,跳转方向不一样。
1.    f代码地址增加的方向
       b代码地址减少的方向
例:b 99f
2.     就近原则

.代表当前行。  例:b   . 相当于    while(1) 

(二)ARM伪指令

ADR      为小范围的地址读取伪指令
ADRL    为中等范围的地址读取伪指令  
‹LDR      为大范围的地址读取伪指令.
‹NOP     为空操作伪指令
注:ldr伪指令的实质 LDR Rd,=const
  • const如果是有效数,会翻译成MOV ,mvn
  • 如果const不是一个有效数,是把要放进寄存器的立即数存储到一个内存地址中,然后将ldr伪指令翻译成一条ldr指令,然后从该地址中读取这个立即数
adr和adrl伪指令的实质:是将基于PC的相对偏移地址值存放到寄存器中

              ldr    r0,=myarry              @ 取标号所在的地址   绝对地址装载l;
                反汇编:ldr   r0, [pc, #64]     @pc+64地址里存放的时标号的地址
                
                ldr   r1,=0x666666
                反汇编:ldr   r1,[pc, #56]     @pc+56地址里存放0x666666

ldr r0,myarry             @ 取标号所在地址的里面的值;注:这个不是伪指令
                反汇编:ldr   r0,[pc, #4]      @pc+4就是标号的地址,然后从标号的地址里取值    

adr r0,myarry             @ 取标号所在的地址   相对pc的偏移量
                反汇编:add   r0,pc,#6        @pc+6就是标号所在的地址

adrl r0,myarry             @ 取标号所在的地址   相对pc的偏移量
                反汇编:add   r0,pc, #8       @pc+6就是标号所在的地址


(三)GNU编译环境下的伪操作和宏指令

1、常量编译控制伪操作 :

.byte                                 定义单字节数据              

例:  .byte     0x12,'a',23

.hword/.short       定义双字节数据            

例:  .short    0x1234,0x6666

.word/.long /.int     定义4字节数据                  

例:  .word    0x12345678

.quad                   定义8字节数据                 

例: .quad    0x1234567812345678

.float/.single        定义32bit 浮点数             

例:.float     0f3.2

.double                定义64bit浮点数  

例:           

.ascii                     定义字符串/0为结束符       

例: .ascii    "hello\0"

.asciz /.string       定义字符串(非零结束符)  

例: .string   "hello"

.fill                        分配一段字节内存单元,用size长度value填充repeat次  

例:  .fill   10,2,6    将两个字节长度的6重复填充10次

.zero                    分配一段字节内存单元,并用0填充内存                          

例:  .zero  10   分配十个字节单元,并用0填充

.space/.skip        分配一段内存单元,用value将内存单元初始化               

例:  .space  10,6  分配十个字节单元,并用6填充



2、汇编程序代码控制伪操作
.arm/.code32         定义以下代码使用ARM指令集
.thumb/.code16    定义以下代码使用Thumb指令集
.arch                        cpu的架构
例: .arch armv7-a    
.fpu                          软件浮点
例: .fpu softvfp  

.section                  定义一个段     

例: .section    expr  ;expr可以是.text,.data,.bss

.text                         将定义符开始的代码编译到代码段

.data                       将定义符开始的数据编译到数据段

.bss                         将变量存放到.bss段

.align                      通过用零或或指定的数据进行填充来使当前位置满足一定的对齐方式,2的权次方对齐

例: .align 1  2个字节对齐

         .align 3  8个字节对齐

.type                       说明一个类型

例:.type   b,%object     #用来说明b的类型,%object是数据类型   %function 函数类型

.size                       占用内存的大小

例:.size   b,2                #字符占用内存的大小

.org指定从当前地址加上offset开始存放代码,并且从当前地址到当前地址加上offset之间的内存单元,用零或指定的数据进行填充

例:.org    offset

.global/.globl         用来定义一个全局的符号

例:.global    main

.include                   将一个源文件包含到当前源文件中

例:.include     "filename"

.end                        标记汇编文件的结束行,即标号后的代码不作处理

_start                     汇编程序的缺省入口是_start标号,用户也可以在链接脚本文件中用ENTRY标志指明其他入口点



3、宏及条件编译控制伪操作

.macro .exitm及.endm     .macro伪操作标识宏定义的开始,.endm标识宏定义的结束。用.macro.endm定义一段代码,称为宏定义体。.exitm伪操作用于提前退出宏。

例:
  • 格式如下:
 .macro 宏名 参数名列表     #伪指令.macro定义一个宏
  宏体
 .endm                      #.endm表示宏结束
  • 如果宏使用参数,那么在宏体中使用该参数时添加前缀“\”。宏定义时的参数还可以使用默认值。可以使用.exitm伪指令来退出宏。
.macro SHIFTLEFT a, b
.if  \b < 0
MOV  \a, \a, ASR #\b
.exitm
.endif
MOV  \a, \a, LSL #\b
.endm
ifdef,.else及.endif    当满足某条件时对一组语句进行编译,而当条件不满足时则编译另一组语句。其中else可以缺省。
例:
格式如下:

.ifdef  condition

.else

.endif

一个实例:
.equ is,5
.if is
mov r2,r3
.endif

4、其他伪操作
.rept                重复定义伪操作
例:
格式如下:
  .rept 重复次数
  数据定义
  .endr @结束重复定义
一个实例
  .rept 3
  .byte 0x23
  .endr
注:必须放在代码最后
 
.equ/.set:        赋值语句,把某一个符号名定义成一个值,该指令并不分配空间。有点像c语言的#define
例:.equ abc,3     #编译时,将abc替换为3
.title:            用来指定汇编列表的标题
例: .title “my program”
.list                 产生汇编列表(从 .list 到 .nolist)

.nolist             表示汇编列表结束处。

.req                用来给寄存器赋予别名

例:rr  .req  r0    定义寄存器r0的别名为rr

 .unreq          用来取消一个寄存器的别名
例: .unreq rr    取消定义的寄存器别名
注意被取消的别名必须事先定义过,否则编译器就会报错,这个伪操作也可以用来取消系统预制的别名, 例如r0, 但如果没有必要的话不推荐那样做。

.ltorg/.pool    用于声明一个数据缓冲池(literal pool)的开始,它可以分配很大的空间。
注:
  • 在使用LDR伪指令时,要在适当的地址加入 ltorg 声明 数据缓冲池 ,这样就会把要加载的数据保存在 数据缓冲池 内,再用ARM的加载指令读出数据.(若没有使用 .ltorg 声明文字池,则汇编器会在程序末尾自动声明.) 
  • 如果把数据缓冲池放在两条无跳转指令之间,处理器会错误的把数据缓冲池中的数据当做指令执行,所以ltorg伪指令常放在无条件跳转指令之后,或者子程序返回指令之后,总之不能让程序执行到数据缓冲池的地址。这样处理器就不会错误地将数据缓冲池中的数据当作指令来执行
  • 根据所需数据缓冲的大小,.ltorg每次分配的数据缓冲区大小不一样

你可能感兴趣的:(ARM)