0

0

Syscall系统调用Linux内核跟踪

WBOY

WBOY

发布时间:2024-02-12 21:21:14

|

826人浏览过

|

来源于良许Linux教程网

转载

linux用户空间中,我们常常需要调用系统调用。下面我们以linux2.6.37版本为例,跟踪一下read系统调用的实现。不同版本的linux系统调用实现可能会有所不同。

Syscall系统调用Linux内核跟踪

在一些应用程序中,我们可以看到如下定义:

scssCopy code
#define real_read(fd, buf, count ) (syscall(SYS_read, (fd), (buf), (count)))

实际上,真正调用的是系统函数syscall(SYS_read),即sys_read()函数。在Linux2.6.37版本中,该函数是通过几个宏定义实现的。

Linux系统调用(SCI,system call interface)实际上是一个多路汇聚以及分解的过程,汇聚点是0x80中断入口点(X86系统结构)。也就是说,所有系统调用都从用户空间中汇聚到0x80中断点,同时保存具体的系统调用号。当0x80中断处理程序运行时,将根据系统调用号对不同的系统调用分别处理,即调用不同的内核函数进行处理。

引起系统调用的途径有两种:

(1)int $0×80,这是老式Linux内核版本中引起系统调用的唯一方式。

(2)sysenter汇编指令

在Linux内核中,我们可以使用下列宏定义来进行系统调用。

知料万语
知料万语

知料万语—AI论文写作,AI论文助手

下载
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
    struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;
}

其中SYSCALL_DEFINE3的宏定义如下:

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

##的意思就是宏中的字符直接替换,
如果name = read,那么在宏中__NR_##name就替换成了__NR_read了。 NR##name是系统调用号,##指的是两次宏展开.即用实际的系统调用名字代替”name”,然后再把__NR…展开.如name == ioctl,则为__NR_ioctl。

#ifdef CONFIG_FTRACE_SYSCALLS
#define SYSCALL_DEFINEx(x, sname, ...)                \
    static const char *types_##sname[] = {            \
        __SC_STR_TDECL##x(__VA_ARGS__)            \
    };                            \
    static const char *args_##sname[] = {            \
        __SC_STR_ADECL##x(__VA_ARGS__)            \
    };                            \
    SYSCALL_METADATA(sname, x);                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#else
#define SYSCALL_DEFINEx(x, sname, ...)                \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
#endif

不管是否定义CONFIG_FTRACE_SYSCALLS宏,最终都会执行 下面的这个宏定义:

__SYSCALL_DEFINEx(x, sname, VA_ARGS)

#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS

#define SYSCALL_DEFINE(name) static inline 
long SYSC_##name

#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));        \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));    \
    asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))        \
    {                                \
        __SC_TEST##x(__VA_ARGS__);                \
        return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));    \
    }                                \
    SYSCALL_ALIAS(sys##name, SyS##name);                \
    static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))

#else /*
 CONFIG_HAVE_SYSCALL_WRAPPERS */

#define SYSCALL_DEFINE(name) asmlinkage 
long sys_##name
#define __SYSCALL_DEFINEx(x, name, ...)                    \
    asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))

#endif /*
 CONFIG_HAVE_SYSCALL_WRAPPERS */

最终会调用下面类型的宏定义:

asmlinkage long sys##name(__SC_DECL##x(VA_ARGS))
也就是我们前面提到的sys_read()系统函数。
asmlinkage通知编译器仅从栈中提取该函数的参数。所有的系统调用都需要这个限定词!这和我们上一篇文章quagga中提到的宏定义,有异曲同工之妙。

也就是宏定义中的下面代码:

struct file *file;
    ssize_t ret = -EBADF;
    int fput_needed;

    file = fget_light(fd, &fput_needed);
    if (file) {
        loff_t pos = file_pos_read(file);
        ret = vfs_read(file, buf, count, &pos);
        file_pos_write(file, pos);
        fput_light(file, fput_needed);
    }

    return ret;

代码解析:

  • fget_light() :根据 fd 指定的索引,从当前进程描述符中取出相应的 file 对象(见图3)。
  • 如果没找到指定的 file 对象,则返回错误
  • 如果找到了指定的 file 对象:
  • 调用 file_pos_read() 函数取出此次读写文件的当前位置。
  • 调用 vfs_read() 执行文件读取操作,而这个函数最终调用 file->f_op.read() 指向的函数,代码如下:

if (file->f_op->read)
ret = file->f_op->read(file, buf, count, pos);

  • 调用 file_pos_write() 更新文件的当前读写位置。
  • 调用 fput_light() 更新文件的引用计数。
  • 最后返回读取数据的字节数。

到此,虚拟文件系统层所做的处理就完成了,控制权交给了 ext2 文件系统层。

相关专题

更多
if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

765

2023.08.22

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

198

2023.11.20

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

358

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

542

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

53

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

197

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

394

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

574

2023.08.10

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.6万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号