一文解决网络系统调用接口到内核的请求

news2025/4/7 4:27:03

网络套接字入口函数

//所有的网络套接字系统调用函数(socket bind listen connect )都使用一个共同的入口函数:sys_socketcall
/*
第一个参数call表示被调用的应用层接口函数,第二个参数是一个指针,指向具体被调用函数(如accept函数)所需要的参数。
这些在用户系统调用时传入的参数将原封不动地传递给内核网络栈相关底层函数使用
*/
asmlinkage int sys_socketcall(int call, unsigned long *args)

{
int er;
switch(call)
{
case SYS_SOCKET:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_socket(get_fs_long(args+0),
get_fs_long(args+1),
get_fs_long(args+2)));
case SYS_BIND:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_bind(get_fs_long(args+0),
(struct sockaddr *)get_fs_long(args+1),
get_fs_long(args+2)));
case SYS_CONNECT:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_connect(get_fs_long(args+0),
(struct sockaddr *)get_fs_long(args+1),
get_fs_long(args+2)));
case SYS_LISTEN:
er=verify_area(VERIFY_READ, args, 2 * sizeof(long));
if(er)
return er;
return(sock_listen(get_fs_long(args+0),
get_fs_long(args+1)));
case SYS_ACCEPT:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_accept(get_fs_long(args+0),
(struct sockaddr *)get_fs_long(args+1),
(int *)get_fs_long(args+2)));
case SYS_GETSOCKNAME:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_getsockname(get_fs_long(args+0),
(struct sockaddr *)get_fs_long(args+1),
(int *)get_fs_long(args+2)));
case SYS_GETPEERNAME:
er=verify_area(VERIFY_READ, args, 3 * sizeof(long));
if(er)
return er;
return(sock_getpeername(get_fs_long(args+0),
(struct sockaddr *)get_fs_long(args+1),
(int *)get_fs_long(args+2)));
case SYS_SOCKETPAIR:
er=verify_area(VERIFY_READ, args, 4 * sizeof(long));
if(er)
return er;
return(sock_socketpair(get_fs_long(args+0),
get_fs_long(args+1),
get_fs_long(args+2),
(unsigned long *)get_fs_long(args+3)));
case SYS_SEND:
er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
if(er)
return er;
return(sock_send(get_fs_long(args+0),
(void *)get_fs_long(args+1),
get_fs_long(args+2),
get_fs_long(args+3)));
case SYS_SENDTO:
er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
if(er)
return er;
return(sock_sendto(get_fs_long(args+0),
(void *)get_fs_long(args+1),
get_fs_long(args+2),
get_fs_long(args+3),
(struct sockaddr *)get_fs_long(args+4),
get_fs_long(args+5)));
case SYS_RECV:
er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long));
if(er)
return er;
return(sock_recv(get_fs_long(args+0),
(void *)get_fs_long(args+1),
get_fs_long(args+2),
get_fs_long(args+3)));
case SYS_RECVFROM:
er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long));
if(er)
return er;
return(sock_recvfrom(get_fs_long(args+0),
(void *)get_fs_long(args+1),
get_fs_long(args+2),
get_fs_long(args+3),
(struct sockaddr *)get_fs_long(args+4),
(int *)get_fs_long(args+5)));
case SYS_SHUTDOWN:
er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long));
if(er)
return er;
return(sock_shutdown(get_fs_long(args+0),
get_fs_long(args+1)));
case SYS_SETSOCKOPT:
er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
if(er)
return er;
return(sock_setsockopt(get_fs_long(args+0),
get_fs_long(args+1),
get_fs_long(args+2),
(char *)get_fs_long(args+3),
get_fs_long(args+4)));
case SYS_GETSOCKOPT:
er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long));
if(er)
return er;
return(sock_getsockopt(get_fs_long(args+0),
get_fs_long(args+1),
get_fs_long(args+2),
(char *)get_fs_long(args+3),
(int *)get_fs_long(args+4)));
default:
return(-EINVAL);
}
}

  资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

套接字系统调用如何到达sys_socketcall

accept函数为例

系统调用中参数从用户态向内核态的传递是通过寄存器完成的,eax表示系统调用,ebx表示第一个参数,ecx表示第二个参数,edx表示第三个参数(主要针对socke.S)

第一层:accept.s文件

(glibc函数库)sysdeps\unis\sysv\linux\accept.S

#define socket accept    //将socket定义为accept
#define _socket _libc_accept
#define NARGS 3           //系统调用的个数
#include <socket.S>     //这几个套接字函数的通用实现

