如何在 Windows 上使用 Clang/LLVM 交叉编译 STM32L4 cortex-m4 mcu

How to crosscompile for STM32L4 cortex-m4 mcu using Clang/LLVM on Windows

我一直在尝试编译一个简单的应用程序,在 Windows 上使用 Clang 为 stm32l4 micro 实现 USB CDC 设备。 该代码由 STMCubeMX 生成,并进行了一些小的更改,因此它只是回显通过虚拟 com 端口发送的任何内容。

使用来自 ubuntu 的 arm-none-eabi-gcc 工具链使用 generated make file works just fine. After flashing to the micro controller it does exactly what it's supposed to do. To compile with clang from windows, i made this fancy build script 进行编译(从 asm/c 来源生成对象,link 那些. 使用这些选项:

set TARGET_TRIPE=--target=arm-none-eabi
set ARCH=-march=armv7e-m
set CPU=-mcpu=cortex-m4
set FPU=-mfpu=fpv4-sp-d16 -mfloat-abi=hard
set MCU=%TARGET_TRIPE% %ARCH% %CPU% %FPU% -mthumb -mlittle-endian

set COMMON_FLAGS=-Wall %OPTIMIZATIONS% --sysroot=%SYSROOT% -fdata-sections -ffunction-sections -O0

set C_FLAGS=%MCU% %C_DEFINES% %COMMON_FLAGS% %C_INCLUDES% -c
set ASM_FLAGS=%MCU% %ASM_DEFINES% %COMMON_FLAGS% -x assembler-with-cpp -c
set LD_FLAGS=%MCU% %COMMON_FLAGS% -nostdlib -nostartfiles -fuse-ld=lld -T%LD_SCRIPT% -Wl,-Map=%BUILD_DIR%/%PROJECT_NAME%.map,--cref,--gc-sections %LIBDIRS% %LIBS%

)。

编译成功,固件镜像看起来没问题,但是烧写后,微控制器什么也没做。甚至外部 crystal 都无法启动,因此固件映像显然有问题。我不知道,为什么会这样。 Clang/GCC. Repo 生成的二进制文件 source.

编辑:clang 二进制图像大约有 400MB 大,这似乎也不对。

编辑 2:

这是我正在使用的链接描述文件:

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x2000A000;    /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Specify the memory areas */
MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 40K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 128K
}

/* Define output sections */
SECTIONS
{
  /* The startup code goes first into FLASH */
  .isr_vector :
  {
    . = ALIGN(8);
    KEEP(*(.isr_vector)) /* Startup code */
    . = ALIGN(8);
  } >FLASH

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(8);
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(8);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(8);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(8);
  } >FLASH

  .ARM.extab   : 
  { 
  . = ALIGN(8);
  *(.ARM.extab* .gnu.linkonce.armextab.*)
  . = ALIGN(8);
  } >FLASH
  .ARM : {
    . = ALIGN(8);
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
    . = ALIGN(8);
  } >FLASH

  .preinit_array     :
  {
    . = ALIGN(8);
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
    . = ALIGN(8);
  } >FLASH

  .init_array :
  {
    . = ALIGN(8);
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
    . = ALIGN(8);
  } >FLASH
  .fini_array :
  {
    . = ALIGN(8);
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
    . = ALIGN(8);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(8);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(8);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH


  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM



  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}

这是我正在使用的启动代码:

.syntax unified
    .cpu cortex-m4
    .fpu softvfp
    .thumb

.global g_pfnVectors
.global Default_Handler

/* start address for the initialization values of the .data section.
defined in linker script */
.word   _sidata
/* start address for the .data section. defined in linker script */
.word   _sdata
/* end address for the .data section. defined in linker script */
.word   _edata
/* start address for the .bss section. defined in linker script */
.word   _sbss
/* end address for the .bss section. defined in linker script */
.word   _ebss

.equ  BootRAM,        0xF1E0F85F
/**
 * @brief  This is the code that gets called when the processor first
 *          starts execution following a reset event. Only the absolutely
 *          necessary set is performed, after which the application
 *          supplied main() routine is called.
 * @param  None
 * @retval : None
*/

    .section    .text.Reset_Handler
    .weak   Reset_Handler
    .type   Reset_Handler, %function
Reset_Handler:
  ldr   sp, =_estack    /* Set stack pointer */

/* Copy the data segment initializers from flash to SRAM */
  movs  r1, #0
  b LoopCopyDataInit

CopyDataInit:
    ldr r3, =_sidata
    ldr r3, [r3, r1]
    str r3, [r0, r1]
    adds    r1, r1, #4

LoopCopyDataInit:
    ldr r0, =_sdata
    ldr r3, =_edata
    adds    r2, r0, r1
    cmp r2, r3
    bcc CopyDataInit
    ldr r2, =_sbss
    b   LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
    movs    r3, #0
    str r3, [r2], #4

LoopFillZerobss:
    ldr r3, = _ebss
    cmp r2, r3
    bcc FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call CRT entry point */
    //bl _mainCRTStartup
    bl __libc_init_array
    bl main

LoopForever:
    b LoopForever

.size   Reset_Handler, .-Reset_Handler

/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section    .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
    b   Infinite_Loop
    .size   Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex-M4.  Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
    .section    .isr_vector,"a",%progbits
    .type   g_pfnVectors, %object
    .size   g_pfnVectors, .-g_pfnVectors


