Have layoutrom.py show info on utilization of fixed area.
[seabios.git] / tools / layoutrom.py
1 #!/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
8 import sys
9
10 def main():
11     # Get output name
12     outname = sys.argv[1]
13
14     # Read in section names and sizes
15     # sections = [(size, align, name), ...]
16     sections = []
17     for line in sys.stdin.readlines():
18         try:
19             idx, name, size, vma, lma, fileoff, align = line.split()
20             if align[:3] != '2**':
21                 continue
22             sections.append((int(size, 16), 2**int(align[3:]), name))
23         except:
24             pass
25
26     doLayout(sections, outname)
27
28 def alignpos(pos, alignbytes):
29     mask = alignbytes - 1
30     return (pos + mask) & ~mask
31
32 MAXPOS = 0x10000
33
34 def doLayout(sections, outname):
35     textsections = []
36     rodatasections = []
37     datasections = []
38     # fixedsections = [(addr, sectioninfo, extasectionslist), ...]
39     fixedsections = []
40     # canrelocate = [(sectioninfo, list), ...]
41     canrelocate = []
42
43     # Find desired sections.
44     for section in sections:
45         size, align, name = section
46         if name[:11] == '.fixedaddr.':
47             addr = int(name[11:], 16)
48             fixedsections.append((addr, section, []))
49             if align != 1:
50                 print "Error: Fixed section %s has non-zero alignment (%d)" % (
51                     name, align)
52                 sys.exit(1)
53         if name[:6] == '.text.':
54             textsections.append(section)
55             canrelocate.append((section, textsections))
56         if name[:17] == '.rodata.__func__.' or name == '.rodata.str1.1':
57             rodatasections.append(section)
58             #canrelocate.append((section, rodatasections))
59         if name[:8] == '.data16.':
60             datasections.append(section)
61             #canrelocate.append((section, datasections))
62
63     # Find freespace in fixed address area
64     fixedsections.sort()
65     # fixedAddr = [(freespace, sectioninfo), ...]
66     fixedAddr = []
67     for i in range(len(fixedsections)):
68         fixedsectioninfo = fixedsections[i]
69         addr, section, extrasectionslist = fixedsectioninfo
70         if i == len(fixedsections) - 1:
71             nextaddr = MAXPOS
72         else:
73             nextaddr = fixedsections[i+1][0]
74         avail = nextaddr - addr - section[0]
75         fixedAddr.append((avail, fixedsectioninfo))
76
77     # Attempt to fit other sections into fixed area
78     fixedAddr.sort()
79     canrelocate.sort()
80     unused = 0
81     for freespace, fixedsectioninfo in fixedAddr:
82         fixedaddr, fixedsection, extrasections = fixedsectioninfo
83         addpos = fixedaddr + fixedsection[0]
84         nextfixedaddr = addpos + freespace
85 #        print "Filling section %x uses %d, next=%x, available=%d" % (
86 #            fixedaddr, fixedsection[0], nextfixedaddr, freespace)
87         while 1:
88             canfit = None
89             for fixedaddrinfo in canrelocate:
90                 fitsection, inlist = fixedaddrinfo
91                 fitsize, fitalign, fitname = fitsection
92                 if addpos + fitsize > nextfixedaddr:
93                     # Can't fit and nothing else will fit.
94                     break
95                 fitnextaddr = alignpos(addpos, fitalign) + fitsize
96 #                print "Test %s - %x vs %x" % (
97 #                    fitname, fitnextaddr, nextfixedaddr)
98                 if fitnextaddr > nextfixedaddr:
99                     # This item can't fit.
100                     continue
101                 canfit = (fitnextaddr, fixedaddrinfo)
102             if canfit is None:
103                 unused += nextfixedaddr - addpos
104                 break
105             # Found a section that can fit.
106             fitnextaddr, fixedaddrinfo = canfit
107             canrelocate.remove(fixedaddrinfo)
108             fitsection, inlist = fixedaddrinfo
109             inlist.remove(fitsection)
110             extrasections.append(fitsection)
111             addpos = fitnextaddr
112             unused += alignpos(addpos, fitsection[1]) - addpos
113 #            print "    Adding %s (size %d align %d)" % (
114 #                fitsection[2], fitsection[0], fitsection[1])
115
116     firstfixed = fixedsections[0][0]
117     total = MAXPOS-firstfixed
118     totalused = total - unused
119     print "Fixed space: 0x%x-0x%x  total: %d  used: %d  Percent used: %.1f%%" % (
120         firstfixed, MAXPOS, total, totalused,
121         (float(totalused) / total) * 100.0)
122
123     # Write regular sections
124     output = open(outname, 'wb')
125     for section in textsections:
126         name = section[2]
127         output.write("*(%s)\n" % (name,))
128     output.write("code16_rodata = . ;\n")
129     for section in rodatasections:
130         name = section[2]
131         output.write("*(%s)\n" % (name,))
132     for section in datasections:
133         name = section[2]
134         output.write("*(%s)\n" % (name,))
135
136     # Write fixed sections
137     output.write("freespace1_start = . ;\n")
138     first = 1
139     for addr, section, extrasections in fixedsections:
140         name = section[2]
141         output.write(". = ( 0x%x - code16_start ) ;\n" % (addr,))
142         if first:
143             first = 0
144             output.write("freespace1_end = . ;\n")
145         output.write("*(%s)\n" % (name,))
146         for extrasection in extrasections:
147             name = extrasection[2]
148             output.write("*(%s)\n" % (name,))
149
150 if __name__ == '__main__':
151     main()