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_getpeername 7
#define SOCKOP_socketpair 8
#define SOCKOP_send 9
#define SOCKOP_recv 10
#define SOCKOP_sendto 11
#define SOCKOP_recvfrom 12
#define SOCKOP_shutdown 13
#define SOCKOP_setsockopt 14
#define SOCKOP_getsockopt 15
#define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17