本帖最后由 sunsili 于 2022-11-29 15:56 编辑 5 h3 d2 I: P& n& o
& l# }& \0 e7 i9 y& O. nMDK Keil使用GCC编译图文详解简介
+ R U: _ U/ u" a. A
2 v" p9 Y L" F& J7 D) u! X! u4 FKeil MDK-ARM 可以与 GNU 编译器集合 (GCC) 一起使用。GCC 是一个有众多贡献者的开源开发工作,它广泛可用并支持许多设备。 Keil 默认使用的是ARMCC编译MCU工程代码。因此设置为GCC编译需要进行以下配置。
: `, e8 h" x0 `下载步骤
' |9 p2 i3 H* TARM GCC编译器下载地址:https://developer.arm.com/tools- ... in/gnu-rm/downloads
4 U( v% w1 L* \ g* T; q, r% X
" s' o7 I; L2 I. Z8 S- J3 I# o" P
* f1 ^2 v; a' V* @5 o; q操作步骤
6 k H& T! z" A1 要启用 MDK-ARM 以使用 GCC:1.打开组件、环境和书籍对话框 项目 > 管理 > 组件、环境、书籍…
μVision GNU 工具选择 6 `) e* I/ c: ^' E) R) O$ r
2.选择文件夹/扩展选项卡, 3.并检查使用 GNU 编译器。
. p& y) ~9 L5 Q/ Q0 U/ M1.配置CC编译规则: M# @& E5 n! V/ R
注意勾选一下选项,填写规则 Misc Controls : -mcpu=cortex-m3 -mthumb -fdata-sections -ffunction-sections注:1.这里我用的cortex-m3,如果你是m4内核就改成4) 2.-mthumb的意义是:使用这个编译选项生成的目标文件是Thumb的 3.-fdata-sections和-ffunction-sections和下文连接规则一起说
2 S* r. k" f: H, A
2.配置Assembler编译规则类似前一项 Misc Controls : -mcpu=cortex-m3 -mthumb
$ a8 S% y$ }- g0 D+ h0 X/ V3.配置Linker连接规则$ S+ _& V) Z; P4 o8 D1 e* @1 H! n
这里要添加连接脚本,一般可以在官方提供的固件库包找到类似的 Misc Controls : -Wl,–gc-sections 注:1.注意这个gc前面是两个短小的“–”,由于博客的问题直接复制会出错 2.-wl, 表示后面的参数 --gc-sections 传递给链接器 3.-fdata-sections和-ffunction-sections和–gc-sections的说明如下
+ _# G+ k0 a' i% O x
4.stm32f10x_flash_extsram.ld内容/*
1 u) C7 g& L+ Q1 f$ mDefault linker script for STM32F10x_1024K_1024K# o4 g0 i9 o) j! q
Copyright RAISONANCE S.A.S. 2008+ Z0 T. G7 T$ ~, J& i
*/
' C# X% d2 k: J5 W, p8 a' O' D t9 \" Q3 u: F
/* include the common STM32F10x sub-script */
% J8 t7 o* S0 r* K* E/* Common part of the linker scripts for STM32 devices*/
' x3 I6 O6 `4 N8 Z/ k' H
$ _0 n1 O9 T7 S, A6 d- r/* default stack sizes.
Y. r* u, r; u z# LThese are used by the startup in order to allocate stacks for the different modes.8 D, c- V/ X" }2 F
*/
% L4 d5 i) R' i* S
! m5 B6 p5 n) p% V6 |, }6 v__Stack_Size = 1024 ;/ Y3 n7 a N, c& p
; q+ q( ^: t3 N7 m1 OPROVIDE ( _Stack_Size = __Stack_Size ) ;% k5 M9 e0 b* a* {; M$ p. H! P
9 x( P1 K; ~ ]2 x__Stack_Init = _estack - __Stack_Size ;; G& e" L" v5 [" J9 N* Z/ l
! D9 G. w( I- k6 L
/*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/
4 I: a1 d9 z0 U) M8 s0 TPROVIDE ( _Stack_Init = __Stack_Init ) ;) X/ [) }. A. _' Z+ N
& R) \* Z* W/ C e
/*
' C+ m# M* u) @8 ?8 T- lThere will be a link error if there is not this amount of RAM free at the end.
4 T: a7 m& d& u: h: U# [*/) N8 a5 @% w) B5 O7 t8 t
_Minimum_Stack_Size = 0x100 ;
* W) {( Z- b/ i& z
. y0 {+ \! I* S: `! b/ a$ U! J0 h$ _0 N
/* include the memory spaces definitions sub-script */
; K4 o, \& P c' Z Y/*: L2 c; b+ z/ e2 w
Linker subscript for STM32F10x definitions with 1024K Flash and 1024K External SRAM */
& G- G4 z( A2 a" P" L7 j0 ?& C# r2 ^1 E% F
/* Memory Spaces Definitions */
1 w% D2 ^% c2 T p0 {* a% L7 Y3 p; U2 m3 d4 k# V' |: h: v
MEMORY" V7 `: M, m- D1 |/ ?) x& ]
{1 w) l( E: v5 g0 x. A
RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 1024K7 \* l+ G) M" e1 J h3 t3 A
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K v7 R5 ?3 E" A2 d9 ^
FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
( e% ]& ^9 R( N" |6 O0 Y& p# C EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
, A7 ~8 [7 f4 ^: h0 H EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0! h0 j; d. `' {
EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
( I. P, y6 U7 X0 K) Z+ h) i; O+ q/ r( j" H EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0/ J% a& R! l% Y f, ?$ H
}
# _. q- A( X$ {4 j/ p% ]/ @3 [9 ]9 J( g( t% z
/* higher address of the user mode stack */3 b+ ?! h/ }/ [: @2 ]1 r% ?( h6 C
_estack = 0x68100000;6 j: l9 T2 y0 k
) [+ z8 ^8 x4 C6 Z, T' i/ T/* include the sections management sub-script for FLASH mode */% U4 r- u7 `9 l2 \9 q$ {
/* Sections Definitions */
" [$ v; \' q9 \; K/ h3 R
- a) M5 q" r; L8 @SECTIONS
1 t% U; `7 ?/ P P) `6 o7 a* k{3 Q' t% u/ I' i# P/ c7 U
/* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */$ s3 X0 _! g' B# m+ N; ~
.isr_vector :5 {2 @$ _ g- n& Y, X
{$ }' P5 X% Z, ]* K" ~# h2 q' K
. = ALIGN(4);
( j9 s5 T8 Q8 f3 p }/ [( w# I KEEP(*(.isr_vector)) /* Startup code */
* K( L- Q8 s$ F% X+ ^; q3 f . = ALIGN(4);
( G0 ^- U/ y: U* |8 ~ } >FLASH6 B3 l4 a- W$ _- B- a
; v* t6 n. f; u! [# \2 T$ a
/* for some STRx devices, the beginning of the startup code is stored in the .flashtext section, which goes to FLASH */8 _! H4 h% A/ X: D
.flashtext :: [. ?5 j) v8 I: p; B5 y) `
{' E- Z2 s/ v @
. = ALIGN(4);% V- d$ }' D% j0 }+ N& t( F, w9 \
*(.flashtext) /* Startup code */
9 \; _: b( e: J. _* ?: Q" R . = ALIGN(4);8 H% V$ n% {) k+ |! s4 N$ W5 i8 C
} >FLASH
: B( e. ]6 g& b# Y+ W/ D3 y
2 H8 U2 N$ ]4 _( W7 k' \: d
+ J5 K: E( o5 c# ~4 n /* the program code is stored in the .text section, which goes to Flash */
3 M( H7 R5 F- L- b* A( v .text :; N; x0 K* Y& g( q/ y# m" w3 E. O
{
7 X* P8 Z( \9 y) j; H% Y! Z . = ALIGN(4); {) s, m0 Q( E
: d0 u8 C! n _! P a
*(.text) /* remaining code */8 }: f+ P/ B& P3 ]4 p
*(.text.*) /* remaining code */
9 a6 t2 l6 c6 @8 @ *(.rodata) /* read-only data (constants) */2 ?, ~1 [6 L: n+ m1 ]; a
*(.rodata*): J0 D% b6 x" s# [0 S! x
*(.glue_7)
" W. ~! I7 y/ |3 V *(.glue_7t)
8 ^8 m# M: {6 D% Z; C+ j6 n& \& `4 k/ A% O- J1 N# ]
. = ALIGN(4);5 @! U# Q, f8 u* I* H
_etext = .;6 u" N2 m, {7 r
/* This is used by the startup in order to initialize the .data secion */
$ S+ G# y# y7 S% i9 P1 f: `. ? _sidata = _etext;
. r' { s; s+ h! s } >FLASH8 ]+ i* L- n& ^
& t& v% ~. r; O% i& S1 d; m: @ 2 V" F( L" Y8 v7 @3 J5 H# P) f
% A4 D# o9 @5 v8 C /* This is the initialized data section4 E& P, B+ @- W0 Y3 s+ D! t
The program executes knowing that the data is in the RAM0 L0 k" d- e* @" a) X4 A
but the loader puts the initial values in the FLASH (inidata).4 N1 L$ r6 t7 j# ]
It is one task of the startup to copy the initial values from FLASH to RAM. */) o( V8 c& ]- D: ^" @2 q3 @
.data : AT ( _sidata ) ]$ [4 t4 `4 b. E. m: D
{
) Q$ q7 N" Q( O; S5 V" H% ~& R . = ALIGN(4);; ]0 ]; K' z" y7 v s# Z$ O8 |
/* This is used by the startup in order to initialize the .data secion */% ?- {& y4 \4 p- T; F- W( g
_sdata = . ;! N6 V2 x2 x5 r0 D& Z
# Q' U- x+ ~" m8 E4 v6 V: h
*(.data)
8 W. _4 f4 ^. [- C# B( k *(.data.*)
; I* A2 L0 C3 v
& n& p$ ~) O- r& B2 y . = ALIGN(4);
" b" ^' A, h+ ]7 T. f. ~ /* This is used by the startup in order to initialize the .data secion */
6 B, S) i- ~5 I& m- Z+ h8 P, p' x' O _edata = . ;5 [2 {+ j$ y' p4 N1 i" g0 f) U1 G
} >RAM
8 D+ y: r' s; y | 2 H v. c* t( w+ \1 c9 @
0 }1 h( [9 g+ A+ c. g! B7 i+ [ /* This is the uninitialized data section */0 m' S0 z5 L5 |/ X, S' a7 e3 O
.bss :3 {/ h6 t+ Q+ f' N7 J; u# F5 |
{# G# d# V7 i* l, D: I
. = ALIGN(4);
+ g/ w) y1 N, ~6 h& Y; P2 E /* This is used by the startup in order to initialize the .bss secion */
2 K- S% g* W. O0 r _sbss = .;
. V4 Z% T' W4 j # G) Y8 v0 M6 y6 k) M
*(.bss)2 |5 X7 b' ~$ g! C$ C
*(COMMON)! N# d p3 ^! i# z! H' j
6 O* v; h% J4 _* { S
. = ALIGN(4);
) ]( L" _( { q4 n6 ~ b( _/ G /* This is used by the startup in order to initialize the .bss secion */
8 X! W2 \( N( d7 u% e7 f _ebss = . ;9 h, @& N" i& X. g S6 r
} >RAM
U9 i) {3 y' ~1 G. l/ u
0 a, Z+ X m) B# M4 Q2 y5 ~5 s PROVIDE ( end = _ebss );2 R/ Z% h8 `; k1 a! t& i2 `
PROVIDE ( _end = _ebss );
, ~/ W% v* k% l% w8 M
8 Y: Z) |- K3 s' Y: V /* This is the user stack section
. q2 ^6 ]$ @; g5 j: N! `3 i This is just to check that there is enough RAM left for the User mode stack# n, A9 [2 F( u1 w1 S7 j; M
It should generate an error if it's full.# E' f# P, z$ P3 Y' b
*/
3 C, J2 e) I, a- m1 R8 h. D9 } ._usrstack :, u+ y2 o- i! u& r
{
1 k# _5 M" [5 y7 O) }, V( @ . = ALIGN(4);* S4 p+ ?. k4 {2 w4 ?8 x
_susrstack = . ;0 N& Q" u N$ I- h! H, S; K! {
% I9 t6 {/ f: C( K. Y . = . + _Minimum_Stack_Size ;
2 y1 _0 }; c! X$ o( E ' {" G1 L& P. M3 g( X) W
. = ALIGN(4);
8 w2 W5 @% z+ S6 a3 }7 a7 Q _eusrstack = . ;1 h) E1 ~2 @+ u% s0 N
} >RAM
Q! x9 k0 W, f! t
s- c- M9 F3 i# Z, q# O6 E /* this is the FLASH Bank1 */- {3 E5 J7 u" F' _
/* the C or assembly source must explicitly place the code or data there
6 A3 i0 d. S; s4 I) G; T" q using the "section" attribute */
) m, k8 `0 a! I/ l* d' N .b1text :6 y9 c% H: m2 K* `% G' J
{
4 q1 |8 Q1 X( E+ o2 J9 C *(.b1text) /* remaining code */
: b1 z! {! p1 ^2 f *(.b1rodata) /* read-only data (constants) */
. I; v7 w. i; F *(.b1rodata*)# V; a# G6 c; B3 N: @3 H
} >FLASHB1
9 s5 Q: {& {2 F6 L6 _
; J. q9 }* ?' m4 o$ s m /* this is the EXTMEM */* m) Y1 }4 y. ]8 ^9 V: h" z
/* the C or assembly source must explicitly place the code or data there
& x+ J7 \7 u8 Q- O using the "section" attribute */! M2 k" z$ S+ G: [
2 s" @& v8 g9 p /* EXTMEM Bank0 */5 |4 M" n `: a
.eb0text :6 L4 l( j: e6 N4 e# I( C; D% j. a
{. g2 Z/ @8 ~% Z0 e, T( Y
*(.eb0text) /* remaining code */
4 U# ]" U* q4 @9 |+ a; x *(.eb0rodata) /* read-only data (constants) */: r' A2 y6 M' ]
*(.eb0rodata*)* v! i3 u. E" |
} >EXTMEMB05 F5 G) p5 z, U1 I: {( `
6 M9 f' c0 D- y; h /* EXTMEM Bank1 */
/ B. P# K; w) g6 l6 N1 r .eb1text :
1 m, x/ B0 p _( O) }" A* n' }7 I/ Q {% o6 l" r- S9 W5 r
*(.eb1text) /* remaining code */2 m' ^4 `) V3 ^! ^; T
*(.eb1rodata) /* read-only data (constants) */* k2 U5 s, ~3 Q6 Q7 `
*(.eb1rodata*)/ B" b6 n+ l: K7 ~- t) B" t" f8 Z) E
} >EXTMEMB1& c! V" c+ I: h# c7 `% Z
8 h' I( U" q+ [1 l+ I# _$ e
/* EXTMEM Bank2 */
8 z e* C/ i- g' r* v .eb2text :
; D. ?, F( Q2 Z7 J- q {. {9 R9 d) c; D* _3 I
*(.eb2text) /* remaining code */
: d( _; u4 U0 T0 {# h *(.eb2rodata) /* read-only data (constants) */
1 ?3 s+ @/ D5 `9 O" c5 o4 D! M *(.eb2rodata*)
7 z/ {# O4 j0 e) e } >EXTMEMB2
* v4 b( B1 n1 }7 a8 Y # o: b/ \! ~' J4 [/ b! m. ?
/* EXTMEM Bank0 */
* b# Z, O/ j2 O9 m h .eb3text :' u/ T* ?5 ? @% J
{' ]7 K! N$ W! o0 \
*(.eb3text) /* remaining code */% u0 }9 k- E# _5 G: Z0 F
*(.eb3rodata) /* read-only data (constants) */$ O4 r2 C: b1 I+ a* y6 K6 N
*(.eb3rodata*)
3 e2 G. v ]/ R* S* z } >EXTMEMB3
- p" V0 y, j+ t, n
+ t. H1 ]7 `1 K) x8 m5 N" V
+ i9 s9 D! T# v% q9 @! @ /* after that it's only debugging information. */
! k9 I& W" F5 L5 G' F 0 Y) N: H3 l6 _" L/ g: N
/* remove the debugging information from the standard libraries */
+ P) B! c" d/ n0 z4 ]3 {" s DISCARD :, g$ B. Y+ I" ?6 s. x- T* I
{6 D( {1 O& i) ~% s$ }
libc.a ( * )/ F( N0 Q& M7 k
libm.a ( * )
' A; I$ `# Y; o5 c libgcc.a ( * )
3 S: U- d, b9 v+ C }. b3 {9 @. c: Y1 H, P+ ?# n- \. V. O
W9 g0 k1 T+ S/ E. F4 ~ /* Stabs debugging sections. */8 P( i/ c, @8 R( C; a
.stab 0 : { *(.stab) }
/ R( o/ J! y0 t .stabstr 0 : { *(.stabstr) }3 ~# b0 ]6 E) Z1 a" E6 {1 t
.stab.excl 0 : { *(.stab.excl) }7 l2 [- R; |0 _
.stab.exclstr 0 : { *(.stab.exclstr) }+ j+ g4 {+ N5 }
.stab.index 0 : { *(.stab.index) }
3 o: |7 _0 Y3 g- j. |5 ` .stab.indexstr 0 : { *(.stab.indexstr) }4 x- k1 B- m1 d9 N6 |4 P* X
.comment 0 : { *(.comment) }
H3 P0 U0 b0 I9 V0 M8 _ /* DWARF debug sections.8 \$ |3 Z, M' Z/ [) k* d
Symbols in the DWARF debugging sections are relative to the beginning E. _0 K% @' V! I! f/ F
of the section so we begin them at 0. *// L. R1 I& F- K0 K4 r7 Z
/* DWARF 1 */
% ~+ P$ M, z5 A. h9 t; R .debug 0 : { *(.debug) }
3 ~9 N) V1 k0 h# q3 D! D: r .line 0 : { *(.line) }
% I; a6 K% r& ]- I$ n5 d /* GNU DWARF 1 extensions */
; w( r1 P, a* d) l* t3 R% {1 z$ e .debug_srcinfo 0 : { *(.debug_srcinfo) }
6 B" i5 L' P; Y0 s6 C .debug_sfnames 0 : { *(.debug_sfnames) }
; K* U$ {+ L% ~2 D& m3 c: m0 y /* DWARF 1.1 and DWARF 2 */
: |+ I$ \4 ]. D, ]0 a+ g .debug_aranges 0 : { *(.debug_aranges) }2 z6 V- w* F Z) A7 \
.debug_pubnames 0 : { *(.debug_pubnames) }
% ~/ ?: E" `- G. G! N /* DWARF 2 */+ t- {) ?. j; L
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }1 |6 s7 N6 b" ^
.debug_abbrev 0 : { *(.debug_abbrev) }
1 j0 w; r K7 p0 ^' H, q6 E" S .debug_line 0 : { *(.debug_line) }
! C* W% O8 J& P8 O/ H7 G .debug_frame 0 : { *(.debug_frame) }
9 _8 J- G/ t J+ D# } .debug_str 0 : { *(.debug_str) }! |# U& ~# Z3 _: F+ K2 f
.debug_loc 0 : { *(.debug_loc) }, ~) q3 c. U9 O2 I& H3 r) Y+ [
.debug_macinfo 0 : { *(.debug_macinfo) }
* ]; z3 x( }% `" G5 o2 @ /* SGI/MIPS DWARF 2 extensions */
. V4 Y' D3 _4 R6 b% C .debug_weaknames 0 : { *(.debug_weaknames) }2 O: a& v! |8 L! ]
.debug_funcnames 0 : { *(.debug_funcnames) }- O& U4 G7 Y( `+ Z r
.debug_typenames 0 : { *(.debug_typenames) }) v2 _: z3 ]+ z8 x; H- E1 r5 r* d
.debug_varnames 0 : { *(.debug_varnames) }
! r) r6 F7 t& p4 q2 }! c} G+ v/ B+ ^" [8 B
* ^. M9 l, l, }( }' [4 C( k3 w4 A) M五、启动代码,使用GCC专用的.S文件8 t" N( F) [" d4 I
使用GCC编译器需要的启动代码不同与AMRCC,不过官方已经有提供了相关代码,如下图:
9 R" C4 |2 V. N% J5 O六、编译运行) y) M9 ^( {7 v+ [! l, ?6 \7 f% X
1 A; D) _* ]1 c2 ?6 h( O" f1.core_cm3.c错误4 X/ a: p8 R9 D4 | y1 _
% y+ R# T. o3 G# L
1 o ^$ l! P* @2 h这里写图片描述出现两个错误,经过在搜索发现原来是官方提供的core_cm3.c有bug造成的 将其中 736行改为: __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );7 z% t1 O4 o0 Y* h2 B, |9 X) B- w
753行改为: __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
6 x+ r3 c1 I' b# u
4 y5 x6 E1 Q: ^( T6 X知识补充–gnu
- K6 O8 J+ @ I+ D8 y( G$ c5 p. B启用 ARM 编译器支持的 GNU 编译器扩展。扩展兼容的 GCC 版本可以通过检查预定义的宏__GNUC__和__GNUC_MINOR__. 此外,在 GNU 模式下,ARMCC 编译器模拟 GCC 以符合 C/C++ 标准,无论其严格程度如何。 此选项还可以与其他源语言命令行选项结合使用。例如,armcc --c90 --gnu。
+ r. k0 n& P$ d+ ~4 u6 x! L–C99和–gnuSOEM代码中好多编译标准貌似是GNU标准,比如匿名UNION,数组大小不能开为0等等。因此需要在Keil c/c++ 的Misc Controls中
加入--gnu 参考其它博主。会导致printf出现问题,因此需在代码内加入以下内容: #ifdef __GNUC__
j1 R3 p9 U4 F /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf% R! B; p; j( R# M
set to 'Yes') calls __io_putchar() */) k+ G1 C4 A' ]& w; A
//#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
+ l* h1 X) w( E8 I; U //comment_20190422: soem needs --gnu compile option, 1 v" o* l' o- \0 i% a" U
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
7 Q/ g5 r# ?6 W M9 U 6 X3 w$ b; K' t& l9 v
#else' t; L6 @1 g, e4 a7 m
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)1 B( L7 L7 I" K8 B6 g
#endif /* __GNUC__ */" h' ~# G9 @! _0 }: W) g$ D
/**- E( ?% ^5 ~8 Q. V9 a- L/ r
* @brief Retargets the C library printf function to the USART.% W3 z0 P/ O" F$ L$ F
* @param None
4 y. l% @4 F# \8 {; R. c- n * @retval None
5 C' ~& h; A& {% O/ f. k */0 @- x1 R; u, s% v @4 B) H+ I$ H
PUTCHAR_PROTOTYPE- \4 f* Q/ l Y
{
9 K6 p$ m7 a- L* y7 g /* Place your implementation of fputc here */
; P8 v: U$ Y' h. E4 n- s /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */
4 a' q2 F/ M+ r# h$ Y& n; i HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
0 z- s5 z+ P! u, ? , |7 f9 Q @, _
return ch;
, |, ?7 R0 a, ]5 O* `- S) [* |}
* Z6 v2 U- h! g: {; E6 k5 @+ e" g) a6 t' x5 [3 T9 @1 o! {$ R
& z/ e- u( a- `1 M- B
|