打印
[经验分享]

ARM 汇编

[复制链接]
1032|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Jiangxiaopi|  楼主 | 2025-3-8 11:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
; 还未更新完...

;--------作者:时空自由民
;
;-----------ARM 汇编语言 例子


;-------常见指令后缀
    EQ      ;相等
    NE      ;不相等
    CS/HS   ;无符号数大于或等于
    ......

    ADD R0,R0,#1    ; R0+1 -> R0

    MOV R0,#0X00FF  ; R0=0X00FF

    MOVS R0,R1,LSL #3 ;将寄存器R1值 左移3位后传送到R0 并影响标志位

    MVN R0,R1 ;将寄存器R1值按位求反后送入R0

    MVN R0,#0XFF ;将立即数0XFF 按位取反后装入R0 然后R0=0xffffff00

    ADD R0,R1,R2    ; R1+R2 ->R0

    MOV R0,R1       ; R1->R0

    LDR R0,[R1]     ; [R1]->R0 假设 R1存储的是0x3FE是内存地址  则是将00X3FE内存地址中的数据存入R0

    MOV R0,R1,LSL #2 ; R1<<2 ->R0, LSL 左移命令  LSR右移命令 ASR算数右移  ROR循环右移 RRX带扩展的循环右移

    ADD R0,R1,R2,LSR #3 ;R1 + R2>>3 ->R0

    SUB R0,R0,#1 ; R0=R0-1

    SUB R0,R1,R2 ; R0=R1-R2

    SUB R0,R1,R2,LSL #3 ;R0=R1-(R2<<3)

    LDR R0,[R1,#2]  ; [R1+2] ->R0 R1中的值+2 当作内存地址 然后将内存地址中的值 赋值到R0

    STR R1,[R0,#0X12]   ; R1 ->R0+0X12地址内存中去
    STR R1,[R0],#0X12   ; R1 ->R0+0X12地址内存中去  R0=R0+0X12

    RSB R0,R0,#0XFFFF   ;R0=0XFFFF - R0
    RSB R0,R1,R2        ;R0=R2-R1

    AND R0,R1,R2    ; R0= R1 & R2
    AND R0,R0,#3    ; R0=R0&3

    ORR R0,R0,#3    ; R0=R0|3

    EOR R0,R0,#0F   ; R0=R0 异或 0F

    BIC R0,R0,#0F   ; 将R0的低4位 清0

    CMP R1,R0       ; R1-R0 并改变CPSR的标志位

    CMN R1,R0       ; R1+R0 并改变CPSR的标志位
    CMN R1,#0x200   ; 将R1值和立即数0X200相加 并根据结果改变CPSR标志位

    TST R1,#0XF     ; 检测R1的低4位是否为0

    TEQ R1,R2       ; 将R1的值 和R2的值 进行异或运算 然后改变CPSR的标志位

    ;程序状态寄存器处理指令
    MRS R0,CPSR  ;将CPSR->R0
    ORR R0,R0,#C0 ;R0=R0|C0 ,即屏蔽外部中断 和快速外部中断

    MSR CPSR,R0 ;R0->CPSR



    ;多寄存器寻址
    ;从左赋值到右  用于存储器读取数据 比单字读取操作方便
    ;IA:每次传送后地址加4
    ;IB:每次传送前地址加4
    ;DA:每次传送后地址减4
    ;DB:每次传送前地址减4
    ;FD:满递减堆栈
    ;ED:空递减堆栈
    ;FA:满递增堆栈
    ;EA:空递增堆栈
    LDMIA R0!,{ R1-R3,R5}   ; [R0] ->R1  假设R0=0XF1 将内存地址0XF1中的数据赋值到 R1
                            ; [R0+4] ->R2 R0=0XF1+4 将内存地址0XF1+4 中的数据赋值到R2
                            ; [R0+8] ->R3
                            ; [R0+12] ->R5

    STMIA R1!,{R3-R9}       ;将R3~R9 数据存储到R1 R1更新值
                            ;R3->[R1]
                            ;R4->[R1+4]
                            ;R5->[R1+8]
                            ;R6->[R1+12]

    SWP R1,R1,[R0]  ;将R1的内容和R0指向的存储单元内容进行交换


    ;异常产生指令
    SWI     0x02  ;软中断 调用操作系统编号为0X02的系统例程
    BKPT    0XFF32 ;

    ;堆栈寻址  栈会向上增长 递增堆栈,也会向下增长 递减堆栈
    ;后缀 IB 先增加堆栈地址值 SP+4,然后再出栈 入栈 SP->XX
    ;后缀 IA 先完成操作在增加地址 SP->XX  SP+4
    ;后缀 DB 先减少堆栈地址值 SP-4,然后再出栈 入栈 SP->XX
    ;后缀 DA 先完成操作在减少地址值 SP->XX  SP-4
    STMFD SP!,{R1-R3,LR}   ; 将寄存器R1~R3 LR 入栈,满递减堆栈 R1->SP SP++ R2->SP SP++....
    LDMFD SP!,{R1-R3,LR}   ; 将栈中数据 出栈 存入R1~R3 LR,SP->R1 SP--, SP->R2 SP--


    ;跳转指令
    LDR PC,[PC,#+0X00FF] ; [PC+8+0X00FF] ->PC  修改程序指针 PC值 实现跳转
    B task1 ;无条件 跳转到task1处执行
    B 0x1234 ;跳转到绝对地址 0X1234处

    BL task1 ;先将当前执行指令的下一条指令的地址值 存储到链接寄存器R14(LR)中(以便再返回来) 在跳转到task1标号执行

    BLX task1 ;先将当前执行指令的下一条指令的地址值 存储到链接寄存器R14(LR)中(以便再返回来) 并从ARM状态切换到Thumb状态 在跳转到task1标号执行
    BLX R0 ;先将当前执行指令的下一条指令的地址值 存储到链接寄存器R14(LR)中(以便再返回来) 并从ARM状态切换到Thumb状态 在跳转到R0中的地址处执行

    BX R0 ; 跳转到R0处执行 如果R0[0]=1 则切换到Thumb状态


    ;ARM 常见伪指令
    DCB ;分配一段字节的内存单元 并用指定的数据初始化
    DCD DCDU ;分配一段字的内存单元 ,并用指定的数据初始化

    DCQ DCQU ;分配一段双字的内存单元 并用64位整型数据初始化

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

    ALIGN ; 边界对齐
    AREA  ; data段 rom段定义
    END ; 汇编结束
    ENTRY ; 程序入口
    EQU ;常量定义 类似C宏定义
    EXPORT , GLORBAL ;声明一个符号可以被 其他文件引用
    IMPORT EXYERN ;声明一个外部符号

    NOP ; 延时空操作

;---------ARM asm Example -------

    AREA BUF,DATA,READWRITE ;声明一个数据段 BUF in RAM , BUF 可读可写
    count DCB 30  ; 定义一个字节单元count
    AREA EXAMPLE1 ,CODE,READONLY ; 声明代码段 EXAMPLE1 in ROM , 只读
    ENTRY ; 程序入口
    CODE32  ;声明32位ARM指令
    START
        LDRB R0,count   ;R0=count
        MOV  R1,#10     ;R1=0X10
        ADD R0,R0,R1    ;R0=R0+R1
        B START ;跳转到START处执行

    END ;程序结束
       
;----------------STM32启动文件.s 代码分析---------------
       
        ;Reset_Handler 类似于子函数的函数名
        Reset_Handler        PROC        ;PROC 定义的子程序的开始 类似C语言函数的{ }的开头{
       
        EXPORT Reset_Handler  [WEAK] ; WEAK 意思若定义 就是或者函数定义的作用很弱 就小领导的说话没啥用 这个也是在这里定义了权威作用不太大,在其他地方还可以再定义这个子函数,其他地方如果在定义了这个子函数,那这里的定义就无效了
       
        ;EXPORT 类似于C语言的extern关键字 声明外部可调用的全局属性
       
        IMPORT __main ; __main是外部的文件         IMPORT在这里 就是引入外部变量 类似于extern pwm; 这个PWM是其他.c文件定义的全局变量 然后在本文件中引用
       
        ENDP ;子函数结束的标志 类似函数{}的末尾}




源代码文件的链接
链接:https://pan.baidu.com/s/12kvtT8djz1hL0X3KFBbK-A?pwd=y4gp
提取码:y4gp


————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_57249200/article/details/129478705

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

90

帖子

0

粉丝