zoukankan      html  css  js  c++  java
  • 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 中添加相应的系统调用号就可以了。

  • 相关阅读:
    hdu 5007 水题 (2014西安网赛A题)
    hdu 1698 线段树(成段替换 区间求和)
    poj 3468 线段树 成段增减 区间求和
    hdu 2795 公告板 (单点最值)
    UVaLive 6833 Miscalculation (表达式计算)
    UVaLive 6832 Bit String Reordering (模拟)
    CodeForces 124C Prime Permutation (数论+贪心)
    SPOJ BALNUM (数位DP)
    CodeForces 628D Magic Numbers (数位DP)
    POJ 3252 Round Numbers (数位DP)
  • 原文地址:https://www.cnblogs.com/wendellyi/p/3993404.html
Copyright © 2011-2022 走看看