123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- #!/usr/bin/env python3
- #
- # Copyright (c) 2021 Intel Corporation
- #
- # SPDX-License-Identifier: Apache-2.0
- """
- Process ELF file to generate placeholders for kobject
- hash table and lookup functions produced by gperf,
- since their sizes depend on how many kobjects have
- been declared. The output header files will be used
- during linking for intermediate output binaries so
- that the addresses of these kobjects would remain
- the same during later stages of linking.
- """
- import sys
- import argparse
- import os
- from distutils.version import LooseVersion
- import elftools
- from elftools.elf.elffile import ELFFile
- if LooseVersion(elftools.__version__) < LooseVersion('0.24'):
- sys.exit("pyelftools is out of date, need version 0.24 or later")
- def write_define(out_fp, prefix, name, value):
- """Write the #define to output file"""
- define_name = f"KOBJECT_{prefix}_{name}"
- out_fp.write(f"#ifndef {define_name}\n")
- out_fp.write(f"#define {define_name} {value}\n")
- out_fp.write("#endif\n\n")
- def output_simple_header(one_sect):
- """Write the header for kobject section"""
- out_fn = os.path.join(args.outdir,
- f"linker-kobject-prebuilt-{one_sect['name']}.h")
- out_fp = open(out_fn, "w")
- if one_sect['exists']:
- align = one_sect['align']
- size = one_sect['size']
- prefix = one_sect['define_prefix']
- write_define(out_fp, prefix, 'ALIGN', align)
- write_define(out_fp, prefix, 'SZ', size)
- out_fp.close()
- def generate_linker_headers(obj):
- """Generate linker header files to be included by the linker script"""
- # Sections we are interested in
- sections = {
- ".data": {
- "name": "data",
- "define_prefix": "DATA",
- "exists": False,
- "multiplier": int(args.datapct) + 100,
- },
- ".rodata": {
- "name": "rodata",
- "define_prefix": "RODATA",
- "exists": False,
- "extra_bytes": args.rodata,
- },
- ".priv_stacks.noinit": {
- "name": "priv-stacks",
- "define_prefix": "PRIV_STACKS",
- "exists": False,
- },
- }
- for one_sect in obj.iter_sections():
- # REALLY NEED to match exact type as all other sections
- # (symbol, debug, etc.) are descendants where
- # isinstance() would match.
- if type(one_sect) is not elftools.elf.sections.Section: # pylint: disable=unidiomatic-typecheck
- continue
- name = one_sect.name
- if name in sections.keys():
- # Need section alignment and size
- sections[name]['align'] = one_sect['sh_addralign']
- sections[name]['size'] = one_sect['sh_size']
- sections[name]['exists'] = True
- if "multiplier" in sections[name]:
- sections[name]['size'] *= sections[name]['multiplier'] / 100
- sections[name]['size'] = int(sections[name]['size'])
- if "extra_bytes" in sections[name]:
- sections[name]['size'] += int(sections[name]['extra_bytes'])
- for one_sect in sections:
- output_simple_header(sections[one_sect])
- def parse_args():
- """Parse command line arguments"""
- global args
- parser = argparse.ArgumentParser(
- description=__doc__,
- formatter_class=argparse.RawDescriptionHelpFormatter)
- parser.add_argument("--object", required=True,
- help="Points to kobject_prebuilt_hash.c.obj")
- parser.add_argument("--outdir", required=True,
- help="Output directory (<build_dir>/include/generated)")
- parser.add_argument("--datapct", required=True,
- help="Multipler to the size of reserved space for DATA region")
- parser.add_argument("--rodata", required=True,
- help="Extra bytes to reserve for RODATA region")
- parser.add_argument("-v", "--verbose", action="store_true",
- help="Verbose messages")
- args = parser.parse_args()
- if "VERBOSE" in os.environ:
- args.verbose = 1
- def main():
- """Main program"""
- parse_args()
- with open(args.object, "rb") as obj_fp:
- obj = ELFFile(obj_fp)
- generate_linker_headers(obj)
- if __name__ == "__main__":
- main()
|