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

很多时候我们在使用 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])






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值