xref: /optee_os/scripts/gen_ldelf_hex.py (revision d5204ccef40c5549b48fbd82e7c590531e718098)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2019, Linaro Limited
5#
6
7from __future__ import print_function
8from __future__ import division
9
10import argparse
11import sys
12try:
13    from elftools.elf.elffile import ELFFile
14    from elftools.elf.sections import SymbolTableSection
15    from elftools.elf.constants import P_FLAGS
16except ImportError:
17    print("""
18***
19Can't find elftools module. Probably it is not installed on your system.
20You can install this module with
21
22$ apt install python3-pyelftools
23
24if you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in
25your package manager if you are using some other distribution.
26***
27""")
28    raise
29
30
31def round_up(n, m):
32    if n == 0:
33        return 0
34    else:
35        return (((n - 1) // m) + 1) * m
36
37
38def emit_load_segments(elffile, outf):
39    load_size = 0
40    data_size = 0
41    next_rwseg_va = 0
42    n = 0
43    for segment in elffile.iter_segments():
44        if segment['p_type'] == 'PT_LOAD':
45            if n == 0:
46                if segment['p_flags'] != (P_FLAGS.PF_R | P_FLAGS.PF_X):
47                    print('Expected first load segment to be read/execute')
48                    sys.exit(1)
49                code_size = segment['p_filesz']
50            else:
51                if segment['p_flags'] != (P_FLAGS.PF_R | P_FLAGS.PF_W):
52                    print('Expected load segment to be read/write')
53                    sys.exit(1)
54                if next_rwseg_va and segment['p_vaddr'] != next_rwseg_va:
55                    print('Expected contiguous read/write segments')
56                    print(segment['p_vaddr'])
57                    print(next_rwseg_va)
58                    sys.exit(1)
59                data_size += segment['p_filesz']
60                next_rwseg_va = segment['p_vaddr'] + segment['p_filesz']
61            load_size += segment['p_filesz']
62            n = n + 1
63
64    outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096))
65    outf.write(b' __aligned(4096) = {\n')
66    i = 0
67    for segment in elffile.iter_segments():
68        if segment['p_type'] == 'PT_LOAD':
69            data = segment.data()
70            for n in range(segment['p_filesz']):
71                if i % 8 == 0:
72                    outf.write(b'\t')
73                outf.write(b'0x' + '{:02x}'.format(data[n]).encode('utf-8')
74                           + b',')
75                i = i + 1
76                if i % 8 == 0 or i == load_size:
77                    outf.write(b'\n')
78                else:
79                    outf.write(b' ')
80    outf.write(b'};\n')
81
82    outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size)
83    outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size)
84
85
86def get_args():
87    parser = argparse.ArgumentParser()
88
89    parser.add_argument('--input',
90                        required=True, type=argparse.FileType('rb'),
91                        help='The input ldelf.elf')
92
93    parser.add_argument('--output',
94                        required=True, type=argparse.FileType('wb'),
95                        help='The output ldelf_hex.c')
96
97    return parser.parse_args()
98
99
100def main():
101    args = get_args()
102    inf = args.input
103    outf = args.output
104
105    elffile = ELFFile(inf)
106
107    outf.write(b'/* Automatically generated, do no edit */\n')
108    outf.write(b'#include <compiler.h>\n')
109    outf.write(b'#include <stdint.h>\n')
110    emit_load_segments(elffile, outf)
111    outf.write(b'const unsigned long ldelf_entry = %lu;\n' %
112               elffile.header['e_entry'])
113
114    inf.close()
115    outf.close()
116
117
118if __name__ == "__main__":
119    main()
120