blob: 38758f1a4592f0e1592ee541f841dad47cc064ff [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
37import os
38import re
Daniel Leung212ec9a2019-03-10 14:20:21 -070039from collections import OrderedDict
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053040from elftools.elf.elffile import ELFFile
Daniel Leung212ec9a2019-03-10 14:20:21 -070041from elftools.elf.sections import SymbolTableSection
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053042
Daniel Leung212ec9a2019-03-10 14:20:21 -070043SZ = 'size'
44SRC = 'sources'
45LIB = 'libraries'
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053046
Andrew Boie7adff462019-01-30 13:44:54 -080047# This script will create sections and linker variables to place the
48# application shared memory partitions.
49# these are later read by the macros defined in app_memdomain.h for
Andrew Boie4ce652e2019-02-22 16:08:44 -080050# initialization purpose when USERSPACE is enabled.
Andrew Boie686bd912019-02-01 11:52:20 -080051data_template = """
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053052 /* Auto generated code do not modify */
Andrew Boief084c382019-03-04 17:57:06 -080053 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
54 z_data_smem_{0}_part_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030055 KEEP(*(data_smem_{0}_data*))
Andrew Boie686bd912019-02-01 11:52:20 -080056"""
57
58library_data_template = """
59 *{0}:*(.data .data.*)
60"""
61
62bss_template = """
Andrew Boief084c382019-03-04 17:57:06 -080063 z_data_smem_{0}_bss_start = .;
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030064 KEEP(*(data_smem_{0}_bss*))
Andrew Boie686bd912019-02-01 11:52:20 -080065"""
66
67library_bss_template = """
68 *{0}:*(.bss .bss.* COMMON COMMON.*)
69"""
70
71footer_template = """
Andrew Boief084c382019-03-04 17:57:06 -080072 z_data_smem_{0}_bss_end = .;
73 SMEM_PARTITION_ALIGN(z_data_smem_{0}_bss_end - z_data_smem_{0}_part_start);
74 z_data_smem_{0}_part_end = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053075"""
Andrew Boie686bd912019-02-01 11:52:20 -080076
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053077linker_start_seq = """
Kumar Gala4da0f8b2019-03-14 18:39:36 -050078 SECTION_PROLOGUE(_APP_SMEM_SECTION_NAME,,)
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053079 {
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053080 APP_SHARED_ALIGN;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053081 _app_smem_start = .;
82"""
83
84linker_end_seq = """
Adithya Baglody10c6a0c2018-09-21 10:17:58 +053085 APP_SHARED_ALIGN;
Andrew Boie7adff462019-01-30 13:44:54 -080086 _app_smem_end = .;
Adithya Baglodyae92f2b2018-09-19 11:20:09 +053087 } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
88"""
89
90size_cal_string = """
Andrew Boief084c382019-03-04 17:57:06 -080091 z_data_smem_{0}_part_size = z_data_smem_{0}_part_end - z_data_smem_{0}_part_start;
92 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 +053093"""
94
Eugeniy Paltsev0a7b65e2020-09-02 16:52:09 +030095section_regex = re.compile(r'data_smem_([A-Za-z0-9_]*)_(data|bss)*')
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +053096
Daniel Leung212ec9a2019-03-10 14:20:21 -070097elf_part_size_regex = re.compile(r'z_data_smem_(.*)_part_size')
98
99def find_obj_file_partitions(filename, partitions):
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530100 with open(filename, 'rb') as f:
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200101 full_lib = ELFFile(f)
Ulf Magnussonba312fe2019-03-20 19:30:29 +0100102 if not full_lib:
Ulf Magnussone9c1d6d2019-03-20 22:40:22 +0100103 sys.exit("Error parsing file: " + filename)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530104
Andrew Boie7adff462019-01-30 13:44:54 -0800105 sections = [x for x in full_lib.iter_sections()]
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530106 for section in sections:
Andrew Boie7adff462019-01-30 13:44:54 -0800107 m = section_regex.match(section.name)
108 if not m:
109 continue
Andrew Boie686bd912019-02-01 11:52:20 -0800110
Andrew Boie7adff462019-01-30 13:44:54 -0800111 partition_name = m.groups()[0]
Andrew Boie686bd912019-02-01 11:52:20 -0800112 if partition_name not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700113 partitions[partition_name] = {SZ: section.header.sh_size}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530114
Daniel Leung212ec9a2019-03-10 14:20:21 -0700115 if args.verbose:
116 partitions[partition_name][SRC] = filename
117
118 else:
119 partitions[partition_name][SZ] += section.header.sh_size
120
121
122 return partitions
123
124
125def parse_obj_files(partitions):
126 # Iterate over all object files to find partitions
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100127 for dirpath, _, files in os.walk(args.directory):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700128 for filename in files:
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200129 if re.match(r".*\.obj$", filename):
Daniel Leung212ec9a2019-03-10 14:20:21 -0700130 fullname = os.path.join(dirpath, filename)
131 find_obj_file_partitions(fullname, partitions)
132
133
134def parse_elf_file(partitions):
135 with open(args.elf, 'rb') as f:
136 elffile = ELFFile(f)
137
138 symbol_tbls = [s for s in elffile.iter_sections()
139 if isinstance(s, SymbolTableSection)]
140
141 for section in symbol_tbls:
Ulf Magnusson12ba9df2019-03-19 19:28:24 +0100142 for symbol in section.iter_symbols():
Daniel Leung212ec9a2019-03-10 14:20:21 -0700143 if symbol['st_shndx'] != "SHN_ABS":
144 continue
145
146 x = elf_part_size_regex.match(symbol.name)
147 if not x:
148 continue
149
150 partition_name = x.groups()[0]
151 size = symbol['st_value']
152 if partition_name not in partitions:
153 partitions[partition_name] = {SZ: size}
154
155 if args.verbose:
156 partitions[partition_name][SRC] = args.elf
157
158 else:
159 partitions[partition_name][SZ] += size
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530160
Andrew Boie686bd912019-02-01 11:52:20 -0800161
162def generate_final_linker(linker_file, partitions):
Adithya Baglodyae92f2b2018-09-19 11:20:09 +0530163 string = linker_start_seq
164 size_string = ''
Marc Herbert85bc0d22019-06-27 15:30:55 -0700165 for partition, item in partitions.items():
Andrew Boie686bd912019-02-01 11:52:20 -0800166 string += data_template.format(partition)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700167 if LIB in item:
168 for lib in item[LIB]:
169 string += library_data_template.format(lib)
Andrew Boie686bd912019-02-01 11:52:20 -0800170 string += bss_template.format(partition)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700171 if LIB in item:
172 for lib in item[LIB]:
173 string += library_bss_template.format(lib)
Andrew Boie686bd912019-02-01 11:52:20 -0800174 string += footer_template.format(partition)
Adithya Baglodyae92f2b2018-09-19 11:20:09 +0530175 size_string += size_cal_string.format(partition)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530176
Adithya Baglodyae92f2b2018-09-19 11:20:09 +0530177 string += linker_end_seq
178 string += size_string
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530179 with open(linker_file, "w") as fw:
180 fw.write(string)
181
182
183def parse_args():
184 global args
185 parser = argparse.ArgumentParser(
186 description=__doc__,
187 formatter_class=argparse.RawDescriptionHelpFormatter)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700188 parser.add_argument("-d", "--directory", required=False, default=None,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530189 help="Root build directory")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700190 parser.add_argument("-e", "--elf", required=False, default=None,
191 help="ELF file")
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530192 parser.add_argument("-o", "--output", required=False,
193 help="Output ld file")
Ulf Magnusson0d39a102019-09-06 11:13:19 +0200194 parser.add_argument("-v", "--verbose", action="count", default=0,
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530195 help="Verbose Output")
Andrew Boie686bd912019-02-01 11:52:20 -0800196 parser.add_argument("-l", "--library", nargs=2, action="append", default=[],
197 metavar=("LIBRARY", "PARTITION"),
198 help="Include globals for a particular library or object filename into a designated partition")
199
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530200 args = parser.parse_args()
201
202
203def main():
204 parse_args()
Andrew Boie686bd912019-02-01 11:52:20 -0800205 partitions = {}
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530206
Daniel Leung212ec9a2019-03-10 14:20:21 -0700207 if args.directory is not None:
208 parse_obj_files(partitions)
209 elif args.elf is not None:
210 parse_elf_file(partitions)
211 else:
212 return
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530213
Andrew Boie686bd912019-02-01 11:52:20 -0800214 for lib, ptn in args.library:
215 if ptn not in partitions:
Daniel Leung212ec9a2019-03-10 14:20:21 -0700216 partitions[ptn] = {}
Andrew Boie686bd912019-02-01 11:52:20 -0800217
Daniel Leung212ec9a2019-03-10 14:20:21 -0700218 if LIB not in partitions[ptn]:
219 partitions[ptn][LIB] = [lib]
220 else:
221 partitions[ptn][LIB].append(lib)
222
Marc Herberteefea9d2019-06-27 16:09:26 -0700223
224 # Sample partitions.items() list before sorting:
225 # [ ('part1', {'size': 64}), ('part3', {'size': 64}, ...
226 # ('part0', {'size': 334}) ]
227 decreasing_tuples = sorted(partitions.items(),
228 key=lambda x: (x[1][SZ], x[0]), reverse=True)
229
230 partsorted = OrderedDict(decreasing_tuples)
Daniel Leung212ec9a2019-03-10 14:20:21 -0700231
232 generate_final_linker(args.output, partsorted)
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530233 if args.verbose:
Andrew Boie7adff462019-01-30 13:44:54 -0800234 print("Partitions retrieved:")
Daniel Leung212ec9a2019-03-10 14:20:21 -0700235 for key in partsorted:
236 print(" {0}: size {1}: {2}".format(key,
237 partsorted[key][SZ],
238 partsorted[key][SRC]))
239
Adithya Baglodyc69fb0d2018-08-04 19:48:52 +0530240
241if __name__ == '__main__':
242 main()