linux sys_call_table 初始化

2023-05-16


前几天看内核中系统调用代码,在系统调用向量表初始化中,有下面这段代码写的让我有点摸不着头脑:

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
    /*
     * Smells like a compiler bug -- it doesn't work
     * when the & below is removed.
     */
    [0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/syscalls_32.h>
};

咱先不管上面代码的意思,先来回顾一下 C 语言中数组初始化的相关知识,然后再回头来理解上面这段代码。
数组初始化

C 语言中数组的初始化,可以在定义时就给出其初始值,以逗号隔开,用花括号括起来,例如:

int my_array[5] = {0, 1, 2, 3, 4};

当然你可以不用显示地去初始化所有的元素,例如,下面的代码就是显示初始化了数组的前三项,后面两项默认为0:

int my_array[5] = {0, 1, 2};

在 C89 标准中,要求按照数组中元素固定的顺序对数组的元素进行初始化;然而在 ISO C99 中,你可以以任意的顺序对数组元素初始化,只是需要给出数组元素所在的索引号;当然 GNU 编译器 GCC 对 C89 进行了扩展,也允许这么做。为了指明初始特殊的数组元素,需要在元素值前加上 [index] =,如:

int my_array[6] = { [4] = 29, [2] = 15 };
或者写成:
int my_array[6] = { [4] 29, [2] 15 };     //省略到索引与值之间的=,GCC 2.5 之后该用法已经过时了,但 GCC 仍然支持
两者均等价于:
int my_array[6] = {0, 0, 15, 0, 29, 0};

GNU 还有一个扩展:在需要将一个范围内的元素初始化为同一值时,可以使用 [first ... last] = value 这样的语法:

int my_array[100] = { [0 ... 9] = 1, [10 ... 98] = 2, 3 };

这是将my_array数组的第0~9个元素初始化为1, 第10~98个元素初始化为2, 第99个元素初始化为3(你也可以显示地写成[99] = 3)。** 注意 **:在语法中... 两边必须要留有空格符。
回到上面

对数组特定元素进行初始化我之前还真没遇到过,但也是 C 标准所支持的。内核中系统调用表是指根据系统调用号来找到系统调用的函数入口地址,结合上面数组初始化这个语法点,再回头看看上面系统调用表的定义:

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
    [0 ... __NR_syscall_max] = &sys_ni_syscall,
#include <asm/syscalls_32.h>
};

先对表中所有 __NR_syscall_max+1 项初始化为指向 sys_ni_syscall 的函数,该函数只返回 -ENOSYS,表示该系统调用未实现。接下来包含一个头文件#include <asm/syscalls_32.h>,该文件是在编译时生成的,内容为:

__SYSCALL_I386(0, sys_restart_syscall, sys_restart_syscall)
__SYSCALL_I386(1, sys_exit, sys_exit)
__SYSCALL_I386(2, sys_fork, stub32_fork)
__SYSCALL_I386(3, sys_read, sys_read)
__SYSCALL_I386(4, sys_write, sys_write)
__SYSCALL_I386(5, sys_open, compat_sys_open)
...

__SYSCALL_I386 是一个宏定义:

#define __SYSCALL_I386(nr, sym, compat) [nr] = sym,

这样上面的系统调用表定义就展开为:

const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
    [0 ... __NR_syscall_max] = &sys_ni_syscall,
    [0] = sys_restart_syscall,
    [1] = sys_exit,
    [2] = sys_fork,
    [3] = sys_read,
    //...
};

当用户进程发生系统调用,通过软中断 int 0x80 或者 sysenter 指令陷入到内核态,首先保存寄存器,然后检查系统调用号是否合法,最后跳转到相应的内核系统调用函数中执行:

ENTRY(system_call)
    pushl_cfi %eax          # 保存原始 eax
    SAVE_ALL                # 保存寄存器帧
    GET_THREAD_INFO(%ebp)
    testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)    # 检查是否跟踪系统调用标志
    jnz syscall_trace_entry
    cmpl $(NR_syscalls), %eax    # 检查系统调用号是否合法
    jae syscall_badsys
syscall_call:
    call *sys_call_table(,%eax,4)   # 调用相应函数,等价于 call sys_call_table[%eax*4]

