|
|
|
@ -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()
|
|
|
|
|