系统全局变量 errno 是如何获得 errno.h 中的值的呢?

2023-05-16

很多时候我们在使用 errno 的时候都知道它代表的是 errno.h 中的错误值,可是为什么它就是代表那些值的呢?系统在哪里给它赋值了呢?故事就要从源头开始:
1、errno 全局变量是在哪里定义的?
答:既然是 errno,那一定是和 err 有关的,搜索发现就在 <bits/errno.h> 中有这么一段说明:
# ifndef __ASSEMBLER__
/* Function to get address of global `errno' variable.  */
extern int *__errno_location (void) __THROW __attribute__ ((__const__));

#  if !defined _LIBC || defined _LIBC_REENTRANT
/* When using threads, errno is a per-thread value.  */
#   define errno (*__errno_location ())
#  endif
# endif /* !__ASSEMBLER__ */
#endif /* _ERRNO_H */
其他先不管,首先我们找到了一个头,那就是 errno 就是 (*__errno_location()),说白了就是函数 __errno_location() 的 返回值 ,结合前面知道 errno 是 int 型整数 ,线索慢慢开始了
2、我们开始去 glibc 即 Linux 源代码中查找 __errno_location() 函数,结果在 errno-loc.c 中有了解释,就一段:
#include <errno.h>
#include <hurd/threadvar.h>

int *
__errno_location (void)
{
  return (int *) __hurd_threadvar_location (_HURD_THREADVAR_ERRNO);
}
strong_alias (__errno_location, __hurd_errno_location)
libc_hidden_def (__errno_location)
意思很明确我 __errno_location() 函数的返回值就是 __hurd_threadvar_location (_HURD_THREADVAR_ERRNO) 函数的返回值被强转成 int * 了,那 __hurd_threadvar_location (_HURD_THREADVAR_ERRNO) 又是什么函数呢?
3、同样搜索 __hurd_threadvar_location 函数,结果没找到,怎么办?通过查看 __errno_location() 函数头文件发现 <hurd/threadvar.h> 似乎好像有点关系,直接找到查看发现这么一段:
#include <machine-sp.h>		/* Define __thread_stack_pointer.  */

/* Return the location of the current thread's value for the
   per-thread variable with index INDEX.  */

extern unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index) __THROW
     /* This declaration tells the compiler that the value is constant
	given the same argument.  We assume this won't be called twice from
	the same stack frame by different threads.  */
     __attribute__ ((__const__));

_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location (enum __hurd_threadvar_index __index)
{
  return __hurd_threadvar_location_from_sp (__index,
					    __thread_stack_pointer ());
}
这是先定义了函数同时在下面直接就给出了函数代码,这个函数的又是调用了 __hurd_threadvar_location_from_sp (__index, __thread_stack_pointer ()) 这个函数,还有一点 _HURD_THREADVAR_H_EXTERN_INLINE 这是什么?(这个其实可以忽略的,因为前面声明了函数是 extern unsigned long int *
注*:在前面有定义
#define _HURD_THREADVAR_H_EXTERN_INLINE extern __inline
了解到其实就是 extern __inline ,其中 ___inline 表示函数是内联函数,没其他功效,在这里我们直接忽略
4、我们同样在<hurd/threadvar.h> 中往前看,有这样的代码:
extern unsigned long int *__hurd_threadvar_location_from_sp
  (enum __hurd_threadvar_index __index, void *__sp);
_HURD_THREADVAR_H_EXTERN_INLINE unsigned long int *
__hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index,
				   void *__sp)
{
  unsigned long int __stack = (unsigned long int) __sp;
  return &((__stack >= __hurd_sigthread_stack_base &&
	    __stack < __hurd_sigthread_stack_end)
	   ? __hurd_sigthread_variables
	   : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) +
				    __hurd_threadvar_stack_offset))[__index];
}

真相似乎已经越来越近了,我们只需要弄清楚一下内容,结果就呼之欲出了:
  1. __hurd_threadvar_index __index 是什么?
  2. __sp 是一个 void * 指针?
  3. __hurd_sigthread_stack_base 是什么?
  4. __hurd_sigthread_stack_end 是什么?
  5. __hurd_sigthread_variables 是什么?
  6. __hurd_threadvar_stack_mask 是什么?
  7. __hurd_threadvar_stack_offset 是什么?
