[转载]kbuild-DEFINE(sym, val)

FROM:https://blog.csdn.net/linglongqiongge/article/details/50008301
#define DEFINE(sym, val) \
        asm volatile("\n->" #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("\n->" #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 中添加相应的系统调用号就可以了

附件:

List:       linux-kernel
Subject:    [RFC] Standard way of generating assembler offsets
From:       Keith Owens <kaos () ocs ! com ! au>
Date:       2001-10-04 11:47:08
[Download message RAW]

Almost every architecture generates Assembler values to map the offsets
of fields in C structures, about the only exception is i386 and that is
because its offsets are hard coded into entry.S.  Every arch has done
it differently, none of them have got it exactly right.

As part of kbuild 2.5 I am standardizing on one method for generating
Assembler offsets.  This change is required for kbuild 2.5 but it can
be added to 2.4 without disturbing the current kbuild, I want to do
this gradually now instead of a single massive change in kernel 2.5.  I
will be issuing per architecture changes for generating Assembler
offsets against 2.4.

The kbuild 2.5 method for generating Assembler offsets satisfies these
requirements:

* No manual intervention required.  Many architectures rely on users
  running make dep after changing config options that affect the
  Assembler offsets.  If the user forgets to run make dep then the C
  and Assembler code is out of sync - totally unacceptable.  This is
  completely fixed in kbuild 2.5; I cannot do a complete fix in kbuild
  2.4 but it is still better than the existing manual system.

* Standard name for the related files.  There are 6+ different names
  for the files used to generate Assembler offsets, kbuild 2.5 uses
  asm-offsets.[csh] on all architectures.

* Allows for multiple parallel compiles from the same source tree.
  Writing the generated asm-offsets.h to include/asm is not an option,
  it prevents concurrent compiles.

* The method must work in native and cross compile mode and give
  exactly the same results.  Some 2.4 code only works in native mode,
  some architectures have different methods for native and cross
  compile with different output formats.  Yeuch!

* Standard scripts for generating the output.  Every arch does it
  differently in 2.4, standards are good!

* Correct dependency trees.  Because 2.4 make dep does not scan .S
  files, there is little or no dependency information.  Even if the
  offsets are regenerated, the affected Assembler code does not always
  get rebuilt.  kbuild 2.5 handles dependencies for Assembler as well
  as C; I cannot get kbuild 2.4 perfect but I can improve on the
  existing (or non-existent) 2.4 dependencies.

All architectures will define arch/$(ARCH)/asm-offsets.c.  This has a
standard prologue for the macros that convert offsets to Assembler,
followed by arch specific field references.

arch/$(ARCH)/asm-offsets.s is generated from arch/$(ARCH)/asm-offsets.c
using standard rules, although kbuild 2.4 needs some tweaking.

arch/$(ARCH)/asm-offsets.h is generated from arch/$(ARCH)/asm-offsets.s
by a semi-standard script.  Most of the script is common to all
architectures but the precise format of the Assembler output is arch
specific.

The final result is included in *only* the Assembler programs that need
it, as #include "asm-offsets.h" with -I arch/$(ARCH) in the relevant
Makefiles.  Hard coding relative paths in source files is a pet hate,
use #include "localname.h" and -I instead.  Including the generated
file in C code is not allowed, it severly pollutes the dependency
chain, to the extent that any config change can force a complete
recompile, unacceptable.


Example from i386:

arch/i386/asm-offsets.c

/*
* Generate definitions needed by assembly language modules.
* This code generates raw asm output which is post-processed to extract
* and format the required data.
*/

#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/sched.h>

/* Use marker if you need to separate the values later */

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

#define BLANK() asm volatile("\n->" : : )

int
main(void)
{
  DEFINE(state,        offsetof(struct task_struct, state),);
  DEFINE(flags,        offsetof(struct task_struct, flags),);
  DEFINE(sigpending,   offsetof(struct task_struct, sigpending),);
  DEFINE(addr_limit,   offsetof(struct task_struct, addr_limit),);
  DEFINE(exec_domain,  offsetof(struct task_struct, exec_domain),);
  DEFINE(need_resched, offsetof(struct task_struct, need_resched),);
  DEFINE(tsk_ptrace,   offsetof(struct task_struct, ptrace),);
  DEFINE(processor,    offsetof(struct task_struct, processor),);
  BLANK();
  DEFINE(ENOSYS,       ENOSYS,);
  return 0;
}

asm-offsets.s to asm-offsets.h.

# Convert raw asm offsets into something that can be included as
# assembler definitions.  It converts
#   -> symbol $value source
# into
#   symbol = value /* 0xvalue source */

echo '#ifndef __ASM_OFFSETS_H__'
echo '#define __ASM_OFFSETS_H__'
echo '/*'
echo ' * DO NOT MODIFY'
echo ' *'
echo " * This file was generated by arch/$(ARCH)/Makefile.in."
echo ' *'
echo ' */'
echo ''
awk '
  /^->$/{printf("\n")}
  /^-> /{
    sym = $2;
    val = $3;
    sub(/^\$/, "", val);
    $1 = "";
    $2 = "";
    $3 = "";
    printf("%-20s = %3d\t/* 0x%x\t%s */\n", sym, val, val, $0)
  }
'
echo '#endif'

Generated arch/i386/asm-offsets.h

#ifndef __ASM_OFFSETS_H__
#define __ASM_OFFSETS_H__
/*
* DO NOT MODIFY
*
* This file was generated by arch/i386/Makefile.in.
*
*/

state                =   0      /* 0x0     offsetof(struct task_struct, state) */
flags                =   4      /* 0x4     offsetof(struct task_struct, flags) */
sigpending           =   8      /* 0x8     offsetof(struct task_struct, sigpending) */
addr_limit           =  12      /* 0xc     offsetof(struct task_struct, addr_limit) */
exec_domain          =  16      /* 0x10    offsetof(struct task_struct, exec_domain) */
need_resched         =  20      /* 0x14    offsetof(struct task_struct, need_resched) */
tsk_ptrace           =  24      /* 0x18    offsetof(struct task_struct, ptrace) */
processor            =  52      /* 0x34    offsetof(struct task_struct, processor) */

ENOSYS               =  38      /* 0x26    ENOSYS */
#endif


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[prev in list] [next in list] [prev in thread] [next in thread] 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值