【ARM 嵌入式 C 入门及渐进 6 -- Linux 内建函数 __builtin_】
文章目录
- 1.1 内建函数
- 1.1.1 内建函数 __builtin_return_address
- 1.1.2 内建函数 __builtin_frame_address
- 1.1.3 内建函数 __builtin_expect(exp, c)
- 1.1.4 C 标准库的内建函数
- 1.2 内建函数编译选项
1.1 内建函数
内建函数是编译器内部实现的函数。这些函数跟关键字一样,可以直接使用,无须像标准库函数那样,要 #include
对应的头文件才能使用。
内建函数的函数命名,通常以 __builtin
开头。这些函数主要在编译器内部使用,主要是为编译器服务的。内建函数的主要用途如下:
- 用来处理变长参数列表;
- 用来处理程序运行异常;
- 程序的编译优化、性能优化;
- 查看函数运行中的底层信息、堆栈信息等;
- C 标准库函数的内建版本。
因为内建函数是编译器内部定义,主要由编译器相关的工具和程序调用,所以这些函数并没有文档说明,而且变动而频繁。对于程序开发者来说,不建议使用这些函数。
1.1.1 内建函数 __builtin_return_address
有些内建函数,对于我们了解程序运行的底层信息、编译优化很有帮助,而且在 Linux 内核中也经常使用这些函数,所以还是很有必要去了解 Linux 内核中常用的一些内建函数。
__builtin_return_address(LEVEL)
这个函数用来返回当前函数或调用者的返回地址。函数的参数 LEVEl 表示函数调用链中的不同层次的函数,各个值代表的意义如下。
0:返回当前函数的返回地址;
1:返回当前函数调用者的返回地址;
2:返回当前函数调用者的调用者的返回地址。
1.1.2 内建函数 __builtin_frame_address
在函数调用过程中,还有一个 “栈帧” 的概念。函数每调用一次,都会将当前函数的现场(返回地址、寄存器等)保存在栈中,每一层函数调用都会将各自的现场信息都保存在各自的栈中。这个栈也就是当前函数的栈帧,每一个栈帧有起始地址和结束地址,表示当前函数的堆栈信息。
__builtin_return_address(LEVEL)
多层函数调用就会有多个栈帧,每个栈帧里会保存上一层栈帧的起始地址,这样各个栈帧就形成了一个调用链。
很多调试器、GDB、包括我们的这个内建函数,其实都是通过回溯函数栈帧调用链来获取函数底层的各种信息的。
在 ARM 系统中,使用 FP 和 SP 这两个寄存器,分别指向当前函数栈帧的起始地址和结束地址。当函数继续调用或者返回,这两个寄存器的值也会发生变化,总是指向当前函数栈帧的起始地址和结束地址。
+----+ <-- high address
| |
+----+ <- fp // 栈帧起始地址
| |
+----+
| |
+----+
| |
+----+ <- sp // 栈顶
| |
+----+
| |
+----+ <-- low address
我们可以通过内建函数 __builtinframeaddress(LEVEL)
,查看函数的栈帧地址。
0: 查看当前函数的栈帧地址;
1: 查看当前函数调用者的栈帧地址。
…
1.1.3 内建函数 __builtin_expect(exp, c)
内建函数 __builtin_expect
也常常用来编译优化。这个函数有两个参数,返回值就是其中一个参数,仍是 exp。这个函数的意义主要就是告诉编译器:参数 exp
的值为 c
的可能性很大。然后编译器可能就会根据这个提示信息,做一些分支预测上的代码优化。
参数 c 跟这个函数的返回值无关,无论 c 为何值,函数的返回值都是 exp
Linux 内核中,使用 __builtin_expect
内建函数,定义了两个宏:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
这两个宏的主要作用,就是告诉编译器:某一个分支发生的概率很高,或者说很低,基本不可能发生。编译器就根据这个提示信息,就会去做一些分值预测的编译优化。在这两个宏定义有一个细节,就是对宏的参数 x
做两次取非操作,这是为了将参数 x
转换为布尔类型,然后与 1
和 0
作比较,告诉编译器 x 为真或为假的可能性很高。
1.1.4 C 标准库的内建函数
在 GNU C 编译器内部,实现了一些和 C 标准库函数类似的内建函数。这些函数跟 C 标准库函数功能相似,函数名也相同,只是在前面加了一个前缀 __builtin_
。
1.2 内建函数编译选项
在项目开发中会遇到下面编译问题:
warning: conflicting types for built-in function
可以看出来其原因是定义的函数和 所使用的 C 库中的的内建函数重名了,导致编译的时候报错了。这个时候一般通过修改函数名来解决这个问题,其实 GCC 编译器已经给我们提供了解决方法,也即在编译参数选项中增加 -fno-builtin
选项。
rt-thread/rt-thread/bsp/taihu/rtconfig.py
AFLAGS = '-D__ASSEMBLY__ -fno-exceptions -fno-builtin -mregnames -c -Wall ...'
在 PC 中如果编译单个文件可以使用 gcc a.c -o a.out -fno-builtin
如果遇到有的函数想用内建函数,有的不想用内建函数,那该怎么办了? 这时可以使用 GCC 提供的另外一个编译选项:-fno-builtin-function
, 该编译参数仅仅是不把 function
这个函数当作内建(built-in)函数,function这个函数不能够以 "__builtin
_ " 开头。如果一个函数不是以内建(built-in)函数名命名的,那么这个选项(-fno-builtin-function)是无效的。
如果编译选项里使用了 “-fno-builtin
” ,但是你又想有选择性的使用内建(built-in)函数,这个时候可通过定义宏(macros)来解决,例如:
#define abs(s) __builtin_abs((n))
#define strcpy(d, s) __builtin_strcpy((d), (s))
推荐阅读:
https://www.cnblogs.com/zhangzhiwei122/p/15759530.html
http://1024s.top/mbstudy/mbBlog/blogDetail?blogId=7269
【ARM 嵌入式 C 入门及渐进 6 -- Linux 内建函数 __builtin_】相关推荐
- 【ARM 嵌入式 C 入门及渐进 4-- Linux 位图 bitmap】
文章目录 1.1 位图算法-bitmap 1.1.1 bitmap 使用场景示例 1.1.2 bitmap算法实现 1.1 位图算法-bitmap 位图算法,是指使用一个 bit 位来表示数据状态. ...
- 网络上所谓的《ARM嵌入式系统入门最好的文章》
一 首先说说ARM的发展 可以用一片大好来形容,翻开各个公司的网站,招聘里面嵌入式占据了大半工程师职位. 广义的嵌入式无非几种:传统的什么51.AVR.PIC称做嵌入式微控制器:ARM是嵌入式微处理器 ...
- arm嵌入式linux应用实例开发pdf,零点起步——ARM嵌入式Linux应用开发入门一书的源代码...
代码片段和文件信息 属性 大小 日期 时间 名称 ----------- --------- ---------- ----- ---- 文件 2 ...
- 收集整理的ARM嵌入式linux开发入门视频教程
嵌入式Linux作为一个系统学科,具有知识点多,知识难度大,实践操作性强等特点,很多踌躇满志的同学最终倒在了学习嵌入式Linux的道路上,绝大部分也是因为没有掌握嵌入式Linux 的知识规律和学习方法 ...
- 嵌入式开发入门之经典 ARM开发板
嵌入式开发入门之经典 开始进入嵌入式世界,真是一头雾水,不知道如何入手!也不知道该如何学习,学习什么,最近从网上转载这篇文章,对我启发很大,对于初始进入嵌入式的人们很有帮组,好多嵌入式大侠都说这是入门 ...
- 嵌入式 Linux 入门(十、Linux 下的 C 编程)
嵌入式 Linux 入门第十课,聊聊 linux 下的 C 编程...... 矜辰所致 插一句,问题讨论群在文末的推广,以后大家提问可以在群中,即便我不在也能看到历史记录. 目录 前言 一.C 语言编 ...
- 基于c语言的linux嵌入式开发入门
前言 本文主要包含,c语言基本结构与语法.make及makefile的使用.main函数参数与返回值的说明.标准输入.输出.错误流的介绍以及linux管道的应用. 语言数据类型 联合体也有翻译为共用体 ...
- 嵌入式linux的运行过程,ARM嵌入式设备Linux系统启动步骤和方式
> 1). 简介本文引用地址:http://www.eepw.com.cn/article/201607/294237.htm 本文简单介绍ARM嵌入式设备基于嵌入式Linux操作系统时候的启动 ...
- 嵌入式跑马灯实验报告linux,ARM嵌入式跑马灯设计实验报告.doc
ARM嵌入式跑马灯设计实验报告.doc ARM嵌入式设计实验报告 题目: 跑马灯的设计 专 业: 班 级: 姓 名: 学 号: 指导教师: 2014年11 月 目 录 1 题目要求---------- ...
最新文章
- R语言ggplot2可视化自定义多个图例(legend)标签之间的距离实战(例如,改变数据点颜色和数据点大小图例之间的距离)
- 第8章6节MonkeyRunner启动运行过程-启动Monkey 4
- WKQ学习(后台知识)
- mysql去掉两个最高分_数据分析系列 16/32 | MySQL中子查询与联合查询
- eclipse下载与安装步骤详解,包含解决错误(最全最详细)
- C语言for循环的嵌套例题,c语言 for循环的嵌套(含答案)
- 常用的mysql sql_mode
- MTK 驱动开发(54)---MTK-thermal.conf温度参数修改的方法
- python操作excel模板_Python Excel模板读写,维护公式和格式
- Solr搜索引擎——中文分词器
- jmeter的如何设置headers
- ORACLE 包内的存储过程的动态sql
- 第三节 UNIX文件系统结构
- Linux为硬盘重建MBR,linux重建mbr
- POJ 3345 Bribing FIPA(树形dp+背包)
- windows移动硬盘接到mac上使用(加载ntfs移动硬盘)
- linux 锐捷客户端 脚本,基于802.1x的锐捷linux客户端认证方法(最新)
- 怎么搭建一份好的产品宣传手册?方法来了
- 什么是机械学习?及Scikit-learn机械学习库
- excel 中 宏的使用
热门文章
- 2017第十八届广州金融理财博览会会刊(参展商名录)
- mendeley添加知网的论文
- VUE+Express+MongoDB前后端分离,实现一个便签墙(一)
- java计算机毕业设计汽车客运站票务管理系统源码+程序+lw文档+mysql数据库
- MATLAB绘制加噪和去噪图像
- wht html标签,index.html
- 【实战分享】不用软件实现百度贴吧无限顶贴技巧
- 噪声估计的主要方法简要概述
- 向github账号和gitee账号添加ssh key
- 织梦dede 后台“标题织梦内容管理系统”修改方法