synth/tools/ld.py

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='Assemble.')
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()