当前位置: 首页 > news >正文

ARM2.(汇编语言)

1.kill4界面介绍

1.1窗口恢复

若不小心关掉左侧项目列表,可以在window中恢复。

1.2Debug调试界面

编写好程序后可以进入Debug界面

左侧会显示寄存器状态

单步执行,会跟随函数逻辑跳转到对应行执行,比如函数调用会跳转到相应行数1执行。

单步执行,但是遇到函数调用会直接将调用的函数执行完毕拿到执行结果,跳转到函数调用的下一行代码执行。

2.汇编语言

2.1汇编语言框架

area reset, code, readonly		code32entryend

        area reset, code, readonly:这是一个汇编指令,用于定义一个名为“reset”的代码区域,该区域是只读的。通常用于嵌入式系统或启动代码中,表示复位向量或初始化代码。

        code32:指定接下来的代码是 32 位 ARM 指令(而不是 Thumb 指令)。

        entry:表示程序的入口点(类似于主函数或启动点)。

        end:代码结束。

2.2mov赋值操作

area reset, code, readonly		code32entry; 赋值操作示例mov r0, #4			 ; 将立即数 4 装入寄存器 r0 (r0 = 4)mov r1, r0           ; 将寄存器 r0 的值复制到 r1 (r1 = r0 = 4)mov r2, r1, lsl #1   ; 将 r1 的值逻辑左移 1 位后存入 r2 (r2 = r1 << 1 = 4 << 1 = 8)mov r3, r1, lsr #1   ; 将 r1 的值逻辑右移 1 位后存入 r3 (r3 = r1 >> 1 = 4 >> 1 = 2)ror r4, r3, #5		 ; 将 r3 的值循环右移 5 位,结果存入 r4end

看看运行结果

注意:右移会将移出去的数字清除,左侧补0,而循环右移会将移出去的数字补充到左侧。

2.3add加法操作

area reset, code, readonly		code32entry; ADD 指令应用示例	mov r0, #100		    ; r0 = 100mov r2, #100		    ; r2 = 100	; 立即数加法add r1, r0, #200		; r1 = r0 + 200 = 100 + 200 = 300; 寄存器加法  add r3, r2, r0			; r3 = r2 + r0 = 100 + 100 = 200; 带移位的加法(您的注释有误)add r4, r2, r0, lsl #1	; r4 = r2 + (r0 << 1) = 100 + (100 × 2) = 100 + 200 = 300; 注意:lsl #1 是左移1位(乘以2),不是右移; 立即数表达式加法add r4, r2, #(100 >> 1)	; r4 = r2 + (100 >> 1) = 100 + 50 = 150; 汇编器会在编译时计算 100 >> 1 = 50; 带寄存器控制移位的加法(存在潜在问题)add r5, r2, r0, lsl r1	; r5 = r2 + (r0 << r1) = 100 + (100 << 300); 注意:r1=300,左移300位没有意义,可能导致意外结果end

看看运行结果

2.4sub减法操作

area reset, code, readonly		code32entry; SUB 指令应用示例mov r0, #100		    ; r0 = 100mov r2, #100		    ; r2 = 100; 立即数减法sub r1, r0, #50		; r1 = 100 - 50 = 50; 寄存器减法sub r3, r2, r0			; r3 = 100 - 100 = 0; 带左移的减法(乘以2)sub r4, r2, r0, lsl #1	; r4 = 100 - (100 × 2) = -100; 带右移的减法(除以2) sub r4, r2, r0, lsr #1	; r4 = 100 - (100 ÷ 2) = 50; 合理的移位寄存器操作mov r6, #2			    ; 设置合理的移位量sub r5, r2, r0, lsl r6	; r5 = 100 - (100 × 4) = -300; 使用反向减法指令(当需要交换操作数顺序时)rsb r7, r0, r2		    ; r7 = r2 - r0 = 100 - 100 = 0rsb r8, r0, #200	    ; r8 = 200 - r0 = 200 - 100 = 100end