第二层:socket.S文件

#include <sysdep.h>
#include <sys/socketcall.h>

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

.text
/* The socket-oriented system calls are handled unusally in Linux.
  They are all gated through the single `socketcall' system call number.
  `socketcall' takes two arguments: the first is the subcode, specifying
  which socket function is being called; and the second is a pointer to
  the arguments to the specific function.

  The .S files for the other calls just #define socket and #include this. */

.globl P(__,socket)
ENTRY (P(__,socket))

/* Save registers. */
movl %ebx, %edx

movl $SYS_ify(socketcall), %eax/* System call number in %eax. */
//展开$SYS_iff()宏
/* Use ## so `socket' is a separate token that might be #define'd. */
movl $P(SOCKOP_,socket), %ebx/* Subcode is first arg to syscall. */
lea 4(%esp), %ecx/* Address of args is 2nd arg. */

       /* Do the system call trap. */
int $0x80

/* Restore registers. */
movl %edx, %ebx

/* %eax is < 0 if there was an error. */
cmpl $-125, %eax
jae syscall_error

/* Successful; return the syscall's value. */
ret

PSEUDO_END (P(__,socket))
c
weak_alias (P(__,socket), socket)

重点看:

movl $SYS_ify(socketcall), %eax /* System call number in %eax. */

展开SYS_iff()宏(glibc函数库: \sysdeps\unix\sysdep.h)

#ifdef __STDC__
#define SYS_ify(syscall_name) SYS_##syscall_name
#else
#define SYS_ify(syscall_name) SYS_/**/syscall_name
#endif

预处理后为:

movl $SYS_socketcall,%eax
//将系统调用号放入eax中,但是对于网络套接字所有的接口函数而言,他们的共同入口函数是sys_socketcall
//在内核中,总入口函数sys_socketcall的系统调用号为_NR_socketcall,定义在include/linux/unistd.h
#define __NR_socketcall102
//在glib函数库中,有如下的预定义
#define SYS_socketcall _NR_socketcall

所以:

movl $SYS_socketcall,%eax
//将sys_socketcall函数对应的系统调用号赋予eax寄存器,从而使套接字系统调用进入到正常的入口函数中

这样套接字系统调用进入到正确的函数中了。

那么第一个参数是识别系统调用的具体函数的,这个参数在socket.S(glibc库)中:

movl $P(SOCKOP_,socket), %ebx
//预处理后:
movl $SOCKOP_accept,%ebx//这就完成了第一个参数的传递

关于SOCKOP_accept:

查看(glibc库:\sysdeps\unix\sysv\linux\socketcall.h)

#ifndef _SYS_SOCKETCALL_H

#define _SYS_SOCKETCALL_H	1

/* Define unique numbers for the operations permitted on socket.  Linux
   uses a single system call for all these functions.  The relevant code
   file is /usr/include/linux/net.h.
   We cannot use a enum here because the values are used in assembler
   code.  */

#define SOCKOP_socket		1
#define SOCKOP_bind		2
#define SOCKOP_connect		3
#define SOCKOP_listen		4
//可以看到SOCKOP_accept对应的值为5
#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

#endif /* _SYS_SOCKETCALL_H */

在linux内核(include/linux/net.h):

#ifndef _SYS_SOCKETCALL_H

#define _SYS_SOCKETCALL_H	1

/* Define unique numbers for the operations permitted on socket.  Linux
   uses a single system call for all these functions.  The relevant code
   file is /usr/include/linux/net.h.
   We cannot use a enum here because the values are used in assembler
   code.  */

#define SOCKOP_socket		1
#define SOCKOP_bind		2
#define SOCKOP_connect		3
#define SOCKOP_listen		4
//这与glibc库中的SOCKOP_accept对应的值相同
#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

#endif /* _SYS_SOCKETCALL_H */

第二个参数

在socket.S中:以指针的方式设置了sys_socketcall的第二个参数

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

设置完以上的系统调用号还有参数后进入软中断:int $0x80,进入了内核态进行处理

第三层:entry.S文件

