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