5、往前有定义
enum __hurd_threadvar_index
  {
    _HURD_THREADVAR_MIG_REPLY,	/* Reply port for MiG user stub functions.  */
    _HURD_THREADVAR_ERRNO,	/* `errno' value for this thread.  */
    _HURD_THREADVAR_SIGSTATE,	/* This thread's `struct hurd_sigstate'.  */
    _HURD_THREADVAR_DYNAMIC_USER, /* Dynamically-assigned user variables.  */
    _HURD_THREADVAR_MALLOC,	/* For use of malloc.  */
    _HURD_THREADVAR_DL_ERROR,	/* For use of -ldl and dynamic linker.  */
    _HURD_THREADVAR_RPC_VARS,	/* For state of RPC functions.  */
    _HURD_THREADVAR_LOCALE,	/* For thread-local locale setting.  */
    _HURD_THREADVAR_CTYPE_B,	/* Cache of thread-local locale data.  */
    _HURD_THREADVAR_CTYPE_TOLOWER, /* Cache of thread-local locale data.  */
    _HURD_THREADVAR_CTYPE_TOUPPER, /* Cache of thread-local locale data.  */
    _HURD_THREADVAR_MAX		/* Default value for __hurd_threadvar_max.  */
  };
再从前面 __hurd_threadvar_location (_HURD_THREADVAR_ERRNO) 传过来的参数,知道 __hurd_threadvar_location_from_sp (enum __hurd_threadvar_index __index, void *__sp) 函数第一个参数是 _HURD_THREADVAR_ERRNO ,第二个参数在 __sp 指向 __thread_stack_pointer () 函数的返回值,查询 <machine-sp.h> 有如下:

_EXTERN_INLINE void *
__thread_stack_pointer (void)
{
  register void *__sp__;
  __asm__ ("mr %0, 1" : "=r" (__sp__));
  return __sp__;
}
关于以上的返回值,不好意思目前还没学到看不懂,后期接触到了补上。
6、继续 cdefg 中的变量在前面声明了:
extern unsigned long int __hurd_threadvar_stack_mask;
extern unsigned long int __hurd_threadvar_stack_offset;
extern unsigned long int __hurd_threadvar_stack_mask;
extern unsigned long int __hurd_threadvar_stack_offset;
extern unsigned long int __hurd_sigthread_stack_base;
extern unsigned long int __hurd_sigthread_stack_end;
extern unsigned long int *__hurd_sigthread_variables;
以下是上面变量的注释:
/* The per-thread variables are found by ANDing this mask
   with the value of the stack pointer and then adding this offset.

   In the multi-threaded case, cthreads initialization sets
   __hurd_threadvar_stack_mask to ~(cthread_stack_size - 1), a mask which
   finds the base of the fixed-size cthreads stack; and
   __hurd_threadvar_stack_offset to a small offset that skips the data
   cthreads itself maintains at the base of each thread's stack.

   In the single-threaded case, __hurd_threadvar_stack_mask is zero, so the
   stack pointer is ignored; and __hurd_threadvar_stack_offset gives the
   address of a small allocated region which contains the variables for the
   single thread.  */

/* A special case must always be made for the signal thread.  Even when there
   is only one user thread and an allocated region can be used for the user
   thread's variables, the signal thread needs to have its own location for
   per-thread variables.  The variables __hurd_sigthread_stack_base and
   __hurd_sigthread_stack_end define the bounds of the stack used by the
   signal thread, so that thread can always be specifically identified.  */

/* At the location described by the two variables above,
   there are __hurd_threadvar_max `unsigned long int's of per-thread data.  */
没时间翻译了
7、解释一下 return &((__stack >= __hurd_sigthread_stack_base && __stack < __hurd_sigthread_stack_end) ? __hurd_sigthread_variables : (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index] 的意思:
首先返回一个地址
该地址要么是 __hurd_sigthread_variables 要么是 (unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index]
如果 __hurd_sigthread_stack_base<=__stack < __hurd_sigthread_stack_end 为真,则取前者的地址,否者取后者的地址
__stack & __hurd_threadvar_stack_mask 这是一个二进制 与 运算
(unsigned long int *) ((__stack & __hurd_threadvar_stack_mask) + __hurd_threadvar_stack_offset))[__index] 等同于 (unsigned long int *)(&__hurd_threadvar_stack_offset[__stack & __hurd_threadvar_stack_mask][_HURD_THREADVAR_ERRNO])






