Попытка понять часть сборки встроенного кронштейна из ядра Linux - PullRequest
0 голосов
/ 28 февраля 2019

Я пытаюсь понять, что делает этот фрагмент встроенной сборки, сгенерированный из макроса C DEFINE:

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

#define offsetof(TYPE, MEMBER)  ((size_t)&((TYPE *)0)->MEMBER)

Он используется в какой-то магии для выполнения AArch64 smcвызовы в linux-imx форке ядра.Место, где вышеупомянутые макросы C используются для определения значений: здесь :

// 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));
    (...)
}

И позже, эти определения используются в макросе сборки, доступном здесь (или, по крайней мере, так выглядит):

// 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.

Любые идеи, для чего он расширен, или как успешно скомпилировать это?

1 Ответ

0 голосов
/ 28 февраля 2019

Вы получаете ошибки, потому что этот файл не должен быть скомпилирован в объект.Он используется только для генерации вывода сборки, который затем обрабатывается для создания заголовка 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)   # */
...