110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			110 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import argparse
 | |
| import os
 | |
| import string
 | |
| import struct
 | |
| import sys
 | |
| 
 | |
| import obj_pb2
 | |
| 
 | |
| _HERE = os.path.dirname(__file__)
 | |
| CRT0_FILE = os.path.join(_HERE, 'ctr0.o')
 | |
| 
 | |
| 
 | |
| def parse_objs(objs):
 | |
|     sections = []
 | |
|     relocs = []
 | |
| 
 | |
|     for obj in objs:
 | |
|         of = obj_pb2.ObjFile()
 | |
|         of.ParseFromString(obj.read())
 | |
|         sections += of.sections
 | |
|         relocs += of.relocs
 | |
| 
 | |
|     return sections, relocs
 | |
| 
 | |
| 
 | |
| def map_sections(sections, offset=0):
 | |
|     secmap = []
 | |
| 
 | |
|     addr = offset
 | |
| 
 | |
|     # _start goes first
 | |
|     for sec in sections:
 | |
|         if sec.name == '_start':
 | |
|             secmap.append((addr, sec))
 | |
|             addr += len(sec.text)
 | |
|             sections.remove(sec)
 | |
|             break
 | |
|     assert secmap, "could not find symbol _start :/"
 | |
| 
 | |
|     for sec in sections:
 | |
|         secmap.append((addr, sec))
 | |
|         addr += len(sec.text)
 | |
| 
 | |
|     return secmap
 | |
| 
 | |
| 
 | |
| def do_relocs(secmap, relocs):
 | |
|     namemap = {s[1].name: s for s in secmap}
 | |
|     for reloc in relocs:
 | |
|         assert reloc.section in namemap
 | |
|         assert reloc.target in namemap
 | |
|         _, sec = namemap[reloc.section]
 | |
|         # the reloc hex should look like /e.ff0000/
 | |
|         buff = bytearray(sec.text)
 | |
|         target_addr = namemap[reloc.target][0]
 | |
|         reg = buff[reloc.offset] & 0xf
 | |
|         buff[reloc.offset+0:reloc.offset+4] = [
 | |
|                 0xe0 | reg, (target_addr >> 0) & 0xff,
 | |
|                 0x90 | reg, (target_addr >> 8) & 0xff,
 | |
|                 ]
 | |
|         sec.text = bytes(buff)
 | |
| 
 | |
| 
 | |
| def dump(secmap):
 | |
|     out = bytearray()
 | |
|     for _, sec in secmap:
 | |
|         out += sec.text
 | |
|     return out
 | |
| 
 | |
| 
 | |
| def parse_args():
 | |
|     parser = argparse.ArgumentParser(description='Link.')
 | |
|     parser.add_argument('--debug', action='store_true',
 | |
|                         help='print debug info')
 | |
|     parser.add_argument('objfiles', metavar='O', nargs='+',
 | |
|                         type=argparse.FileType('rb'),
 | |
|                         help='input file (default: stdin)')
 | |
|     parser.add_argument('--output', '-o', type=argparse.FileType('wb'),
 | |
|                         default=sys.stdout.buffer, help='output file')
 | |
|     parser.add_argument('--vhdl', help='vhdl output with given template')
 | |
|     parser.add_argument('--offset', default=0, type=int,
 | |
|                         help='memory offset to link from')
 | |
|     return parser.parse_args()
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     args = parse_args()
 | |
| 
 | |
|     with open(CRT0_FILE, 'rb') as crt0:
 | |
|         sections, relocs = parse_objs(args.objfiles + [crt0])
 | |
| 
 | |
|     sectionmap = map_sections(sections, offset=args.offset)
 | |
|     do_relocs(sectionmap, relocs)
 | |
|     text = dump(sectionmap)
 | |
| 
 | |
|     if args.vhdl:
 | |
|         words = struct.unpack(f'>{len(text) // 2}H', text)
 | |
|         subd = dict(words=',\n'.join(f'x"{w:04x}"' for w in words), nwords=len(words))
 | |
| 
 | |
|         with open(args.vhdl) as fin:
 | |
|             tpl = string.Template(fin.read())
 | |
|         args.output.write(tpl.substitute(subd).encode())
 | |
| 
 | |
|     else:
 | |
|         args.output.write(text)
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |