为啥 PC 加载了包含未定义指令的地址? - STM32H745

Posted

技术标签:

【中文标题】为啥 PC 加载了包含未定义指令的地址? - STM32H745【英文标题】:Why PC is loaded with address containing undefined instruction? - STM32H745为什么 PC 加载了包含未定义指令的地址? - STM32H745 【发布时间】:2021-09-26 04:42:52 【问题描述】:

我在 STM32H745 MCU 上启用 MPU 时遇到问题。我只想禁用 MPU,设置区域然后启用它。然而,HardFault 出现了。我认为这是区域设置错误的问题。但是在评论之后,我注意到打开MPU就会出现问题。

代码:

static syslog_status_t setMPU_sysLog(void)

    [...]
    ARM_MPU_Disable();
    /* ARM_MPU_SetRegion(ARM_MPU_RBAR(0, (uint32_t)NON_CACHABLE_RAM4_D3_BASE_ADDR),
        ARM_MPU_RASR(0UL, ARM_MPU_AP_FULL, 1UL, 0UL, 0UL, 1UL, 0x00UL, ARM_MPU_REGION_SIZE_8KB)); */
    HALT_IF_DEBUGGING();
    ARM_MPU_Enable(0);
    return SYSLOG_OK;

我只使用 CMSIS API,所以我检查程序集并发出警告:

>0x80003ec <setMPU_sysLog+36>    bkpt    0x0001
  0x80003ee <setMPU_sysLog+38>    ldr     r3, [pc, #28]   ; (0x800040c <setMPU_sysLog+68>)
  0x80003f0 <setMPU_sysLog+40>    movs    r2, #1
  0x80003f2 <setMPU_sysLog+42>    str.w   r2, [r3, #148]  ; 0x94
  0x80003f6 <setMPU_sysLog+46>    ldr     r2, [r3, #36]   ; 0x24
  0x80003f8 <setMPU_sysLog+48>    orr.w   r2, r2, #65536  ; 0x10000
  0x80003fc <setMPU_sysLog+52>    str     r2, [r3, #36]   ; 0x24
  0x80003fe <setMPU_sysLog+54>    dsb     sy
  0x8000402 <setMPU_sysLog+58>    isb     sy
  0x8000406 <setMPU_sysLog+62>    movs    r0, #0
  0x8000408 <setMPU_sysLog+64>    bx      lr
  0x800040a <setMPU_sysLog+66>    nop
  0x800040c <setMPU_sysLog+68>                    ; <UNDEFINED> instruction: 0xed00e000
  0x8000410 <initSysLog>          push    r3, lr

在 0x80003ee 中将 UNDEFINED 指令 加载到 PC?什么可能导致此编译器(?)错误?有没有人遇到过这样的问题?如何开始调试呢?附加调试信息如下:

0x08000398 in my_fault_handler_c (frame=0x2001ffb0) at CM7/exceptionHandlers.c:29
29        HALT_IF_DEBUGGING();
(gdb) p/a *frame
$1 = r0 = 0xde684c0e, r1 = 0x6cefc92c, r2 = 0xed5b5cfb, r3 = 0xa3feeed1, r12 = 0xef082047, lr = 0xd7121a9e, return_address = 0xf16a13cf, xpsr = 0xf60e2caf


Fields in SCB > HFSR:
        VECTTBL:   0  Vector table hard fault
        FORCED:    1  Forced hard fault
        DEBUG_VT:  0  Reserved for Debug use
        
Fields in SCB > CFSR_UFSR_BFSR_MMFSR:
        IACCVIOL:     1
        DACCVIOL:     0
        MUNSTKERR:    0
        MSTKERR:      1
        MLSPERR:      0
        MMARVALID:    0
        IBUSERR:      0  Instruction bus error
        PRECISERR:    0  Precise data bus error
        IMPRECISERR:  0  Imprecise data bus error
        UNSTKERR:     0  Bus fault on unstacking for a return from exception
        STKERR:       0  Bus fault on stacking for exception entry
        LSPERR:       0  Bus fault on floating-point lazy state preservation
        BFARVALID:    0  Bus Fault Address Register (BFAR) valid flag
        UNDEFINSTR:   0  Undefined instruction usage fault
        INVSTATE:     0  Invalid state usage fault
        INVPC:        0  Invalid PC load usage fault
        NOCP:         0  No coprocessor usage fault.
        UNALIGNED:    0  Unaligned access usage fault
        DIVBYZERO:    0  Divide by zero usage fault
arm-none-eabi-gcc -v
cc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)

【问题讨论】:

so I check assembly 你如何检查装配?您使用了什么命令和选项? 我只是通过 gdb-multiarch 中的“layout asm”检查了它,并加载了 m7 核心 .elf 文件 我看不到你在看什么。 0x80003ee 处的指令是ldr,它根本不是未定义的,我不明白你为什么会这么认为。 0x800040c 处有一条未定义的指令,但它只是对齐填充的一部分。它不应该被执行(它在bx lr 之后)而且我没有看到任何证据表明它已经被执行。 ldr r3, [pc, #28] ; (0x800040c ) 是不是意味着地址0x800040c包含未定义指令被加载到PC? @NateEldredge 它没有填充它是寄存器的简单地址,因为 Thumb 指令确实有 32 个立即加载 【参考方案1】:

问题是没有设置 PRIVDEFENA 位。因此,按以下方式打开 MPU 有帮助:

ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk);

【讨论】:

【参考方案2】:

这不是未定义的指令。它是您的函数使用的值(在本例中为硬件寄存器块的地址)。 ARM Thumb 指令无法将寄存器设置为 32 位值,因此必须将其存储在内存中并从那里加载。

这不是错误 - 这是非常标准的东西。

例子:

typedef struct

    volatile uint32_t reg1;
    volatile uint32_t reg2;
MYREG_t;

#define MYREG ((MYREG_t *)0xed00e000)

void foo(uint32_t val)

    MYREG -> reg2 = val;



void bar(uint32_t val)

    MYREG -> reg1 = val;

并生成代码:

foo:
        ldr     r3, .L3
        str     r0, [r3, #4]
        bx      lr
.L3:
        .word   -318709760
bar:
        ldr     r3, .L6
        str     r0, [r3]
        bx      lr
.L6:
        .word   -318709760

存储此数据且代码从未到达的位置。您的代码中也是如此。它在得到 tere 之前从函数中返回 (bc lr)

如果您使用反汇编工具(如您所做的那样),它将无法理解并显示未定义的指令。

顺便说一句,您使用的是 arm-none-eabi-gdb 吗?因为它显示了寄存器的无意义值,

【讨论】:

以上是关于为啥 PC 加载了包含未定义指令的地址? - STM32H745的主要内容,如果未能解决你的问题,请参考以下文章

Angular - 使用自定义指令加载多个组件返回未定义

自定义凭据提供程序未加载

为啥自定义指令不能立即反映其代码的变化

为啥我不能跳过这个 div 指令?

为啥在输入地址上使用 getPlace() 时谷歌自动完成返回未定义

单片机的程序存储器和数据存储器共处同一地址空间为啥不会发生总线冲突?