184c0da04SRouven Czerwinski#!/usr/bin/env python3 2b8c97753SJens Wiklander# SPDX-License-Identifier: BSD-2-Clause 3b8c97753SJens Wiklander# 4b8c97753SJens Wiklander# Copyright (c) 2019, Linaro Limited 5b8c97753SJens Wiklander# 6b8c97753SJens Wiklander 7b8c97753SJens Wiklanderfrom __future__ import print_function 8b8c97753SJens Wiklanderfrom __future__ import division 9b8c97753SJens Wiklander 10b8c97753SJens Wiklanderimport argparse 11b8c97753SJens Wiklanderimport sys 127ba36df9SVolodymyr Babchuktry: 13b8c97753SJens Wiklander from elftools.elf.elffile import ELFFile 14b8c97753SJens Wiklander from elftools.elf.sections import SymbolTableSection 15b8c97753SJens Wiklander from elftools.elf.constants import P_FLAGS 167ba36df9SVolodymyr Babchukexcept ImportError: 177ba36df9SVolodymyr Babchuk print(""" 187ba36df9SVolodymyr Babchuk*** 197ba36df9SVolodymyr BabchukCan't find elftools module. Probably it is not installed on your system. 207ba36df9SVolodymyr BabchukYou can install this module with 217ba36df9SVolodymyr Babchuk 227ba36df9SVolodymyr Babchuk$ apt install python3-pyelftools 237ba36df9SVolodymyr Babchuk 247ba36df9SVolodymyr Babchukif you are using Ubuntu. Or try to search for "pyelftools" or "elftools" in 257ba36df9SVolodymyr Babchukyour package manager if you are using some other distribution. 267ba36df9SVolodymyr Babchuk*** 277ba36df9SVolodymyr Babchuk""") 287ba36df9SVolodymyr Babchuk raise 297ba36df9SVolodymyr Babchuk 30b8c97753SJens Wiklander 31b8c97753SJens Wiklanderdef round_up(n, m): 32b8c97753SJens Wiklander if n == 0: 33b8c97753SJens Wiklander return 0 34b8c97753SJens Wiklander else: 35b8c97753SJens Wiklander return (((n - 1) // m) + 1) * m 36b8c97753SJens Wiklander 37b8c97753SJens Wiklander 38b8c97753SJens Wiklanderdef emit_load_segments(elffile, outf): 39b8c97753SJens Wiklander load_size = 0 40*c706c244SJerome Forissier code_size = 0 41d2fb6900SJerome Forissier data_size = 0 42*c706c244SJerome Forissier load_segments = [s for s in elffile.iter_segments() 43*c706c244SJerome Forissier if s['p_type'] == 'PT_LOAD'] 44*c706c244SJerome Forissier prev_segment = None 45*c706c244SJerome Forissier pad = 0 46*c706c244SJerome Forissier pad_size = [] 47*c706c244SJerome Forissier w_found = False 48b8c97753SJens Wiklander n = 0 49*c706c244SJerome Forissier # Check that load segments ordered by VA have the expected layout: 50*c706c244SJerome Forissier # read only first, then read-write. Compute padding at end of each segment, 51*c706c244SJerome Forissier # 0 if none is required. 52*c706c244SJerome Forissier for segment in load_segments: 53*c706c244SJerome Forissier if prev_segment: 54*c706c244SJerome Forissier pad = segment['p_vaddr'] - (prev_segment['p_vaddr'] + 55*c706c244SJerome Forissier prev_segment['p_filesz']) 56d2fb6900SJerome Forissier else: 57*c706c244SJerome Forissier if segment['p_flags'] & P_FLAGS.PF_W: 58*c706c244SJerome Forissier print('Expected RO load segment(s) first') 59b8c97753SJens Wiklander sys.exit(1) 60*c706c244SJerome Forissier if segment['p_flags'] & P_FLAGS.PF_W: 61*c706c244SJerome Forissier if not w_found: 62*c706c244SJerome Forissier # End of RO segments, discard padding for the last one (it 63*c706c244SJerome Forissier # would just take up space in the generated C file) 64*c706c244SJerome Forissier pad = 0 65*c706c244SJerome Forissier w_found = True 66*c706c244SJerome Forissier else: 67*c706c244SJerome Forissier if w_found: 68*c706c244SJerome Forissier print(f'RO load segment found after RW one(s) (m={n})') 69b8c97753SJens Wiklander sys.exit(1) 70*c706c244SJerome Forissier if prev_segment: 71*c706c244SJerome Forissier if pad > 31: 72*c706c244SJerome Forissier # We expect segments to be tightly packed together for memory 73*c706c244SJerome Forissier # efficiency. 31 is an arbitrary, "sounds reasonable" value 74*c706c244SJerome Forissier # which might need to be adjusted -- who knows what the 75*c706c244SJerome Forissier # compiler/linker can do. 76*c706c244SJerome Forissier print(f'Warning: suspiciously large padding ({pad}) after ' 77*c706c244SJerome Forissier f'load segment {n-1}, please check') 78*c706c244SJerome Forissier pad_size.append(pad) 79*c706c244SJerome Forissier prev_segment = segment 80b8c97753SJens Wiklander n = n + 1 81*c706c244SJerome Forissier pad_size.append(0) 82*c706c244SJerome Forissier n = 0 83*c706c244SJerome Forissier # Compute code_size, data_size and load_size 84*c706c244SJerome Forissier for segment in load_segments: 85*c706c244SJerome Forissier sz = segment['p_filesz'] + pad_size[n] 86*c706c244SJerome Forissier if segment['p_flags'] & P_FLAGS.PF_W: 87*c706c244SJerome Forissier data_size += sz 88*c706c244SJerome Forissier else: 89*c706c244SJerome Forissier code_size += sz 90*c706c244SJerome Forissier load_size += sz 91*c706c244SJerome Forissier n = n + 1 92*c706c244SJerome Forissier n = 0 93*c706c244SJerome Forissier i = 0 94*c706c244SJerome Forissier # Output data to C file 9584c0da04SRouven Czerwinski outf.write(b'const uint8_t ldelf_data[%d]' % round_up(load_size, 4096)) 9684c0da04SRouven Czerwinski outf.write(b' __aligned(4096) = {\n') 97*c706c244SJerome Forissier for segment in load_segments: 98b8c97753SJens Wiklander data = segment.data() 99*c706c244SJerome Forissier if pad_size[n]: 100*c706c244SJerome Forissier # Pad with zeros if needed 101*c706c244SJerome Forissier data += bytearray(pad_size[n]) 102*c706c244SJerome Forissier for j in range(len(data)): 103b8c97753SJens Wiklander if i % 8 == 0: 10484c0da04SRouven Czerwinski outf.write(b'\t') 105*c706c244SJerome Forissier outf.write(b'0x' + '{:02x}'.format(data[j]).encode('utf-8') 10684c0da04SRouven Czerwinski + b',') 107b8c97753SJens Wiklander i = i + 1 108b8c97753SJens Wiklander if i % 8 == 0 or i == load_size: 10984c0da04SRouven Czerwinski outf.write(b'\n') 110b8c97753SJens Wiklander else: 11184c0da04SRouven Czerwinski outf.write(b' ') 112*c706c244SJerome Forissier n = n + 1 11384c0da04SRouven Czerwinski outf.write(b'};\n') 114b8c97753SJens Wiklander 11584c0da04SRouven Czerwinski outf.write(b'const unsigned int ldelf_code_size = %d;\n' % code_size) 11684c0da04SRouven Czerwinski outf.write(b'const unsigned int ldelf_data_size = %d;\n' % data_size) 117b8c97753SJens Wiklander 118b8c97753SJens Wiklander 119b8c97753SJens Wiklanderdef get_args(): 120b8c97753SJens Wiklander parser = argparse.ArgumentParser() 121b8c97753SJens Wiklander 122b8c97753SJens Wiklander parser.add_argument('--input', 123b8c97753SJens Wiklander required=True, type=argparse.FileType('rb'), 124b8c97753SJens Wiklander help='The input ldelf.elf') 125b8c97753SJens Wiklander 126b8c97753SJens Wiklander parser.add_argument('--output', 127b8c97753SJens Wiklander required=True, type=argparse.FileType('wb'), 128b8c97753SJens Wiklander help='The output ldelf_hex.c') 129b8c97753SJens Wiklander 130b8c97753SJens Wiklander return parser.parse_args() 131b8c97753SJens Wiklander 132b8c97753SJens Wiklander 133b8c97753SJens Wiklanderdef main(): 134b8c97753SJens Wiklander args = get_args() 135b8c97753SJens Wiklander inf = args.input 136b8c97753SJens Wiklander outf = args.output 137b8c97753SJens Wiklander 138b8c97753SJens Wiklander elffile = ELFFile(inf) 139b8c97753SJens Wiklander 14084c0da04SRouven Czerwinski outf.write(b'/* Automatically generated, do no edit */\n') 14184c0da04SRouven Czerwinski outf.write(b'#include <compiler.h>\n') 14284c0da04SRouven Czerwinski outf.write(b'#include <stdint.h>\n') 143b8c97753SJens Wiklander emit_load_segments(elffile, outf) 14484c0da04SRouven Czerwinski outf.write(b'const unsigned long ldelf_entry = %lu;\n' % 145b8c97753SJens Wiklander elffile.header['e_entry']) 146b8c97753SJens Wiklander 147b8c97753SJens Wiklander inf.close() 148b8c97753SJens Wiklander outf.close() 149b8c97753SJens Wiklander 150b8c97753SJens Wiklander 151b8c97753SJens Wiklanderif __name__ == "__main__": 152b8c97753SJens Wiklander main() 153