C与汇编深入分析
汇编怎么调用C函数
直接调用
BL main
传参数
在arm中有个ATPCS规则(ARM-THUMB procedure call standard)(ARM-Thumb过程调用标准)。
约定r0-r15寄存器的用途:
- r0-r3:调用者和被调用者之间传递参数
- r4-r11:函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。

int delay(unsigned int d)
{while(d--);return 0;
}
ldr r0,=1000000
dl delay
cmp r0,#0
返回值保存在r0
A函数调用B函数
假设A函数里需要用到R4寄存器,B函数里也需要用到R4寄存器。
因此B函数就有会覆盖A函数R4寄存器的值。
于是需要在B函数执行前,保存R4-R11寄存器的值在A的栈中 。
B函数执行完后,返回A函数前,要从A的栈中恢复R4-R11寄存器。
C函数的反汇编码阅读
要解决几个问题:
- 为什么调用C函数前要设置栈?栈的作用是?
- C函数传参
- C函数执行过程

反汇编示例

地址0x08000010,Flash上烧写20010000。
启动流程
上电后:
- 设置栈:CPU会从0x08000000读取值,用来设置SP(我们的程序里再次设置了SP)。
- 跳转:CPU会从0x08000004得到地址值,根据它的BIT0切换到ARM状态或Thumb状态,然后跳转。
对于Cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1。
对0x08000004上的值=Reset_Handler+1。
从Reset_Handler上继续执行
纯汇编点灯


写程序
寄存器操作
对于寄存器的操作,主要涉及读、修改、写。
- 读可以使用LDR指令,代码为LDR R1,[R0]
- 写使用STR指令,代码为STR R1,[R0]
- 修改:清除位使用BIC或AND指令,设置位使用ORR指令
LDR R0, =(1<<20) | (1<<21)
BIC R1,R1,R0 ;清除R1的bit20,bit21
LDR R0, =(1<<20)
ORR R1,R1,R0 ;设置R1的bit20
- 函数里的条件判断
比如减1操作,代码为SUB R0,R0,#1
顺便使用减1后的结果影响程序状态寄存器,代码为SUBS R0,R0,#1 - 程序的调用与返回值
传参,代码为LDR R0,=VAL
调用,代码为BL delay,它顺便把下一条指令的地址保存在LR寄存器了。
返回,代码为MOV PC,LR
使用按键控制LED

先看原理图,我们使用KEY1来控制红色LED,按下KEY1在灯亮,松开后灯灭。
KEY1的引脚是PA0
使能GPIOA模块,RCC_APB2ENR:0x40021000+0x18
串口的硬件介绍
UART的全称是Universal Asynchronous Receiver and Transmitter,即通用异步收发器。
串口在嵌入式中用途非常的广泛,主要的用途有:
- 打印调试信息
- 外接各种模块:GPS、蓝牙
串口因为结构简单、稳定可靠,广受欢迎。
通过三根线即可,发送、接收、地线。

TXD线把PC机要发送的信息发送给ARM开发板。
最下面的地线统一参考地。
串口的参数
- 波特率:一般选波特率都会有9600、19200、115200等选项。其实意思就是每秒传输这么多个比特位数(bit)。
- 起始位:先发出一个逻辑0的信号,表示传输数据的开始。
- 数据位:可以是5~8位逻辑0或1.如ASCII码(7位)、扩展BCD码(8位)。小端传输。
- 校验位:数据位加上这一位后,使得1的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。
- 停止位:它是一个字符数据的结束标志。
怎么发送一字节数据,比如A?
'A’的ASCII值是0x41,二进制就是0x01000001,怎么把这8位数据发送给PC机呢?
- 双方约定好波特率(每一位占据的时间)
- 规定传输协议
原来是高电平,ARM拉低电平,保持1bit时间。
PC在低电平处开始计时。
ARM根据数据依次驱动TXD电平,同时PC依次读取RXD电平,获得数据。
PC机在数据位的中间读取引脚状态。

RS-232的电平比TTL/CMOS高,能传输更远的距离,在工业上用得比较多。
市面上大多数ARM芯片都不止一个串口,一般使用串口0来调试,其它串口来外接模块。

115200,8n1。
一秒钟可以传输115200个bit,传送一个字节需要:1个起始位+8个数据位+1个停止位=10bit。
所以一秒钟可以传输11520个字节。
UART编程
看原理图确定引脚
- 有很多串口,使用哪一个?看原理图确定。
- 配置引脚为UART功能
至少用到发送、接收引脚:txd、rxd
需要把这些引脚配置为UART功能,并使能UART模块 - 设置串口参数
- 根据状态寄存器读写数据
肯定有一个数据寄存器,程序把数据写入,即可通过串口向外发送数据。
肯定有一个数据寄存器,程序读取这个寄存器,就可以获得先前接收到的数据。
很多有状态寄存器:判断数据是否发送出去?是否发送成功?判断是否接收到了数据?

