keil把c语言函数转成汇编

汇编可以让开发人员从根源上理解程序的运行逻辑,本文介绍如何在keil环境下如何把一个c文件中的某一个函数,转换为汇编函数,并编译运行。

右击某个c文件,选择Option for File。。。

  图1

然后把下图中的Generate Assembler SRC File(生成汇编源文件)打黑色勾。(默认是灰色勾)

图2

然后执行编译,这样就会在工程的输出文件夹(一般会被命名为OBJ)下,找到与.c文件同名的.s文件,这个C文件中的所有函数,都会被一一转换为汇编函数。

以我的ad.c为例,里面有个test()函数,这个函数中会调用另外一个函数uint16_t AD_getValue1(void),还会对一个全局变量var做写操作。

图3

转换出的汇编函数如下:

图4

由这段代码可以看到在汇编中是如何调用C函数的,以及汇编是如何读写c语言中的全局变量var的。

写var的代码是这两行:

图5

首先LDR指令从|L0.260|标签处载入var变量的内存地址,然后VSTR指令把s0的值写入该内存地址处。汇编中的标签和C语言中的goto语句标签,是类似的。

那么|L0.260|标签定义了什么?在s文件中搜索可见:

图6

有上图可见,这个标签对应的flash地址处,通过DCD命令占用了一个32bit的空间,这个空间中的值被初始化成了全局变量var的地址。DCD本身并不是一个可执行语句,只是一个占位而已。

上图还可以看到,对于C语言中定义的很多常量,也用DCD命令给保存下来了。

接下来我们就可以把c语言中的这个test()函数,用汇编给替换一下:

float var;
void test(void)
{volatile float k = 1.5f;var = AD_getValue1() * k;
}//前缀__asm代表这是个汇编语言编写的函数,以便编译时供编译器识别
__asm void test(void)
{THUMBREQUIRE8PRESERVE8//本汇编函数所有要调用的c函数,必须全部用IMPORT指令导入,不然编译报错IMPORT AD_getValue1[CODE]//全局变量也必须IMPORT导入IMPORT var//以下代码直接从生成的.s文件中对应的test函数拷贝而来,见前文图4,我加了注释PUSH     {r3,lr}//PC指针存储到如r3寄存器VMOV.F32 s0,#1.50000000//把常量1.5加载到浮点寄存器s0中VSTR     s0,[sp,#0]//把s0中的值,存储到(sp指针+0)指向的内存处BL       AD_getValue1//调用c函数,其返回值(uint16类型)会被存到r0寄存器VMOV     s0,r0//把R0寄存器中的数转存到浮点寄存器s0中VCVT.F32.U32 s0,s0//把s0中的值由uint类型转成float类型VLDR     s1,[sp,#0]//把(sp指针+0)内存处的值加载到s1中VMUL.F32 s0,s0,s1//等价于s0=s0*siLDR      r0,|L0.260|/从|L0.260|标签处载入全局变量var的地址VSTR     s0,[r0,#0]//把s0中的值存储到var中POP      {r3,pc}//函数返回
//以上代码需要调用|L0.260|标签处的数据,也手动复制进来:|L0.260|DCD      var
}

至此,这个汇编函数__asm void test(void)和C语言函数void test(void),功能完全一致了。把这个c函数void test(void)删掉后,只保留汇编函数,仍然可以编译通过。这样我们就实现了:在一个c源文件中,既有c函数,又有汇编函数共存。

如果编译时看到以下报错:

error: A1875E: Register Rn must be from R0 to R7 in this instruction

 报错对应的代码为LDR      r0,|L0.260|,这行代码本身并没有问题,问题出在|L0.260|这个标签没有4字节对齐。

同时伴随上述报错的,还有一个警告:

 warning: A1581W: Added 2 bytes of padding at address 0x2aa

这个你警报的意思是ROM没有4字节对齐,编译器自动添加了2字节的空白。这个问题来源于图6中第一行DCW,这个指令占用了2字节的位置,导致后面的DCD无法4字节对齐了。解决方法就是直接把DCW这行删掉。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DDP、pytorch的分布式 torch.distributed.launch 训练说明

0、DDP的运行原理 执行步骤: 将data分为多个不同的batch,每个gpu得到batch都是不一样的然后将每个batch放在每个gpu上独立的执行最后得到的梯度求平均将平均梯度平分给每个gpu执行下一次迭代 这也就意味着你有多少个gpu,训练的速度也会提升…

数据结构与算法解题-20240422

这里写目录标题 一、2. 两数相加二、67. 二进制求和三、415. 字符串相加四、LCS 01. 下载插件五、71. 简化路径 一、2. 两数相加 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 …

uniapp——授权报错,选择合适的基础库

说明 我的小程序开发版本点击选择头像报错 更换基础库就好了

发布自己的Docker镜像到DockerHub

学会了Dockerfile生成Docker image 之后,如何上传自己的镜像到 DockerHub呢?下面我以自己制作的 bs-cqhttp 镜像为例,演示一下如何将自己的镜像发布到 Docker 仓库。 1 生成自己的 Docker 镜像 1.1 实例镜像用到的文件 图1 实例镜像制作用到…

vue 请求php接口 header 传自定义参数 提示cors 跨域问题

前端地址 http://192.168.0.125:4021 请求后端地址的时候报 from origin http://192.168.0.125:4021 has been blocked by CORS policy: Request header field userid is not allowed by Access-Control-Allow-Headers in preflight response. 大概意思是请求 header里有个…

