Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

#!/usr/bin/env python3
#
# Copyright (c) 2018 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

import sys
import argparse
import os
import re
import string
from elf_helper import ElfHelper
from elftools.elf.elffile import ELFFile


# This script will create sections and linker variables to place the
# application shared memory partitions.
# these are later read by the macros defined in app_memdomain.h for
# initialization purpose when APP_SHARED_MEM is enabled.
data_template = """
		/* Auto generated code do not modify */
		SMEM_PARTITION_ALIGN(data_smem_{0}_bss_end - data_smem_{0}_start);
		data_smem_{0}_start = .;
		KEEP(*(data_smem_{0}_data))
"""

library_data_template = """
		*{0}:*(.data .data.*)
"""

bss_template = """
		data_smem_{0}_bss_start = .;
		KEEP(*(data_smem_{0}_bss))
"""

library_bss_template = """
		*{0}:*(.bss .bss.* COMMON COMMON.*)
"""

footer_template = """
		SMEM_PARTITION_ALIGN(data_smem_{0}_bss_end - data_smem_{0}_start);
		data_smem_{0}_bss_end = .;
		data_smem_{0}_end = .;
"""

linker_start_seq = """
	SECTION_PROLOGUE(_APP_SMEM_SECTION_NAME, (OPTIONAL),)
	{
		APP_SHARED_ALIGN;
		_app_smem_start = .;
"""

linker_end_seq = """
		APP_SHARED_ALIGN;
		_app_smem_end = .;
	} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
"""

size_cal_string = """
	data_smem_{0}_size = data_smem_{0}_end - data_smem_{0}_start;
	data_smem_{0}_bss_size = data_smem_{0}_bss_end - data_smem_{0}_bss_start;
"""

section_regex = re.compile(r'data_smem_([A-Za-z0-9_]*)_(data|bss)')

def find_partitions(filename, partitions, sources):
    with open(filename, 'rb') as f:
        full_lib = ELFFile( f)
        if (not full_lib):
            print("Error parsing file: ",filename)
            os.exit(1)

        sections = [x for x in full_lib.iter_sections()]
        for section in sections:
            m = section_regex.match(section.name)
            if not m:
                continue

            partition_name = m.groups()[0]
            if partition_name not in partitions:
                partitions[partition_name] = []
                if args.verbose:
                    sources.update({partition_name: filename})

    return (partitions, sources)


def generate_final_linker(linker_file, partitions):
    string = linker_start_seq
    size_string = ''
    for partition, libs in partitions.items():
        string += data_template.format(partition)
        for lib in libs:
            string += library_data_template.format(lib)
        string += bss_template.format(partition)
        for lib in libs:
            string += library_bss_template.format(lib)
        string += footer_template.format(partition)
        size_string += size_cal_string.format(partition)

    string += linker_end_seq
    string += size_string
    with open(linker_file, "w") as fw:
        fw.write(string)


def parse_args():
    global args
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("-d", "--directory", required=True,
                        help="Root build directory")
    parser.add_argument("-o", "--output", required=False,
                        help="Output ld file")
    parser.add_argument("-v", "--verbose", action="count", default =0,
                        help="Verbose Output")
    parser.add_argument("-l", "--library", nargs=2, action="append", default=[],
                        metavar=("LIBRARY", "PARTITION"),
                        help="Include globals for a particular library or object filename into a designated partition")

    args = parser.parse_args()


def main():
    parse_args()
    linker_file = args.output
    partitions = {}
    sources = {}

    for dirpath, dirs, files in os.walk(args.directory):
        for filename in files:
            if re.match(".*\.obj$",filename):
                fullname = os.path.join(dirpath, filename)
                find_partitions(fullname, partitions,
                                sources)

    for lib, ptn in args.library:
        if ptn not in partitions:
            partitions[ptn] = [lib]
        else:
            partitions[ptn].append(lib)

    generate_final_linker(args.output, partitions)
    if args.verbose:
        print("Partitions retrieved:")
        for key in partitions:
            print("    %s: %s\n", key, sources[key])

if __name__ == '__main__':
    main()