CC2538 (Cortex m3) 启动硬故障,在 __lib_init_array
Hardfault on CC2538 (Cortex m3) startup, in __lib_init_array
我正在尝试将 mbed-os (RTX RTOS) 项目移植到 CC2538 (ARM Cortex M3),它是使用集成了 arm-none- 的 mbed-cli 工具链编译的eabi-gcc。当我尝试启动 MCU 时,我遇到了 Hard Fault error in startup.
00202678 <__libc_init_array>:
202678: b570 push {r4, r5, r6, lr}
20267a: 4e0f ldr r6, [pc, #60] ; (2026b8 <__libc_init_array+0x40>)
20267c: 4d0f ldr r5, [pc, #60] ; (2026bc <__libc_init_array+0x44>)
20267e: 1b76 subs r6, r6, r5
202680: 10b6 asrs r6, r6, #2
202682: bf18 it ne
202684: 2400 movne r4, #0
202686: d005 beq.n 202694 <__libc_init_array+0x1c>
202688: 3401 adds r4, #1
20268a: f855 3b04 ldr.w r3, [r5], #4
20268e: 4798 blx r3
202690: 42a6 cmp r6, r4
202692: d1f9 bne.n 202688 <__libc_init_array+0x10>
202694: 4e0a ldr r6, [pc, #40] ; (2026c0 <__libc_init_array+0x48>)
202696: 4d0b ldr r5, [pc, #44] ; (2026c4 <__libc_init_array+0x4c>)
202698: f004 fec2 bl 207420 <_etext>
20269c: 1b76 subs r6, r6, r5
20269e: 10b6 asrs r6, r6, #2
2026a0: bf18 it ne
2026a2: 2400 movne r4, #0
2026a4: d006 beq.n 2026b4 <__libc_init_array+0x3c>
2026a6: 3401 adds r4, #1
2026a8: f855 3b04 ldr.w r3, [r5], #4
2026ac: 4798 blx r3
2026ae: 42a6 cmp r6, r4
2026b0: d1f9 bne.n 2026a6 <__libc_init_array+0x2e>
2026b2: bd70 pop {r4, r5, r6, pc}
2026b4: bd70 pop {r4, r5, r6, pc}
2026b6: bf00 nop
我跟踪了代码流,最后一步 PC 正在执行
2026a4: d006 beq.n 2026b4 <__libc_init_array+0x3c>
然后
2026b4: bd70 pop {r4, r5, r6, pc}
此时PC得到值0,然后跳转到地址0x00000000,导致
硬故障错误。
在 cpu 之后执行
202678: b570 push {r4, r5, r6, lr}
[register]
R0 =00000000
R1 =00000001
R2 =00000000
R3 =00000002
R4 =00000000
R5 =00000000
R6 =00000000
R7 =00000000
R8 =00000000
R9 =00000000
R10=00000000
R11=00000000
R12=00200F51
SP =200019F0
LR =00200A77
PC =0020267A
[memory]
200019b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019d0: f0 09 00 20 00 00 00 00 00 00 00 00 04 0a 00 20
200019e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019f0: 00 00 00 00 00 00 00 00 00 00 00 00 77 0a 20 00
20001a00: 00 00 00 00 5d 0c 20 00 00 04 00 00 01 01 00 00
在 cpu 执行之前
2026b4: bd70 pop {r4, r5, r6, pc}
调试器转储
[register]
R0 =00000000
R1 =00000001
R2 =00000000
R3 =00000002
R4 =00000000
R5 =00000000
R6 =00000000
R7 =00000000
R8 =00000000
R9 =00000000
R10=00000000
R11=00000000
R12=00200F51
SP =200019C0
LR =0020269D
PC =002026B4
[memory]
200019b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019c0: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019d0: 00 00 00 00 9d 26 20 00 02 00 00 00 00 00 00 00
200019e0: 00 00 00 00 00 00 00 00 00 00 00 00 9d 26 20 00
200019f0: 00 00 00 00 00 00 00 00 00 00 00 00 77 0a 20 00
20001a00: 00 00 00 00 5d 0c 20 00 00 04 00 00 01 01 00 00
如果我在 __libc_init_array 中执行 pop 寄存器指令时手动将 StackPointer 修改为 0x200019f0
。
我发现它最后会成功跳转到 main() 。
看来问题解决了。
我的问题是为什么堆栈控制在 __libc_init_array() 中出错?
我什至在mbed-os整个项目下都找不到__libc_init_array()函数的实现源码
附上 .ld 文件
MEMORY
{
FLASH_FW (rx) : ORIGIN = 0x00200000 + 0,
LENGTH = (0x00200000 + (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x0000FFF0) >> 4) << 10) - 0x0000002C) - (0x00200000 + 0)
FLASH_CCA (RX) : ORIGIN = (0x00200000 + (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x0000FFF0) >> 4) << 10) - 0x0000002C), LENGTH = 0x0000002C
NRSRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0
FRSRAM (RWX) : ORIGIN = (((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10) - ((((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)) < (16384)) ? ((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)) : (16384))) ? 0x20000000 : 0x20004000), LENGTH = (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(flash_cca_lock_page)
SECTIONS
{
.text :
{
_text = .;
*(.vectors)
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH_FW= 0
.socdata (NOLOAD) :
{
*(.udma_channel_control_table)
} > FRSRAM
.data : ALIGN(4)
{
_data = .;
*(.data*)
_edata = .;
} > FRSRAM AT > FLASH_FW
_ldata = LOADADDR(.data);
.ARM.exidx :
{
*(.ARM.exidx*)
} > FLASH_FW
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > FRSRAM
.heap :
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
.stack (NOLOAD) :
{
*(.stack)
} > FRSRAM
_heap = .;
_eheap = ORIGIN(FRSRAM) + LENGTH(FRSRAM);
.nrdata (NOLOAD) :
{
_nrdata = .;
*(.nrdata*)
_enrdata = .;
} > NRSRAM
.flashcca :
{
*(.flashcca)
} > FLASH_CCA
}
@notlikethat 是对的,问题是 link 脚本文件,但根本原因不是部分重叠。正如我上面的 post。在 __libc_init_array()
202678: b570 push {r4, r5, r6, lr}
此时栈指针指向0x200019F0
,但有些pop操作时栈指针指向0x200019C0
,导致Hardfault错误。我跟踪了代码流,在 __libc_init_array()
中,它将跳转到
处的 <_init>
部分
202698: f004 fec2 bl 207420 <_etext>
记忆中的样子
00207420 <_init>:
207420: b5f8 push {r3, r4, r5, r6, r7, lr}
207422: bf00 nop
00207424 <_fini>:
207426: b5f8 push {r3, r4, r5, r6, r7, lr}
207428: bf00 nop
我想知道这个函数会导致堆栈指针超过计数,因为 <_init>
部分只显示 push 指令而没有 pop 指令。
我对 <_init>
部分做了更多的网络搜索,并确认这不应该只有 2 条指令。它受 linker 文件影响。
在之前的 linker 文件中,我没有注意 .init
& .fini
部分。
然后我做了一些修改,看起来像
.text :
{
_text = .;
*(.vectors)
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
_etext = .;
} > FLASH_FW= 0
.socdata (NOLOAD) :
编译后 <_init> 和 <_fini> 部分已更改如下。
00207040 <_init>:
207040: b5f8 push {r3, r4, r5, r6, r7, lr}
207042: bf00 nop
207044: bcf8 pop {r3, r4, r5, r6, r7}
207046: bc08 pop {r3}
207048: 469e mov lr, r3
20704a: 4770 bx lr
0020704c <_fini>:
20704c: b5f8 push {r3, r4, r5, r6, r7, lr}
20704e: bf00 nop
207050: bcf8 pop {r3, r4, r5, r6, r7}
207052: bc08 pop {r3}
207054: 469e mov lr, r3
207056: 4770 bx lr
207058: 6465626d .word 0x6465626d
20705c: 73736120 .word 0x73736120
207060: 61747265 .word 0x61747265
207064: 6e6f6974 .word 0x6e6f6974
207068: 69616620 .word 0x69616620
20706c: 3a64656c .word 0x3a64656c
207070: 2c732520 .word 0x2c732520
207074: 6c696620 .word 0x6c696620
207078: 25203a65 .word 0x25203a65
然后成功跳入main()
我正在尝试将 mbed-os (RTX RTOS) 项目移植到 CC2538 (ARM Cortex M3),它是使用集成了 arm-none- 的 mbed-cli 工具链编译的eabi-gcc。当我尝试启动 MCU 时,我遇到了 Hard Fault error in startup.
00202678 <__libc_init_array>:
202678: b570 push {r4, r5, r6, lr}
20267a: 4e0f ldr r6, [pc, #60] ; (2026b8 <__libc_init_array+0x40>)
20267c: 4d0f ldr r5, [pc, #60] ; (2026bc <__libc_init_array+0x44>)
20267e: 1b76 subs r6, r6, r5
202680: 10b6 asrs r6, r6, #2
202682: bf18 it ne
202684: 2400 movne r4, #0
202686: d005 beq.n 202694 <__libc_init_array+0x1c>
202688: 3401 adds r4, #1
20268a: f855 3b04 ldr.w r3, [r5], #4
20268e: 4798 blx r3
202690: 42a6 cmp r6, r4
202692: d1f9 bne.n 202688 <__libc_init_array+0x10>
202694: 4e0a ldr r6, [pc, #40] ; (2026c0 <__libc_init_array+0x48>)
202696: 4d0b ldr r5, [pc, #44] ; (2026c4 <__libc_init_array+0x4c>)
202698: f004 fec2 bl 207420 <_etext>
20269c: 1b76 subs r6, r6, r5
20269e: 10b6 asrs r6, r6, #2
2026a0: bf18 it ne
2026a2: 2400 movne r4, #0
2026a4: d006 beq.n 2026b4 <__libc_init_array+0x3c>
2026a6: 3401 adds r4, #1
2026a8: f855 3b04 ldr.w r3, [r5], #4
2026ac: 4798 blx r3
2026ae: 42a6 cmp r6, r4
2026b0: d1f9 bne.n 2026a6 <__libc_init_array+0x2e>
2026b2: bd70 pop {r4, r5, r6, pc}
2026b4: bd70 pop {r4, r5, r6, pc}
2026b6: bf00 nop
我跟踪了代码流,最后一步 PC 正在执行
2026a4: d006 beq.n 2026b4 <__libc_init_array+0x3c>
然后
2026b4: bd70 pop {r4, r5, r6, pc}
此时PC得到值0,然后跳转到地址0x00000000,导致 硬故障错误。
在 cpu 之后执行
202678: b570 push {r4, r5, r6, lr}
[register]
R0 =00000000
R1 =00000001
R2 =00000000
R3 =00000002
R4 =00000000
R5 =00000000
R6 =00000000
R7 =00000000
R8 =00000000
R9 =00000000
R10=00000000
R11=00000000
R12=00200F51
SP =200019F0
LR =00200A77
PC =0020267A
[memory]
200019b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019d0: f0 09 00 20 00 00 00 00 00 00 00 00 04 0a 00 20
200019e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019f0: 00 00 00 00 00 00 00 00 00 00 00 00 77 0a 20 00
20001a00: 00 00 00 00 5d 0c 20 00 00 04 00 00 01 01 00 00
在 cpu 执行之前
2026b4: bd70 pop {r4, r5, r6, pc}
调试器转储
[register]
R0 =00000000
R1 =00000001
R2 =00000000
R3 =00000002
R4 =00000000
R5 =00000000
R6 =00000000
R7 =00000000
R8 =00000000
R9 =00000000
R10=00000000
R11=00000000
R12=00200F51
SP =200019C0
LR =0020269D
PC =002026B4
[memory]
200019b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019c0: 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
200019d0: 00 00 00 00 9d 26 20 00 02 00 00 00 00 00 00 00
200019e0: 00 00 00 00 00 00 00 00 00 00 00 00 9d 26 20 00
200019f0: 00 00 00 00 00 00 00 00 00 00 00 00 77 0a 20 00
20001a00: 00 00 00 00 5d 0c 20 00 00 04 00 00 01 01 00 00
如果我在 __libc_init_array 中执行 pop 寄存器指令时手动将 StackPointer 修改为 0x200019f0
。
我发现它最后会成功跳转到 main() 。
看来问题解决了。
我的问题是为什么堆栈控制在 __libc_init_array() 中出错?
我什至在mbed-os整个项目下都找不到__libc_init_array()函数的实现源码
附上 .ld 文件
MEMORY
{
FLASH_FW (rx) : ORIGIN = 0x00200000 + 0,
LENGTH = (0x00200000 + (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x0000FFF0) >> 4) << 10) - 0x0000002C) - (0x00200000 + 0)
FLASH_CCA (RX) : ORIGIN = (0x00200000 + (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x0000FFF0) >> 4) << 10) - 0x0000002C), LENGTH = 0x0000002C
NRSRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 0
FRSRAM (RWX) : ORIGIN = (((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10) - ((((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)) < (16384)) ? ((((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)) : (16384))) ? 0x20000000 : 0x20004000), LENGTH = (((((0) << 0 | (512) << 4 | (32) << 16 | ((1) ? 0x01000000 : 0) | ((1) ? 0x02000000 : 0)) & 0x00FF0000) >> 16) << 10)
}
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(flash_cca_lock_page)
SECTIONS
{
.text :
{
_text = .;
*(.vectors)
*(.text*)
*(.rodata*)
_etext = .;
} > FLASH_FW= 0
.socdata (NOLOAD) :
{
*(.udma_channel_control_table)
} > FRSRAM
.data : ALIGN(4)
{
_data = .;
*(.data*)
_edata = .;
} > FRSRAM AT > FLASH_FW
_ldata = LOADADDR(.data);
.ARM.exidx :
{
*(.ARM.exidx*)
} > FLASH_FW
.bss :
{
_bss = .;
*(.bss*)
*(COMMON)
_ebss = .;
} > FRSRAM
.heap :
{
__end__ = .;
end = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
.stack (NOLOAD) :
{
*(.stack)
} > FRSRAM
_heap = .;
_eheap = ORIGIN(FRSRAM) + LENGTH(FRSRAM);
.nrdata (NOLOAD) :
{
_nrdata = .;
*(.nrdata*)
_enrdata = .;
} > NRSRAM
.flashcca :
{
*(.flashcca)
} > FLASH_CCA
}
@notlikethat 是对的,问题是 link 脚本文件,但根本原因不是部分重叠。正如我上面的 post。在 __libc_init_array()
202678: b570 push {r4, r5, r6, lr}
此时栈指针指向0x200019F0
,但有些pop操作时栈指针指向0x200019C0
,导致Hardfault错误。我跟踪了代码流,在 __libc_init_array()
中,它将跳转到
<_init>
部分
202698: f004 fec2 bl 207420 <_etext>
记忆中的样子
00207420 <_init>:
207420: b5f8 push {r3, r4, r5, r6, r7, lr}
207422: bf00 nop
00207424 <_fini>:
207426: b5f8 push {r3, r4, r5, r6, r7, lr}
207428: bf00 nop
我想知道这个函数会导致堆栈指针超过计数,因为 <_init>
部分只显示 push 指令而没有 pop 指令。
我对 <_init>
部分做了更多的网络搜索,并确认这不应该只有 2 条指令。它受 linker 文件影响。
在之前的 linker 文件中,我没有注意 .init
& .fini
部分。
然后我做了一些修改,看起来像
.text :
{
_text = .;
*(.vectors)
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
_etext = .;
} > FLASH_FW= 0
.socdata (NOLOAD) :
编译后 <_init> 和 <_fini> 部分已更改如下。
00207040 <_init>:
207040: b5f8 push {r3, r4, r5, r6, r7, lr}
207042: bf00 nop
207044: bcf8 pop {r3, r4, r5, r6, r7}
207046: bc08 pop {r3}
207048: 469e mov lr, r3
20704a: 4770 bx lr
0020704c <_fini>:
20704c: b5f8 push {r3, r4, r5, r6, r7, lr}
20704e: bf00 nop
207050: bcf8 pop {r3, r4, r5, r6, r7}
207052: bc08 pop {r3}
207054: 469e mov lr, r3
207056: 4770 bx lr
207058: 6465626d .word 0x6465626d
20705c: 73736120 .word 0x73736120
207060: 61747265 .word 0x61747265
207064: 6e6f6974 .word 0x6e6f6974
207068: 69616620 .word 0x69616620
20706c: 3a64656c .word 0x3a64656c
207070: 2c732520 .word 0x2c732520
207074: 6c696620 .word 0x6c696620
207078: 25203a65 .word 0x25203a65
然后成功跳入main()