_system_call:
	pushl %eax			# save orig_eax
	SAVE_ALL
	movl $-ENOSYS,EAX(%esp)
	cmpl $(NR_syscalls),%eax
	jae ret_from_sys_call
    /*对应上面,未调用软中断之前,eax寄存器中被初始化为系统调用号,即_NR_socketcall,
       这个调用号别用于在_sys_call_table数组中进行函数指针的寻址,将对应的函数地址对eax寄存器赋值      */
	movl _sys_call_table(,%eax,4),%eax
	testl %eax,%eax
	je ret_from_sys_call
	movl _current,%ebx
	andl $~CF_MASK,EFLAGS(%esp)	# clear carry - assume no errors
	movl $0,errno(%ebx)
	movl %db6,%edx
	movl %edx,dbgreg6(%ebx)  # save current hardware debugging status
	testb $0x20,flags(%ebx)		# PF_TRACESYS
	jne 1f
    /*上面给eax复制后,这里进行调用该函数,到这为止,accept系统调用将请求传递给了sys_socketcall,
        然后将socket.S中设置的参数传递给sock_accept函数,就完成了应用层接口函数accept到BSD socket层函数的请求传递工作
        */
	call *%eax
	movl %eax,EAX(%esp)		# save the return value
	movl errno(%ebx),%edx
	negl %edx
	je ret_from_sys_call
	movl %edx,EAX(%esp)
	orl $(CF_MASK),EFLAGS(%esp)	# set carry to indicate error
	jmp ret_from_sys_call

以上源码来自:linux内核源码1.2.12

glibc-2.0.1

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/70914.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【综合案例】原生JS实现购物商城

目录一、案例说明1、目录结构2、conf文件夹3、用户名密码的正则和ajax的封装二、登录页的实现1、案例效果2、登录页逻辑3、接口文档4、代码实现5、返回信息显示三、首页的实现1、案例效果2、首页的逻辑3、接口文档4、代码实现5、返回信息显示四、个人中心1、案例效果2、个人页的…

springboot车辆管理系统的设计与实现毕业设计源码031034

车辆管理系统的设计与实现 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化&#xff0c;电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用。信息时代的到来已成为不可阻挡的时尚潮流&#xff0c;人类发展的历史正进入一个新时代。在现实运用中&…

Runtime源码解析-alloc

Runtime源码解析-alloc 前言alloc 通过汇编查看调用流程1. objc_alloc方法2. callAlloc方法 首次进入非首次进入LLVM优化 3. _objc_rootAllocWithZone方法4. _class_createInstanceFromZone方法 instanceSize&#xff1a;计算内存大小 fastInstanceSizealignedInstanceSize mal…

TS201的DMA通信基本原理以及IIR的加深理解(含源代码)

实验目的&#xff1a; 了解DMA通信基本原理&#xff0c;掌握内存与SDRAM间一维DMA通信方式、二维DMA通信方式以及相关控制方法。学习数字滤波器设计方法&#xff0c;掌握其调试步骤&#xff0c;使学生加深对IIR的理解&#xff0c;进一步提高对数字信号处理理论的认识。 实验任…

Java+SSM美妆商城全套电商购物(含源码+论文+答辩PPT等)

项目功能简介: 本项目含代码详细讲解视频&#xff0c;手把手带同学们敲代码从0到1完成项目 该项目采用技术Springmvc、Spring、MyBatis、Tomcat服务器、MySQL数据库 项目含有源码、配套开发软件、软件安装教程、项目发布教程以及代码讲解教程 项目功能介绍&#xff1a; 系统管理…

[附源码]计算机毕业设计酒店物联网平台系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

国标码的发展历史以及编码方式

文章目录引言GB2312GBKunicode 和 ISO10646ISO10646的编码结构结论参考文献引言 由于物理实现比较容易等原因计算机等数字系统内部使用二进制字符的记录、存贮、传递和交换通过编码来实现。字符的机内编码其实就是该字符在字符图库中的序号。拼音文字一般仅有几十个字母组成。而…

【传输层】TCP、三次握手、四次挥手、可靠传输、TCP拥塞控制、慢开始、拥塞避免、快重传、快恢复

文章目录TCP------打电话----可靠有序、不丢不重复--------提供全双工-------------发送接收缓存----------面向字节流--------搬砖一样加个头运走TCP首部格式-----源端口目的端口一共4B-------序号字段&#xff08;报文第一个字节的序号&#xff09;--------确认号&#xff08…

手机软件系统测试用例设计大全

一、 等价类分析法 二、 边界值分析 三、 错误猜测法 四、 判定表法 五、 流程分析方法 六、 正交试验设计法 七、 状态迁移法 等价类分析法等价类划分方法针对手机状态大致可以归几个大类&#xff1a; 按键类&#xff08;等价法&#xff09;&#xff1a;有效输入和无效…

