IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:System Call

共 4 篇相关文章

IT 累计浏览 1,937

如何hook一个系统调用

这篇讲的是如何通过hook系统调用来定位一个隐蔽的bug。作者从一个具体问题出发:他们使用的某个库会断言socket的文件描述符必须大于0,但系统运行一段时间后这个断言会失败,意味着有人错误地关闭了标准输入(fd=0)。 面对这个难题,作者没有选择在每个close调用处手动添加日志(工作量大且易遗漏),而是利用了Linux下动态链接的一个精妙特性:`LD_PRELOAD`。文章详细展示了如何编写一个名为`my_close.c`的共享库,在其中重新定义`close`函数。这个函数会先检查传入的fd是否为0,如果是则直接让程序崩溃(coredump),否则通过`dlsym`获取并调用原始的`close`函数。 通过设置`LD_PRELOAD`环境变量指向这个自定义库,程序在运行时就会优先加载它,从而劫持所有的`close`调用。这样,一旦程序中有代码试图关闭标准输入,就能立刻被定位到。整个过程巧妙地利用了系统机制,将原本需要大范围排查的问题,转化为了一个精准的触发点,是调试动态库和大型程序时一个非常实用的技巧。

IT 累计浏览 3,047

Linux内核文件系统挂载分析

作者从mount系统调用的实现过程入手,聚焦于Linux 3.2.0内核,拆解文件系统挂载的底层机制。文章首先厘清了两个核心数据结构:每个挂载的文件系统都对应一个vfsmount,它维护着文件系统在哈希表、父子关系链表以及名字空间中的位置;path结构则封装了目标挂载点与父文件系统的关联。 核心分析围绕一连串的函数调用展开:系统调用服务例程将参数复制进内核后,便交由do_mount处理。它通过kern_path定位挂载点,随后分发至do_new_mount进行常规挂载。后者的关键步骤是通过do_kern_mount获取源文件系统的vfsmount,并经由do_add_mount执行合法性检查,最终调用graft_tree进行装载。 装载的精髓体现在attach_recursive_mnt中。该函数建立父子映射:让子文件系统的vfsmount指向父vfsmount,并链接到父系统中的挂载点dentry。最后的commit_tree则将这一切“落地”:把新vfsmount置入正确的名字空间链表、全局哈希表以及父文件系统的子文件系统列表中。整个过程清晰地揭示,挂载在内核层面的本质,正是将源文件系统的vfsmount结构以严格的层级关系,嫁接到目标文件系统的目录树之中。

IT 累计浏览 2,512

文件操作函数在VFS层的实现

这是一篇源码分析/实现类的文章,深入内核代码,拆解了open、read、write和close这四个基础文件操作函数在VFS(虚拟文件系统)层的具体实现路径。 文章开篇点明VFS作为统一接口的承上启下作用,随后逐一攻破。例如,对于open,它聚焦于do_sys_open函数,展示了如何从用户空间获取路径、分配文件描述符,到核心的do_filp_open如何查找/创建inode并构建file对象的完整过程。对于read和write,文章对比了它们近乎对称的实现结构:通过fget_light获取file对象,调用vfs_read/vfs_write执行操作,再更新文件偏移量。其中特别剖析了vfs_read如何根据file操作函数集(f_op)中是否存在自定义的read钩子来决定调用驱动层函数还是内核默认的同步读函数,清晰体现了VFS的灵活性与抽象层设计。 最后,close的实现则强调了资源的清理与释放,如调用flush写回缓存、释放锁和file对象。整篇文章通过关键代码段的解析,清晰勾勒出一个系统调用从用户空间下发后,如何在内核VFS层被逐步拆解、调度,最终落地到具体文件系统操作的过程,巧妙之处在于VFS如何通过一套统一的数据结构(如file、inode、f_op函数指针集)和调度逻辑来屏蔽底层差异,为上层提供一致的体验。对于想理解Linux文件I/O内核实现的开发者而言,这篇代码级的走查非常直接且具参考价值。

IT 累计浏览 2,109

使用exit(-1)为什么得到255退出码?

这篇讲的是一个常见的PHP陷阱:为什么在`exec()`函数中使用`exit(-1)`后,捕获到的返回值却是255。作者从微博上一个真实的开发者提问出发,揭示了这个现象背后的系统级原因。 问题的根因在于操作系统对进程退出码的处理方式。在Unix-like系统中,进程的退出码是一个8位的无符号整数(范围0-255)。当PHP执行`exit(-1)`时,-1在计算机中以二进制补码形式表示,其低8位恰好是全1,换算成十进制就是255。所以操作系统忠实地将这个值作为退出状态报告给了父进程。 文章没有止步于解释现象,而是给出了解决方案:要明确传递一个“失败”状态,应使用`exit(1)`(通用的错误码)或者显式地`exit(255)`。对于需要精细错误控制的场景,应查阅系统规范选择0-254之间的可用码。理解这一底层行为,能帮助开发者避免在脚本调用或进程间通信时被意外的返回值困扰,写出更健壮的代码。