看看运行结果

2.5ldr伪指令,加载任意32位数

加载任意32位数:

area reset, code, readonly		code32entry; LDR 指令应用示例mov r1, #10			; r1 = 10mov r0, #0xffffffff	; 错误!ARM的mov 不能加载32位立即数mvn r0, #0xffffffff	; 正确!使用mvn取反加载,r0 = 0x00000000ldr r0, =0xfac0		; 正确!使用ldr伪指令加载32位立即数end

看看运行结果

2.6bic指定位清零

area reset, code, readonly		code32entry; BIC(位清除)指令应用示例mov r0, #0xffffffff	; r0 = 0xFFFFFFFF (所有位都为1)mov r1, #1		    ; r1 = 1 (二进制: 0001); 方法1:使用立即数直接清除特定位bic r0, r0, #4		  ; 清除第2位(从0开始计数); #4 = 二进制 0100 (第2位为1); r0 = r0 AND NOT(0100) = 0xFFFFFFFB; 方法2:使用寄存器移位清除特定位bic r0, r0, r1, lsl #2  ; r1 = 1 (0001), 左移2位 = 0100 (4); 清除第2位,结果同上; 方法3:使用表达式清除特定位bic r0, r0, #(1 << 2)   ; 1左移2位 = 0100 (4); 清除第2位,结果同上end

运行结果

2.7orr指定位置1

area reset, code, readonly		code32entry; ORR(按位或)指令应用示例 - 指定位置1mov	r0, #0x0			; r0 = 0x00000000 (所有位都为0); 使用ORR指令将第10位置1(位编号从0开始)orr r0, r0, #(1 << 10)	; r0 = r0 OR 0x00000400 = 0x00000400; 1 << 10 = 21? = 1024 = 0x400; 第10位(二进制第11位)被设置为1end

运行结果

2.8subs带标志位的减法

area reset, code, readonly		code32entryend

运行结果

2.9比较大小

比较两位数大小:

area reset, code, readonly		code32entry;比较两数大小;mov r0, #0x100    ; R0 = 0x100 (十进制256);mov r1, #0x2      ; R1 = 0x2 (十进制2);cmp r0, r1        ; 比较 R0 和 R1 的值;movge r2, r0      ; 如果 R0 >= R1 (Greater than or Equal),则 R2 = R0;movlt r2, r1      ; 如果 R0 < R1 (Less Than),则 R2 = R1end

运行结果

比较三位数大小:

area reset, code, readonly		code32entry;比较三个数大小mov r0, #0xff	  ;R0 =  255mov r1, #0x100	  ;R1 = 256mov r2, #0xfe	  ;R2 = 254cmp r0, r1		  ;比较r0和r1movge r3, r0	  ;如果 R0 >= R1,则 R2 = R0movlt r3, r1	  ;如果 R0 < R1 (Less Than),则 R2 = R1cmp r3, r2		  ;比较r3和r2movge r4, r3	  ;如果 R3 >= R2,则 R4 = R3movlt r4, r2	  ;如果 R3 < R2 (Less Than),则 R4 = R2end

运行结果

2.10用分支结构比较大小

area reset, code, readonly		code32entry;分支结构判断两个数大小mov r0, #0x100mov r1, #0x2cmp r0, r1		;比较r0,r1bge greatr		;r0>r1跳转到greatrblt less		;r0<r1跳转到less
greatrmov r2, r0b finish
lessmov r2, r1b finish
finishb finish		 ;无限循环end

运行结果

2.11循环结构求1~99的和

while

area reset, code, readonly		code32entry;循环
;1到99的和 (while)mov r0, #0x0       ; R0 = 0 (用于存储和)mov r1, #0x1       ; R1 = 1 (计数器,从1开始)mov r2, #0x64      ; R2 = 100 (循环终止条件)
loop                 ; 循环开始cmp r1, r2        ; 比较计数器和100bge finish        ; 如果计数器 >= 100,跳转到结束add r0, r0, r1    ; 累加:和 = 和 + 计数器add r1, r1, #1    ; 计数器加1b loop            ; 继续循环
finishb finish          ; 无限循环end

