140 lines
4.2 KiB
Python
Executable File
140 lines
4.2 KiB
Python
Executable File
#!/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 packaging import version
|
|
|
|
import elftools
|
|
from elftools.elf.elffile import ELFFile
|
|
|
|
|
|
if version.parse(elftools.__version__) < version.parse('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:
|
|
# 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, allow_abbrev=False)
|
|
|
|
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="Multiplier 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()
|