Skip to content

Commit 4c5de37

Browse files
committed
Add link script and output map file
1 parent 321b52f commit 4c5de37

4 files changed

Lines changed: 213 additions & 41 deletions

File tree

example/setup.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
from mcu_meson_setup import setup
22

3-
setup("builddir", ["../gcc-arm-none-eabi.ini", "../gcc-cortex-m3.ini"])
4-
# setup("builddir", ["../armclang.ini", "../clang-cortex-m3.ini"])
3+
setup(
4+
"builddir",
5+
[
6+
"https://raw.githubusercontent.com/JalonWong/mcu_meson/refs/heads/main/gcc-arm-none-eabi.ini",
7+
"https://raw.githubusercontent.com/JalonWong/mcu_meson/refs/heads/main/gcc-cortex-m3.ini",
8+
],
9+
link_script="src/my_link.ld",
10+
output_map="app.map",
11+
)
512
# setup(
613
# "builddir",
7-
# [
8-
# "https://raw.githubusercontent.com/JalonWong/mcu_meson/refs/heads/main/gcc-arm-none-eabi.ini",
9-
# "https://raw.githubusercontent.com/JalonWong/mcu_meson/refs/heads/main/gcc-cortex-m3.ini",
10-
# ],
14+
# ["../gcc-arm-none-eabi.ini", "../gcc-cortex-m3.ini"],
15+
# link_script="src/my_link.ld",
16+
# output_map="app.map",
1117
# )
18+
# setup("builddir", ["../armclang.ini", "../clang-cortex-m3.ini"])

example/src/my_link.ld

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
******************************************************************************
3+
**
4+
5+
** File : LinkerScript.ld
6+
**
7+
** Author : STM32CubeMX
8+
**
9+
** Abstract : Linker script for STM32F103C8Tx series
10+
** 64Kbytes FLASH and 20Kbytes RAM
11+
**
12+
** Set heap size, stack size and stack location according
13+
** to application requirements.
14+
**
15+
** Set memory bank area and size if external memory is used.
16+
**
17+
** Target : STMicroelectronics STM32
18+
**
19+
** Distribution: The file is distributed “as is,” without any warranty
20+
** of any kind.
21+
**
22+
*****************************************************************************
23+
** @attention
24+
**
25+
** <h2><center>&copy; COPYRIGHT(c) 2025 STMicroelectronics</center></h2>
26+
**
27+
** Redistribution and use in source and binary forms, with or without modification,
28+
** are permitted provided that the following conditions are met:
29+
** 1. Redistributions of source code must retain the above copyright notice,
30+
** this list of conditions and the following disclaimer.
31+
** 2. Redistributions in binary form must reproduce the above copyright notice,
32+
** this list of conditions and the following disclaimer in the documentation
33+
** and/or other materials provided with the distribution.
34+
** 3. Neither the name of STMicroelectronics nor the names of its contributors
35+
** may be used to endorse or promote products derived from this software
36+
** without specific prior written permission.
37+
**
38+
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
39+
** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40+
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41+
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
42+
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43+
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
44+
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
45+
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46+
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47+
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48+
**
49+
*****************************************************************************
50+
*/
51+
52+
/* Entry Point */
53+
ENTRY(Reset_Handler)
54+
55+
/* Highest address of the user mode stack */
56+
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
57+
/* Generate a link error if heap and stack don't fit into RAM */
58+
_Min_Heap_Size = 0x200; /* required amount of heap */
59+
_Min_Stack_Size = 0x400; /* required amount of stack */
60+
61+
/* Specify the memory areas */
62+
MEMORY
63+
{
64+
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
65+
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
66+
}
67+
68+
/* Define output sections */
69+
SECTIONS
70+
{
71+
/* The startup code goes first into FLASH */
72+
.isr_vector :
73+
{
74+
. = ALIGN(4);
75+
KEEP(*(.isr_vector)) /* Startup code */
76+
. = ALIGN(4);
77+
} >FLASH
78+
79+
/* The program code and other data goes into FLASH */
80+
.text :
81+
{
82+
. = ALIGN(4);
83+
*(.text) /* .text sections (code) */
84+
*(.text*) /* .text* sections (code) */
85+
*(.glue_7) /* glue arm to thumb code */
86+
*(.glue_7t) /* glue thumb to arm code */
87+
*(.eh_frame)
88+
89+
KEEP (*(.init))
90+
KEEP (*(.fini))
91+
92+
. = ALIGN(4);
93+
_etext = .; /* define a global symbols at end of code */
94+
} >FLASH
95+
96+
/* Constant data goes into FLASH */
97+
.rodata :
98+
{
99+
. = ALIGN(4);
100+
*(.rodata) /* .rodata sections (constants, strings, etc.) */
101+
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
102+
. = ALIGN(4);
103+
} >FLASH
104+
105+
/* used by the startup to initialize data */
106+
_sidata = LOADADDR(.data);
107+
108+
/* Initialized data sections goes into RAM, load LMA copy after code */
109+
.data :
110+
{
111+
. = ALIGN(4);
112+
_sdata = .; /* create a global symbol at data start */
113+
*(.data) /* .data sections */
114+
*(.data*) /* .data* sections */
115+
*(.RamFunc) /* .RamFunc sections */
116+
*(.RamFunc*) /* .RamFunc* sections */
117+
118+
. = ALIGN(4);
119+
_edata = .; /* define a global symbol at data end */
120+
} >RAM AT> FLASH
121+
122+
123+
/* Uninitialized data section */
124+
. = ALIGN(4);
125+
.bss :
126+
{
127+
/* This is used by the startup in order to initialize the .bss secion */
128+
_sbss = .; /* define a global symbol at bss start */
129+
__bss_start__ = _sbss;
130+
*(.bss)
131+
*(.bss*)
132+
*(COMMON)
133+
134+
. = ALIGN(4);
135+
_ebss = .; /* define a global symbol at bss end */
136+
__bss_end__ = _ebss;
137+
} >RAM
138+
139+
/* User_heap_stack section, used to check that there is enough RAM left */
140+
._user_heap_stack :
141+
{
142+
. = ALIGN(8);
143+
PROVIDE ( end = . );
144+
PROVIDE ( _end = . );
145+
. = . + _Min_Heap_Size;
146+
. = . + _Min_Stack_Size;
147+
. = ALIGN(8);
148+
} >RAM
149+
150+
151+
152+
/* Remove information from the standard libraries */
153+
/DISCARD/ :
154+
{
155+
libc.a ( * )
156+
libm.a ( * )
157+
libgcc.a ( * )
158+
}
159+
160+
}

gcc-arm-none-eabi.ini

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ needs_exe_wrapper = true
99
[constants]
1010
cross_toolchain = 'ARM_TOOLCHAIN_PATH'
1111
cross_compile = cross_toolchain + '/bin/arm-none-eabi-'
12+
link_script = 'link.ld'
13+
output_map = 'out.map'
1214
user_c_args = []
1315
user_c_link_args = []
1416
cpu_args = []
1517
base_c_args = ['-Wno-comment','-Wno-unused-const-variable','-Wno-unused-function','-Wreturn-type','-funsigned-char','-fshort-enums','-gdwarf-3','-fdata-sections','-ffunction-sections']
16-
base_c_link_args2 = []
17-
base_c_link_args = ['-specs=nano.specs','-lc','-lm','-lsupc++_nano','-funsigned-char','-fshort-enums','-ffunction-sections','-fdata-sections','-Wl,--gc-sections'] + base_c_link_args2
18+
additional_c_link_args = []
19+
base_c_link_args = ['-specs=nano.specs','-lc','-lm','-lnosys','-lsupc++_nano','-funsigned-char','-fshort-enums','-ffunction-sections','-fdata-sections','-Wl,--gc-sections'] + additional_c_link_args
1820

1921
[binaries]
2022
c = cross_compile + 'gcc'

mcu_meson_setup/mcu_meson_setup.py

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,25 +20,7 @@ def blue(s: str) -> str:
2020
return f"\033[1;34m{s}\033[0m"
2121

2222

23-
def find_path(cmd: str) -> str | None:
24-
if platform.system() == "Windows":
25-
PATH = os.environ["PATH"].split(";")
26-
cmd += ".exe"
27-
else:
28-
PATH = os.environ["PATH"].split(":")
29-
30-
for P in PATH:
31-
p = Path(P).joinpath(cmd)
32-
if p.exists():
33-
print(green("Found:"), p, flush=True)
34-
subprocess.run([p, "--version"])
35-
return Path(P).as_posix()[:-3]
36-
37-
print(red("Can not find:"), cmd, flush=True)
38-
return None
39-
40-
41-
def find_path2(cmd: str) -> Path | None:
23+
def find_path(cmd: str) -> Path | None:
4224
if platform.system() == "Windows":
4325
PATH = os.environ["PATH"].split(";")
4426
cmd += ".exe"
@@ -55,7 +37,7 @@ def find_path2(cmd: str) -> Path | None:
5537
return None
5638

5739

58-
def write_path(file: Path, arm_path: str | None) -> None:
40+
def modify_cross_file(file: Path, link_script: str, output_map: str, arm_path: str | None) -> None:
5941
if str(file).endswith("gcc-arm-none-eabi.ini"):
6042
arm_cmd = "arm-none-eabi-gcc"
6143
else:
@@ -66,29 +48,44 @@ def write_path(file: Path, arm_path: str | None) -> None:
6648
if path.name != "bin":
6749
path = path.joinpath("bin")
6850
else:
69-
tmp = find_path2(arm_cmd)
70-
if tmp is None:
51+
tmp_path = find_path(arm_cmd)
52+
if tmp_path is None:
7153
print(red("Can not find:"), arm_cmd, flush=True)
7254
exit(1)
73-
path = tmp
55+
path = tmp_path
7456

7557
rst = subprocess.run(
7658
[path.joinpath(arm_cmd), "--version"], text=True, capture_output=True, check=True
7759
)
7860
# print(rst.stdout, flush=True)
7961

80-
text = file.read_text()
62+
path_str = path.parent.as_posix()
63+
text = re.sub(
64+
r"cross_toolchain = '[^']+'", f"cross_toolchain = '{path_str}'", file.read_text(), count=1
65+
)
66+
67+
additional_c_link_args: list[str] = []
8168
if arm_cmd == "arm-none-eabi-gcc":
8269
ver = re.search(r"\) ([\d\.]+) ", rst.stdout)
8370
if ver and int(ver.group(1).split(".")[0]) >= 12:
84-
text = text.replace(
85-
"base_c_link_args2 = []",
86-
"base_c_link_args2 = ['-Wl,-no-warn-rwx-segments']",
87-
count=1,
88-
)
71+
additional_c_link_args.append("-Wl,-no-warn-rwx-segments")
72+
73+
if link_script:
74+
additional_c_link_args.append(f"-T../{link_script}")
75+
76+
if output_map:
77+
additional_c_link_args.append(f"-Wl,-Map={output_map},--cref")
78+
79+
if len(additional_c_link_args) > 0:
80+
args_str = "','".join(additional_c_link_args)
81+
print(args_str)
82+
text = re.sub(
83+
r"additional_c_link_args = \[[^\[]*\]",
84+
f"additional_c_link_args = ['{args_str}']",
85+
text,
86+
count=1,
87+
)
8988

90-
path_str = path.parent.as_posix()
91-
text = re.sub(r"cross_toolchain = '[^']+'", f"cross_toolchain = '{path_str}'", text, count=1)
9289
file.write_text(text)
9390

9491

@@ -109,7 +106,13 @@ def download_files(cross_files: list[str]) -> list[str]:
109106
return rst_list
110107

111108

112-
def setup(build_dir: str, cross_files: list[str], msvc: bool = True) -> None:
109+
def setup(
110+
build_dir: str,
111+
cross_files: list[str],
112+
link_script: str = "",
113+
output_map: str = "",
114+
msvc: bool = True,
115+
) -> None:
113116
parser = argparse.ArgumentParser()
114117
parser.add_argument("--native", help="Setup for native at the same time", action="store_true")
115118
parser.add_argument("--arm_path", help="Path of arm toolchain", type=str)
@@ -129,7 +132,7 @@ def setup(build_dir: str, cross_files: list[str], msvc: bool = True) -> None:
129132
if os.path.exists(build_dir):
130133
shutil.rmtree(build_dir)
131134
cross_files = download_files(cross_files)
132-
write_path(Path(cross_files[0]), opts.arm_path)
135+
modify_cross_file(Path(cross_files[0]), link_script, output_map, opts.arm_path)
133136
cmd = f"meson setup {build_dir}".split() + [f"--cross-file={f}" for f in cross_files]
134137
print(green("Run:"), " ".join(cmd), flush=True)
135138
subprocess.run(cmd)

0 commit comments

Comments
 (0)