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