上面就是系统调用的进入过程,比较简单,这里只是说明了我们之前定义的系统调用表 sys_call_table 的用处。
再举一例

内核中还有其他地方应用到此种初始化数组的方法:

/* There are machines which are known to not boot with the GDT
   being 8-byte unaligned.  Intel recommends 16 byte alignment. */
static const u64 boot_gdt[] __attribute__((aligned(16))) = {
    /* CS: code, read/execute, 4 GB, base 0 */
    [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff),
    /* DS: data, read/write, 4 GB, base 0 */
    [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff),
    /* TSS: 32-bit tss, 104 bytes, base 4096 */
    /* We only have a TSS here to keep Intel VT happy;
       we don't actually use it for anything. */
    [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103),
};

这是对系统启动时对全局符号表GDT的初始化。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux sys_call_table 初始化 的相关文章

  • pytorch中contiguous()

    contiguous xff1a view只能用在contiguous的variable上 如果在view之前用了transpose permute等 xff0c 需要用contiguous 来返回一个contiguous copy 一种可
  • tensorflow中control_flow_ops.while_loop

    self h0 61 tf zeros self batch size self hidden dim self h0 61 tf stack self h0 self h0 相当于 h0和C0 generator on initial r
  • k8s基础

    目录 一 基本介绍 二 组件介绍 1 master组件 2 node组件 三 核心概念 1 Pod 2 controller 3 service 四 单master搭建集群 1 系统初始化 2 安装k8s核心组件 3 容器化安装其他插件 4
  • 论文解读:Tips and Tricks for Visual Question Answering: Learnings from the 2017 Challenge

    这是关于VQA问题的第十二篇系列文章 这篇论文具有很强的指导意义 xff0c 本篇文章将介绍论文 xff1a 主要思想 xff1b 模型方法 xff1b 试验细节 有兴趣可以查看原文 xff1a Tips and Tricks for Vi
  • 总结2014——迷茫以及迷茫过后的坚持

    首先 xff0c 借用一句话和大家共勉 xff1a 少一些功利主义的追求 xff0c 多一些不为什么的坚持 xff01 xff01 不知不觉15年也快过了1个月了 xff0c 还是想着要为14年做一下总结 xff1a 记录一下自己的历程 今
  • 在faster rcnn中使用soft nms,faster rcnn的改进(一)

    1 背景介绍 我的项目是利用faster rcnn检测kiiti数据集 xff0c 用原始nms xff0c iters 61 10000的情况下 xff0c 得到的mAP 61 0 586 在改用soft nms后 xff0c 其他参数均
  • 建立DATAGUARD最大保护模式-测试手记

    建立DATAGUARD 最大保护模式 xff08 自写 xff09 xff08 备注 xff1a 本文档符合最大保护模式 xff0c 所有参数均为最大保护模式下适用 xff0c 其他模式不适用 xff09 1 主库 xff0c 启动归档 x
  • docker中安装ping | vim | nginx镜像

    docker安装nginx镜像并常见nginx容器 docker pull nginx latest docker run detach publish 9999 80 name nginxSer restart unless stoppe
  • 从操作系统内核解释电脑死机原理

    关于电脑死机的原因或者说原理 xff0c 即电脑为什么会死机 xff0c 电脑死机时计算机底层都发生了什么 一直不太明白 xff0c 在网上也查过相关的资料 xff0c 但是都没有找到自己想要的 网上谈的都是外部导致电脑死机的原因 xff0
  • 自己动手写操作系统第二章 pmtest1.asm分析

    34 pm inc 34 描述符 Usage Descrptor Base Limit Attr Base dd Limit dd Low 20 bits available Attr dw lower 4 bits of higher b
  • Linux 0.11 内核在内核空间创建进程时不使用写时复制技术

    在Linux0 12内核完全剖析中 xff0c 有这样一段话 34 由于创建新进程的过程是通过完全复制父进程代码段和数据段的方式实现 xff0c 因此在首次使用fork 创建新进程init 时 xff0c 为了确保新进程用户态栈中没有进程0
  • putty 登陆VMware虚拟机下的linux系统

    物理机的操作系统是Windows XP 虚拟机是在VMware上安装的CentOS xff0c 版本是5 6 因为每次登陆虚拟机鼠标会被限定在虚拟机的登陆界面 xff0c 所以想通过远程登陆工具来登陆虚拟机 虚拟机使用的网络是桥接模式 注意
  • Minx内核中scanf函数实现代码

    include lt stdio h gt include lt stdarg h gt include 34 loc incl h 34 int scanf const char format va list ap int retval
  • 双系统Linux下突然挂载Windows分区失败

    问题描述 xff0c 装了双系统之后 xff0c 一开始在Linux下还能访问Windows的分区 xff0c 可是突然之间就不能访问了 xff0c 错误信息如下 xff1a Error mounting dev sda1 at media
  • 对Linux0.11 "内核空间不使用写时复制机制" 本质理解

    一个页面被多个进程共享 xff0c 每当一个进程产生一次写保护 错误 xff0c 内核将给进程分配一个新的物理页面 xff0c 将共享页面的内容复制过来 xff0c 新的页面将设置为可读写 xff0c 而共享页面仍然是只读的 xff0c 只
  • Session && Cookie

  • windowsxp远程桌面端口号改变的位置

    HKEY LOCAL MACHINE SYSTEM CurrentControlSet Control Terminal Server Wds rdpwd Tds tcp 下的PortNamber HKEY LOCAL MACHINE SY
  • linux0.11 进程切换

    move to user mode是在堆栈中创建一个任务切换的假象 xff0c 用iret跳转到外层3 xff0c 这样cpu就会自动根据tr加载tss xff0c 并初始化各个寄存器运行任务0 所以 xff0c 任务0其实就是内核空间中的
  • Linux0.11 进程0

    Linux中1号进程是由0号进程来创建的 xff0c 因此必须要知道的是如何创建0号进程 xff0c 由于在创建进程时 xff0c 程序一直运行在内核态 xff0c 而进程运行在用户态 xff0c 因此创建0号进程涉及到特权级的变化 xff
  • Linux0.11 由进程睡眠函数sleep_on()中的堆栈变量tmp引发的思考 关于进程内核堆栈

    sleep on cpp view plaincopy 功能 xff1a 当前进程进入不可中断睡眠态 xff0c 挂起在等待队列上 参数 xff1a p 等待队列头 返回 xff1a xff08 无 xff09

