arm底层汇编

目录

  • 前言

    • arm发展简介
    • 32位 ARMv7
  • 汇编指令
    • 中断向量表
  • 解惑
  • armv8 64位

前言

在学习和工作中,遇到关于嵌入式程序运行的困惑,通过底层汇编,可以知道arm怎么做到保护现场、linux怎么做到安全运行和系统调用等。

arm发展简介

arm发展历程

指令集的设计是处理器结构中最重要的一个部分,用ARM的术语称之为ISA(Instruction Set Architecture)。根据不同的指令集进行区分,ARM11芯片之后,也就是从ARMv7架构开始,ARM的命名方式有所改变。新的处理器家族,改以Cortex命名,并分为三个系列,分别是Cortex-A,Cortex-R,Cortex-M。(A、R、M),比较熟悉,stm32F4是cortex-M4,imx6ull是cortex-A7。2011 年 10 月,arm公司推出armv8架构,从之前32位到64位,支持64位指令集,在内存、虚拟化和安全有了一定的提升。2021年,arm已经推出armv9。

一、32位 ARMv7

以cortex-M为例

ARM主要有7种基本工作模式,USER、FIQ、IRQ、Supervisor、Abort、Undef和System。如果cortex-A会多出2种,安全监控模式(mon):可在安全模式和非安全模式下转换;HYP虚拟化模式。

CPU的模式可以简单的理解为当前CPU的工作状态

arm寄存器示意图

1、bank寄存器

带有三角,表示bank 寄存器,该模式下独有的寄存器,没有带三角,表示各个模式共用这部分寄存器。

什么是寄存器?

存放数据的地方,cpu内部访问,读取速度最快。

2、特殊寄存器

r15 PC程序计数器(Program Counter),存储下一条要执行的指令的地址

r14 LR 连接寄存器(Link Register ),保存函数返回地址,当通过BL或BLX指令调用函数时,硬件自动将函数返回地址保存在R14寄存器中。当函数完成时,将LR值传到PC,即可返回到被调用位置。

r13 SP 堆栈指针(Process Stack Pointer),保护现场和恢复现场要用,当发生异常的时候,硬件会把当前状态(使用到寄存器数值)保存在堆栈中,SP保存这个堆栈指针,异常处理完成,通过SP出栈,恢复到异常前的状态。

CPSR程序状态寄存器(current program status register),CPSR和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义.而CPSR寄存器是按位起作用的,也就是说,它的每一位都有专门的含义。

CPSR位域寄存器

二、汇编指令

思考下C语言编译流程,预处理(preprocessing),对头文件和宏展开→编译(compilation),将展开后的程序转成汇编代码→汇编,将汇编代码转成零一二进制机器码,目标文件;链接,将多个目标文件链接成可执行的文件。

现在我们介绍汇编程序,汇编程序相比C语言,有执行效率高的特点,但是可读性差。汇编程序编译开始流程差不多是C语言汇编步骤的开始,此编译非彼编译。汇编语言,包括两种指令,一种是汇编指令,一种是伪指令。汇编指令有对应的机器码,伪指令并没有对应的机器码,最终不会被CPU执行,而是会被编译器所执行。

1、基础指令

;将立即数3 放在r13   注意:mov指令只能用于通用的寄存器
mov   r13,#3
;cpsr是特殊寄存器
mrs   r0,cpsr
msr   cpsr,r0;相与
and   r0,r0,#0xFFFFFFE0
;相或
orr   r0,r0,#0x10;逻辑左移
mov   r0,r1,LSL#2
mov   r0,r1,LSR#2;比较指令
cmp   r0,#0
;相等 r1 = 0
moveq r1,#0
;大于 r1 = r1 + 3
addgt r1,r1,#3;跳转到标号为main地代码处 (只能短跳转32M)
b    main
;跳转函数func,并保存下一条要执行的指令的位置到 lr寄存器, 当跳转代码结束后,用mov pc,lr指令跳回来
bl   func
;相等(指CPSR寄存器中的Z条件码置位时)时,跳转到地址addr处
beq  addr
;不等时,跳转到地址addr
bne  addr     bic    r0,r0,#0x0B    ;清除r0中的位 0、1、和 3
tst    r0,#0x20       ;测试第6位是否为0 ,为0则Z标志置1
cmp    r1,r0          ;将寄存器R1的值与寄存器R0的值相减,;并根据结果设置CPSR的标志位

