Try to automatically fit sections into open spaces in the 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 def doLayout(sections, outname):
33     textsections = []
34     rodatasections = []
35     datasections = []
36     # fixedsections = [(addr, sectioninfo, extasectionslist), ...]
37     fixedsections = []
38     # canrelocate = [(sectioninfo, list), ...]
39     canrelocate = []
40
41     # Find desired sections.
42     for section in sections:
43         size, align, name = section
44         if name[:11] == '.fixedaddr.':
45             addr = int(name[11:], 16)
46             fixedsections.append((addr, section, []))
47             if align != 1:
48                 print "Error: Fixed section %s has non-zero alignment (%d)" % (
49                     name, align)
50                 sys.exit(1)
51         if name[:6] == '.text.':
52             textsections.append(section)
53             canrelocate.append((section, textsections))
54         if name[:17] == '.rodata.__func__.' or name == '.rodata.str1.1':
55             rodatasections.append(section)
56             #canrelocate.append((section, rodatasections))
57         if name[:8] == '.data16.':
58             datasections.append(section)
59             #canrelocate.append((section, datasections))
60
61     # Find freespace in fixed address area
62     fixedsections.sort()
63     # fixedAddr = [(freespace, sectioninfo), ...]
64     fixedAddr = []
65     for i in range(len(fixedsections)):
66         fixedsectioninfo = fixedsections[i]
67         addr, section, extrasectionslist = fixedsectioninfo
68         if i == len(fixedsections) - 1:
69             nextaddr = 0x10000
70         else:
71             nextaddr = fixedsections[i+1][0]
72         avail = nextaddr - addr - section[0]
73         fixedAddr.append((avail, fixedsectioninfo))
74
75     # Attempt to fit other sections into fixed area
76     fixedAddr.sort()
77     canrelocate.sort()
78     for freespace, fixedsectioninfo in fixedAddr:
79         fixedaddr, fixedsection, extrasections = fixedsectioninfo
80         addpos = fixedaddr + fixedsection[0]
81         nextfixedaddr = addpos + freespace
82 #        print "Filling section %x uses %d, next=%x, available=%d" % (
83 #            fixedaddr, fixedsection[0], nextfixedaddr, freespace)
84         while 1:
85             canfit = None
86             for fixedaddrinfo in canrelocate:
87                 fitsection, inlist = fixedaddrinfo
88                 fitnextaddr = alignpos(addpos, fitsection[1]) + fitsection[0]
89 #                print "Test %s - %x vs %x" % (
90 #                    fitsection[2], fitnextaddr, nextfixedaddr)
91                 if fitnextaddr > nextfixedaddr:
92                     # Can't fit.
93                     break
94                 canfit = (fitnextaddr, fixedaddrinfo)
95             if canfit is None:
96                 break
97             # Found a section that can fit.
98             fitnextaddr, fixedaddrinfo = canfit
99             canrelocate.remove(fixedaddrinfo)
100             fitsection, inlist = fixedaddrinfo
101             inlist.remove(fitsection)
102             extrasections.append(fitsection)
103             addpos = fitnextaddr
104 #            print "    Adding %s (size %d align %d)" % (
105 #                fitsection[2], fitsection[0], fitsection[1])
106
107     # Write regular sections
108     output = open(outname, 'wb')
109     for section in textsections:
110         name = section[2]
111         output.write("*(%s)\n" % (name,))
112     output.write("code16_rodata = . ;\n")
113     for section in rodatasections:
114         name = section[2]
115         output.write("*(%s)\n" % (name,))
116     for section in datasections:
117         name = section[2]
118         output.write("*(%s)\n" % (name,))
119
120     # Write fixed sections
121     output.write("freespace1_start = . ;\n")
122     first = 1
123     for addr, section, extrasections in fixedsections:
124         name = section[2]
125         output.write(". = ( 0x%x - code16_start ) ;\n" % (addr,))
126         if first:
127             first = 0
128             output.write("freespace1_end = . ;\n")
129         output.write("*(%s)\n" % (name,))
130         for extrasection in extrasections:
131             name = extrasection[2]
132             output.write("*(%s)\n" % (name,))
133
134 if __name__ == '__main__':
135     main()