【问题标题】:Trying to understand a piece of inline arm assembly from the linux kernel试图从 linux 内核中理解一段内联 arm 程序集
【发布时间】:2019-07-22 09:36:51
【问题描述】:

我试图了解这段内联汇编的作用,它是从 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 内核分支中执行 AArch64 smc 调用的一些魔法。以上C宏定义值的地方是here

// 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 宏中使用字符串化和->

有什么想法可以扩展成什么,或者如何成功编译它?

【问题讨论】:

  • [macro] 标签是这些标签中最不重要的...不能适合内联汇编
  • 在源文件上使用gcc -S 为该文件生成程序集。大概DEFINEs 只在程序集文件的中间才有意义——这就是asm volatile 的作用,以确保它们不会被移动......

标签: c gcc assembly gnu-assembler arm64


【解决方案1】:

您会收到错误,因为该文件不应该被编译为对象。它仅用于生成程序集输出,然后对其进行处理以创建标题asm_offsets.h。该标头是随后包含在其他地方的内容。您可以在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:->#\(.*\):/* \1 */:; \
        s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \
        s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
        s:->::; p;}"
endef

您可以看到它使用sed 将程序集输出转换为标题。临时程序集文件可以在arch/<arch>/kernel/asm-offsets.s 中找到。示例行如下所示:

->pt_regs_bx $40 offsetof(struct pt_regs, bx)   #
->pt_regs_cx $88 offsetof(struct pt_regs, cx)   #
->pt_regs_dx $96 offsetof(struct pt_regs, dx)   #

请注意,这不是有效的汇编语法,但编译器不在乎,它会在进行参数替换后无意识地发出您放入 asm 块中的任何内容。然后sed 命令转换它们,使标题中的匹配行看起来像:

#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)   # */

【讨论】:

    猜你喜欢
    • 2013-05-14
    • 1970-01-01
    • 2012-03-23
    • 2019-12-12
    • 1970-01-01
    • 2012-03-27
    • 2014-02-05
    • 2013-10-20
    • 1970-01-01
    相关资源
    最近更新 更多