linux kernel中的asm-offsets.c

本文详细介绍了在汇编语言中使用结构体时如何自动化处理成员偏移量的问题。通过DEFINE宏结合sed等工具,自动生成宏定义,确保结构体变化时偏移量始终正确。这一机制在Linux kernel的开发中尤为重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 在汇编中使用结构体

首先考虑一下结构体:

struct test
{
	int a;
	int b;
}

这个结构体很简单,只是用来举例子。在c语言中,如果我们要访问结构体中的某个成员,这非常容易:

struct test t;
t.a = 1;

假如我们想知道结构体中某个成员在结构体中的偏移,这也不难,比如linux kernel就提供了offsetof宏来实现这个功能:

offsetof(struct test, b) /* 得到的就是成员b在结构体中的偏移 */

这一切在c语言中都平平无奇,但是考虑这样一个需求:我们需要在汇编语言中使用结构体。这时候怎么办呢?汇编文件里用c的语法定义结构体肯定是不行的,现实的做法是,把结构体的首地址存放在某个寄存器里,然后只要知道各个成员的偏移,就可以通过首地址+偏移的方式寻址到某个具体的成员。

于是,问题的关键来了。我们怎么获取到各个成员的偏移呢?仍旧使用offsetof宏肯定是不行的,汇编器根本不认识c的语法。最容易想到的方法就是手工算好偏移,然后用于汇编,考虑到程序的可读性,这个偏移用宏定义的形式给出:

#define A_OFFSET (0)
#define B_OFFSET (4)

但这样就是硬编码,万一结构体的成员有变动,那维护起来很麻烦。我们期待的是类似offsetof宏那样的解决方法,不管结构体怎么变,都让编译器帮我们计算好偏移,这样偏移总是正确的,但这在汇编里面不可行。对于这一矛盾,kernel的解决办法是,在c文件中使用offsetof算出偏移量,然后想办法自动化 的把算出来的偏移量表示成宏定义,之后再汇编里包含相应头文件。这样,汇编文件直接使用宏定义就可以总是正确的得到结构体中成员的偏移量。如此一来,在汇编中使用结构体,让数据组织的更有结构,就完全可行了。在kernel中实现上述功能的c文件通常被命名为asm-offsets.c,自动生成的表示偏移量的宏被存放在自动生成的头文件中,这个头文件被命名为asm-offsets.h

那么这一切到底是怎么做到的呢?这就不得不提asm-offsets.c使用到的一个宏DEFINE,这个宏是自动生成asm-offsets.h的关键。

2 DEFINE宏

首先给出DEFINE的定义:

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

这真是好奇怪的一个宏,虽然内联汇编并不稀罕,但这样的内联汇编确实少见。这个宏在asm-offsets.c中是这么使用的,假如我需要上文的struct test的成员的偏移,那么需要在asm-offsets.c中写出如下代码:

int main(void)
{
	DEFINE(TEST_A, offsetof(struct test, a));
	DEFINE(TEST_B, offsetof(struct test, b));
}

接下来,将asm-offsets.c编译成asm-offsets.s,注意这里的编译是狭义上的编译,即只编译不汇编。仍旧以本例来说,编译后,asm-offsets.s的内容(只选其中关键内容,不是所有内容)如下:

.ascii "->TEST_A #0 offsetof(struct test, a)"
.ascii "->TEST_B #4 offsetof(struct test, b)"

