[SeaBIOS] [PATCH 02/11] Modify tools/layoutrom.py to use classes instead of tuples.

Kevin O'Connor kevin at koconnor.net
Thu Sep 16 04:33:01 CEST 2010


Using classes and updating the values in the classes makes the code
easier to understand.
---
 tools/checkrom.py  |    9 +-
 tools/layoutrom.py |  358 +++++++++++++++++++++++++++-------------------------
 2 files changed, 189 insertions(+), 178 deletions(-)

diff --git a/tools/checkrom.py b/tools/checkrom.py
index 039010d..42cf2df 100755
--- a/tools/checkrom.py
+++ b/tools/checkrom.py
@@ -14,10 +14,7 @@ def main():
 
     # Read in symbols
     objinfofile = open(objinfo, 'rb')
-    symbols = layoutrom.parseObjDump(objinfofile)[1]
-    syms = {}
-    for name, (addr, section) in symbols.items():
-        syms[name] = addr
+    symbols = layoutrom.parseObjDump(objinfofile, 'in')[1]
 
     # Read in raw file
     f = open(rawfile, 'rb')
@@ -29,8 +26,8 @@ def main():
         finalsize = 128*1024
 
     # Sanity checks
-    start = syms['code32flat_start']
-    end = syms['code32flat_end']
+    start = symbols['code32flat_start'].offset
+    end = symbols['code32flat_end'].offset
     expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
     if end != expend:
         print "Error!  Code does not end at 0x%x (got 0x%x)" % (
diff --git a/tools/layoutrom.py b/tools/layoutrom.py
index 7603f38..ac6fd14 100755
--- a/tools/layoutrom.py
+++ b/tools/layoutrom.py
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 # Script to analyze code and arrange ld sections.
 #
-# Copyright (C) 2008  Kevin O'Connor <kevin at koconnor.net>
+# Copyright (C) 2008-2010  Kevin O'Connor <kevin at koconnor.net>
 #
 # This file may be distributed under the terms of the GNU GPLv3 license.
 
@@ -40,30 +40,21 @@ def alignpos(pos, alignbytes):
 
 # Determine the final addresses for a list of sections that end at an
 # address.
-def getSectionsStart(sections, endaddr, minalign=1):
+def setSectionsStart(sections, endaddr, minalign=1):
     totspace = 0
-    for size, align, name in sections:
-        if align > minalign:
-            minalign = align
-        totspace = alignpos(totspace, align) + size
+    for section in sections:
+        if section.align > minalign:
+            minalign = section.align
+        totspace = alignpos(totspace, section.align) + section.size
     startaddr = (endaddr - totspace) / minalign * minalign
     curaddr = startaddr
     # out = [(addr, sectioninfo), ...]
     out = []
-    for sectioninfo in sections:
-        size, align, name = sectioninfo
-        curaddr = alignpos(curaddr, align)
-        out.append((curaddr, sectioninfo))
-        curaddr += size
-    return out, startaddr
-
-# Return the subset of sections with a given name prefix
-def getSectionsPrefix(sections, prefix):
-    out = []
-    for size, align, name in sections:
-        if name.startswith(prefix):
-            out.append((size, align, name))
-    return out
+    for section in sections:
+        curaddr = alignpos(curaddr, section.align)
+        section.finalloc = curaddr
+        curaddr += section.size
+    return startaddr
 
 # The 16bit code can't exceed 64K of space.
 BUILD_BIOS_ADDR = 0xf0000
@@ -73,22 +64,22 @@ BUILD_BIOS_SIZE = 0x10000
 # requirements are placed in the correct location.  It also places the
 # 16bit code as high as possible in the f-segment.
 def fitSections(sections, fillsections):
-    canrelocate = list(fillsections)
-    # fixedsections = [(addr, sectioninfo), ...]
+    # fixedsections = [(addr, section), ...]
     fixedsections = []
-    for sectioninfo in sections:
-        size, align, name = sectioninfo
-        if name.startswith('.fixedaddr.'):
-            addr = int(name[11:], 16)
-            fixedsections.append((addr, sectioninfo))
-            if align != 1:
+    for section in sections:
+        if section.name.startswith('.fixedaddr.'):
+            addr = int(section.name[11:], 16)
+            section.finalloc = addr
+            fixedsections.append((addr, section))
+            if section.align != 1:
                 print "Error: Fixed section %s has non-zero alignment (%d)" % (
-                    name, align)
+                    section.name, section.align)
                 sys.exit(1)
