【FreeRTOS】ARM架构汇编实例

学习视频
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=9&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933

ARM架构简明教程

1. ARM架构

电脑的组成

电脑的组成

对于单片机,叫SoC system on chip,在芯片上有完整的系统

芯片集成了CPU 内存 硬盘(flash)

内存:读出数据,写入数据

计算都是在CPU内完成的

1.2 RISC

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

① 对内存只有读、写指令
② 对于数据的运算是在CPU内部实现
③ 使用RISC指令的CPU复杂度小一点,易于设计

在这里插入图片描述

对于上图所示的乘法运算a = a * b,在RISC中要使用4条汇编指令:

① 读内存a
② 读内存b
③ 计算a*b
④ 把结果写入内存

1.2 提出问题

问题:在CPU内部,用什么来保存a、b、a*b ?

回答:寄存器 R0、R1、R2……

1.3 CPU内部寄存器

在这里插入图片描述

无论是cortex-M3/M4,

还是cortex-A7,

CPU内部都有R0、R1、……、R15寄存器;

它们可以用来“暂存”数据。

在这里插入图片描述

对于R13、R14、R15,还另有用途:

R13:别名SP(Stack Pointer),栈指针

R14:别名LR(Link Register),用来保存返回地址

R15:别名PC(Program Counter),程序计数器,表示当前指令地址,写入新值即可跳转

