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