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

ARM 汇编基础知识

1.为什么学习汇编?

        我们在进行嵌入式 Linux 开发的时候是绝对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一
上电 SP 指针还没初始化, C 环境还没准备好,所以肯定不能运行 C 代码,必须先用汇编语言设置好 C 环境,比如初始化 DDR 、设置 SP 指针等等,当汇编把 C 环境设置好了以后才可以运行 C 代码。
        我们要编写的是 ARM 汇编,编译使用的 GCC 交叉编译器,所以我们的汇编代码要符合 GNU 语法。

 2.GNU 语法

1.语法结构

        GNU 汇编语法适用于所有的架构,并不是 ARM 独享的, GNU 汇编由一系列的语句组成,
每行一条语句,每条语句有三个可选部分:
        
label:instruction @ comment
  • label 即标号,表示地址位置,有些指令前面可能会有标号,这样就可以通过这个标号得到指令的地址,标号也可以用来表示数据地址。注意 label 后面的“:”,任何以“:”结尾的标识 符都会被识别为一个标号。
  • instruction 即指令,也就是汇编指令或伪指令。@符号,表示后面的是注释,就跟 C 语言里面的“/*”和“*/”一样,其实在 GNU 汇编文件中我们也可以使用“/*”和“*/”来注释。
  • comment 就是注释内容。

for example:

add:           @标号
MOVS R0, #0X12 @指令:设置 R0=0X12
        注意!ARM 中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用
小写,但是不能大小写混用

2.section 伪操作

用户可以使用 .section 伪操作来定义一个段,汇编系统预定义了一些段名:
.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。
也可以自己定义段,每个段以段名开始,以下一段名或者文件结尾结束
.section .testsection   @定义一个 testsetcion 段

3.汇编程序入口

        汇编程序的默认入口标号是_start ,不过我们也可以在链接脚本中使用 ENTRY 来指明其它
的入口点,下面的代码就是使用 _start 作为入口标号:
/*.global是伪操作,表示_start是全局标号*/
.global _start   
_start:
ldr r0, =0x12 @r0=0x12

类似C语言,常见的伪操作有:

.byte     定义单字节数据,比如.byte 0x12
.short   定义双字节数据,比如.short 0x1234
.long    定义一个 4 字节数据,比如 .long 0x12345678
.equ     赋值语句,格式为:.equ 变量名,表达式,比如 .equ num, 0x12 ,表示 num=0x12
.align    数据字节对齐,比如: .align 4 表示 4 字节对齐。
.end     表示源文件结束。
.global   定义一个全局符号,格式为: .global symbol ,比如: .global _start

GNU 汇编同样也支持函数,函数格式如下:

函数名 :
        函数体
        返回语句  @GNU 汇编函数返回语句不是必须的

 for example:

/* SVC 中断 */
SVC_Handler:           @函数名ldr r0, =SVC_Handler  @函数体  bx r0                 @返回语句

3.Cortex-A7 常用汇编指令

3.1 处理器内部数据传输指令

常用:MOVMRS MSR 

1.MOV指令

将数据从一个寄存器拷贝到另外一个寄存器,或者将一个立即数传递到寄 存器里面
MOV R0,R1
@将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12
@将立即数 0X12 传递给 R0 寄存器,即 R0=0X12

2.MRS指令

将特殊寄存器 ( CPSR SPSR) 中的数据传递给通用寄存器,要读取特殊寄存器的数据只能使用 MRS 指令!
MRS R0, CPSR @将特殊寄存器 CPSR 里面的数据传递给 R0,即 R0=CPSR

3.MSR指令

MSR 指令和 MRS 刚好相反, MSR 指令用来将普通寄存器的数据传递给特殊寄存器,也就
是写特殊寄存器,写特殊寄存器只能使用 MSR。
MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0

3.2 存储器访问指令

        ARM 不能直接访问存储器,比如 RAM 中的数据, I.MX6UL 中的寄存器就是 RAM 类型 的,我用汇编来配置 I.MX6UL 寄存器的时候需要借助存储器访问指令,一般先将要配置的值写入到 Rx(x=0~12) 寄存器中,然后借助存储器访问指令将 Rx 中的数据写入到 I.MX6UL 寄存器。读取 I.MX6UL 寄存器也是一样的,只是过程相反。
        常用的存储器访问指令有两种:LDR 和 STR。
