📚

SYSCONFIG_DEFINEマクロについて

2022/09/27に公開

SYSCONFIG_DEFINEマクロが難解だったため展開してみた。
最後を-E -o kernel/sys.i に変更して単体コンパイル。

sudo gcc -Wp,-MMD,kernel/.sys.o.d -nostdinc -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu11 -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m64 -falign-jumps=1 -falign-loops=1 -mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup -mtune=generic -mno-red-zone -mcmodel=kernel -Wno-sign-compare -fno-asynchronous-unwind-tables -mindirect-branch=thunk-extern -mindirect-branch-register -mindirect-branch-cs-prefix -fno-jump-tables -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 -fno-allow-store-data-races -Wframe-larger-than=1024 -fstack-protector-strong -Wimplicit-fallthrough=5 -Wno-main -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-stack-clash-protection -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wcast-function-type -Wno-stringop-truncation -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -Wno-alloc-size-larger-than -fno-strict-overflow -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -Wno-packed-not-aligned -g -gdwarf-5 -fsanitize=bounds -fsanitize=shift -fsanitize=bool -fsanitize=enum -DKBUILD_MODFILE='"kernel/sys"' -DKBUILD_BASENAME='"sys"' -DKBUILD_MODNAME='"sys"' -D__KBUILD_MODNAME=kmod_sys -E -o kernel/sys.i kernel/sys.c ;

unameシステムコールを以下に展開した。
極力簡単にするため、.configカーネルコンフィグのFTRACEとIA32_EMULATIONは無効にしてある。

① static long __se_sys_newuname(__typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0ULL))), 0LL, 0L)) name);

② static inline attribute((gnu_inline)) attribute((unused)) attribute((no_instrument_function)) long __do_sys_newuname(struct new_utsname * name);

③ long __x64_sys_newuname(const struct pt_regs *regs);

④ static struct error_injection_entry attribute((used)) attribute((section("_error_injection_whitelist"))) _eil_addr___x64_sys_newuname = {
.addr = (unsigned long)__x64_sys_newuname,
.etype = EI_ETYPE_ERRNO,
};

⑤ long __x64_sys_newuname(const struct pt_regs *regs) {
  return __se_sys_newuname(regs->di); }

⑥ static long __se_sys_newuname(__typeof(__builtin_choose_expr((__builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0ULL))), 0LL, 0L)) name) { long ret = __do_sys_newuname(( struct new_utsname *) name);

⑦ (void)((int)(sizeof(struct { int:(-!!(!(__builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0LL)) || __builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0ULL))) && sizeof(struct new_utsname *) > sizeof(long))); })));
do { } while (0);
return ret;}

⑧ static inline attribute((gnu_inline)) attribute((unused)) attribute((no_instrument_function)) long __do_sys_newuname(struct new_utsname * name) {
システムコール本体
}

解説
SYSCONFIG_DEFINEマクロを展開すると①から⑧までの関数に展開される。
①と②と③はただの関数定義。
⑤⑥⑧が関数本体。

システムコールの実行は⑤ ⇨ ⑥ ⇨ ⑧の順に実行される。

⑧ inlineはインライン関数。高速化したいときに使う。
Cソースでは別れているが、アセンブラレベルでは呼び出し元に挿入される。
つまり⑧は⑥の関数内に埋め込まれる。
関数呼び出しをしないため、関数オーバーヘッドがなく高速化される。

attribute((gnu_inline))
CコンパイラのバージョンをC90指定。

attribute((unused))
関数を使わなくても警告を出さない。

attribute((no_instrument_function))
関数プロファイルを出さない。

① どれもゼロの定数だが、型チェックとして使っている。
0LL = long long型
0ULL = unsigned long long型
0L = long型

①__builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0LL))
new_utsname構造体のポインタはlong long型か?

①__builtin_types_compatible_p(typeof(( struct new_utsname *)0), typeof(0ULL)))
new_utsname構造体のポインタはunsigned long long型か?

①__builtin_choose_expr(?: x, y)
?がTrueならx, Falseならy

詳しくはC言語のビルトイン関数。

⑦何がしたいのかわからん。

⑧要するに__do_sys_newunameがシステムコール本体であり、ここにブレークポイントを貼ると良い。

Discussion