•(汇编)指令是CPU机器指令的助记符,经过编译后会得到一串10组成的机器码,可以由CPU读取执行。
•(汇编)伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。
•ARM官方的ARM汇编风格:指令一般用大写、Windows中IDE开发环境(如ADS、MDK等)常用。如: LDR R0, [R1]
•GNU风格的ARM汇编:指令一般用小写字母、linux中常用。如:ldr r0, [r1]
ARM官方已经确认采用GNU风格的ARM汇编作为其官方推荐的风格。这意味着在将来的ARM开发中,建议使用小写字母的指令格式,例如"ldr r0, [r1]"。
- ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。
- LDR指令(Load Register)用于将内存中的数据加载到寄存器中。
- STR指令(Store Register)用于将寄存器中的数据存储到内存中。
- LDR/STR组合用来实现 ARM CPU和内存数据交换
1、寄存器寻址 mov r1, r2 (将 r2 寄存器的值复制到 r1 寄存器中)
2、立即寻址 mov r0, #0xFF00 (将常数 0xFF00 加载到 r0寄存器 中)
3、寄存器移位寻址 mov r0, r1, lsl #3 (将 r1 的值左移 3 位,然后将结果存入 r0 中)
LSL:逻辑左移,移位后寄存器空出的低位补0。
LSR:逻辑右移,移位后寄存器空出的高位补0。
ASR:算术右移,移位过程中,符号位保持不变,如果源操作数是正数,则空出的高位补0,否则补1.
ROR:循环右移,移位后移除的低位填入空出的高位。
RRX:带扩展的循环右移,操作数右移一位,移位空出的高位用C标志的值填充。
4、寄存器间接寻址 ldr r1, [r2] (从内存中读取 r2 的数据,并存入 r1 中)
5、基址变址寻址 ldr r1, [r2, #4] (将 r2 作为基址,再加上偏移量 4,从相应的内存地址读取数据并存入 r1 中;r2+4地址的数据存入r1)
6、多寄存器寻址 ldmia r1!, {r2-r7, r12} (将 r1 指向的内存地址开始的一段连续的数据加载到 r2-r7 和 r12 这些寄存器中;r1相当于数组8个元素依次读入到8个寄存器)
7、堆栈寻址 stmfd sp!, {r2-r7, lr} (将 r2-r7 和 lr 这些寄存器的值依次保存到堆栈中,同时堆栈指针 sp 会自动减小)
8、相对寻址 beq flag (根据指令跳转的相对位置来确定目标地址,通常用于分支指令。例如, 表示如果前一个指令的比较结果为相等,则跳转到标记为 flag 的位置继续执行。)
根据进行条件判断
条件执行后缀用于在指令执行之前设置条件,只有在满足条件的情况下指令才会被执行。条件执行后缀可以使得指令的执行更加灵活和有选择性,根据特定条件来决定是否执行某个指令或者跳转。
•前导零计数 clz
这些指令的作用是在计算机中对数据进行处理,进行各种运算或传输操作
- mrs & msr
• mrs用来读psr,msr用来写psr• CPSR寄存器比较特殊,需要专门的指令访问,这就是mrs和msr。
- b & bl & bx
- b 直接跳转(就没打开算返回)
- bl branch and link,跳转前把返回地址放入lr中,以便返回,以便用于函数调用
- bx跳转同时切换到ARM模式,一般用于异常处理的跳转。
- ldr/str & ldm/stm & swp
- 单个字/半字/字节访问 ldr/str
- 多字批量访问 ldm/stm
- swp r1, r2, [r0]
ARM汇编中的立即数
- ARM指令都是32位,除了指令标记和操作标记外,本身只能附带很少位数的立即数。因此立即数有合法和非法之分。
- 合法立即数:经过任意位数的移位后非零部分可以用8位表示的即为合法立即数
- 非法立即数则是不满足合法立即数条件的立即数。
- swi(software interrupt)
软中断指令用来实现操作系统中系统调用,它提供了一种机制,让用户程序与操作系统进行交互,实现了用户程序与底层硬件的隔离和保护。(写操作系统用)
- mcr & mrc
- mrc用于读取CP15中的寄存器
- mcr用于写入CP15中的寄存器
协处理器
SoC内部另一处理核心,协助主CPU实现某些功能,被主CPU调用执行一定任务。
- ARM设计上支持多达16个协处理器,但是一般SoC只实现其中的CP15.(cp:coprocessor)
- 协处理器和MMU、cache、TLB等处理有关,功能上和操作系统的虚拟地址映射、cache管理等有关。
MRC & MCR的使用方法
- mcr{<cond>} p15, <opcode_1>, <Rd>, <Crn>, <Crm>, {<opcode_2>}
- opcode_1:对于cp15永远为0
- Rd: ARM的普通寄存器
- Crn: cp15的寄存器,合法值是c0~c15
- Crm: cp15的寄存器,一般均设为c0
- opcode_2:一般省略或为0
ldm/stm与栈的处理
为什么需要多寄存器访问指令
- ldr/str每周期只能访问4字节内存,如果需要批量读取、写入内存时太慢,解决方案是stm/ldm
- ldm(load register mutiple)
- stm(store register mutiple)
8种后缀
- ia(increase after)先传输,再地址+4
- ib(increase before)先地址+4,再传输
- da(decrease after)先传输,再地址-4
- db(decrease before)先地址-4,再传输
- fd(full decrease)满递减堆栈
- ed(empty decrease)空递减堆栈
- fa(·······) 满递增堆栈
- ea(·······)空递增堆栈
- 将r0存入sp指向的内存处(假设为0x30001000);然后地址+4(即指向0x30001004),将r1存入该地址;然后地址再+4(指向0x30001008),将r2存入该地址······直到r12内容放入(0x3001030),指令完成。
- 一个访存周期同时完成13个寄存器的读写
四种栈
- 空栈:栈指针指向空位,每次存入时可以直接存入然后栈指针移动一格;而取出时需要先移动一格才能取出
- 满栈:栈指针指向栈中最后一格数据,每次存入时需要先移动栈指针一格再存入;取出时可以直接取出,然后再移动栈指针
- 增栈:栈指针移动时向地址增加的方向移动的栈
- 减栈:栈指针移动时向地址减小的方向移动的栈
!的作用
- ldmia r0, {r2 - r3}
- ldmia r0!, {r2 - r3}
感叹号的作用就是r0的值在ldm过程中发生的增加或者减少最后写回到r0去,也就是说ldm时会改变r0的值。
^的作用
ldmfd sp!, {r0 - r6, pc}
ldmfd sp!, {r0 - r6, pc}^
^的作用:在目标寄存器中有pc时,会同时将spsr写入到cpsr,一般用于从异常模式返回。
- 伪指令不是指令,伪指令和指令的根本区别是经过编译后会不会生成机器码。
- 伪指令的意义在于指导编译过程。
- 伪指令是和具体的编译器相关的,我们使用gnu工具链,因此学习gnu环境下的汇编伪指令。
- .global _start @ 给_start外部链接属性
- .section .text @ 指定当前段为代码段
- .ascii .byte .short .long .word
- .quad .float .string @ 定义数据
- .align 4 @ 以16字节对齐
- .balignl 16 0xabcdefgh @ 16字节对齐填充
- .end @标识文件结束
- .include @ 头文件包含
- .arm / .code32 @声明以下为arm指令
- .thumb / .code16 @声明以下为thubm指令
- ldr 大范围的地址加载指令
- adr 小范围的地址加载指令
- adrl 中等范围的地址加载指令
- nop 空操作
- ARM中有一个ldr指令,还有一个ldr伪指令
- 一般都使用ldr伪指令而不用ldr指令
adr与ldr区别
- adr编译时会被1条sub或add指令替代,而ldr编译时会被一条mov指令替代或者文字池方式处理
- adr总是以PC为基准来表示地址,因此指令本身和运行地址有关,可以用来检测程序当前的运行地址在哪里
- ldr加载的地址和链接时给定的地址有关,由链接脚本决定。
- ldr加载的地址在链接时确定,而adr加载的地址在运行时确定
- @ 用来做注释。可以在行首也可以在代码后面同一行直接跟,和C语言中//类似
- # 做注释,一般放在行首,表示这一行都是注释而不是代码。
- :以冒号结尾的是标号
- . 点号在gnu汇编中表示当前指令的地址
- # 立即数前面要加#或$,表示这是个立即数
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/bian-cheng-ri-ji/39973.html