3Darray 修改array值然后保存图片

from PIL import Image import numpy as np img_path ./000001.jpg # 读取图片 image Image.open(img_path) width, height image.size print("图片的宽度为{},高度为{}".format(width,height)) print("图片的mode为{}".format(image.mode)) print(&quo…

指针专题(4)【qsort函数的概念和使用】

1.前言 上节我们学习了指针的相关内容,本节我们在有指针的基础的条件下学习一下指针的运用,那么废话不多说,我们正式进入今天的学习 2.回调函数 我们既然已经学习了指针的相关基础,那么我们此时就可以用指针来实现回调函数 而回…

Linux学习之HTTP

引言:了解到了协议的定制,我们就知道在进行客户端与服务端通信时,对于报文的封装协议的定制是必不可少的,虽说协议是我们自己定制,但是有大佬们直接为我们写了一套完整的,可靠的协议,例如http协…

Python | Leetcode Python题解之第32题最长有效括号

题目: 题解: class Solution:def longestValidParentheses(self, s: str) -> int:stack[]maxL0nlen(s)tmp[0]*n #标记数组cur0for i in range(n):if s[i](:stack.append(i)else:if stack:jstack.pop()if s[j](:tmp[i],tmp[j]1,1 #匹配成…

cookie-editor 管理您的 cookie

Cookie-Editor - 适用于 Chrome、Firefox、Safari、Edge 和 Opera 的安全 cookie 编辑器https://cookie-editor.com/ Cookie-Editor 是一个专注于生产力的浏览器扩展,可帮助您以尽可能少的点击次数管理您的 cookie。 您最多只需点击三次,即可访问当前页…

龙迅LT8618SXB TTL /BT656/BT601/BT1120桥接到HDMI 1.4,低功耗HDMI1.4发射机

龙迅LT8618SXB描述: LT8618SX是Lontium基于ClearEdgeTM技术的低功耗版本HDMI发射机。它支持24位颜色深度HDMI1.4(高清多媒体接口)规范。它们完全向后兼容Lontium的第一代HDMI发射机LT8618EX。LT8618SX是一款高性能、低功耗的部件&#xff0c…

2W 隔离宽范围输入,单输出 DC/DC 电源模块——TP2L-2W 系列

TP2L-2W系列是一款高性能、超小型的电源模块,宽范围2:1输入,输出有稳压和连续短路保护功能,隔离电压为1.5KVDC、3KVDC,工作温度范围为–40℃到85℃。特别适合对输出电压的精度有严格要求的地方,外部遥控功能…

【STM32】嵌入式实验二 GPIO 实验:数码管

实验内容: 编写程序,在数码管上显示自己的学号。 数码管相关电路: PA7对应的应该是段码,上面的图写错了。 注意:选中数码管是低电平选中;并且用74HC595模块驱动输出的段码, 这个模块的学习可以…

JAVA基础之垃圾收集器

一 JVM垃圾收集 分代收集思想 当前虚拟机的垃圾收集一般采用分代收集算法,这种算法本身没有创新性,只是根据对象存活周期的不同将内存分为几块。一般将java堆内存分为新生代和老年代,这样我们就可以根据不同年龄到的特点选择不同的垃圾收集…

学之思考试系统环境启动QA

学之思考试系统环境启动Q&A 目录 学之思考试系统环境启动Q&A后台代码启动失败:前台代码启动失败常见解决方式参考资料后台代码启动失败: 后端代码启动不成功,不能够自动导入maven,配置依赖; 使用idea打开到:\xzs-master\xzs-mysql-master\source\xzs这个路径下;…

ruoyi-cloud-plus添加一个不要认证的公开新页面

文章目录 一、前端1. 组件创建2. src/router/index.ts3. src/permission.ts 二、后端1. 设计思想2. ruoyi-gateway.yml3. 开发Controller 版本RuoYiCloudPlusv2.1.2plus-uiVue3 ts 以新增一个公开的课程搜索页面为例。 一、前端 1. 组件创建 在view目录下创建一个页面的vue…

Java面试题笔记(持续更新)

目录 Java基础 java中的Math.round(-1.5)等于多少? JDK和JRE的区别? 抽象类能被final修饰吗? 如何决定使用TreeMap还是HashMap? 迭代器Iterator是什么? Queue中的poll和remove有什么区别? 为什么要使用克隆&a…

web前端框架设计第五课-计算属性与监听属性

web前端框架设计第五课-计算属性与监听属性 一.预习笔记 1.计算属性 computed split():拆分 reverse():倒序 join():拼接 计算属性与方法,两者效果一致,但是computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 met…

Nodejs安装与配置--基于Linux系统--RedHat7.9

nodejs安装从未这么简单 1、nodejs版本设置? curl -fsSL https://rpm.nodesource.com/setup_16.x | sudo bash - 其他版本如下: * https://rpm.nodesource.com/setup_16.x — Node.js 16 "Gallium" (deprecated) * https://rpm.nodesource.co…

2024 抖音欢笑中国年(五):Wasm、WebGL 在互动技术中的创新应用

前言 随着 Web 前端技术的不断发展,越来越多的新兴技术方案被引入到 Web 开发中,其中 Wasm 和 WebGL 作为前端领域的两大利器,为开发者带来了更多的可能性。 本文将结合2024 年抖音欢笑中国年的部分项目,重点介绍如何利用 Wasm 和…