xref: /optee_os/scripts/gen_ldelf_hex.py (revision 50d680c433e4eb39990fd998326d0e6164d33458)
184c0da04SRouven Czerwinski#!/usr/bin/env python3
2b8c97753SJens Wiklander# SPDX-License-Identifier: BSD-2-Clause
3b8c97753SJens Wiklander#
4b8c97753SJens Wiklander# Copyright (c) 2019, Linaro Limited
5b8c97753SJens Wiklander#
6b8c97753SJens Wiklander
7b8c97753SJens Wiklanderfrom __future__ import print_function
8b8c97753SJens Wiklanderfrom __future__ import division
9b8c97753SJens Wiklander
10b8c97753SJens Wiklanderimport argparse
11b8c97753SJens Wiklanderimport sys
127ba36df9SVolodymyr Babchuktry:
13b8c97753SJens Wiklander    from elftools.elf.elffile import ELFFile
14b8c97753SJens Wiklander    from elftools.elf.sections import SymbolTableSection
15b8c97753SJens Wiklander    from elftools.elf.constants import P_FLAGS
167ba36df9SVolodymyr Babchukexcept ImportError:
177ba36df9SVolodymyr Babchuk    print("""
187ba36df9SVolodymyr Babchuk***
197ba36df9SVolodymyr BabchukCan't find elftools module. Probably it is not installed on your system.
207ba36df9SVolodymyr BabchukYou can install this module with
217ba36df9SVolodymyr Babchuk
227ba36df9SVolodymyr Babchuk$ apt install python3-pyelftools
237ba36df9SVolodymyr Babchuk
247ba36df9SVolodymyr Babchukif you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
257ba36df9SVolodymyr Babchukyour package manager if you are using some other distribution.
267ba36df9SVolodymyr Babchuk***
277ba36df9SVolodymyr Babchuk""")
287ba36df9SVolodymyr Babchuk    raise
297ba36df9SVolodymyr Babchuk
30b8c97753SJens Wiklander
31b8c97753SJens Wiklanderdef round_up(n, m):
32b8c97753SJens Wiklander    if n == 0:
33b8c97753SJens Wiklander        return 0
34b8c97753SJens Wiklander    else:
35b8c97753SJens Wiklander        return (((n - 1) // m) + 1) * m
36b8c97753SJens Wiklander
37b8c97753SJens Wiklander
38b8c97753SJens Wiklanderdef emit_load_segments(elffile, outf):
39b8c97753SJens Wiklander    load_size = 0
40c706c244SJerome Forissier    code_size = 0
41d2fb6900SJerome Forissier    data_size = 0
42c706c244SJerome Forissier    load_segments = [s for s in elffile.iter_segments()
43c706c244SJerome Forissier                     if s['p_type'] == 'PT_LOAD']
44c706c244SJerome Forissier    prev_segment = None
45c706c244SJerome Forissier    pad = 0
46c706c244SJerome Forissier    pad_size = []
47c706c244SJerome Forissier    w_found = False
48b8c97753SJens Wiklander    n = 0
49c706c244SJerome Forissier    # Check that load segments ordered by VA have the expected layout:
50c706c244SJerome Forissier    # read only first, then read-write. Compute padding at end of each segment,
51c706c244SJerome Forissier    # 0 if none is required.
52c706c244SJerome Forissier    for segment in load_segments:
53c706c244SJerome Forissier        if prev_segment:
54c706c244SJerome Forissier            pad = segment['p_vaddr'] - (prev_segment['p_vaddr'] +
55c706c244SJerome Forissier                                        prev_segment['p_filesz'])
56d2fb6900SJerome Forissier        else:
57c706c244SJerome Forissier            if segment['p_flags'] & P_FLAGS.PF_W:
58c706c244SJerome Forissier                print('Expected RO load segment(s) first')
59b8c97753SJens Wiklander                sys.exit(1)
60c706c244SJerome Forissier        if segment['p_flags'] & P_FLAGS.PF_W:
61c706c244SJerome Forissier            if not w_found:
62c706c244SJerome Forissier                # End of RO segments, discard padding for the last one (it
63c706c244SJerome Forissier                # would just take up space in the generated C file)
64c706c244SJerome Forissier                pad = 0
65c706c244SJerome Forissier                w_found = True
66c706c244SJerome Forissier        else:
67c706c244SJerome Forissier            if w_found:
68*50d680c4SJerome Forissier                print('RO load segment found after RW one(s) (m={})'.format(n))
69b8c97753SJens Wiklander                sys.exit(1)
70c706c244SJerome Forissier        if prev_segment:
71c706c244SJerome Forissier            if pad > 31:
72c706c244SJerome Forissier                # We expect segments to be tightly packed together for memory
73c706c244SJerome Forissier                # efficiency. 31 is an arbitrary, "sounds reasonable" value
74c706c244SJerome Forissier                # which might need to be adjusted -- who knows what the
75c706c244SJerome Forissier                # compiler/linker can do.
76*50d680c4SJerome Forissier                print('Warning: suspiciously large padding ({}) after load '
77*50d680c4SJerome Forissier                      'segment {}, please check'.format(pad, n-1))
78c706c244SJerome Forissier            pad_size.append(pad)
79c706c244SJerome Forissier        prev_segment = segment
80b8c97753SJens Wiklander        n = n + 1
81c706c244SJerome Forissier    pad_size.append(0)
82c706c244SJerome Forissier    n = 0
83c706c244SJerome Forissier    # Compute code_size, data_size and load_size
84c706c244SJerome Forissier    for segment in load_segments:
85c706c244SJerome Forissier        sz = segment['p_filesz'] + pad_size[n]
86c706c244SJerome Forissier        if segment['p_flags'] & P_FLAGS.PF_W:
87c706c244SJerome Forissier            data_size += sz
88c706c244SJerome Forissier        else:
89c706c244SJerome Forissier            code_size += sz
90c706c244SJerome Forissier        load_size += sz
91c706c244SJerome Forissier        n = n + 1
92c706c244SJerome Forissier    n = 0
93c706c244SJerome Forissier    i = 0
94c706c244SJerome Forissier    # Output data to C file
9584c0da04SRouven Czerwinski    outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096))
9684c0da04SRouven Czerwinski    outf.write(b' __aligned(4096) = {\n')
97c706c244SJerome Forissier    for segment in load_segments:
98b8c97753SJens Wiklander        data = segment.data()
99c706c244SJerome Forissier        if pad_size[n]:
100c706c244SJerome Forissier            # Pad with zeros if needed
101c706c244SJerome Forissier            data += bytearray(pad_size[n])
102c706c244SJerome Forissier        for j in range(len(data)):
103b8c97753SJens Wiklander            if i % 8 == 0:
10484c0da04SRouven Czerwinski                outf.write(b'\t')
105c706c244SJerome Forissier            outf.write(b'0x' + '{:02x}'.format(data[j]).encode('utf-8')
10684c0da04SRouven Czerwinski                       + b',')
107b8c97753SJens Wiklander            i = i + 1
108b8c97753SJens Wiklander            if i % 8 == 0 or i == load_size:
10984c0da04SRouven Czerwinski                outf.write(b'\n')
110b8c97753SJens Wiklander            else:
11184c0da04SRouven Czerwinski                outf.write(b' ')
112c706c244SJerome Forissier        n = n + 1
11384c0da04SRouven Czerwinski    outf.write(b'};\n')
114b8c97753SJens Wiklander
11584c0da04SRouven Czerwinski    outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size)
11684c0da04SRouven Czerwinski    outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size)
117b8c97753SJens Wiklander
118b8c97753SJens Wiklander
119b8c97753SJens Wiklanderdef get_args():
120b8c97753SJens Wiklander    parser = argparse.ArgumentParser()
121b8c97753SJens Wiklander
122b8c97753SJens Wiklander    parser.add_argument('--input',
123b8c97753SJens Wiklander                        required=True, type=argparse.FileType('rb'),
124b8c97753SJens Wiklander                        help='The input ldelf.elf')
125b8c97753SJens Wiklander
126b8c97753SJens Wiklander    parser.add_argument('--output',
127b8c97753SJens Wiklander                        required=True, type=argparse.FileType('wb'),
128b8c97753SJens Wiklander                        help='The output ldelf_hex.c')
129b8c97753SJens Wiklander
130b8c97753SJens Wiklander    return parser.parse_args()
131b8c97753SJens Wiklander
132b8c97753SJens Wiklander
133b8c97753SJens Wiklanderdef main():
134b8c97753SJens Wiklander    args = get_args()
135b8c97753SJens Wiklander    inf = args.input
136b8c97753SJens Wiklander    outf = args.output
137b8c97753SJens Wiklander
138b8c97753SJens Wiklander    elffile = ELFFile(inf)
139b8c97753SJens Wiklander
14084c0da04SRouven Czerwinski    outf.write(b'/* Automatically generated, do no edit */\n')
14184c0da04SRouven Czerwinski    outf.write(b'#include <compiler.h>\n')
14284c0da04SRouven Czerwinski    outf.write(b'#include <stdint.h>\n')
143b8c97753SJens Wiklander    emit_load_segments(elffile, outf)
14484c0da04SRouven Czerwinski    outf.write(b'const unsigned long ldelf_entry = %lu;\n' %
145b8c97753SJens Wiklander               elffile.header['e_entry'])
146b8c97753SJens Wiklander
147b8c97753SJens Wiklander    inf.close()
148b8c97753SJens Wiklander    outf.close()
149b8c97753SJens Wiklander
150b8c97753SJens Wiklander
151b8c97753SJens Wiklanderif __name__ == "__main__":
152b8c97753SJens Wiklander    main()
153