blob: 76d505068ff24810b4bd4a17c879fc15515a077b [file] [log] [blame]
Rupert Swarbrick4a500042020-07-20 15:39:16 +01001#!/usr/bin/env python3
2# Copyright lowRISC contributors.
3# Licensed under the Apache License, Version 2.0, see LICENSE for details.
4# SPDX-License-Identifier: Apache-2.0
Rupert Swarbrick4a500042020-07-20 15:39:16 +01005'''A wrapper around riscv32-unknown-elf-ld for OTBN
6
7This just adds the OTBN linker script and calls the underlying
8linker.'''
9
10import os
11import subprocess
12import sys
Rupert Swarbrickb2381352020-07-24 15:55:04 +010013import tempfile
Timothy Trippela7b30e62022-04-20 16:26:09 -070014from contextlib import contextmanager
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010015from typing import Iterator, List, Optional
Rupert Swarbrickb2381352020-07-24 15:55:04 +010016
Rupert Swarbrickb2381352020-07-24 15:55:04 +010017from mako import exceptions # type: ignore
Timothy Trippela7b30e62022-04-20 16:26:09 -070018from mako.template import Template # type: ignore
Rupert Swarbrickb2381352020-07-24 15:55:04 +010019
Rupert Swarbrickb1ed9a92020-08-03 17:01:26 +010020from shared.mem_layout import get_memory_layout
Rupert Swarbrick823343f2020-08-17 14:43:59 +010021from shared.toolchain import find_tool
Rupert Swarbrickb2381352020-07-24 15:55:04 +010022
23
24def interpolate_linker_script(in_path: str, out_path: str) -> None:
Rupert Swarbrickb1ed9a92020-08-03 17:01:26 +010025 mems = get_memory_layout()
Rupert Swarbrick95356802021-10-26 13:12:31 +010026 imem_lma, imem_length = mems['IMEM']
27 dmem_lma, dmem_bus_length = mems['DMEM']
28
29 dmem_length = dmem_bus_length * 2
Rupert Swarbrickb2381352020-07-24 15:55:04 +010030
31 try:
32 template = Template(filename=in_path)
Rupert Swarbrick95356802021-10-26 13:12:31 +010033 rendered = template.render(imem_lma=imem_lma,
34 imem_length=imem_length,
35 dmem_lma=dmem_lma,
36 dmem_length=dmem_length,
37 dmem_bus_length=dmem_bus_length)
Rupert Swarbrickb2381352020-07-24 15:55:04 +010038 except OSError as err:
39 raise RuntimeError(str(err)) from None
40 except: # noqa: 722
41 raise RuntimeError(exceptions.text_error_template().render()) from None
42
43 try:
44 with open(out_path, 'w') as out_file:
45 out_file.write(rendered)
46 except FileNotFoundError:
Timothy Trippela7b30e62022-04-20 16:26:09 -070047 raise RuntimeError(
48 'Failed to open output file at {!r}.'.format(out_path)) from None
Rupert Swarbrick4a500042020-07-20 15:39:16 +010049
50
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010051@contextmanager
52def mk_linker_script() -> Iterator[str]:
Timothy Trippela7b30e62022-04-20 16:26:09 -070053 ld_in = os.path.abspath(
54 os.path.join(os.path.dirname(__file__), '..', 'data', 'otbn.ld.tpl'))
Rupert Swarbrickb2381352020-07-24 15:55:04 +010055 with tempfile.TemporaryDirectory(prefix='otbn-ld-') as tmpdir:
56 ld_out = os.path.join(tmpdir, 'otbn.ld')
57 try:
58 interpolate_linker_script(ld_in, ld_out)
59 except RuntimeError as err:
Timothy Trippela7b30e62022-04-20 16:26:09 -070060 sys.stderr.write(
61 'Failed to interpolate linker script: {}\n'.format(err))
Rupert Swarbrickb2381352020-07-24 15:55:04 +010062 return 1
63
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010064 yield ld_out
65
66
67def run_ld(ld_script: Optional[str], args: List[str]) -> int:
68 '''Run the underlying linker and return the status code'''
Rupert Swarbrick823343f2020-08-17 14:43:59 +010069 ld_name = find_tool('ld')
Rupert Swarbrickc02c22e2020-11-18 08:02:45 +000070 # The --no-check-sections argument tells ld not to complain when we have
71 # more than one section with the same VMA. Since we have a Harvard
72 # architecture where data and instructions both start at zero, we expect
73 # that to happen.
74 cmd = [ld_name, '--no-check-sections']
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010075 if ld_script is not None:
76 cmd.append('--script={}'.format(ld_script))
77 cmd += args
78
79 try:
80 return subprocess.run(cmd).returncode
81 except FileNotFoundError:
Timothy Trippela7b30e62022-04-20 16:26:09 -070082 sys.stderr.write(
83 'Unknown command: {!r}. '
84 '(is it installed and on your PATH?)\n'.format(ld_name))
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010085 return 127
86
87
Timothy Trippela7b30e62022-04-20 16:26:09 -070088def main(argv: List[str]) -> int:
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010089 # Only add the --script argument if the caller isn't supplying one
90 # themselves. This argument accumulates (so -T foo -T bar is like
91 # concatenating foo and bar), so we mustn't supply our own if the user
92 # has one.
93 needs_script = True
Timothy Trippela7b30e62022-04-20 16:26:09 -070094 for arg in argv[1:]:
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +010095 if arg == '-T' or arg.startswith('--script='):
96 needs_script = False
97 break
98
99 if needs_script:
100 with mk_linker_script() as script_path:
Timothy Trippela7b30e62022-04-20 16:26:09 -0700101 return run_ld(script_path, argv[1:])
Rupert Swarbrick0d0b2dc2020-08-17 17:35:22 +0100102 else:
Timothy Trippela7b30e62022-04-20 16:26:09 -0700103 return run_ld(None, argv[1:])
Rupert Swarbrick4a500042020-07-20 15:39:16 +0100104
105
106if __name__ == '__main__':
Timothy Trippela7b30e62022-04-20 16:26:09 -0700107 sys.exit(main(sys.argv))