1.4 汇编指令

  • 读内存:Load

    # 示例
    LDR  R0, [R1, #4]  ; 读地址"R1+4", 得到的4字节数据存入R0
    

Load R 读 四个字节,读R1+4的地址,读入的数据保存到R0里
其他指令:LDRB\LDRH
LDRB 读取一个字节 1Byte,LDRH 读取Half,2Bytes

  • 写内存:Stroe

    # 示例
    STR  R0, [R1, #4]  ; 把R0的4字节数据写入地址"R1+4"
    

写内存 4个字节STR 把R0的4字节数据写到R1+4
写其他字节数
STRB 1byte
STRH half - 2bytes

读写指令经常用到,一定要掌握这两条指令

  • 加减

    ADD R0, R1, R2  ; R0=R1+R2
    ADD R0, R0, #1  ; R0=R0+1
    SUB R0, R1, R2  ; R0=R1-R2
    SUB R0, R0, #1  ; R0=R0-1
    
  • 比较

    CMP R0, R1  ; 结果保存在PSR(程序状态寄存器)
    

结果保存到程序状态寄存器里

  • 跳转

    B  main  ; Branch, 直接跳转
    BL main  ; Branch and Link, 先把返回地址保存在LR寄存器里再跳转
    

跳转
B main; PC/R15=main的地址

BL main; 分为两个步骤
LR/R14=返回地址
PC/R15=main的地址

2. C函数的反汇编

C函数:

int add(volatile int a, volatile int b)
{
	volatile int sum;
    sum = a + b;
    return sum;
}

这段代码里用volatile int a,不要让编译器优化我们的程序

把这个函数复制,随便我们工程的放到一个地方

修改如下部分
在这里插入图片描述

void OLED_Test(void)
{
    int OLED_Count = 0;
    OLED_Init();
    // 清屏
    OLED_Clear();

    while (1)
    {
        // 在(0, 0)打印'A'
        OLED_PutChar(0, 0, 'A');
        // 在(1, 0)打印'Y'
        OLED_PutChar(1, 0, 'Y');
        // 在第0列第2页打印一个字符串"Hello World!"
        OLED_PrintString(0, 2, "Hello World!");
        OLED_PrintSignedVal(6, 4, OLED_Count);
        
        OLED_Count = add(OLED_Count, 1);    //OLED_Count ++ 看反汇编代码
    }
}

让Keil生成反汇编:

选择 魔术棒-uesr 示例图片
在这里插入图片描述

  • 为例方便复制,制作反汇编的指令如下:
fromelf  --text  -a -c  --output=xxx.dis  xxx.axf

上面语句的作用是 用 xxx.axf 输出 xxx.dis 的反汇编

  • 为了方便复制粘贴,先做好我自己的这行代码,自己的路径自己粘贴,方法在如下
  • 在linker的窗口下,往下翻,就能找到linker的路径,复制粘贴到对应的位置即可

在这里插入图片描述
结合起来就是

fromelf  --text  -a -c  --output=test.dis  01_freertos_template\01_freertos_template.axf

用01_freertos_template\01_freertos_template.axf ,输出test.dis的反汇编

粘贴到对应的位置

在这里插入图片描述

编译 看输出结果
在这里插入图片描述
这里很直观的看到输出了.dis文件

找到这个文件,用文本文档打开

在这里插入图片描述

OLED_Test
	0x08002a00:    2400        .$      MOVS     r4,#0
	0x08002a02:    f7ffff01    ....    BL       OLED_Init ; 0x8002808
	0x08002a06:    f7fffeea    ....    BL       OLED_Clear ; 0x80027de
	0x08002a0a:    2100        .!      MOVS     r1,#0
	0x08002a0c:    2241        A"      MOVS     r2,#0x41
	0x08002a0e:    4608        .F      MOV      r0,r1
	0x08002a10:    f7ffff9c    ....    BL       OLED_PutChar ; 0x800294c
	0x08002a14:    2259        Y"      MOVS     r2,#0x59
	0x08002a16:    2100        .!      MOVS     r1,#0
	0x08002a18:    2001        .       MOVS     r0,#1
	0x08002a1a:    f7ffff97    ....    BL       OLED_PutChar ; 0x800294c
	0x08002a1e:    a208        ..      ADR      r2,{pc}+0x22 ; 0x8002a40
	0x08002a20:    2102        .!      MOVS     r1,#2
	0x08002a22:    2000        .       MOVS     r0,#0
	0x08002a24:    f7ffff79    ..y.    BL       OLED_PrintString ; 0x800291a
	0x08002a28:    4622        "F      MOV      r2,r4
	0x08002a2a:    2104        .!      MOVS     r1,#4
	0x08002a2c:    2006        .       MOVS     r0,#6
	0x08002a2e:    f7ffff35    ..5.    BL       OLED_PrintSignedVal ; 0x800289c
	0x08002a32:    2101        .!      MOVS     r1,#1
	0x08002a34:    4620         F      MOV      r0,r4
	0x08002a36:    f000fa7f    ....    BL       add ; 0x8002f38
	0x08002a3a:    4604        .F      MOV      r4,r0
	0x08002a3c:    e7e5        ..      B        0x8002a0a ; OLED_Test + 10
add
	0x08002f38:    b503        ..      PUSH     {r0,r1,lr}
	0x08002f3a:    b081        ..      SUB      sp,sp,#4
	0x08002f3c:    e9dd0101    ....    LDRD     r0,r1,[sp,#4]
	0x08002f40:    4408        .D      ADD      r0,r0,r1
	0x08002f42:    9000        ..      STR      r0,[sp,#0]
	0x08002f44:    bd0e        ..      POP      {r1-r3,pc}
i.main
main
	0x08002f46:    f7fdfe77    ..w.    BL       HAL_Init ; 0x8000c38
	0x08002f4a:    f7fffe0f    ....    BL       SystemClock_Config ; 0x8002b6c
	0x08002f4e:    f7fffa1d    ....    BL       MX_GPIO_Init ; 0x800238c
	0x08002f52:    f7fffac3    ....    BL       MX_I2C1_Init ; 0x80024dc
	0x08002f56:    f7fff9cf    ....    BL       MX_ADC1_Init ; 0x80022f8
	0x08002f5a:    f7fffadf    ....    BL       MX_SPI1_Init ; 0x800251c
	0x08002f5e:    f7fffc1f    ....    BL       MX_USB_PCD_Init ; 0x80027a0
	0x08002f62:    f7fffaff    ....    BL       MX_TIM1_Init ; 0x8002564
	0x08002f66:    f7fffb65    ..e.    BL       MX_TIM2_Init ; 0x8002634
	0x08002f6a:    f7fffbc1    ....    BL       MX_TIM3_Init ; 0x80026f0
	0x08002f6e:    f7fffbfb    ....    BL       MX_USART1_UART_Init ; 0x8002768
	0x08002f72:    f000f813    ....    BL       osKernelInitialize ; 0x8002f9c
	0x08002f76:    f7fff9e7    ....    BL       MX_FREERTOS_Init ; 0x8002348
	0x08002f7a:    f000f82b    ..+.    BL       osKernelStart ; 0x8002fd4
	0x08002f7e:    e7fe        ..      B        0x8002f7e ; main + 56

搜索add,要区分大小写!
在这里插入图片描述

C函数add

int add(volatile int a, volatile int b)
{
	volatile int sum;
    sum = a + b;
    return sum;
}

C函数add的反汇编代码如下:

    i.add
    add
        0x08002f34:    b503        ..      PUSH     {r0,r1,lr}
        0x08002f36:    b081        ..      SUB      sp,sp,#4
        0x08002f38:    e9dd0101    ....    LDRD     r0,r1,[sp,#4]
        0x08002f3c:    4408        .D      ADD      r0,r0,r1
        0x08002f3e:    9000        ..      STR      r0,[sp,#0]
        0x08002f40:    bd0e        ..      POP      {r1-r3,pc}

在这里插入图片描述
add函数里的cnt参数保存在r0里,1保存在r1里,局部变量保存在栈里

在这里插入图片描述

对于单片机来说,在FLASH的地址上,保存这些数据

在这里插入图片描述
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
cpu会读取FLASH地址,得到对应的机器码,在cpu内部执行机器码,
……

在这里插入图片描述

从栈里把数值POP到R1R2R3,
仅仅是为了后面把LR的值POP到PC寄存器,仅
仅是为了恢复栈

以上可以看出,对于汇编代码,本质上,大多数汇编代码都是读取内存,写入内存,加加,减减,跳转

看起来很高大上的C语言的函数,在汇编里都是如此,读内存,写内存,加加,减减,跳转~

韦老师说这节课看不懂没关系,后面课程还会讲的

学习视频
【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=9&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/700035.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

php yield使用

一,概念 yield简单的调用形式看起来像一个return申明,不同之处在于普通return会返回值并终止函数的执行,而yield会返回一个值给循环调用此生成器的代码并且只是暂停执行生成器函数。yield只有在调用的时候才会执行,并不产生多余的…

点云分割报告整理(未完成版-每天写一点)

体积占用网格表示对点进行体素化,然后使用3d卷积神经网络来学习体素级语义。由于点云的稀疏性,体素化效率低,为避免较高的计算成本而忽略了细节。此外,由于同一体素内的所有点都被赋予了相同的语义标签,因此精度受到限…

UPerNet 统一感知解析:场景理解的新视角 Unified Perceptual Parsing for Scene Understanding

论文题目:统一感知解析:场景理解的新视角 Unified Perceptual Parsing for Scene Understanding 论文链接:http://arxiv.org/abs/1807.10221(ECCV 2018) 代码链接:https://github.com/CSAILVision/unifiedparsing 一、摘要 研究…

深圳比创达电子|EMI电磁干扰行业:挑战到突破,电子产业新未来

随着电子技术的飞速发展,电磁干扰(EMI)问题日益凸显,成为影响电子设备性能和稳定性的重要因素。EMI电磁干扰行业作为解决这一问题的关键领域,正面临着前所未有的机遇与挑战。 一、引言:EMI电磁干扰行业的崛…

【Linux】shell脚本变量——系统变量、环境变量和用户自定义变量

系统变量 系统变量是由系统预设的,它们通常在系统启动时被加载,并对所有用户和所有shell实例都有效。这些变量通常控制着系统的行为和配置,例如PATH(命令搜索路径)、HOME(用户主目录)等。系统变…

JavaScript的运算符(算术、比较、赋值、逻辑、条件)

天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…

马斯克怒了,禁止员工使用苹果设备,抨击库克出卖数据给OpenA

昨晚,苹果发布会正式宣布了一系列重磅AI升级,甚至创造了一个新的概念——苹果智能(Apple Intelligence)。 这次升级在操作系统的交互层面上进行了智能化改进,使得更多自然语音和语言理解的控制成为可能,将…

工业操作系统是企业把舵的“仪表盘”

supOS向下连接海量工业设备、仪器、仪表、产品,为各类设备提供统一的接口,实现不同设备之间的互联互通;向上连接各类工业应用软件,将企业内部的生产数据、运营数据、管理数据汇集起来,是链接海量工业设备和各类应用软件…

Docker系列.Docker Desktop中如何启用Kubernetes

Docker技术概论 Docker Desktop中如何启用Kubernetes - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.…

如何在网上下载到最新或者历史QGIS各个版本的C++源码

背景: 博主写下这篇文章的时候已经是PyQGIS下二开了两年,开发一些功能必须得去阅读QGIS的C版本源码,还得考虑到QGIS的长期稳定版和最新版的源码区别。 所以如何去下载到QGIS的源码,就成了当务之急。 QGIS3.36.3的C源码长得像这…

面试题:缓存穿透,缓存击穿,缓存雪崩

1 穿透: 两边都不存在(皇帝的新装) ——简介:缓存穿透指的是恶意用户或攻击者通过请求不存在于缓存和后端存储中的数据来使得所有请求都落到后端存储上,导致系统瘫痪。 ——详述:(缓存穿透是指查询一个一定不存在的数…

BP8519C非隔离降压型恒压芯片

BP8519封装和丝印 BP8519封装和丝印 注意: 该芯片为非隔离ACDC电源芯片,非专业人员请勿使用。专业人员在使用时必须注意防护,避免触电。 非隔离ACDC电源芯片,国内有多家半导体厂商生产,在部分追求低价格的低端仪表、灯…

性价比之选!W830NB降噪耳机高性能配置,探底价309元起

目录 一、降噪技术的革新:-45dB深度沉浸 二、超长续航,乐动不停歇 三、音质的极致追求:Hi-Res双金标认证 四、空间音频与低延迟游戏模式 五、人性化设计与智能互联 六、总结 在这个快节奏的时代,寻找一片属于自己的宁静空间…

35.四方定理

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/477 题目背…

基于长短期记忆网络 LSTM 的下一个单词预测

前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对…

【精选研报】#2形态识别,均线的收敛与发散

下载地址https://pan.baidu.com/s/1L1wPR7kXCb-ZbrgwFKcIvg?pwd8888

leetcode 所有可能的路径(图的遍历:深度优先和广度优先)

leetcode 链接: 所有可能的路径 1 图的基本概念 1.1 有向图和无向图 左边是有向图,右边是无向图。对于无向图来说,图中的边没有方向,两个节点之间只可能存在一条边,比如 0 和 1 之间的边,因为是无向图&am…

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0

成功解决IndexError: index 0 is out of bounds for axis 1 with size 0 🛠️ 成功解决IndexError: index 0 is out of bounds for axis 1 with size 0摘要引言正文内容(详细介绍)🤔 错误分析:为什么会发生IndexError&…

栈和队列优先级队列适配器原理

栈和队列接口函数 stack 栈接口函数 因为栈的结构限制,栈只能栈顶push和栈顶pop, 所以接口略少 queue 队列接口函数 队列只比栈多了一个接口:back 队列的front相当于栈的top 适配器 栈的类模板 其中第二个参数是Container, 且缺省参数为…

Linux操作系统学习:day02

内容来自:Linux介绍 视频推荐:[Linux基础入门教程-linux命令-vim-gcc/g -动态库/静态库 -makefile-gdb调试]( day02 5、Linux目录结构 操作系统文件结构的开始,只有一个单独的顶级目录结构,叫做根目录。所有一切都从“根”开始…