python在Keras中使用LSTM解决序列问题

时间序列预测是指我们必须根据时间相关的输入来预测结果的问题类型。时间序列数据的典型示例是股市数据&#xff0c;其中股价随时间变化。 最近我们被客户要求撰写关于LSTM的研究报告&#xff0c;包括一些图形和统计输出。 递归神经网络&#xff08;RNN&#xff09;已被证明可…

D-026 LVDS硬件电路设计

LVDS硬件接口电路设计1 简介2 硬件设计实战3 硬件设计要点4 Layout注意事项5 MIPI与LVDS的区别1 简介 LVDS&#xff08;Low-Voltage Differential Singnaling&#xff0c;低电压差分信号&#xff09;可以实现点对点或者一点对多点的连接&#xff0c;具有低功耗、低误码率、低串…

蓝桥杯比赛 NOC竞赛C++项目,选择题真题和模拟题汇总答案解析

题目来源&#xff1a;第10届蓝桥杯青少年组C选拔赛 1、下面哪个密码最安全 D A. 111111 B. 123456 C. qwerty D. Z2a8Q1 2、如果今天是星期六&#xff0c;再过60天是星期几&#xff1f;A A. 星期三 B. 星期四 C. 星期五 D. 星期六 3、90到100之间有几个素数&#xff1f…

HTML学生作业网页 传统端午节节日 学生节日网页设计作业源码(HTML+CSS+JS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Android Studio的ADV无法启动解决办法【IDEA 的ADV无法启动解决办法】

Android Studio的ADV无法启动解决办法【IDEA 的ADV无法启动解决办法】 开发者指南:https://developer.android.google.cn/guide 一、BIOS开启Intel VT-x 这一步如果在创建Android项目时&#xff0c;可以启动的话&#xff0c;证明已经开启了&#xff0c;可以忽略 1. 开始菜单&am…

新鲜出炉!阿里内部开源SpringCloud Alibaba全解(全彩版)全网首发

第一章微服务介绍 第二章微服务环境搭建 第三章Nacos Discovery–服务治理 自定义实现负载均衡 第四章Sentinel–服务容错 第五章Gateway–服务网关 Gateway核心架构 第六章Sleuth-链路追踪 ![新鲜出炉&#xff01;阿里内部开源SpringCloud Alibaba全解&#xff08;全彩版&…

基于OpenLayers实现导航地图上(起/终)点的交互式图标显示

目录 1、准备 2、瓦片地图显示 3、增加矢量图层 4、利用click实现鼠标点击效果 在常见的导航软件中&#xff0c;往往都存在标记起/止点的需求。毕竟路径规划中的重要传入参数就是起止点坐标。在常用的不管是移动端还是PC端&#xff0c;导航地图上一般在选择起止点位置会留…

大数据 | Spark安装及测试

一、安装 Spark On Yarn 在公司中&#xff0c;通常采用Yarn进行资源调度&#xff0c;故此处采用Yarn模式的集群部署。 采用Yarn部署模式时&#xff0c;需要保证集群中已经安装好Hadoop集群&#xff0c;在此基础上才能实现Yarn模式的部署。 在Yarn模式中&#xff0c;Spark应用…

Python学习-8.2.1 库(jieba库的基础与实例-中文分词库)

jieba库的安装见上篇&#xff1a;Python学习-8.库&#xff08;第三方库介绍与下载安装&#xff09; jieba库概述 由于中文文本中的单词不像英文那样&#xff0c;并不是根据空格或者标点符号进行分割的&#xff0c;而是存在一个重要的分词问题。因此引入了jieba库。 分词原理&…

chrome Google无法翻译?腾讯已经出手了,一劳永逸!

谷歌翻译中国版和谷歌地图中国版同时停服&#xff0c;此次停服也影响到谷歌浏览器翻译功能的使用。谷歌给出的官方回应是谷歌翻译和谷歌地图的中国版使用率都太低&#xff0c;既然使用率太低那直接停服也情有可原&#xff08;笑笑&#xff09;。 只是谷歌浏览器内置的翻译功能…

前端开发:JS中使用到的贪心算法场景

前言 在前端开发过程中&#xff0c;除了一般的逻辑使用之外&#xff0c;也会涉及到算法相关的知识&#xff0c;比如冒泡排序、数组去重/合并、贪心算法、八皇后算法等等&#xff0c;这些都是比较常用的前端算法相关的知识点。关于前端实际开发中用到的算法&#xff0c;虽然没有…