g_pfnVectors:
    .word   _estack
    .word   Reset_Handler
    .word   NMI_Handler
    .word   HardFault_Handler
    .word   MemManage_Handler
    .word   BusFault_Handler
    .word   UsageFault_Handler
    .word   0
    .word   0
    .word   0
    .word   0
    .word   SVC_Handler
    .word   DebugMon_Handler
    .word   0
    .word   PendSV_Handler
    .word   SysTick_Handler
    .word   WWDG_IRQHandler
    .word   PVD_PVM_IRQHandler
    .word   TAMP_STAMP_IRQHandler
    .word   RTC_WKUP_IRQHandler
    .word   FLASH_IRQHandler
    .word   RCC_IRQHandler
    .word   EXTI0_IRQHandler
    .word   EXTI1_IRQHandler
    .word   EXTI2_IRQHandler
    .word   EXTI3_IRQHandler
    .word   EXTI4_IRQHandler
    .word   DMA1_Channel1_IRQHandler
    .word   DMA1_Channel2_IRQHandler
    .word   DMA1_Channel3_IRQHandler
    .word   DMA1_Channel4_IRQHandler
    .word   DMA1_Channel5_IRQHandler
    .word   DMA1_Channel6_IRQHandler
    .word   DMA1_Channel7_IRQHandler
    .word   ADC1_2_IRQHandler
    .word   0
    .word   0
    .word   0
    .word   0
    .word   EXTI9_5_IRQHandler
    .word   TIM1_BRK_TIM15_IRQHandler
    .word   TIM1_UP_TIM16_IRQHandler
    .word   TIM1_TRG_COM_IRQHandler
    .word   TIM1_CC_IRQHandler
    .word   TIM2_IRQHandler
    .word   0
    .word   0
    .word   I2C1_EV_IRQHandler
    .word   I2C1_ER_IRQHandler
    .word   I2C2_EV_IRQHandler
    .word   I2C2_ER_IRQHandler
    .word   SPI1_IRQHandler
    .word   SPI2_IRQHandler
    .word   USART1_IRQHandler
    .word   USART2_IRQHandler
    .word   USART3_IRQHandler
    .word   EXTI15_10_IRQHandler
    .word   RTC_Alarm_IRQHandler
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   0
    .word   TIM6_IRQHandler
    .word   0
    .word   DMA2_Channel1_IRQHandler
    .word   DMA2_Channel2_IRQHandler
    .word   DMA2_Channel3_IRQHandler
    .word   DMA2_Channel4_IRQHandler
    .word   DMA2_Channel5_IRQHandler
    .word   0
    .word   0
    .word   0
    .word   COMP_IRQHandler
    .word   LPTIM1_IRQHandler
    .word   LPTIM2_IRQHandler
    .word   USB_IRQHandler
    .word   DMA2_Channel6_IRQHandler
    .word   DMA2_Channel7_IRQHandler
    .word   LPUART1_IRQHandler
    .word   QUADSPI_IRQHandler
    .word   I2C3_EV_IRQHandler
    .word   I2C3_ER_IRQHandler
    .word   0
    .word   0
    .word   0
    .word   TSC_IRQHandler
    .word   0
    .word   AES_IRQHandler
    .word   RNG_IRQHandler
    .word   FPU_IRQHandler
    .word   CRS_IRQHandler


