TCP/IP - 函数到系统调用的过程

来源:互联网 发布:淘宝店铺首页无法打开 编辑:程序博客网 时间:2024/06/05 04:03

1. 代码运行环境:

glibc:2.3.6

Linux:2.6.26


2. 库函数socket():

glibc-2.3.6/sysdeps/generic中的socket.c文件。

weak_alias()为socket()声明了一个“函数别名”__socket()

glibc库中经常使用weak_alias()指定库函数。

__socket()函数是socket()的真实实现。

__socket()函数使用汇编语言实现,glibc-2.3.6/sysdeps/unix/sysv/linux/i386中的socket.S文件。


3. 汇编函数__socket():

从内核include/asm-x86/unistd_32.h文件中找到系统调用号:

#define __NR_socketcall  102

__socket()将系统调用号102保存到寄存器eax中:

movl $__NR_socketcall, %eax

从glibc-2.3.6/sysdeps/unix/sysv/linux/socketcall.h文件中找到socket()函数的调用号:

#define SOCKOP_socket  1

__socket()将socket()的调用号保存到寄存器ebx中:

movl $SOCKOP_socket, %ebx

__socket()将调用socket()时的参数地址保存到寄存器ecx中:

lea 4(%esp), %ecx

__socket()执行软中断指令到达系统系统调用的总入口system_call()函数:

int $0x80


4. 汇编函数system_call():

定义于Linux内核目录arch/x86/kernel/entry_32.S文件中。

system_call()最终使用汇编call指令执行sys_call_table系统调用表102处的函数指针

call *sys_call_table(, %eax, 4)


5. 系统调用表sys_call_table:

定义在arch/x86/kernel/syscall_table_32.S文件中。

.long sys_socketcall   /* 102 */


6. sys_socketcall()函数:

sys_socketcall()是bind(), socket(), listen(), accept()等函数的系统调用入口,是内核提供给socket通信的总入口。

sys_socketcall()将参数从服务器程序用户空间复制到内核空间:

参数call是具体的socket调用号,存储在寄存器ebx中。

参数args是参数数组指针,由ecx寄存器传递。

参数a为内核空间数组。

需要复制的参数个数由nargs[]数组决定,nargs[]数组在call下标处存储相对应于call调用号的函数的参数个数。

copy_from_user(a, args, nargs[call])

根据系统调用号确定执行函数:

switch(call){case SYS_SOCKET:err = sys_socket(a0, a1, a[2]);}


7. 参数call:

定义在Linux内核include/linux/net.h中。

定义在glibc库的sysdeps/unix/sysv/linux的socketcall.h文件中。

上述两个位置定义完全一致。

#define SYS_SOCKET  1  /* sys_socket(2) */#define SYS_BIND    2  /* sys_bind(2) */


8. 系统调用sys_socket():

socket()库函数对应的系统调用函数为sys_socket()

创建socket:

sock_create(family, type, protocol, &sock);

与文件系统建立关联,为新建的socket在网络文件系统中申请文件号和文件描述符结构:

sock_map_fd(sock);


9. 调用流程:

socket() -> __socket() -> system_call() -> sys_socketcall() -> sys_socket()

原创粉丝点击