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 [email protected] 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]