【问题标题】:Assembler error when using 'dccmvac' in a kernel module在内核模块中使用“dccmvac”时的汇编器错误
【发布时间】:2020-07-30 00:54:04
【问题描述】:

当我尝试在 Raspberry Pi 3B+(ARMv8a、AARCH32)上的内核模块中编译以下代码时,我收到“错误指令”错误。根据 ARMv8a 的 ARM 参考手册,此指令在 AARCH32 的异常级别 0 (EL0) 中未定义,但我在内核模块中使用它,所以我不明白这个问题。

__asm(
"mov r9,%0 \n\t"
"mov r10,%1 \n\t"
"mov r1,#0 \n\t
"str r1,[r9] \n\t"
"str r1,[r10] \n\t"
"DCCMVAC r9 \n\t"
"DCCMVAC r10 \n\t"
:
:"r" (firstPtr),
 "r" (secondPtr)
:"r1","r9","r10","memory"
);

汇编相关消息如下,

/tmp/ccCmW5TY.s: Assembler messages:
/tmp/ccCmW5TY.s:221: Error: bad instruction `dccmvac r9'
/tmp/ccCmW5TY.s:222: Error: bad instruction `dccmvac r10'

【问题讨论】:

  • 在 inline-asm 语句中硬编码 r9 和 r10 意味着您需要在这些寄存器上声明一个clobber。此外,您不会要求编译器在r0 中添加任何内容,因此这个 asm 片段不可能成为未损坏程序的一部分。 (请注意,官方不支持在 naked 函数中使用任何操作数,因此这不应该是 naked 函数的整个主体,其中包含调用约定中 r0 中的内容。)
  • 非常感谢 cmets。该代码只是我放入内核模块中的原始汇编程序的一部分,以测试错误指令错误是否在更高的特权级别消失。因此,该代码不打算用作内联汇编。
  • 在这种情况下,我会使用 .S 文件创建 minimal reproducible example,而不是伪造的内联汇编。
  • 现在应该修复了。

标签: assembly arm raspberry-pi3


【解决方案1】:

GNU as 可能无法识别DCCMVAC 指令: 根据 Arm 文档,DCCMVAC 指令是通过在CP15 协处理器上执行操作来执行的:

MCR{<c>}{<q>} <coproc>, {#}<opc1>, <Rt>, <CRn>, <CRm>{, {#}<opc2>} 
with the following values:
coproc  opc1    CRn     CRm     opc2
0b1111  0b000   0b0111  0b1010  0b001

CMSIS_5 项目中有一个实现,形式如下定义/函数/宏,在文件CMSIS/Core_A/Include/cmsis_gcc.hCMSIS/Core_A/Include/cmsis_cp15.h 中。

我们可以重复使用一些代码来构建示例程序dccmvac.c

#include <stdint.h>
  
#define __ASM                                  __asm
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
#define __STATIC_FORCEINLINE                   __attribute__((always_inline)) static inline

/** \brief  Set DCCMVAC
    
  Data cache clean
 */
__STATIC_FORCEINLINE void __set_DCCMVAC(uint32_t value)
{
  __set_CP(15, 0, value, 7, 10, 1);
}

int main()
{
  __set_DCCMVAC(0x12345678U);

  return 0;
}


/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc -c -o dccmvac.o dccmvac.c
/opt/arm/9/gcc-arm-9.2-2019.12-x86_64-arm-none-eabi/bin/arm-none-eabi-objdump -D  dccmvac.o



dccmvac.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <main>:
   0:   e52db004        push    {fp}            ; (str fp, [sp, #-4]!)
   4:   e28db000        add     fp, sp, #0
   8:   e24dd00c        sub     sp, sp, #12
   c:   e59f3020        ldr     r3, [pc, #32]   ; 34 <main+0x34>
  10:   e50b3008        str     r3, [fp, #-8]
  14:   e51b3008        ldr     r3, [fp, #-8]
  18:   ee073f3a        mcr     15, 0, r3, cr7, cr10, {1}
  1c:   e1a00000        nop                     ; (mov r0, r0)
  20:   e3a03000        mov     r3, #0
  24:   e1a00003        mov     r0, r3
  28:   e28bd000        add     sp, fp, #0
  2c:   e49db004        pop     {fp}            ; (ldr fp, [sp], #4)
  30:   e12fff1e        bx      lr
  34:   12345678        eorsne  r5, r4, #120, 12        ; 0x7800000

0x123456781 正在加载到 r3,然后 mcr 15, 0, r3, cr7, cr10, {1} 正在执行。

反汇编0xee073f3a使用shell-storm给出:

0x0000000000000000: EE 07 3F 3A mcr p15, #0, r3, c7, c10, #1

您现在应该拥有在代码中使用 DCCMVAC 指令所需的信息 - 请记住,Arm CMSIS_5 代码已根据 Apache-2.0 许可证获得许可,因此不能仅复制/粘贴到一个 Linux 内核模块 - 您可能应该改用在 arch/arm/mm/cache-v7m.S 中定义的 Linux dccmvac 宏,或者编写您自己的等效代码。

【讨论】:

  • 在哪里指定 r3 作为 MCR 的参数?我的理解是,在您的代码中,值 0x12345678U 分配给 Rt,而我期望它类似于 R3。
  • 在 Arm 文档中,Rt 是一种符号表示法,使用一种快捷方式表示指令可以使用任何通用寄存器。也就是说,当您看到提到 Rt 时,您可以将 替换为 3 ,这意味着 R3 将是实际使用的寄存器。我没有看到汇编代码对 Rt 的任何引用,只是对 R3 的一个引用。代码由 C 编译器从 __set_DCCMVAC(0x12345678U); 生成。也就是说,编译器决定使用 3 作为 的值,即使用 R3 寄存器。这能回答你的问题吗?
猜你喜欢
  • 2012-11-20
  • 2015-08-30
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
相关资源
最近更新 更多