sunsili 发表于 2022-11-29 15:53:29

MDK Keil使用GCC编译图文详解

本帖最后由 sunsili 于 2022-11-29 15:56 编辑

MDK Keil使用GCC编译图文详解简介

Keil MDK-ARM 可以与 GNU 编译器集合 (GCC) 一起使用。GCC 是一个有众多贡献者的开源开发工作,它广泛可用并支持许多设备。Keil 默认使用的是ARMCC编译MCU工程代码。因此设置为GCC编译需要进行以下配置。
下载步骤
ARM GCC编译器下载地址:https://developer.arm.com/tools- ... in/gnu-rm/downloads


操作步骤
1 要启用 MDK-ARM 以使用 GCC:1.打开组件、环境和书籍对话框 项目 > 管理 > 组件、环境、书籍…μVision GNU 工具选择
2.选择文件夹/扩展选项卡,3.并检查使用 GNU 编译器。
1.配置CC编译规则
注意勾选一下选项,填写规则Misc Controls : -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections注:1.这里我用的cortex-m3,如果你是m4内核就改成4) 2.-mthumb的意义是:使用这个编译选项生成的目标文件是Thumb的 3.-fdata-sections和-ffunction-sections和下文连接规则一起说
2.配置Assembler编译规则类似前一项 Misc Controls : -mcpu=cortex-m3 -mthumb
3.配置Linker连接规则
这里要添加连接脚本,一般可以在官方提供的固件库包找到类似的Misc Controls : -Wl,–gc-sections 注:1.注意这个gc前面是两个短小的“–”,由于博客的问题直接复制会出错 2.-wl, 表示后面的参数 --gc-sections 传递给链接器 3.-fdata-sections和-ffunction-sections和–gc-sections的说明如下
4.stm32f10x_flash_extsram.ld内容/*
Default linker script for STM32F10x_1024K_1024K
Copyright RAISONANCE S.A.S. 2008
*/

/* include the common STM32F10x sub-script */
/* Common part of the linker scripts for STM32 devices*/

/* default stack sizes.
These are used by the startup in order to allocate stacks for the different modes.
*/

__Stack_Size = 1024 ;

PROVIDE ( _Stack_Size = __Stack_Size ) ;

__Stack_Init = _estack- __Stack_Size ;

/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
PROVIDE ( _Stack_Init = __Stack_Init ) ;

/*
There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 0x100 ;


/* include the memory spaces definitions sub-script */
/*
Linker subscript for STM32F10x definitions with 1024K Flash and 1024K External SRAM */

/* Memory Spaces Definitions */

MEMORY
{
RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 1024K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
}

/* higher address of the user mode stack */
_estack = 0x68100000;

/* include the sections management sub-script for FLASH mode */
/* Sections Definitions */

