socket函数到系统调用的过程

linux应用程序使用C运行GNUglibc读者可以GNU官方网站下载源码文件也可以Linux 发布网站www.kernel.org 下载本书例子使用glibc版本2.3.6

服务器程序客户端程序调用函数均可glibc源码找到例如服务器程序调用socket函数读者就可以打开目录glibc-2.3.6 socket.c 文件

#include <errno.h>

#include <sys/socket.h>int __socket(domain, type, protocol)

int domain;

int type;

int protocol;

{

__set_errno(ENOSYS);

return -1;

}

weak_alias(__socket, socket)

stub_warning(socket)

#include <stub-tag.h>

#define weak_alias(name, aliasname) __weak_alias(name, aliasname)

#define _weak_alias(name, aliasname)

extern __typedef(name) aliasname __attribute__ ((weak, alias(#name)))

代码清淡1.2并没有socket()函数声明取而代之是使用weak_aliasocket 声明一个函数别名__socket 因此_socket函数就是函数socket()

Weak AliasGCC编译器扩展内容制定了函数weak属性因而glibc会经常使用weak_alias 指定库函数 编译glibc函数别名 属性保存weak symbol 这种用法可以其它定义真实_socket函数编译器自动识别哪个真实定义这里_socket()真实定义汇编语言实现读者可以额打开目录glibc-2.3.6/sys=deps/unix/sysv/linux/i386

ENTRY(__socket)

.....

movl $SYS_ify(socketcall), %eax

movl $P(SOCKOP_, socket), %ebx

lea 4(%esp), %ecx //Address of args is 2nd arg

/**Do the system call trap/

ENTER_KERNEL

//对于使用i286系统内核来说,ENTER_KERNEL SYS_ify声明如下

#define ENTER_KERNEL int $0x80 系统调用中断

#define SYS_ify(syscall_name);

#define P(a, b) P2(a, b)

#define P2(a, b) a##b

汇编代码替换一下

ENTRY (__socket)

movl $__NR_socketcall, %eax //system call number in %eax

//Use ## so socket is a separate token that might be #defined

movl $SOCKOP_socket, %ebx

lea 4(%esp), %ecx

//do the system call trap

int $0x80

glibclinux系统编译__NR_socketcall内核include/asm-x86/unistd_32.h 文件中找到定义作为系统调用

#define __NR_socketcall 102

SOCKOP_socket 定义glibc-2.3.6/sysdeps/unix/sysv/linux/socketcall.h

#define SOCKOP _socket

汇编代码这个作为socke调用保存寄存器ebx代码 lea 4, (%esp), %ecx调用socket参数地址保存到寄存器ecx

使用寄存器ebx, ecx没有使用堆栈因为系统调用内核空间进入内核空间必然引起堆栈切换这是CPU保护模式要求可是寄存器用于传值数量毕竟有限因此对于服务器程序传递3参数AF_INET, SOCK_STREAM,0 采取传递指针形式指针保存到ecx我们后面会看到系统调用要用指针取得每个参数

服务器程序运行调用socket()函数就会执行glibc上述代码从而系统调用102 保存到寄存器eax然后执行int 0x80这个函数也是汇编实现linux内核目录arch/x86/kernel/entry_32.S 文件中

ENTRY(system_call)

syscall_call:

call *sys_call_table(,%eax,4);

代码清淡1.4省去中断执行许多细节以及寄存器传递参数内容system_call最终使用汇编call指令执行sys_call_table 系统调用102函数指针系统调用sys_call_tablearch/x86/kernel/syscall_table_32.S文件中

ENTRY(sys_call_table)

long sys_socketcall 102

备注:这里是32位的系统调用,linux下,32

位编译后参数用栈传递的,64位是用6个寄存器,超出用栈。

参数 + 4是因为执行的返回地址,也压栈了,这里要跳过去。

你可能感兴趣的:(汇编,开发语言)