1.LDR指令
        LDR 主要用于从存储加载数据到寄存器 Rx 中,LDR 也可以将一个立即数加载到寄存器 Rx 中,LDR 加载立即数的时候要使用“ = ”,而不是“ # ”。
        在嵌入式开发中,LDR 最常用的就是读 取 CPU 的寄存器值。
例如:如 I.MX6UL 有个寄存器 GPIO1_GDIR,其地址为 0X0209C004,我们现在要读取这个寄存器中的数据,代码: 
 LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中,offset为0
2.STR指令
        LDR 是从存储器读取数据, STR 就是将数据写入到存储器中,同样以 I.MX6UL 寄存器
GPIO1_GDIR 为例:
 LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中
LDR 和 STR 都是按照进行读取和写入的,也就是操作的 32 位数据,如果要按照字节、 半字进行操作的话可以在指令“LDR ”后面加上 B H ,比如按字节操作的指令就是 LDRB 和 STRB,按半字操作的指令就是 LDRH STRH

3.3压栈和出栈指令

        我们通常会在 A 函数中调用 B 函数,当 B 函数执行完以后再回到 A 函数继续执行。要想
再跳回 A 函数以后代码能够接着正常运行,那就必须在跳到 B 函数之前将当前处理器状态保存
起来 ( 就是保存 R0~R15 这些寄存器值 ) ,当 B 函数执行完成以后再用前面保存的寄存器值恢复
R0~R15 即可。保存 R0~R15 寄存器的操作就叫做现场保护恢复 R0~R15 寄存器的操作就叫做
恢复现场在进行现场保护的时候需要进行压栈 (入栈) 操作,恢复现场就要进行出栈操作压栈
的指令为 PUSH,出栈的指令为 POPPUSH POP 是一种多存储和多加载指令即可以一次
操作多个寄存器数据他们利用当前的栈指针 SP 来生成地址 PUSH POP 的用法如表:

 例如:将R0~R3、R12寄存器压栈操作当前的 SP 指针指向 0X80000000,处理器的堆栈是向下增长的,使用的汇编代码如下:

PUSH {R0~R3, R12} @R0~R3 R12 压栈

压栈完成以后的堆栈如图

 由于32位处理器,每个寄存器为32位,占用4个字节,这里5个寄存器占用20个字节,转换为十六进制是0x14,需要在堆栈上分配连续的地址空间长度为0x14,

        故SP指针的位置变化为:0x800000 - 0x14 = 0x7FFFFFEC

 LR 进行压栈完成以后的堆栈模型如图:

这里使用LR寄存器来存放程序的返回地址,同理, LR寄存器(备份寄存器R14)占4个字节,

SP变化:0x7FFFFFEC-0X04 = 0X7FFFFFE8

接下来作出栈操作:

POP {LR}                @先恢复 LR
POP {R0~R3,R12}  @ 在恢复 R0~R3,R12
 出栈的就是从栈顶,也就是 SP 当前执行的位置开始,地址依次减小来提取堆栈中的数据到要恢复的寄存器列表中。

        PUSH 和 POP 的另外一种写法是“STMFD SP!”和“LDMFD SP!”。STM LDM 就是多存储和多加载,可以连续的读写存储器中的多个连续数据。

3.4跳转指令

有多种跳转操作,比如:
①、直接使用跳转指令 B BL BX 等。
②、直接向 PC 寄存器里面写入数据。

一般常用的还是 BBL 或 BX

如果要在汇编中进行函 数调用使用的就是 B 和 BL 指令

1 B 指令
        这是最简单的跳转指令,B 指令会将 PC 寄存器的值设置为跳转目标地址, 一旦执行 B 指 令,ARM 处理器就会立即跳转到指定的目标地址,如果要调用的函数不会再返回到原来的执行
