参考UG585Address Map.csdnstm32的栈监控与HardFault_Handler问题排查.csdn崩溃现象程序崩溃后会跳转到ps7_cortexa9_0\standalone_domain\bsp\ps7_cortexa9_0\libsrc\standalone_v7_3\src\xil_exception.c异常总览表异常类型默认处理函数Xilinx BSPCPU进入时机典型触发场景向量表默认绑定关键寄存器/信息默认行为常见根因重点架构说明Reset复位启动汇编入口上电 / 硬复位瞬间上电、复位按键、看门狗复位Boot ROM / Reset Vector-从头启动系统硬复位、看门狗复位ARM32/64均有最高优先级Undefined InstructionXil_UndefinedExceptionHandler()指令译码阶段ID执行非法机器码、跑飞执行数据区默认绑定该函数UndefinedExceptionAddr打印地址 死循环PC跑飞、Flash损坏、函数指针错误、代码被破坏ARM32/64均支持ARM64为同步异常SVC / SWI系统调用Xil_ExceptionNullHandler()裸机执行 SVC 指令瞬间OS系统调用、特权级切换默认空处理-裸机死循环 / OS接管正常系统调用 / 误执行SVCARM32独立 / ARM64同步异常Prefetch / Instruction AbortXil_PrefetchAbortHandler()取指阶段IFPC跳飞、执行非法代码地址默认绑定该函数PrefetchAbortAddr / IFSR打印寄存器 死循环栈溢出、函数指针错误、return地址破坏、跳转非法地址、MMU禁止执行ARM32为Prefetch Abort / ARM64为Instruction AbortData AbortXil_DataAbortHandler()访存阶段MEM读写非法内存或外设地址默认绑定该函数DataAbortAddr / DFSR打印地址 死循环野指针、堆损坏、栈溢出、free后使用、访问未映射外设ARM32/64均存在ARM64为同步异常IRQ普通中断用户注册 handler默认NullHandlerGIC中断分发后UART、Timer、GPIO等外设中断未注册则NullHandlerGIC CPU Interface寄存器未注册→死循环中断未清、未注册handlerARM32/64均有FIQ快速中断用户注册 handler默认NullHandlerGIC高优先级通道高实时控制、电机控制未注册则NullHandlerGIC高优先级路径未注册→死循环高优先级实时任务ARM32/64均有SError系统错误Xil_SErrorAbortHandler()AArch64异步触发与指令无关ECC错误、AXI总线错误、cache一致性错误AArch64向量表绑定系统错误状态寄存器打印日志 死循环DDR ECC损坏、AXI bus fault、硬件一致性错误ARM64常见ARM32通常归入Abort类问题1中断专用栈被破坏了在中断里调用 AT_println(“ke %d”, code); 崩溃进入 Xil_DataAbortHandler改成 AT_println(“ke”); 正常主循环 注释 BspGetMillis 又不崩把BspGetMillis 代码拷贝到主循环也不崩解决修改 链接脚本 lscript.ldx# 修改_IRQ_STACK_SIZEDEFINED(_IRQ_STACK_SIZE)? _IRQ_STACK_SIZE:1024;# 为_IRQ_STACK_SIZEDEFINED(_IRQ_STACK_SIZE)? _IRQ_STACK_SIZE:4000;lscript.ld分组键值功能解释栈/堆配置_STACK_SIZE0x2000主栈大小System/User 模式栈大小8KB_HEAP_SIZE0x2000堆大小malloc/new 动态内存_ABORT_STACK_SIZE1024Abort栈Data Abort / Prefetch Abort_SUPERVISOR_STACK_SIZE2048SVC栈Supervisor模式_IRQ_STACK_SIZE4000IRQ栈中断模式_FIQ_STACK_SIZE1024FIQ栈快速中断模式_UNDEF_STACK_SIZE1024Undefined栈未定义指令异常MEMORY内存区域ps7_ddr_00x00100000~0x3FFFFFFFDDR区域主程序运行内存ps7_qspi_linear_00xFC000000~0xFCFFFFFFQSPI线性映射Flash线性访问ps7_ram_00x00000000~0x0002FFFFOCM低地址On-Chip Memoryps7_ram_10xFFFF0000~0xFFFFFE00OCM高地址高地址映射OCM程序入口ENTRY(_vector_table)_vector_table程序入口CPU复位后跳转地址代码段.text ps7_ddr_0代码段函数机器码.vectors异常向量中断入口ARM异常向量表.bootBoot代码启动代码reset/startup.init初始化代码CRT初始化main前执行.fini结束代码程序退出清理main后执行只读数据.rodataconst数据只读常量字符串/查表.rodata1扩展rodata编译器扩展次级只读区.sdata2小只读数据GP优化小常量快速访问.sbss2小只读BSSGP优化小未初始化数据数据段.data已初始化变量全局静态变量启动时复制.data1扩展data编译器扩展次级data.sdata小数据区GP优化小变量快速访问.sbss小BSS区GP优化小未初始化变量.bss未初始化变量零初始化区启动时清零COMMON公共变量旧式全局变量GCC兼容TLS线程局部存储.tdataTLS初始化数据线程局部变量Thread Local.tbssTLS未初始化数据TLS BSSThread LocalC初始化.ctors构造函数表全局对象构造main前执行.dtors析构函数表全局对象析构main后执行.preinit_array预初始化数组libc前初始化极少使用.init_array初始化数组GCC现代构造机制替代ctors.fini_array析构数组GCC现代析构机制替代dtors异常/调试.eh_frame异常展开表C异常stack unwind.eh_framehdr异常头unwind索引backtrace辅助.gcc_except_tableGCC异常表throw/catchC异常.ARM.exidxARM异常索引ARM unwindbacktrace.ARM.extabARM unwind表ARM异常处理unwind数据MMU相关.mmu_tblMMU页表一级页表Cortex-A9 MMUALIGN(16384)16KB对齐页表对齐ARM硬件要求地址符号__rodata_start地址符号rodata开始边界标记__rodata_end地址符号rodata结束边界标记__data_start地址符号data开始数据复制起点__data_end地址符号data结束数据复制终点__bss_start地址符号bss开始清零起点__bss_end地址符号bss结束清零终点SDA小数据_SDA_BASE_sdata中点SDA基址GP小数据寻址_SDA2_BASE_sdata2中点SDA2基址小只读寻址Heap区域.heapheap段动态内存malloc/new_heap_startheap起点heap开始libc使用_heap_endheap终点heap结束heap边界HeapBaseheap基址heap起始调试/库HeapLimitheap结束heap上限heap边界Stack区域.stackstack段CPU栈所有模式栈_stack_end栈底主栈开始向上分配_stack主栈顶SP初值User/System__stack主栈符号SP引用BSP使用__irq_stackIRQ栈顶IRQ SPIRQ模式__supervisor_stackSVC栈顶SVC SPSupervisor模式__abort_stackAbort栈顶Abort SPData Abort__fiq_stackFIQ栈顶FIQ SPFast IRQ__undef_stackUndefined栈顶Undefined SPUndefined模式程序结束_end最终地址程序结束heap边界参考GNU LD语法KEEP()强制保留防止gc删除向量表常用ALIGN(x)地址对齐cache/MMU要求硬件对齐NOLOAD不装载不生成binBSS/StackSORT()section排序ctor顺序GCC使用EXCLUDE_FILE()排除文件避免重复ctor/dtorsection映射指定MEMORY放入内存区脚本工具# 设置环境变量$env:PATHD:\Xilinx\Vitis\2020.2\gnu\aarch32\nt\gcc-arm-none-eabi\bin;$env:PATH# 查源码位置arm-none-eabi-addr2line-ezynq_wave_app.elf 0x00109264 axi_test/src/main.cpp:44# 查符号表arm-none-eabi-nm zynq_wave_app.elf# wsl有各种工具更方便wsl $:arm-none-eabi-nm zynq_wave_app.elf|grepheap 0012d360 B _heap 0012f360 B _heap_end 0012d360 B _heap_start 0012d310 b heap.5721# 查看IRQ栈大小$: arm-none-eabi-nm zynq_wave_app.elf|grep_IRQ_STACK_SIZE 00000fa0 A _IRQ_STACK_SIZE# IRQ 栈地址 0x001313600x00132300 向下增长$: arm-none-eabi-nm zynq_wave_app.elf|grepirq 0012ccd8 b _ZL12s_pl_irq_cnt 00107448 t _ZL14pl_irq_handlerPv 00107a20 t _ZL16uart_irq_handlerPvmj 00132300 B __irq_stack 00131360 B _irq_stack_end栈监控这里以__irq_stack 栈为例#defineIRQ_STACK_TOP((uint32_t*)0x00132300)#defineIRQ_STACK_END((uint32_t*)0x00131360)#defineWATERMARK0xA5A5A5A5volatileuint32_tg_irq_stack_max_usage0;//irq 栈填充水印voidirq_stack_fill_watermark(void){uint32_t*pIRQ_STACK_END;while(pIRQ_STACK_TOP){*pWATERMARK;}}// irq 栈最大用量写入全局变量g_irq_stack_max_usagevoidirq_stack_update_usage(void){uint32_t*pIRQ_STACK_END;while(pIRQ_STACK_TOP){if(*p!WATERMARK){break;}p;}g_irq_stack_max_usage(uint32_t)((uint8_t*)IRQ_STACK_TOP-(uint8_t*)p);}测试intmain(){staticuint32_ts_ms_tick0;staticuint32_ts_pt_tick0;irq_stack_fill_watermark();BspInit();at_init(Bsp_shell_write);AT_printf(ke);at_app_init();at_show_version();//启动PT协程Protothread::AllStart();while(1){uint32_tmsBspGetTickMs();BspGetMillis();if(ms-s_ms_tick10){s_ms_tickms;intlenBspUartRead((uint8_t*)AT_m_buf,-1);at_import((uint8_t*)AT_m_buf,len,ms);}if(g_bt.key_flag){g_bt.key_flag0;irq_stack_update_usage();AT_println(IRQ stack max usage %lu bytes\n,g_irq_stack_max_usage);}}return0;}打印因为 _IRQ_STACK_SIZE 配置的只有1024 ,irq栈最大用量是1248所以发生了各种奇怪现象[18:52:51.763]收←◆ke268435456IRQ stack max usage1248bytes