ARM汇编进阶

发布者:RainbowGarden最新更新时间:2021-03-25 来源: eefocus关键字:ARM  GNU汇编 手机看文章 扫描二维码
随时随地手机看文章

接触嵌入式以来,汇编来来回回学了好几遍,感觉还是有几个地方不清楚,所以在这里做一下总结,基本的非常简单的指令就不多余介绍了,主要分享一些个人觉得虽然微不足道,但是对于理解ARM汇编有帮助的一些知识


在这里一定要说一下,刚开始学的时候步入了一个大坑,我以为我学的是ARM汇编,后来了解到了,原来是GNU汇编,怪不得我有些问题去网上找的时候迷迷糊糊的,直到最近才纠正过来


所以首先就是介绍一下这两种汇编有什么区别


ARM汇编与GNU汇编区别

ARM汇编开发,有两种开发方式,一种是使用ARM汇编,一种是使用ARM GNU汇编。


两种汇编开发,使用的汇编指令是完全一样的。


区别是宏指令,伪指令,伪操作不一样。


有上述区别的原因就是 两种开发方式所使用的编译工具不一样。


在指令表示方面: ARM汇编指令都是大写 GNU汇编指令都是小写


两种常用的ARM的编译开发环境 :


DS5、MDK、keil:ARM提供的集成开发软件。使用的是ARM提供的工具链进行程序编译。


GNU开发环境: 由GNU的汇编器as,交叉编译器gcc,和链接器ld等组成。


因为我们使用的是GNU的交叉编译工具链,所以我们使用GNU汇编。


虽说我们使用GNU汇编,但我开始学错了,记了好多ARM汇编的笔记,在这里也分享出来(主要是不能浪费了),然后会将ARM汇编与GNU汇编的异同列举出来,大家对照着看完的话会有不一样的收获


完整汇编语句(适用于ARM汇编与GNU汇编)

汇编语言局限于硬件平台 以下面不同平台举例(68k为摩托罗拉的一个架构)


# 向一个寄存器中的一个值加100

x86: add eax, #100

68k: ADD #100,d0

ARM: add r0, r0, 100

ARM汇编指令格式


Operation{cond}{s} Rd, Rn, Operand2

# 一条汇编指令可分为6个部分,存在2个可选项

#1. Operation 表示操作指令

#2. {cond} 可选项,表示条件,例如 eq(相等)

#3. {s} 可选项,表示状态,例如 n z 也就是上文提到的CPSR寄存器的标志位

#4. Rd 英文rigister direction 即 目标寄存器

#5. Rn 即 源寄存器

#6. 后续附加操作

接下来将上面的完整的汇编指令引申到32位的二进制指令


所以汇编与二进制指令是一一对应的关系


# 可能有错误,但意思是这么个意思

[7:0]表示 Operand2

[11:8] 表示 Rn

[15:12] 表示 Rd

[19:16] 表示 s

[24:20] 表示 cond

[27:25] 为保留

[31:28] 表示 Operation

汇编入口(只适用于ARM汇编)

# 下面一行表示 名字叫做 (Example) 的 (只读 READONLY) (代码 CODE) (区域 AREA)

AREA Example, CODE, REANONLY

# 下面一行ENTRY 表示入口

ENTYR

# 下面一行 表示32位编码,与16位的Thumb编码对应

CODE32

# 下面一行表示 固有label标号,表示代码在这里开始执行

START 

汇编指令

# 下面一行 表示代码结束

END

状态码status

这里也需要结合上文ARM体系结构提到的CPSR寄存器



status码也紧跟在操作码以后


例如 MOVC 表示 先进位再操作


寻址方式

单寄存器访问

立即数寻址

ADD R0,R0,#0X3F

立即数即代表一个数字, 立即数寻址表示在寄存器与一个数字之间操作

寄存器寻址

ADD R0,R1,R2 只在寄存器之间操作,不涉及内存。

内存靠地址寻找,寄存器靠名字寻找

寄存器间接寻址

ADD与MOV指令只能操作寄存器,不能操作内存。


操作内存使用LDR与STR指令 MOV指令 可以在寄存器之间传输数据,也可以将立即数传输到寄存器


使用如下指令使数据在内存与寄存器之间传递


LDR R0,[R1] 表示将R1对应内存的数据放到R0


STR R0,[R1] 表示将R0里面的数据放到R1对应的内存


c语言中指针的解引用也使用这种方式

寄存器移位寻址

ADD R3,R2,R1,LSL#2 表示R1左移两位加上R2再赋值给R3,LSL表示左移

基址地址寻址