+    fixedsections.sort()
+    firstfixed = fixedsections[0][0]
 
     # Find freespace in fixed address area
-    fixedsections.sort()
-    # fixedAddr = [(freespace, sectioninfo), ...]
+    # fixedAddr = [(freespace, section), ...]
     fixedAddr = []
     for i in range(len(fixedsections)):
         fixedsectioninfo = fixedsections[i]
@@ -97,31 +88,31 @@ def fitSections(sections, fillsections):
             nextaddr = BUILD_BIOS_SIZE
         else:
             nextaddr = fixedsections[i+1][0]
-        avail = nextaddr - addr - section[0]
-        fixedAddr.append((avail, fixedsectioninfo))
+        avail = nextaddr - addr - section.size
+        fixedAddr.append((avail, section))
+    fixedAddr.sort()
 
     # Attempt to fit other sections into fixed area
-    extrasections = []
-    fixedAddr.sort()
+    canrelocate = [(section.size, section.align, section.name, section)
+                   for section in fillsections]
     canrelocate.sort()
+    canrelocate = [section for size, align, name, section in canrelocate]
     totalused = 0
-    for freespace, fixedsectioninfo in fixedAddr:
-        fixedaddr, fixedsection = fixedsectioninfo
-        addpos = fixedaddr + fixedsection[0]
-        totalused += fixedsection[0]
+    for freespace, fixedsection in fixedAddr:
+        addpos = fixedsection.finalloc + fixedsection.size
+        totalused += fixedsection.size
         nextfixedaddr = addpos + freespace
 #        print "Filling section %x uses %d, next=%x, available=%d" % (
-#            fixedaddr, fixedsection[0], nextfixedaddr, freespace)
+#            fixedsection.finalloc, fixedsection.size, nextfixedaddr, freespace)
         while 1:
             canfit = None
             for fitsection in canrelocate:
-                fitsize, fitalign, fitname = fitsection
-                if addpos + fitsize > nextfixedaddr:
+                if addpos + fitsection.size > nextfixedaddr:
                     # Can't fit and nothing else will fit.
                     break
-                fitnextaddr = alignpos(addpos, fitalign) + fitsize
+                fitnextaddr = alignpos(addpos, fitsection.align) + fitsection.size
 #                print "Test %s - %x vs %x" % (
-#                    fitname, fitnextaddr, nextfixedaddr)
+#                    fitsection.name, fitnextaddr, nextfixedaddr)
                 if fitnextaddr > nextfixedaddr:
                     # This item can't fit.
                     continue
@@ -131,13 +122,12 @@ def fitSections(sections, fillsections):
             # Found a section that can fit.
             fitnextaddr, fitsection = canfit
             canrelocate.remove(fitsection)
-            extrasections.append((addpos, fitsection))
+            fitsection.finalloc = addpos
             addpos = fitnextaddr
-            totalused += fitsection[0]
+            totalused += fitsection.size
 #            print "    Adding %s (size %d align %d) pos=%x avail=%d" % (
 #                fitsection[2], fitsection[0], fitsection[1]
 #                , fitnextaddr, nextfixedaddr - fitnextaddr)
-    firstfixed = fixedsections[0][0]
 
     # Report stats
     total = BUILD_BIOS_SIZE-firstfixed
@@ -147,40 +137,42 @@ def fitSections(sections, fillsections):
             firstfixed, BUILD_BIOS_SIZE, total, slack,
             (float(slack) / total) * 100.0))
 
-    return fixedsections + extrasections, firstfixed
+    return firstfixed
 
-def doLayout(sections16, sections32seg, sections32flat):
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, fileid, prefix):
+    return [section for section in sections
+            if section.fileid == fileid and section.name.startswith(prefix)]
+
+def doLayout(sections):
     # Determine 16bit positions
-    textsections = getSectionsPrefix(sections16, '.text.')
-    rodatasections = (getSectionsPrefix(sections16, '.rodata.str1.1')
-                      + getSectionsPrefix(sections16, '.rodata.__func__.'))
-    datasections = getSectionsPrefix(sections16, '.data16.')
-    fixedsections = getSectionsPrefix(sections16, '.fixedaddr.')
-
-    locs16fixed, firstfixed = fitSections(fixedsections, textsections)
-    prunesections = [i[1] for i in locs16fixed]
-    remsections = [i for i in textsections+rodatasections+datasections
-                   if i not in prunesections]
-    locs16, code16_start = getSectionsStart(remsections, firstfixed)
-    locs16 = locs16 + locs16fixed
-    locs16.sort()
+    textsections = getSectionsPrefix(sections, '16', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '16', '.rodata.str1.1')
+                      + getSectionsPrefix(sections, '16', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '16', '.data16.')
+    fixedsections = getSectionsPrefix(sections, '16', '.fixedaddr.')
+
+    firstfixed = fitSections(fixedsections, textsections)
+    remsections = [s for s in textsections+rodatasections+datasections
+                   if s.finalloc is None]
+    code16_start = setSectionsStart(remsections, firstfixed)
 
     # Determine 32seg positions
-    textsections = getSectionsPrefix(sections32seg, '.text.')
-    rodatasections = (getSectionsPrefix(sections32seg, '.rodata.str1.1')
-                      + getSectionsPrefix(sections32seg, '.rodata.__func__.'))
-    datasections = getSectionsPrefix(sections32seg, '.data32seg.')
+    textsections = getSectionsPrefix(sections, '32seg', '.text.')
+    rodatasections = (getSectionsPrefix(sections, '32seg', '.rodata.str1.1')
+                      +getSectionsPrefix(sections, '32seg', '.rodata.__func__.'))
+    datasections = getSectionsPrefix(sections, '32seg', '.data32seg.')
 
-    locs32seg, code32seg_start = getSectionsStart(
+    code32seg_start = setSectionsStart(
         textsections + rodatasections + datasections, code16_start)
 
-    # Determine 32flat positions
-    textsections = getSectionsPrefix(sections32flat, '.text.')
-    rodatasections = getSectionsPrefix(sections32flat, '.rodata')
-    datasections = getSectionsPrefix(sections32flat, '.data.')
-    bsssections = getSectionsPrefix(sections32flat, '.bss.')
+    # Determine 32flat runtime positions
+    textsections = getSectionsPrefix(sections, '32flat', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32flat', '.rodata')
+    datasections = getSectionsPrefix(sections, '32flat', '.data.')
+    bsssections = getSectionsPrefix(sections, '32flat', '.bss.')
 
-    locs32flat, code32flat_start = getSectionsStart(
+    code32flat_start = setSectionsStart(
         textsections + rodatasections + datasections + bsssections
         , code32seg_start + BUILD_BIOS_ADDR, 16)
 
@@ -192,52 +184,60 @@ def doLayout(sections16, sections32seg, sections32flat):
     print "32bit segmented size: %d" % size32seg
     print "32bit flat size:      %d" % size32flat
 
-    return locs16, locs32seg, locs32flat
-
 
 ######################################################################
 # Linker script output
 ######################################################################
 
 # Write LD script includes for the given cross references
-def outXRefs(xrefs, finallocs, delta=0):
+def outXRefs(sections):
+    xrefs = {}
     out = ""
-    for symbol, (fileid, section, addr) in xrefs.items():
-        if fileid < 2:
-            addr += delta
-        out += "%s = 0x%x ;\n" % (symbol, finallocs[(fileid, section)] + addr)
+    for section in sections:
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if (symbol.section is None
+                or symbol.section.fileid == section.fileid
+                or symbol.name in xrefs):
+                continue
+            xrefs[symbol.name] = 1
+            addr = symbol.section.finalloc + symbol.offset
+            if (section.fileid == '32flat'
+                and symbol.section.fileid in ('16', '32seg')):
+                addr += BUILD_BIOS_ADDR
+            out += "%s = 0x%x ;\n" % (symbol.name, addr)
     return out
 
 # Write LD script includes for the given sections using relative offsets
-def outRelSections(locs, startsym):
+def outRelSections(sections, startsym):
     out = ""
-    for addr, sectioninfo in locs:
-        size, align, name = sectioninfo
-        out += ". = ( 0x%x - %s ) ;\n" % (addr, startsym)
-        if name == '.rodata.str1.1':
+    for section in sections:
+        out += ". = ( 0x%x - %s ) ;\n" % (section.finalloc, startsym)
+        if section.name == '.rodata.str1.1':
             out += "_rodata = . ;\n"
-        out += "*(%s)\n" % (name,)
+        out += "*(%s)\n" % (section.name,)
     return out
 
-# Layout the 32bit segmented code.  This places the code as high as possible.
-def writeLinkerScripts(locs16, locs32seg, locs32flat
-                       , xref16, xref32seg, xref32flat
-                       , out16, out32seg, out32flat):
-    # Index to final location for each section
-    # finallocs[(fileid, section)] = addr
-    finallocs = {}
-    for fileid, locs in ((0, locs16), (1, locs32seg), (2, locs32flat)):
-        for addr, sectioninfo in locs:
-            finallocs[(fileid, sectioninfo[2])] = addr
+def getSectionsFile(sections, fileid, defaddr=0):
+    sections = [(section.finalloc, section)
+                for section in sections if section.fileid == fileid]
+    sections.sort()
+    sections = [section for addr, section in sections]
+    pos = defaddr
+    if sections:
+        pos = sections[0].finalloc
+    return sections, pos
 
+# Layout the 32bit segmented code.  This places the code as high as possible.
+def writeLinkerScripts(sections, entrysym, out16, out32seg, out32flat):
     # Write 16bit linker script
-    code16_start = locs16[0][0]
+    sections16, code16_start = getSectionsFile(sections, '16')
     output = open(out16, 'wb')
-    output.write(COMMONHEADER + outXRefs(xref16, finallocs) + """
+    output.write(COMMONHEADER + outXRefs(sections16) + """
     code16_start = 0x%x ;
     .text16 code16_start : {
 """ % (code16_start)
-                 + outRelSections(locs16, 'code16_start')
+                 + outRelSections(sections16, 'code16_start')
                  + """
     }
 """
@@ -245,15 +245,14 @@ def writeLinkerScripts(locs16, locs32seg, locs32flat
     output.close()
 
     # Write 32seg linker script
-    code32seg_start = code16_start
-    if locs32seg:
-        code32seg_start = locs32seg[0][0]
+    sections32seg, code32seg_start = getSectionsFile(
+        sections, '32seg', code16_start)
     output = open(out32seg, 'wb')
-    output.write(COMMONHEADER + outXRefs(xref32seg, finallocs) + """
+    output.write(COMMONHEADER + outXRefs(sections32seg) + """
     code32seg_start = 0x%x ;
     .text32seg code32seg_start : {
 """ % (code32seg_start)
-                 + outRelSections(locs32seg, 'code32seg_start')
+                 + outRelSections(sections32seg, 'code32seg_start')
                  + """
     }
 """
@@ -261,13 +260,19 @@ def writeLinkerScripts(locs16, locs32seg, locs32flat
     output.close()
 
     # Write 32flat linker script
+    sections32flat, code32flat_start = getSectionsFile(
+        sections, '32flat', code32seg_start)
     output = open(out32flat, 'wb')
     output.write(COMMONHEADER
-                 + outXRefs(xref32flat, finallocs, BUILD_BIOS_ADDR) + """
+                 + outXRefs(sections32flat) + """
+    %s = 0x%x ;
     code32flat_start = 0x%x ;
     .text code32flat_start : {
-""" % (locs32flat[0][0])
-                 + outRelSections(locs32flat, 'code32flat_start')
+""" % (entrysym.name,
+       entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
+       code32flat_start)
+                 + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
+                                  , 'code32flat_start')
                  + """
         . = ( 0x%x - code32flat_start ) ;
         *(.text32seg)
@@ -278,12 +283,12 @@ def writeLinkerScripts(locs16, locs32seg, locs32flat
 """ % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
                  + COMMONTRAILER
                  + """
-ENTRY(post32)
+ENTRY(%s)
 PHDRS
 {
         text PT_LOAD AT ( code32flat_start ) ;
 }
-""")
+""" % (entrysym.name,))
     output.close()
 
 
@@ -292,75 +297,69 @@ PHDRS
 ######################################################################
 
 # Find and keep the section associated with a symbol (if available).
-def keepsymbol(symbol, infos, pos, callerpos=None):
-    addr, section = infos[pos][1].get(symbol, (None, None))
-    if section is None or '*' in section or section.startswith('.discard.'):
+def keepsymbol(reloc, infos, pos):
+    symbolname = reloc.symbol.name
+    symbol = infos[pos][1].get(symbolname)
+    if (symbol is None or symbol.section is None
+        or symbol.section.name.startswith('.discard.')):
         return -1
-    if callerpos is not None and symbol not in infos[callerpos][4]:
-        # This symbol reference is a cross section reference (an xref).
-        # xref[symbol] = (fileid, section, addr)
-        infos[callerpos][4][symbol] = (pos, section, addr)
-    keepsection(section, infos, pos)
+    reloc.symbol = symbol
+    keepsection(symbol.section, infos, pos)
     return 0
 
 # Note required section, and recursively set all referenced sections
 # as required.
-def keepsection(name, infos, pos=0):
-    if name in infos[pos][3]:
+def keepsection(section, infos, pos=0):
+    if section.keep:
         # Already kept - nothing to do.
         return
-    infos[pos][3].append(name)
-    relocs = infos[pos][2].get(name)
-    if relocs is None:
-        return
+    section.keep = 1
     # Keep all sections that this section points to
-    for symbol in relocs:
-        ret = keepsymbol(symbol, infos, pos)
+    for reloc in section.relocs:
+        ret = keepsymbol(reloc, infos, pos)
         if not ret:
             continue
         # Not in primary sections - it may be a cross 16/32 reference
-        ret = keepsymbol(symbol, infos, (pos+1)%3, pos)
+        ret = keepsymbol(reloc, infos, (pos+1)%3)
         if not ret:
             continue
-        ret = keepsymbol(symbol, infos, (pos+2)%3, pos)
+        ret = keepsymbol(reloc, infos, (pos+2)%3)
         if not ret:
             continue
 
-# Return a list of kept sections.
-def getSectionsList(sections, names):
-    return [i for i in sections if i[2] in names]
-
 # Determine which sections are actually referenced and need to be
 # placed into the output file.
 def gc(info16, info32seg, info32flat):
-    # infos = ((sections, symbols, relocs, keep sections, xrefs), ...)
-    infos = ((info16[0], info16[1], info16[2], [], {}),
-             (info32seg[0], info32seg[1], info32seg[2], [], {}),
-             (info32flat[0], info32flat[1], info32flat[2], [], {}))
+    # infos = ((sections16, symbols16), (sect32seg, sym32seg)
+    #          , (sect32flat, sym32flat))
+    infos = (info16, info32seg, info32flat)
     # Start by keeping sections that are globally visible.
-    for size, align, section in info16[0]:
-        if section.startswith('.fixedaddr.') or '.export.' in section:
+    for section in info16[0]:
+        if section.name.startswith('.fixedaddr.') or '.export.' in section.name:
             keepsection(section, infos)
-    keepsymbol('post32', infos, 0, 2)
-    # Return sections found.
-    keep16 = getSectionsList(info16[0], infos[0][3]), infos[0][4]
-    keep32seg = getSectionsList(info32seg[0], infos[1][3]), infos[1][4]
-    keep32flat = getSectionsList(info32flat[0], infos[2][3]), infos[2][4]
-    return keep16, keep32seg, keep32flat
+    return [section for section in info16[0]+info32seg[0]+info32flat[0]
+            if section.keep]
 
 
 ######################################################################
 # Startup and input parsing
 ######################################################################
 
+class Section:
+    name = size = alignment = fileid = relocs = None
+    finalloc = keep = None
+class Reloc:
+    offset = type = symbol = None
+class Symbol:
+    name = offset = section = None
+
 # Read in output from objdump
-def parseObjDump(file):
-    # sections = [(size, align, section), ...]
+def parseObjDump(file, fileid):
+    # sections = [section, ...]
     sections = []
-    # symbols[symbol] = (addr, section)
+    sectionmap = {}
+    # symbols[symbolname] = symbol
     symbols = {}
-    # relocs[section] = [symbol, ...]
-    relocs = {}
 
     state = None
     for line in file.readlines():
@@ -372,8 +371,13 @@ def parseObjDump(file):
             state = 'symbol'
             continue
         if line.startswith('RELOCATION RECORDS FOR ['):
+            sectionname = line[24:-2]
+            if sectionname.startswith('.debug_'):
+                # Skip debugging sections (to reduce parsing time)
+                state = None
+                continue
             state = 'reloc'
-            relocsection = line[24:-2]
+            relocsection = sectionmap[sectionname]
             continue
 
         if state == 'section':
@@ -381,27 +385,40 @@ def parseObjDump(file):
                 idx, name, size, vma, lma, fileoff, align = line.split()
                 if align[:3] != '2**':
                     continue
-                sections.append((int(size, 16), 2**int(align[3:]), name))
-            except:
+                section = Section()
+                section.name = name
+                section.size = int(size, 16)
+                section.align = 2**int(align[3:])
+                section.fileid = fileid
+                section.relocs = []
+                sections.append(section)
+                sectionmap[name] = section
+            except ValueError:
                 pass
             continue
         if state == 'symbol':
             try:
-                section, size, symbol = line[17:].split()
-                size = int(size, 16)
-                addr = int(line[:8], 16)
-                symbols[symbol] = addr, section
-            except:
+                sectionname, size, name = line[17:].split()
+                symbol = Symbol()
+                symbol.size = int(size, 16)
+                symbol.offset = int(line[:8], 16)
+                symbol.name = name
+                symbol.section = sectionmap.get(sectionname)
+                symbols[name] = symbol
+            except ValueError:
                 pass
             continue
         if state == 'reloc':
             try:
-                off, type, symbol = line.split()
-                off = int(off, 16)
-                relocs.setdefault(relocsection, []).append(symbol)
-            except:
+                off, type, symbolname = line.split()
+                reloc = Reloc()
+                reloc.offset = int(off, 16)
+                reloc.type = type
+                reloc.symbol = symbols[symbolname]
+                relocsection.relocs.append(reloc)
+            except ValueError:
                 pass
-    return sections, symbols, relocs
+    return sections, symbols
 
 def main():
     # Get output name
@@ -412,24 +429,21 @@ def main():
     infile32seg = open(in32seg, 'rb')
     infile32flat = open(in32flat, 'rb')
 
-    # infoX = (sections, symbols, relocs)
-    info16 = parseObjDump(infile16)
-    info32seg = parseObjDump(infile32seg)
-    info32flat = parseObjDump(infile32flat)
+    # infoX = (sections, symbols)
+    info16 = parseObjDump(infile16, '16')
+    info32seg = parseObjDump(infile32seg, '32seg')
+    info32flat = parseObjDump(infile32flat, '32flat')
 
     # Figure out which sections to keep.
-    # keepX = (sections, xrefs)
-    keep16, keep32seg, keep32flat = gc(info16, info32seg, info32flat)
+    sections = gc(info16, info32seg, info32flat)
 
     # Determine the final memory locations of each kept section.
     # locsX = [(addr, sectioninfo), ...]
-    locs16, locs32seg, locs32flat = doLayout(
-        keep16[0], keep32seg[0], keep32flat[0])
+    doLayout(sections)
 
     # Write out linker script files.
-    writeLinkerScripts(locs16, locs32seg, locs32flat
-                       , keep16[1], keep32seg[1], keep32flat[1]
-                       , out16, out32seg, out32flat)
+    entrysym = info16[1]['post32']
+    writeLinkerScripts(sections, entrysym, out16, out32seg, out32flat)
 
 if __name__ == '__main__':
     main()
-- 
1.7.2.3




More information about the SeaBIOS mailing list