文章目录

  • 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 系统中,使用 FPSP 这两个寄存器,分别指向当前函数栈帧的起始地址和结束地址。当函数继续调用或者返回,这两个寄存器的值也会发生变化,总是指向当前函数栈帧的起始地址和结束地址。

+----+ <-- 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 转换为布尔类型,然后与 10 作比较,告诉编译器 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_】相关推荐

  1. 【ARM 嵌入式 C 入门及渐进 4-- Linux 位图 bitmap】

    文章目录 1.1 位图算法-bitmap 1.1.1 bitmap 使用场景示例 1.1.2 bitmap算法实现 1.1 位图算法-bitmap 位图算法,是指使用一个 bit 位来表示数据状态. ...

  2. 网络上所谓的《ARM嵌入式系统入门最好的文章》

    一 首先说说ARM的发展 可以用一片大好来形容,翻开各个公司的网站,招聘里面嵌入式占据了大半工程师职位. 广义的嵌入式无非几种:传统的什么51.AVR.PIC称做嵌入式微控制器:ARM是嵌入式微处理器 ...

  3. arm嵌入式linux应用实例开发pdf,零点起步——ARM嵌入式Linux应用开发入门一书的源代码...

    代码片段和文件信息 属性            大小     日期    时间   名称 ----------- ---------  ---------- -----  ---- 文件      2 ...

  4. 收集整理的ARM嵌入式linux开发入门视频教程

    嵌入式Linux作为一个系统学科,具有知识点多,知识难度大,实践操作性强等特点,很多踌躇满志的同学最终倒在了学习嵌入式Linux的道路上,绝大部分也是因为没有掌握嵌入式Linux 的知识规律和学习方法 ...

  5. 嵌入式开发入门之经典 ARM开发板

    嵌入式开发入门之经典 开始进入嵌入式世界,真是一头雾水,不知道如何入手!也不知道该如何学习,学习什么,最近从网上转载这篇文章,对我启发很大,对于初始进入嵌入式的人们很有帮组,好多嵌入式大侠都说这是入门 ...

  6. 嵌入式 Linux 入门(十、Linux 下的 C 编程)

    嵌入式 Linux 入门第十课,聊聊 linux 下的 C 编程...... 矜辰所致 插一句,问题讨论群在文末的推广,以后大家提问可以在群中,即便我不在也能看到历史记录. 目录 前言 一.C 语言编 ...

  7. 基于c语言的linux嵌入式开发入门

    前言 本文主要包含,c语言基本结构与语法.make及makefile的使用.main函数参数与返回值的说明.标准输入.输出.错误流的介绍以及linux管道的应用. 语言数据类型 联合体也有翻译为共用体 ...

  8. 嵌入式linux的运行过程,ARM嵌入式设备Linux系统启动步骤和方式

    > 1). 简介本文引用地址:http://www.eepw.com.cn/article/201607/294237.htm 本文简单介绍ARM嵌入式设备基于嵌入式Linux操作系统时候的启动 ...

  9. 嵌入式跑马灯实验报告linux,ARM嵌入式跑马灯设计实验报告.doc

    ARM嵌入式跑马灯设计实验报告.doc ARM嵌入式设计实验报告 题目: 跑马灯的设计 专 业: 班 级: 姓 名: 学 号: 指导教师: 2014年11 月 目 录 1 题目要求---------- ...

最新文章

  1. R语言ggplot2可视化自定义多个图例(legend)标签之间的距离实战(例如,改变数据点颜色和数据点大小图例之间的距离)
  2. 第8章6节MonkeyRunner启动运行过程-启动Monkey 4
  3. WKQ学习(后台知识)
  4. mysql去掉两个最高分_数据分析系列 16/32 | MySQL中子查询与联合查询
  5. eclipse下载与安装步骤详解,包含解决错误(最全最详细)
  6. C语言for循环的嵌套例题,c语言 for循环的嵌套(含答案)
  7. 常用的mysql sql_mode
  8. MTK 驱动开发(54)---MTK-thermal.conf温度参数修改的方法
  9. python操作excel模板_Python Excel模板读写,维护公式和格式
  10. Solr搜索引擎——中文分词器
  11. jmeter的如何设置headers
  12. ORACLE 包内的存储过程的动态sql
  13. 第三节 UNIX文件系统结构
  14. Linux为硬盘重建MBR,linux重建mbr
  15. POJ 3345 Bribing FIPA(树形dp+背包)
  16. windows移动硬盘接到mac上使用(加载ntfs移动硬盘)
  17. linux 锐捷客户端 脚本,基于802.1x的锐捷linux客户端认证方法(最新)
  18. 怎么搭建一份好的产品宣传手册?方法来了
  19. 什么是机械学习?及Scikit-learn机械学习库
  20. excel 中 宏的使用

热门文章

  1. 2017第十八届广州金融理财博览会会刊(参展商名录)
  2. mendeley添加知网的论文
  3. VUE+Express+MongoDB前后端分离,实现一个便签墙(一)
  4. java计算机毕业设计汽车客运站票务管理系统源码+程序+lw文档+mysql数据库
  5. MATLAB绘制加噪和去噪图像
  6. wht html标签,index.html
  7. 【实战分享】不用软件实现百度贴吧无限顶贴技巧
  8. 噪声估计的主要方法简要概述
  9. 向github账号和gitee账号添加ssh key
  10. 织梦dede 后台“标题织梦内容管理系统”修改方法