2、armv7汇编demo

  .textb   main  nopnopnopnopnopnopnop
main: ldr  r0,=bufldr r1,[r0]mov r2,#5str r2,[r0]str r2,[r0,#8]
main_end:b  main_end

对应的机器码:

keil debug

数据不合法

;立即数不合法  因为机器码中只有低12位是存储数据位 借助伪指令,编译器进行编译
mov r3,#0x1101
;使用伪指令
ldr r3,=0x1101
;但是这条指令却是合法的
mov r3,#0x1100000;立即数合法性判断:循环移动到低8位能放下,并且移动次数是偶数次。
;使用伪指令可以避免,立即数合法判断。

机器码:

反汇编示意图

立即数合法性判断:循环移动到低8位能放下,并且移动次数是偶数次,0x1100000是0x11相左移动6次。

3、存储器之间不能直接拷贝,必须通过寄存器中转

ldr r0,[r7] ;4字节载入
ldrb r0,[r7] ;1字节载入
ldrh r0,[r7] ;2字节载入
ldr r0,[r7,#8] ;r7加上8后,载入对应地址的内容
ldr pc,_irq ;将标号中的内容载入,机器码
ldr pc,=irq  ;将标号地址载入str r0,[r3]
str r0,[r3,#4]
str r0,[r3],#4

伪指令

.section               //定义内存段
.text                  //将定义符开始的代码编译到代码段
.data                  //数据段
.if  .else  .endif     //条件编译
.end                   //文件结束.byte   0x11, ’a’,0    //定义char型数组(.byte 对应1字节)
.word  0x12, 0x445566  //定义int型数组(. word 对应4字节)
.quad  0x3FA0          //分配8字节的空间(.quad 对应8字节)
.string  “abcd\0”      //定义字符串
.align   4             //2^4 =16 字节对齐ldr r0, =0xE0028008   //载入大常数0xE0028008 到r0中
.equ  GPG3CON, 0XE03001C0     //定义宏
.global  _start         //声明_start 为全局符号

堆栈操作

 stmfd sp!,{r0-r12,lr}
//将寄存器r0~r12 lr中的值存入栈中   常用于中断保护现场,! 表示会自动偏移                                       ldmfd sp!,{r0-r12,pc}^
//将栈中值逐个弹出到寄存器r0~r12 pc中  常用于中恢复断现场,^表示会恢复spsr到cpsr

三、中断向量表

指示中断服务程序的入口位置,中断向量的顺序是固化,不可改变。(是顺序,不是地址,起始地址可以变,偏移地址)

arm异常处理地址

当发生中断或者异常时,arm会自动跳到对应中断入口,由硬件完成。

以stm32启动文件为例,startup_stm32f10x.md.S

...
; Vector Table Mapped to Address 0 at ResetAREA    RESET, DATA, READONLY ;只读数据段EXPORT  __VectorsEXPORT  __Vectors_EndEXPORT  __Vectors_Size
;DCD 连续 一段连续空间 外部中断发生时,把要处理的动作放在EXTI0_IRQHandler中断服务函数
__Vectors       DCD     __initial_sp               ; Top of StackDCD     Reset_Handler              ; Reset HandlerDCD     NMI_Handler                ; NMI HandlerDCD     HardFault_Handler          ; Hard Fault HandlerDCD     MemManage_Handler          ; MPU Fault HandlerDCD     BusFault_Handler           ; Bus Fault HandlerDCD     UsageFault_Handler         ; Usage Fault HandlerDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     0                          ; ReservedDCD     SVC_Handler                ; SVCall HandlerDCD     DebugMon_Handler           ; Debug Monitor HandlerDCD     0                          ; ReservedDCD     PendSV_Handler             ; PendSV HandlerDCD     SysTick_Handler            ; SysTick Handler; External InterruptsDCD     WWDG_IRQHandler            ; Window WatchdogDCD     PVD_IRQHandler             ; PVD through EXTI Line detectDCD     TAMPER_IRQHandler          ; TamperDCD     RTC_IRQHandler             ; RTCDCD     FLASH_IRQHandler           ; FlashDCD     RCC_IRQHandler             ; RCCDCD     EXTI0_IRQHandler           ; EXTI Line 0DCD     EXTI1_IRQHandler           ; EXTI Line 1......
  .text;---------vector tableb   main    ;0x00 resetnop         ;0x04 undef         ldr pc,_sirq_hander  ;0x08 soft irqnop         ;0x0c prefecth abortnop         ;0x10 data abortnop         ;0x14 reservednop         ;0x18 irqnop         ;0x1C fiq
_sirq_hander:.word  sirq_hander;----handler vector table
sirq_hander:stmfd sp!,{r0-r12,lr} ; 入栈 保护现场ldr r0,[lr,#-4]       ; 获取到软件中断 号 是1还是2bic r0,#0xff000000cmp r0,#1   addeq  r2,#1cmp r0,#2subeq  r2,#1sirq_hander_end:ldmfd sp!,{r0-r12,pc}  ;出栈  恢复现场;----------app----
main: ldr sp,=stack_buf  ;保存栈地址mov r1,#1mov r2,#2swi 0x1             ;软中断 让linux陷入内核 中断号1cmp r2,#2moveq r4,#4movne r4,#6swi 0x2            ;中断号2mov r0,#3
main_end:b  main_end.data.space 15*4     ;数据段
stack_buf:          ;因为栈是向下增长,递减,这里要注意。.end

四、解惑

1、linux 上层最终怎么进入内核层?

通过系统调用,即swi指令软中断,进入异常,改变arm权限,获取访问硬件的权限。

2、中断怎么做到现场保护和恢复现场?

在进入中断,一般是user模式切换到异常模式(应用层到内核层),因为中断需要用到cpu的寄存器(有共用寄存器),为了不破坏原有的工作环境,会对前一个模式进行现场保护,会对各个寄存器值和代码段地址保存到栈中,记录栈指针到SP。当中断完成后,通过SP堆栈指针,出栈,恢复现场,恢复成之前的环境。

3、当man函数中,调用外部函数时,外部函数执行完,怎么返回到main函数继续执行后面代码?

LR寄存器保存函数返回地址。mov PC,LR。

4、快速中断为什么会比一般中断响应快?

1.FIQ的处理优先级比IRQ更高,甚至可以打断正在执行的IRQ;
2.FIQ模式有自己独有的寄存器,而IRQ需要和其他模式共用寄存器(共用寄存器多),在中断处理的保护/恢复现场会更快;
3.在异常向量表中,FIQ处在最末尾。在异常向量表中IRQ只能保存中断处理程序的首地址,在发生IRQ时需要一次跳转;而FIQ处在最末尾,所以可以直接将FIQ模式下的中断处理程序紧接着存放,这样在处理FIQ时就少一次跳转。

5、对于c语言 i = 1,在用汇编怎么实现的?

把1放在寄存器0中,将i地址载入到寄存器1中,最后将寄存器0数据存入到i地址。C语言一条语句可能对应多个汇编指令。这里可以联想为什么会有系统中会有锁和原子的机制,在上层一条语句其实对应底层多条指令,特别是对多线程而言,竞争访问同一资源的情况。

mov r0,#1
ldr r1,=i
str r0,[r1]

arm官网

armv8 64位

armv8相对armv7增加哪些?以下是arm社区回答

对比图

在内存、虚拟化和安全有了一定的提升,执行状态可在AArch64和AArch32来回切换,兼容之前32位arm指令集。

AArch64中,已经没有User、SVC、ABT等处理器模式的概念,但ARMv8需要向前兼容,在AArch32中,就把这些处理器模式映射到了4个Exception level。

异常类型:SError 系统错误,FIQ 快速中断,IRQ一般中断和Synchronous同步异常。

异常级别有,EL0、EL1和EL2和EL3,

armv8异常示例图

每个异常等级都有自己的异常向量表。异常向量表中的每一项都会保存有异常处理的跳转函数,然后跳转过去处理异常。每个向量表基虚拟地址是由矢量基址寄存器设置的,例如VBAR_EL3,VBAR_EL2和VBAR_EL1。

每个表有16个条目,每个条目的大小为128字节(32条指令)。ARMv8的向量表如下图所示,可以看到每一种异常都有固定的偏移地址。

SVC指令可以用来从EL0的用户应用程序调用到EL1的内核。HVC和SMC系统调用指令以类似的方式将处理器移动到EL2和EL3。当处理器在EL0(应用程序)执行时,它不能直接调用管理程序(EL2)或安全监视器(EL3)。

2、armv8基础汇编指令

b.ne    label    //不等时跳转
cbz  w10, 1f   //w10值等于0的适合,跳转导1f
ret              //子程序返回指令,返回地址默认保存在LR(X30),代替了mov pc,lrldr   x0,=__main  //大范围的地址读取:把标号__main(地址)读入x0
adr     x0,vector    //小范围的地址读取:把标号vector(地址)读入x0,标号距当前指令PC的偏移小于1M
stp  x29, x30, [sp, #-16]!   //入栈:把x29, x30 存储到sp-16指向的空间后,sp自减16 (因寄存器是8字节,栈是向下生长故是 -16)                              //类似前索引: *(sp-16) = x29,x30   sp=sp-16 (!使得sp能自更新)  把 x29,x30看成整体              //stp只支持2个寄存器,代替了复杂的stmfd  (64位汇编,取消了批量操作指令)
ldp   x29, x30, [sp],#16   //出栈: 把sp指向的空间内容载入到x29, x30后,sp加16//类似后索引: x29,x30=*sp  sp=sp+16   mrs  x0, sctlr_el1   //读sctlr_el1内容到x0  (注:系统寄存器,都通过mrs msr来操作)
msr    sctlr_el1, x0   //写x0内容到 sctlr_el1
svc     #2      //系统调用指令(触发一个同步异常,cpu则会陷入EL1).global  _start     //声明_start 为全局符号(让链接脚本能看到)
.quad  0x3FA0       //在存储器中分配8个字节,初值设为0x3FA0
.align  4           //2^4 =16 字节对齐
.macro  myAdd, x,y  //宏函数, 类似 myAdd(x, y) add \x,\x,\y
.endm
myAdd  x0,x2b.ne   lable   //不等时跳转到标号
cbz  w10, 1f   //w10值等于0的适合,跳转导1f
ret              //子程序返回指令,返回地址默认保存在LR(X30),代替了mov pc,lr  .macro  myAdd, x,y      //宏函数, 类似 myAdd(x, y) add   \x,\x,\y
.endm
myAdd  x0,x2  

3、armv8中断向量表示例

.globl  _start
_start:mrs   x1,SPSelmrs   x2,CurrentELmov   x0,#0msr   SPSel,x0mov   x0, #0x5adr   x0,vectorsmsr   vbar_el1,x0svc   #0x02  //系统调用 ,
reset_end:b  reset_enddo_bad_sync:mov   x2,#1b    reset_enddo_bad_irq:mov   x2,#2b    reset_end.align  11  //2^11=2048  整个异常向量表 2K对齐  -> 通过对齐,实现向量表空间的预留//16个异常 ,每个异常32条指令    16*32*4=2048 //16个异常,这里使用前8个
vectors://===============sp0===============//---同步异常.align  7  //2^7     1000 0000 =0x80   字节对齐mov  x0,#1b    do_bad_sync//---irq异常.align  7  //2^7     1000 0000 =0x80mov  x0,#1b    do_bad_irq//---fiq异常.align  7  mov  x0,#1b    reset_end//---SError异常.align  7  mov  x0,#1b    reset_end//===============sp_elx===============//---同步异常.align  7  //2^7     1000 0000 =0x80   字节对齐mov  x0,#1b    do_bad_sync//---irq异常.align  7  //2^7     1000 0000 =0x80mov  x0,#1b    do_bad_irq//---fiq异常.align  7  mov  x0,#1b    reset_end//---SError异常.align  7  mov  x0,#1b    reset_end

如果有帮助,可以关注 小昭debug,有学习资料等你拿。

arm底层奠定基础 (汇编)相关推荐

  1. 操作系统内核Hack:(二)底层编程基础

    操作系统内核Hack:(二)底层编程基础 在<操作系统内核Hack:(一)实验环境搭建>中,我们看到了一个迷你操作系统引导程序.尽管只有不到二十行,然而要完全看懂还是需要不少底层软硬件知识 ...

  2. 汇编语言基础--汇编操作指令概述

    本文是接续"汇编语言基础--机器级数据存储",主要介绍汇编指令的构造.寻址和指令主要分类. 操作指令 指令的基本要素:       在"计算机处理器(CPU)基础&quo ...

  3. 15 计算机底层——二进制到汇编学习

    计算机底层--二进制到汇编学习 1.概述 语言 机制 进制如何计算 二进制 数据宽度 有符号和无符号数 原码和反码 位运算 位运算计算 汇编 寄存器 内存 汇编指令 内存复制 堆栈的指令 汇编如何写函 ...

  4. Java(计算机底层——二进制到汇编)(先导课)

    Java(计算机底层--二进制到汇编)(先导课) 参考视频:最通俗易懂的计算机底层教学,二进制到汇编学习!(狂神) 1. 概述 语言 进制 进制如何运算 二进制 数据宽度 有符号数和无符号数 原码反码 ...

  5. ARM 指令集的基础指令

    ARM 和汇编语言基础 ARM 基础 位.字节.字是计算机数据存储的单位. 位是最小的存储单位,每一个位存储一个1位的二进制码,一个字节由8位组成. 而字通常为16.32或64个位组成.ARM 处理器 ...

  6. 清华校友斩获ACM博士论文奖!相关研究为自动驾驶新算法奠定基础

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 明敏 萧箫 发自 凹非寺 量子位 报道 | 公众号 QbitAI 今 ...

  7. 【Brain】复旦类脑研究院:破解大脑奥秘,为实现人工智能自我思考奠定基础...

    文章来源:新民晚报 图说:复旦类脑研究院 采访对象供图 理解大脑的结构与功能是21世纪最具挑战性的前沿科学问题,谁揭开大脑运作的神秘面纱,谁就在重大脑疾病防治和全球智能产业革命中抢占了先机.利用磁共振 ...

  8. Zilliqa联合创始人:ZIP-12提案已成功部署,为未来的治理投票奠定基础

    Zilliqa联合创始人表示,关于治理的ZIP-12提案在治理投票成功后已成功部署,为未来的治理投票奠定基础. 文章链接:https://www.tuoluocaijing.cn/kuaixun/de ...

  9. 埃及通信和信息技术部使用 OpenText ECM 内容服务平台为电子政务转型奠定基础

    埃及通信和信息技术部为电子政务转型奠定基础 IT 专家通过使用 OpenText™ Extended ECM 平台提供的安全.可扩展和面向未来的数字工作流程替代纸质流程,为服务创新做准备. 名称:埃及 ...

最新文章

  1. 番外:Spring MVC环境搭建和Mybatis配置避坑篇
  2. Redis的安装及使用
  3. composer php 使用方法,Composer的基本使用方法
  4. 【阿里云课程】卷积神经网络:结构单元、卷积层反向传播求解与典型模型
  5. POJ 3660 Cow Contest(传递闭包floyed算法)
  6. LeetCode——Find Minimum in Rotated Sorted Array II
  7. 学完Java后可从事的十大领域!
  8. 数据采集无线网服务器软件,WIFI智能数据盒
  9. oracle+erp+采购管理操作手册 - 图文 - 百度文库
  10. matlab的persistent,MATLAB局部静态变量类型persistent
  11. android点击按钮打开蓝牙,Android打开蓝牙的两种方式
  12. 关于美团、饿了么外卖优惠券公众号的设计思路
  13. 微信小程序 | canvas为你的天气预报添加雨雪效果
  14. mSystem:鸟枪法宏基因组测序之外我们还能做什么
  15. matlab做胶州湾地图,惊了,青岛也有了五环地图,快来看你家在几环?
  16. 利用用户行为数据——基于Spark平台的协同过滤实时电影推荐系统项目系列博客(二)
  17. 【Flask】篇一:Error: Failed to find Flask application or factory in module “学习用“. Use “FLASK_APP=学习用:nam
  18. 测量中的坐标与时间系统1.3(在大地测量学中)
  19. 2021-2027全球及中国散射光粉尘测量仪行业研究及十四五规划分析报告
  20. 国庆临近,字节后端开发3+4面,终于拿到秋招第一个offer

热门文章

  1. Android自定义圆角圆形图片
  2. 干货丨什么是Java三元运算符?基本用法有哪些?
  3. linux如何使history命令可以显示更多信息
  4. 幽门螺杆菌检测方法学习笔记
  5. 家居家具产品促销视频AE幻灯片模板 Furniture Slideshow
  6. CUDA编程时遇到无法解析外部符号threadIdx或blockIdx问题的解决办法
  7. 经典:偶和偶mm(完全版之下)
  8. java毕业设计大学生个人博客网站Mybatis+系统+数据库+调试部署
  9. 【记录一次硬盘修复过程】
  10. 如何使用Java在Word中插入表格