1#!/usr/bin/env python3 2# 3# Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 4# 5# SPDX-License-Identifier: GPL-2.0-only 6# 7""" 8Extract information of interest to the seL4 image build process from ELF files. 9 10THIS IS NOT A STABLE API. Use as a script, not a module. 11""" 12 13import argparse 14import elftools.elf.elffile 15import sys 16 17from typing import BinaryIO 18 19 20def get_aligned_size(n: int) -> int: 21 """ 22 Return the smallest multiple of 4KiB not less than the total of the loadable 23 segments. (In other words, the size will be returned as-is if it is an 24 exact multiple of 4KiB, otherwise it is rounded up to the next higher 25 multiple of 4KiB.) 26 """ 27 return n if n % 4096 == 0 else ((n // 4096) + 1) * 4096 28 29 30def get_memory_usage(elf_file: BinaryIO, align: bool) -> int: 31 """ 32 Return the size in bytes occuped in memory of the loadable ELF segments from 33 the ELF object file `elf_file`. 34 """ 35 36 total: int = 0 37 elf = elftools.elf.elffile.ELFFile(elf_file) 38 39 # We only care about loadable segments (p_type is "PT_LOAD"), and we 40 # want the size in memory of those segments (p_memsz), which can be 41 # greater than the size in the file (p_filesz). This is especially 42 # important for the BSS section. See elf(5). 43 total = sum([seg['p_memsz'] for seg in elf.iter_segments() 44 if seg['p_type'] == 'PT_LOAD']) 45 46 return get_aligned_size(total) if align else total 47 48 49def get_memory_usage_from_file(filename: str, align: bool) -> int: 50 """ 51 Return the size in bytes occuped in memory of the loadable ELF segments from 52 the ELF object file `filename`. 53 """ 54 55 with open(filename, 'rb') as f: 56 return get_memory_size(f) 57 58 59def main() -> int: 60 parser = argparse.ArgumentParser( 61 formatter_class=argparse.RawDescriptionHelpFormatter, 62 description=""" 63Extract information of interest to the seL4 image build process from ELF files. 64 65We extract the sizes of loadable ELF segments from the ELF files given as 66operands and print their sum. 67 68If the "--align" flag is specified, the space "after" each ELF file is aligned 69to the next 4KiB boundary, increasing the total. 70""") 71 parser.add_argument('elf_file', nargs='+', type=str, 72 help='ELF object file to examine') 73 parser.add_argument('--align', action='store_true', 74 help='align to 4KiB between files') 75 parser.add_argument('--reserve', metavar='BYTES', type=int, action='store', 76 default=0, help='number of additional bytes to reserve') 77 args = parser.parse_args() 78 regions = [get_memory_usage_from_file(elf, args.align) 79 for elf in args.elf_file] 80 regions.append(args.reserve) 81 total = sum(regions) 82 83 if args.align: 84 total = get_aligned_size(total) 85 86 print(total) 87 return 0 88 89 90if __name__ == '__main__': 91 sys.exit(main()) 92