Simplify build by manually resolving external symbols in layoutrom.py.

Enhance tools/layoutrom.py to explicitly set those symbols that
resolve to a different code chunk (eg, 16, 32seg, 32flat).  This
eliminates the need to link the code chunks multiple times.

This patch reduces the dependency on binutils behavior and makes the
build simpler to understand.
This commit is contained in:
Kevin O'Connor 2010-05-01 09:50:13 -04:00
parent 698d3f92c2
commit 9ba1deaceb
7 changed files with 302 additions and 352 deletions

View File

@ -100,6 +100,9 @@ endef
endif
endif
%.strip.o: %.o
@echo " Stripping $@"
$(Q)$(STRIP) $< -o $@
$(OUT)%.s: %.c
@echo " Compiling to assembler $@"
@ -135,27 +138,17 @@ $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds $(OUT)c
$(Q)./tools/layoutrom.py $(OUT)code16.o.objdump $(OUT)code32seg.o.objdump $(OUT)code32flat.o.objdump $(OUT)romlayout16.lds $(OUT)romlayout32seg.lds $(OUT)romlayout32flat.lds
$(OUT)rom16.o: $(OUT)code16.o $(OUT)rom32flat.o $(OUT)romlayout16.lds
@echo " Linking (no relocs) $@"
$(Q)$(LD) -r -T $(OUT)romlayout16.lds $< -o $@
$(OUT)rom16.o: $(OUT)code16.o $(OUT)romlayout16.lds
@echo " Linking $@"
$(Q)$(LD) -T $(OUT)romlayout16.lds $< -o $@
$(OUT)rom32seg.o: $(OUT)code32seg.o $(OUT)romlayout32seg.lds
@echo " Linking (no relocs) $@"
$(Q)$(LD) -r -T $(OUT)romlayout32seg.lds $< -o $@
$(OUT)rom32flat.o: $(OUT)code32flat.o $(OUT)romlayout32flat.lds
@echo " Linking (no relocs) $@"
$(Q)$(LD) -r -T $(OUT)romlayout32flat.lds $< -o $@
$(OUT)rom.o: $(OUT)rom16.o $(OUT)rom32seg.o $(OUT)rom32flat.o $(OUT)rombios16.lds $(OUT)rombios32seg.lds $(OUT)rombios.lds
@echo " Linking $@"
$(Q)$(LD) -T $(OUT)rombios16.lds $(OUT)rom16.o -R $(OUT)rom32seg.o -R $(OUT)rom32flat.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)rombios32seg.lds $(OUT)rom32seg.o -R $(OUT)rom16.o -R $(OUT)rom32flat.o -o $(OUT)rom32seg.reloc.o
$(Q)$(STRIP) $(OUT)rom32seg.reloc.o -o $(OUT)rom32seg.final.o
$(Q)$(OBJCOPY) --adjust-vma 0xf0000 $(OUT)rom32seg.o $(OUT)rom32seg.moved.o
$(Q)$(LD) -T $(OUT)rombios.lds $(OUT)rom16.final.o $(OUT)rom32seg.final.o $(OUT)rom32flat.o -R $(OUT)rom16.moved.o -R $(OUT)rom32seg.moved.o -o $@
$(Q)$(LD) -T $(OUT)romlayout32seg.lds $< -o $@
$(OUT)rom.o: $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o $(OUT)romlayout32flat.lds
@echo " Linking $@"
$(Q)$(LD) -T $(OUT)romlayout32flat.lds $(OUT)rom16.strip.o $(OUT)rom32seg.strip.o $(OUT)code32flat.o -o $@
$(OUT)bios.bin.elf $(OUT)bios.bin: $(OUT)rom.o tools/checkrom.py
@echo " Prepping $@"

View File

