blob: 7639cb6afdf519ca96031349e0d4d28db1a9e5bb [file] [log] [blame]
xiaohu.huangffae1712022-11-01 18:04:01 +08001#!/usr/bin/python3
2#coding:utf-8
3#
4# Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
5#
6# SPDX-License-Identifier: MIT
7#
8
9
10from __future__ import print_function
11
12import sys
13import os
14import argparse
15
16parser = argparse.ArgumentParser(description='total size of each object file in an ld linker map.')
17parser.add_argument('map_file', help="A map file generated by passing -M/--print-map to ld during linking.")
18parser.add_argument('--combine', action='store_true',
19 help="All object files in an .a archive or in a directory are combined")
20args = parser.parse_args()
21
xiaohu.huang1f337742023-04-20 17:06:31 +080022class SectionSize:
xiaohu.huangffae1712022-11-01 18:04:01 +080023 text = 0
24 rela_text = 0
25 data = 0 # Including metadata like import tables
26 bss = 0
27 customize = 0
xiaohu.huang1f337742023-04-20 17:06:31 +080028 system_heap = 0
29 system_stack = 0
xiaohu.huang0fb34ef2024-04-19 17:05:08 +080030 rodata = 0
31 rom_usage = 0
32 ram_usage = 0
33
xiaohu.huangffae1712022-11-01 18:04:01 +080034 def total(self):
35 return self.text + self.data + self.bss
xiaohu.huang0fb34ef2024-04-19 17:05:08 +080036
37 def add_text_with_rodata(self, section, size):
38 if section.startswith('.text') or section.startswith('.rodata'):
xiaohu.huangffae1712022-11-01 18:04:01 +080039 self.text += size
xiaohu.huang0fb34ef2024-04-19 17:05:08 +080040 #add the .rodata to data in order to match the result of size command with gcc's elf file
41 #the elf file generate by riscv then toolchain add the .rodata to .text
42 if section.startswith('.rodata'):
43 self.rodata += size
xiaohu.huangffae1712022-11-01 18:04:01 +080044 elif section.startswith('.rela.dyn'):
45 self.rela_text += size
46 elif section.startswith('.bss') or section.startswith('.common') or section.startswith('.sbss'):
47 self.bss += size
xiaohu.huang0fb34ef2024-04-19 17:05:08 +080048 elif section.startswith('.data'):
xiaohu.huangffae1712022-11-01 18:04:01 +080049 self.data += size
50 elif section.startswith('.heap'):
xiaohu.huang1f337742023-04-20 17:06:31 +080051 SectionSize.system_heap += size
xiaohu.huangffae1712022-11-01 18:04:01 +080052 elif section.startswith('.stack'):
xiaohu.huang1f337742023-04-20 17:06:31 +080053 SectionSize.system_stack += size
xiaohu.huangffae1712022-11-01 18:04:01 +080054 else:
55 if (size > 0):
56 print("customer section:%s, size:%d" % (section, size))
57 self.customize += size
xiaohu.huang0fb34ef2024-04-19 17:05:08 +080058 self.rom_usage = (self.text + self.data)
59 self.ram_usage = (self.data + self.bss)
60
61 def add_data_with_rodata(self, section, size):
62 #arch is arm64 and arm32
63 if section.startswith('.text'):
64 self.text += size
65 elif section.startswith('.rela.dyn'):
66 self.rela_text += size
67 elif section.startswith('.bss') or section.startswith('.common') or section.startswith('.sbss'):
68 self.bss += size
69 elif section.startswith('.data') or section.startswith('.rodata'):
70 #add the .rodata to data in order to match the result of size command with gcc's elf file
71 #the elf file generate by arm toolchain then it add the .rodata to .data
72 self.data += size
73 if section.startswith('.rodata'):
74 self.rodata += size
75 elif section.startswith('.heap'):
76 SectionSize.system_heap += size
77 elif section.startswith('.stack'):
78 SectionSize.system_stack += size
79 else:
80 if (size > 0):
81 print("customer section:%s, size:%d" % (section, size))
82 self.customize += size
83 self.rom_usage = (self.text + self.data)
84 self.ram_usage = (self.data + self.bss - self.rodata)
85
86 def add_gcc_section(self, section, size):
87 if current_section is None:
88 return;
89 if section.startswith('.comment'):
90 return
91 if section.startswith('.debug'):
92 return
93 if section.startswith('.ARM.attributes'):
94 return
95
96 if os.getenv('ARCH') == "riscv":
97 self.add_text_with_rodata(section, size)
98 else:
99 self.add_data_with_rodata(section, size)
100
xiaohu.huange6c31672022-12-05 10:10:42 +0800101 def add_xcc_section(self, section, size):
xiaohu.huangfc139972024-01-23 10:36:50 +0800102 if current_section is None:
103 return;
xiaohu.huange6c31672022-12-05 10:10:42 +0800104 if section.startswith('.comment'):
105 return
106 if section.startswith('.debug'):
107 return
108 if section.startswith('.xt.prop')or section.startswith('.xt.lit'):
109 return
110 if section.startswith('.text') or section.endswith('.text') \
111 or section.startswith('.literal') or section.endswith('.literal') \
112 or section.startswith('.rodata') or section.endswith('.rodata'):
xiaohu.huang0fb34ef2024-04-19 17:05:08 +0800113 #add the .rodata to text in order to match the result of size command with xcc's elf file
xiaohu.huange6c31672022-12-05 10:10:42 +0800114 self.text += size
xiaohu.huang0fb34ef2024-04-19 17:05:08 +0800115 if section.startswith('.rodata') or section.endswith('.rodata'):
116 self.rodata += size
xiaohu.huange6c31672022-12-05 10:10:42 +0800117 elif section.startswith('.rela.dyn'):
118 self.rela_text += size
119 elif section.startswith('.bss') or section.startswith('.common') or section.startswith('.sbss'):
120 self.bss += size
121 elif section.startswith('.data') or section.endswith('.data'):
122 self.data += size
123 elif section.startswith('.heap'):
124 self.heap += size
125 self.bss += size
126 elif section.startswith('.stack'):
127 self.stack += size
128 self.bss += size
129 else:
130 if (size > 0):
131 print("customer section:%s, size:%d" % (section, size))
132 self.customize += size
xiaohu.huang0fb34ef2024-04-19 17:05:08 +0800133 self.rom_usage = (self.text + self.data)
134 self.ram_usage = (self.data + self.bss)
135
136def print_codesize_module_text_with_rodata():
137 print('---------------------------------------------------------------------------------------------------')
138 col_format = "%-20s\t%-12s\t%-12s\t%-10s%-10s\t%-12s\t%-12s\t%-7s"
139 print(col_format % ("module file", "ROM(text+data)", "RAM(data+bss)", ".text", "(.rodata)", ".data", ".bss", "customize"))
140 col_format = "%-20s\t%-12s\t%-12s\t%-10s(%-10s)\t%-12s\t%-12s\t%-7s"
141 for source in sources:
142 size = size_by_source[source]
143 print(col_format % (os.path.basename(source)[:20], size.rom_usage, size.ram_usage, size.text, size.rodata, size.data, size.bss, size.customize))
144 print('---------------------------------------------------------------------------------------------------')
145
146def print_codesize_module_data_with_rodata():
147 print('---------------------------------------------------------------------------------------------------')
148 col_format = "%-20s\t%-12s\t%-12s\t%-7s\t%-10s%-10s\t%-12s\t%-7s"
149 print(col_format % ("module file", "ROM(text+data)", "RAM(data+bss)", ".text", ".data", "(.rodata)", ".bss", "customize"))
150 col_format = "%-20s\t%-12s\t%-12s\t%-7s\t%-10s(%-10s)\t%-12s\t%-7s"
151 for source in sources:
152 size = size_by_source[source]
153 print(col_format % (os.path.basename(source)[:20], size.rom_usage, size.ram_usage, size.text, size.data, size.rodata, size.bss, size.customize))
154 print('---------------------------------------------------------------------------------------------------')
155
156def print_codesize_summary_text_with_rodata():
157 global sumrom
158 global sumram
159 global sumcode
160 global sumdata
161 global sumbss
162 global sumcustomize
163 global sumrodata
164 global sys_mem_usage
165
166 for source in sources:
167 size = size_by_source[source]
168 sumcode += size.text
169 sumdata += size.data
170 sumbss += size.bss
171 sumrodata += size.rodata
172 sumrom += size.rom_usage
173 sumram += size.ram_usage
174 sumcustomize += size.customize
175
176 print('---------------------------------------------------------------------------------------------------')
177 col_format = "%-5s\t%-12s\t%-12s\t%-12s%-12s\t%-12s\t%-12s\t%-7s\t%-7s\t%-7s"
178 print(col_format % (" ", "ROM(text+data)", "RAM(data+bss)", ".text", "(.rodata)", ".data", ".bss", "cust", "stack", "heap" ))
179 col_format = "%-5s\t%-12s\t%-12s\t%-12s(%-12s)\t%-12s\t%-12s\t%-7s\t%-7s\t%-7s"
180 print(col_format % ("total", sumrom, sumram + sys_mem_usage, sumcode, sumrodata, sumdata, sumbss + sys_mem_usage, sumcustomize, SectionSize.system_stack, SectionSize.system_heap))
181 print('---------------------------------------------------------------------------------------------------')
182
183def print_codesize_summary_data_with_rodata():
184 global sumrom
185 global sumram
186 global sumcode
187 global sumdata
188 global sumbss
189 global sumcustomize
190 global sumrodata
191 global sys_mem_usage
192
193 for source in sources:
194 size = size_by_source[source]
195 sumcode += size.text
196 sumdata += size.data
197 sumbss += size.bss
198 sumrodata += size.rodata
199 sumrom += size.rom_usage
200 sumram += size.ram_usage
201 sumcustomize += size.customize
202
203 print('---------------------------------------------------------------------------------------------------')
204 col_format = "%-5s\t%-12s\t%-12s\t%-7s\t%-12s%-12s\t%-12s\t%-7s\t%-7s\t%-7s"
205 print(col_format % (" ", "ROM(text+data)", "RAM(data+bss)", ".text", ".data", "(.rodata)", ".bss", "cust", "stack", "heap" ))
206 col_format = "%-5s\t%-12s\t%-12s\t%-7s\t%-12s(%-12s)\t%-12s\t%-7s\t%-7s\t%-7s"
207 print(col_format % ("total", sumrom, sumram + sys_mem_usage, sumcode, sumdata, sumrodata, sumbss + sys_mem_usage, sumcustomize, SectionSize.system_stack, SectionSize.system_heap))
208 print('---------------------------------------------------------------------------------------------------')
xiaohu.huangffae1712022-11-01 18:04:01 +0800209
210size_by_source = {}
xiaohu.huangffae1712022-11-01 18:04:01 +0800211with open(args.map_file) as f:
xiaohu.huang29fd84c2022-12-19 15:27:00 +0800212 if os.getenv('COMPILER') == "xcc":
xiaohu.huange6c31672022-12-05 10:10:42 +0800213 arch_toolchain = "XCC"
214 toolchain_keyword = "xtensa-elf"
215 is_xtensa = 1
216 else:
217 arch_toolchain = "GCC"
218 toolchain_keyword = "toolchains"
219 is_xtensa = 0
220 print("%s toolchain map analyzer" % arch_toolchain)
221
xiaohu.huangffae1712022-11-01 18:04:01 +0800222 lines = iter(f)
223 for line in lines:
224 if line.strip() == "Linker script and memory map":
225 break
226
227 current_section = None
228 split_line = None
229 last_addr = 0
230 last_size = 0
231 for line in lines:
232 line = line.strip('\n')
233 if split_line:
234 # Glue a line that was split in two back together
235 if line.startswith(' ' * 16):
236 line = split_line + line
237 else: # Shouldn't happen
238 print("Warning: discarding line ", split_line)
239 split_line = None
240
241 if ('size before relaxing' in line):
242 continue
243 if line.startswith((".", " .", " *fill*")):
244 pieces = line.split(None, 3) # Don't split paths containing spaces
xiaohu.huang1f337742023-04-20 17:06:31 +0800245 pieces_num = len(pieces)
xiaohu.huangffae1712022-11-01 18:04:01 +0800246
247 if line.startswith("."):
248 # Note: this line might be wrapped, with the size of the section
249 # on the next line, but we ignore the size anyway and will ignore that line
250 current_section = pieces[0]
xiaohu.huange6c31672022-12-05 10:10:42 +0800251 # XCC text section format
xiaohu.huang1f337742023-04-20 17:06:31 +0800252 if (pieces_num == 4):
xiaohu.huange6c31672022-12-05 10:10:42 +0800253 source = pieces[-1]
xiaohu.huang1f337742023-04-20 17:06:31 +0800254 elif pieces_num == 1 and len(line) > 14:
xiaohu.huangffae1712022-11-01 18:04:01 +0800255 # ld splits the rest of this line onto the next if the section name is too long
256 split_line = line
xiaohu.huang1f337742023-04-20 17:06:31 +0800257 elif pieces_num >= 3 and "=" not in pieces and "before" not in pieces:
xiaohu.huangffae1712022-11-01 18:04:01 +0800258 if pieces[0] == "*fill*":
259 # fill use the last source to store the fill align data
260 #source = pieces[0]
261 size = int(pieces[-1], 16)
262 if (pieces[-2] == last_addr):
263 # sub the merged size from the same address for fill data
264 size = size - last_size
265 else:
266 last_size = size
267 last_addr = pieces[-2]
268 else:
269 source = pieces[-1]
270 size = int(pieces[-2], 16)
271 if (pieces[-3] == last_addr):
272 # sub the merged size from the same address for text data
273 size = size - last_size
274 else:
275 last_size = size
276 last_addr = pieces[-3]
277
278 if args.combine:
279 if '.a(' in source:
280 # path/to/archive.a(object.o)
281 source = source[:source.index('.a(') + 2]
282 elif '.dir' in source:
283 source = source[:source.find(".dir")]
284 elif source.endswith('.o'):
xiaohu.huange6c31672022-12-05 10:10:42 +0800285 if toolchain_keyword in source:
xiaohu.huangffae1712022-11-01 18:04:01 +0800286 source = 'toolchain_obj'
287 else:
288 source = os.path.basename(source)
289
290 if source not in size_by_source:
291 size_by_source[source] = SectionSize()
xiaohu.huange6c31672022-12-05 10:10:42 +0800292 if is_xtensa == 1:
293 size_by_source[source].add_xcc_section(current_section, size)
294 else:
295 size_by_source[source].add_gcc_section(current_section, size)
xiaohu.huangffae1712022-11-01 18:04:01 +0800296
xiaohu.huangffae1712022-11-01 18:04:01 +0800297sources = list(size_by_source.keys())
298sources.sort(key = lambda x: size_by_source[x].total())
xiaohu.huang0fb34ef2024-04-19 17:05:08 +0800299sumrom = sumram = sumcode = sumdata = sumbss = sumcustomize = sumrodata = 0
xiaohu.huang1f337742023-04-20 17:06:31 +0800300sys_mem_usage = SectionSize.system_stack + SectionSize.system_heap
xiaohu.huang0fb34ef2024-04-19 17:05:08 +0800301if os.getenv('COMPILER') == "xcc":
302 print_codesize_module_text_with_rodata()
303 print_codesize_summary_text_with_rodata()
304else:
305 if os.getenv('ARCH') == "riscv":
306 print_codesize_module_text_with_rodata()
307 print_codesize_summary_text_with_rodata()
308 else:
309 print_codesize_module_data_with_rodata()
310 print_codesize_summary_data_with_rodata()