首页 > 编程语言 >C++学习------cerrno头文件的作用与源码学习

C++学习------cerrno头文件的作用与源码学习

时间:2022-11-12 16:31:32浏览次数:76  
标签:__ tls 头文件 val get errno C++ 源码 bionic

引言

cerrno是C++对errno.h头文件的封装,里面实现了一个errno宏,返回上一次的错误码。我们来看看这个宏的具体实现以及其背后的原理。

cerrno 头文件

代码位置: ​​www.aospxref.com/android-12.…​

52  int* __errno(void) __attribute_const__;
53
54 /**
55 * [errno(3)](http://man7.org/linux/man-pages/man3/errno.3.html) is the last error on the calling
56 * thread.
57 */
58 #define errno (*__errno())

可见这个宏的具体实现其实是调用了​​int* __errno(void)​​函数,我们继续追踪

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/bionic/__errno.cpp
32 #include "pthread_internal.h"
33
34 int* __errno() {
35 return &__get_thread()->errno_value;
36 }

这里调用了​​__get_thread()​​函数,获取其对应的​​errno_value​​值,然后取地址返回指针,我们看看这个函数的作用:

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/bionic/pthread_internal.h
197 // Make __get_thread() inlined for performance reason. See http://b/19825434.
198 static inline __always_inline pthread_internal_t* __get_thread() {
199 return static_cast<pthread_internal_t*>(__get_tls()[TLS_SLOT_THREAD_ID]);
200 }

这里实际是通过__get_tls()获取之后,取index为TLS_SLOT_THREAD_ID的元素,格式转换为pthread_internal_t*得到的这个信息,我们先来看看pthread_internal_t的结构定义:

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/bionic/pthread_internal.h
65 class pthread_internal_t {
66 public:
67 class pthread_internal_t* next;
68 class pthread_internal_t* prev;
69
70 pid_t tid;
...
160 bionic_tls* bionic_tls;
161
162 int errno_value;//这个就是我们需要的errno
163 };

对应TLS_SLOT_THREAD_ID的定义,是一个与计算机体系结构相关的量:

72  #if defined(__arm__) || defined(__aarch64__)
...
86 #define TLS_SLOT_THREAD_ID 1
...
97 #elif defined(__i386__) || defined(__x86_64__)
98
99 // x86 uses variant 2 ELF TLS layout, which places the executable's TLS segment
100 // immediately before the thread pointer. New slots are allocated at positive
101 // offsets from the thread pointer.
...
106 #define TLS_SLOT_THREAD_ID 1

继续追踪__get_tls()函数

、、http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/bionic/ndk_cruft.cpp
75 void** __get_tls() {
76 #include "platform/bionic/tls.h"
77 return __get_tls();
78 }

//http://www.aospxref.com/android-12.0.0_r3/xref/bionic/libc/platform/bionic/tls.h
31 #if defined(__aarch64__)
32 # define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
33 #elif defined(__arm__)
34 # define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; })
35 #elif defined(__i386__)
36 # define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; })
37 #elif defined(__x86_64__)
38 # define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
39 #else
40 #error unsupported architecture
41 #endif

到这里其实就已经很明显了,对应我们分析__x86_64__架构的逻辑,定义void**指针__val,通过__asm__汇编语法,​​__asm__("mov %%fs:0, %0" : "=r"(__val));​​这里是将__val作为返回参数,填充到%0的位置,即​​mov %%fs:0, __val​​,即将fs段寄存器偏移为0的地址拷贝给到__val,这里保存了TLS(Thread Local Storage)的信息,当前线程的相关信息都保存在此处,通过后续的转换,即可以得到对应的错误信息。

为什么fs段寄存器会保存TLS的信息?有哪些段寄存器可以使用呢?------这些都是与对应的操作系统架构相关的,通过上面的宏我们可以看到至少有四种不同的获取方式,针对aarch64/arm/i386/x86_64都是使用不同的汇编语句返回其对应的TLS信息。 x86_64架构下面还有如下的段寄存器:

  • cs(Code Segment): 代码段
  • ds(Data Segment): 数据段
  • ss(Stack Segment): 栈段
  • es(Extra Segment): 扩展段
  • fs: 数据段,通常保存动态创建的数据结构
  • gs: 数据段,保存另一个程序共享出来的数据

标签:__,tls,头文件,val,get,errno,C++,源码,bionic
From: https://blog.51cto.com/u_15830688/5846643

相关文章

  • Linux-0.11操作系统源码调试
    学习操作系统有比较好的两种方式,第一种是跟着别人写一个操作系统出来,《操作系统真相还原》、《Orange's:一个操作系统的实现》等书就是教学这个的;另一种方式就是调试操作系......
  • WINDOWS下从源码编译Carla0.9.13+UE4.26
    CARLA是一个开源的自动驾驶模拟器,基于UE4。本篇文章讲述如何在windows系统上从源码编译Carla0.9.13+UE4.26。参考官方文档:https://carla.readthedocs.io/en/0.9.13/build_......
  • 理解C++中 const 在指针中的用法
    intmain(){ int*constarray; constint*array; inta=10; array=&a;//Youcan'texchangearrayself,arrayjustisaintegar// *array=13;//Thisiserror......
  • C++飞机票订票系统
    C++飞机票订票系统题目7飞机票订票系统问题描述:某公司每天有10航班(航班号、价格),每个航班的飞机,共有80个座位,分20排,每排4个位子。编号为A,B,C,D。如座位号:10D表示1......
  • C++一元多项式计算器的设计与实现
    C++一元多项式计算器的设计与实现七、一元多项式计算器的设计与实现1.基于动态数组或者链表实现--元多项式的计算,可以使用STL的vector或者list。2.在系统中需要提供必......
  • 周六900C++班级2022-11-12-搜索练习
    KnightMoves#include<bits/stdc++.h>usingnamespacestd;intnex[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};//方向数组intvis[310][3......
  • 关于Redhat-Linux中-compat-sap-c++软件包的说明
    本文OS版本:RedHatEnterpriseLinuxrelease8.6(Ootpa)还是先说一下compat-sap-c++软件包的作用:InordertorunSAPapplicationscompiledwithcertainnewerGCC......
  • 这些不知道,别说你熟悉 Nacos,深度源码解析!
    SpringCloud应用启动拉去配置我们之前写过一篇文章,介绍了一些Spring提供的扩展机制。其中说到了ApplicationContextInitializer,该扩展是在上下文准备阶段(prepareContext......
  • C++获取毫秒时间戳的方法
    c++std::chrono::millisecondsTimeUtils::CurrentTimeMillis(){returnstd::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock:......
  • C/C++树和图的应用
    C/C++树和图的应用题目三哈夫曼编码/译码系统(树应用)[问题描述]根据哈夫曼编码算法,编写文件压缩及解压缩软件(有图像界面为最佳,无亦可),可对word文件进行压缩,压缩时要......