@ -1,34 +0,0 @@
// Linker definitions for merging 16 and 32 bit 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")
OUTPUT_ARCH("i386")
ENTRY(post32)
PHDRS
{
text PT_LOAD AT ( code32flat_start ) ;
}
SECTIONS
{
.text code32flat_start : {
*(.text32flat)
. = code32seg_start + BUILD_BIOS_ADDR - code32flat_start ;
*(.text32seg)
. = data16_start + BUILD_BIOS_ADDR - code32flat_start ;
*(.data16)
. = text16_start + BUILD_BIOS_ADDR - code32flat_start ;
*(.text16)
final_text16_end = . ;
} :text
/DISCARD/ : {
*(.text*) *(.data*) *(.bss*) *(.rodata*)
*(COMMON) *(.discard*) *(.eh_frame)
}
}

View File

@ -1,21 +0,0 @@
// Linker definitions for 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.
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH("i386")
PHDRS
{
}
SECTIONS
{
.data16 data16_start : {
*(.data16)
}
.text16 text16_start : {
*(.text16)
}
/DISCARD/ : { *(.discard*) }
}

View File

@ -1,18 +0,0 @@
// Linker definitions for 32bit segmented code
//
// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH("i386")
PHDRS
{
}
SECTIONS
{
.text32seg code32seg_start : {
*(.text32seg)
}
/DISCARD/ : { *(.discard*) }
}

View File

@ -29,34 +29,27 @@ def main():
finalsize = 128*1024
# Sanity checks
c16e = syms['text16_end'] + 0xf0000
f16e = syms['final_text16_end']
if c16e != f16e:
print "Error! 16bit code moved during linking (0x%x vs 0x%x)" % (
c16e, f16e)
start = syms['code32flat_start']
end = syms['code32flat_end']
expend = layoutrom.BUILD_BIOS_ADDR + layoutrom.BUILD_BIOS_SIZE
if end != expend:
print "Error! Code does not end at 0x%x (got 0x%x)" % (
expend, end)
sys.exit(1)
if datasize > finalsize:
print "Error! Code is too big (0x%x vs 0x%x)" % (
datasize, finalsize)
sys.exit(1)
actualdatasize = f16e - syms['code32flat_start']
if datasize != actualdatasize:
expdatasize = end - start
if datasize != expdatasize:
print "Error! Unknown extra data (0x%x vs 0x%x)" % (
datasize, actualdatasize)
datasize, expdatasize)
sys.exit(1)
# Print statistics
sizefree = syms['freespace_end'] - syms['freespace_start']
size16 = syms['text16_end'] - syms['data16_start']
size32seg = syms['code32seg_end'] - syms['code32seg_start']
size32flat = syms['code32flat_end'] - syms['code32flat_start']
totalc = size16+size32seg+size32flat
print "16bit size: %d" % size16
print "32bit segmented size: %d" % size32seg
print "32bit flat size: %d" % size32flat
print "Total size: %d Free space: %d Percent used: %.1f%% (%dKiB rom)" % (
totalc, sizefree + finalsize - datasize
, (totalc / float(finalsize)) * 100.0
datasize, finalsize - datasize
, (datasize / float(finalsize)) * 100.0
, finalsize / 1024)
# Write final file

View File

@ -7,7 +7,7 @@
# This file may be distributed under the terms of the GNU GPLv3 license.
# Usage:
# objdump -m i386 -M i8086 -M suffix -d out/rom16.reloc.o | tools/checkstack.py
# objdump -m i386 -M i8086 -M suffix -d out/rom16.o | tools/checkstack.py
import sys
import re

View File