SECTIONS
{
    /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
    .isr_vector :
    {
. = ALIGN(4);
      KEEP(*(.isr_vector))            /* Startup code */
. = ALIGN(4);
    } >FLASH

    /* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */
    .flashtext :
    {
. = ALIGN(4);
      *(.flashtext)            /* Startup code */
. = ALIGN(4);
    } >FLASH

   
    /* the program code is stored in the .text section, which goes to Flash */
    .text :
    {
   . = ALIGN(4);
   
      *(.text)                   /* remaining code */
      *(.text.*)                   /* remaining code */
      *(.rodata)               /* read-only data (constants) */
      *(.rodata*)
      *(.glue_7)
      *(.glue_7t)

   . = ALIGN(4);
   _etext = .;
   /* This is used by the startup in order to initialize the .data secion */
   _sidata = _etext;
    } >FLASH
   


    /* This is the initialized data section
    The program executes knowing that the data is in the RAM
    but the loader puts the initial values in the FLASH (inidata).
    It is one task of the startup to copy the initial values from FLASH to RAM. */
    .data: AT ( _sidata )
    {
   . = ALIGN(4);
      /* This is used by the startup in order to initialize the .data secion */
      _sdata = . ;
      
      *(.data)
      *(.data.*)

   . = ALIGN(4);
   /* This is used by the startup in order to initialize the .data secion */
   _edata = . ;
    } >RAM
      

    /* This is the uninitialized data section */
    .bss :
    {
   . = ALIGN(4);
      /* This is used by the startup in order to initialize the .bss secion */
      _sbss = .;
      
      *(.bss)
      *(COMMON)
      
   . = ALIGN(4);
   /* This is used by the startup in order to initialize the .bss secion */
   _ebss = . ;
    } >RAM
   
    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );
   
    /* This is the user stack section
    This is just to check that there is enough RAM left for the User mode stack
    It should generate an error if it's full.
   */
    ._usrstack :
    {
   . = ALIGN(4);
      _susrstack = . ;
      
      . = . + _Minimum_Stack_Size ;
      
   . = ALIGN(4);
      _eusrstack = . ;
    } >RAM
      
    /* this is the FLASH Bank1 */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */
    .b1text :
    {
      *(.b1text)                   /* remaining code */
      *(.b1rodata)               /* read-only data (constants) */
      *(.b1rodata*)
    } >FLASHB1
   
    /* this is the EXTMEM */
    /* the C or assembly source must explicitly place the code or data there
    using the "section" attribute */
   
    /* EXTMEM Bank0 */
    .eb0text :
    {
      *(.eb0text)                   /* remaining code */
      *(.eb0rodata)               /* read-only data (constants) */
      *(.eb0rodata*)
    } >EXTMEMB0
   
    /* EXTMEM Bank1 */
    .eb1text :
    {
      *(.eb1text)                   /* remaining code */
      *(.eb1rodata)               /* read-only data (constants) */
      *(.eb1rodata*)
    } >EXTMEMB1
   
    /* EXTMEM Bank2 */
    .eb2text :
    {
      *(.eb2text)                   /* remaining code */
      *(.eb2rodata)               /* read-only data (constants) */
      *(.eb2rodata*)
    } >EXTMEMB2
   
    /* EXTMEM Bank0 */
    .eb3text :
    {
      *(.eb3text)                   /* remaining code */
      *(.eb3rodata)               /* read-only data (constants) */
      *(.eb3rodata*)
    } >EXTMEMB3
   
      
    /* after that it's only debugging information. */
   
    /* remove the debugging information from the standard libraries */
    DISCARD :
    {
   libc.a ( * )
   libm.a ( * )
   libgcc.a ( * )
   }

    /* Stabs debugging sections.*/
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl   0 : { *(.stab.excl) }
    .stab.exclstr0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /* DWARF debug sections.
       Symbols in the DWARF debugging sections are relative to the beginning
       of the section so we begin them at 0.*/
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line         0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo0 : { *(.debug_srcinfo) }
    .debug_sfnames0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info   0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line   0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames0 : { *(.debug_varnames) }
}

五、启动代码,使用GCC专用的.S文件
使用GCC编译器需要的启动代码不同与AMRCC,不过官方已经有提供了相关代码,如下图:
六、编译运行

1.core_cm3.c错误


这里写图片描述出现两个错误,经过在搜索发现原来是官方提供的core_cm3.c有bug造成的 将其中 736行改为:   __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
753行改为:   __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

知识补充–gnu
启用 ARM 编译器支持的 GNU 编译器扩展。扩展兼容的 GCC 版本可以通过检查预定义的宏__GNUC__和__GNUC_MINOR__. 此外,在 GNU 模式下,ARMCC 编译器模拟 GCC 以符合 C/C++ 标准,无论其严格程度如何。此选项还可以与其他源语言命令行选项结合使用。例如,armcc --c90 --gnu。
–C99和–gnuSOEM代码中好多编译标准貌似是GNU标准,比如匿名UNION,数组大小不能开为0等等。因此需要在Keil c/c++ 的Misc Controls中加入--gnu参考其它博主。会导致printf出现问题,因此需在代码内加入以下内容:#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
//#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
//comment_20190422: soem needs --gnu compile option,
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)

#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/**
* @briefRetargets the C library printf function to the USART.
* @paramNone
* @retval None
*/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

return ch;
}


页: [1]
查看完整版本: MDK Keil使用GCC编译图文详解