[SeaBIOS] [PATCH 02/10] build: Extract section visiting logic in layoutrom.py.

Kevin O'Connor kevin at koconnor.net
Wed Jun 11 21:20:32 CEST 2014


Extract out the logic that visits all reachable sections into new
function findReachable().

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 scripts/layoutrom.py | 117 ++++++++++++++++++++++++++-------------------------
 1 file changed, 60 insertions(+), 57 deletions(-)

diff --git a/scripts/layoutrom.py b/scripts/layoutrom.py
index 28e7d0c..a4eba89 100755
--- a/scripts/layoutrom.py
+++ b/scripts/layoutrom.py
@@ -449,29 +449,42 @@ PHDRS
 # Detection of init code
 ######################################################################
 
-def markRuntime(section, sections, chain=[]):
-    if (section is None or not section.keep or section.category is not None
+# Visit all sections reachable from a given set of start sections
+def findReachable(anchorsections, checkreloc, data):
+    anchorsections = dict([(section, []) for section in anchorsections])
+    pending = list(anchorsections)
+    while pending:
+        section = pending.pop()
+        for reloc in section.relocs:
+            chain = anchorsections[section] + [section.name]
+            if not checkreloc(reloc, section, data, chain):
+                continue
+            nextsection = reloc.symbol.section
+            if nextsection not in anchorsections:
+                anchorsections[nextsection] = chain
+                pending.append(nextsection)
+    return anchorsections
+
+def checkRuntime(reloc, rsection, data, chain):
+    section = reloc.symbol.section
+    if (section is None or not section.keep
         or '.init.' in section.name or section.fileid != '32flat'):
-        return
+        return 0
     if '.data.varinit.' in section.name:
         print("ERROR: %s is VARVERIFY32INIT but used from %s" % (
             section.name, chain))
         sys.exit(1)
-    section.category = '32flat'
-    # Recursively mark all sections this section points to
-    for reloc in section.relocs:
-        markRuntime(reloc.symbol.section, sections, chain + [section.name])
+    return 1
 
 def findInit(sections):
     # Recursively find and mark all "runtime" sections.
-    for section in sections:
+    anchorsections = [
+        section for section in sections
         if ('.data.varlow.' in section.name or '.data.varfseg.' in section.name
-            or '.runtime.' in section.name or '.export.' in section.name):
-            markRuntime(section, sections)
+            or '.runtime.' in section.name or '.export.' in section.name)]
+    runtimesections = findReachable(anchorsections, checkRuntime, None)
     for section in sections:
-        if section.category is not None:
-            continue
-        if section.fileid == '32flat':
+        if section.fileid == '32flat' and section not in runtimesections:
             section.category = '32init'
         else:
             section.category = section.fileid
@@ -481,65 +494,55 @@ def findInit(sections):
 # Section garbage collection
 ######################################################################
 
-CFUNCPREFIX = [('_cfunc16_', 0), ('_cfunc32seg_', 1), ('_cfunc32flat_', 2)]
-
 # Find and keep the section associated with a symbol (if available).
-def keepsymbol(reloc, infos, pos, isxref):
+def checkKeepSym(reloc, syms, fileid, isxref):
     symbolname = reloc.symbolname
-    mustbecfunc = 0
-    for symprefix, needpos in CFUNCPREFIX:
-        if symbolname.startswith(symprefix):
-            if needpos != pos:
-                return -1
-            symbolname = symbolname[len(symprefix):]
-            mustbecfunc = 1
-            break
-    symbol = infos[pos][1].get(symbolname)
+    mustbecfunc = symbolname.startswith('_cfunc')
+    if mustbecfunc:
+        symprefix = '_cfunc' + fileid + '_'
+        if not symbolname.startswith(symprefix):
+            return 0
+        symbolname = symbolname[len(symprefix):]
+    symbol = syms.get(symbolname)
     if (symbol is None or symbol.section is None
         or symbol.section.name.startswith('.discard.')):
-        return -1
+        return 0
     isdestcfunc = (symbol.section.name.startswith('.text.')
                    and not symbol.section.name.startswith('.text.asm.'))
     if ((mustbecfunc and not isdestcfunc)
         or (not mustbecfunc and isdestcfunc and isxref)):
-        return -1
+        return 0
 
     reloc.symbol = symbol
-    keepsection(symbol.section, infos, pos)
+    return 1
+
+# Resolve a relocation and check if it should be kept in the final binary.
+def checkKeep(reloc, section, infos, chain):
+    ret = checkKeepSym(reloc, infos[section.fileid][1], section.fileid, 0)
+    if ret:
+        return ret
+    # Not in primary sections - it may be a cross 16/32 reference
+    for fileid in ('16', '32seg', '32flat'):
+        if fileid != section.fileid:
+            ret = checkKeepSym(reloc, infos[fileid][1], fileid, 1)
+            if ret:
+                return ret
     return 0
 
-# Note required section, and recursively set all referenced sections
-# as required.
-def keepsection(section, infos, pos=0):
-    if section.keep:
-        # Already kept - nothing to do.
-        return
-    section.keep = 1
-    # Keep all sections that this section points to
-    for reloc in section.relocs:
-        ret = keepsymbol(reloc, infos, pos, 0)
-        if not ret:
-            continue
-        # Not in primary sections - it may be a cross 16/32 reference
-        ret = keepsymbol(reloc, infos, (pos+1)%3, 1)
-        if not ret:
-            continue
-        ret = keepsymbol(reloc, infos, (pos+2)%3, 1)
-        if not ret:
-            continue
-
 # Determine which sections are actually referenced and need to be
 # placed into the output file.
 def gc(info16, info32seg, info32flat):
-    # infos = ((sections16, symbols16), (sect32seg, sym32seg)
-    #          , (sect32flat, sym32flat))
-    infos = (info16, info32seg, info32flat)
-    # Start by keeping sections that are globally visible.
-    for section in info16[0]:
-        if section.name.startswith('.fixedaddr.') or '.export.' in section.name:
-            keepsection(section, infos)
-    return [section for section in info16[0]+info32seg[0]+info32flat[0]
-            if section.keep]
+    anchorsections = [section for section in info16[0]
+                      if (section.name.startswith('.fixedaddr.')
+                          or '.export.' in section.name)]
+    infos = {'16': info16, '32seg': info32seg, '32flat': info32flat}
+    keepsections = findReachable(anchorsections, checkKeep, infos)
+    sections = []
+    for section in info16[0] + info32seg[0] + info32flat[0]:
+        if section in keepsections:
+            section.keep = 1
+            sections.append(section)
+    return sections
 
 
 ######################################################################
-- 
1.9.3




More information about the SeaBIOS mailing list