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