【问题标题】:cortex m1 hard fault at ldrshldrsh 的 cortex m1 硬故障
【发布时间】:2016-12-18 09:02:56
【问题描述】:

大家好,我的 cortex m1 在同一个地方多次出现 HardFault 异常。我有 HardFault 实现,我可以读取堆栈寄存器:

stacked_r0 unsigned int 0x4(十六进制)
堆叠 r1 无符号整数 0x60905f98(十六进制)
堆叠 r2 无符号整数 0x0(十六进制)
堆叠 r3 无符号整数 0x6092304b(十六进制)
stack_r12 unsigned int 0x60922ff8(十六进制)
stack_lr unsigned int 0x60810be3(十六进制)
stack_pc unsigned int 0x60810ce2(十六进制)
stack_psr unsigned int 0x41000000(十六进制)

在堆叠 PC 上的操作是: 60810ce2:ldrsh r2,[r3,r2]

为什么会导致故障?

更新 我已经重新排列了变量,现在它已经在从 freertos 代码调用的 memcpy 中崩溃了

stacked_r0 unsigned int 0x6090c858(十六进制)
堆叠 r1 无符号整数 0x6091f8b4(十六进制)
堆叠 r2 无符号整数 0x3c(十六进制)
堆叠 r3 无符号整数 0x6091f8a4(十六进制)
堆叠 r12 无符号整数 0x280(十六进制) stack_lr unsigned int 0x60827f89(十六进制)
stack_pc unsigned int 0x6082b0dc(十六进制)
stack_psr unsigned int 0x1000000 (十六进制)

6082b0ba: bne.n 0x6082b120

6082b0bc:添加 r5、r2、#0

6082b0be: 添加 r4, r0, #0

6082b0c0: subs r5, #16

6082b0c2: lsrs r5, r5, #4

6082b0c4:添加 r5,#1

6082b0c6: lsls r5, r5, #4

6082b0c8:添加 r1、r1、r5

6082b0ca: ldr r6, [r3, #0]

6082b0cc: str r6, [r4, #0]

6082b0ce: ldr r6, [r3, #4]

6082b0d0: str r6, [r4, #4]

6082b0d2: ldr r6, [r3, #8]

6082b0d4: str r6, [r4, #8]

6082b0d6: ldr r6, [r3, #12]

6082b0d8:添加 r3,#16

6082b0da: str r6, [r4, #12]

6082b0dc:添加 r4,#16

【问题讨论】:

  • 这是一个未对齐的访问。
  • 好的,但是为什么呢? r3 指向堆栈
  • 堆栈是 ram,堆栈与它有什么关系 ldrsh 或 ldrh 的低位为 0xB 或 1011 ldr 的低位必须为零,低两位必须为零ldrd 后三个必须为零。您正在尝试进行未对齐的半字访问,而处理器正确地阻止了您这样做。
  • 正确。我正在使用 freertos 和 GCC。看起来它生成的代码不会将堆栈地址操作 8 个字节?
  • 如果您想了解编译器正在做什么,您必须提供一个简单的示例函数、编译器和选项,以及输出并从那里开始。不知道为什么 gcc 会使用 r3 或 r2 来访问堆栈,加载与堆栈的对齐无关。

标签: gcc arm cortex-m


【解决方案1】:

编译器使用 ldrsh 生成对齐的简单示例:

short more_fun ( short );
short fun ( short a )
{
    unsigned int ra;
    short x[16];
    for(ra=0;ra<16;ra++)
    {
        a+=more_fun(x[ra]);
    }
    return(a);
}

arm-none-eabi-gcc -mthumb -O2 -c so.c -o so.o -march=armv6-m arm-none-eabi-objdump -D so.o

00000000 <fun>:
   0:   b570        push    {r4, r5, r6, lr}
   2:   b088        sub sp, #32
   4:   0004        movs    r4, r0
   6:   466d        mov r5, sp
   8:   ae08        add r6, sp, #32
   a:   2300        movs    r3, #0
   c:   5ee8        ldrsh   r0, [r5, r3]
   e:   f7ff fffe   bl  0 <more_fun>
  12:   3502        adds    r5, #2
  14:   1904        adds    r4, r0, r4
  16:   b224        sxth    r4, r4
  18:   42b5        cmp r5, r6
  1a:   d1f6        bne.n   a <fun+0xa>
  1c:   0020        movs    r0, r4
  1e:   b008        add sp, #32
  20:   bd70        pop {r4, r5, r6, pc}
  22:   46c0        nop         ; (mov r8, r8)

堆栈保持对齐,堆栈操作、压入、弹出和堆栈帧都是 8 字节(两个字)的倍数。

数组在堆栈上,他们基本上使用 r5 作为数组的索引,看起来 ldrsh 需要两个寄存器,所以他们将 r3 设置为零,这样他们就可以有第二个寄存器。这里的关键是它们开始对齐,假设该代码之外的每个人都符合约定,则 sp 地址至少具有低三位零。然后代码每次通过循环将 2 添加到 r5,保持指向数组的指针在半字边界上对齐,每次使用 ldrsh 时,地址的低位保持为零。没有对齐问题。

请提供类似的示例,可能是代码片段,但肯定是未对齐的 ldrsh 周围的相关片段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 1970-01-01
    • 2020-11-12
    • 2021-12-18
    • 1970-01-01
    相关资源
    最近更新 更多