运行结果

结果正确

do while

area reset, code, readonly		code32entry;循环
;1到99的和 (do while)mov r0, #0x0mov r1, #0x1mov r2, #0x64
loopadd r0, r0, r1  add r1, r1, #1 cmp r1, r2    blt loop 
finishb finishend

运行结果与上述一致

2.12函数封装并调用

area reset, code, readonly		code32entry;函数封装并调用b main			   ;跳转到主程序,避免执行函数代码
asm_maxTwoNummov r0, #100mov r1, #200cmp r0, r1movge r3, r0movlt r3, r1mov pc, lr
mainmov r0, #10mov r1, #20bl asm_maxTwoNum   ;调用函数:bl会跳转到函数并将返回地址保存到lr寄存器mov r2, #10mov r3, #20
finishb finishend

通过b跳转可以实现函数的封装和调用。

2.13STMDB(STMFD)解决函数调用嵌套,lr保存地址不够用

在多级函数调用时,lr会被覆盖,因此我们需要用stmfd将lr的内容存入栈中,在执行完函数后用ldmfd弹出,这样就能保证函数准确的返回。     

   操作流程:先递减栈指针,然后存储寄存器到内存,更新栈指针

   注意,在每次函数调用时,都要加上压栈和弹栈操作!

area reset, code, readonly		code32entry;函数封装并调用b main				;跳转到主程序,避免执行函数代码
asm_fun0mov r0, #100mov r1, #200bx lr
asm_maxTwoNummov r0, #100mov r1, #200cmp r0, r1stmfd sp!, {r0-r12,lr};带!栈帧移动,不带不移动,将r0-r12,lr压栈bl asm_fun0			 ;调用函数:bl会跳转到函数并将返回地址保存到lr寄存器ldmfd sp!, {r0-r12,lr};与压栈列表对应,否则会产生错位,将r0-r12,lr弹出 movge r3, r0movlt r3, r1bx lr				  ;返回lr寄存器地址
mainldr sp, =0x40001000mov r0, #10mov r1, #20stmfd sp!, {r0-r12,lr};带!栈帧移动,不带不移动,将r0-r12,lr压栈bl asm_maxTwoNum     ;调用函数:bl会跳转到函数并将返回地址保存到lr寄存器ldmfd sp!, {r0-r12,lr};与压栈列表对应,否则会产生错位,将r0-r12,lr弹出 mov r2, #10mov r3, #20
finishb finishend

我们可以看到,程序可以进行准确的跳转

3.概念补充

3.1ARM内核工作模式以及切换

7种模式:

1. 异常触发模式切换

; 1. 复位(Reset) - 进入 Supervisor 模式
; 处理器上电或复位时自动进入
; 这是程序的起点; 2. 未定义指令异常 - 进入 Undefined 模式
udiv r0, r1, r2    ; 如果处理器不支持UDIV指令; 自动切换到Undefined模式; 3. 软件中断(SWI)或SVC - 进入 Supervisor 模式
svc 0x1234         ; 主动触发管理模式切换; 用于系统调用; 4. 预取指中止 - 进入 Abort 模式
; 当处理器尝试执行无效地址的指令时; 5. 数据中止 - 进入 Abort 模式  
ldr r0, [r1]       ; 如果r1指向无效内存地址; 自动切换到Abort模式; 6. IRQ中断 - 进入 IRQ 模式
; 外部设备触发普通中断时; 7. FIQ中断 - 进入 FIQ 模式
; 高速外设触发快速中断时

2. 手动模式切换