随机推荐

  • 关于Windows系统环境变量的引用问题

    做Leap Motion开发时 xff0c 新建了LEAP SDK的系统环境变量 xff0c 按照官方SDK文档中说明的 xff0c 在工程中引入 LEAP SDK include 之前半年的时间里都是这样做的 xff0c 没有任何问题 x
  • 深入理解Linux内核--信号

    信号用于在用户态进程间通信 内核也用信号通知进程系统所发生的事情 1 信号的作用 信号 signal 是很短的消息 xff0c 可以被发送到一个进程或一组进程 发送给进程的唯一信息通常是一个数 xff0c 以此来标识信号 使用信号的两个主要
  • 进程上下文与中断上下文

    处理器总处于以下状态中的一种 xff1a xff11 内核 态 xff0c 运行于进程 上下文 xff0c 内核代表进程运行于内核空间 xff12 内核态 xff0c 运行于中断上下文 xff0c 内核代表硬件运行于内核空间 xff13 用
  • 进程上下文VS中断上下文

    内核空间和用户空间是现代操作 系统的两种工作模式 xff0c 内核模块运行在内核空间 xff0c 而用户态应用程序运行在用户空间 它们代表不同的级别 xff0c 而对系统资源具有不同的访问权限 内核模块运行在最高级别 xff08 内核态 x
  • 中断不可睡眠的一些理解

    一 LINUX中到是有中断还没有完全返回就调用schedule 而睡眠过去的例子 可以猜是哪里 我觉得 xff0c 中断和异常不同 xff0c 中断是异步的 xff0c 异常和系统调用是同步的 异常比如缺页异常发生时 xff0c 当前任务在
  • kmalloc和vmalloc

  • linux内核中内存相关的操作函数

    1 kmalloc kfree static always inline void kmalloc size t size gfp t flags 内核空间申请指定大小的内存区域 xff0c 返回内核空间虚拟地址 在函数实现中 xff0c
  • Oracle安全:SCN可能最大值与耗尽问题Oracle安全:SCN可能最大值与耗尽问题

    SCN的问题一旦出现 xff0c 使得数据库的一切事务停止 xff0c 由于SCN不能后退 xff0c 所以数据库必须重建 xff0c 才能够重用 在2012年第一季度的CPU补丁中 xff0c 包含了一个关于SCN修正的重要变更 xff0
  • Linux内核 申请和释放内存流程

    1 内核初始化 xff1a 内核建立好内核页目录页表数据库 xff0c 假设物理内存大小为len xff0c 则建立了 3G 3G 43 len 0 len 这样的虚地址vaddr和物理地址paddr的线性对应关系 xff1b 内核建立一个
  • 编译器"自举与移植"原理

    本文基于对 编译原理与实践 中有关编译器自举与移植部分的读书 笔记 形式 xff0c 因为原书是老外写的 xff0c 感觉翻译的地方好多语句不通或难以理解 xff0c 所以花了好多功夫研究这一块 注 xff1a 本文中与原书一致的地方都是P
  • Linux 内核 由block_read和block_write函数引发的设备块号转换问题的思考

    在1 2内核版本中 xff0c 在Linux fs目录下 xff0c 有一个block dev c文件 xff0c 里面主要包含了block read block write block fsync函数 先说说我遇到的问题 xff0c 在块
  • Linux 进程调度时机

    Linux调度时机主要 有 xff1a 1 进程状态转换的时刻 xff1a 进程终止 进程睡眠 2 当前进程的时间 片用完时 xff08 current gt counter 61 0 xff09 3 设备驱动程序 4 进程从中断 异常及系
  • linux 下批量转换pdf的命令方法

    由于在windows下的图形界面 xff0c 难以批量进行其他格式的文件到PDF格式文件的转换 xff0c 而一些其他的软件也不是很满意 xff0c 所以转到linux下 xff0c 想利用linux强大的命令行来完成这件事 linux下有
  • Linux内核 内存映射文件机制mmap

    今天研究Linux1 2内核运行加载a out格式的可执行文件的代码时 xff0c 无意中研究明白了内核提供的内存映射机制 mmap xff08 memory map xff09 当内核要加载可执行文件到相应的用户地址空间时 xff0c 有
  • bash提示符的配置:

    bash提示符的配置 xff1a 如果您很容易使 shell 提示行变得色彩绚烂斓且带有更多信息 xff0c 为什么还要坚持用单调的标准 shell 提示行呢 xff1f 在这篇技巧中 xff0c Daniel Robbins 将说明如何获
  • Linux线性地址空间的划分及内核寻址方式

    今天研究Linux1 2内核时 xff0c 注意到该版本中的PAGE OFFSET宏被定义为0 xff0c 考虑到进程的地址空间被划分为3G的用户态地址空间和1G的内核态地址空间 xff0c 于是深入的研究了一下这个问题 一开始我只是疑惑
  • linux 最简单的模块的编写和运行

    第一次动手编写一个内核模块 xff0c 但是查找了许多资料没有一个可以完美通过编译的 xff0c 郁闷 xff0c 最后还是解决了 xff0c 分享出来 首先是hello c include lt linux kernel h gt Nee
  • 截获或替换linux系统调用

    直接上代码吧 xff1a hello c include lt linux kernel h gt Needed by all modules include lt linux module h gt Needed for KERN inc
  • oracle临时表实际应用

    xff08 这段是后面添加的 xff1a 临时表 xff0c 在实际应用中 xff0c 其实和nologging的固定表 xff0c 是差不多的 xff0c 都是中间表 xff0c 所以这里为什么添加这段话 xff0c 是让自己记得 xff
  • linux sys_call_table 初始化

    前几天看内核中系统调用代码 xff0c 在系统调用向量表初始化中 xff0c 有下面这段代码写的让我有点摸不着头脑 xff1a const sys call ptr t sys call table NR syscall max 43 1