可以看到,上述内容已经包含了宏名以及偏移量(#0、#4),但还不是一个合法的c语言宏定义的形式。接下来怎么得到asm-offsets.h呢?kernel采取的做法很直接,直接使用sedecho等工具,来匹配文本,处理文本,并生成相应的asm-offsets.h。更细一点说,从上述文本中提取出三部分内容:

作为宏名:TEST_A
作为偏移:0
作为注释:offsetof(struct test, a)

作为宏名:TEST_B
作为偏移:4
作为注释:offsetof(struct test, b)

最终生成的asm-offsets.h大体如下:

#define TEST_A 0 /* offsetof(struct test, a) */
#define TEST_B 4 /* offsetof(struct test, b) */

当然,除了结构体中的成员偏移,我们还可以用DEFINE来定义供汇编文件使用 的表示结构体大小的宏,如:

DEFINE(TEST_SIZE, sizeof(struct test));

DEFINE外加后续的处理只是机制,只要机制有了,就可以玩出花来。要是没有机制呢?kernel开发者就会想办法把机制构建出来。

参考文献

[1] What’s purpose of “arm64/kernel/asm-offsets.c”?
[2] lib/asm-offsets.c的作用

mouse@mouse-virtual-machine:~/workspace/kernel/linux-4.19.3$ make -j8 scripts/kconfig/conf --syncconfig Kconfig SYSTBL arch/x86/include/generated/asm/syscalls_32.h SYSHDR arch/x86/include/generated/asm/unistd_32_ia32.h SYSTBL arch/x86/include/generated/asm/syscalls_64.h SYSHDR arch/x86/include/generated/asm/unistd_64_x32.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_64.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_32.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_x32.h UPD include/config/kernel.release WRAP arch/x86/include/generated/uapi/asm/bpf_perf_event.h WRAP arch/x86/include/generated/uapi/asm/poll.h UPD include/generated/uapi/linux/version.h UPD include/generated/utsrelease.h DESCEND objtool HOSTCC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep.o HOSTLD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep-in.o LINK /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/builtin-check.o GEN /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/lib/inat-tables.c CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/decode.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/exec-cmd.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/builtin-orc.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/help.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/pager.o In file included from help.c:12: In function ‘xrealloc’, inlined from ‘add_cmdname’ at help.c:24:2: subcmd-util.h:56:23: error: pointer may be used after ‘realloc’ [-Werror=use-after-free] 56 | ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ subcmd-util.h:52:21: note: call to ‘realloc’ here 52 | void *ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ subcmd-util.h:58:31: error: pointer may be used after ‘realloc’ [-Werror=use-after-free] 58 | ret = realloc(ptr, 1); | ^~~~~~~~~~~~~~~ subcmd-util.h:52:21: note: call to ‘realloc’ here 52 | void *ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/check.o cc1: all warnings being treated as errors mv: 对 '/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/.help.o.tmp' 调用 stat 失败: 没有那个文件或目录 make[4]: *** [/home/mouse/workspace/kernel/linux-4.19.3/tools/build/Makefile.build:96:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/help.o] 错误 1 make[3]: *** [Makefile:52:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libsubcmd-in.o] 错误 2 make[2]: *** [Makefile:54:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libsubcmd.a] 错误 2 make[2]: *** 正在等待未完成的任务.... CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/orc_gen.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/orc_dump.o LD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/objtool-in.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/elf.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/special.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/objtool.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libstring.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/str_error_r.o HOSTCC arch/x86/tools/relocs_32.o HOSTCC arch/x86/tools/relocs_64.o WRAP arch/x86/include/generated/asm/dma-contiguous.h HOSTCC arch/x86/tools/relocs_common.o WRAP arch/x86/include/generated/asm/early_ioremap.h WRAP arch/x86/include/generated/asm/export.h WRAP arch/x86/include/generated/asm/mcs_spinlock.h WRAP arch/x86/include/generated/asm/mm-arch-hooks.h CC scripts/mod/empty.o HOSTCC scripts/mod/mk_elfconfig HOSTLD arch/x86/tools/relocs CC scripts/mod/devicetable-offsets.s LD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/objtool-in.o make[1]: *** [Makefile:63:objtool] 错误 2 make: *** [Makefile:1644:tools/objtool] 错误 2 make: *** 正在等待未完成的任务.... MKELF scripts/mod/elfconfig.h HOSTCC scripts/kallsyms HOSTCC scripts/selinux/genheaders/genheaders In file included from scripts/selinux/genheaders/genheaders.c:19: ./security/selinux/include/classmap.h:249:2: error: #error New address family defined, please update secclass_map. 249 | #error New address family defined, please update secclass_map. | ^~~~~ HOSTCC scripts/selinux/mdp/mdp make[3]: *** [scripts/Makefile.host:90:scripts/selinux/genheaders/genheaders] 错误 1 make[2]: *** [scripts/Makefile.build:546:scripts/selinux/genheaders] 错误 2 make[2]: *** 正在等待未完成的任务.... HOSTCC scripts/mod/modpost.o HOSTCC scripts/pnmtologo In file included from scripts/selinux/mdp/mdp.c:49: ./security/selinux/include/classmap.h:249:2: error: #error New address family defined, please update secclass_map. 249 | #error New address family defined, please update secclass_map. | ^~~~~ make[3]: *** [scripts/Makefile.host:90:scripts/selinux/mdp/mdp] 错误 1 make[2]: *** [scripts/Makefile.build:546:scripts/selinux/mdp] 错误 2 make[1]: *** [scripts/Makefile.build:546:scripts/selinux] 错误 2 make[1]: *** 正在等待未完成的任务.... UPD scripts/mod/devicetable-offsets.h HOSTCC scripts/mod/sumversion.o HOSTCC scripts/mod/file2alias.o HOSTLD scripts/mod/modpost make: *** [Makefile:1067:scripts] 错误 2
最新发布
08-06
mouse@mouse-virtual-machine:~/workspace/kernel/linux-4.19.3$ make -j8 scripts/kconfig/conf --syncconfig Kconfig SYSTBL arch/x86/include/generated/asm/syscalls_32.h SYSHDR arch/x86/include/generated/asm/unistd_32_ia32.h SYSTBL arch/x86/include/generated/asm/syscalls_64.h SYSHDR arch/x86/include/generated/asm/unistd_64_x32.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_64.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_32.h SYSHDR arch/x86/include/generated/uapi/asm/unistd_x32.h UPD include/config/kernel.release WRAP arch/x86/include/generated/uapi/asm/bpf_perf_event.h WRAP arch/x86/include/generated/uapi/asm/poll.h UPD include/generated/uapi/linux/version.h UPD include/generated/utsrelease.h DESCEND objtool HOSTCC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep.o HOSTLD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep-in.o LINK /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/fixdep CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/builtin-check.o GEN /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/lib/inat-tables.c CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/decode.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/exec-cmd.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/builtin-orc.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/help.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/pager.o In file included from help.c:12: In function ‘xrealloc’, inlined from ‘add_cmdname’ at help.c:24:2: subcmd-util.h:56:23: error: pointer may be used after ‘realloc’ [-Werror=use-after-free] 56 | ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ subcmd-util.h:52:21: note: call to ‘realloc’ here 52 | void *ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ subcmd-util.h:58:31: error: pointer may be used after ‘realloc’ [-Werror=use-after-free] 58 | ret = realloc(ptr, 1); | ^~~~~~~~~~~~~~~ subcmd-util.h:52:21: note: call to ‘realloc’ here 52 | void *ret = realloc(ptr, size); | ^~~~~~~~~~~~~~~~~~ CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/check.o cc1: all warnings being treated as errors mv: 对 ‘/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/.help.o.tmp’ 调用 stat 失败: 没有那个文件或目录 make[4]: *** [/home/mouse/workspace/kernel/linux-4.19.3/tools/build/Makefile.build:96:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/help.o] 错误 1 make[3]: *** [Makefile:52:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libsubcmd-in.o] 错误 2 make[2]: *** [Makefile:54:/home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libsubcmd.a] 错误 2 make[2]: *** 正在等待未完成的任务… CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/orc_gen.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/orc_dump.o LD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/arch/x86/objtool-in.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/elf.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/special.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/objtool.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/libstring.o CC /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/str_error_r.o HOSTCC arch/x86/tools/relocs_32.o HOSTCC arch/x86/tools/relocs_64.o WRAP arch/x86/include/generated/asm/dma-contiguous.h HOSTCC arch/x86/tools/relocs_common.o WRAP arch/x86/include/generated/asm/early_ioremap.h WRAP arch/x86/include/generated/asm/export.h WRAP arch/x86/include/generated/asm/mcs_spinlock.h WRAP arch/x86/include/generated/asm/mm-arch-hooks.h CC scripts/mod/empty.o HOSTCC scripts/mod/mk_elfconfig HOSTLD arch/x86/tools/relocs CC scripts/mod/devicetable-offsets.s LD /home/mouse/workspace/kernel/linux-4.19.3/tools/objtool/objtool-in.o make[1]: *** [Makefile:63:objtool] 错误 2 make: *** [Makefile:1644:tools/objtool] 错误 2 make: *** 正在等待未完成的任务… MKELF scripts/mod/elfconfig.h HOSTCC scripts/kallsyms HOSTCC scripts/selinux/genheaders/genheaders In file included from scripts/selinux/genheaders/genheaders.c:19: ./security/selinux/include/classmap.h:249:2: error: #error New address family defined, please update secclass_map. 249 | #error New address family defined, please update secclass_map. | ^~~~~ HOSTCC scripts/selinux/mdp/mdp make[3]: *** [scripts/Makefile.host:90:scripts/selinux/genheaders/genheaders] 错误 1 make[2]: *** [scripts/Makefile.build:546:scripts/selinux/genheaders] 错误 2 make[2]: *** 正在等待未完成的任务… HOSTCC scripts/mod/modpost.o HOSTCC scripts/pnmtologo In file included from scripts/selinux/mdp/mdp.c:49: ./security/selinux/include/classmap.h:249:2: error: #error New address family defined, please update secclass_map. 249 | #error New address family defined, please update secclass_map. | ^~~~~ make[3]: *** [scripts/Makefile.host:90:scripts/selinux/mdp/mdp] 错误 1 make[2]: *** [scripts/Makefile.build:546:scripts/selinux/mdp] 错误 2 make[1]: *** [scripts/Makefile.build:546:scripts/selinux] 错误 2 make[1]: *** 正在等待未完成的任务… UPD scripts/mod/devicetable-offsets.h HOSTCC scripts/mod/sumversion.o HOSTCC scripts/mod/file2alias.o HOSTLD scripts/mod/modpost make: *** [Makefile:1067:scripts] 错误 2
08-06
processing option: kernel ============Start build kernel============ TARGET_ARCH =arm64 TARGET_KERNEL_CONFIG =rockchip_linux_defconfig TARGET_KERNEL_DTS =itop-3399_linux-lvds ========================================== # # No change to .config # arch/arm64/Makefile:36: Detected assembler with broken .inst; disassembly will be unreliable arch/arm64/Makefile:36: Detected assembler with broken .inst; disassembly will be unreliable GEN arch/arm64/include/generated/asm/cpucaps.h GEN arch/arm64/include/generated/asm/sysreg-defs.h DTC arch/arm64/boot/dts/rockchip/itop-3399_linux-lvds.dtb warning: ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum warning: LSE atomics not supported by binutils Error: arch/arm64/boot/dts/rockchip/itop-3399_linux-lvds.dts:206.65-66 syntax error FATAL ERROR: Unable to parse input tree scripts/Makefile.lib:423: recipe for target 'arch/arm64/boot/dts/rockchip/itop-3399_linux-lvds.dtb' failed make[3]: *** [arch/arm64/boot/dts/rockchip/itop-3399_linux-lvds.dtb] Error 1 scripts/Makefile.build:503: recipe for target 'arch/arm64/boot/dts/rockchip' failed make[2]: *** [arch/arm64/boot/dts/rockchip] Error 2 Makefile:1466: recipe for target 'rockchip/itop-3399_linux-lvds.dtb' failed make[1]: *** [rockchip/itop-3399_linux-lvds.dtb] Error 2 make[1]: *** Waiting for unfinished jobs.... CC scripts/mod/empty.o HOSTCC scripts/mod/mk_elfconfig CC scripts/mod/devicetable-offsets.s gcc: error: unrecognized command line option ‘-mlittle-endian’ gcc: error: unrecognized command line option ‘-mgeneral-regs-only’ scripts/Makefile.build:250: recipe for target 'scripts/mod/empty.o' failed make[2]: *** [scripts/mod/empty.o] Error 1 make[2]: *** Waiting for unfinished jobs.... gcc: error: unrecognized command line option ‘-mlittle-endian’ gcc: error: unrecognized command line option ‘-mgeneral-regs-only’ scripts/Makefile.build:118: recipe for target 'scripts/mod/devicetable-offsets.s' failed make[2]: *** [scripts/mod/devicetable-offsets.s] Error 1 Makefile:1283: recipe for target 'prepare0' failed make[1]: *** [prepare0] Error 2 arch/arm64/Makefile:221: recipe for target 'itop-3399_linux-lvds.img' failed make: *** [itop-3399_linux-lvds.img] Error 2 ====Build kernel failed!====
07-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值