哪里的glibc套接字实现在?

时间:2015-12-28 23:53:01

标签: c sockets posix glibc

在glibc 2.22中,在/socket目录中,套接字库实现位于。
但是,当打开任何这些文件时,我看到的只是一个错误设置功能,下面有一些宏 这是一个示例文件(/socket/send.c):

#include <errno.h>
#include <sys/socket.h>

/* Send N bytes of BUF to socket FD.  Returns the number sent or -1.  */
ssize_t
__send (fd, buf, n, flags)
     int fd;
     const __ptr_t buf;
     size_t n;
     int flags;
{
  __set_errno (ENOSYS);
  return -1;
}
libc_hidden_def (__send)
weak_alias (__send, send)

stub_warning (send)

(删除了许可证评论。)

send宏作为参数的weak_alias在哪里?这些宏定义在哪里?
我认为这是由于与一些糟糕的旧编译器的兼容性,但为什么他们仍然使用K&amp; R语法?
最重要的是,为什么 __send 这样定义?

2 个答案:

答案 0 :(得分:6)

这里有几件事情。

首先,如this answer中所述,glibc本身不能定义标准C不保留的随机标识符,因为标准C允许程序自己定义这些标识符。以双下划线开头的名称是为实现保留的,因此这里的实现定义了函数__send()。弱别名允许使用名称send()来引用它,但也允许该引用被其他地方的强定义覆盖。

其次,正如in the glibc documentation所解释的,为了便于移植glibc,需要任何特定于机器的函数具有相应的泛型函数。如果可以编写相应的泛型函数,那么它应该是,但如果不是,那么泛型函数应该是“存根函数”,它基本上只是将errno设置为ENOSYS(未实现)并返回一个错误。如果提供了特定于机器的功能,则将使用该功能代替存根功能。由于send()需要系统调用,显然它不能以与机器无关的方式编写,因此这里有一个存根函数。因此,您应该能够找到__send()的机器特定实现(或其中的各种实现),例如,在glibc源代码树中的/sysdeps/unix/sysv/linux/x86_64/send.c

顺便说一句,由于send()确实是一个系统调用,所以你通常会在glibc中看到的是一个简短的汇编语言例程,它会调用系统。实际做的东西的代码将存在于内核中。

答案 1 :(得分:3)

通常,sendbindsocket等套接字函数是系统调用,这意味着它们直接由操作系统提供。请注意,在unix系统上,您将man 2 socketman 3 fopen进行比较。前者是系统调用,后者是库函数。所以glibc没有提供任何功能,这就是为什么你在glibc源代码中找不到实现的原因。

关于__sendweak_alias,正在发生的是glibc正在从send__send创建弱约束这基本上意味着如果你调用send并且没有其他可用的实现,你将得到glibc的__send。这只是返回ENOSYS,因为没有可用的实现。如果有真正的实现,它将覆盖弱绑定。

sysdeps目录是完成包装系统调用所有脏工作的地方。例如,查看sysdeps/unix/sysv/linux/x86_64/syscalls.list,您将看到从C函数调用到该操作系统和体系结构的OS系统调用的映射。查看同一目录中的syscall.S,您将看到系统调用是如何实际制作的。简而言之,没有真正的用户级代码实现系统调用,libc实现将与系统调用关联的数字放在寄存器中,然后执行syscall指令。所有真正的实现都在内核中。