kernel: generate placeholders for kobj tables before final build

Due to the use of gperf to generate hash table for kobjects,
the addresses of these kobjects cannot change during the last
few phases of linking (especially between zephyr_prebuilt.elf
and zephyr.elf). Because of this, the gperf generated data
needs to be placed at the end of memory to avoid pushing symbols
around in memory. This prevents moving these generated blocks
to earlier sections, for example, pinned data section needed
for demand paging. So create placeholders for use in
intermediate linking to reserve space for these generated blocks.
Due to uncertainty on the size of these blocks, more space is
being reserved which could result in wasted space. Though, this
retains the use of hash table for faster lookup.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2021-03-18 14:00:07 -07:00 committed by Anas Nashif
parent 317dcd908f
commit 1117169980
19 changed files with 488 additions and 97 deletions

View file

@ -350,6 +350,10 @@ if(CONFIG_USERSPACE)
set(APP_SMEM_UNALIGNED_DEP app_smem_unaligned_linker)
endif()
if(CONFIG_USERSPACE)
set(KOBJECT_LINKER_DEP kobject_linker)
endif()
get_property(TOPT GLOBAL PROPERTY TOPT)
set_ifndef( TOPT -Wl,-T) # clang doesn't pick -T for some reason and complains,
# while -Wl,-T works for both, gcc and clang
@ -847,6 +851,7 @@ if(CONFIG_USERSPACE)
COMMAND
${GPERF}
--output-file ${KOBJECT_HASH_OUTPUT_SRC_PRE}
--multiple-iterations 10
${KOBJECT_HASH_LIST}
DEPENDS kobj_hash_list ${KOBJECT_HASH_LIST}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
@ -1062,10 +1067,137 @@ if(CONFIG_USERSPACE)
)
endif()
if(CONFIG_USERSPACE)
# This CONFIG_USERSPACE block is to create place holders to reserve space
# for the gperf generated structures for zephyr_prebuilt.elf.
# These place holders are there so that the placement of kobjects would be
# the same between linking zephyr_prebuilt.elf and zephyr.elf, as
# the gperf hash table is hashed on the addresses of kobjects.
# The placeholders are generated from app_smem_unaligned_prebuilt.elf.
set(KOBJECT_PREBUILT_HASH_LIST kobject_prebuilt_hash.gperf)
set(KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE kobject_prebuilt_hash_preprocessed.c)
set(KOBJECT_PREBUILT_HASH_OUTPUT_SRC kobject_prebuilt_hash.c)
set(KOBJECT_PREBUILT_HASH_OUTPUT_OBJ kobject_prebuilt_hash.c.obj)
add_custom_command(
OUTPUT ${KOBJECT_PREBUILT_HASH_LIST}
COMMAND
${PYTHON_EXECUTABLE}
${GEN_KOBJ_LIST}
--kernel $<TARGET_FILE:app_smem_unaligned_prebuilt>
--gperf-output ${KOBJECT_PREBUILT_HASH_LIST}
${gen_kobject_list_include_args}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS
app_smem_unaligned_prebuilt
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(
kobj_prebuilt_hash_list
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_LIST}
)
add_custom_command(
OUTPUT ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE}
COMMAND
${GPERF}
--output-file ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE}
--multiple-iterations 10
${KOBJECT_PREBUILT_HASH_LIST}
DEPENDS kobj_prebuilt_hash_list ${KOBJECT_PREBUILT_HASH_LIST}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(
kobj_prebuilt_hash_output_src_pre
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE}
)
add_custom_command(
OUTPUT ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
COMMAND
${PYTHON_EXECUTABLE}
${PROCESS_GPERF}
-i ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE}
-o ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
-p "struct z_object"
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS kobj_prebuilt_hash_output_src_pre ${KOBJECT_PREBUILT_HASH_OUTPUT_SRC_PRE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(
kobj_prebuilt_hash_output_src
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
)
add_library(
kobj_prebuilt_hash_output_lib
STATIC ${CMAKE_CURRENT_BINARY_DIR}/${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
)
set_source_files_properties(${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
PROPERTIES COMPILE_FLAGS
"${NO_COVERAGE_FLAGS} -fno-function-sections -fno-data-sections")
set_source_files_properties(${KOBJECT_PREBUILT_HASH_OUTPUT_SRC}
PROPERTIES COMPILE_DEFINITIONS "${compile_definitions_interface}")
add_library(kobj_prebuilt_hash_output_lib_interface INTERFACE)
target_link_libraries(
kobj_prebuilt_hash_output_lib
kobj_prebuilt_hash_output_lib_interface
)
foreach(incl ${include_dir_in_interface})
target_include_directories(
kobj_prebuilt_hash_output_lib_interface
INTERFACE ${incl}
)
endforeach()
foreach(incl ${sys_include_dir_in_interface})
target_include_directories(
kobj_prebuilt_hash_output_lib_interface
SYSTEM INTERFACE ${incl}
)
endforeach()
set(
KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH
${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/kobj_prebuilt_hash_output_lib.dir/${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ}
)
set(KOBJECT_LINKER_HEADER_DATA "${PROJECT_BINARY_DIR}/include/generated/linker-kobject-prebuilt-data.h")
add_custom_command(
OUTPUT ${KOBJECT_LINKER_HEADER_DATA}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/gen_kobject_placeholders.py
--object ${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH}
--outdir ${PROJECT_BINARY_DIR}/include/generated
--datapct ${CONFIG_KOBJECT_DATA_AREA_RESERVE_EXTRA_PERCENT}
--rodata ${CONFIG_KOBJECT_RODATA_AREA_EXTRA_BYTES}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS
kobj_prebuilt_hash_output_lib
${KOBJECT_PREBUILT_HASH_OUTPUT_OBJ_PATH}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(
${KOBJECT_LINKER_DEP}
DEPENDS
${KOBJECT_LINKER_HEADER_DATA}
)
endif()
configure_linker_script(
linker_zephyr_prebuilt.cmd
"-DLINKER_ZEPHYR_PREBUILT"
${APP_SMEM_ALIGNED_DEP}
${KOBJECT_LINKER_DEP}
${CODE_RELOCATION_DEP}
zephyr_generated_headers
)

View file

@ -547,6 +547,7 @@
/arch/x86/gen_gdt.py @dcpleung @nashif
/arch/x86/gen_idt.py @dcpleung @nashif
/scripts/gen_kobject_list.py @dcpleung @nashif
/scripts/gen_kobject_placeholders.py @dcpleung
/scripts/gen_syscalls.py @dcpleung @nashif
/scripts/list_boards.py @mbolivar-nordic
/scripts/net/ @jukkar

View file

@ -273,7 +273,7 @@ config PRIVILEGED_STACK_SIZE
a multiple of the minimum stack alignment.
config KOBJECT_TEXT_AREA
int "Size if kobject text area"
int "Size of kobject text area"
default 512 if COVERAGE_GCOV
default 512 if NO_OPTIMIZATIONS
default 512 if STACK_CANARIES && RISCV
@ -282,6 +282,28 @@ config KOBJECT_TEXT_AREA
help
Size of kernel object text area. Used in linker script.
config KOBJECT_DATA_AREA_RESERVE_EXTRA_PERCENT
int "Reserve extra kobject data area (in percentage)"
default 100
depends on ARCH_HAS_USERSPACE
help
Multiplication factor used to calculate the size of placeholder to
reserve space for kobject metadata hash table. The hash table is
generated via gperf is highly dependent on the absolute addresses of
kobjects which might change between prebuilts. To reserve enough
space for the hash table during final linking passes to keep
kobjects in same place, the size of reserved space is calculated
from the first prebuilt plus additional space calculated with
this percentage (of the kobject data area in first prebuilt).
config KOBJECT_RODATA_AREA_EXTRA_BYTES
int "Reserve extra bytes for kobject rodata area"
default 16
depends on ARCH_HAS_USERSPACE
help
Reserve a few more bytes for the RODATA region for kobject metadata.
This is to account for the uncertainty of tables generated by gperf.
config GEN_PRIV_STACKS
bool
help

View file

@ -188,7 +188,7 @@ SECTIONS {
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
#include <linker/common-ram.ld>
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
#ifdef __MWDT_LINKER_CMD__
/* TODO: add mwdt specific RAM C++ sections */

View file

@ -295,7 +295,7 @@ SECTIONS
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
#include <linker/common-ram.ld>
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
#include <linker/cplusplus-ram.ld>
__data_ram_end = .;

View file

@ -329,7 +329,7 @@ SECTIONS
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
#include <linker/common-ram.ld>
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
#include <linker/cplusplus-ram.ld>

View file

@ -271,7 +271,7 @@ SECTIONS
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
#include <linker/common-ram.ld>
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
#include <linker/cplusplus-ram.ld>
__data_ram_end = .;

View file

@ -225,7 +225,7 @@ SECTIONS
__data_rom_start = LOADADDR(_DATA_SECTION_NAME);
#include <linker/common-ram.ld>
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
/* Located in generated directory. This file is populated by the
* zephyr_linker_sources() Cmake function.

View file

@ -336,7 +336,7 @@ SECTIONS
#include <arch/x86/pagetables.ld>
/* Must be last in RAM */
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
MMU_PAGE_ALIGN
__data_ram_end = .;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019 Intel Corp.
* Copyright (c) 2019-2021 Intel Corp.
* SPDX-License-Identifier: Apache-2.0
*/
@ -185,7 +185,7 @@ SECTIONS
#include <arch/x86/pagetables.ld>
/* Must be last in RAM */
#include <linker/kobject.ld>
#include <linker/kobject-data.ld>
MMU_PAGE_ALIGN
_image_ram_end = .;
z_mapped_end = .;

View file

@ -24,3 +24,5 @@ SECTION_PROLOGUE(_NOINIT_SECTION_NAME,(NOLOAD),)
#include <snippets-noinit.ld>
} GROUP_NOLOAD_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#include "kobject-priv-stacks.ld"

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2017,2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef CONFIG_USERSPACE
z_kobject_data_begin = .;
SECTION_DATA_PROLOGUE(kobject_data,,)
{
#if !defined(LINKER_ZEPHYR_PREBUILT) && \
!defined(LINKER_ZEPHYR_FINAL)
#ifdef CONFIG_DYNAMIC_OBJECTS
PROVIDE(_thread_idx_map = .);
. += CONFIG_MAX_THREAD_BYTES;
#endif
#endif /* !LINKER_ZEPHYR_PREBUILT && !LINKER_ZEPHYR_FINAL */
/* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT,
* space needs to be reserved for the rodata that will be
* produced by gperf during the final stages of linking.
* The alignment and size are produced by
* scripts/gen_kobject_placeholders.py. These are here
* so the addresses to kobjects would remain the same
* during the final stages of linking (LINKER_ZEPHYR_FINAL).
*/
#if defined(LINKER_ZEPHYR_PREBUILT)
#include <linker-kobject-prebuilt-data.h>
#ifdef CONFIG_DYNAMIC_OBJECTS
/* This is produced by gperf. Put a place holder here
* to avoid compilation error.
*/
PROVIDE(_thread_idx_map = .);
#endif
#ifdef KOBJECT_DATA_ALIGN
. = ALIGN(KOBJECT_DATA_ALIGN);
. += KOBJECT_DATA_SZ;
#endif
#endif /* LINKER_ZEPHYR_PREBUILT */
#if defined(LINKER_ZEPHYR_FINAL)
#include <linker-kobject-prebuilt-data.h>
#ifdef KOBJECT_DATA_ALIGN
. = ALIGN(KOBJECT_DATA_ALIGN);
_kobject_data_area_start = .;
#endif
*(".kobject_data.data*")
#ifdef KOBJECT_DATA_ALIGN
_kobject_data_area_end = .;
_kobject_data_area_used = _kobject_data_area_end - _kobject_data_area_start;
ASSERT(_kobject_data_area_used <= KOBJECT_DATA_SZ,
"scripts/gen_kobject_placeholders.py did not reserve enough space \
for kobject data."
);
/* Padding is needed to preserve kobject addresses
* if we have reserved more space than needed.
*/
. = MAX(., _kobject_data_area_start + KOBJECT_DATA_SZ);
#endif /* KOBJECT_DATA_ALIGN */
#endif /* LINKER_ZEPHYR_FINAL */
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif /* CONFIG_USERSPACE */

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2017,2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef CONFIG_USERSPACE
#ifdef CONFIG_GEN_PRIV_STACKS
SECTION_DATA_PROLOGUE(priv_stacks_noinit,,)
{
z_priv_stacks_ram_start = .;
/* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT,
* space needs to be reserved for the rodata that will be
* produced by gperf during the final stages of linking.
* The alignment and size are produced by
* scripts/gen_kobject_placeholders.py. These are here
* so the addresses to kobjects would remain the same
* during the final stages of linking (LINKER_ZEPHYR_FINAL).
*/
#if defined(LINKER_ZEPHYR_PREBUILT)
#include <linker-kobject-prebuilt-priv-stacks.h>
#ifdef KOBJECT_PRIV_STACKS_ALIGN
. = ALIGN(KOBJECT_PRIV_STACKS_ALIGN);
. += KOBJECT_PRIV_STACKS_SZ;
#endif
#endif /* LINKER_ZEPHYR_PREBUILT */
#if defined(LINKER_ZEPHYR_FINAL)
#include <linker-kobject-prebuilt-priv-stacks.h>
#ifdef KOBJECT_PRIV_STACKS_ALIGN
. = ALIGN(KOBJECT_PRIV_STACKS_ALIGN);
#endif
*(".priv_stacks.noinit")
#endif /* LINKER_ZEPHYR_FINAL */
z_priv_stacks_ram_end = .;
#if defined(LINKER_ZEPHYR_FINAL)
#ifdef KOBJECT_PRIV_STACKS_ALIGN
z_priv_stacks_ram_used = z_priv_stacks_ram_end - z_priv_stacks_ram_start;
ASSERT(z_priv_stacks_ram_used <= KOBJECT_PRIV_STACKS_SZ,
"scripts/gen_kobject_placeholders.py did not reserve enough space \
for priviledged stacks."
);
/* Padding is needed to preserve kobject addresses
* if we have reserved more space than needed.
*/
. = MAX(., z_priv_stacks_ram_start + KOBJECT_PRIV_STACKS_SZ);
#endif /* KOBJECT_PRIV_STACKS_ALIGN */
#endif /* LINKER_ZEPHYR_FINAL */
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif /* CONFIG_GEN_PRIV_STACKS */
#endif /* CONFIG_USERSPACE */

View file

@ -1,13 +1,57 @@
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2017,2021 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef CONFIG_USERSPACE
/* Kept in RAM on non-XIP */
#ifdef CONFIG_XIP
*(".kobject_data.rodata*")
#endif
#endif /* CONFIG_USERSPACE */
/* During LINKER_KOBJECT_PREBUILT and LINKER_ZEPHYR_PREBUILT,
* space needs to be reserved for the rodata that will be
* produced by gperf during the final stages of linking.
* The alignment and size are produced by
* scripts/gen_kobject_placeholders.py. These are here
* so the addresses to kobjects would remain the same
* during the final stages of linking (LINKER_ZEPHYR_FINAL).
*/
#if defined(LINKER_ZEPHYR_PREBUILT)
#include <linker-kobject-prebuilt-rodata.h>
#ifdef KOBJECT_RODATA_ALIGN
. = ALIGN(KOBJECT_RODATA_ALIGN);
_kobject_rodata_area_start = .;
. += KOBJECT_RODATA_SZ;
_kobject_rodata_area_end = .;
#endif
#endif /* LINKER_ZEPHYR_PREBUILT */
#if defined(LINKER_ZEPHYR_FINAL)
#include <linker-kobject-prebuilt-rodata.h>
#ifdef KOBJECT_RODATA_ALIGN
. = ALIGN(KOBJECT_RODATA_ALIGN);
_kobject_rodata_area_start = .;
#endif
*(".kobject_data.rodata*")
#ifdef KOBJECT_RODATA_ALIGN
_kobject_rodata_area_end = .;
_kobject_rodata_area_used = _kobject_rodata_area_end - _kobject_rodata_area_start;
ASSERT(_kobject_rodata_area_used <= KOBJECT_RODATA_SZ,
"scripts/gen_kobject_placeholders.py did not reserve enough space \
for kobject rodata."
);
/* Padding is needed to preserve kobject addresses
* if we have reserved more space than needed.
*/
. = MAX(., _kobject_rodata_area_start + KOBJECT_RODATA_SZ);
#endif /* KOBJECT_RODATA_ALIGN */
#endif /* LINKER_ZEPHYR_FINAL */
#endif /* CONFIG_USERSPACE */

View file

@ -1,52 +0,0 @@
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifdef CONFIG_USERSPACE
z_kobject_data_begin = .;
/* Constraints:
*
* - changes to the size of this section between build phases
* *must not* shift the memory address of any kernel obejcts,
* since it contains a hashtable of the memory addresses of those
* kernel objects
*
* - It is OK if this section itself is shifted in between builds; for
* example some arches may precede this section with generated MMU
* page tables which are also unpredictable in size.
*
* The size of the
* gperf tables is both a function of the number of kernel objects,
* *and* the specific memory addresses being hashed. It is not something
* that can be predicted without actually building and compling it.
*/
SECTION_DATA_PROLOGUE(kobject_data,,)
{
*(".kobject_data.data*")
#ifndef LINKER_ZEPHYR_FINAL
#ifdef CONFIG_DYNAMIC_OBJECTS
PROVIDE(_thread_idx_map = .);
. += CONFIG_MAX_THREAD_BYTES;
#endif
#endif
/* This is also unpredictable in size, and has the same constraints.
* On XIP systems this will get put at the very end of ROM.
*/
#ifndef CONFIG_XIP
*(".kobject_data.rodata*")
#endif
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#ifdef CONFIG_GEN_PRIV_STACKS
SECTION_DATA_PROLOGUE(priv_stacks_noinit,,)
{
z_priv_stacks_ram_start = .;
*(".priv_stacks.noinit")
z_priv_stacks_ram_end = .;
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION)
#endif /* CONFIG_GEN_PRIV_STACKS */
#endif /* CONFIG_USERSPACE */

View file

@ -199,9 +199,6 @@ void z_thread_mark_switched_out(void);
*/
void z_mem_manage_init(void);
/* Workaround for build-time page table mapping of the kernel */
void z_kernel_map_fixup(void);
#define LOCKED(lck) for (k_spinlock_key_t __i = {}, \
__key = k_spin_lock(lck); \
!__i.key; \

View file

@ -382,9 +382,6 @@ FUNC_NORETURN void z_cstart(void)
struct k_thread dummy_thread;
z_dummy_thread_init(&dummy_thread);
#endif
#if defined(CONFIG_MMU) && defined(CONFIG_USERSPACE)
z_kernel_map_fixup();
#endif
/* do any necessary initialization of static devices */
z_device_state_init();

View file

@ -486,30 +486,6 @@ size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size,
return addr_offset;
}
#ifdef CONFIG_USERSPACE
void z_kernel_map_fixup(void)
{
/* XXX: Gperf kernel object data created at build time will not have
* visibility in zephyr_prebuilt.elf. There is a possibility that this
* data would not be memory-mapped if it shifts z_mapped_end between
* builds. Ensure this area is mapped.
*
* A third build phase for page tables would solve this.
*/
uint8_t *kobject_page_begin =
(uint8_t *)ROUND_DOWN((uintptr_t)&z_kobject_data_begin,
CONFIG_MMU_PAGE_SIZE);
size_t kobject_size = (size_t)(Z_KERNEL_VIRT_END - kobject_page_begin);
if (kobject_size != 0U) {
arch_mem_map(kobject_page_begin,
Z_BOOT_VIRT_TO_PHYS(kobject_page_begin),
kobject_size, K_MEM_PERM_RW | K_MEM_CACHE_WB);
}
}
#endif /* CONFIG_USERSPACE */
void z_mem_manage_init(void)
{
uintptr_t phys;

View file

@ -0,0 +1,139 @@
#!/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()