Initial commit
This commit is contained in:
100
tools/ld.py
Normal file
100
tools/ld.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import argparse
|
||||
import struct
|
||||
import sys
|
||||
|
||||
import obj_pb2
|
||||
|
||||
CRT0_FILE = '/home/paulmathieu/vhdl/bin/crt0.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):
|
||||
secmap = []
|
||||
|
||||
addr = 0
|
||||
|
||||
# _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] = [
|
||||
0xf0 | 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', action='store_true',
|
||||
help='vhdl output')
|
||||
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)
|
||||
do_relocs(sectionmap, relocs)
|
||||
text = dump(sectionmap)
|
||||
|
||||
if args.vhdl:
|
||||
args.output.write(',\n'.join(f'x"{x:04x}"' for x in
|
||||
struct.unpack(f'>{len(text) // 2}H', text)).encode())
|
||||
else:
|
||||
args.output.write(text)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user