/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/

  .weak NMI_Handler
    .thumb_set NMI_Handler,Default_Handler

  .weak HardFault_Handler
    .thumb_set HardFault_Handler,Default_Handler

  .weak MemManage_Handler
    .thumb_set MemManage_Handler,Default_Handler

  .weak BusFault_Handler
    .thumb_set BusFault_Handler,Default_Handler

    .weak   UsageFault_Handler
    .thumb_set UsageFault_Handler,Default_Handler

    .weak   SVC_Handler
    .thumb_set SVC_Handler,Default_Handler

    .weak   DebugMon_Handler
    .thumb_set DebugMon_Handler,Default_Handler

    .weak   PendSV_Handler
    .thumb_set PendSV_Handler,Default_Handler

    .weak   SysTick_Handler
    .thumb_set SysTick_Handler,Default_Handler

    .weak   WWDG_IRQHandler
    .thumb_set WWDG_IRQHandler,Default_Handler

    .weak   PVD_PVM_IRQHandler
    .thumb_set PVD_PVM_IRQHandler,Default_Handler

    .weak   TAMP_STAMP_IRQHandler
    .thumb_set TAMP_STAMP_IRQHandler,Default_Handler

    .weak   RTC_WKUP_IRQHandler
    .thumb_set RTC_WKUP_IRQHandler,Default_Handler

    .weak   FLASH_IRQHandler
    .thumb_set FLASH_IRQHandler,Default_Handler

    .weak   RCC_IRQHandler
    .thumb_set RCC_IRQHandler,Default_Handler

    .weak   EXTI0_IRQHandler
    .thumb_set EXTI0_IRQHandler,Default_Handler

    .weak   EXTI1_IRQHandler
    .thumb_set EXTI1_IRQHandler,Default_Handler

    .weak   EXTI2_IRQHandler
    .thumb_set EXTI2_IRQHandler,Default_Handler

    .weak   EXTI3_IRQHandler
    .thumb_set EXTI3_IRQHandler,Default_Handler

    .weak   EXTI4_IRQHandler
    .thumb_set EXTI4_IRQHandler,Default_Handler

    .weak   DMA1_Channel1_IRQHandler
    .thumb_set DMA1_Channel1_IRQHandler,Default_Handler

    .weak   DMA1_Channel2_IRQHandler
    .thumb_set DMA1_Channel2_IRQHandler,Default_Handler

    .weak   DMA1_Channel3_IRQHandler
    .thumb_set DMA1_Channel3_IRQHandler,Default_Handler

    .weak   DMA1_Channel4_IRQHandler
    .thumb_set DMA1_Channel4_IRQHandler,Default_Handler

    .weak   DMA1_Channel5_IRQHandler
    .thumb_set DMA1_Channel5_IRQHandler,Default_Handler

    .weak   DMA1_Channel6_IRQHandler
    .thumb_set DMA1_Channel6_IRQHandler,Default_Handler

    .weak   DMA1_Channel7_IRQHandler
    .thumb_set DMA1_Channel7_IRQHandler,Default_Handler

    .weak   ADC1_2_IRQHandler
    .thumb_set ADC1_2_IRQHandler,Default_Handler

    .weak   EXTI9_5_IRQHandler
    .thumb_set EXTI9_5_IRQHandler,Default_Handler

    .weak   TIM1_BRK_TIM15_IRQHandler
    .thumb_set TIM1_BRK_TIM15_IRQHandler,Default_Handler

    .weak   TIM1_UP_TIM16_IRQHandler
    .thumb_set TIM1_UP_TIM16_IRQHandler,Default_Handler

    .weak   TIM1_TRG_COM_IRQHandler
    .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler

    .weak   TIM1_CC_IRQHandler
    .thumb_set TIM1_CC_IRQHandler,Default_Handler

    .weak   TIM2_IRQHandler
    .thumb_set TIM2_IRQHandler,Default_Handler

    .weak   I2C1_EV_IRQHandler
    .thumb_set I2C1_EV_IRQHandler,Default_Handler

    .weak   I2C1_ER_IRQHandler
    .thumb_set I2C1_ER_IRQHandler,Default_Handler

    .weak   I2C2_EV_IRQHandler
    .thumb_set I2C2_EV_IRQHandler,Default_Handler

    .weak   I2C2_ER_IRQHandler
    .thumb_set I2C2_ER_IRQHandler,Default_Handler

    .weak   SPI1_IRQHandler
    .thumb_set SPI1_IRQHandler,Default_Handler

    .weak   SPI2_IRQHandler
    .thumb_set SPI2_IRQHandler,Default_Handler

    .weak   USART1_IRQHandler
    .thumb_set USART1_IRQHandler,Default_Handler

    .weak   USART2_IRQHandler
    .thumb_set USART2_IRQHandler,Default_Handler

    .weak   USART3_IRQHandler
    .thumb_set USART3_IRQHandler,Default_Handler

    .weak   EXTI15_10_IRQHandler
    .thumb_set EXTI15_10_IRQHandler,Default_Handler

    .weak   RTC_Alarm_IRQHandler
    .thumb_set RTC_Alarm_IRQHandler,Default_Handler

    .weak   TIM6_IRQHandler
    .thumb_set TIM6_IRQHandler,Default_Handler

    .weak   DMA2_Channel1_IRQHandler
    .thumb_set DMA2_Channel1_IRQHandler,Default_Handler

    .weak   DMA2_Channel2_IRQHandler
    .thumb_set DMA2_Channel2_IRQHandler,Default_Handler

    .weak   DMA2_Channel3_IRQHandler
    .thumb_set DMA2_Channel3_IRQHandler,Default_Handler

    .weak   DMA2_Channel4_IRQHandler
    .thumb_set DMA2_Channel4_IRQHandler,Default_Handler

    .weak   DMA2_Channel5_IRQHandler
    .thumb_set DMA2_Channel5_IRQHandler,Default_Handler

    .weak   COMP_IRQHandler
    .thumb_set COMP_IRQHandler,Default_Handler

    .weak   LPTIM1_IRQHandler
    .thumb_set LPTIM1_IRQHandler,Default_Handler

    .weak   LPTIM2_IRQHandler
    .thumb_set LPTIM2_IRQHandler,Default_Handler    

    .weak   USB_IRQHandler
    .thumb_set USB_IRQHandler,Default_Handler   

    .weak   DMA2_Channel6_IRQHandler
    .thumb_set DMA2_Channel6_IRQHandler,Default_Handler 

    .weak   DMA2_Channel7_IRQHandler
    .thumb_set DMA2_Channel7_IRQHandler,Default_Handler 

    .weak   LPUART1_IRQHandler
    .thumb_set LPUART1_IRQHandler,Default_Handler   

    .weak   QUADSPI_IRQHandler
    .thumb_set QUADSPI_IRQHandler,Default_Handler   

    .weak   I2C3_EV_IRQHandler
    .thumb_set I2C3_EV_IRQHandler,Default_Handler   

    .weak   I2C3_ER_IRQHandler
    .thumb_set I2C3_ER_IRQHandler,Default_Handler

    .weak   TSC_IRQHandler
    .thumb_set TSC_IRQHandler,Default_Handler

    .weak   AES_IRQHandler
    .thumb_set AES_IRQHandler,Default_Handler

    .weak   RNG_IRQHandler
    .thumb_set RNG_IRQHandler,Default_Handler

    .weak   FPU_IRQHandler
    .thumb_set FPU_IRQHandler,Default_Handler

    .weak   CRS_IRQHandler
    .thumb_set CRS_IRQHandler,Default_Handler