处,那就可以用 B 指令,例如:
  _start :                        @入口标号
 ldr sp ,= 0X80200000 @ 设置栈指针
 b main                        @跳转到 main 函数  跳转到 C 文件以后再也不会回到汇编了。
2 BL 指令
        BL 指令相比 B 指令,在跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值所以可以 通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行这是子程序调用的一个基本但常用的手段。比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。但是具体的中断处理过程都是 C 函数,所以就会存在汇编中调用 C 函数的问题。而且当 C 语言版本的中断处理函数执行完成以后是需要返回到irq 汇编中断服务函数,因为还要处理其他的工作,一般是恢复现场。这个时候就不能直接使用B 指令了,因为 B 指令一旦跳转就再也不会回来了,这个时候要使用 BL 指令。

3.5算术运算指令

掌握加法运算。

3.6逻辑运算指令

具体案例再补充。

参考:

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》

ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》和《 ARM Cortex-A(armV7) 编程手册 V4.0.pdf

相关文章:

ARM 汇编基础知识

1.为什么学习汇编? 我们在进行嵌入式 Linux 开发的时候是绝对要掌握基本的 ARM 汇编,因为 Cortex-A 芯片一 上电 SP 指针还没初始化, C 环境还没准备好,所以肯定不能运行 C 代码,必须先用汇编语言设置好 C 环境…...

CRM 自动化如何改善销售和客户服务?

许多 B2B 和 B2C 公司都使用 CRM 系统来组织业务流程,使复杂的任务更容易完成。企业可以使用 CRM 自动化来自动化工作流程,让团队有更多的时间来执行高价值的任务,而不是陷于一堆琐碎事情中。 什么是CRM自动化? CRM 自动化是指 C…...

Bean 的六种作用域

目录 一、作用域是什么? 1、singleton(单例作用域) 2、prototype(原型作用域) 3、request(请求作用域) 4、session(回话作用域) 5、application(全局作用域&a…...

go语言--锁

锁的基础,go的锁是构建在原子操作和信号锁之上的 原子锁 原子包实现协程的对同一个数据的操作,可以实现原子操作,只能用于简单变量的简单操作,可以把多个操作变成一个操作 sema锁 也叫信号量锁/信号锁 核心是一个uint32值&#…...

再见,CSDN

从我2018年1月31日加入CSDN,到现在已经5年多的时间了。在这5年里,陆陆续续在CSDN上发布了很多论文阅读笔记、教程、技术文章等等,记录了我从大四到研究生再到工作这段时间的学习和成长轨迹。 我一直有备份个人资料的习惯,尤其是耗…...

MySQL总复习

目录 登录 显示数据库 创建数据库 删除数据库 使用数据库 创建表 添加数据表数据 查询表 添加数据表多条数据 查询表中某数据 增insert 删delete 改update 查select ​ where like ​编辑 范围查找 order by 聚合函数 count max min sum avg g…...

桌面平台层安全随手记录

声明 本文是学习桌面云安全技术要求. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 桌面平台层安全 桌面接入安全 用户标识 一般要求 本项要求包括: a) 系统应为用户提供唯一的身份标识,同时将用户的身份标识与该用户的所…...

【Docker】 08-Dockerfile

什么是Dockerfile Dockerfile可以认为是Docker镜像的描述文件,是由一系列命令和参数构成的教程,主要作用是用来构建docker镜像的构建文件。 Dockerfile解析过程 Dockerfile的保留命令 保留字作用FROM当前镜像是基于哪个镜像的 第一个指令必须是FROMMA…...

【二等奖方案】大规模金融图数据中异常风险行为模式挖掘赛题「Aries」解题思路

第十届CCF大数据与计算智能大赛(2022 CCF BDCI)已圆满结束,大赛官方竞赛平台DataFountain(简称DF平台)正在陆续释出各赛题获奖队伍的方案思路,欢迎广大数据科学家交流讨论。 本方案为【大规模金融图数据中…...

Github 下载指定文件夹(git sparse-checkout)

