glibc定义的系统调用

最近有人问道,glibc 中对我们常见的那些系统调用的定义在哪里?比如write(2)recv(2)

这个问题我以前在看glibc的代码时注意到了。我们通常可以直接找到的所谓定义,比如下面这个:



C:
  1. ssize_t
  2. __libc_write  ( int fd,  const  void  *buf, size_t nbytes )
  3. {
  4.    if  (nbytes  ==  0 )
  5.      return  0;
  6.    if  (fd < 0 )
  7.      {
  8.       __set_errno  (EBADF );
  9.        return  -1;
  10.      }
  11.    if  (buf  ==  NULL )
  12.      {
  13.       __set_errno  (EINVAL );
  14.        return  -1;
  15.      }
  16.  
  17.   __set_errno  (ENOSYS );
  18.    return  -1;
  19. }
  20. libc_hidden_def  (__libc_write )
  21. stub_warning  (write )
  22.  
  23. weak_alias  (__libc_write, __write )
  24. libc_hidden_weak  (__write )
  25. weak_alias  (__libc_write, write )

其实很明显,这并不是真正的定义,至少并不是你想找的那个。这个是什么呢?这个其实是write(2)的一个alias,而且还是weak alias,换句话说也就是,如果一个平台上没有定义自己的write(2),那么就用一个。而且从上面的代码也可以看得出来,这个函数仅仅是处理了一下errno,别的什么都不做。

那真正的定义究竟在哪里?说实话,我当初找到费了一番周折,找到它们并不容易,因为它们是编译时生成的!!可以从下面三个文件中看出来:

sysdeps/unix/make-syscalls.sh
sysdeps/unix/syscalls.list(sysdeps/unix/inet/syscalls.list)
sysdeps/unix/syscall-template.S

syscall-template.S顾名思义是个定义的模板,每个生成的系统调用都要参考这个模板,但是怎么用模板来“刻画”每一个系统调用呢?于是就有了syscalls.list,而make-syscalls.sh就是用模板和那个列表来构建生成系统调用定义的makefile,该makefile最终生成最后的定义。有兴趣的朋友应该仔细看看这几个文件。

现在再想想,这么做其实是有道理的,在Linux下,系统调用的真正定义有很多相似的地方,确实可以通过“模板”来生成对应的汇编,但是否真值得花时间去构建那么抽象的一个模板和框架?我说不清楚,本着“懒惰”的原则确实应该如此,不过看看模板本身似乎原因不仅仅是“懒惰”。

从这里我们也可以看出glibc的代码难读啊,比起Linux内核来,不仅仅是风格的问题,还有就是使用了太多的tricks,导致的结果也很显而易见,参与glibc开发的和参与linux内核开发的人明显不是一个数量级的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值