我可以通过 GCC 为 ARM 构建一个简单的代码,我正在尝试使用 gdbserver 和 arm-none-eabi.gdb 在 MCB4300 上运行它。链接器脚本和启动代码取自 CMSIS v3 (Device/ARM/ARMCM4/Source/GCC/startup_ARMCM4.S and Device/ARM/ARMCM4/Source/GCC/gcc_arm.ld) 没有修改,但我也尝试修改闪存和 .ld 文件中的 RAM 地址。
使用此命令构建时没有问题:
./arm-none-eabi-gcc -g -mthumb -mcpu=cortex-m4 -march=armv7e-m -T Device/ARM/ARMCM4/Source/GCC/gcc_arm.ld Device/ ARM/ARMCM4/Source/GCC/startup_ARMCM4.S main.c -o out.elf
我必须 ctrl+c 因为它永远不会到达断点。相反,它转到 0x1c000206,但断点位于 0x200。应该放入链接描述文件的内存地址是什么?CMSIS 的 .ld 和 .s 文件中是否应该更改其他任何内容?
arm-none-eabi-gbd 的输出:
(gdb) target remote :2331
Remote debugging using :2331
0x00000000 in __isr_vector ()
(gdb) load
Loading sec
tion .text, size 0x50c lma 0x0
Loading section .ARM.exidx, size 0x8 lma 0x50c
加载节 .data,大小 0x440 lma 0x514
加载节 .jcr,大小 0x4 lma 0x954
起始地址 0x17d,加载大小 2392
传输速率:395 字节/秒,598 字节/写入。(gdb)在 0x200 处
中断主断点 1:文件 main.c,第 37 行。
(gdb) c
继续。
^C
程序收到信号 SIGTRAP,跟踪/断点陷阱。
0x1c000206 在 ?? ()
(gdb)
and from gdbserver:
SEGGER J-Link GDB Server V4.50i
JLinkARM.dll V4.50i (DLL compiled Jun 22 2012 19:00:36)
服务器已启动,设置如下:
---Server相关设置---
GDBInit 文件:无
监听端口:2331
SWO 线程监听端口:2332
接受远程连接:是
日志文件:关闭
验证下载:关闭
Init regs on start:on
静默模式:off
单运行模式:off
---J-Link相关设置---
J-Link脚本:无
目标接口:JTAG
主机接口:USB
目标字节序:小
目标接口速度:5kHz
等待J-Link连接...
J-Link已连接。
固件:J-Link ARM V8 compiled Aug 1 2012 13:40:47
硬件:V8.00
S/N:158007019
OEM:IAR
Checking target voltage...
Listening on TCP/IP port 2331
Connecting to target...
J- Link found 2 JTAG devices, Total IRLen = 8
JTAG ID: 0x4BA00477 (Cortex-M4)
Connected to target
Waiting for GDB connection...Connected to 127.0.0.1
读取所有寄存器
读取 4 个字节 @ 地址 0x00000000(数据 = 0x1000BEC8)
下载 1292 个字节 @ 地址 0x00000000
下载 8 个字节 @ 地址 0x0000050C 下载
1088 个字节 @ 地址 0x00000514
下载 4 个字节 @ 地址 0x00000954
写入寄存器(PC = 0x00000 17d)
读取 4 个字节@地址 0x0000017C(数据= 0x4B01F810)
Read 2 bytes @ address 0x00000200 (Data = 0x4809)
Read 2 bytes @ address 0x00000200 (Data = 0x4809) Read
2 bytes @ address 0x00000200 (Data = 0x4809)
Setting breakpoint @ address 0x00000200, Size = 2, BPHand le = 0x0001
开始目标 CPU...
调试器请求暂停目标...
...目标已暂停 (PC = 0x1C000206)
读取所有寄存器
删除断点@地址 0x00000200,大小 = 2
读取 4 个字节@地址 0x1C000206(数据 = 0xE7FEE7FE)
main.c:
int globalVar = 0;
void SystemInit (void) {
#if 0
uint32_t SystemCoreClock = __IRC;
#ifdef __CODE_RED
// CodeRed 启动代码将修改 VTOR 寄存器以匹配
// 当代码已链接运行时。
// 检查我们是否从外部闪存运行
if (SCB->VTOR == 0x1C000000)
/*为外部闪存启用缓冲区*/
LPC_EMC->STATICCONFIG0 |= 1<<19;
// 调用时钟初始化代码
CGU_Init();
#else
#if defined(CORE_M4) || 定义(CORE_M3)
// 使 VTOR 寄存器指向向量表
SCB->VTOR = getPC() & 0xFFF00000;
#endif
/*为外部闪存启用缓冲区*/
LPC_EMC->STATICCONFIG0 |= 1<<19;
#endif
#endif
}
int main(void)
{
int i;
while(1)
全局变量++;
返回 0;
}
startup_ARMCM4.S:
/* 文件:startup_ARMCM4.S
* 用途:Cortex-M4 设备的启动文件。
应与* GCC for ARM 嵌入式处理器一起使用
* 版本:V1.3
* 日期:2012 年 2 月 8 日
*
* 版权所有 (c) 2012,ARM Limited
* 保留所有权利。
*
*如果满足以下条件,则允许以源代码和二进制形式重新分发和使用,无论是否进行* 修改:
* 源代码的重新分发必须保留上述版权
声明、此条件列表和以下免责声明。
* 二进制形式的重新分发必须在 随分发提供的文档和/或其他材料
中复制上述版权声明、此条件列表和以下免责声明。 *未经明确的事先书面许可, 不得使用 ARM Limited 的名称或其贡献者的名称来认可或推广从该软件衍生的产品。*
* 本软件由版权持有者和贡献者“按原样”提供,并且
* 不提供任何明示或暗示的保证,包括但不限于暗示的
* 适销性和特定用途适用性
保证。在任何情况下,ARM LIMITED 均不对任何
*直接、间接、偶然、特殊、惩戒性或后果性损害
*(包括但不限于替代商品或服务的采购;
*使用、数据或利润的损失;或业务中断)无论如何造成和
*根据任何责任理论,无论是合同、严格责任或侵权行为
*(包括疏忽或其他)以任何方式产生的使用此
* 软件,即使已被告知存在此类损坏的可能性。
*/
.syntax unified
.arch armv7-m
.section .stack
.align 3
#ifdef __STACK_SIZE
.equ Stack_Size, __STACK_SIZE
#else
.equ Stack_Size, 0x400
#endif
.globl __StackTop
.globl __StackLimit
__StackLimit:
.space Stack_Size
.size __StackLimit, . - __StackLimit
__StackTop:
.size __StackTop, . - __StackTop
.section .heap
.align 3
#ifdef __HEAP_SIZE
.equ Heap_Size, __HEAP_SIZE
#else
.equ Heap_Size, 0xC00
#endif
.globl __HeapBase
.globl __HeapLimit
__HeapBase:
.if Heap_Size
.space Heap_Size
.endif
.size __HeapBase, . - __HeapBase
__HeapLimit:
.size __HeapLimit, . - __HeapLimit
.section .isr_vector
.align 2
.globl __isr_vector
__isr_vector:
.long __StackTop /* 堆栈顶部 */
.long Reset_Handler /* 重置处理程序 */
.long NMI_Handler /* NMI 处理程序 */
.long HardFault_Handler /* 硬故障处理程序*/
.long MemManage_Handler /* MPU 故障处理程序 */
.long BusFault_Handler /* 总线故障处理程序 */
.long UsageFault_Handler /* 使用错误处理程序 */
.long 0 /* 保留 */
.long 0 /* 保留 */
.long 0 /* 保留 */
.long 0 /* 保留 */
.long SVC_Handler /* SVCall 处理程序 * /
.long DebugMon_Handler /* 调试监视器处理程序 */
.long 0 /* 保留
*/ .long PendSV_Handler
/* PendSV 处理程序 */ .long SysTick_Handler /* SysTick 处理程序 */
/* 外部中断 */
.long WDT_IRQHandler /* 0:看门狗定时器 */
.long RTC_IRQHandler /* 1: 实时时钟 */
.long TIM0_IRQHandler /* 2: Timer0 / Timer1 */
.long TIM2_IRQHandler /* 3: Timer2 / Timer3 */
.long MCIA_IRQHandler /* 4: MCIa */
.long MCIB_IRQHandler / * 5: MCIb */
.long UART0_IRQHandler /* 6: UART0 - DUT
FPGA */ .long
UART1_IRQHandler /* 7: UART1 - DUT FPGA */
.long UART2_IRQHandler /* 8: UART2 - DUT FPGA */
.long UART4_IRQHandler /* 9: UART4 - 未连接 */
.long AACI_IRQHandler /* 10: AACI / AC97 */
.long CLCD_IRQHandler /* 11:CLCD 组合中断 */
.long ENET_IRQHandler /* 12:以太网 */
.long USBDC_IRQHandler /* 13:USB 设备 */
.long USBHC_IRQHandler /* 14:USB 主机控制器 */
.long CHLCD_IRQHandler /* 15:字符 LCD */
.long FLEXRAY_IRQHandler /* 16:Flexray */ .long
CAN_IRQHandler /* 17:CAN */
.long LIN_IRQHandler /* 18:LIN */
.long I2C_IRQHandler /* 19:I2C ADC/DAC */
. long 0 /* 20:保留 */
.long 0 /* 21:保留*/
.long 0 /* 22:保留*/
.long 0 /* 23:保留*/
.long 0 /* 24:保留*/
.long 0 /* 25:保留*/
.long 0 /* 26:保留 */
.long 0 /* 27:保留 */
.long CPU_CLCD_IRQHandler /* 28:保留 - CPU FPGA CLCD */
.long 0 /* 29:保留 - CPU FPGA */
.long UART3_IRQHandler /* 30: UART3 - CPU FPGA */
.long SPI_IRQHandler /* 31: SPI 触摸屏 - CPU FPGA */
.size __isr_vector, . - __isr_vector
.text
.thumb
.thumb_func
.align 2
.globl Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* 循环将数据从只读存储器复制到 RAM。复制自/复制到的范围
* 由以下在 * 链接描述文件中评估的符号指定
。
* __etext:代码段的结尾,即要从中复制的数据段的开头。
* __data_start__/__data_end__:数据应
复制到的 RAM 地址范围。两者都必须对齐到 4 字节边界。*/
ldr r1, =__etext
ldr r2, =__data_start__
ldr r3, =__data_end__
#if 1
/* 这是循环实现的两个副本。第一个有利于代码大小
*,第二个有利于性能。默认使用第一个。
* 更改为“#if 0”以使用第二个 */
.flash_to_ram_loop:
cmp r2, r3
ittt lt
ldrlt r0, [r1], #4
strlt r0, [r2], #4
blt .flash_to_ram_loop
#else
subs r3, r2
ble .flash_to_ram_loop_end
.flash_to_ram_loop:
subs r3, #4
ldr r0, [r1, r3]
str r0, [r2, r3]
bgt .flash_to_ram_loop
.flash_to_ram_loop_end:
#endif
#ifndef __NO_SYSTEM_INIT
ldr r0, =SystemInit
blx r0
#endif
ldr r0, =_start
bx r0
.pool
.size Reset_Handler, . - Reset_Handler
/* 定义默认处理程序的宏。默认处理程序
* 将是弱符号并且只是死循环。它们可以
* 被其他处理程序覆盖 */
.macro def_irq_handler handler_name
.align 1
.thumb_func
.weak \handler_name
.type \handler_name, %function
\handler_name :
b 。
.size \handler_name, . - \handler_name
.endm
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler SysTick_Handler
def_irq_handler 默认值_处理程序 def_irq_handler
WDT_IRQHandler def_irq_handler
RTC_IRQHandler
def_irq_handler TIM0_IRQHandler def_irq_handler
TIM2_IRQHandler def_irq_handler
MCIA_IRQHandler def_irq_handler MCIB_IRQHandler
def_irq_handler
UART0_IRQHandler
def_irq_handler UART1_IRQHandler
def_irq_handler UART2_IRQHandler
def_irq_handler UART3_IRQHandler
def_irq_handler UART4_IRQHandler
def_irq_handler AACI_IRQHandler
def_irq_handler CLCD_IRQHandler
def_irq_handler ENET_IRQHandler
def_irq_handler USBDC_IR QHandler
def_irq_handler USBHC_IRQHandler def_irq_handler CHLCD_IRQHandler def_irq_handler FLEXRAY_IRQHandler def_irq_handler CAN_IRQHandler def_irq_handler LIN_IRQHandler def_irq_handler I2C_IRQHandler def_irq_handler CPU_CLCD_IRQHandler def_irq_handler S PI_IRQHandler .end
gcc_arm.ld:
/* 用于配置内存区域的链接描述文件。*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x40000 /* 256k */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x08000 /* 32k */
}
/* 库配置 */
GROUP(libgcc.a libc.a libm.a libnosys.a)
/* 用于放置段和符号值的链接描述文件。应
与其他定义内存区域 FLASH 和 RAM 的链接描述文件一起使用。
* 它引用了以下符号,这些符号必须在代码中定义:
* Reset_Handler :复位处理程序的入口
*
* 它定义了以下符号,代码无需定义即可使用:
* __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(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*( .isr_vector))
*(.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* ))
} > 闪存
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > 闪存
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
__etext = .;
.data : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data*)
。=对齐(4);
/* 预初始化数据 */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. =对齐(4);
/* 初始化数据 */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. =对齐(4);
/* finit 数据 */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
. =对齐(4);
/* 所有数据结束 */
__data_end__ = .;
} > RAM
.bss :
{
__bss_start__ = .;
*(.bss*)
*(普通)
__bss_end__ = .;
} > 内存
堆:
{
__end__ = .;
结束 = __end__;
*(.heap*)
__HeapLimit = .;
} > RAM
/* .stack_dummy 部分不包含任何符号。它仅
* 用于链接器计算堆栈部分的大小,并
在以后将 * 值分配给堆栈符号 */
.stack_dummy :
{
*(.stack)
} > RAM
/* 将堆栈顶部设置为 RAM 的末端,并移动堆栈限制向下
* stack_dummy 部分的大小 */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
提供(__stack = __StackTop);
/* 检查数据+堆+栈是否超过RAM限制*/
ASSERT(__StackLimit >= __HeapLimit, "区域 RAM 溢出堆栈")
}