比如要下载这里的 data_utils 步骤 1、新建空文件夹,并进入新建的空文件夹。 2、git init 初始化 3、git remote add origin 添加远程仓库 4、git config core.sparsecheckout true 允许稀疏检出 5、git sparse-checkout set 设置需要拉取的文件夹(可…...

蚂蚁集团SQLess 开源,与内部版有何区别?

当我们使用关系型数据库时,SQL 是联系起用户和数据库的一座桥梁。 SQL 是一种高度非过程化的语言,当我们在编写SQL 时,表达的是想要什么数据,而不是怎么获取数据。因此,我们往往更关心SQL 有没有满足业务逻辑&#xff…...

An Efficient Memory-Augmented Transformer for Knowledge-Intensive NLP Tasks

本文是LLM系列文章,针对《An Efficient Memory-Augmented Transformer for Knowledge 一种用于知识密集型NLP任务的高效内存增强转换器 摘要1 引言2 相关工作3 高效内存增强Transformer4 EMAT的训练流程5 实验6 分析7 结论局限性 摘要 获取外部知识对于许多自然语言…...

Java项目中jar war pom包的区别

1、pom&#xff1a;用在父级工程或聚合工程中&#xff0c;用来做jar包的版本控制&#xff0c;必须指明这个聚合工程的打包方式为pom。 <project ...> <modelVersion>4.0.0</modelVersion> <groupId>com.wong.tech</groupId> <artifactI…...

整理mongodb文档:分页

个人博客 整理mongodb文档:分页 个人博客&#xff0c;求关注&#xff0c;如果文章不够清晰&#xff0c;麻烦指出。 文章概叙 本文主要讲下在聚合以及crud的find方法中如何使用limit还有skip进行排序。 分页的情况很经常出现&#xff0c;这也是这篇博客诞生的理由。 数据准备…...

社区团购新玩法,生鲜蔬菜配货发货小程序商城

在当前的电商市场中&#xff0c;生鲜市场具有巨大的潜力和发展空间。为了满足消费者的需求&#xff0c;许多生鲜店正在寻找创新的方法来提高销售和客户满意度。其中&#xff0c;制作一个个性且功能强大的生鲜小程序商城是一个非常有效的策略。以下是在乔拓云平台上制作生鲜小程…...

shell bash中设置命令set

1 Preface/Foreword set命令用于shell脚本在执行命令时候&#xff0c;遇到异常的处理机制。 2 Usage 2.1 set -e 当执行命令过程中遇到异常&#xff0c;那么就退出脚本&#xff0c;不会往下执行其它命令。 #!/bin/bash #set -eroot GIT_TAG${CI_BUILD_TAG-NOTAG} GIT_REV…...

机器学习---预剪枝、后剪枝(REP、CCP、PEP、)

1. 为什么要进行剪枝 横轴表示在决策树创建过程中树的结点总数&#xff0c;纵轴表示决策树的预测精度。 实线显示的是决策树 在训练集上的精度&#xff0c;虚线显示的则是在⼀个独⽴的测试集上测量出来的精度。 随着树的增⻓&#xff0c;在 训练样集上的精度是单调上升的&…...

Python 爬虫—scrapy

scrapy用于从网站中提取所需数据的开源协作框架。以一种快速、简单但可扩展的方式。 该爬虫框架适合于那种静态页面&#xff0c; js 加载的话&#xff0c;如果你无法模拟它的 API 请求&#xff0c;可能就需要使用 selenium 这种使用无头浏览器的方式来完成你的需求了 入门 imp…...

ABB机器人20032转数计数器未更新故障报警处理方法

ABB机器人20032转数计数器未更新故障报警处理方法 ABB的机器人上面安装有电池,需要定期进行更换(正常一年换一次),如果长时间不更换,电量过低,就会出现转数计数器未更新的报警,各轴编码器的位置就会丢失,在更换新电池后,需要更新转数计数器。 具体步骤如下: 先用手动…...

C# 记事本应用程序

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System...

零基础入门:REX-UniNLU中文NLP系统保姆级安装与使用指南

零基础入门&#xff1a;REX-UniNLU中文NLP系统保姆级安装与使用指南 1. 为什么选择REX-UniNLU系统 如果你正在寻找一个简单易用但功能强大的中文自然语言处理工具&#xff0c;REX-UniNLU可能是你的理想选择。这个系统最大的特点就是"开箱即用"——不需要复杂的配置…...

OpenClaw健康检查方案:千问3.5-35B-A3B-FP8长期运行维护指南

OpenClaw健康检查方案&#xff1a;千问3.5-35B-A3B-FP8长期运行维护指南 1. 为什么需要健康检查&#xff1f; 去年冬天的一个深夜&#xff0c;我被手机警报惊醒——部署在家庭服务器的OpenClaw千问3.5组合突然停止了响应。检查日志发现是显存泄漏导致进程崩溃&#xff0c;而当…...

50天学习FPGA第41天-PCIe的的介绍及使用

目录 简介 配置过程 简介 XDMA是一种DMA/Bridge Subsystem for PCI Express IP,由Xilinx提供。 XDMA IP核设计使用Xilinx提供的DMASubsystem for PCI Express IP是一个高性能、可配置的适用于PCIE 2.0、PCIE 3.0的SG模式DMA,提供用户可选择的AXI4接口或者AXI4-Stream接口。…...

Sub-Agent 与 Agent Team 的本质区别

用了 Team 模式的 API&#xff0c;就是 Agent Team 了吗&#xff1f;从一个真实项目出发&#xff0c;拆解两种多 Agent 架构的核心差异。引言&#xff1a;名字叫 Team&#xff0c;就真是 Team 吗&#xff1f; 2026 年&#xff0c;AI 编程圈最热的词之一是"多 Agent 协作&q…...

PCIe新手必看:3层体系结构详解(附实战避坑指南)

PCIe三层体系结构深度解析&#xff1a;从原理到实战避坑指南 刚接触PCIe总线的工程师们&#xff0c;常常会被其复杂的协议栈和晦涩的专业术语所困扰。作为现代计算机系统中至关重要的高速串行总线标准&#xff0c;PCIe凭借其分层架构设计&#xff0c;在保证兼容性的同时实现了性…...

OpenClaw数据可视化:千问3.5-9B自动生成分析图表

OpenClaw数据可视化&#xff1a;千问3.5-9B自动生成分析图表 1. 为什么需要AI驱动的数据可视化&#xff1f; 上周我面对一个典型的数据分析困境&#xff1a;手头有3份Excel表格&#xff0c;分别是销售数据、用户行为日志和库存记录。老板要求第二天早晨提交可视化报告&#x…...

OpenClaw+千问3.5-9B自动化写作:技术博客大纲与初稿生成

OpenClaw千问3.5-9B自动化写作&#xff1a;技术博客大纲与初稿生成 1. 为什么需要自动化写作助手 作为一个技术博主&#xff0c;我经常面临这样的困境&#xff1a;明明对某个技术点有深刻理解&#xff0c;却卡在如何组织文章结构上。有时候花在列大纲上的时间比实际写作还长&…...

QQ 第三方登录(Django)

QQ 第三方登录&#xff08;Django&#xff09; 本篇教程完全面向 Django 开发者&#xff0c;从 QQ 互联原理、三端交互流程&#xff0c;到完整代码实现&#xff0c;一步到位&#xff0c;新手可直接复制粘贴跟着操作&#xff0c;避开所有常见踩坑点&#xff0c;兼顾教学和实战需…...

智慧校园系统怎么选?看懂这 5 个核心功能再决定不迟

✅作者简介&#xff1a;合肥自友科技 &#x1f4cc;核心产品&#xff1a;智慧校园系统(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…...

[具身智能-230]:大模型编程的一个最佳实践:先通过自然语言让大模型编写Python语言代码,功能和性能调通后,再让大模型把python程序转换成C++或其他语言的程序

这种“Python 原型验证 C 性能落地”的开发模式&#xff0c;完美契合了大模型&#xff08;LLM&#xff09;的能力特点以及现代软件工程的需求。结合最新的行业实践和技术原理&#xff0c;我为你深度解析为什么这种工作流如此有效&#xff0c;以及在实际操作中需要注意的关键点…...