| 2009年10月11日
glibc-2.9, linux-2.6.32-rc1 在查看系统调用的时候发现: 关于网络的系统调用只有一个socketcall:
/usr/include/asm/unistd_32.h
#define __NR_socketcall 102
而这个系统调用的调用实现是在glibc中: 在glibc中socket的实现实在这里: sysdeps/unix/sysv/linux/i386/socket.S 对这个文件稍后分析,先看其它的函数: 而其它的网络相关函数都在这里定义:
2 F d socket sysdeps/unix/sysv/linux/accept.S
#define socket accept
3 F d socket sysdeps/unix/sysv/linux/bind.S
#define socket bind
。。。。其它还有:
#define socket connect
#define socket getpeername
#define socket getsockname
#define socket getsockopt
#define socket listen
#define socket recv
#define socket recvfrom
#define socket recvmsg
#define socket sendmsg
#define socket sendto
#define socket setsockopt
。。。。
而其中每个.S文件中的内容几乎一致,下面只取几个说明一下:
#define socket bind
#define NARGS 3 //这个是说它的参数的个数
#define NO_WEAK_ALIAS 1 //这个是说这个没有其它的别名
#include <socket.S>
---------------------------------------------------------
#define socket listen
#define NARGS 2
#define NO_WEAK_ALIAS 1
#include <socket.S>
----------------------------------------------------------
#define socket accept
#define __socket __libc_accept //这里还定义了其它的别名
#define NARGS 3
#include <socket.S>
也就是所有的网络系统调用都是基于socket这个系统调用的,只是在调用的时候传递的参数不同而已。
那现在再来具体分析sysdeps/unix/sysv/linux/i386/socket.S: 主要内容如下:
/*这个要在上面定义其它函数中使用,如accept,bind等
*看在上面的具体函数中有些定义了__socket,有些没有,有些定义了NO_WEAK_ALIAS。
*这些都是为选择不同的函数做设置的
*/
#ifndef __socket
# ifndef NO_WEAK_ALIAS
# define __socket P(__,socket)
# else
# define __socket socket
# endif
#endif
.globl __socket
ENTRY (__socket)
#if defined NEED_CANCELLATION && defined CENABLE
SINGLE_THREAD_P
jne 1f
#endif
/* Save registers. */
movl %ebx, %edx
cfi_register (3, 2)
movl $SYS_ify(socketcall), %eax /* System call number in %eax. */
/* Use ## so `socket' is a separate token that might be #define'd. */
/* 这个号是来区别调用那个具体函数的,是socket还是bind
*这里的socket的具体值是会发生变化的,就是在上面的#define socket bind
*这样类似的语句中变换这个socket的值,关于其具体的值在后面给出
*/
movl $P(SOCKOP_,socket), %ebx
lea 4(%esp), %ecx /* Address of args is 2nd arg. 这里以堆栈方式传递其它的参数 */
/* 这里进入系统调用,从PII之后的cpu都有两种方式进入系统调用,一种是传统的int 0x80
另一种就是cpu直接提供的指令enter_syscall,所以这里提供了这样一个语句,
而其实这也是通过条件编译的方式将其值为int 0x80或其它方式
*/
ENTER_KERNEL
/* Restore registers. 恢复寄存器 */
movl %edx, %ebx
cfi_restore (3)
/* %eax is < 0 if there was an error. 比较返回值 */
cmpl $-125, %eax
jae SYSCALL_ERROR_LABEL
/* Successful; return the syscall's value. 正常返回 */
L(pseudo_end):
ret
$P(SOCKOP_,socket)的值: sysdeps/unix/sysv/linux/socketcall.h :
#define SOCKOP_socket 1
#define SOCKOP_bind 2
#define SOCKOP_connect 3
#define SOCKOP_listen 4
#define SOCKOP_accept 5
#define SOCKOP_getsockname 6
。。。。
#define SOCKOP_recvmsg 17
#define SOCKOP_paccept 18
还有其内核的实现我们下一篇文章在进行分析。。。
关注「黑光技术」,关注大数据+微服务