良许Linux教程网 干货合集 MDK Keil使用GCC编译图文详解

MDK Keil使用GCC编译图文详解

简介

Keil MDK-ARM 可以与 GNU 编译器集合 (GCC) 一起使用。GCC 是一个有众多贡献者的开源开发工作,它广泛可用并支持许多设备。

Keil 默认使用的是ARMCC编译MCU工程代码。因此设置为GCC编译需要进行以下配置。

下载步骤

ARM GCC编译器下载地址:https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm/downloads

*image-20240106185637298

操作步骤

1 要启用 MDK-ARM 以使用 GCC:1.打开组件、环境和书籍对话框 项目 > 管理 > 组件、环境、书籍…

image-20240106185641748
image-20240106185641748

μVision GNU 工具选择

2.选择文件夹/扩展选项卡,

3.并检查使用 GNU 编译器。image-20240106185647233

image-20240106185650231
image-20240106185650231

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和下文连接规则一起说

image-20240106185653124
image-20240106185653124

2.配置Assembler编译规则

类似前一项 Misc Controls : -mcpu=cortex-m3 -mthumbimage-20240106185656193

3.配置Linker连接规则

这里要添加连接脚本,一般可以在官方提供的固件库包找到类似的

Misc Controls : -Wl,–gc-sections 注:1.注意这个gc前面是两个短小的“–”,由于博客的问题直接复制会出错 2.-wl, 表示后面的参数 –gc-sections 传递给链接器 3.-fdata-sections和-ffunction-sections和–gc-sections的说明如下image-20240106185659123

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.exclstr  0 : { *(.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_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.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_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
}

五、启动代码,使用GCC专用的.S文件

使用GCC编译器需要的启动代码不同与AMRCC,不过官方已经有提供了相关代码,如下图:image-20240106185705816

六、编译运行

1.core_cm3.c错误

image-20240106185709192这里写图片描述

出现两个错误,经过在搜索发现原来是官方提供的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和–gnu

SOEM代码中好多编译标准貌似是GNU标准,比如匿名UNION,数组大小不能开为0等等。因此需要在Keil c/c++ 的Misc Controls中

image-20240106185720823
image-20240106185720823

加入--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__ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @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;
}

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部