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 code_size = 0 41 data_size = 0 42 load_segments = [s for s in elffile.iter_segments() 43 if s['p_type'] == 'PT_LOAD'] 44 prev_segment = None 45 pad = 0 46 pad_size = [] 47 w_found = False 48 n = 0 49 # Check that load segments ordered by VA have the expected layout: 50 # read only first, then read-write. Compute padding at end of each segment, 51 # 0 if none is required. 52 for segment in load_segments: 53 if prev_segment: 54 pad = segment['p_vaddr'] - (prev_segment['p_vaddr'] + 55 prev_segment['p_filesz']) 56 else: 57 if segment['p_flags'] & P_FLAGS.PF_W: 58 print('Expected RO load segment(s) first') 59 sys.exit(1) 60 if segment['p_flags'] & P_FLAGS.PF_W: 61 if not w_found: 62 # End of RO segments, discard padding for the last one (it 63 # would just take up space in the generated C file) 64 pad = 0 65 w_found = True 66 else: 67 if w_found: 68 print('RO load segment found after RW one(s) (m={})'.format(n)) 69 sys.exit(1) 70 if prev_segment: 71 if pad > 31: 72 # We expect segments to be tightly packed together for memory 73 # efficiency. 31 is an arbitrary, "sounds reasonable" value 74 # which might need to be adjusted -- who knows what the 75 # compiler/linker can do. 76 print('Warning: suspiciously large padding ({}) after load ' 77 'segment {}, please check'.format(pad, n-1)) 78 pad_size.append(pad) 79 prev_segment = segment 80 n = n + 1 81 pad_size.append(0) 82 n = 0 83 # Compute code_size, data_size and load_size 84 for segment in load_segments: 85 sz = segment['p_filesz'] + pad_size[n] 86 if segment['p_flags'] & P_FLAGS.PF_W: 87 data_size += sz 88 else: 89 code_size += sz 90 load_size += sz 91 n = n + 1 92 n = 0 93 i = 0 94 # Output data to C file 95 outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096)) 96 outf.write(b' __aligned(4096) = {\n') 97 for segment in load_segments: 98 data = segment.data() 99 if pad_size[n]: 100 # Pad with zeros if needed 101 data += bytearray(pad_size[n]) 102 for j in range(len(data)): 103 if i % 8 == 0: 104 outf.write(b'\t') 105 outf.write(b'0x' + '{:02x}'.format(data[j]).encode('utf-8') 106 + b',') 107 i = i + 1 108 if i % 8 == 0 or i == load_size: 109 outf.write(b'\n') 110 else: 111 outf.write(b' ') 112 n = n + 1 113 outf.write(b'};\n') 114 115 outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size) 116 outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size) 117 118 119def get_args(): 120 parser = argparse.ArgumentParser() 121 122 parser.add_argument('--input', 123 required=True, type=argparse.FileType('rb'), 124 help='The input ldelf.elf') 125 126 parser.add_argument('--output', 127 required=True, type=argparse.FileType('wb'), 128 help='The output ldelf_hex.c') 129 130 return parser.parse_args() 131 132 133def main(): 134 args = get_args() 135 inf = args.input 136 outf = args.output 137 138 elffile = ELFFile(inf) 139 140 outf.write(b'/* Automatically generated, do no edit */\n') 141 outf.write(b'#include <compiler.h>\n') 142 outf.write(b'#include <stdint.h>\n') 143 emit_load_segments(elffile, outf) 144 outf.write(b'const unsigned long ldelf_entry = %lu;\n' % 145 elffile.header['e_entry']) 146 147 inf.close() 148 outf.close() 149 150 151if __name__ == "__main__": 152 main() 153