Annotation of qemu/roms/seabios/tools/layoutrom.py, revision 1.1

1.1     ! root        1: #!/usr/bin/env python
        !             2: # Script to analyze code and arrange ld sections.
        !             3: #
        !             4: # Copyright (C) 2008  Kevin O'Connor <[email protected]>
        !             5: #
        !             6: # This file may be distributed under the terms of the GNU GPLv3 license.
        !             7: 
        !             8: import sys
        !             9: 
        !            10: # Align 'pos' to 'alignbytes' offset
        !            11: def alignpos(pos, alignbytes):
        !            12:     mask = alignbytes - 1
        !            13:     return (pos + mask) & ~mask
        !            14: 
        !            15: # LD script headers/trailers
        !            16: COMMONHEADER = """
        !            17: /* DO NOT EDIT!  This is an autogenerated file.  See tools/layoutrom.py. */
        !            18: OUTPUT_FORMAT("elf32-i386")
        !            19: OUTPUT_ARCH("i386")
        !            20: SECTIONS
        !            21: {
        !            22: """
        !            23: COMMONTRAILER = """
        !            24: }
        !            25: """
        !            26: 
        !            27: 
        !            28: ######################################################################
        !            29: # 16bit fixed address section fitting
        !            30: ######################################################################
        !            31: 
        !            32: # Get the maximum start position for a list of sections that end at an
        !            33: # address.
        !            34: def getSectionsStart(sections, endaddr, minalign=1):
        !            35:     totspace = 0
        !            36:     for size, align, name in sections:
        !            37:         if align > minalign:
        !            38:             minalign = align
        !            39:         totspace = alignpos(totspace, align) + size
        !            40:     return (endaddr - totspace) / minalign * minalign
        !            41: 
        !            42: # Write LD script includes for the given sections
        !            43: def outSections(file, sections):
        !            44:     for size, align, name in sections:
        !            45:         file.write("*(%s)\n" % (name,))
        !            46: 
        !            47: # The 16bit code can't exceed 64K of space.
        !            48: MAXPOS = 64*1024
        !            49: 
        !            50: # Layout the 16bit code.  This ensures sections with fixed offset
        !            51: # requirements are placed in the correct location.  It also places the
        !            52: # 16bit code as high as possible in the f-segment.
        !            53: def doLayout16(sections, outname):
        !            54:     textsections = []
        !            55:     rodatasections = []
        !            56:     datasections = []
        !            57:     # fixedsections = [(addr, sectioninfo, extasectionslist), ...]
        !            58:     fixedsections = []
        !            59:     # canrelocate = [(sectioninfo, list), ...]
        !            60:     canrelocate = []
        !            61: 
        !            62:     # Find desired sections.
        !            63:     for section in sections:
        !            64:         size, align, name = section
        !            65:         if name[:11] == '.fixedaddr.':
        !            66:             addr = int(name[11:], 16)
        !            67:             fixedsections.append((addr, section, []))
        !            68:             if align != 1:
        !            69:                 print "Error: Fixed section %s has non-zero alignment (%d)" % (
        !            70:                     name, align)
        !            71:                 sys.exit(1)
        !            72:         if name[:6] == '.text.':
        !            73:             textsections.append(section)
        !            74:             canrelocate.append((section, textsections))
        !            75:         if name[:17] == '.rodata.__func__.' or name == '.rodata.str1.1':
        !            76:             rodatasections.append(section)
        !            77:             #canrelocate.append((section, rodatasections))
        !            78:         if name[:8] == '.data16.':
        !            79:             datasections.append(section)
        !            80:             #canrelocate.append((section, datasections))
        !            81: 
        !            82:     # Find freespace in fixed address area
        !            83:     fixedsections.sort()
        !            84:     # fixedAddr = [(freespace, sectioninfo), ...]
        !            85:     fixedAddr = []
        !            86:     for i in range(len(fixedsections)):
        !            87:         fixedsectioninfo = fixedsections[i]
        !            88:         addr, section, extrasectionslist = fixedsectioninfo
        !            89:         if i == len(fixedsections) - 1:
        !            90:             nextaddr = MAXPOS
        !            91:         else:
        !            92:             nextaddr = fixedsections[i+1][0]
        !            93:         avail = nextaddr - addr - section[0]
        !            94:         fixedAddr.append((avail, fixedsectioninfo))
        !            95: 
        !            96:     # Attempt to fit other sections into fixed area
        !            97:     fixedAddr.sort()
        !            98:     canrelocate.sort()
        !            99:     totalused = 0
        !           100:     for freespace, fixedsectioninfo in fixedAddr:
        !           101:         fixedaddr, fixedsection, extrasections = fixedsectioninfo
        !           102:         addpos = fixedaddr + fixedsection[0]
        !           103:         totalused += fixedsection[0]
        !           104:         nextfixedaddr = addpos + freespace
        !           105: #        print "Filling section %x uses %d, next=%x, available=%d" % (
        !           106: #            fixedaddr, fixedsection[0], nextfixedaddr, freespace)
        !           107:         while 1:
        !           108:             canfit = None
        !           109:             for fixedaddrinfo in canrelocate:
        !           110:                 fitsection, inlist = fixedaddrinfo
        !           111:                 fitsize, fitalign, fitname = fitsection
        !           112:                 if addpos + fitsize > nextfixedaddr:
        !           113:                     # Can't fit and nothing else will fit.
        !           114:                     break
        !           115:                 fitnextaddr = alignpos(addpos, fitalign) + fitsize
        !           116: #                print "Test %s - %x vs %x" % (
        !           117: #                    fitname, fitnextaddr, nextfixedaddr)
        !           118:                 if fitnextaddr > nextfixedaddr:
        !           119:                     # This item can't fit.
        !           120:                     continue
        !           121:                 canfit = (fitnextaddr, fixedaddrinfo)
        !           122:             if canfit is None:
        !           123:                 break
        !           124:             # Found a section that can fit.
        !           125:             fitnextaddr, fixedaddrinfo = canfit
        !           126:             canrelocate.remove(fixedaddrinfo)
        !           127:             fitsection, inlist = fixedaddrinfo
        !           128:             inlist.remove(fitsection)
        !           129:             extrasections.append(fitsection)
        !           130:             addpos = fitnextaddr
        !           131:             totalused += fitsection[0]
        !           132: #            print "    Adding %s (size %d align %d) pos=%x avail=%d" % (
        !           133: #                fitsection[2], fitsection[0], fitsection[1]
        !           134: #                , fitnextaddr, nextfixedaddr - fitnextaddr)
        !           135:     firstfixed = fixedsections[0][0]
        !           136: 
        !           137:     # Report stats
        !           138:     total = MAXPOS-firstfixed
        !           139:     slack = total - totalused
        !           140:     print ("Fixed space: 0x%x-0x%x  total: %d  slack: %d"
        !           141:            "  Percent slack: %.1f%%" % (
        !           142:             firstfixed, MAXPOS, total, slack,
        !           143:             (float(slack) / total) * 100.0))
        !           144: 
        !           145:     # Find overall start position
        !           146:     start16 = getSectionsStart(
        !           147:         textsections + rodatasections + datasections, firstfixed)
        !           148: 
        !           149:     # Write header
        !           150:     output = open(outname, 'wb')
        !           151:     output.write(COMMONHEADER + """
        !           152:         .text16 0x%x : {
        !           153:                 code16_start = ABSOLUTE(.) ;
        !           154:                 freespace_end = . ;
        !           155: """ % start16)
        !           156: 
        !           157:     # Write regular sections
        !           158:     outSections(output, textsections)
        !           159:     output.write("code16_rodata = . ;\n")
        !           160:     outSections(output, rodatasections)
        !           161:     outSections(output, datasections)
        !           162: 
        !           163:     # Write fixed sections
        !           164:     for addr, section, extrasections in fixedsections:
        !           165:         name = section[2]
        !           166:         output.write(". = ( 0x%x - code16_start ) ;\n" % (addr,))
        !           167:         output.write("*(%s)\n" % (name,))
        !           168:         for extrasection in extrasections:
        !           169:             output.write("*(%s)\n" % (extrasection[2],))
        !           170: 
        !           171:     # Write trailer
        !           172:     output.write("""
        !           173:                 code16_end = ABSOLUTE(.) ;
        !           174:         }
        !           175: 
        !           176:         /* Discard regular data sections to force a link error if
        !           177:          * 16bit code attempts to access data not marked with VAR16
        !           178:          */
        !           179:         /DISCARD/ : { *(.text*) *(.rodata*) *(.data*) *(.bss*) *(COMMON) }
        !           180: """ + COMMONTRAILER)
        !           181: 
        !           182:     return start16
        !           183: 
        !           184: 
        !           185: ######################################################################
        !           186: # 32bit section outputting
        !           187: ######################################################################
        !           188: 
        !           189: # Return the subset of sections with a given name prefix
        !           190: def getSectionsPrefix(sections, prefix):
        !           191:     lp = len(prefix)
        !           192:     out = []
        !           193:     for size, align, name in sections:
        !           194:         if name[:lp] == prefix:
        !           195:             out.append((size, align, name))
        !           196:     return out
        !           197: 
        !           198: # Layout the 32bit code.  This places the code as high as possible.
        !           199: def doLayout32(sections, outname, start16):
        !           200:     start16 += 0xf0000
        !           201:     # Find sections to output
        !           202:     textsections = getSectionsPrefix(sections, '.text.')
        !           203:     rodatasections = getSectionsPrefix(sections, '.rodata')
        !           204:     datasections = getSectionsPrefix(sections, '.data.')
        !           205:     bsssections = getSectionsPrefix(sections, '.bss.')
        !           206:     start32 = getSectionsStart(
        !           207:         textsections + rodatasections + datasections + bsssections, start16, 512)
        !           208: 
        !           209:     # Write sections
        !           210:     output = open(outname, 'wb')
        !           211:     output.write(COMMONHEADER + """
        !           212:         .text32 0x%x : {
        !           213:                 code32_start = ABSOLUTE(.) ;
        !           214: """ % start32)
        !           215: 
        !           216:     outSections(output, textsections)
        !           217:     output.write("code32_rodata = . ;\n")
        !           218:     outSections(output, rodatasections)
        !           219:     outSections(output, datasections)
        !           220:     outSections(output, bsssections)
        !           221: 
        !           222:     output.write("""
        !           223:                 freespace_start = . ;
        !           224:                 code32_end = ABSOLUTE(.) ;
        !           225:         }
        !           226: """ + COMMONTRAILER)
        !           227: 
        !           228: 
        !           229: ######################################################################
        !           230: # Section garbage collection
        !           231: ######################################################################
        !           232: 
        !           233: # Note required section, and recursively set all referenced sections
        !           234: # as required.
        !           235: def keepsection(name, pri, alt):
        !           236:     if name in pri[3]:
        !           237:         # Already kept - nothing to do.
        !           238:         return
        !           239:     pri[3].append(name)
        !           240:     relocs = pri[2].get(name)
        !           241:     if relocs is None:
        !           242:         return
        !           243:     # Keep all sections that this section points to
        !           244:     for symbol in relocs:
        !           245:         addr, section = pri[1].get(symbol, (None, None))
        !           246:         if (section is not None and '*' not in section
        !           247:             and section[:9] != '.discard.'):
        !           248:             keepsection(section, pri, alt)
        !           249:             continue
        !           250:         # Not in primary sections - it may be a cross 16/32 reference
        !           251:         addr, section = alt[1].get(symbol, (None, None))
        !           252:         if section is not None and '*' not in section:
        !           253:             keepsection(section, alt, pri)
        !           254: 
        !           255: # Determine which sections are actually referenced and need to be
        !           256: # placed into the output file.
        !           257: def gc(info16, info32):
        !           258:     # pri = (sections, symbols, relocs, keep sections)
        !           259:     pri = (info16[0], info16[1], info16[2], [])
        !           260:     alt = (info32[0], info32[1], info32[2], [])
        !           261:     # Start by keeping sections that are globally visible.
        !           262:     for size, align, section in info16[0]:
        !           263:         if section[:11] == '.fixedaddr.' or '.export.' in section:
        !           264:             keepsection(section, pri, alt)
        !           265:     # Return sections found.
        !           266:     sections16 = []
        !           267:     for info in info16[0]:
        !           268:         size, align, section = info
        !           269:         if section not in pri[3]:
        !           270: #            print "gc16", section
        !           271:             continue
        !           272:         sections16.append(info)
        !           273:     sections32 = []
        !           274:     for info in info32[0]:
        !           275:         size, align, section = info
        !           276:         if section not in alt[3]:
        !           277: #            print "gc32", section
        !           278:             continue
        !           279:         sections32.append(info)
        !           280:     return sections16, sections32
        !           281: 
        !           282: 
        !           283: ######################################################################
        !           284: # Startup and input parsing
        !           285: ######################################################################
        !           286: 
        !           287: # Read in output from objdump
        !           288: def parseObjDump(file):
        !           289:     # sections = [(size, align, section), ...]
        !           290:     sections = []
        !           291:     # symbols[symbol] = section
        !           292:     symbols = {}
        !           293:     # relocs[section] = [symbol, ...]
        !           294:     relocs = {}
        !           295: 
        !           296:     state = None
        !           297:     for line in file.readlines():
        !           298:         line = line.rstrip()
        !           299:         if line == 'Sections:':
        !           300:             state = 'section'
        !           301:             continue
        !           302:         if line == 'SYMBOL TABLE:':
        !           303:             state = 'symbol'
        !           304:             continue
        !           305:         if line[:24] == 'RELOCATION RECORDS FOR [':
        !           306:             state = 'reloc'
        !           307:             relocsection = line[24:-2]
        !           308:             continue
        !           309: 
        !           310:         if state == 'section':
        !           311:             try:
        !           312:                 idx, name, size, vma, lma, fileoff, align = line.split()
        !           313:                 if align[:3] != '2**':
        !           314:                     continue
        !           315:                 sections.append((int(size, 16), 2**int(align[3:]), name))
        !           316:             except:
        !           317:                 pass
        !           318:             continue
        !           319:         if state == 'symbol':
        !           320:             try:
        !           321:                 section, off, symbol = line[17:].split()
        !           322:                 off = int(off, 16)
        !           323:                 addr = int(line[:8], 16)
        !           324:                 symbols[symbol] = addr, section
        !           325:             except:
        !           326:                 pass
        !           327:             continue
        !           328:         if state == 'reloc':
        !           329:             try:
        !           330:                 off, type, symbol = line.split()
        !           331:                 off = int(off, 16)
        !           332:                 relocs.setdefault(relocsection, []).append(symbol)
        !           333:             except:
        !           334:                 pass
        !           335:     return sections, symbols, relocs
        !           336: 
        !           337: def main():
        !           338:     # Get output name
        !           339:     in16, in32, out16, out32 = sys.argv[1:]
        !           340: 
        !           341:     infile16 = open(in16, 'rb')
        !           342:     infile32 = open(in32, 'rb')
        !           343: 
        !           344:     info16 = parseObjDump(infile16)
        !           345:     info32 = parseObjDump(infile32)
        !           346: 
        !           347:     sections16, sections32 = gc(info16, info32)
        !           348: 
        !           349:     start16 = doLayout16(sections16, out16)
        !           350:     doLayout32(sections32, out32, start16)
        !           351: 
        !           352: if __name__ == '__main__':
        !           353:     main()

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.