需要使能GPIOA/USART1模块
需要设置GPIOA的寄存器,选择引脚功能:所以要使能GPIOA模块。
GPIOA模块、USART1模块的使能都是在同一个寄存器里实现。


USART寄存器,用结构体来表示比较方便:
typedef unsigned int uint32_t;
typedef struct
{volatile uint32_t SR; /*!< USART Status register, Address offset: 0x00 */volatile uint32_t DR; /*!< USART Data register, Address offset: 0x04 */volatile uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */volatile uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */volatile uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */volatile uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */volatile uint32_t GTPR; /*!< USART Guard time and prescaler register, Address
}USART_TypeDef;
USART_TypeDef *usart1 = (USART_TypeDef *)0x40013800;
在C语言中,编译器通常会对代码进行各种优化,以提高程序的执行效率。这些优化包括重新排序指令、删除看似无用的变量读取等。
然而,在与硬件通信的情景下,有些变量的值可能会被硬件或者其他事件异步地修改,而这种修改通常是在程序控制流之外发生的。
假设有一个代表硬件寄存器的变量,如果没有使用’volatile’关键字,编译器可能会进行一些优化,认为这个变量的值在程序的某个地方被设置后就不再改变。这就可能导致一些问题,因为实际上这个变量的值可能会在程序的其它地方被异步地修改。
通过在变量声明中加入’volatile’关键字,告诉编译器不要对这个变量进行过多的优化,以确保每次访问这个变量时都从内存中读取最新的值,而不是使用之前缓存的值。
这对于与硬件直接交互的变量,比如你提供的USART通信寄存器,非常重要,因为这些寄存器的值可能会在程序的正常流程之外被外部事件改变。
#ifndef __UART_H
#define __UART_Hvoid uart_init();
char getchar();
char putchar(char c);#endif
这段代码是一种常见的C/C++预处理器约定,用于防止头文件(header file)被多次包含,避免引起重定义错误。
- #ifndef:这是预处理指令,表示if not defined,即如果之前没有定义过指定的标识符,那么执行接下来的代码。
- __UART_H:这是一个宏标识符,通常是头文件名的大写形式,加上双下划线前缀以确保标识符的唯一性。在这里,它用于作为一个宏,防止头文件被多次包含。
- #define __UART_H:如果之前没有定义过__UART_H,那么用这个#define指令定义它。这样,当头文件再次被引用时,#ifndef检查将会失败,因为__UART_H已经被定义了。
- #endif:表示条件编译的结束。如果之前#ifndef条件成立,那么在这里结束条件编译块。
这种写法的目的是确保一个头文件只会被编译一次,即使它在多个地方被引用。这可以防止由于头文件被重复引用而导致的重定义错误。这是一种预防措施,用于提高代码的可维护性和可移植性。
相关文章:
C与汇编深入分析
汇编怎么调用C函数 直接调用 BL main传参数 在arm中有个ATPCS规则(ARM-THUMB procedure call standard)(ARM-Thumb过程调用标准)。 约定r0-r15寄存器的用途: r0-r3:调用者和被调用者之间传递参数r4-r11…...
MySQL中外键的使用及外键约束策略
一、外键约束的概念 外键约束(FOREIGN KEY,缩写FK是数据库设计的一个概念,它确保在两个表之间的关系保持数据的一致性和完整性。 外键是指表中的某个字段的依赖于另一张表中某个字段的值,而被依赖的字段必须具有主键约束或者唯一约束&#…...
Home Assistant使用ios主题更换背景
Home Assistant使用ios主题、更换背景 lovelace-ios-dark-mode-theme 默认前置情况,1、已安转HACS插件2、搜索安装 IOS Dark Mode Theme1)第一、二步应该很容易实现,configuration.yaml文件很容易被找到2)而本人在进行第三步操作时…...
深入了解鼠标光标的设置过程
有一位读者问了这样一个问题: “为什么鼠标光标的设定绑定在窗口类,而不是窗口上?” 这个问题隐含地假设了光标与窗口类相关联。虽然每个窗口类都有一个关联的光标,但决定使用哪个光标的是窗口。 光标设置过程在 WM_SETCURSOR 消…...
数据结构-散列表
列表(Hash Table),又称哈希表,是一种数据结构,特点是:数据元素的关键字与其存储地址直接相关 例:有一堆数据元素,关键字分别为{19,14,23ÿ…...
一款IT团队都在用的私有化知识库,技术开放,还开源了!
IT和软件开发团队需要处理大量的技术文档和知识,通过建立内部知识库,可以将技术文档、代码示例、最佳实践等知识整理和归档起来,方便团队成员查找和参考。 IT和软件开发团队为什么要建立内部知识库? 提高知识管理效率:…...
解决 docker compose 官方 MySQL 镜像在容器中不能输入中文的问题
该问题可以通过添加环境变量解决,途径如下: 一、如果容器没条件或不允许重启,可通过命令行方式临时解决。 docker compose exec SERVICE-NAME env LANGC.UTF-8 mysql -u username -p 二、修改 docker-compose.yml 配置文件一劳永逸 envir…...
基于连续Hopfield神经网络优化——旅行商问题优化计算
大家好,我是带我去滑雪! 利用神经网络解决组合优化问题是神经网络应用的一个重要方面。所谓组合优化问题,就是在给定约束条件下,使目标函数极小(或极大)的变量组合问题。将Hopfield网络应用于求解组合优化问…...
SpringBoot整合Activiti7——定时器事件(九)
文章目录 定时器事件时间定义时间固定时间段时间周期 1.开始事件2.中间事件3.边界事件代码实现xml文件自定义服务任务监听器自定义用户任务监听器测试流程流程执行步骤 定时器事件 可以用在开始事件、中间事件、边界事件上,边界事件可以是中断和非中断边界事件 需要…...
轻量封装WebGPU渲染系统示例<29>- 深度模糊DepthBlur(源码)
实现方式: step1. 通过mrt机制,输出颜色和深度相关数据的两张rtt纹理。 step2. 基于上述颜色纹理,生成一张模糊之后的新rtt纹理。 setp3. 基于深度(也就是距离摄像机的远近)数据,合成颜色和模糊纹理数据,并最终输出。 当前示例…...
LeetCode226. Invert Binary Tree
文章目录 一、题目二、题解2.1 前序遍历版本2.2 中序遍历版本2.3 后序遍历版本 一、题目 Given the root of a binary tree, invert the tree, and return its root. Example 1: Input: root [4,2,7,1,3,6,9] Output: [4,7,2,9,6,3,1] Example 2: Input: root [2,1,3] Ou…...
Java设计模式-创建型模式-建造者模式
建造者模式 建造者模式案例与工厂模式的区别:Builder 注解 建造者模式 建造者模式是将一个复杂对象的构件与表示分离,使得同样的构件过程可以创建不同的表示。 建造者模式将内部构件的创建和组装分割开,一般使用链式编程,代码整洁…...
PyQt中QFrame窗口中的组件不显示的原因
文章目录 问题代码(例)原因和解决方法 问题代码(例) from PyQt5.QtWidgets import * from PyQt5.QtGui import QFont, QIcon, QCursor, QPixmap import sysclass FrameToplevel(QFrame):def __init__(self, parentNone):super().…...
git 命令行回退版本
git 命令行回退版本 git 命令行回退版本命令: 1.切换到需要回退的分支 git checkout branch-v2.0.02.更新远程分支 git fetch3.找到需要回退版本的版本号git revert a6914da55ff40a09e67ac2426b86f1212e6580eb4.清除工作区缓存git clean -df5.强制提交git push -f...
IntelliJ IDEA 安装 GitHub Copilot插件 (最新)
注意: GitHub Copilot 插件对IDEA最低版本要求是2021.2,建议直接用2023.3,一次到位反正后续要升级的。 各个版本的依赖关系,请参照: ##在线安装: 打开 IntelliJ IDEA扩展商店,输入 "Git…...
viewpage选择器
GitHub - hackware1993/MagicIndicator: A powerful, customizable and extensible ViewPager indicator framework. As the best alternative of ViewPagerIndicator, TabLayout and PagerSlidingTabStrip —— 强大、可定制、易扩展的 ViewPager 指示器框架。是ViewPagerIndi…...
vue中如何将json数组指定的key赋值给el-form-item并均匀的分成2列
在Vue中,你可以使用v-for指令来遍历JSON数组,并将指定的key赋值给el-form-item。下面是一个示例: <template><el-form><el-row><el-col :span"6" v-for"item in jsonArray" :key"item.key&qu…...
笔记本分屏怎么操作?3个方法提高工作效率!
“有朋友知道笔记本怎么才能实现分屏吗?我在工作时,经常需要来回切换屏幕,效率真的太低了,有什么方法可以实现两个屏幕同时使用吗?” 在现代生活中,多任务处理已成为常态,而笔记本分屏技术为用户…...
Android 使用poi生成Excel ,word并保存在指定路径内
一添加依赖(一定要用新版依赖防止一些bug) minSdk 26 //注意最小支持SDK26 dependencies {implementation org.apache.poi:poi:5.2.4implementation org.apache.poi:poi-ooxml:5.2.4implementation javax.xml.stream:stax-api:1.0-2 }二,创…...
嵌入式杂记 -- MCU的大小端模式
MCU的大小端模式 大端模式小端模式大小端模式测试联合体概念MCU大小端模式测试大端模式测试小端模式测试 大小端模式转换 在进行MCU开发的时候,我们需要注意MCU的数据存储模式,在嵌入式中有两种不同的存储模式,分别是 大端模式和小端模式。 …...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