启动代码和 linker 脚本均由 STM32CubeMX 生成

这是从启动代码中调用的主要函数:

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USB_DEVICE_Init();

  while (1)
  {
  }
}

初始化外围设备和 CDC usb 设备。

矢量反汇编table:

Disassembly of section .isr_vector:

08000000 <g_pfnVectors>:
 8000000: 00 a0                         adr r0, #0
 8000002: 00 20                         movs    r0, #0
 8000004: 81 53                         strh    r1, [r0, r6]
 8000006: 00 08                         lsrs    r0, r0, #32
 8000008: a5 04                         lsls    r5, r4, #18
 800000a: 00 08                         lsrs    r0, r0, #32
 800000c: a7 04                         lsls    r7, r4, #18
 800000e: 00 08                         lsrs    r0, r0, #32
 8000010: ab 04                         lsls    r3, r5, #18
 8000012: 00 08                         lsrs    r0, r0, #32
 8000014: af 04                         lsls    r7, r5, #18
 8000016: 00 08                         lsrs    r0, r0, #32
 8000018: b3 04                         lsls    r3, r6, #18
 800001a: 00 08                         lsrs    r0, r0, #32
        ...
 800002c: b7 04                         lsls    r7, r6, #18
 800002e: 00 08                         lsrs    r0, r0, #32
 8000030: b9 04                         lsls    r1, r7, #18
 8000032: 00 08                         lsrs    r0, r0, #32
 8000034: 00 00                         movs    r0, r0
 8000036: 00 00                         movs    r0, r0
 8000038: bb 04                         lsls    r3, r7, #18
 800003a: 00 08                         lsrs    r0, r0, #32
 800003c: bd 04                         lsls    r5, r7, #18
 800003e: 00 08                         lsrs    r0, r0, #32
 8000040: d1 53                         strh    r1, [r2, r7]
 8000042: 00 08                         lsrs    r0, r0, #32
 8000044: d1 53                         strh    r1, [r2, r7]
 8000046: 00 08                         lsrs    r0, r0, #32
 8000048: d1 53                         strh    r1, [r2, r7]
 800004a: 00 08                         lsrs    r0, r0, #32
 800004c: d1 53                         strh    r1, [r2, r7]
 800004e: 00 08                         lsrs    r0, r0, #32
 8000050: d1 53                         strh    r1, [r2, r7]
 8000052: 00 08                         lsrs    r0, r0, #32
 8000054: d1 53                         strh    r1, [r2, r7]
 8000056: 00 08                         lsrs    r0, r0, #32
 8000058: d1 53                         strh    r1, [r2, r7]
 800005a: 00 08                         lsrs    r0, r0, #32
 800005c: d1 53                         strh    r1, [r2, r7]
 800005e: 00 08                         lsrs    r0, r0, #32
 8000060: d1 53                         strh    r1, [r2, r7]
 8000062: 00 08                         lsrs    r0, r0, #32
 8000064: d1 53                         strh    r1, [r2, r7]
 8000066: 00 08                         lsrs    r0, r0, #32
 8000068: d1 53                         strh    r1, [r2, r7]
 800006a: 00 08                         lsrs    r0, r0, #32
 800006c: d1 53                         strh    r1, [r2, r7]
 800006e: 00 08                         lsrs    r0, r0, #32
 8000070: d1 53                         strh    r1, [r2, r7]
 8000072: 00 08                         lsrs    r0, r0, #32
 8000074: d1 53                         strh    r1, [r2, r7]
 8000076: 00 08                         lsrs    r0, r0, #32
 8000078: d1 53                         strh    r1, [r2, r7]
 800007a: 00 08                         lsrs    r0, r0, #32
 800007c: d1 53                         strh    r1, [r2, r7]
 800007e: 00 08                         lsrs    r0, r0, #32
 8000080: d1 53                         strh    r1, [r2, r7]
 8000082: 00 08                         lsrs    r0, r0, #32
 8000084: d1 53                         strh    r1, [r2, r7]
 8000086: 00 08                         lsrs    r0, r0, #32
 8000088: d1 53                         strh    r1, [r2, r7]
 800008a: 00 08                         lsrs    r0, r0, #32
        ...
 800009c: d1 53                         strh    r1, [r2, r7]
 800009e: 00 08                         lsrs    r0, r0, #32
 80000a0: d1 53                         strh    r1, [r2, r7]
 80000a2: 00 08                         lsrs    r0, r0, #32
 80000a4: d1 53                         strh    r1, [r2, r7]
 80000a6: 00 08                         lsrs    r0, r0, #32
 80000a8: d1 53                         strh    r1, [r2, r7]
 80000aa: 00 08                         lsrs    r0, r0, #32
 80000ac: d1 53                         strh    r1, [r2, r7]
 80000ae: 00 08                         lsrs    r0, r0, #32
 80000b0: d1 53                         strh    r1, [r2, r7]
 80000b2: 00 08                         lsrs    r0, r0, #32
        ...
 80000bc: d1 53                         strh    r1, [r2, r7]
 80000be: 00 08                         lsrs    r0, r0, #32
 80000c0: d1 53                         strh    r1, [r2, r7]
 80000c2: 00 08                         lsrs    r0, r0, #32
 80000c4: d1 53                         strh    r1, [r2, r7]
 80000c6: 00 08                         lsrs    r0, r0, #32
 80000c8: d1 53                         strh    r1, [r2, r7]
 80000ca: 00 08                         lsrs    r0, r0, #32
 80000cc: d1 53                         strh    r1, [r2, r7]
 80000ce: 00 08                         lsrs    r0, r0, #32
 80000d0: d1 53                         strh    r1, [r2, r7]
 80000d2: 00 08                         lsrs    r0, r0, #32
 80000d4: d1 53                         strh    r1, [r2, r7]
 80000d6: 00 08                         lsrs    r0, r0, #32
 80000d8: d1 53                         strh    r1, [r2, r7]
 80000da: 00 08                         lsrs    r0, r0, #32
 80000dc: d1 53                         strh    r1, [r2, r7]
 80000de: 00 08                         lsrs    r0, r0, #32
 80000e0: d1 53                         strh    r1, [r2, r7]
 80000e2: 00 08                         lsrs    r0, r0, #32
 80000e4: d1 53                         strh    r1, [r2, r7]
 80000e6: 00 08                         lsrs    r0, r0, #32
        ...
 8000118: d1 53                         strh    r1, [r2, r7]
 800011a: 00 08                         lsrs    r0, r0, #32
 800011c: 00 00                         movs    r0, r0
 800011e: 00 00                         movs    r0, r0
 8000120: d1 53                         strh    r1, [r2, r7]
 8000122: 00 08                         lsrs    r0, r0, #32
 8000124: d1 53                         strh    r1, [r2, r7]
 8000126: 00 08                         lsrs    r0, r0, #32
 8000128: d1 53                         strh    r1, [r2, r7]
 800012a: 00 08                         lsrs    r0, r0, #32
 800012c: d1 53                         strh    r1, [r2, r7]
 800012e: 00 08                         lsrs    r0, r0, #32
 8000130: d1 53                         strh    r1, [r2, r7]
 8000132: 00 08                         lsrs    r0, r0, #32
        ...
 8000140: d1 53                         strh    r1, [r2, r7]
 8000142: 00 08                         lsrs    r0, r0, #32
 8000144: d1 53                         strh    r1, [r2, r7]
 8000146: 00 08                         lsrs    r0, r0, #32
 8000148: d1 53                         strh    r1, [r2, r7]
 800014a: 00 08                         lsrs    r0, r0, #32
 800014c: c7 04                         lsls    r7, r0, #19
 800014e: 00 08                         lsrs    r0, r0, #32
 8000150: d1 53                         strh    r1, [r2, r7]
 8000152: 00 08                         lsrs    r0, r0, #32
 8000154: d1 53                         strh    r1, [r2, r7]
 8000156: 00 08                         lsrs    r0, r0, #32
 8000158: d1 53                         strh    r1, [r2, r7]
 800015a: 00 08                         lsrs    r0, r0, #32
 800015c: d1 53                         strh    r1, [r2, r7]
 800015e: 00 08                         lsrs    r0, r0, #32
 8000160: d1 53                         strh    r1, [r2, r7]
 8000162: 00 08                         lsrs    r0, r0, #32
 8000164: d1 53                         strh    r1, [r2, r7]
 8000166: 00 08                         lsrs    r0, r0, #32
        ...
 8000174: d1 53                         strh    r1, [r2, r7]
 8000176: 00 08                         lsrs    r0, r0, #32
 8000178: 00 00                         movs    r0, r0
 800017a: 00 00                         movs    r0, r0
 800017c: d1 53                         strh    r1, [r2, r7]
 800017e: 00 08                         lsrs    r0, r0, #32
 8000180: d1 53                         strh    r1, [r2, r7]
 8000182: 00 08                         lsrs    r0, r0, #32
 8000184: d1 53                         strh    r1, [r2, r7]
 8000186: 00 08                         lsrs    r0, r0, #32
 8000188: d1 53                         strh    r1, [r2, r7]
 800018a: 00 08                         lsrs    r0, r0, #32
 800018c: 00 00                         movs    r0, r0
 800018e: 00 00                         movs    r0, r0

