blob: 7b2841f6688da749d6064272d0cb56977635edf8 [file] [log] [blame]
Kevin O'Connor202024a2009-01-17 10:41:28 -05001#!/usr/bin/env python
2# Script to arrange sections to ensure fixed offsets.
3#
4# Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
5#
6# This file may be distributed under the terms of the GNU GPLv3 license.
7
8import sys
9
Kevin O'Connor711ddc62009-01-17 15:17:34 -050010
11def alignpos(pos, alignbytes):
12 mask = alignbytes - 1
13 return (pos + mask) & ~mask
14
Kevin O'Connorc0693942009-06-10 21:56:01 -040015
16######################################################################
17# 16bit fixed address section fitting
18######################################################################
19
Kevin O'Connordb802ad2009-01-17 19:35:10 -050020MAXPOS = 0x10000
21
Kevin O'Connorc0693942009-06-10 21:56:01 -040022def doLayout16(sections, outname):
Kevin O'Connor202024a2009-01-17 10:41:28 -050023 textsections = []
24 rodatasections = []
25 datasections = []
Kevin O'Connor711ddc62009-01-17 15:17:34 -050026 # fixedsections = [(addr, sectioninfo, extasectionslist), ...]
27 fixedsections = []
28 # canrelocate = [(sectioninfo, list), ...]
29 canrelocate = []
Kevin O'Connor202024a2009-01-17 10:41:28 -050030
31 # Find desired sections.
32 for section in sections:
Kevin O'Connor711ddc62009-01-17 15:17:34 -050033 size, align, name = section
Kevin O'Connor202024a2009-01-17 10:41:28 -050034 if name[:11] == '.fixedaddr.':
35 addr = int(name[11:], 16)
Kevin O'Connor711ddc62009-01-17 15:17:34 -050036 fixedsections.append((addr, section, []))
37 if align != 1:
38 print "Error: Fixed section %s has non-zero alignment (%d)" % (
39 name, align)
40 sys.exit(1)
Kevin O'Connor202024a2009-01-17 10:41:28 -050041 if name[:6] == '.text.':
42 textsections.append(section)
Kevin O'Connor711ddc62009-01-17 15:17:34 -050043 canrelocate.append((section, textsections))
Kevin O'Connor202024a2009-01-17 10:41:28 -050044 if name[:17] == '.rodata.__func__.' or name == '.rodata.str1.1':
45 rodatasections.append(section)
Kevin O'Connor711ddc62009-01-17 15:17:34 -050046 #canrelocate.append((section, rodatasections))
Kevin O'Connor202024a2009-01-17 10:41:28 -050047 if name[:8] == '.data16.':
48 datasections.append(section)
Kevin O'Connor711ddc62009-01-17 15:17:34 -050049 #canrelocate.append((section, datasections))
50
51 # Find freespace in fixed address area
52 fixedsections.sort()
53 # fixedAddr = [(freespace, sectioninfo), ...]
54 fixedAddr = []
55 for i in range(len(fixedsections)):
56 fixedsectioninfo = fixedsections[i]
57 addr, section, extrasectionslist = fixedsectioninfo
58 if i == len(fixedsections) - 1:
Kevin O'Connordb802ad2009-01-17 19:35:10 -050059 nextaddr = MAXPOS
Kevin O'Connor711ddc62009-01-17 15:17:34 -050060 else:
61 nextaddr = fixedsections[i+1][0]
62 avail = nextaddr - addr - section[0]
63 fixedAddr.append((avail, fixedsectioninfo))
64
65 # Attempt to fit other sections into fixed area
66 fixedAddr.sort()
67 canrelocate.sort()
Kevin O'Connor76f0bed2009-01-19 13:00:42 -050068 totalused = 0
Kevin O'Connor711ddc62009-01-17 15:17:34 -050069 for freespace, fixedsectioninfo in fixedAddr:
70 fixedaddr, fixedsection, extrasections = fixedsectioninfo
71 addpos = fixedaddr + fixedsection[0]
Kevin O'Connor76f0bed2009-01-19 13:00:42 -050072 totalused += fixedsection[0]
Kevin O'Connor711ddc62009-01-17 15:17:34 -050073 nextfixedaddr = addpos + freespace
74# print "Filling section %x uses %d, next=%x, available=%d" % (
75# fixedaddr, fixedsection[0], nextfixedaddr, freespace)
76 while 1:
77 canfit = None
78 for fixedaddrinfo in canrelocate:
79 fitsection, inlist = fixedaddrinfo
Kevin O'Connordb802ad2009-01-17 19:35:10 -050080 fitsize, fitalign, fitname = fitsection
81 if addpos + fitsize > nextfixedaddr:
82 # Can't fit and nothing else will fit.
Kevin O'Connor711ddc62009-01-17 15:17:34 -050083 break
Kevin O'Connordb802ad2009-01-17 19:35:10 -050084 fitnextaddr = alignpos(addpos, fitalign) + fitsize
85# print "Test %s - %x vs %x" % (
86# fitname, fitnextaddr, nextfixedaddr)
87 if fitnextaddr > nextfixedaddr:
88 # This item can't fit.
89 continue
Kevin O'Connor711ddc62009-01-17 15:17:34 -050090 canfit = (fitnextaddr, fixedaddrinfo)
91 if canfit is None:
92 break
93 # Found a section that can fit.
94 fitnextaddr, fixedaddrinfo = canfit
95 canrelocate.remove(fixedaddrinfo)
96 fitsection, inlist = fixedaddrinfo
97 inlist.remove(fitsection)
98 extrasections.append(fitsection)
99 addpos = fitnextaddr
Kevin O'Connor76f0bed2009-01-19 13:00:42 -0500100 totalused += fitsection[0]
101# print " Adding %s (size %d align %d) pos=%x avail=%d" % (
102# fitsection[2], fitsection[0], fitsection[1]
103# , fitnextaddr, nextfixedaddr - fitnextaddr)
Kevin O'Connordb802ad2009-01-17 19:35:10 -0500104 firstfixed = fixedsections[0][0]
Kevin O'Connorb1a0d3a2009-05-23 17:49:44 -0400105
106 # Find overall start position
107 restalign = 0
108 restspace = 0
109 restsections = []
110 for section in textsections + rodatasections + datasections:
111 size, align, name = section
112 if align > restalign:
113 restalign = align
114 restspace = alignpos(restspace, align) + size
115 restsections.append(section)
116 startrest = (firstfixed - restspace) / restalign * restalign
117
118 # Report stats
Kevin O'Connordb802ad2009-01-17 19:35:10 -0500119 total = MAXPOS-firstfixed
Kevin O'Connorb1a0d3a2009-05-23 17:49:44 -0400120 slack = total - totalused
121 print ("Fixed space: 0x%x-0x%x total: %d slack: %d"
122 " Percent slack: %.1f%%" % (
123 firstfixed, MAXPOS, total, slack,
124 (float(slack) / total) * 100.0))
125
126 # Write header
127 output = open(outname, 'wb')
128 output.write("""
129 .text16 0x%x : {
130 code16_start = ABSOLUTE(.) ;
131 freespace_end = . ;
132""" % startrest)
Kevin O'Connordb802ad2009-01-17 19:35:10 -0500133
Kevin O'Connor202024a2009-01-17 10:41:28 -0500134 # Write regular sections
Kevin O'Connorb1a0d3a2009-05-23 17:49:44 -0400135 for section in restsections:
Kevin O'Connor711ddc62009-01-17 15:17:34 -0500136 name = section[2]
Kevin O'Connorb1a0d3a2009-05-23 17:49:44 -0400137 if name == rodatasections[0][2]:
138 output.write("code16_rodata = . ;\n")
Kevin O'Connorc0693942009-06-10 21:56:01 -0400139 output.write("*(%s)\n" % (name,))
Kevin O'Connor202024a2009-01-17 10:41:28 -0500140
141 # Write fixed sections
Kevin O'Connor711ddc62009-01-17 15:17:34 -0500142 for addr, section, extrasections in fixedsections:
143 name = section[2]
144 output.write(". = ( 0x%x - code16_start ) ;\n" % (addr,))
Kevin O'Connor711ddc62009-01-17 15:17:34 -0500145 output.write("*(%s)\n" % (name,))
146 for extrasection in extrasections:
Kevin O'Connorc0693942009-06-10 21:56:01 -0400147 output.write("*(%s)\n" % (extrasection[2],))
Kevin O'Connorb1a0d3a2009-05-23 17:49:44 -0400148
149 # Write trailer
150 output.write("""
151 code16_end = ABSOLUTE(.) ;
152 }
153""")
154
Kevin O'Connor202024a2009-01-17 10:41:28 -0500155
Kevin O'Connorc0693942009-06-10 21:56:01 -0400156######################################################################
157# 32bit section outputting
158######################################################################
159
160def outsections(file, sections, prefix):
161 lp = len(prefix)
162 for size, align, name in sections:
163 if name[:lp] == prefix:
164 file.write("*(%s)\n" % (name,))
165
166def doLayout32(sections, outname):
167 output = open(outname, 'wb')
168 outsections(output, sections, '.text.')
169 output.write("code32_rodata = . ;\n")
170 outsections(output, sections, '.rodata')
171 outsections(output, sections, '.data.')
172 outsections(output, sections, '.bss.')
173
174
175######################################################################
176# Section garbage collection
177######################################################################
178
179def keepsection(name, pri, alt):
180 if name in pri[3]:
181 # Already kept - nothing to do.
182 return
183 pri[3].append(name)
184 relocs = pri[2].get(name)
185 if relocs is None:
186 return
187 # Keep all sections that this section points to
188 for symbol in relocs:
189 section = pri[1].get(symbol)
190 if section is not None and section[:9] != '.discard.':
191 keepsection(section, pri, alt)
192 continue
193 # Not in primary sections - it may be a cross 16/32 reference
194 section = alt[1].get(symbol)
195 if section is not None:
196 keepsection(section, alt, pri)
197
198def gc(info16, info32):
199 # pri = (sections, symbols, relocs, keep sections)
200 pri = (info16[0], info16[1], info16[2], [])
201 alt = (info32[0], info32[1], info32[2], [])
202 # Start by keeping sections that are globally visible.
203 for size, align, section in info16[0]:
204 if section[:11] == '.fixedaddr.' or '.export.' in section:
205 keepsection(section, pri, alt)
206 # Return sections found.
207 sections16 = []
208 for info in info16[0]:
209 size, align, section = info
210 if section not in pri[3]:
211# print "gc16", section
212 continue
213 sections16.append(info)
214 sections32 = []
215 for info in info32[0]:
216 size, align, section = info
217 if section not in alt[3]:
218# print "gc32", section
219 continue
220 sections32.append(info)
221 return sections16, sections32
222
223
224######################################################################
225# Startup and input parsing
226######################################################################
227
228# Read in output from objdump
229def parseObjDump(file):
230 # sections = [(size, align, section), ...]
231 sections = []
232 # symbols[symbol] = section
233 symbols = {}
234 # relocs[section] = [symbol, ...]
235 relocs = {}
236
237 state = None
238 for line in file.readlines():
239 line = line.rstrip()
240 if line == 'Sections:':
241 state = 'section'
242 continue
243 if line == 'SYMBOL TABLE:':
244 state = 'symbol'
245 continue
246 if line[:24] == 'RELOCATION RECORDS FOR [':
247 state = 'reloc'
248 relocsection = line[24:-2]
249 continue
250
251 if state == 'section':
252 try:
253 idx, name, size, vma, lma, fileoff, align = line.split()
254 if align[:3] != '2**':
255 continue
256 sections.append((int(size, 16), 2**int(align[3:]), name))
257 except:
258 pass
259 continue
260 if state == 'symbol':
261 try:
262 section, off, symbol = line[17:].split()
263 off = int(off, 16)
264 if '*' not in section:
265 symbols[symbol] = section
266 except:
267 pass
268 continue
269 if state == 'reloc':
270 try:
271 off, type, symbol = line.split()
272 off = int(off, 16)
273 relocs.setdefault(relocsection, []).append(symbol)
274 except:
275 pass
276 return sections, symbols, relocs
277
278def main():
279 # Get output name
280 in16, in32, out16, out32 = sys.argv[1:]
281
282 infile16 = open(in16, 'rb')
283 infile32 = open(in32, 'rb')
284
285 info16 = parseObjDump(infile16)
286 info32 = parseObjDump(infile32)
287
288 sections16, sections32 = gc(info16, info32)
289
290 doLayout16(sections16, out16)
291 doLayout32(sections32, out32)
292
Kevin O'Connor202024a2009-01-17 10:41:28 -0500293if __name__ == '__main__':
294 main()