试图从 linux 内核中理解一段内联 arm 程序集
Trying to understand a piece of inline arm assembly from the linux kernel
我想了解这段内联汇编的作用,它是从 C DEFINE
宏生成的:
#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
它被用于在 linux-imx kernel fork. The place where the above C macros are used to define the values is here:
中执行 AArch64 smc
调用的一些魔法
// arch/arm64/kernel/asm-offsets.c
int main(void)
{
(...)
DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
(...)
}
后来,这些定义被用在汇编宏中,available here(或者至少看起来是这样):
// arch/arm64/kernel/smccc-call.S
.macro SMCCC instr
.cfi_startproc
\instr #0
ldr x4, [sp]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
ldr x4, [sp, #8]
cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1: ret
.cfi_endproc
.endm
ENTRY(__arm_smccc_smc)
SMCCC smc
ENDPROC(__arm_smccc_smc)
最终在实践中使用,例如在 gpc-psci driver.
我试图将代码隔离到一个单独的裸机 AArch64 程序中,以查看宏是如何扩展和实际工作的,但我得到的只是编译错误。
// main.c
// the struct arm_smccc_res and others are inserted here to satisfy the compiler
int
main()
{
DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
return 0;
}
// gcc output
/tmp/cccqaaY3.s: Assembler messages:
/tmp/cccqaaY3.s:459: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:464: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:469: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:474: Error: junk at end of line, first unrecognized character is `-'
offsetof
宏是不言自明的,但我无法理解 DEFINE
宏中字符串化和 ->
的使用。
知道它扩展到什么,或者如何成功编译它吗?
您收到错误是因为该文件不应编译为 object。它仅用于生成程序集输出,然后对其进行处理以创建 header asm_offsets.h
。这个 header 是然后包含在其他地方的内容。您可以在 include/generated
中找到它。创建它的规则在顶层 KBuild
:
# Kbuild for top-level directory of the kernel
# This file takes care of the following:
# 1) Generate bounds.h
# 2) Generate timeconst.h
# 3) Generate asm-offsets.h (may need bounds.h and timeconst.h)
# 4) Check for missing system calls
# 5) Generate constants.py (may need bounds.h)
# Default sed regexp - multiline due to syntax constraints
define sed-y
"/^->/{s:->#\(.*\):/* */:; \
s:^->\([^ ]*\) [$$#]*\([-0-9]*\) \(.*\):#define /* */:; \
s:^->\([^ ]*\) [$$#]*\([^ ]*\) \(.*\):#define /* */:; \
s:->::; p;}"
endef
您可以看到它使用 sed
将程序集输出转换为 header。可以在 arch/<arch>/kernel/asm-offsets.s
中找到临时程序集文件。示例行如下所示:
->pt_regs_bx offsetof(struct pt_regs, bx) #
->pt_regs_cx offsetof(struct pt_regs, cx) #
->pt_regs_dx offsetof(struct pt_regs, dx) #
请注意,这不是有效的汇编语法,但编译器并不关心,它会在执行参数替换后无意识地发出您在 asm
块中输入的任何内容。 sed
命令然后转换它们,使 header 中的匹配行看起来像:
#define pt_regs_bx 40 /* offsetof(struct pt_regs, bx) # */
#define pt_regs_cx 88 /* offsetof(struct pt_regs, cx) # */
#define pt_regs_dx 96 /* offsetof(struct pt_regs, dx) # */
我想了解这段内联汇编的作用,它是从 C DEFINE
宏生成的:
#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
它被用于在 linux-imx kernel fork. The place where the above C macros are used to define the values is here:
中执行 AArch64smc
调用的一些魔法
// arch/arm64/kernel/asm-offsets.c
int main(void)
{
(...)
DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
(...)
}
后来,这些定义被用在汇编宏中,available here(或者至少看起来是这样):
// arch/arm64/kernel/smccc-call.S
.macro SMCCC instr
.cfi_startproc
\instr #0
ldr x4, [sp]
stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
ldr x4, [sp, #8]
cbz x4, 1f /* no quirk structure */
ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
b.ne 1f
str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
1: ret
.cfi_endproc
.endm
ENTRY(__arm_smccc_smc)
SMCCC smc
ENDPROC(__arm_smccc_smc)
最终在实践中使用,例如在 gpc-psci driver.
我试图将代码隔离到一个单独的裸机 AArch64 程序中,以查看宏是如何扩展和实际工作的,但我得到的只是编译错误。
// main.c
// the struct arm_smccc_res and others are inserted here to satisfy the compiler
int
main()
{
DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
return 0;
}
// gcc output
/tmp/cccqaaY3.s: Assembler messages:
/tmp/cccqaaY3.s:459: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:464: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:469: Error: junk at end of line, first unrecognized character is `-'
/tmp/cccqaaY3.s:474: Error: junk at end of line, first unrecognized character is `-'
offsetof
宏是不言自明的,但我无法理解 DEFINE
宏中字符串化和 ->
的使用。
知道它扩展到什么,或者如何成功编译它吗?
您收到错误是因为该文件不应编译为 object。它仅用于生成程序集输出,然后对其进行处理以创建 header asm_offsets.h
。这个 header 是然后包含在其他地方的内容。您可以在 include/generated
中找到它。创建它的规则在顶层 KBuild
:
# Kbuild for top-level directory of the kernel
# This file takes care of the following:
# 1) Generate bounds.h
# 2) Generate timeconst.h
# 3) Generate asm-offsets.h (may need bounds.h and timeconst.h)
# 4) Check for missing system calls
# 5) Generate constants.py (may need bounds.h)
# Default sed regexp - multiline due to syntax constraints
define sed-y
"/^->/{s:->#\(.*\):/* */:; \
s:^->\([^ ]*\) [$$#]*\([-0-9]*\) \(.*\):#define /* */:; \
s:^->\([^ ]*\) [$$#]*\([^ ]*\) \(.*\):#define /* */:; \
s:->::; p;}"
endef
您可以看到它使用 sed
将程序集输出转换为 header。可以在 arch/<arch>/kernel/asm-offsets.s
中找到临时程序集文件。示例行如下所示:
->pt_regs_bx offsetof(struct pt_regs, bx) #
->pt_regs_cx offsetof(struct pt_regs, cx) #
->pt_regs_dx offsetof(struct pt_regs, dx) #
请注意,这不是有效的汇编语法,但编译器并不关心,它会在执行参数替换后无意识地发出您在 asm
块中输入的任何内容。 sed
命令然后转换它们,使 header 中的匹配行看起来像:
#define pt_regs_bx 40 /* offsetof(struct pt_regs, bx) # */
#define pt_regs_cx 88 /* offsetof(struct pt_regs, cx) # */
#define pt_regs_dx 96 /* offsetof(struct pt_regs, dx) # */