所以这激发了我尝试 clang/llvm 几年后...

现在我在Linux而不是Windows,但是你应该可以适应Windows(或者当然双启动Linux或者把Linux 在虚拟机或其他什么)。

源自 clang/llvm 站点上的构建说明

rm -rf /opt/llvmv6m
rm -rf llvm-project
git clone https://github.com/llvm/llvm-project.git
cd llvm-project
mkdir build
cd build
cmake -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_CROSSCOMPILING=True -DCMAKE_INSTALL_PREFIX=/opt/llvmv6m -DLLVM_DEFAULT_TARGET_TRIPLE=armv6m-none-eabi -DLLVM_TARGET_ARCH=ARM -DLLVM_TARGETS_TO_BUILD=ARM -G "Unix Makefiles" ../llvm
make
sudo make install

我就是这样建造的。是的,我知道你的是 cortex-m4 所有的 cortex-ms(到目前为止)都支持 armv6-m,你可以很容易地制作这个 armv7m。是基于这些网页的实验,有趣的是,现在我不必在命令行上指定内容来指定体系结构或 cpu,很想知道这是否仍然是通用的 clang 交叉编译器,而 armv6m 只是默认值。无论如何...

这比简单的无限循环稍微复杂一点,但可以使用 gnu 中没有的 llvm 功能。

start.s

.thumb
.cpu    cortex-m0
.globl _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop
.thumb_func
reset:
    bl notmain