; 通过修改CPSR(当前程序状态寄存器)的模式位
mrs r0, cpsr          ; 读取CPSR到r0
bic r0, r0, #0x1F     ; 清除模式位(低5位)
orr r0, r0, #0x13     ; 设置为Supervisor模式(0b10011)
msr cpsr_c, r0        ; 写回CPSR,切换模式; 注意:在用户模式下不能直接修改CPSR,会触发异常

3.各种模式的具体切换场景

1. User → Supervisor
系统调用:应用程序通过SVC指令请求操作系统服务
复位:处理器启动时自动进入
软件调试:调试器需要更高权限时2. User → IRQ/FIQ
硬件中断:外设(键盘、定时器、网络等)产生中断
实时事件:需要立即处理的紧急事件3. User → Abort
内存访问错误:访问非法内存地址或权限不足
页错误:虚拟内存管理中页面未加载或只读写入4. User → Undefined
执行未定义指令:处理器遇到不认识的指令
协处理器访问:访问不存在的协处理器5. 任何模式 → 任何模式
异常嵌套:在处理一个异常时又发生另一个异常
模式切换指令:操作系统有意识地切换模式

3.2立即数判断

        立即数 是指在指令中直接编码的常数数值,而不是来自寄存器或内存的值。

在 ARM 架构中,由于指令长度固定为 32 位,不能将完整的 32 位立即数直接编码在指令中。因此,ARM 使用了一种巧妙的编码方案。

ARM 中的 12 位立即数实际上由两部分组成:

        8 位 常数(0-255)

        4 位 旋转值(0-15)

编码格式:

[11:8] - 旋转值 (rotate)
[7:0] - 8位常数 (imm8)

实际数值计算:

真正的 32 位立即数 = imm8 循环右移 (2 × rotate) 位

mov r0, #100        ; #100 就是立即数
add r1, r2, #0xFF   ; #0xFF 就是立即数
cmp r3, #42         ; #42 就是立即数

        一个 32 位数值是合法立即数的条件是:它可以通过 8 位常数循环右移偶数位得到。

判断方法:
将数值表示为 32 位二进制检查是否能被分解为 8 位有效字段这个 8 位字段必须能通过循环右移偶数位得到
; 合法立即数示例:
mov r0, #0xFF           ; 合法:0xFF = 0xFF ROR 0
mov r0, #0xFF00         ; 合法:0xFF00 = 0xFF ROR 24 (2×12)
mov r0, #0x3FC0         ; 合法:0x3FC0 = 0xFF ROR 2 (2×1); 非法立即数示例:
mov r0, #0x12345        ; 非法:无法用8位常数通过循环右移得到
mov r0, #0x101          ; 非法:0x101 = 0000 0001 0000 0001; 无法找到8位的连续有效位

3.3b,bl,bx指令

1. b 指令(Branch - 无条件跳转)

b label      ; 跳转到标签处
b #0x1000    ; 跳转到绝对地址 0x1000

特点:

        最简单的跳转指令,不保存返回地址,用于循环、条件分支、无限跳转。

2. bl 指令(Branch with Link - 带链接的分支)

main:mov r0, #10mov r1, #20bl add_numbers    ; 调用函数,lr = main+4的地址b end_programadd_numbers:add r2, r0, r1    ; r2 = r0 + r1mov pc, lr        ; 返回到调用处(使用保存的lr)

特点:

        跳转前将返回地址(下一条指令地址)保存到 lr 寄存器,用于函数调用,是最常用的函数调用指令。

3. bx 指令(Branch and eXchange - 分支并交换)

; 函数返回
bl some_function
; ... 其他代码 ...some_function:; 函数体bx lr          ; 返回到调用处(lr保存的地址); 切换指令集
mov r0, #0x1001    ; 地址最低位为1,表示Thumb模式
bx r0              ; 跳转到0x1000,进入Thumb模式

特点:

        跳转到寄存器指定的地址(不是立即数或标签),可以根据目标地址的最低位切换 ARM/Thumb 指令集,常用于函数返回模式切换

3.4ARM内核采用的栈

