xref: /optee_os/scripts/gen_ldelf_hex.py (revision 15e14f8ff549038cea7fb0b9ea2cd1602d0292c4)
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:
6850d680c4SJerome 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.
7650d680c4SJerome Forissier                print('Warning: suspiciously large padding ({}) after load '
7750d680c4SJerome Forissier                      'segment {}, please check'.format(pad, n-1))
78c706c244SJerome Forissier            pad_size.append(pad)
79c706c244SJerome Forissier        prev_segment = segment
80b8c97753SJens Wiklander        n = n + 1
81*15e14f8fSAleksandr Iashchenko    # Last padding is actual memsz and filesz difference
82*15e14f8fSAleksandr Iashchenko    # The .bss section may typically be here
83*15e14f8fSAleksandr Iashchenko    last_pad = segment['p_memsz'] - segment['p_filesz']
84*15e14f8fSAleksandr Iashchenko    pad_size.append(last_pad)
85c706c244SJerome Forissier    n = 0
86c706c244SJerome Forissier    # Compute code_size, data_size and load_size
87c706c244SJerome Forissier    for segment in load_segments:
88c706c244SJerome Forissier        sz = segment['p_filesz'] + pad_size[n]
89c706c244SJerome Forissier        if segment['p_flags'] & P_FLAGS.PF_W:
90c706c244SJerome Forissier            data_size += sz
91c706c244SJerome Forissier        else:
92c706c244SJerome Forissier            code_size += sz
93c706c244SJerome Forissier        load_size += sz
94c706c244SJerome Forissier        n = n + 1
95c706c244SJerome Forissier    n = 0
96c706c244SJerome Forissier    i = 0
97c706c244SJerome Forissier    # Output data to C file
9884c0da04SRouven Czerwinski    outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096))
9984c0da04SRouven Czerwinski    outf.write(b' __aligned(4096) = {\n')
100c706c244SJerome Forissier    for segment in load_segments:
101b8c97753SJens Wiklander        data = segment.data()
102c706c244SJerome Forissier        if pad_size[n]:
103c706c244SJerome Forissier            # Pad with zeros if needed
104c706c244SJerome Forissier            data += bytearray(pad_size[n])
105c706c244SJerome Forissier        for j in range(len(data)):
106b8c97753SJens Wiklander            if i % 8 == 0:
10784c0da04SRouven Czerwinski                outf.write(b'\t')
108c706c244SJerome Forissier            outf.write(b'0x' + '{:02x}'.format(data[j]).encode('utf-8')
10984c0da04SRouven Czerwinski                       + b',')
110b8c97753SJens Wiklander            i = i + 1
111b8c97753SJens Wiklander            if i % 8 == 0 or i == load_size:
11284c0da04SRouven Czerwinski                outf.write(b'\n')
113b8c97753SJens Wiklander            else:
11484c0da04SRouven Czerwinski                outf.write(b' ')
115c706c244SJerome Forissier        n = n + 1
11684c0da04SRouven Czerwinski    outf.write(b'};\n')
117b8c97753SJens Wiklander
11884c0da04SRouven Czerwinski    outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size)
11984c0da04SRouven Czerwinski    outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size)
120b8c97753SJens Wiklander
121b8c97753SJens Wiklander
122b8c97753SJens Wiklanderdef get_args():
123b8c97753SJens Wiklander    parser = argparse.ArgumentParser()
124b8c97753SJens Wiklander
125b8c97753SJens Wiklander    parser.add_argument('--input',
126b8c97753SJens Wiklander                        required=True, type=argparse.FileType('rb'),
127b8c97753SJens Wiklander                        help='The input ldelf.elf')
128b8c97753SJens Wiklander
129b8c97753SJens Wiklander    parser.add_argument('--output',
130b8c97753SJens Wiklander                        required=True, type=argparse.FileType('wb'),
131b8c97753SJens Wiklander                        help='The output ldelf_hex.c')
132b8c97753SJens Wiklander
133b8c97753SJens Wiklander    return parser.parse_args()
134b8c97753SJens Wiklander
135b8c97753SJens Wiklander
136b8c97753SJens Wiklanderdef main():
137b8c97753SJens Wiklander    args = get_args()
138b8c97753SJens Wiklander    inf = args.input
139b8c97753SJens Wiklander    outf = args.output
140b8c97753SJens Wiklander
141b8c97753SJens Wiklander    elffile = ELFFile(inf)
142b8c97753SJens Wiklander
14384c0da04SRouven Czerwinski    outf.write(b'/* Automatically generated, do no edit */\n')
14484c0da04SRouven Czerwinski    outf.write(b'#include <compiler.h>\n')
14584c0da04SRouven Czerwinski    outf.write(b'#include <stdint.h>\n')
146b8c97753SJens Wiklander    emit_load_segments(elffile, outf)
14784c0da04SRouven Czerwinski    outf.write(b'const unsigned long ldelf_entry = %lu;\n' %
148b8c97753SJens Wiklander               elffile.header['e_entry'])
149b8c97753SJens Wiklander
150b8c97753SJens Wiklander    inf.close()
151b8c97753SJens Wiklander    outf.close()
152b8c97753SJens Wiklander
153b8c97753SJens Wiklander
154b8c97753SJens Wiklanderif __name__ == "__main__":
155b8c97753SJens Wiklander    main()
156