.thumb_func
loop:
    b .

notmain.c

unsigned int fun ( void );
unsigned int notmain ( void )
{
    return(fun());
}

fun.c

unsigned int fun ( void )
{
    return(5);
}

内存映射

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

生成文件

all :
    arm-none-eabi-as start.s -o start.o
    clang -O2 -fomit-frame-pointer -c notmain.c -o notmain.o
    clang -O2 -fomit-frame-pointer -c fun.c -o fun.o
    arm-none-eabi-ld -T memmap start.o notmain.o fun.o -o basic.elf
    arm-none-eabi-objdump -D basic.elf > basic.list
    clang -fomit-frame-pointer -c -emit-llvm notmain.c -o notmain.bc
    clang -fomit-frame-pointer -c -emit-llvm fun.c -o fun.bc
    llc $(LLCOPS) notmain.bc -filetype=obj -o notmain.not.o
    llc $(LLCOPS) fun.bc -filetype=obj -o fun.not.o
    arm-none-eabi-ld -T memmap start.o notmain.not.o fun.not.o -o not.elf
    arm-none-eabi-objdump -D not.elf > not.list
    llvm-link notmain.bc fun.bc -o notmain.not.bc
    opt -O2 notmain.not.bc -o notmain.opt.bc
    llc $(LLCOPS) notmain.opt.bc -filetype=obj -o notmain.opt.o
    arm-none-eabi-ld -T memmap start.o notmain.opt.o -o opt.elf
    arm-none-eabi-objdump -D opt.elf > opt.list

clean:
    rm -f *.S
    rm -f *.o
    rm -f *.list
    rm -f *.elf
    rm -f *.bc

basic.list

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000011    stmdaeq r0, {r0, r4}
 8000008:   08000015    stmdaeq r0, {r0, r2, r4}
 800000c:   08000015    stmdaeq r0, {r0, r2, r4}

08000010 <reset>:
 8000010:   f000 f802   bl  8000018 <notmain>

08000014 <loop>:
 8000014:   e7fe        b.n 8000014 <loop>
    ...

08000018 <notmain>:
 8000018:   b580        push    {r7, lr}
 800001a:   f000 f801   bl  8000020 <fun>
 800001e:   bd80        pop {r7, pc}

08000020 <fun>:
 8000020:   2005        movs    r0, #5
 8000022:   4770        bx  lr

not.list

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000011    stmdaeq r0, {r0, r4}
 8000008:   08000015    stmdaeq r0, {r0, r2, r4}
 800000c:   08000015    stmdaeq r0, {r0, r2, r4}

08000010 <reset>:
 8000010:   f000 f802   bl  8000018 <notmain>

08000014 <loop>:
 8000014:   e7fe        b.n 8000014 <loop>
    ...

08000018 <notmain>:
 8000018:   b580        push    {r7, lr}
 800001a:   f000 f801   bl  8000020 <fun>
 800001e:   bd80        pop {r7, pc}

08000020 <fun>:
 8000020:   2005        movs    r0, #5
 8000022:   4770        bx  lr

opt.list

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000    andcs   r1, r0, r0
 8000004:   08000011    stmdaeq r0, {r0, r4}
 8000008:   08000015    stmdaeq r0, {r0, r2, r4}
 800000c:   08000015    stmdaeq r0, {r0, r2, r4}

08000010 <reset>:
 8000010:   f000 f802   bl  8000018 <notmain>

08000014 <loop>:
 8000014:   e7fe        b.n 8000014 <loop>
    ...

08000018 <notmain>:
 8000018:   b580        push    {r7, lr}
 800001a:   f000 f802   bl  8000022 <fun>
 800001e:   2005        movs    r0, #5
 8000020:   bd80        pop {r7, pc}

08000022 <fun>:
 8000022:   2005        movs    r0, #5
 8000024:   4770        bx  lr

这里有趣的部分是您可以跨 files/objects 进行优化,这是您使用 gnu 工具 AFAIK 无法做到的。所以,实际上 LLVM 做得非常糟糕,必须对此进行调查。

现在我使用了 gnus 链接器和汇编器,但仍然不确定如何解决我在尝试仅使用 clang 构建时遇到错误的问题。

这些都足够通用,可以在您的处理器上 运行 如此处所示,使用新项目或工具寻找关键陷阱。

08000000 <_start>:
 8000000:   20001000
 8000004:   08000011
 8000008:   08000015
 800000c:   08000015

08000010 <reset>:

08000014 <loop>:

为了使 cortex-m 正确启动并且不会立即无法工作,向量 table 需要为向量设置 lsbit,从重置开始,在这种情况下重置位于 0x08000010,因此向量table 条目需要为 0x08000011 才能使代码 运行。这就是我们在这里看到的,所以我们不会因此而失败。

虽然有些 mcus 没有 0x1000 字节,但我认为你的有,所以 0x20001000 是堆栈指针的一个好的起始位置。

从那里开始,这又不仅仅是一个无限循环,它更复杂,但这应该 运行 在您的处理器上并且不会失败。如果你把它改成这样:

.thumb
.cpu    cortex-m0
.globl _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop
.thumb_func
reset:
    mov r0,#0
    b reset
.thumb_func
loop:
    b .

(假设这成为一个 gnu 工具项目,而不是 llvm/clang 您使用的是什么汇编器和链接器?)

