grml...
[seabios.git] / tools / layoutrom.py
index ac6fd1477d5191bf6b8ca5e1f7cb86c38b6a8e15..45738a3bb5cf3306b7f0eeee6d233835d8e3ccd6 100755 (executable)
@@ -140,9 +140,9 @@ def fitSections(sections, fillsections):
     return firstfixed
 
 # Return the subset of sections with a given name prefix
-def getSectionsPrefix(sections, fileid, prefix):
+def getSectionsPrefix(sections, category, prefix):
     return [section for section in sections
-            if section.fileid == fileid and section.name.startswith(prefix)]
+            if section.category == category and section.name.startswith(prefix)]
 
 def doLayout(sections):
     # Determine 16bit positions
@@ -176,13 +176,25 @@ def doLayout(sections):
         textsections + rodatasections + datasections + bsssections
         , code32seg_start + BUILD_BIOS_ADDR, 16)
 
+    # Determine 32flat init positions
+    textsections = getSectionsPrefix(sections, '32init', '.text.')
+    rodatasections = getSectionsPrefix(sections, '32init', '.rodata')
+    datasections = getSectionsPrefix(sections, '32init', '.data.')
+    bsssections = getSectionsPrefix(sections, '32init', '.bss.')
+
+    code32init_start = setSectionsStart(
+        textsections + rodatasections + datasections + bsssections
+        , code32flat_start, 16)
+
     # Print statistics
     size16 = BUILD_BIOS_SIZE - code16_start
     size32seg = code16_start - code32seg_start
     size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
+    size32init = code32flat_start - code32init_start
     print "16bit size:           %d" % size16
     print "32bit segmented size: %d" % size32seg
     print "32bit flat size:      %d" % size32flat
+    print "32bit flat init size: %d" % size32init
 
 
 ######################################################################
@@ -197,15 +209,16 @@ def outXRefs(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):
+                or (symbol.section.fileid == section.fileid
+                    and symbol.name == reloc.symbolname)
+                or reloc.symbolname in xrefs):
                 continue
-            xrefs[symbol.name] = 1
+            xrefs[reloc.symbolname] = 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)
+            out += "%s = 0x%x ;\n" % (reloc.symbolname, addr)
     return out
 
 # Write LD script includes for the given sections using relative offsets
@@ -229,7 +242,7 @@ def getSectionsFile(sections, fileid, defaddr=0):
     return sections, pos
 
 # Layout the 32bit segmented code.  This places the code as high as possible.
-def writeLinkerScripts(sections, entrysym, out16, out32seg, out32flat):
+def writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat):
     # Write 16bit linker script
     sections16, code16_start = getSectionsFile(sections, '16')
     output = open(out16, 'wb')
@@ -262,15 +275,31 @@ def writeLinkerScripts(sections, entrysym, out16, out32seg, out32flat):
     # Write 32flat linker script
     sections32flat, code32flat_start = getSectionsFile(
         sections, '32flat', code32seg_start)
+    relocstr = ""
+    relocminalign = 0
+    if genreloc:
+        # Generate relocations
+        relocstr, size, relocminalign = genRelocs(sections)
+        code32flat_start -= size
     output = open(out32flat, 'wb')
     output.write(COMMONHEADER
                  + outXRefs(sections32flat) + """
     %s = 0x%x ;
+    _reloc_min_align = 0x%x ;
     code32flat_start = 0x%x ;
     .text code32flat_start : {
 """ % (entrysym.name,
        entrysym.section.finalloc + entrysym.offset + BUILD_BIOS_ADDR,
-       code32flat_start)
+       relocminalign, code32flat_start)
+                 + relocstr
+                 + """
+        code32init_start = ABSOLUTE(.) ;
+"""
+                 + outRelSections(getSectionsPrefix(sections32flat, '32init', '')
+                                  , 'code32flat_start')
+                 + """
+        code32init_end = ABSOLUTE(.) ;
+"""
                  + outRelSections(getSectionsPrefix(sections32flat, '32flat', '')
                                   , 'code32flat_start')
                  + """
@@ -292,17 +321,105 @@ PHDRS
     output.close()
 
 
+######################################################################
+# Detection of init code
+######################################################################
+
+# Determine init section relocations
+def genRelocs(sections):
+    absrelocs = []
+    relrelocs = []
+    initrelocs = []
+    minalign = 16
+    for section in sections:
+        if section.category == '32init' and section.align > minalign:
+            minalign = section.align
+        for reloc in section.relocs:
+            symbol = reloc.symbol
+            if symbol.section is None:
+                continue
+            relocpos = section.finalloc + reloc.offset
+            if (reloc.type == 'R_386_32' and section.category == '32init'
+                and symbol.section.category == '32init'):
+                # Absolute relocation
+                absrelocs.append(relocpos)
+            elif (reloc.type == 'R_386_PC32' and section.category == '32init'
+                  and symbol.section.category != '32init'):
+                # Relative relocation
+                relrelocs.append(relocpos)
+            elif (section.category != '32init'
+                  and symbol.section.category == '32init'):
+                # Relocation to the init section
+                if section.fileid in ('16', '32seg'):
+                    relocpos += BUILD_BIOS_ADDR
+                initrelocs.append(relocpos)
+    absrelocs.sort()
+    relrelocs.sort()
+    initrelocs.sort()
+    out = ("        _reloc_abs_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in absrelocs])
+           + "        _reloc_abs_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_rel_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32init_start)\n" % (pos,)
+                      for pos in relrelocs])
+           + "        _reloc_rel_end = ABSOLUTE(.) ;\n"
+           + "        _reloc_init_start = ABSOLUTE(.) ;\n"
+           + "".join(["LONG(0x%x - code32flat_start)\n" % (pos,)
+                      for pos in initrelocs])
+           + "        _reloc_init_end = ABSOLUTE(.) ;\n")
+    return out, len(absrelocs + relrelocs + initrelocs) * 4, minalign
+
+def markRuntime(section, sections):
+    if (section is None or not section.keep or section.category is not None
+        or '.init.' in section.name or section.fileid != '32flat'):
+        return
+    section.category = '32flat'
+    # Recursively mark all sections this section points to
+    for reloc in section.relocs:
+        markRuntime(reloc.symbol.section, sections)
+
+def findInit(sections):
+    # Recursively find and mark all "runtime" sections.
+    for section in sections:
+        if '.runtime.' in section.name or '.export.' in section.name:
+            markRuntime(section, sections)
+    for section in sections:
+        if section.category is not None:
+            continue
+        if section.fileid == '32flat':
+            section.category = '32init'
+        else:
+            section.category = section.fileid
+
+
 ######################################################################
 # 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):
-    symbolname = reloc.symbol.name
+def keepsymbol(reloc, infos, pos, 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)
     if (symbol is None or symbol.section is None
         or symbol.section.name.startswith('.discard.')):
         return -1
+    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
+
     reloc.symbol = symbol
     keepsection(symbol.section, infos, pos)
     return 0
@@ -316,14 +433,14 @@ def keepsection(section, infos, pos=0):
     section.keep = 1
     # Keep all sections that this section points to
     for reloc in section.relocs:
-        ret = keepsymbol(reloc, infos, pos)
+        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)
+        ret = keepsymbol(reloc, infos, (pos+1)%3, 1)
         if not ret:
             continue
-        ret = keepsymbol(reloc, infos, (pos+2)%3)
+        ret = keepsymbol(reloc, infos, (pos+2)%3, 1)
         if not ret:
             continue
 
@@ -347,9 +464,9 @@ def gc(info16, info32seg, info32flat):
 
 class Section:
     name = size = alignment = fileid = relocs = None
-    finalloc = keep = None
+    finalloc = category = keep = None
 class Reloc:
-    offset = type = symbol = None
+    offset = type = symbolname = symbol = None
 class Symbol:
     name = offset = section = None
 
@@ -414,7 +531,17 @@ def parseObjDump(file, fileid):
                 reloc = Reloc()
                 reloc.offset = int(off, 16)
                 reloc.type = type
-                reloc.symbol = symbols[symbolname]
+                reloc.symbolname = symbolname
+                reloc.symbol = symbols.get(symbolname)
+                if reloc.symbol is None:
+                    # Some binutils (2.20.1) give section name instead
+                    # of a symbol - create a dummy symbol.
+                    reloc.symbol = symbol = Symbol()
+                    symbol.size = 0
+                    symbol.offset = 0
+                    symbol.name = symbolname
+                    symbol.section = sectionmap.get(symbolname)
+                    symbols[symbolname] = symbol
                 relocsection.relocs.append(reloc)
             except ValueError:
                 pass
@@ -437,13 +564,16 @@ def main():
     # Figure out which sections to keep.
     sections = gc(info16, info32seg, info32flat)
 
+    # Separate 32bit flat into runtime and init parts
+    findInit(sections)
+
     # Determine the final memory locations of each kept section.
-    # locsX = [(addr, sectioninfo), ...]
     doLayout(sections)
 
     # Write out linker script files.
-    entrysym = info16[1]['post32']
-    writeLinkerScripts(sections, entrysym, out16, out32seg, out32flat)
+    entrysym = info16[1]['entry_elf']
+    genreloc = '_reloc_abs_start' in info32flat[1]
+    writeLinkerScripts(sections, entrysym, genreloc, out16, out32seg, out32flat)
 
 if __name__ == '__main__':
     main()