本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

系统全局变量 errno 是如何获得 errno.h 中的值的呢? 的相关文章

  • Leetcode每日一题——“回文数”

    各位CSDN的uu们 xff0c 你们好呀 xff0c 今天小雅兰又来刷力扣啦 xff0c 今天的题目是回文数 xff0c 下面 xff0c 让我们进入回文数的世界吧 示例 1 xff1a 输入 xff1a x 61 121 输出 xff1
  • 【社区图书馆】《新程序员005:开源深度指南 & 新金融背后的科技力量》

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰来给大家推荐一本书 xff0c 此书的书名为新程序员005 xff1a 开源深度指南 amp 新金融背后的科技力量 xff0c 为什么小雅兰今天要给大家推荐这样一本书呢 xf
  • Nodejs快速搭建简单的HTTP服务器,并发布公网远程访问

    文章目录 前言1 安装Node js环境2 创建node js服务3 访问node js 服务4 内网穿透4 1 安装配置cpolar内网穿透4 2 创建隧道映射本地端口 5 固定公网地址 转载自内网穿透工具的文章 xff1a 使用Node
  • Leetcode每日一题——“合并两个有序数组”

    各位CSDN的uu们你们好呀 xff0c 又到小雅兰的愉快题解时候啦 xff0c 今天 xff0c 我们的题目内容是合并两个有序数组 xff0c 下面 xff0c 让我们进入合并两个有序数组的世界吧 示例 1 xff1a 输入 xff1a
  • Leetcode每日一题——“链表的中间结点”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰愉快的刷题内容是链表的中间结点 嘿嘿 xff0c 小雅兰的单链表还在偷懒ing xff0c 一直没有更新 xff0c 最近应该会更新出来 下面 xff0c 就让我们进入链表的
  • VRPN-体验

    VRPN简介 VRPN提供封装在库里的一套类 xff0c 在VR系统中 xff0c 用来为应用程序和物理外设提供网络传输接口 详细点击这里 VRPN源码获取 git clone https github com vrpn vrpn git
  • 单链表——“数据结构与算法”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰的内容终于是我们心心念念的单链表啦 xff0c 这一块呢 xff0c 是一个很重要的部分 xff0c 也是一个对目前的我来说 xff0c 比较困难的部分 xff0c 下面 x
  • springboot服务端接口外网远程调试,并实现HTTP服务监听【内网穿透】

    文章目录 前言1 本地环境搭建1 1 环境参数1 2 搭建springboot服务项目 2 内网穿透2 1 安装配置cpolar内网穿透2 1 1 windows系统2 1 2 linux系统 2 2 创建隧道映射本地端口2 3 测试公网地
  • MCSM面板一键搭建我的世界服务器-外网远程联机【内网穿透】

    文章目录 前言1 Mcsmanager安装2 创建Minecraft服务器3 本地测试联机4 内网穿透4 1 安装cpolar内网穿透4 2 创建隧道映射内网端口 5 远程联机测试6 配置固定远程联机端口地址6 1 保留一个固定TCP地址6
  • 初识MySQL数据库——“MySQL数据库”

    各位CSDN的uu们你们好呀 xff0c 小雅兰好久没有更文啦 xff0c 确实是心有余而力不足 xff0c 最近学习的内容太难了 xff0c 这篇博客又是小雅兰的新专栏啦 xff0c 主要介绍的是一些MySQL数据库的知识点 xff0c
  • Windows10本地搭建网站教程【内网穿透】

    文章目录 概述1 搭建一个静态Web站点2 本地浏览测试站点是否正常3 本地站点发布公网可访问3 1 安装cpolar内网穿透3 2 创建隧道映射公网地址3 3 获取公网URL地址 4 公网远程访问内网web站点5 配置固定二级子域名5 1
  • MySQL环境搭建——“MySQL数据库”

    各位CSDN的uu们你们好呀 xff0c 小雅兰又来啦 xff0c 好久没有更文啦 xff0c 今天继续 xff01 xff01 xff01 今天小雅兰的内容是MySQL环境搭建 xff0c 下面 xff0c 让我们进入MySQL数据库的世
  • 在树莓派上搭建WordPress博客网站【内网穿透】

    文章目录 概述安装 PHP安装MySQL数据库安装 Wordpress设置您的 WordPress 数据库设置 MySQL MariaDB创建 WordPress 数据库 WordPress configuration将WordPress站
  • 双链表——“数据结构与算法”

    各位CSDN的uu们你们好呀 xff0c 今天 xff0c 小雅兰又回来了 xff0c 到了好久没有更新的数据结构与算法专栏 xff0c 最近确实发现自己有很多不足 xff0c 需要学习的内容也有很多 xff0c 所以之后更新文章可能不会像
  • Windows在外远程桌面控制macOS【macOS自带VNC远程】

    文章目录 前言1 测试局域网内远程控制1 1 macOS打开屏幕共享1 2 测试局域网内VNC远程控制 2 测试公网远程控制2 1 macOS安装配置cpolar内网穿透2 2 创建tcp隧道 xff0c 指向5900端口 3 测试公网远程
  • 初学正点原子Ministm32板串口实验

    本章将实现如下功能 xff1a STM32 通过串口和上位机的对话 xff0c STM32 在收到上位机发过来的字符串后 xff0c 原原本本的返回给上位机 本章分为如下几个小节 xff1a 1 STM32串口简介 2 硬件设计 3 软件设
  • Qt网络通信实战(聊天室小项目TCP实现)

    一 UDP与TCP的区别 用一个表格来显示这两者的区别 比较项TCPUDP是否连接面向连接无连接传输是否可靠可靠不可靠流量控制提供不提供工作方式全双工可以是全双工应用场合大量数据少量数据速度慢 快 我们这里采用TCP 当有新的连接出现时就会
  • 常用坐标系及坐标系之间的变换

    坐标系统 xff1a 有哪些坐标系 xff0c 他们之间的变换矩阵是怎样的 xff1f xff08 主要是3个坐标系 3 个角 xff09 地理坐标系 xff08 n系 xff09 坐标系原点On取为飞行器质心 Xn轴向指向北 xff0c
  • ulimit命令用法详解

    ulimit用来限制每个用户可使用的资源 xff0c 如CPU 内存 句柄等 一 用法 ulimit SHacdefilmnpqrstuvx 限制 参数详解 S xff1a 表示软限制 超出设定的值会告警 H xff1a 表示硬限制 xff
  • java的数组反转

    Java中数组反转一般有两个思路 xff0c 第一个是新建一个临时数组 xff0c 把原来的数组内各值倒着给放进去 public class ArrayReverse public static void main String args