然后使用调试器(stlink 加 openocd 加 telnet)您可以停止并恢复并检查 r0 以查看它是 运行ning。

.thumb
.cpu    cortex-m0
.globl _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop
.thumb_func
reset:
    bl notmain
.thumb_func
loop:
    b .
.thumb_func
bounce:
    bx lr


void bounce ( unsigned int );
unsigned int notmain ( void )
{
    for(ra=0;;ra++) bounce(ra);
    return(0);
}

它添加了一点 clang/llvm 并且如果你 stop/resume.

看到 r0 正在改变

有些芯片会查看向量是否存在,如果它看到 0xFFs 那么它可能会进入引导加载程序,因此使用调试器您还可以检查 0x00000000 和 0x08000000,尝试在 telnet/openocd 命令上重置暂停行,然后 mdw 0 20 查看 cpu 将在地址零处看到什么,看看它是否是您的向量 table.

如果你克服了这些非常简单但非常致命的常见问题,那么你可能正在处理其他问题,比如 clang 不喜欢 while(1) 循环,也许他们最终修复了那个错误,但是当我提交它时他们拒绝了因此,如果有代码等待使用 while(1) 更改状态位,那么这可能就是问题所在。在上面的操作之后,我会采取一些小的步骤,因为你一直在尝试时钟,所以你在时钟初始化之后调用并查看时钟初始化是否 运行 完成并返回到 main()。

您是使用 clang/llvm 来构建您正在使用的库,还是它们是预先构建的供您与 clang/llvm 一起使用?

编辑

做了更多工作,以防以上内容与任何人相关并且不会被删除。

改为

-DLLVM_ENABLE_PROJECTS='clang;lld'

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
    /DISCARD/ : {
        *(.ARM.exidx*)
    }
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

也许还有其他一些事情。现在反汇编也与您的反汇编相似,数据以单独的小字节序排列。

Disassembly of section .text:

08000000 _start:
 8000000: 00 10                         asrs    r0, r0, #32
 8000002: 00 20                         movs    r0, #0
 8000004: 11 00                         movs    r1, r2
 8000006: 00 08                         lsrs    r0, r0, #32
 8000008: 15 00                         movs    r5, r2
 800000a: 00 08                         lsrs    r0, r0, #32
 800000c: 15 00                         movs    r5, r2
 800000e: 00 08                         lsrs    r0, r0, #32

08000010 reset:
 8000010: 00 f0 02 f8                   bl  #4

08000014 loop:
 8000014: fe e7                         b   #-4 <loop>
 8000016: d4 d4                         bmi #-88 <start.c+0x7ffffc2>

08000018 notmain:
 8000018: 80 b5                         push    {r7, lr}
 800001a: 00 f0 02 f8                   bl  #4
 800001e: 05 20                         movs    r0, #5
 8000020: 80 bd                         pop {r7, pc}

08000022 fun:
 8000022: 05 20                         movs    r0, #5
 8000024: 70 47                         bx  lr

现在关于 400MB 的评论。

0x20000000 - 0x08000000 = 0x18000000 = 402653184.

这可能是你的问题,所以听起来你有一些.data。

让我开始一个新的:

start.s

.text
/*.syntax unified*/
.cpu    cortex-m0
.code   16
.globl _start
_start:
.word 0x20001000
.word reset
.word loop
.word loop
.thumb_func
reset:
    bl notmain
.thumb_func
loop:
    b .

notmain.c

unsigned int notmain ( void )
{
    return(7);
}

生成文件

all :
    clang -c start.s -o start.o
    clang -O2 -fomit-frame-pointer -c notmain.c -o notmain.o
    ld.lld -T memmap start.o notmain.o -o basic.elf
    llvm-objdump -D basic.elf > basic.list
    llvm-objcopy -O binary basic.elf basic.bin

clean:
    rm -f *.o
    rm -f *.list
    rm -f *.elf

内存映射

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    /DISCARD/ : {
        *(.ARM.exidx*)
    }
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
    .data : { *(.data*) } > ram
}

这会生成一个 28 字节的 basic.bin 文件

08000000 _start:
 8000000: 00 10                         asrs    r0, r0, #32
 8000002: 00 20                         movs    r0, #0
 8000004: 11 00                         movs    r1, r2
 8000006: 00 08                         lsrs    r0, r0, #32
 8000008: 15 00                         movs    r5, r2
 800000a: 00 08                         lsrs    r0, r0, #32
 800000c: 15 00                         movs    r5, r2
 800000e: 00 08                         lsrs    r0, r0, #32

08000010 reset:
 8000010: 00 f0 02 f8                   bl  #4

08000014 loop:
 8000014: fe e7                         b   #-4 <loop>
 8000016: d4 d4                         bmi #-88 <start.c+0x7ffffc2>

08000018 notmain:
 8000018: 07 20                         movs    r0, #7
 800001a: 70 47                         bx  lr

现在让我们添加.data:

unsigned int x = 5;
unsigned int notmain ( void )
{
    return(7);
}

现在我的 basic.bin 是 402653188 字节。

正在发生的事情是 objcopy 正在制作一个二进制内存映像,该映像从第一个可加载或相关 space 开始并以最后一个结束

Disassembly of section .text:

