You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.2 KiB
139 lines
4.2 KiB
#!/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()
|
|
|