xref: /optee_os/scripts/gen_ldelf_hex.py (revision 5a913ee74d3c71af2a2860ce8a4e7aeab2916f9b)
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
30import struct
31import re
32from collections import deque
33
34
35def round_up(n, m):
36    if n == 0:
37        return 0
38    else:
39        return (((n - 1) // m) + 1) * m
40
41
42def emit_load_segments(elffile, outf):
43    load_size = 0
44    data_size = 0
45    next_rwseg_va = 0
46    n = 0
47    for segment in elffile.iter_segments():
48        if segment['p_type'] == 'PT_LOAD':
49            if n == 0:
50                if segment['p_flags'] != (P_FLAGS.PF_R | P_FLAGS.PF_X):
51                    print('Expected first load segment to be read/execute')
52                    sys.exit(1)
53                code_size = segment['p_filesz']
54            else:
55                if segment['p_flags'] != (P_FLAGS.PF_R | P_FLAGS.PF_W):
56                    print('Expected load segment to be read/write')
57                    sys.exit(1)
58                if next_rwseg_va and segment['p_vaddr'] != next_rwseg_va:
59                    print('Expected contiguous read/write segments')
60                    print(segment['p_vaddr'])
61                    print(next_rwseg_va)
62                    sys.exit(1)
63                data_size += segment['p_filesz']
64                next_rwseg_va = segment['p_vaddr'] + segment['p_filesz']
65            load_size += segment['p_filesz']
66            n = n + 1
67
68    outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096))
69    outf.write(b' __aligned(4096) = {\n')
70    i = 0
71    for segment in elffile.iter_segments():
72        if segment['p_type'] == 'PT_LOAD':
73            data = segment.data()
74            for n in range(segment['p_filesz']):
75                if i % 8 == 0:
76                    outf.write(b'\t')
77                outf.write(b'0x' + '{:02x}'.format(data[n]).encode('utf-8')
78                           + b',')
79                i = i + 1
80                if i % 8 == 0 or i == load_size:
81                    outf.write(b'\n')
82                else:
83                    outf.write(b' ')
84    outf.write(b'};\n')
85
86    outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size)
87    outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size)
88
89
90def get_args():
91    parser = argparse.ArgumentParser()
92
93    parser.add_argument('--input',
94                        required=True, type=argparse.FileType('rb'),
95                        help='The input ldelf.elf')
96
97    parser.add_argument('--output',
98                        required=True, type=argparse.FileType('wb'),
99                        help='The output ldelf_hex.c')
100
101    return parser.parse_args()
102
103
104def main():
105    args = get_args()
106    inf = args.input
107    outf = args.output
108
109    elffile = ELFFile(inf)
110
111    outf.write(b'/* Automatically generated, do no edit */\n')
112    outf.write(b'#include <compiler.h>\n')
113    outf.write(b'#include <stdint.h>\n')
114    emit_load_segments(elffile, outf)
115    outf.write(b'const unsigned long ldelf_entry = %lu;\n' %
116               elffile.header['e_entry'])
117
118    inf.close()
119    outf.close()
120
121
122if __name__ == "__main__":
123    main()
124