08000000 _start:
 8000000: 00 10                         asrs    r0, r0, #32
 8000002: 00 20                         movs    r0, #0
 8000004: 11 00                         movs    r1, r2
 8000006: 00 08                         lsrs    r0, r0, #32
 8000008: 15 00                         movs    r5, r2
 800000a: 00 08                         lsrs    r0, r0, #32
 800000c: 15 00                         movs    r5, r2
 800000e: 00 08                         lsrs    r0, r0, #32

08000010 reset:
 8000010: 00 f0 02 f8                   bl  #4

08000014 loop:
 8000014: fe e7                         b   #-4 <loop>
 8000016: d4 d4                         bmi #-88 <start.c+0x7ffffc2>

08000018 notmain:
 8000018: 07 20                         movs    r0, #7
 800001a: 70 47                         bx  lr

Disassembly of section .data:

20000000 x:
20000000: 05 00                         movs    r5, r0
20000002: 00 00                         movs    r0, r0

从 0x08000000 到 0x20000002(含)

0x20000003 - 0x08000000 = 402653187 所以他们将它填充到最近的单词(或半字)。

你不能将它加载到你的微控制器中,它无论如何都不会工作,你的程序需要包含在非易失性存储器中...闪存...

第一步:

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    /DISCARD/ : {
        *(.ARM.exidx*)
    }
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
    .data : { *(.data*) } > ram AT > rom
}

改成ram AT rom.

basic.bin 文件现在是 32 字节。

00000000  00 10 00 20 11 00 00 08  15 00 00 08 15 00 00 08  |... ............|
00000010  00 f0 02 f8 fe e7 d4 d4  07 20 70 47 05 00 00 00  |......... pG....|
00000020

Disassembly of section .text:

08000000 _start:
 8000000: 00 10                         asrs    r0, r0, #32
 8000002: 00 20                         movs    r0, #0
 8000004: 11 00                         movs    r1, r2
 8000006: 00 08                         lsrs    r0, r0, #32
 8000008: 15 00                         movs    r5, r2
 800000a: 00 08                         lsrs    r0, r0, #32
 800000c: 15 00                         movs    r5, r2
 800000e: 00 08                         lsrs    r0, r0, #32

08000010 reset:
 8000010: 00 f0 02 f8                   bl  #4

08000014 loop:
 8000014: fe e7                         b   #-4 <loop>
 8000016: d4 d4                         bmi #-88 <start.c+0x7ffffc2>

08000018 notmain:
 8000018: 07 20                         movs    r0, #7
 800001a: 70 47                         bx  lr

Disassembly of section .data:

20000000 x:
20000000: 05 00                         movs    r5, r0
20000002: 00 00                         movs    r0, r0

注意二进制文件的结尾:

70 47 05 00 00 00

它有最后一个 .text 项 70 47 然后是 .data 项。

让工具为您完成工作

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    /DISCARD/ : {
        *(.ARM.exidx*)
    }
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ram AT > rom
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;
}

basic.bin 当前仍然是 32 字节但是

llvm-nm basic.elf 
20000004 D __data_end__
0800001c T __data_rom_start__
00000004 A __data_size__
20000000 D __data_start__
08000000 T _start
08000014 t loop
08000018 T notmain
08000010 t reset
20000000 D x

现在我们知道在地址 0x0800001c 的闪存中,嵌入的 .data 开始,它的大小为 4 个字节,其在 ram 中的目标是 0x20000000 所以现在 bootstrap 代码可以将 .data 从闪存复制到调用 C 入口点之前的 ram。

现在你已经完成了所有这些,我假设你知道关于链接器脚本和 bootstrap 的所有这些,但是你得到的是 400MB 的二进制文件,这表明有其他东西泄漏到 ram 中地址 space.

检查反汇编 (objdump -D) and.or readelf and/or nm 输出以找出其中的内容并将其与要复制的 bootstrap 代码一起添加到链接描述文件它。

添加一些.bss

unsigned int x = 5;
unsigned int y;
unsigned int notmain ( void )
{
    return(7);
}

来自 objdump

Disassembly of section .bss:

20000000 y:
...

Disassembly of section .data:

20000004 x:
20000004: 05 00                         movs    r5, r0
20000006: 00 00                         movs    r0, r0

来自 readelf

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x001000 0x08000000 0x08000000 0x0001c 0x0001c R E 0x1000
  LOAD           0x002000 0x20000000 0x20000000 0x00000 0x00004 RW  0x1000
  LOAD           0x002004 0x20000004 0x0800001c 0x00004 0x00004 RW  0x1000

.bss 看起来有点吓人,但它并没有以二进制形式结束,它又是 32 字节。但我们在这里看到 .data 物理上位于闪存中,但希望位于 ram 中,这正是我们对此类平台的期望。也许你可以从 readelf 找到内存泄漏。

您的 objcopy -O 二进制输出应该适合闪存并包含 100% 的程序和数据,否则如果您仅从该 400MByte 文件中提取闪存部分,它将无法工作,可能会有或可能有一些数据项不会在那里运行预期的软件。或者它可能是一些愚蠢的字符串 table 东西或其他一些并非真正用于二进制文件但碰巧有一个节名称到目前为止未在链接器脚本中处理的东西。

抱歉,400MB 对我来说从一开始就应该很明显,这是准备新项目时另一个常见的链接描述文件陷阱。我个人从不使用 .data 也不依赖 .bss 所以没有这些问题,但你的体验可能不同,但我仍然非常清楚。 (当你的 .text 为 0 且 ram 为 0x80000000 或更高时,你会得到千兆字节大小的文件,这会更有趣)。