• asm-offset.h 生成


    内核文件 arch/x86/kernel/syscall_64.c 文件中包含了一个头文件 arch/x86/include/asm/asm-offset.h ,这个文件在内核构建之初是不存在的,是在构建过程中生成的。下面我们来看看它是如何生成的。

    1. include/linux/kbuild.h

    #define DEFINE(sym, val) 
            asm volatile("
    ->" #sym " %0 " #val : : "i" (val))

    这是一个内联汇编宏,不过实际上它不会生成合法的内联汇编代码,它只是利用了内联汇编中嵌入立即数的功能。

    2. arch/x86/include/asm/unistd.h

    这个文件使用了宏控制,在 x86_64 平台下包含了 arch/x86/include/asm/unistd_64.h ,部分内容如下,

    ...
    #ifndef __SYSCALL
    #define __SYSCALL(a, b)
    #endif
    ...
    #define __NR_read                0
    __SYSCALL(__NR_read, sys_read)
    #define __NR_write                1
    __SYSCALL(__NR_write, sys_write)
    #define __NR_open                2
    __SYSCALL(__NR_open, sys_open)
    #define __NR_close                3
    __SYSCALL(__NR_close, sys_close)
    ...

    3. arch/x86/kernel/asm-offsets_64.c

    ...
    #include <linux/kbuild.h>
    ...
    
    #define __NO_STUBS 1
    #undef __SYSCALL
    #undef _ASM_X86_UNISTD_64_H
    #define __SYSCALL(nr, sym) [nr] = 1,
    static char syscalls[] = {
    #include <asm/unistd.h>
    };
    ...
    DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);

    syscalls 这个数组的大小刚好就等于所有系统调用项总的值,注意它类型是 char 型数组,而且也请注意 gnu c 数组初始化时的扩展语法。

    4. Kbuild

    这个文件在根目录下,实际上是一个 Makefile,它的部分内容如下

    #####
    # 2) Generate asm-offsets.h
    #
    
    offsets-file := include/asm/asm-offsets.h
    
    always  += $(offsets-file)
    targets += $(offsets-file)
    targets += arch/$(SRCARCH)/kernel/asm-offsets.s
    
    
    # Default sed regexp - multiline due to syntax constraints
    define sed-y
        "/^->/{s:->#(.*):/* 1 */:; 
        s:^->([^ ]*) [$$#]*([^ ]*) (.*):#define 1 2 /* 3 */:; 
        s:->::; p;}"
    endef
    
    quiet_cmd_offsets = GEN     $@
    define cmd_offsets
        (set -e; 
         echo "#ifndef __ASM_OFFSETS_H__"; 
         echo "#define __ASM_OFFSETS_H__"; 
         echo "/*"; 
         echo " * DO NOT MODIFY."; 
         echo " *"; 
         echo " * This file was generated by Kbuild"; 
         echo " *"; 
         echo " */"; 
         echo ""; 
         sed -ne $(sed-y) $<; 
         echo ""; 
         echo "#endif" ) > $@
    endef
    
    # We use internal kbuild rules to avoid the "is up to date" message from make
    arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c 
                                          $(obj)/$(bounds-file) FORCE
        $(Q)mkdir -p $(dir $@)
        $(call if_changed_dep,cc_s_c)
    
    $(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s Kbuild
        $(call cmd,offsets)

    也就是先用 .c 文件生成 .s 文件,然后再用 sed 命令对其中特定的行进行替换,进而重定向到目标文件中,也就是 asm-offset.h。

    5. 模拟

    有了基于上面过程的分析,我们可以自己对这个过程进行构建。

    (1)kbuild.h

    #ifndef _KBUILD_H_
    #define _KBUILD_H_
    
    #define DEFINE(sym, val) 
        asm volatile("
    ->" #sym " %0 " #val : : "i" (val))
    
    #endif

    (2)unistd.h

    #ifndef _UNISTD_H_
    #define _UNISTD_H_
    
    #ifndef __SYSCALL
    #define __SYSCALL(a, b)
    #endif
    
    #define __NR_read                0
    __SYSCALL(__NR_read, sys_read)
    #define __NR_write                1
    __SYSCALL(__NR_write, sys_write)
    #define __NR_open                2
    __SYSCALL(__NR_open, sys_open)
    #define __NR_close                3
    __SYSCALL(__NR_close, sys_close)
    
    #endif

    (3)asm-offsets.c

    #include "kbuild.h"
    
    #define __NO_STUBS 1
    #undef __SYSCALL
    #undef _UNISTD_H_
    #define __SYSCALL(nr, sym) [nr] = 1,
    static char syscalls[] = {
    #include "unistd.h"
    };
    
    int main(void)
    {
        DEFINE(__NR_syscall_max, sizeof(syscalls) - 1);
        return 0;
    }

    注意没有 main 函数会报错的。

    (4)Makefile

    offsets-file := asm-offsets.h
    
    define sed-y
        "/^->/{s:->#(.*):/* 1 */:; 
        s:^->([^ ]*) [$$#]*([^ ]*) (.*):#define 1 2 /* 3 */:; 
        s:->::; p;}"
    endef
    
    define cmd_offsets
        (set -e; 
         echo "#ifndef __ASM_OFFSETS_H__"; 
         echo "#define __ASM_OFFSETS_H__"; 
         echo "/*"; 
         echo " * DO NOT MODIFY."; 
         echo " *"; 
         echo " * This file was generated by Kbuild"; 
         echo " *"; 
         echo " */"; 
         echo ""; 
         sed -ne $(sed-y) $<; 
         echo ""; 
         echo "#endif" ) > $@
    endef
    
    asm-offsets.s: asm-offsets.c
        gcc -S $<
    
    $(offsets-file): asm-offsets.s
        @$(cmd_offsets)

    只要执行命令

    make asm-offsets.h

    就可以一生成下面的文件,

    #ifndef __ASM_OFFSETS_H__
    #define __ASM_OFFSETS_H__
    /*
     * DO NOT MODIFY.
     *
     * This file was generated by Kbuild
     *
     */
    
    #define __NR_syscall_max 3 /* sizeof(syscalls) - 1 */
    
    #endif

    所以在构建之前生成这个头文件,就可以完成对 __NR_syscall_max 的自动赋值,进入如果要增加系统调用选项,只需要在 unistd.h 中添加相应的系统调用号就可以了。

  • 相关阅读:
    串口通信
    无法安装SQL提示文件被挂起
    flash图片幻灯片浏览
    document.all与WEB标准
    在新窗口中打开页面 的asp.net后台代码
    sql 触发器
    无技术含量的正则表达式笔记
    两个FTP服务器之间传送数据
    repeater嵌套
    登录
  • 原文地址:https://www.cnblogs.com/wendellyi/p/3993404.html
Copyright © 2020-2023  润新知