ARM 内核采用的栈类型不是固定的,而是可配置的,但最常用的是满递减栈

这是 ARM 架构的默认最常用的栈类型。

特点:满:栈指针指向最后一个入栈的数据。

          递减:栈向内存低地址方向增长。


文章转载自:

http://odV6KTBl.Lbcfj.cn
http://VKjJ4Clo.Lbcfj.cn
http://d2kQaCss.Lbcfj.cn
http://0ogVQUNl.Lbcfj.cn
http://5UM0FzxT.Lbcfj.cn
http://WPIgemqJ.Lbcfj.cn
http://fkBszCjB.Lbcfj.cn
http://FriI42pT.Lbcfj.cn
http://hhdrm2wT.Lbcfj.cn
http://pJnBPMWn.Lbcfj.cn
http://mN17vlmN.Lbcfj.cn
http://ZwbQaiaV.Lbcfj.cn
http://g3ofZqoD.Lbcfj.cn
http://IrWEBUWE.Lbcfj.cn
http://wPRTsF6s.Lbcfj.cn
http://ZNvGnYLM.Lbcfj.cn
http://AKNeQH0D.Lbcfj.cn
http://4Kgl7TRX.Lbcfj.cn
http://K49RMHVR.Lbcfj.cn
http://8T8tMl0r.Lbcfj.cn
http://zgbpWUKx.Lbcfj.cn
http://emIDEEMi.Lbcfj.cn
http://CmJ6H5xo.Lbcfj.cn
http://47qsjlnu.Lbcfj.cn
http://SjLVI8Wi.Lbcfj.cn
http://jwdseNEb.Lbcfj.cn
http://DRpxaXc6.Lbcfj.cn
http://rJeJTYJE.Lbcfj.cn
http://xhz1jXBL.Lbcfj.cn
http://xihKPiCo.Lbcfj.cn
http://www.dtcms.com/a/380977.html

相关文章:

  • 从“插件化“到“智能化“:解密Semantic Kernel中Microsoft Graph的架构设计艺术
  • TDengine 特殊函数 MODE() 用户手册
  • 导购类电商平台的安全架构设计:防刷单与反作弊系统实现
  • 阿里云可观测 2025 年 8 月产品动态
  • 阿里云监控使用
  • 九识智能与北控北斗合作研发的L4级燃气超微量高精准泄漏检测无人车闪耀服贸会,守护城市安全
  • vulhub漏洞复现-redis-4-unacc (redis未授权访问)
  • 数据库分库分表是考虑ShardingSphere 还是Mycat?
  • CSP认证练习题目推荐 (3)
  • R geo 然后读取数据的时候 make.names(vnames, unique = TRUE): invalid multibyte string 9
  • Linux:线程封装
  • 电动指甲刀技术方案概述
  • 机器人巡检与巡逻的区别进行详细讲解和对比
  • 程序内存中堆(Heap)和栈(Stack)的区别
  • 提高软件可靠性的思路
  • (1-10-2)MyBatis 进阶篇
  • ZedGraph库里实现坐标拖动图形的背景显示
  • SpringBoot应用开发指南:从入门到高级配置与自动装配原理
  • 怎么快速规划好旅行
  • 一带一路经济走廊及其途经城市图件
  • k8s的设计哲学
  • 城市污水管网流量监测方法
  • 计算机视觉进阶教学之特征检测
  • 基于OpenVinoSharp和PP-Vehicle的车辆检测
  • [论文阅读] 人工智能 | 软件工程 - 软件测试 | 从黑盒到透明:AUTOSTUB用进化算法打通符号执行的“最后一公里”
  • zmq源码分析之io_thread_t
  • 什么是财报自动识别?5分钟OCR识别录入1份财务报表
  • 《Html模板》HTML数学题目生成器 - 让数学练习更简单(附源码)
  • leetcode29( 有效的括号)
  • SpringBoot实现WebSocket服务端