xref: /optee_os/scripts/gen_ldelf_hex.py (revision c706c2449b50bbfa62528ee515a7ac07fec98769)
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
40*c706c244SJerome Forissier    code_size = 0
41d2fb6900SJerome Forissier    data_size = 0
42*c706c244SJerome Forissier    load_segments = [s for s in elffile.iter_segments()
43*c706c244SJerome Forissier                     if s['p_type'] == 'PT_LOAD']
44*c706c244SJerome Forissier    prev_segment = None
45*c706c244SJerome Forissier    pad = 0
46*c706c244SJerome Forissier    pad_size = []
47*c706c244SJerome Forissier    w_found = False
48b8c97753SJens Wiklander    n = 0
49*c706c244SJerome Forissier    # Check that load segments ordered by VA have the expected layout:
50*c706c244SJerome Forissier    # read only first, then read-write. Compute padding at end of each segment,
51*c706c244SJerome Forissier    # 0 if none is required.
52*c706c244SJerome Forissier    for segment in load_segments:
53*c706c244SJerome Forissier        if prev_segment:
54*c706c244SJerome Forissier            pad = segment['p_vaddr'] - (prev_segment['p_vaddr'] +
55*c706c244SJerome Forissier                                        prev_segment['p_filesz'])
56d2fb6900SJerome Forissier        else:
57*c706c244SJerome Forissier            if segment['p_flags'] & P_FLAGS.PF_W:
58*c706c244SJerome Forissier                print('Expected RO load segment(s) first')
59b8c97753SJens Wiklander                sys.exit(1)
60*c706c244SJerome Forissier        if segment['p_flags'] & P_FLAGS.PF_W:
61*c706c244SJerome Forissier            if not w_found:
62*c706c244SJerome Forissier                # End of RO segments, discard padding for the last one (it
63*c706c244SJerome Forissier                # would just take up space in the generated C file)
64*c706c244SJerome Forissier                pad = 0
65*c706c244SJerome Forissier                w_found = True
66*c706c244SJerome Forissier        else:
67*c706c244SJerome Forissier            if w_found:
68*c706c244SJerome Forissier                print(f'RO load segment found after RW one(s) (m={n})')
69b8c97753SJens Wiklander                sys.exit(1)
70*c706c244SJerome Forissier        if prev_segment:
71*c706c244SJerome Forissier            if pad > 31:
72*c706c244SJerome Forissier                # We expect segments to be tightly packed together for memory
73*c706c244SJerome Forissier                # efficiency. 31 is an arbitrary, "sounds reasonable" value
74*c706c244SJerome Forissier                # which might need to be adjusted -- who knows what the
75*c706c244SJerome Forissier                # compiler/linker can do.
76*c706c244SJerome Forissier                print(f'Warning: suspiciously large padding ({pad}) after '
77*c706c244SJerome Forissier                      f'load segment {n-1}, please check')
78*c706c244SJerome Forissier            pad_size.append(pad)
79*c706c244SJerome Forissier        prev_segment = segment
80b8c97753SJens Wiklander        n = n + 1
81*c706c244SJerome Forissier    pad_size.append(0)
82*c706c244SJerome Forissier    n = 0
83*c706c244SJerome Forissier    # Compute code_size, data_size and load_size
84*c706c244SJerome Forissier    for segment in load_segments:
85*c706c244SJerome Forissier        sz = segment['p_filesz'] + pad_size[n]
86*c706c244SJerome Forissier        if segment['p_flags'] & P_FLAGS.PF_W:
87*c706c244SJerome Forissier            data_size += sz
88*c706c244SJerome Forissier        else:
89*c706c244SJerome Forissier            code_size += sz
90*c706c244SJerome Forissier        load_size += sz
91*c706c244SJerome Forissier        n = n + 1
92*c706c244SJerome Forissier    n = 0
93*c706c244SJerome Forissier    i = 0
94*c706c244SJerome 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')
97*c706c244SJerome Forissier    for segment in load_segments:
98b8c97753SJens Wiklander        data = segment.data()
99*c706c244SJerome Forissier        if pad_size[n]:
100*c706c244SJerome Forissier            # Pad with zeros if needed
101*c706c244SJerome Forissier            data += bytearray(pad_size[n])
102*c706c244SJerome Forissier        for j in range(len(data)):
103b8c97753SJens Wiklander            if i % 8 == 0:
10484c0da04SRouven Czerwinski                outf.write(b'\t')
105*c706c244SJerome 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' ')
112*c706c244SJerome 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