Allow rom to grow beyond 64K.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 20 Sep 2009 23:47:45 +0000 (19:47 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 20 Sep 2009 23:47:45 +0000 (19:47 -0400)
If rom is over 64K then use part of e-segment for 32bit code.
Push 32bit code as high as it can go in the f-segment.
Do version building before layoutrom.py - this way layoutrom knows
    full size of rom.
Make layoutrom.py build the full ld script - remove now unused ld
    scripts that just imported the output of layoutrom.py.
Also, use "objdump" instead of "nm" - reduce toolchain requirements.
Enhance tools/checkrom.py so that it can pad bios.bin to size qemu is
    happy with.
Also, add dependencies to build rules for local tools - if tool
    changes automatically rerun it.
Make sure option roms don't overwrite the 32bit code (should the 32bit
    code be in the e-segment).
Make sure shadow code works even if part of the code is in the
    e-segment.

Makefile
src/layout16.lds.S [deleted file]
src/optionroms.c
src/rombios.lds.S
src/rombios16.lds.S
src/rombios32.lds.S [deleted file]
src/shadow.c
tools/checkrom.py
tools/layoutrom.py

index ec30f3947709c3bba36fcc60ad74c7a3ce410a73..a933f607e6236cf7c89a07bc2c4a70606e4f92b0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -51,7 +51,6 @@ endif
 
 OBJCOPY=objcopy
 OBJDUMP=objdump
-NM=nm
 STRIP=strip
 
 .PHONY : all FORCE
@@ -112,47 +111,43 @@ $(OUT)asm-offsets.h: $(OUT)asm-offsets.s
 
 $(OUT)ccode.16.s: ; $(call whole-compile, $(CFLAGS16) -S, $(addprefix src/, $(SRC16)),$@)
 
+$(OUT)ccode32.o: ; $(call whole-compile, $(CFLAGS), $(addprefix src/, $(SRC32)),$@)
+
 $(OUT)code16.o: romlayout.S $(OUT)ccode.16.s $(OUT)asm-offsets.h
        @echo "  Compiling (16bit) $@"
        $(Q)$(CC) $(CFLAGS16INC) -c -D__ASSEMBLY__ $< -o $@
 
-$(OUT)code32.o: ; $(call whole-compile, $(CFLAGS), $(addprefix src/, $(SRC32)),$@)
-
-$(OUT)romlayout16.lds $(OUT)romlayout32.lds: $(OUT)code32.o $(OUT)code16.o
-       @echo "  Building layout information $@"
+$(OUT)romlayout16.lds $(OUT)romlayout32.lds $(OUT)code32.o: $(OUT)ccode32.o $(OUT)code16.o tools/layoutrom.py
+       @echo "  Building ld scripts (version \"$(VERSION)\")"
+       $(Q)echo 'const char VERSION[] = "$(VERSION)";' > $(OUT)version.c
+       $(Q)$(CC) $(CFLAGS) -c $(OUT)version.c -o $(OUT)version.o
+       $(Q)$(LD) -melf_i386 -r $(OUT)ccode32.o $(OUT)version.o -o $(OUT)code32.o
        $(Q)$(OBJDUMP) -thr $(OUT)code32.o > $(OUT)code32.o.objdump
        $(Q)$(OBJDUMP) -thr $(OUT)code16.o > $(OUT)code16.o.objdump
        $(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32.lds
 
-$(OUT)layout16.lds: $(OUT)romlayout16.lds
-$(OUT)rombios32.lds: $(OUT)romlayout32.lds
-
 
-$(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32.o $(OUT)layout16.lds
+$(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32.o $(OUT)romlayout16.lds
        @echo "  Linking (no relocs) $@"
-       $(Q)$(LD) -r -T $(OUT)layout16.lds $< -o $@
+       $(Q)$(LD) -r -T $(OUT)romlayout16.lds $< -o $@
 
-$(OUT)rom32.o: $(OUT)code32.o $(OUT)rombios32.lds
+$(OUT)rom32.o: $(OUT)code32.o $(OUT)romlayout32.lds
        @echo "  Linking (no relocs) $@"
-       $(Q)$(LD) -r -T $(OUT)rombios32.lds $< -o $@
+       $(Q)$(LD) -r -T $(OUT)romlayout32.lds $< -o $@
 
 $(OUT)rom.o: $(OUT)rom16.o $(OUT)rom32.o $(OUT)rombios16.lds $(OUT)rombios.lds
        @echo "  Linking $@ (version \"$(VERSION)\")"
-       $(Q)echo 'const char VERSION[] __attribute__((section(".data32.version"))) = "$(VERSION)";' > $(OUT)version.c
-       $(Q)$(CC) $(CFLAGS) -c $(OUT)version.c -o $(OUT)version.o
        $(Q)$(LD) -T $(OUT)rombios16.lds $(OUT)rom16.o -R $(OUT)rom32.o -o $(OUT)rom16.reloc.o
        $(Q)$(STRIP) $(OUT)rom16.reloc.o -o $(OUT)rom16.final.o
        $(Q)$(OBJCOPY) --adjust-vma 0xf0000 $(OUT)rom16.o $(OUT)rom16.moved.o
-       $(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32.o $(OUT)version.o -R $(OUT)rom16.moved.o -o $@
+       $(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32.o -R $(OUT)rom16.moved.o -o $@
 
-$(OUT)bios.bin.elf: $(OUT)rom.o
+$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
        @echo "  Prepping $@"
-       $(Q)$(NM) $< | ./tools/checkrom.py
-       $(Q)$(STRIP) $< -o $@
-
-$(OUT)bios.bin: $(OUT)bios.bin.elf
-       @echo "  Extracting binary $@"
-       $(Q)$(OBJCOPY) -O binary $< $@
+       $(Q)$(OBJDUMP) -thr $< > $<.objdump
+       $(Q)$(OBJCOPY) -O binary $< $(OUT)bios.bin.raw
+       $(Q)./tools/checkrom.py $<.objdump $(OUT)bios.bin.raw $(OUT)bios.bin
+       $(Q)$(STRIP) $< -o $(OUT)bios.bin.elf
 
 
 ################ VGA build rules
@@ -175,7 +170,7 @@ $(OUT)vgabios.bin.raw: $(OUT)vgarom.o
        @echo "  Extracting binary $@"
        $(Q)$(OBJCOPY) -O binary $< $@
 
-$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw
+$(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py
        @echo "  Finalizing rom $@"
        $(Q)./tools/buildrom.py $< $@
 
diff --git a/src/layout16.lds.S b/src/layout16.lds.S
deleted file mode 100644 (file)
index 40f3664..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Placement of the 16bit code.
-//
-// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "config.h" // BUILD_BIOS_ADDR
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH("i386")
-SECTIONS
-{
-
-// The actual placement of the 16bit sections is determined by the
-// script tools/layoutrom.py
-#include "../out/romlayout16.lds"
-
-        // Discard regular data sections to force a link error if
-        // 16bit code attempts to access data not marked with VAR16.
-        /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
-}
index 7d93a87b4ad32792ef633e3369b5bfce1af8ce8a..18526f4b57c2249413cc9fac59ba208157f60ba3 100644 (file)
@@ -164,12 +164,22 @@ get_pci_rom(struct rom_header *rom)
     return pci;
 }
 
+// Return the memory position up to which roms may be located.
+static inline u32
+max_rom()
+{
+    extern u8 code32_start[];
+    if ((u32)code32_start > BUILD_BIOS_ADDR)
+        return BUILD_BIOS_ADDR;
+    return (u32)code32_start;
+}
+
 // Copy a rom to its permanent location below 1MiB
 static struct rom_header *
 copy_rom(struct rom_header *rom)
 {
     u32 romsize = rom->size * 512;
-    if (RomEnd + romsize > BUILD_BIOS_ADDR) {
+    if (RomEnd + romsize > max_rom()) {
         // Option rom doesn't fit.
         dprintf(1, "Option rom %p doesn't fit.\n", rom);
         return NULL;
@@ -213,8 +223,7 @@ lookup_hardcode(u32 vendev)
         && ((OPTIONROM_VENDEV_2 >> 16)
             | ((OPTIONROM_VENDEV_2 & 0xffff)) << 16) == vendev)
         return copy_rom((void*)OPTIONROM_MEM_2);
-    int ret = cbfs_copy_optionrom((void*)RomEnd, BUILD_BIOS_ADDR - RomEnd
-                                  , vendev);
+    int ret = cbfs_copy_optionrom((void*)RomEnd, max_rom() - RomEnd, vendev);
     if (ret < 0)
         return NULL;
     return (void*)RomEnd;
@@ -229,7 +238,7 @@ run_cbfs_roms(const char *prefix, int isvga)
         file = cbfs_findprefix(prefix, file);
         if (!file)
             break;
-        int ret = cbfs_copyfile(file, (void*)RomEnd, BUILD_BIOS_ADDR - RomEnd);
+        int ret = cbfs_copyfile(file, (void*)RomEnd, max_rom() - RomEnd);
         if (ret > 0)
             init_optionrom((void*)RomEnd, 0, isvga);
     }
@@ -343,7 +352,7 @@ optionrom_setup()
     if (CONFIG_OPTIONROMS_DEPLOYED) {
         // Option roms are already deployed on the system.
         u32 pos = RomEnd;
-        while (pos < BUILD_BIOS_ADDR) {
+        while (pos < max_rom()) {
             int ret = init_optionrom((void*)pos, 0, 0);
             if (ret)
                 pos += OPTION_ROM_ALIGN;
index 3d59fad4b531b910547fe7acc8e3563e026518b1..8400732e39bde82309e5206b1cb449ecd72eb377 100644 (file)
@@ -4,16 +4,17 @@
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+#include "config.h" // BUILD_BIOS_ADDR
+
+OUTPUT_FORMAT("elf32-i386")
 OUTPUT_ARCH("i386")
 ENTRY(post32)
 SECTIONS
 {
         .text code32_start : {
                 *(.text32)
-                *(.data32.version)
 
-                . = code16_start ;
+                . = code16_start + BUILD_BIOS_ADDR - code32_start ;
                 *(.text16)
                 final_code16_end = . ;
                 }
index 6e6a2f1f4b125e49aacdae738370eb3d2c83fb28..f9046adc952b672feac06f306d742a9acb8b8a82 100644 (file)
@@ -4,8 +4,6 @@
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
-#include "config.h" // BUILD_BIOS_ADDR
-
 OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
 OUTPUT_ARCH("i386")
 SECTIONS
diff --git a/src/rombios32.lds.S b/src/rombios32.lds.S
deleted file mode 100644 (file)
index 62e92d1..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Linker definitions for 32 bit code
-//
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
-//
-// This file may be distributed under the terms of the GNU LGPLv3 license.
-
-#include "config.h" // BUILD_BIOS_ADDR
-
-OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
-OUTPUT_ARCH("i386")
-SECTIONS
-{
-        .text32 BUILD_BIOS_ADDR : {
-                code32_start = ABSOLUTE(.) ;
-
-// The actual sections kept is determined by the script tools/layoutrom.py
-#include "../out/romlayout32.lds"
-
-                freespace_start = . ;
-                code32_end = ABSOLUTE(.) ;
-                }
-}
index daa2e213f43ede8330e7a3f65f6ba00ff2b9577a..f0f97c516f8c29e0c73b8019b1019532eaa051ab 100644 (file)
 
 // Enable shadowing and copy bios.
 static void
-copy_bios(u16 bdf)
+__make_bios_writable(u16 bdf)
 {
-    pci_config_writeb(bdf, 0x59, 0x30);
-    memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE);
-}
-
-// Make the 0xc0000-0x100000 area read/writable.
-void
-make_bios_writable()
-{
-    if (CONFIG_COREBOOT)
-        return;
-
-    dprintf(3, "enabling shadow ram\n");
-
-    // Locate chip controlling ram shadowing.
-    int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
-    if (bdf < 0) {
-        dprintf(1, "Unable to unlock ram - bridge not found\n");
-        return;
-    }
-
     // Make ram from 0xc0000-0xf0000 writable
     int clear = 0;
     int i;
@@ -68,24 +48,46 @@ make_bios_writable()
     if (clear)
         memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
 
+    // Make ram from 0xf0000-0x100000 writable
     int reg = pci_config_readb(bdf, 0x59);
-    if (reg & 0x10) {
-        // Ram already present - just enable writes
-        pci_config_writeb(bdf, 0x59, 0x30);
+    pci_config_writeb(bdf, 0x59, 0x30);
+    if (reg & 0x10)
+        // Ram already present.
+        return;
+
+    // Copy bios.
+    memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE);
+}
+
+// Make the 0xc0000-0x100000 area read/writable.
+void
+make_bios_writable()
+{
+    if (CONFIG_COREBOOT)
+        return;
+
+    dprintf(3, "enabling shadow ram\n");
+
+    // Locate chip controlling ram shadowing.
+    int bdf = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441);
+    if (bdf < 0) {
+        dprintf(1, "Unable to unlock ram - bridge not found\n");
         return;
     }
 
-    // Enable shadowing and copy bios.
-    if (IN_RANGE((u32)copy_bios, BUILD_BIOS_ADDR, BUILD_BIOS_SIZE)) {
-        // Jump to shadow enable function - use the copy in the
-        // temporary storage area so that memory does not change under
-        // the executing code.
-        u32 pos = (u32)copy_bios - BUILD_BIOS_ADDR + BIOS_SRC_ADDR;
+    int reg = pci_config_readb(bdf, 0x59);
+    if (!(reg & 0x10)) {
+        // QEMU doesn't fully implement the piix shadow capabilities -
+        // if ram isn't backing the bios segment when shadowing is
+        // disabled, the code itself wont be in memory.  So, run the
+        // code from the high-memory flash location.
+        u32 pos = (u32)__make_bios_writable - BUILD_BIOS_ADDR + BIOS_SRC_ADDR;
         void (*func)(u16 bdf) = (void*)pos;
         func(bdf);
-    } else {
-        copy_bios(bdf);
+        return;
     }
+    // Ram already present - just enable writes
+    __make_bios_writable(bdf);
 }
 
 // Make the BIOS code segment area (0xf0000) read-only.
index 7dc5afcbab5d75917ccc9c61bc8e25883cd19bbc..b1d732a017082bc66323a1f882eb66a626955171 100755 (executable)
@@ -6,33 +6,56 @@
 # This file may be distributed under the terms of the GNU GPLv3 license.
 
 import sys
+import layoutrom
 
 def main():
-    # Read in symbols (that are valid)
+    # Get args
+    objinfo, rawfile, outfile = sys.argv[1:]
+
+    # Read in symbols
+    objinfofile = open(objinfo, 'rb')
+    symbols = layoutrom.parseObjDump(objinfofile)[1]
     syms = {}
-    for line in sys.stdin.readlines():
-        try:
-            addr, type, sym = line.split()
-            syms[sym] = int(addr, 16)
-        except:
-            pass
+    for name, (addr, section) in symbols.items():
+        syms[name] = addr
+
+    # Read in raw file
+    f = open(rawfile, 'rb')
+    rawdata = f.read()
+    f.close()
+    datasize = len(rawdata)
+    finalsize = 64*1024
+    if datasize > 64*1024:
+        finalsize = 128*1024
 
+    # Sanity checks
     c16e = syms['code16_end'] + 0xf0000
     f16e = syms['final_code16_end']
     if c16e != f16e:
         print "Error!  16bit code moved during linking (0x%x vs 0x%x)" % (
             c16e, f16e)
         sys.exit(1)
+    if datasize > finalsize:
+        print "Error!  Code is too big (0x%x vs 0x%x)" % (
+            datasize, finalsize)
+        sys.exit(1)
 
+    # Print statistics
     sizefree = syms['freespace_end'] - syms['freespace_start']
     size16 = syms['code16_end'] - syms['code16_start']
     size32 = syms['code32_end'] - syms['code32_start']
     totalc = size16+size32
     print "16bit size: %d" % size16
     print "32bit size: %d" % size32
-    print "Total size: %d  Free space: %d  Percent used: %.1f%%" % (
-        totalc, sizefree
-        , (totalc / float(size16+size32+sizefree)) * 100.0)
+    print "Total size: %d  Free space: %d  Percent used: %.1f%% (%dKiB rom)" % (
+        totalc, sizefree + finalsize - datasize
+        , (totalc / float(finalsize)) * 100.0
+        , finalsize / 1024)
+
+    # Write final file
+    f = open(outfile, 'wb')
+    f.write(("\0" * (finalsize - datasize)) + rawdata)
+    f.close()
 
 if __name__ == '__main__':
     main()
index 8d557bc1c74e9420adc6aa07dd5a003561122c72..da2940f9241e6df790b4de6d86ac7c24a30e50b5 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# Script to arrange sections to ensure fixed offsets.
+# Script to analyze code and arrange ld sections.
 #
 # Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
 #
@@ -7,18 +7,49 @@
 
 import sys
 
-
+# Align 'pos' to 'alignbytes' offset
 def alignpos(pos, alignbytes):
     mask = alignbytes - 1
     return (pos + mask) & ~mask
 
+# LD script headers/trailers
+COMMONHEADER = """
+/* DO NOT EDIT!  This is an autogenerated file.  See tools/layoutrom.py. */
+OUTPUT_FORMAT("elf32-i386")
+OUTPUT_ARCH("i386")
+SECTIONS
+{
+"""
+COMMONTRAILER = """
+}
+"""
+
 
 ######################################################################
 # 16bit fixed address section fitting
 ######################################################################
 
-MAXPOS = 0x10000
+# Get the maximum start position for a list of sections that end at an
+# address.
+def getSectionsStart(sections, endaddr, minalign=1):
+    totspace = 0
+    for size, align, name in sections:
+        if align > minalign:
+            minalign = align
+        totspace = alignpos(totspace, align) + size
+    return (endaddr - totspace) / minalign * minalign
+
+# Write LD script includes for the given sections
+def outSections(file, sections):
+    for size, align, name in sections:
+        file.write("*(%s)\n" % (name,))
+
+# The 16bit code can't exceed 64K of space.
+MAXPOS = 64*1024
 
+# Layout the 16bit code.  This ensures sections with fixed offset
+# requirements are placed in the correct location.  It also places the
+# 16bit code as high as possible in the f-segment.
 def doLayout16(sections, outname):
     textsections = []
     rodatasections = []
@@ -103,18 +134,6 @@ def doLayout16(sections, outname):
 #                , fitnextaddr, nextfixedaddr - fitnextaddr)
     firstfixed = fixedsections[0][0]
 
-    # Find overall start position
-    restalign = 0
-    restspace = 0
-    restsections = []
-    for section in textsections + rodatasections + datasections:
-        size, align, name = section
-        if align > restalign:
-            restalign = align
-        restspace = alignpos(restspace, align) + size
-        restsections.append(section)
-    startrest = (firstfixed - restspace) / restalign * restalign
-
     # Report stats
     total = MAXPOS-firstfixed
     slack = total - totalused
@@ -123,20 +142,23 @@ def doLayout16(sections, outname):
             firstfixed, MAXPOS, total, slack,
             (float(slack) / total) * 100.0))
 
+    # Find overall start position
+    start16 = getSectionsStart(
+        textsections + rodatasections + datasections, firstfixed)
+
     # Write header
     output = open(outname, 'wb')
-    output.write("""
+    output.write(COMMONHEADER + """
         .text16 0x%x : {
                 code16_start = ABSOLUTE(.) ;
                 freespace_end = . ;
-""" % startrest)
+""" % start16)
 
     # Write regular sections
-    for section in restsections:
-        name = section[2]
-        if rodatasections and name == rodatasections[0][2]:
-            output.write("code16_rodata = . ;\n")
-        output.write("*(%s)\n" % (name,))
+    outSections(output, textsections)
+    output.write("code16_rodata = . ;\n")
+    outSections(output, rodatasections)
+    outSections(output, datasections)
 
     # Write fixed sections
     for addr, section, extrasections in fixedsections:
@@ -150,32 +172,66 @@ def doLayout16(sections, outname):
     output.write("""
                 code16_end = ABSOLUTE(.) ;
         }
-""")
+
+        /* Discard regular data sections to force a link error if
+         * 16bit code attempts to access data not marked with VAR16
+         */
+        /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
+""" + COMMONTRAILER)
+
+    return start16
 
 
 ######################################################################
 # 32bit section outputting
 ######################################################################
 
-def outsections(file, sections, prefix):
+# Return the subset of sections with a given name prefix
+def getSectionsPrefix(sections, prefix):
     lp = len(prefix)
+    out = []
     for size, align, name in sections:
         if name[:lp] == prefix:
-            file.write("*(%s)\n" % (name,))
-
-def doLayout32(sections, outname):
+            out.append((size, align, name))
+    return out
+
+# Layout the 32bit code.  This places the code as high as possible.
+def doLayout32(sections, outname, start16):
+    start16 += 0xf0000
+    # Find sections to output
+    textsections = getSectionsPrefix(sections, '.text.')
+    rodatasections = getSectionsPrefix(sections, '.rodata')
+    datasections = getSectionsPrefix(sections, '.data.')
+    bsssections = getSectionsPrefix(sections, '.bss.')
+    start32 = getSectionsStart(
+        textsections + rodatasections + datasections + bsssections, start16, 512)
+
+    # Write sections
     output = open(outname, 'wb')
-    outsections(output, sections, '.text.')
+    output.write(COMMONHEADER + """
+        .text32 0x%x : {
+                code32_start = ABSOLUTE(.) ;
+""" % start32)
+
+    outSections(output, textsections)
     output.write("code32_rodata = . ;\n")
-    outsections(output, sections, '.rodata')
-    outsections(output, sections, '.data.')
-    outsections(output, sections, '.bss.')
+    outSections(output, rodatasections)
+    outSections(output, datasections)
+    outSections(output, bsssections)
+
+    output.write("""
+                freespace_start = . ;
+                code32_end = ABSOLUTE(.) ;
+        }
+""" + COMMONTRAILER)
 
 
 ######################################################################
 # Section garbage collection
 ######################################################################
 
+# Note required section, and recursively set all referenced sections
+# as required.
 def keepsection(name, pri, alt):
     if name in pri[3]:
         # Already kept - nothing to do.
@@ -186,15 +242,18 @@ def keepsection(name, pri, alt):
         return
     # Keep all sections that this section points to
     for symbol in relocs:
-        section = pri[1].get(symbol)
-        if section is not None and section[:9] != '.discard.':
+        addr, section = pri[1].get(symbol, (None, None))
+        if (section is not None and '*' not in section
+            and section[:9] != '.discard.'):
             keepsection(section, pri, alt)
             continue
         # Not in primary sections - it may be a cross 16/32 reference
-        section = alt[1].get(symbol)
-        if section is not None:
+        addr, section = alt[1].get(symbol, (None, None))
+        if section is not None and '*' not in section:
             keepsection(section, alt, pri)
 
+# Determine which sections are actually referenced and need to be
+# placed into the output file.
 def gc(info16, info32):
     # pri = (sections, symbols, relocs, keep sections)
     pri = (info16[0], info16[1], info16[2], [])
@@ -261,8 +320,8 @@ def parseObjDump(file):
             try:
                 section, off, symbol = line[17:].split()
                 off = int(off, 16)
-                if '*' not in section:
-                    symbols[symbol] = section
+                addr = int(line[:8], 16)
+                symbols[symbol] = addr, section
             except:
                 pass
             continue
@@ -287,8 +346,8 @@ def main():
 
     sections16, sections32 = gc(info16, info32)
 
-    doLayout16(sections16, out16)
-    doLayout32(sections32, out32)
+    start16 = doLayout16(sections16, out16)
+    doLayout32(sections32, out32, start16)
 
 if __name__ == '__main__':
     main()