随机推荐

  • Ardupilot移植经验分享(1)

    目录 前言背景为什么写这篇文章移植Ardupilot的方法有两种底层适配提取应用层代码两种方法对比 准备阅读源码阅读官方开发者wiki选择编译平台下载编译源代码切换版本的正确方式编译老版本手动下载编译器修改PATH配置配置ubuntu以支持
  • 国产UOS系统之——安装wxPython

    安装依赖库 xff1a sudo apt get install libgtk 3 dev sudo apt get install libcanberra gtk module sudo apt get install pkg confi
  • OpenHarmonyllvm交叉编译工具链编译介绍

    一 工具链基础介绍 1 1 工具链下载 repo init u https gitee com OpenHarmony manifest git b master m llvm toolchain xml repo sync c repo
  • 一键配置Ubuntu的OpenHarmony基础编译环境

    一键配置Ubuntu的OpenHarmony基础编译环境 一 配置前说明 该更新源仅适用于Ubuntu以下系列 Ubuntu18 04 Ubuntu20 04 Ubuntu22 04 强烈推荐Ubuntu20 04 xff0c 本人使用的一
  • 卸载Proteus后再次安装出错解决办法

    相信有人和我一样 xff0c 在卸载Proteus后再次安装时会跳过下图这一步 然后安装完了注册时会弹出修改注册 LICENCE失败 xff0c 从而导致破解不成功 xff0c 怎么办呢 xff1f 本人解决方法 xff1a 1 首先正常安
  • STM32cubeMx来对单片机串口1进行初始化

    步骤如下 xff1a 打开STM32CubeMX软件并新建一个工程在Pinout amp Configuration选项卡中选择正确的芯片型号 xff0c 然后在Pinout视图中找到串口1相关的引脚 默认情况下 xff0c 串口1使用PA
  • Keil 头文件源程序代码——Math.h

    MATH H Prototypes for mathematic functions Copyright c 1988 2002 Keil Elektronik GmbH and Keil Software Inc All rights r
  • Keil头文件代码—Absacc

    ABSACC H Direct access to 8051 extended 8051 and NXP 8051MX memory areas Copyright c 1988 2010 Keil Elektronik GmbH and
  • reg52.h中直接定义了P3^4等引脚,但是P1^5引脚没有明确表示出来?

    实际上reg52 h中已经定义了 34 sfr P0 61 0x80 sfr P1 61 0x90 sfr P2 61 0xA0 sfr P3 61 0xB0 34 等引脚的地址 xff0c 如果取P1 5的引脚 xff0c 只需要表示成
  • 关于scanf很多人不知道的小秘密

    今天忽然想到一个问题 xff0c 假如我利用scanf想给变量a输入一个 d的整数 xff0c 结果不小心输入了一个字符串yf或者是123ff后会怎么样呢 xff1f 哈哈 xff0c 自己测试了一下 xff0c 结果发现 xff0c 当你
  • 关于sizeof(*p+1)的那些事

    今天老铁在写程序时发现一个意外 xff0c 在char a 61 1 3 5 7 9 p 61 a 程序求sizeof p 43 1 时遇到一些意外 xff0c 本来以为会是1 xff0c 结果却出意料的是4 xff0c 这就有些尴尬了 x
  • 求解完数

    完数的定义 xff1a 一个数如果恰好等于它的因子之和 xff0c 这个数就称为 完数 例如 xff1a 6 61 1 xff0b 2 xff0b 3 如果需要求解1000或者10000以内的所有完数 xff0c 怎么做呢 xff1f 分析
  • 查找100-200以内素数

    只能被1和其本身整除的数称为素数 xff0c 1不是素数 xff0c 因为简单 xff0c 所以不做解释 xff0c 直接上程序 源代码如下 xff1a Search all prime numbers from 101 to 200 in
  • 实现4个按键控制8个LED灯1个数码管程序

    按要求C语言编程 xff0c 实现4个按键控制8个LED灯1个数码管程序 具体要求如下 xff1a 1 按键一 xff0c 清零作用 无论数码管以前显示何内容 xff0c 都归零 xff0c 显示0 xff1b 2 按键二 xff0c 加一
  • Linux 关机/重启指令

    Linux系统下关机指令只有root用户终端才能下达 xff08 Linux里切换用户可以用 su root 输入密码便进入 root 用户 xff09 xff0c 同时其他终端也会接收到 如root用户发出关机指令 其他终端也会收到相应的
  • C 语言中的goto、 break 和 continue 语句使用

    一 goto 语句 goto 语句为无条件跳转 xff0c goto 语句后面带一个标识符 xff0c 该标识符是同一个函数 内某条语句的标号 标号可以出现在任何可执行语句的前面 xff0c 并且以一个冒号 xff1a 作为后缀 gt Fi
  • 云台控制协议VISCA、PELCO-D、PELCO-P

    原 云台控制协议VISCA PELCO D PELCO P 2013年12月02日 18 42 21 autowanglei 阅读数 xff1a 10146 更多 lt div class 61 34 tags box space 34 g
  • 目录和文件权限与 umask 关系

    一 权限 文件权限 xff1a r xff1a 读取文件内容的权限 w xff1a 新增 修改和删除文件内容的权限 x xff1a 执行文件的权限 例如 xff1a 一个文件a sh xff0c 它的权限是rw xff0c 使用 a sh
  • open 函数的 flag 参数和错误代码

    一 flag 参数 定义头文件 xff1a lt bits fcntl linux h gt 必选参数说明 xff1a define O ACCMODE 0003 xff1a 读写文件操作时取出 flag 的低两位 define O RDO
  • 系统全局变量 errno 是如何获得 errno.h 中的值的呢?

    很多时候我们在使用 errno 的时候都知道它代表的是 errno h 中的错误值 xff0c 可是为什么它就是代表那些值的呢 xff1f 系统在哪里给它赋值了呢 xff1f 故事就要从源头开始 1 errno 全局变量是在哪里定义的 xf