@ -7,11 +7,6 @@
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. */
@ -21,15 +16,29 @@ SECTIONS
{
"""
COMMONTRAILER = """
/* Discard regular data sections to force a link error if
* code attempts to access data not marked with VAR16 (or other
* appropriate macro)
*/
/DISCARD/ : {
*(.text*) *(.data*) *(.bss*) *(.rodata*)
*(COMMON) *(.discard*) *(.eh_frame)
}
}
"""
######################################################################
# 16bit fixed address section fitting
# Determine section locations
######################################################################
# Get the maximum start position for a list of sections that end at an
# Align 'pos' to 'alignbytes' offset
def alignpos(pos, alignbytes):
mask = alignbytes - 1
return (pos + mask) & ~mask
# Determine the final addresses for a list of sections that end at an
# address.
def getSectionsStart(sections, endaddr, minalign=1):
totspace = 0
@ -37,157 +46,16 @@ def getSectionsStart(sections, endaddr, minalign=1):
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 = []
datasections = []
# fixedsections = [(addr, sectioninfo, extasectionslist), ...]
fixedsections = []
# canrelocate = [(sectioninfo, list), ...]
canrelocate = []
# Find desired sections.
for section in sections:
size, align, name = section
if name[:11] == '.fixedaddr.':
addr = int(name[11:], 16)
fixedsections.append((addr, section, []))
if align != 1:
print "Error: Fixed section %s has non-zero alignment (%d)" % (
name, align)
sys.exit(1)
if name[:6] == '.text.':
textsections.append(section)
canrelocate.append((section, textsections))
if name[:17] == '.rodata.__func__.' or name == '.rodata.str1.1':
rodatasections.append(section)
#canrelocate.append((section, rodatasections))
if name[:8] == '.data16.':
datasections.append(section)
#canrelocate.append((section, datasections))
# Find freespace in fixed address area
fixedsections.sort()
# fixedAddr = [(freespace, sectioninfo), ...]
fixedAddr = []
for i in range(len(fixedsections)):
fixedsectioninfo = fixedsections[i]
addr, section, extrasectionslist = fixedsectioninfo
if i == len(fixedsections) - 1:
nextaddr = MAXPOS
else:
nextaddr = fixedsections[i+1][0]
avail = nextaddr - addr - section[0]
fixedAddr.append((avail, fixedsectioninfo))
# Attempt to fit other sections into fixed area
fixedAddr.sort()
canrelocate.sort()
totalused = 0
for freespace, fixedsectioninfo in fixedAddr:
fixedaddr, fixedsection, extrasections = fixedsectioninfo
addpos = fixedaddr + fixedsection[0]
totalused += fixedsection[0]
nextfixedaddr = addpos + freespace
# print "Filling section %x uses %d, next=%x, available=%d" % (
# fixedaddr, fixedsection[0], nextfixedaddr, freespace)
while 1:
canfit = None
for fixedaddrinfo in canrelocate:
fitsection, inlist = fixedaddrinfo
fitsize, fitalign, fitname = fitsection
if addpos + fitsize > nextfixedaddr:
# Can't fit and nothing else will fit.
break
fitnextaddr = alignpos(addpos, fitalign) + fitsize
# print "Test %s - %x vs %x" % (
# fitname, fitnextaddr, nextfixedaddr)
if fitnextaddr > nextfixedaddr:
# This item can't fit.
continue
canfit = (fitnextaddr, fixedaddrinfo)
if canfit is None:
break
# Found a section that can fit.
fitnextaddr, fixedaddrinfo = canfit
canrelocate.remove(fixedaddrinfo)
fitsection, inlist = fixedaddrinfo
inlist.remove(fitsection)
extrasections.append(fitsection)
addpos = fitnextaddr
totalused += fitsection[0]
# 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 = MAXPOS-firstfixed
slack = total - totalused
print ("Fixed space: 0x%x-0x%x total: %d slack: %d"
" Percent slack: %.1f%%" % (
firstfixed, MAXPOS, total, slack,
(float(slack) / total) * 100.0))
# Find start positions
text16_start = getSectionsStart(textsections, firstfixed)
data16_start = getSectionsStart(rodatasections + datasections, text16_start)
# Write header and regular sections
output = open(outname, 'wb')
output.write(COMMONHEADER + """
data16_start = 0x%x ;
.data16 data16_start : {
""" % data16_start)
outSections(output, datasections)
output.write("code16_rodata = . ;\n")
outSections(output, rodatasections)
output.write("""
}
text16_start = 0x%x ;
.text16 text16_start : {
""" % text16_start)
outSections(output, textsections)
# Write fixed sections
for addr, section, extrasections in fixedsections:
name = section[2]
output.write(". = ( 0x%x - text16_start ) ;\n" % (addr,))
output.write("*(%s)\n" % (name,))
for extrasection in extrasections:
output.write("*(%s)\n" % (extrasection[2],))
# Write trailer
output.write("""
text16_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 data16_start
######################################################################
# 32bit section outputting
######################################################################
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):
@ -198,87 +66,241 @@ def getSectionsPrefix(sections, prefix):
out.append((size, align, name))
return out
# The 16bit code can't exceed 64K of space.
BUILD_BIOS_ADDR = 0xf0000
BUILD_BIOS_SIZE = 0x10000
# 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 fitSections(sections, fillsections):
canrelocate = list(fillsections)
# fixedsections = [(addr, sectioninfo), ...]
fixedsections = []
for sectioninfo in sections:
size, align, name = sectioninfo
if name[:11] == '.fixedaddr.':
addr = int(name[11:], 16)
fixedsections.append((addr, sectioninfo))
if align != 1:
print "Error: Fixed section %s has non-zero alignment (%d)" % (
name, align)
sys.exit(1)
# Find freespace in fixed address area
fixedsections.sort()
# fixedAddr = [(freespace, sectioninfo), ...]
fixedAddr = []
for i in range(len(fixedsections)):
fixedsectioninfo = fixedsections[i]
addr, section = fixedsectioninfo
if i == len(fixedsections) - 1:
nextaddr = BUILD_BIOS_SIZE
else:
nextaddr = fixedsections[i+1][0]
avail = nextaddr - addr - section[0]
fixedAddr.append((avail, fixedsectioninfo))
# Attempt to fit other sections into fixed area
extrasections = []
fixedAddr.sort()
canrelocate.sort()
totalused = 0
for freespace, fixedsectioninfo in fixedAddr:
fixedaddr, fixedsection = fixedsectioninfo
addpos = fixedaddr + fixedsection[0]
totalused += fixedsection[0]
nextfixedaddr = addpos + freespace
# print "Filling section %x uses %d, next=%x, available=%d" % (
# fixedaddr, fixedsection[0], nextfixedaddr, freespace)
while 1:
canfit = None
for fitsection in canrelocate:
fitsize, fitalign, fitname = fitsection
if addpos + fitsize > nextfixedaddr:
# Can't fit and nothing else will fit.
break
fitnextaddr = alignpos(addpos, fitalign) + fitsize
# print "Test %s - %x vs %x" % (
# fitname, fitnextaddr, nextfixedaddr)
if fitnextaddr > nextfixedaddr:
# This item can't fit.
continue
canfit = (fitnextaddr, fitsection)
if canfit is None:
break
# Found a section that can fit.
fitnextaddr, fitsection = canfit
canrelocate.remove(fitsection)
extrasections.append((addpos, fitsection))
addpos = fitnextaddr
totalused += fitsection[0]
# 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
slack = total - totalused
print ("Fixed space: 0x%x-0x%x total: %d slack: %d"
" Percent slack: %.1f%%" % (
firstfixed, BUILD_BIOS_SIZE, total, slack,
(float(slack) / total) * 100.0))
return fixedsections + extrasections, firstfixed
def doLayout(sections16, sections32seg, sections32flat):
# 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()
# Determine 32seg positions
textsections = getSectionsPrefix(sections32seg, '.text.')
rodatasections = (getSectionsPrefix(sections32seg, '.rodata.str1.1')
+ getSectionsPrefix(sections32seg, '.rodata.__func__.'))
datasections = getSectionsPrefix(sections32seg, '.data32seg.')
locs32seg, code32seg_start = getSectionsStart(
textsections + rodatasections + datasections, code16_start)
# Determine 32flat positions
textsections = getSectionsPrefix(sections32flat, '.text.')
rodatasections = getSectionsPrefix(sections32flat, '.rodata')
datasections = getSectionsPrefix(sections32flat, '.data.')
bsssections = getSectionsPrefix(sections32flat, '.bss.')
locs32flat, code32flat_start = getSectionsStart(
textsections + rodatasections + datasections + bsssections
, code32seg_start + BUILD_BIOS_ADDR, 16)
# Print statistics
size16 = BUILD_BIOS_SIZE - code16_start
size32seg = code16_start - code32seg_start
size32flat = code32seg_start + BUILD_BIOS_ADDR - code32flat_start
print "16bit size: %d" % size16
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):
out = ""
for symbol, (fileid, section, addr) in xrefs.items():
if fileid < 2:
addr += delta
out += "%s = 0x%x ;\n" % (symbol, finallocs[(fileid, section)] + addr)
return out
# Write LD script includes for the given sections using relative offsets
def outRelSections(locs, startsym):
out = ""
for addr, sectioninfo in locs:
size, align, name = sectioninfo
out += ". = ( 0x%x - %s ) ;\n" % (addr, startsym)
if name == '.rodata.str1.1':
out += "_rodata = . ;\n"
out += "*(%s)\n" % (name,)
return out
# Layout the 32bit segmented code. This places the code as high as possible.
def doLayout32seg(sections, outname, endat):
# Find sections to output
textsections = getSectionsPrefix(sections, '.text.')
rodatasections = (getSectionsPrefix(sections, '.rodata.str1.1')
+ getSectionsPrefix(sections, '.rodata.__func__.'))
datasections = getSectionsPrefix(sections, '.data32seg.')
startat = getSectionsStart(
textsections + rodatasections + datasections, endat)
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
# Write sections
output = open(outname, 'wb')
output.write(COMMONHEADER + """
code32seg_start = 0x%x ;
.text32seg code32seg_start : {
freespace_end = . ;
""" % startat)
# Write 16bit linker script
code16_start = locs16[0][0]
output = open(out16, 'wb')
output.write(COMMONHEADER + outXRefs(xref16, finallocs) + """
code16_start = 0x%x ;
.text16 code16_start : {
""" % (code16_start)
+ outRelSections(locs16, 'code16_start')
+ """
}
"""
+ COMMONTRAILER)
output.close()
outSections(output, textsections)
output.write("code32seg_rodata = . ;\n")
outSections(output, rodatasections)
outSections(output, datasections)
# Write 32seg linker script
code32seg_start = code16_start
if locs32seg:
code32seg_start = locs32seg[0][0]
output = open(out32seg, 'wb')
output.write(COMMONHEADER + outXRefs(xref32seg, finallocs) + """
code32seg_start = 0x%x ;
.text32seg code32seg_start : {
""" % (code32seg_start)
+ outRelSections(locs32seg, 'code32seg_start')
+ """
}
"""
+ COMMONTRAILER)
output.close()
output.write("""
code32seg_end = ABSOLUTE(.) ;
}
/DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
""" + COMMONTRAILER)
return startat
# Layout the 32bit flat code. This places the code as high as possible.
def doLayout32flat(sections, outname, endat):
endat += 0xf0000
# Find sections to output
textsections = getSectionsPrefix(sections, '.text.')
rodatasections = getSectionsPrefix(sections, '.rodata')
datasections = getSectionsPrefix(sections, '.data.')
bsssections = getSectionsPrefix(sections, '.bss.')
startat = getSectionsStart(
textsections + rodatasections + datasections + bsssections, endat, 512)
# Write sections
output = open(outname, 'wb')
output.write(COMMONHEADER + """
code32flat_start = 0x%x ;
.text32flat code32flat_start : {
""" % startat)
outSections(output, textsections)
output.write("code32_rodata = . ;\n")
outSections(output, rodatasections)
outSections(output, datasections)
outSections(output, bsssections)
output.write("""
freespace_start = . ;
code32flat_end = ABSOLUTE(.) ;
}
""" + COMMONTRAILER)
return startat
# Write 32flat linker script
output = open(out32flat, 'wb')
output.write(COMMONHEADER
+ outXRefs(xref32flat, finallocs, BUILD_BIOS_ADDR) + """
code32flat_start = 0x%x ;
.text code32flat_start : {
""" % (locs32flat[0][0])
+ outRelSections(locs32flat, 'code32flat_start')
+ """
. = ( 0x%x - code32flat_start ) ;
*(.text32seg)
. = ( 0x%x - code32flat_start ) ;
*(.text16)
code32flat_end = ABSOLUTE(.) ;
} :text
""" % (code32seg_start + BUILD_BIOS_ADDR, code16_start + BUILD_BIOS_ADDR)
+ COMMONTRAILER
+ """
ENTRY(post32)
PHDRS
{
text PT_LOAD AT ( code32flat_start ) ;
}
""")
output.close()
######################################################################
# Section garbage collection
######################################################################
def getSectionsList(info, names):
out = []
for i in info[0]:
size, align, section = i
if section not in names:
# print "gc", section
continue
out.append(i)
return out
# Find and keep the section associated with a symbol (if available).
def keepsymbol(symbol, infos, pos):
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[:9] == '.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)
return 0
@ -298,29 +320,34 @@ def keepsection(name, infos, pos=0):
if not ret:
continue
# Not in primary sections - it may be a cross 16/32 reference
ret = keepsymbol(symbol, infos, (pos+1)%3)
ret = keepsymbol(symbol, infos, (pos+1)%3, pos)
if not ret:
continue
ret = keepsymbol(symbol, infos, (pos+2)%3)
ret = keepsymbol(symbol, infos, (pos+2)%3, pos)
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), ...)
infos = ((info16[0], info16[1], info16[2], []),
(info32seg[0], info32seg[1], info32seg[2], []),
(info32flat[0], info32flat[1], info32flat[2], []))
# 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], [], {}))
# Start by keeping sections that are globally visible.
for size, align, section in info16[0]:
if section[:11] == '.fixedaddr.' or '.export.' in section:
keepsection(section, infos)
keepsymbol('post32', infos, 0, 2)
# Return sections found.
sections16 = getSectionsList(info16, infos[0][3])
sections32seg = getSectionsList(info32seg, infos[1][3])
sections32flat = getSectionsList(info32flat, infos[2][3])
return sections16, sections32seg, sections32flat
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
######################################################################
@ -331,7 +358,7 @@ def gc(info16, info32seg, info32flat):
def parseObjDump(file):
# sections = [(size, align, section), ...]
sections = []
# symbols[symbol] = section
# symbols[symbol] = (addr, section)
symbols = {}
# relocs[section] = [symbol, ...]
relocs = {}
@ -361,8 +388,8 @@ def parseObjDump(file):
continue
if state == 'symbol':
try:
section, off, symbol = line[17:].split()
off = int(off, 16)
section, size, symbol = line[17:].split()
size = int(size, 16)
addr = int(line[:8], 16)
symbols[symbol] = addr, section
except:
@ -381,19 +408,29 @@ def main():
# Get output name
in16, in32seg, in32flat, out16, out32seg, out32flat = sys.argv[1:]
# Read in the objdump information
infile16 = open(in16, 'rb')
infile32seg = open(in32seg, 'rb')
infile32flat = open(in32flat, 'rb')
# infoX = (sections, symbols, relocs)
info16 = parseObjDump(infile16)
info32seg = parseObjDump(infile32seg)
info32flat = parseObjDump(infile32flat)
sections16, sections32seg, sections32flat = gc(info16, info32seg, info32flat)
# Figure out which sections to keep.
# keepX = (sections, xrefs)
keep16, keep32seg, keep32flat = gc(info16, info32seg, info32flat)
start16 = doLayout16(sections16, out16)
start32seg = doLayout32seg(sections32seg, out32seg, start16)
doLayout32flat(sections32flat, out32flat, start32seg)
# Determine the final memory locations of each kept section.
# locsX = [(addr, sectioninfo), ...]
locs16, locs32seg, locs32flat = doLayout(
keep16[0], keep32seg[0], keep32flat[0])
# Write out linker script files.
writeLinkerScripts(locs16, locs32seg, locs32flat
, keep16[1], keep32seg[1], keep32flat[1]
, out16, out32seg, out32flat)
if __name__ == '__main__':
main()