LDR R0,[R1,#4] 表示R1地址加4的地址处的值放到R0

LDR R0,[R1],#4 表示R1地址处的值取出再加4放到R0

LDR R0,[R1,R2] 表示R1加R2对应的内存地址的值放到R0

相对寻址

BL NEXT 表示跳转到NEXT,并且保存跳转前的地址到LR寄存器

相当于计算pc指针的偏移量来进行跳转

多寄存器内存访问

原型: STM LDM


变种:

STMIA xx {xx} 表示将后面连续寄存器地址的值写入前面所指的内存中去

LDMIA xx {xx} 表示读取前面所指内存的值放到后面连续的寄存器中


这里一定要注意单寄存器与多寄存器的存取方向是正好相反的


数据块模式:

A 表示 after 传送前

B 表示 before 传送后

I 表示 increase 自增4字节

D 表示 decrease 递减4字节

IA 表示传送前地址加4

IB 表示传送后地址加4

DA 表示传输前地址减4

DB 表示传输后地址减4


默认情况下:

STM = STMIA

LDM = LDRIA


堆栈模式: 也是多寄存器寻址的方式

但是多寄存器寻址的位置是任意的

ldria sp! {xxx} 表示在堆栈上连续读取多个数据到寄存器

是一种压栈和出栈的实现方式


跳转指令

长指令跳转,直接操作pc寄存器

短指令跳转,使用bl 或者 b 进行跳转


b与bl与bx

b相当于c语言中的goto语句,不回到原来地方


bl相当于将当前地址放入lr寄存器,执行完以后最后一句为mov pc, lr跳回原来的地址继续执行


bx表示带模式跳转,返回原有的模式(例如超级模式)


MRS 与 MSR 记忆方法

这是操作CPSR寄存器的两个命令,具体使用方法不做过多介绍


MRS 表示 Move to Register from Status register英文的其中几个简写


MSR 表示 Move to Status register from Register 英文的其中几个简写


arm汇编伪指令

虽然汇编指令可以实现循环以及跳转等各种工作,但比较繁琐 所以使用带参数宏的方法来实现一些伪指令
伪指令只在汇编器之前作用,汇编之后会翻译成标准的汇编指令集
伪指令分为arm汇编伪指令与GNU汇编伪指令
下面均为 ARM汇编 伪指令
两种伪指令对应关系在后面表格列举出来

.global 是GNU伪指令,表示全局的标签,对外导出

_start 是GNU伪指令,表示起始地址,类似于我们之前提到的ENTYR

指令后缀

ldrb r0, [r1] 指令意思不变,操作数变为一个字节(byte)(8位)

ldrh r0, [r1] 指令意思不变,操作数变为一个半字(half word)16位

ldrs r0, [r1] 指令意思不变,操作数变为有符号数(signed)

movs r0, #0 默认结果为零但不影响CPSR的Z位,加上s以后会影响CPSR标志位

但是以下指令一定会影响标志位

cmp r0, r1 等价于sub r0, r1, 比较结果是否为零,将CPSR中的 Z 标志位置位

cmn r0, r1 等价于add r0, r1 判断两个数是否互补,比较结果是否为零,将CPSR中的 Z 标志位置位

tst r0, #01 等价于 add r0, #01 用于测试某些位是否为1 ,将CPSR中的 Z 标志位置位

teq r0, r1等价于 eor r0, r1 使用异或判断两个寄存器是否相等,将CPSR中的 Z 标志位置位

条件执行后缀

beq 如果条件成立再进行跳转,条件后缀成立取决于之前代码的运行结果。

上一句代码执行结果影响CPSR的标志位

CPSR标志位决定条件后缀是否成立

具体如下表格

GT表示 greater than

LT表示 lower than

E表示 equal

N表示 not

条件码会紧跟在指令的后面,例如 BEQ表示相等再跳转

GNU汇编中 !

! 表示寄存器自增/自减

因为栈是向下增长的。

STMDB SP! {R0-R3} 表示传输完一个数据以后,SP指针也会自减,相当于 PUSH {R0-R3}

同理 LDMIA SP! {R0-R3} 相当于 POP {R0-R3}

加上感叹号以后相当于sp的值会进行实时更新,不然只是一个临时变量在自加,不会改变sp指针的值。

换句话说,加上感叹号代表sp实时指向栈顶,但是不加的话,数据虽然保存到栈里,但指针还是指向原来的位置。

pc指针

由于三级流水线的关系

pc指向正在被取指的指令

真正被执行的指令为pc - 8

arm伪指令与GNU伪指令的区别


swi

软中断指令,软件模拟中断用来实现操作系统中的系统调用

中断向量表有一个软中断入口 编写操作系统的人才会用到,普通驱动开发基本用不到


mcr 与 mrc 记忆方法

协处理器操作指令

mrc 是 move to register from cp15 从cp15读取数据

mcr 是 move to cp15 from register 向cp15写入数据

这样记忆起来就特别容易,不至于弄乱顺序

协处理器

coperation processor或者写成 coprocessor

  • soC内部另一个处理核心(不需要CPU参与),协助CPU完成某些功能

  • ARM设计上可以支持16个协处理器,但是我们常用的一般soC只实现其中的cp15(只实现了这一个)

  • 协处理器和MMU、cache、TLB(这三个概念可以查看之前的文章-ARM体系架构)等处理有关

伪指令

伪指令编译以后不生成机器码


伪指令与编译器有关,因为我们使用的是GNU工具链,所以我们使用GNU伪指令


符号:


@用在行后注释


以 : 结尾的是标号


.点号在GNU汇编中表示当前指令地址


# 下面表示一个死循环

flag:

b flag

# 下面也表示一个死循环

b .

立即数之前要加上#


GNU汇编伪指令


# 声明 _start为外部链接属性

.global _start

# 指定当前段为代码段

.section .text

# 数据类型

.ascii 定义字符

.byte 定义字节

.short 定义两个字节类型数据,相当于c语言中的unsigned short

.word 定义四个字节类型数据 相当于c语言中的unsigned int

.quad 定义八个字节类型数据 

.float 定义四个字节类型的数据 相当于c语言中的float

# 以 2的n次方 进行字节对齐

.align n

下面表示定义一个unsigned int 类型变量 变量名为 a 变量值为123


a:

.word 123

ldr指令 与 ldr伪指令

ldr指令需要考虑合法立即数与非法立即数 ldr伪指令不需要考虑立即数是否合法


ARM指令只有32位,包括指令标记等,所以32位不能全部用来放数字


所以就有了合法立即数与非法立即数的区别


经过任意位数移位后非零部分可以用8位表示的称为合法立即数


但我们使用的ldr 伪指令,他会自动判断是合法还是非法立即数,如果非法,它会自动转成合法立即数


伪指令与指令的区别在于立即数之前是=还是#


为 = 表示ldr伪指令


为 # 表示ldr指令


所以 99% 的情况下都会使用伪指令


寄存器改名

汇编语言的时候直接写这些寄存器的名字就可以


但是芯片厂商也可以自己改变寄存器的名字


方便厂商更加方便的定制


cotex A 系列引入的机制


四种栈

  1. 空栈表示栈顶指针指向最后一个数据的下一个内存位置,相当于栈顶指针指向一个空元素


  1. 满栈表示栈顶指针指向栈顶的最后一个数据,相当于指向一个元素


  1. 增栈 表示栈的增长是向内存地址高的位置进行增长


  1. 减栈 表示栈的增长是向内存低的位置进行增长


ARM体系结构正常情况下都是满减栈

c/c++程序中嵌入汇编

格式: __asm [volatile] {instruction} 限制条件:

  • 不能直接向pc赋值,程序跳转使用b或者bl指令

  • 在使用物理寄存器的时候,不能使用过于复杂的c表达式,比买你屋里寄存器中途

  • 尽量使用R0-R7通用寄存器

C语言调用汇编(不常用)

  1. 汇编export

  2. c语言定义 extern function

  3. c语言使用

c语言和汇编语言之间传递参数是通过对应的R0-R3来传递的,即R0第一个参数,以此类推,多于4个参数是借助栈完成,函数返回值通过R0来传递,这个规定叫做ATPCS(ARM Thumb Procedure Call Standard),具体见ATPCS规范

汇编调用c语言

  1. c语言实现函数

  2. 汇编import导入函数名

  3. bl 函数名


关键字:ARM  GNU汇编 引用地址:ARM汇编进阶

上一篇:一文看懂arm架构和x86架构有什么区别
下一篇:ARM汇编语言 - 简介 [一]

推荐阅读最新更新时间:2024-11-02 16:39

使用J-Link ARM烧录FLASH
//===================================================================== //TITLE: // 使用J-Link ARM烧录FLASH //AUTHOR: // norains //DATE: // February 21-September-2010 //Environment: // J-Link ARM //===================================================================== 如果大家使用的是MDK开发环境的话,并且选择调试的工具是J-Link,那么当我们点击deb
[单片机]
使用J-Link <font color='red'>ARM</font>烧录FLASH
专题1-MMU-lesson1-MMU功能解析
1、Memory Management Unit(存储器管理单元) 单片机与ARM在硬件体系上的一些区别:其中就有MMU的区别。 虚拟地址的使用 把p1.c复制成P2.c,把变量a改成b,再进行编译看看情况如何 可以看出两个程序在同样地址读出不同的值,在这里就用到了MMU。 在这里程序当中的地址都是虚拟地址;
[单片机]
专题1-MMU-lesson1-MMU功能解析
赛灵思发布行业第一款可扩展处理平台
——Zynq系列挺入百亿嵌入式应用 拥有26年创新历史的全球可编程平台领导厂商赛灵思 (Xilinx)公司, 日前通过一款名为Zynq的新产品品牌及系列,再次用创新为FPGA赋予了新的定义。。 ZYNQ系列实际上是一款集双ARM Cortex-A9与赛灵思 28nm FPGA为一体的高性能处理器。它的推出不仅意味着处理器发展史上第一款可扩展处理平台的出现, 而且也意味着赛灵思从一个FPGA厂商进入了广阔的嵌入式应用领域。 实际上, 早在2010年4月赛灵思就宣布了ARM合作共同开发可扩展处理平台, 此次发布时真正意义上新产品新品牌的推出和相关技术细节的发布。(关于产品详细介绍,请参考: http:/
[嵌入式]
基于ARM和CDMA的远程视频监控系统
0 引言 CDMA(码分多址)网络具有覆盖面广,高效、低成本的特点,CDMA网络的数据传输速率可达200kb/s,这里开发的嵌入式远程视频系统就是充分利用CDMA网络技术和嵌入式系统的特点而搭建的数据传输系统,特别适合边远偏僻或不具备常规网络传输条件的地方使用,例如车载视频系统、交通路口(车牌实时监视)及城市路灯的等。 1 嵌入式Linux系统 嵌入式系统是以应用为中心、以计算机技术为基础、软件硬件可裁剪、适应对功能、可靠性、成本、体积、功耗要求严格的专用计算机系统,目前嵌入式系统已经无处不在,从汽车、家用微波炉、PDA(个人数字助理)、电视机、到工控生产现场、通信、仪器、仪表、汽车、船舶、航空、航天、军事装
[单片机]
ARM 底层开发工具
现在的ARM基本上都比较强大,从ARM9开始就可以直接上操作系统,如Linux和WINCE。但某些情况下,会裸奔,即不用操作系统,把ARM当做超级MCU用。 要吧ARM当超级MCU用,需要如下开发工具: ADS:不支持ARM11,最高只支持ARM9,现在已淘汰。 Keil MDK-ARM:同RealView MDK是同一个东西。以前的版本,内核用的是Keil的,对ARM的支持不如ARM自家的ADS好,现在已经被ARM公司收购。ARM收购Keil后,编译器改用自家的Real View,成为RealView MDK。 RealView MDK:RealView Microcontroller Develop K
[单片机]
基于ARM+DSP的智能网络视频监控终端设计
  1 引言   随着电子、计算机技术的发展, 视频监控 系统正从模拟技术向数字技术方向发展。从硬件形式上看, 视频监控 技术的发展经历了三个阶段:模拟视频信号监控、PC机加视频卡的数字 视频监控 和基于嵌入式技术的数字视频监控 。基于PC机技术的监控系统采用在普通PC机中插接视频采集卡的集成方式,由视频卡完成图像采集、数字化和数据压缩,PC机通过网卡和通信设备实现互连。这一类系统目前已经占据市场主流。随着嵌入式芯片技术和嵌入式操作系统的发展与成熟,基于嵌入式体系结构的视频监控系统由于具备体积小、性能稳定、安装方便等优越性能,越来越受到人们的关注 。对于嵌入式视频监控系统的研究,国外起步早,已有产品性能较好,但价格昂贵,国内用户
[嵌入式]
基于<font color='red'>ARM</font>+DSP的智能网络视频监控终端设计
ARM或在上网本市场威胁英特尔
10月14日消息,据国外媒体报道,位于英国的ARM及其芯片和设备厂商将对英特尔构成越来越大的威胁。也许ARM的威胁会超过英特尔传统的竞争对手AMD。    两位分析师最新发表的声明称,生产基于ARM设计的芯片的阵营将决定移动计算未来的竞争。这些厂商包括高通、德州仪器、三星电子和将来的苹果。    据位于宾夕法尼亚州新的黎波里(New Tripoli)的研究公司Information Network(信息网络)上个月末称,ARM处理器,而不是英特尔的Atom处理器,将在2012年占有上网本市场55%的份额。上网本是售价在400美元以下的超轻型小型笔记本电脑。    EE Times本周一引述ABN AMRO Bank N
[手机便携]
ARM Linux外部中断处理过程
ARM Linux外部中断处理过程 最近在学习arm linux的整套外部中断的处理过程,在网上汇总了一些资料,整个过程差不多都了解到了。如果没有这些资料我真是没信心从汇编开始读代码,感谢 奔腾年代的jimmy.lee和 linux论坛的bx_bird。 在下面的的注释中有一些我读代码时遇到的问题,要是大家知道是怎么回事,希望多多回复。 ============================================= 一.ARM linux的中断向量表初始化分析 ARM linux内核启动时,通过start_kernel()- trap_init()的调用关系,初始化内核的中断异常向量表. /* arch/ar
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved