blob: 2017011018d16b98e6a84bc98d3c641bbee69567 [file] [log] [blame]
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +05301#!/usr/bin/env python3
Ioannis Glaropoulos560357b2018-11-23 09:39:53 +01002#
3# Copyright (c) 2018 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6
Andrew Boiec78c5e62019-03-11 14:45:43 -07007"""
8Script to generate a linker script organizing application memory partitions
9
10Applications may declare build-time memory domain partitions with
11K_APPMEM_PARTITION_DEFINE, and assign globals to them using K_APP_DMEM
12or K_APP_BMEM macros. For each of these partitions, we need to
13route all their data into appropriately-sized memory areas which meet the
14size/alignment constraints of the memory protection hardware.
15
16This linker script is created very early in the build process, before
17the build attempts to link the kernel binary, as the linker script this
18tool generates is a necessary pre-condition for kernel linking. We extract
19the set of memory partitions to generate by looking for variables which
20have been assigned to input sections that follow a defined naming convention.
21We also allow entire libraries to be pulled in to assign their globals
22to a particular memory partition via command line directives.
23
24This script takes as inputs:
25
26- The base directory to look for compiled objects
27- key/value pairs mapping static library files to what partitions their globals
28 should end up in.
29
30The output is a linker script fragment containing the definition of the
31app shared memory section, which is further divided, for each partition
32found, into data and BSS for each partition.
33"""
34
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053035import sys
36import argparse
Torsten Rasmussenf643b8b2021-11-24 15:35:47 +010037import json
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053038import os
39import re
Daniel Leung212ec9a2019-03-10 14:20:21 -070040from collections import OrderedDict
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053041from elftools.elf.elffile import ELFFile
Daniel Leung212ec9a2019-03-10 14:20:21 -070042from elftools.elf.sections import SymbolTableSection
Anas Nashif2c5a37c2021-11-22 16:09:31 -050043import elftools.common.exceptions
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053044
Daniel Leung212ec9a2019-03-10 14:20:21 -070045SZ = 'size'
46SRC = 'sources'
47LIB = 'libraries'
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053048
Andrew Boie7adff462019-01-30 13:44:54 -080049# This script will create sections and linker variables to place the
50# application shared memory partitions.
51# these are later read by the macros defined in app_memdomain.h for
Andrew Boie4ce652e2019-02-22 16:08:44 -080052# initialization purpose when USERSPACE is enabled.
Andrew Boie686bd912019-02-01 11:52:20 -080053data_template = """
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053054 /* Auto generated code do not modify */
Andrew Boief084c382019-03-04 17:57:06 -080055 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
56 z_data_smem_{0}_part_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030057 KEEP(*(data_smem_{0}_data*))
Andrew Boie686bd912019-02-01 11:52:20 -080058"""
59
60library_data_template = """
Jim Shu46eb3e52021-09-28 10:03:21 +080061 *{0}:*(.data .data.* .sdata .sdata.*)
Andrew Boie686bd912019-02-01 11:52:20 -080062"""
63
64bss_template = """
Andrew Boief084c382019-03-04 17:57:06 -080065 z_data_smem_{0}_bss_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030066 KEEP(*(data_smem_{0}_bss*))
Andrew Boie686bd912019-02-01 11:52:20 -080067"""
68
69library_bss_template = """
Jim Shu46eb3e52021-09-28 10:03:21 +080070 *{0}:*(.bss .bss.* .sbss .sbss.* COMMON COMMON.*)
Andrew Boie686bd912019-02-01 11:52:20 -080071"""
72
73footer_template = """
Andrew Boief084c382019-03-04 17:57:06 -080074 z_data_smem_{0}_bss_end = .;
75 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
76 z_data_smem_{0}_part_end = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053077"""
Andrew Boie686bd912019-02-01 11:52:20 -080078
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053079linker_start_seq = """
Daniel Leung2117a2a2021-07-12 13:33:32 -070080 SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
81 {{
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053082 APP_SHARED_ALIGN;
Daniel Leung2117a2a2021-07-12 13:33:32 -070083 _app_smem{0}_start = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053084"""
85
86linker_end_seq = """
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053087 APP_SHARED_ALIGN;
Daniel Leung2117a2a2021-07-12 13:33:32 -070088 _app_smem{0}_end = .;
89 }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
90"""
91
92empty_app_smem = """
93 SECTION_PROLOGUE(_APP_SMEM{1}_SECTION_NAME,,)
94 {{
Jaxson Hanf079e662021-08-31 14:14:03 +080095#ifdef EMPTY_APP_SHARED_ALIGN
96 EMPTY_APP_SHARED_ALIGN;
97#endif
Daniel Leung2117a2a2021-07-12 13:33:32 -070098 _app_smem{0}_start = .;
99 _app_smem{0}_end = .;
100 }} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
Adithya Baglodyae92f2b2018-09-19 11:20:09 +0530101"""
102
103size_cal_string = """
Andrew Boief084c382019-03-04 17:57:06 -0800104 z_data_smem_{0}_part_size = z_data_smem_{0}_part_end - z_data_smem_{0}_part_start;
105 z_data_smem_{0}_bss_size = z_data_smem_{0}_bss_end - z_data_smem_{0}_bss_start;
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530106"""
107
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +0300108section_regex = re.compile(r'data_smem_([A-Za-z0-9_]*)_(data|bss)*')
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530109
Daniel Leung212ec9a2019-03-10 14:20:21 -0700110elf_part_size_regex = re.compile(r'z_data_smem_(.*)_part_size')
111
112def find_obj_file_partitions(filename, partitions):
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530113 with open(filename, 'rb') as f:
Anas Nashif2c5a37c2021-11-22 16:09:31 -0500114 try:
115 full_lib = ELFFile(f)
116 except elftools.common.exceptions.ELFError as e:
117 exit(f"Error: {filename}: {e}")
118
Ulf Magnussonba312fe2019-03-20 19:30:29 +0100119 if not full_lib:
Ulf Magnussone9c1d6d2019-03-20 22:40:22 +0100120 sys.exit("Error parsing file: " + filename)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530121
Andrew Boie7adff462019-01-30 13:44:54 -0800122 sections = [x for x in full_lib.iter_sections()]
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530123 for section in sections:
Andrew Boie7adff462019-01-30 13:44:54 -0800124 m = section_regex.match(section.name)
125 if not m:
126 continue
Andrew Boie686bd912019-02-01 11:52:20 -0800127
Andrew Boie7adff462019-01-30 13:44:54 -0800128 partition_name = m.groups()[0]
Andrew Boie686bd912019-02-01 11:52:20 -0800129 if partition_name not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700130 partitions[partition_name] = {SZ: section.header.sh_size}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530131
Daniel Leung212ec9a2019-03-10 14:20:21 -0700132 if args.verbose:
133 partitions[partition_name][SRC] = filename
134
135 else:
136 partitions[partition_name][SZ] += section.header.sh_size
137
138
139 return partitions
140
141
142def parse_obj_files(partitions):
143 # Iterate over all object files to find partitions
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100144 for dirpath, _, files in os.walk(args.directory):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700145 for filename in files:
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200146 if re.match(r".*\.obj$", filename):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700147 fullname = os.path.join(dirpath, filename)
Anas Nashif2c5a37c2021-11-22 16:09:31 -0500148 fsize = os.path.getsize(fullname)
149 if fsize != 0:
150 find_obj_file_partitions(fullname, partitions)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700151
152
Torsten Rasmussenf643b8b2021-11-24 15:35:47 +0100153def parse_compile_command_file(partitions):
154 # Iterate over all entries to find object files.
155 # Thereafter process each object file to find partitions
156 object_pattern = re.compile(r'-o\s+(\S*)')
157 with open(args.compile_commands_file, 'rb') as f:
158 commands = json.load(f)
159 for command in commands:
160 build_dir = command.get('directory')
161 compile_command = command.get('command')
162 compile_arg = object_pattern.search(compile_command)
163 obj_file = None if compile_arg is None else compile_arg.group(1)
164 if obj_file:
165 fullname = os.path.join(build_dir, obj_file)
166 # Because of issue #40635, then not all objects referenced by
167 # the compile_commands.json file may be available, therefore
168 # only include existing files.
169 if os.path.exists(fullname):
170 find_obj_file_partitions(fullname, partitions)
171
172
Daniel Leung212ec9a2019-03-10 14:20:21 -0700173def parse_elf_file(partitions):
174 with open(args.elf, 'rb') as f:
Anas Nashif2c5a37c2021-11-22 16:09:31 -0500175 try:
176 elffile = ELFFile(f)
177 except elftools.common.exceptions.ELFError as e:
178 exit(f"Error: {args.elf}: {e}")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700179
180 symbol_tbls = [s for s in elffile.iter_sections()
181 if isinstance(s, SymbolTableSection)]
182
183 for section in symbol_tbls:
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100184 for symbol in section.iter_symbols():
Daniel Leung212ec9a2019-03-10 14:20:21 -0700185 if symbol['st_shndx'] != "SHN_ABS":
186 continue
187
188 x = elf_part_size_regex.match(symbol.name)
189 if not x:
190 continue
191
192 partition_name = x.groups()[0]
193 size = symbol['st_value']
194 if partition_name not in partitions:
195 partitions[partition_name] = {SZ: size}
196
197 if args.verbose:
198 partitions[partition_name][SRC] = args.elf
199
200 else:
201 partitions[partition_name][SZ] += size
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530202
Andrew Boie686bd912019-02-01 11:52:20 -0800203
Daniel Leung2117a2a2021-07-12 13:33:32 -0700204def generate_final_linker(linker_file, partitions, lnkr_sect=""):
205 string = ""
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530206
Daniel Leung2117a2a2021-07-12 13:33:32 -0700207 if len(partitions) > 0:
208 string = linker_start_seq.format(lnkr_sect, lnkr_sect.upper())
209 size_string = ''
210 for partition, item in partitions.items():
211 string += data_template.format(partition)
212 if LIB in item:
213 for lib in item[LIB]:
214 string += library_data_template.format(lib)
215 string += bss_template.format(partition, lnkr_sect)
216 if LIB in item:
217 for lib in item[LIB]:
218 string += library_bss_template.format(lib)
219 string += footer_template.format(partition)
220 size_string += size_cal_string.format(partition)
221
222 string += linker_end_seq.format(lnkr_sect)
223 string += size_string
224 else:
225 string = empty_app_smem.format(lnkr_sect, lnkr_sect.upper())
226
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530227 with open(linker_file, "w") as fw:
228 fw.write(string)
229
230
231def parse_args():
232 global args
233 parser = argparse.ArgumentParser(
234 description=__doc__,
235 formatter_class=argparse.RawDescriptionHelpFormatter)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700236 parser.add_argument("-d", "--directory", required=False, default=None,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530237 help="Root build directory")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700238 parser.add_argument("-e", "--elf", required=False, default=None,
239 help="ELF file")
Torsten Rasmussenf643b8b2021-11-24 15:35:47 +0100240 parser.add_argument("-f", "--compile-commands-file", required=False,
241 default=None, help="CMake compile commands file")
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530242 parser.add_argument("-o", "--output", required=False,
243 help="Output ld file")
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200244 parser.add_argument("-v", "--verbose", action="count", default=0,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530245 help="Verbose Output")
Andrew Boie686bd912019-02-01 11:52:20 -0800246 parser.add_argument("-l", "--library", nargs=2, action="append", default=[],
247 metavar=("LIBRARY", "PARTITION"),
248 help="Include globals for a particular library or object filename into a designated partition")
Daniel Leung2117a2a2021-07-12 13:33:32 -0700249 parser.add_argument("--pinoutput", required=False,
250 help="Output ld file for pinned sections")
251 parser.add_argument("--pinpartitions", action="store", required=False, default="",
252 help="Comma separated names of partitions to be pinned in physical memory")
Andrew Boie686bd912019-02-01 11:52:20 -0800253
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530254 args = parser.parse_args()
255
256
257def main():
258 parse_args()
Andrew Boie686bd912019-02-01 11:52:20 -0800259 partitions = {}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530260
Daniel Leung212ec9a2019-03-10 14:20:21 -0700261 if args.directory is not None:
262 parse_obj_files(partitions)
Torsten Rasmussenf643b8b2021-11-24 15:35:47 +0100263 if args.compile_commands_file is not None:
264 parse_compile_command_file(partitions)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700265 elif args.elf is not None:
266 parse_elf_file(partitions)
267 else:
268 return
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530269
Andrew Boie686bd912019-02-01 11:52:20 -0800270 for lib, ptn in args.library:
271 if ptn not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700272 partitions[ptn] = {}
Andrew Boie686bd912019-02-01 11:52:20 -0800273
Daniel Leung212ec9a2019-03-10 14:20:21 -0700274 if LIB not in partitions[ptn]:
275 partitions[ptn][LIB] = [lib]
276 else:
277 partitions[ptn][LIB].append(lib)
278
Daniel Leung2117a2a2021-07-12 13:33:32 -0700279 if args.pinoutput:
280 pin_part_names = args.pinpartitions.split(',')
281
282 generic_partitions = {key: value for key, value in partitions.items()
283 if key not in pin_part_names}
284 pinned_partitions = {key: value for key, value in partitions.items()
285 if key in pin_part_names}
286 else:
287 generic_partitions = partitions
Marc Herberteefea9d2019-06-27 16:09:26 -0700288
289 # Sample partitions.items() list before sorting:
290 # [ ('part1', {'size': 64}), ('part3', {'size': 64}, ...
291 # ('part0', {'size': 334}) ]
Daniel Leung2117a2a2021-07-12 13:33:32 -0700292 decreasing_tuples = sorted(generic_partitions.items(),
Marc Herberteefea9d2019-06-27 16:09:26 -0700293 key=lambda x: (x[1][SZ], x[0]), reverse=True)
294
295 partsorted = OrderedDict(decreasing_tuples)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700296
297 generate_final_linker(args.output, partsorted)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530298 if args.verbose:
Andrew Boie7adff462019-01-30 13:44:54 -0800299 print("Partitions retrieved:")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700300 for key in partsorted:
301 print(" {0}: size {1}: {2}".format(key,
302 partsorted[key][SZ],
303 partsorted[key][SRC]))
304
Daniel Leung2117a2a2021-07-12 13:33:32 -0700305 if args.pinoutput:
306 decreasing_tuples = sorted(pinned_partitions.items(),
307 key=lambda x: (x[1][SZ], x[0]), reverse=True)
308
309 partsorted = OrderedDict(decreasing_tuples)
310
311 generate_final_linker(args.pinoutput, partsorted, lnkr_sect="_pinned")
312 if args.verbose:
313 print("Pinned partitions retrieved:")
314 for key in partsorted:
315 print(" {0}: size {1}: {2}".format(key,
316 partsorted[key][SZ],
317 partsorted[key][SRC]))
318
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530319
320if __name__ == '__main__':
321 main()