ARM指令集

数据处理指令:

  • 数据处理指令只可用于寄存器之间或寄存器与立即数之间


  • 移位指令

  1. Rotate left(ROL) 可以通过 rotate right (ROR)(32-number)来实现, e.g. ROL 10 相当于 ROR 22.
  2. 立即数:只要该数,可以通过0x00-0xFF中某个数,循环右移偶数位而产生,就是合法的mov的操作数,否则就是非法的mov的操作数。
    mov r0, #256       ; mov r0, #0x100
    mov r1, #0x40, 30  ; mov r1, #0x100
    
  3. 伪指令LDR可以用来MOV任意32位的常数到寄存器中


  • 例如:
 SUB    r0,r1,#5         ;r1-5->r0    (立即寻址)
 ADD    r2,r3,r3,LSL #2  ;R3x4+r3->r2
 ANDS   r4,r4,#0x20      ;r4+0x20->r4,更新条件码标志位
 ADDEQ  r5,r5,r6         ;r5+r6->r5(条件-相等)(寄存器寻址)

存储器存取指令:

  • 存储器存取指令用于通用寄存器与内存单元之间


  • 例如
 LDR    r0,[r1],#4      ;r1+4->r0(基址变址寻址)
 STRNEB r2,[r3,r4]      ;NE符合-将r2低8位数写到[r3+r4]内存单元(寄存器间接寻址)
 LDRSH  r5,[r6,#8]!     ;[r6+8]->r5(半字节),r5中高16位设置成该字节的符号位
 STMFD  sp!,{r0,r2-r7,r10}  ;出栈(多寄存器寻址)
  • STR :从寄存器中将32bits字数据存储到内存中
  • LDM/STM(出栈/入栈) 用于基址寄存器所指的一片连续内存到寄存器列表中的多个寄存器之间的数据传送。

PSR 读写指令

  • MRS 将CPSR/SPSR的内容读取到通用寄存器中
  • MSR 将通用寄存器的值写到CPSR/SPSR的特定位域(f,c)中
  • 例如
MRS R0, CPSR     ;R0 = CPSR 
MSR CPSR_c, R0   ;CPSR [c] = R0

ARM 跳转分支指令

  • B <label>
    PC 相对寻址
  • BL <子程序>
    保存返回地址到 LR
    返回时从 LR 恢复 PC
    对于 non-leaf 函数(func1), LR 必须压栈保存

ARM条件执行与标志位

  • ARM指令可以通过添加合适的条件码后缀的方式使其条件执行
  • 通常情况下,数据处理指令不影响条件码标志位,但可以添加"S"后缀来改变标志位状态。

常用条件码如下:


  • 例如:
  1. if (a==0) func(1);
CMP      r0,#0�
MOVEQ    r0,#1
�BLEQ     func
  1. if (a==0) x=0;�
    if (a>0) x=1;
CMP      r0,#0
�MOVEQ    r1,#0�
MOVGT    r1,#1�
  1. if (a==4 || a==10) x=0;
CMP      r0,#4
�CMPNE    r0,#10�
MOVEQ    r1,#0

软件中断指令SWI

  • SWI 指令用于产生软件中断,以便用户程序能调用操作系统的系统例
    程。
  • 操作系统在SWI 的异常处理程序中提供相应的系统服务,指令中
    24 位的立即数指定用户程序调用系统例程的类型,相关参数通过通用
    寄存器传递。
  • 当指令中24 位的立即数被忽略时,用户程序调用系统例
    程的类型由通用寄存器R0 的内容决定。

ARM 伪指令

1. 符号定义伪指令

符号定义伪指令用于定义ARM 汇编程序中的变量、对变量赋值以及定
义寄存器的别名等操作

  • GBLA、GBLL 和GBLS 伪指令用于定义一个ARM 程序中的全局变量
    并将其初始化。
    GBLA Number         ;定义一个全局的数字变量并初始化为0,变量名为Number
    Number SETA 0xaa    ;将该变量赋值为0xaa
    GBLL Logical        ;定义一个全局的逻辑变量并初始化为F(False),变量名为Logical
    Logical SETL {TRUE} ;将该变量赋值为真
    GBLS Str            ;定义一个全局的字符串变量并初始化为空,变量名为Str
    Str SETS “Testing”  ;将该变量赋值为“Testing”
    
  • LCLA、LCLL 和LCLS 伪指令用于定义一个ARM 程序中的局部变量
    并将其初始化。
  • SETA、SETL、SETS 伪指令用于给一个已经定义的全局变量或局部变
    量赋值。
  • RLIST 伪指令可用于对一个通用寄存器列表定义名称,使用该伪指令定
    义的名称可在ARM 指令LDM/STM 中使用。LDM/STM 指令中,列
    表中的寄存器访问次序为根据寄存器的编号由低到高,而与列表中的寄
    存器排列次序无关。
    RegList RLIST {R0-R5,R8,R10} ;将寄存器列表名称定义为RegList,可在ARM 指令LDM/STM 中通过该名称访问寄存器列表。
    

2. 数据定义伪指令

数据定义伪指令一般用于为特定的数据分配存储单元,同时可完成已分
配存储单元的初始化。

  • DCB 伪指令用于分配一片连续的字节存储单元并用伪指令中指定的表
    达式初始化。
    Str DCB “This is a test!”  ;为Str分配一片连续的字节存储单元并初始化。
    Str = “This is a test!”
    
  • SPACE 伪指令用于分配一片连续的存储区域并初始化为0。
    DataSpace SPACE 100;分配连续100 字节的存储单元并初始化为0。
    DataSpace % 100
    
  • MAP 伪指令用于定义一个结构化的内存表的首地址。MAP 也可用“^”
    代替
  • FIELD 伪指令用于定义一个结构化内存表中的数据域。FILED 也可用
    “#”代替。
    MAP 0x100, R0   ;定义结构化内存表首地址的值为0x100+R0。
    A FIELD 16  ;定义A 的长度为16 字节,位置为0x100+R0
    B FIELD 32  ;定义B 的长度为32 字节,位置为0x110+R0
    S FIELD 256 ;定义S 的长度为256 字节,位置为0x130+R0
    

3. 汇编控制伪指令

汇编控制伪指令用于控制汇编程序的执行流程。

  • IF、ELSE、ENDIF 伪指令能根据条件的成立与否决定是否执行某个指
    令序列。
    GBLL Test   ;声明一个全局的逻辑变量,变量名为Test
    IF Test = TRUE
      指令序列1
    ELSE
      指令序列2
    ENDIF
    
  • WHILE、WEND 伪指令能根据条件的成立与否决定是否循环执行某个
    指令序列。
    GBLA Counter   ;声明一个全局的数学变量,变量名为Counter
    Counter SETA 3 ;由变量Counter 控制循环次数
    ……
    WHILE Counter < 10
    指令序列
    WEND
    
  • MACRO、MEND 伪指令可以将一段代码定义为一个整体,称为宏指令,然后就可以在程序中通过宏指令多次调用该段代码。MEXIT 用于从宏定义中跳转出去。
    MACRO
    $HandlerLabel HANDLER $Handlerpara;宏的名称为HANDLER,有1 个参数$Handlerpara, $HandlerLabel为标号,在宏指令被展开时会被替换为用户定义的符号。
    sub sp,sp,#4 ;decrement sp(to store jump address)
    stmfd sp!,{r0} ;PUSH the work register to stack(lr does not push because it return to original address)
    ldr r0,=$Handlerpara;load the address of HandleXXX to r0
    ldr r0,[r0] ;load the contents(service routine start address) of HandleXXX
    str r0,[sp,#4] ;store the contents(ISR) of HandleXXX to stack
    ldmfd sp!,{r0,pc} ;POP the work register and pc(jump to ISR)
    MEND
    

4. 其他常用伪指令

  • AREA 伪指令用于定义一个代码段或数据段。
  • ALIGN 伪指令可通过添加填充字节的方式,使当前位置满足一定的对
    其方式。
  • CODE16 伪指令通知编译器其后的指令序列为16 位的Thumb 指令,
  • CODE32 伪指令通知编译器其后的指令序列为32 位的ARM 指令。
  • ENTRY 伪指令用于指定汇编程序的入口点
  • END 伪指令用于通知编译器已经到了源程序的结尾。
  • EQU 伪指令用于为程序中的常量、标号等定义一个等效的字符名称,
    类似于C 语言中的#define。其中EQU 可用“*”代替。
  • EXPORT 伪指令用于在程序中声明一个全局的标号,该标号可在其他的
    文件中引用。EXPORT 可用GLOBAL 代替。
  • IMPORT 伪指令用于通知编译器要使用的标号在其他的源文件中定义,
    但要在当前源文件中引用,而且无论当前源文件是否引用该标号,该标
    号均会被加入到当前源文件的符号表中。
  • EXTERN 伪指令用于通知编译器要使用的标号在其他的源文件中定义,
    但要在当前源文件中引用,如果当前源文件实际并未引用该标号,该标
    号就不会被加入到当前源文件的符号表中。
  • GET 伪指令用于将一个源文件包含到当前的源文件中,并将被包含的
    源文件在当前位置进行汇编处理。可以使用INCLUDE 代替GET。
  • INCBIN 伪指令用于将一个目标文件或数据文件包含到当前的源文件
    中。
  • RN 伪指令用于给一个寄存器定义一个别名
AREA Init,CODE,READONLY,ALIGN=3 ;该伪指令定义了一个代码段,段名为Init,属性为只读, 并指定后面的指令为8 字节对齐。
ENTRY      ;指定应用程序的入口点
Temp RN R0 ;将R0 定义一个别名Temp
GET a1.s   ;通知编译器当前源文件包含源文件a1.s
GET C:\a2.s ;通知编译器当前源文件包含源文件C:\ a2.s
INCBIN a1.bin;通知编译器当前源文件包含文件a1.bin
EXPORT Stest ;声明一个可全局引用的标号Stest
IMPORT Main  ;通知编译器当前文件要引用标号Main,但Main 在其他源文件中定义
Test EQU 50  ;定义标号Test 的值为50
CODE32       ;通知编译器其后的指令为32 位的ARM 指令
LDR R0,=NEXT+1 ;将跳转地址放入寄存器R0
BX R0            ;程序跳转到新的位置执行,并将处理器切换到Thumb 工作状态
……
CODE16    ;通知编译器其后的指令为16 位的Thumb 指令
NEXT LDR R3,=0x3FF
……
END   ;指定应用程序的结尾

C与ARM汇编混合编程

1. C/C++中嵌入汇编程序

void enable_IRQ(void) //使能中断程序  
{  
    int tmp;              //定义临时变量,后面使用  
    __asm                 //内嵌汇编程序的关键词  
    {  
        MRS tmp, CPSR     //把状态寄存器加载给tmp  
        BIC tmp, tmp, #80 //将IRQ控制位清0  
        MSR CPSR_c, tmp   //加载程序状态寄存器  
    }  
}  
  
void disable_IRQ(void) //禁止中断程序  
{  
    int tmp;              //定义临时变量,后面使用  
    __asm                 //内嵌汇编程序的关键词  
    {  
        MRS tmp, CPSR     //把状态寄存器加载给tmp  
        ORR tmp, tmp, #80 //将IRQ控制位置1  
        MSR CPSR_c, tmp   //加载程序状态寄存器  
    }  
}  

2. 汇编与C/C++程序的变量相互访问

  • 在C/C++程序中声明的全局变量可以被汇编程序通过地址间接访问。
    AREA Example, CODE, READONLY  
       EXPORT AsmAdd  
       IMPORT g_cVal      @声明外部变量g_cVal,在C中定义的全局变量  
    Add  
       LDR R1, =g_cVal    @装载变量地址  
       LDR R0, [R1]       @从地址中读取数据到R0  
       ADD R0, R0, #1     @加1操作  
       STR R0, [R1]       @保存变量值  
       MOV PC, LR         @程序返回  
    END  
    
  • 在汇编程序中声明的数据可以被C/C++程序所访问。在汇编程序中用EXPORT/GLOBAL伪指令声明该符号为全局标号,C/C++程序中定义相应数据类型的指针变量
    汇编:
      EXPORT Message        @声明全局标号  
      Message DCB "HELLO$"  @定义了5个有效字符,$为结束符 
    
    C/C++:
    extern char* Message;  
    int MessageLength()  
    {  
        int Length = 0;  
        char *pMessage;         //定义字符指针变量  
        pMessage = Message;     //指针指向Message 内存块的首地址  
        
        /*while循环,统计字符串的长度*/  
        while(*pMessage != '$') //$为字符串的结束符  
        {  
            Length++;  
            pMessage++;  
        }  
        return(Length); //返回字符串的长度  
    }  
    

3. 汇编与C/C++程序的函数相互调用(APTCS规则)

汇编程序设置要遵循APTCS规则,保证程序调用时参数的正确传递。

  • C程序调用汇编程序。
    汇编程序中使用EXPORT伪指令声明本子程序可外部使用,使其他程序可调用该子程序;在C语言程序中使用extern关键字声明外部函数(声明要调用的汇编子程序),才可调用此汇编的子程序。
    strcopy实现汇编代码:

    AREA  Example, CODE, READONLY    @声明代码段Example  
          EXPORT strcopy          @声明strcopy,以便外部函数调用  
    
    strcopy     @ R0为目标字符串的地址, R1为源字符串的地址  
    
             LDRB R2, [R1], #1    @读取字节数据,源地址加1  
             STRB R2, [R0], #1    @保存读取的1字节数据,目标地址加1  
             CMP R2, #0           @判断字符是否复制完毕  
             BNE strcopy          @没有复制完,继续循环复制  
             MOV PC, LR  
    END 
    

    C/C++:

    #include <stdio.h>  
    extern void strcopy(char *d, const char *s); //声明外部函数,即要调用的汇编子程序  
    int main(void)  
    {  
      const char *srcstr = "First ource";          //定义字符串常量  
      char dststr[] = "Second string-destination"; //定义字符串变量  
      printf("Before copying: \n");  
      printf("src=%s, dst=%s\n", srcstr, dststr);  //显示源字符串和目标字符串的内容  
      strcopy(dststr, srcstr);                     //调用汇编子程序R0=dststr, R1=srcstr  
      printf("After copying: \n");  
      printf("src=%s, dst=%s\n", srcstr, dststr);  //显示复制后的结果  
      return(0);  
    }  
    
  • 汇编程序调用C程序
    在汇编程序中使用IMPORT伪指令声明将要调用的C程序函数。在调用C程序时,要正确设置入口参数,然后使用BL指令调用。
    C/C++ sum函数:

    int sum(int a, int b, int c, int d, int e)  
    {  
        return(a+b+c+d+e); //返回5个变量的和  
    }  
    

    汇编调用sum函数:

     AREA Example, CODE, READONLY  
       IMPORT sum      @ 声明外部标号sum,即C函数sum()  
       EXPORT CALLSUM  
    UM  
       STMFD SP!, {LR}    @LR寄存器入栈  
       MOV R0, #1         @设置sum函数入口参数,R0为参数a  
       MOV R1, #2         @R1为参数b  
       MOV R2, #3         @R2为参数c  
       MOV R3, #5         @参数 e=5,保存到堆栈中  
       STR R3, {SP, #-4}!  
       MOV R3, #4         @R3为参数d, d=4  
       BL sum             @调用C程序中的sum函数,结果放在R0中  
       ADD SP, SP, #4     @调整堆栈指针  
       LDMFD SP, {PC}     @程序返回  
    END  
    

寄存器最多传递4个参数(R0-R3),超出四个的需要用到堆栈。
以上程序使用了5个参数,分别使用寄存器R0存储第1个参数,R1存储第2个参数,R2存储第3个参数,R3存储第4个参数,第5个参数利用堆栈传送。
由于利用了堆栈传递参数,在程序调用结束后要调整堆栈指针。汇编程序中调用了C程序的sum子函数,实现了1+2+3+4+5,最后相加结果保存在R0寄存器中。

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

推荐阅读更多精彩内容

  • 算术和逻辑指令ADC : 带进位的加法(Addition with Carry)ADC{条件}{S} <dest...
    luffier阅读 3,455评论 0 3
  • 8086汇编 本笔记是笔者观看小甲鱼老师(鱼C论坛)《零基础入门学习汇编语言》系列视频的笔记,在此感谢他和像他一样...
    Gibbs基阅读 36,348评论 8 113
  • ARM 汇编指令学习:[2]ARM指令集 一、跳转指令 1、 B(跳转指令)及BL(带返回跳转指令) 其中: L决...
    techping阅读 2,869评论 0 2
  • 我沉沉地梦着 沉沉地醒来 光与暗如鸳鸯降临到我身上 风轻轻吹过 在欢呼 在悲泣 如牧羊人在大块的云下吹奏 听不出细...
    木子珩阅读 244评论 0 0
  • 我最近一直以来在整理自己十八年来的记忆,想来十八年风雨、十八年飘摇,总算还是平稳度过,近来在某一聊天软件上认识一些...
    默读人心阅读 2,684评论 0 1