-
汇编指令
.text /* 逻辑指令 */ mov r7,#0x88 @ and r0,r1,#0xFF //r0=r1&0xFF @ orr r7,r7,#0xffff77 //r7=r7&0x88,清除7号3号位,但立即数太大,报错 bic r7,r7,#0x88 //清除r7中7号3号 @ tst r0,#0x20 //测试5号位是否为0,为0则Z(30号位)标志置1 @ cmp r1,r0 //将R1与R0相减做比较,并根据结果设置CPSR的标志位 @ eg: 使能中断和快速中断 @ mrs r0,cpsr //对cpsr操作需要以寄存器为中介 @ bic r0,r0,#0xc0 //I-6,F-7,使能,将6/7位清零 @ msr cpsr,r0 @ eg: 判断当前工作状态位ARM状态,是则切换到user工作模式? @ mrs r0,cpsr @ tst r0,#0x20 //5号位-1-Thumb状态,0-ARM状态 @ andeq r0,#0xffffffe0 //1110 0000 ,先把M[4:0]清零 @ orreq r0,#0x10 //将4号位置1 @ mrseq cpsr,r0 //上一判断为真,则执行 /* 算术指令 */ @ add r0,r1,r2 //ro=r1+r2 @ sub r0,r1,#3 //ro=r1-3 @ sub r0,r1,r2,LSL#1 //r0=r1-(r2<<1) @ mul r1,r2,r3 //r1=r2*r3 /* 跳转指令 */ @ b main //跳转到标号为main的代码处 @ bl func //保存下一条要执行的指令的位置到LR寄存器,跳转函数func @ //跳转代码结束后,使用MOV PC,LR指令跳回来 @ beq addr //当CPSR寄存器中的Z条件码置位时,跳转到该地址处 @ bne addr //当不等时,跳转到地址addr .end
用汇编实现以下功能:
1 void main(void) 2 { 3 int ret=0; 4 func1(2); 5 while(1) {} 6 } 7 8 func1(int a) 9 { 10 if(a=2) 11 return func2(a); 12 else 13 return func3(a); 14 } 15 16 func2(int a) 17 { 18 return a+3; 19 } 20 21 func3(int a) 22 { 23 return a-1; 24 }
示例代码(1)
1 .text 2 3 main: 4 mov r5,#0 //0x00 5 mov r0,#2 //0x04 6 bl func1 //PC:0x08 LR:0x0C(12) 7 8 main_end: 9 b main_end @ while(1) {}; 死循环 10 11 func1: 12 cmp r0,#2 //PC:0x10(16) LR:0x0C 13 bleq func2 //PC:0x14(20) LR:0x18(24) 注意此处LR被跳转指令里面嵌套的跳转指令覆盖了,导致无法跳回第一次跳转指令的下一指令 14 blne func3 //跳转回来时,PC:0x18 LR:0x18 往下走到0x1C, 15 func1_end: 16 mov pc,lr //PC:0x1C(28) LR:0x18,又将跳回0x18,成死循环,跳不出func1 17 18 func2: 19 add r0,#3 //PC:0x20(32) LR:0x18 20 mov pc,lr //PC:0x24 LR:0x18 21 22 func3: 23 sub r0,r0,#1 @或者写成sub r0,#1 24 func2_end: 25 26 .end 27
为了避免跳转指令嵌套导致LR被覆盖的问题,可以在嵌套调用的函数里另设寄存器R储存会被覆盖的LR值,在跳转时,将R赋PC就可以
1 .text 2 3 main: 4 mov r5,#0 //0x00 5 mov r0,#2 //0x04 6 bl func1 //PC:0x08 LR:0x0C(12) 7 8 main_end: 9 b main_end @ while(1) {}; 死循环 10 11 func1: 12 mov r12,lr //保存LR:0x0C,避免被覆盖 13 cmp r0,#2 14 bleq func2 // 注意此处LR被跳转指令里面嵌套的跳转指令覆盖了,导致无法跳回第一次跳转指令的下一指令 15 blne func3 16 func1_end: 17 mov pc,r12 18 19 func2: 20 add r0,#3 21 mov pc,lr 22 23 func3: 24 sub r0,r0,#1 @或者写成sub r0,#1 25 func2_end: 26 27 .end 28
1 .text 2 3 //load/store架构规定,存储器之间不能直接拷贝,需要通过寄存器做中转 4 ldr r0,[r1] //r0=*r1,r1里面存放的是地址,把该地址存放的内容读入到r0 5 //LDRB(byte) LDRH(half word) 6 ldr r0,[r1,#8] //r0= *(r1+8) 存储器地址为r1+8的字数据读入寄存器0 7 ldr pc,_irq //pc= *(_irq) 将标号中的内容放入PC中 8 9 str r0,[r1] // *r1=r0 将r0中的值写入存储器地址为r1的空间中,并将r1+4写入r1 10 11 str r0,[r1],#4 //r0=*r1,r1=r1+4 ,将r0中的值写入存储器地址为r1的空间中,并将r1+4写入r1 12 13 str r0,[r1,#4] //*r0=(r1+4) 将r0中的字数据写入以r1+4为地址的内存中 14 15 .end
示例:拷贝srcBuf里的内容到destBuf中
.text ldr r0,=srcBuf @r0存放src的地址 ldrb r1,[r0] @将r0里地址(src)里的(1byte)数据存入r1 ldr r0,=destBuf @r0存放dest地址 strb r1,[r0] @将r1里的数据存入r0里的地址的空间 scrBuf: .byte 0x01,0x02,0x03,0x04 .data destBuf: .space 8 .end
示例2:用汇编实现以下功能:
main() { int i=0; const char buf[]={1,2,3}; char destbuf[8]; for(i=0;i<3;i++) { destbuf[i] = buf[i]; } }
main: mov r5,#0 @用于for循环计数 ldr r7,=buf ldr r8,=destbuf loop: cmp r5,#3 beq main_end add r5,#1 ldrb r0,[r7],#1 @将r7里的地址buf里的1byte数据存入r0后,r7=r7+1 strb r0,[r8],#1 @将r0的值赋给r8里的地址dest空间后,r8=r8+1 b loop main_end: b main_end buf: .byte 1,2,3 @定义在代码段仅可读,在数据段可读可写 .data destbuf: .space 8 @定义空间大小为8个字节 .end
GNU汇编伪指令
.text // 将定义符开始的代码编译到代码段 .data // 将定义符开始的代码编译到数据段 .end //文件结束 .equ GPG3, 0xFFFF //定义宏 .byte //定义变量1字节 .word //定义word变量(4字节 32位机) .string //定义字符串 .string "abc\0" .global _start //声明_start为去全局符号
批量操作指令
ia --- Increment After
ib --- Increment Before
da --- Decrement After
db --- Decrement Befor
stmdb和ldmia指令一般配对使用,stmdb用于将寄存器压栈,ldmia用于将寄存器弹出栈,作用是保存使用到的寄存器。
详见:https://blog.csdn.net/minsophia/article/details/53080183
指令:stmdb sp!,{r0-r12,lr}
含义:sp = sp - 4,先压lr,sp = lr(即将lr中的内容放入sp所指的内存地址)。sp = sp - 4,再压r12,sp = r12。sp = sp - 4,再压r11,sp = r11......sp = sp - 4,最后压r0,sp = r0。
如果想要将r0-r12和lr弹出,可以用ldmia指令:
指令:ldmia sp!,{r0-r12,lr}
原文:https://www.cnblogs.com/y4247464/p/12271751.html
最新更新
Objective-C语法之代码块(block)的使用
VB.NET eBook
Add-in and Automation Development In VB.NET 2003 (F
Add-in and Automation Development In VB.NET 2003 (8
Add-in and Automation Development in VB.NET 2003 (6
Add-in and Automation Development In VB.NET 2003 (5
AddIn Automation Development In VB.NET 2003 (4)
AddIn And Automation Development In VB.NET 2003 (2)
Addin and Automation Development In VB.NET 2003 (3)
AddIn And Automation Development In VB.NET 2003 (1)
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
武装你的WEBAPI-OData入门
武装你的WEBAPI-OData便捷查询
武装你的WEBAPI-OData分页查询
武装你的WEBAPI-OData资源更新Delta
5. 武装你的WEBAPI-OData使用Endpoint 05-09
武装你的WEBAPI-OData之API版本管理
武装你的WEBAPI-OData常见问题
武装你的WEBAPI-OData聚合查询
OData WebAPI实践-OData与EDM
OData WebAPI实践-Non-EDM模式