diff --git a/components/ulp/cmake/CMakeLists.txt b/components/ulp/cmake/CMakeLists.txt index 9d42579931c..816a4006ab7 100644 --- a/components/ulp/cmake/CMakeLists.txt +++ b/components/ulp/cmake/CMakeLists.txt @@ -8,4 +8,4 @@ include(IDFULPProject) ulp_apply_default_options(${ULP_APP_NAME}) ulp_apply_default_sources(${ULP_APP_NAME}) -ulp_add_build_binary_targets(${ULP_APP_NAME}) +ulp_add_build_binary_targets(${ULP_APP_NAME} ${ULP_VAR_PREFIX}) diff --git a/components/ulp/cmake/IDFULPProject.cmake b/components/ulp/cmake/IDFULPProject.cmake index fd90cfd87ff..e9c60da22e2 100644 --- a/components/ulp/cmake/IDFULPProject.cmake +++ b/components/ulp/cmake/IDFULPProject.cmake @@ -178,7 +178,7 @@ function(ulp_apply_default_sources ulp_app_name) endif() endfunction() -function(ulp_add_build_binary_targets ulp_app_name) +function(ulp_add_build_binary_targets ulp_app_name prefix) if(CONFIG_ULP_COPROC_TYPE_LP_CORE) set(ULP_BASE_ADDR "0x0") @@ -190,7 +190,7 @@ function(ulp_add_build_binary_targets ulp_app_name) # Dump the list of global symbols in a convenient format add_custom_command(OUTPUT ${ULP_APP_NAME}.sym - COMMAND ${CMAKE_NM} -f posix -g $ > ${ulp_app_name}.sym + COMMAND ${CMAKE_READELF} -sW $ > ${ulp_app_name}.sym DEPENDS ${ulp_app_name} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) @@ -201,7 +201,8 @@ function(ulp_add_build_binary_targets ulp_app_name) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) add_custom_command(OUTPUT ${ulp_app_name}.ld ${ulp_app_name}.h - COMMAND ${ULP_MAP_GEN} -s ${ulp_app_name}.sym -o ${ulp_app_name} --base ${ULP_BASE_ADDR} + COMMAND ${ULP_MAP_GEN} -s ${ulp_app_name}.sym -o ${ulp_app_name} + --base ${ULP_BASE_ADDR} --prefix ${prefix} DEPENDS ${ulp_app_name}.sym WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/components/ulp/esp32ulp_mapgen.py b/components/ulp/esp32ulp_mapgen.py index 382752269c3..5bc1551aa50 100755 --- a/components/ulp/esp32ulp_mapgen.py +++ b/components/ulp/esp32ulp_mapgen.py @@ -2,71 +2,105 @@ # esp32ulp_mapgen utility converts a symbol list provided by nm into an export script # for the linker and a header file. # -# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 - -from __future__ import print_function - import argparse import os +import re import textwrap import typing UTIL = os.path.basename(__file__) -def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int) -> None: +def name_mangling(name: str) -> str: + # Simple and dumb name mangling for namespaced name following GCC algorithm + ns, n = name.split('::') + return '_ZN{0}{1}{2}{3}E'.format(len(ns), ns, len(n), n) + + +def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int, prefix: str) -> None: f_ld.write(textwrap.dedent( f""" /* ULP variable definitions for the linker. * This file is generated automatically by {UTIL} utility. */ - """ - )) - f_h.write(textwrap.dedent( - f""" - /* ULP variable definitions for the compiler. - * This file is generated automatically by {UTIL} utility. - */ - #pragma once - #ifdef __cplusplus - extern "C" {{ - #endif - """ + """ # noqa: E222 )) + cpp_mode = False + var_prefix = prefix + namespace = '' + if '::' in prefix: + # C++ mode, let's avoid the extern "C" type and instead use namespace + f_h.write(textwrap.dedent( + f""" + /* ULP variable definitions for the compiler. + * This file is generated automatically by {UTIL} utility. + */ + #pragma once + """ # noqa: E222 + )) + tmp = prefix.split('::') + namespace = tmp[0] + var_prefix = '_'.join(tmp[1:]) # Limit to a single namespace here to avoid complex mangling rules + f_h.write('namespace {0} {{\n'.format(namespace)) + cpp_mode = True + else: + f_h.write(textwrap.dedent( + f""" + /* ULP variable definitions for the compiler. + * This file is generated automatically by {UTIL} utility. + */ + #pragma once + #ifdef __cplusplus + extern "C" {{ + #endif + """ # noqa: E222 + )) + expr = re.compile('^\\s*\\d+: ([a-f0-9]{8})\\s+(\\d+) OBJECT\\s+GLOBAL\\s+DEFAULT\\s+[^ ]+ (.*)$') + already_defined = 'this_symbol_is_already_defined_please_use_prefix_in_ulp_embed_binary' for line in f_sym: - # NM "posix" format output has the following structure: - # symbol_name symbol_type addr_hex [size_hex] - parts = line.split() - name = parts[0] - addr = int(parts[2], 16) + base_addr - f_h.write('extern uint32_t ulp_{0};\n'.format(name)) - f_ld.write('PROVIDE ( ulp_{0} = 0x{1:08x} );\n'.format(name, addr)) + # readelf format output has the following structure: + # index: addr_hex size TYPE SCOPE DEFAULT junk symbol_name + # So match the line with a regular expression to parse it first + groups = expr.match(line) + if groups is None: # Ignore non global or non object + continue + addr = int(groups.group(1), 16) + base_addr + size = int(groups.group(2)) + name = var_prefix + groups.group(3) + f_h.write('extern uint32_t {0}{1};\n'.format(name, '[{0}]'.format(int(size / 4)) if size > 4 else '')) + f_ld.write('{0} = DEFINED({0}) ? {2} : 0x{1:08x};\n'.format( + name_mangling(namespace + '::' + name) if cpp_mode else name, addr, already_defined)) - f_h.write(textwrap.dedent( - """ - #ifdef __cplusplus - } - #endif - """ - )) + if cpp_mode: + f_h.write('}\n') + else: + f_h.write(textwrap.dedent( + """ + #ifdef __cplusplus + } + #endif + """ + )) def main() -> None: description = ('This application generates .h and .ld files for symbols defined in input file. ' - 'The input symbols file can be generated using nm utility like this: ' - 'nm -g -f posix > ') + 'The input symbols file can be generated using readelf utility like this: ' + 'readelf -sW > ') parser = argparse.ArgumentParser(description=description) parser.add_argument('-s', '--symfile', required=True, help='symbols file name', metavar='SYMFILE', type=argparse.FileType('r')) parser.add_argument('-o', '--outputfile', required=True, help='destination .h and .ld files name prefix', metavar='OUTFILE') parser.add_argument('--base-addr', required=True, help='base address of the ULP memory, to be added to each symbol') + parser.add_argument('-p', '--prefix', required=False, help='prefix for generated header file', default='ulp_') args = parser.parse_args() with open(args.outputfile + '.h', 'w') as f_h, open(args.outputfile + '.ld', 'w') as f_ld: - gen_ld_h_from_sym(args.symfile, f_ld, f_h, int(args.base_addr, 0)) + gen_ld_h_from_sym(args.symfile, f_ld, f_h, int(args.base_addr, 0), args.prefix) if __name__ == '__main__': diff --git a/components/ulp/project_include.cmake b/components/ulp/project_include.cmake index 47b2af53c40..35b5d395319 100644 --- a/components/ulp/project_include.cmake +++ b/components/ulp/project_include.cmake @@ -2,7 +2,7 @@ # # Create ULP binary and embed into the application. -function(__setup_ulp_project app_name project_path s_sources exp_dep_srcs) +function(__setup_ulp_project app_name project_path prefix s_sources exp_dep_srcs) if(NOT CMAKE_BUILD_EARLY_EXPANSION) spaces2list(s_sources) @@ -60,6 +60,7 @@ function(__setup_ulp_project app_name project_path s_sources exp_dep_srcs) -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_FLAG} -DULP_S_SOURCES=$ -DULP_APP_NAME=${app_name} + -DULP_VAR_PREFIX=${prefix} -DCOMPONENT_DIR=${COMPONENT_DIR} -DCOMPONENT_INCLUDES=$ -DIDF_TARGET=${idf_target} @@ -92,9 +93,14 @@ function(__setup_ulp_project app_name project_path s_sources exp_dep_srcs) endfunction() function(ulp_embed_binary app_name s_sources exp_dep_srcs) - __setup_ulp_project("${app_name}" "${idf_path}/components/ulp/cmake" "${s_sources}" "${exp_dep_srcs}") + cmake_parse_arguments(ULP "" "PREFIX" "" ${ARGN}) + if(NOT ULP_PREFIX) + set(ULP_PREFIX "ulp_") + endif() + __setup_ulp_project("${app_name}" "${idf_path}/components/ulp/cmake" + "${ULP_PREFIX}" "${s_sources}" "${exp_dep_srcs}") endfunction() function(ulp_add_project app_name project_path) - __setup_ulp_project("${app_name}" "${project_path}" "" "") + __setup_ulp_project("${app_name}" "${project_path}" "ulp_" "" "") endfunction()