|
2 | 2 | # esp32ulp_mapgen utility converts a symbol list provided by nm into an export script
|
3 | 3 | # for the linker and a header file.
|
4 | 4 | #
|
5 |
| -# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD |
| 5 | +# SPDX-FileCopyrightText: 2016-2024 Espressif Systems (Shanghai) CO LTD |
6 | 6 | # SPDX-License-Identifier: Apache-2.0
|
7 |
| - |
8 |
| -from __future__ import print_function |
9 |
| - |
10 | 7 | import argparse
|
11 | 8 | import os
|
| 9 | +import re |
12 | 10 | import textwrap
|
13 | 11 | import typing
|
14 | 12 |
|
15 | 13 | UTIL = os.path.basename(__file__)
|
16 | 14 |
|
17 | 15 |
|
18 |
| -def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int) -> None: |
| 16 | +def name_mangling(name: str) -> str: |
| 17 | + # Simple and dumb name mangling for namespaced name following GCC algorithm |
| 18 | + ns, n = name.split('::') |
| 19 | + return '_ZN{0}{1}{2}{3}E'.format(len(ns), ns, len(n), n) |
| 20 | + |
| 21 | + |
| 22 | +def gen_ld_h_from_sym(f_sym: typing.TextIO, f_ld: typing.TextIO, f_h: typing.TextIO, base_addr: int, prefix: str) -> None: |
19 | 23 | f_ld.write(textwrap.dedent(
|
20 | 24 | f"""
|
21 | 25 | /* ULP variable definitions for the linker.
|
22 | 26 | * This file is generated automatically by {UTIL} utility.
|
23 | 27 | */
|
24 |
| - """ |
25 |
| - )) |
26 |
| - f_h.write(textwrap.dedent( |
27 |
| - f""" |
28 |
| - /* ULP variable definitions for the compiler. |
29 |
| - * This file is generated automatically by {UTIL} utility. |
30 |
| - */ |
31 |
| - #pragma once |
32 |
| - #ifdef __cplusplus |
33 |
| - extern "C" {{ |
34 |
| - #endif |
35 |
| - """ |
| 28 | + """ # noqa: E222 |
36 | 29 | ))
|
| 30 | + cpp_mode = False |
| 31 | + var_prefix = prefix |
| 32 | + namespace = '' |
| 33 | + if '::' in prefix: |
| 34 | + # C++ mode, let's avoid the extern "C" type and instead use namespace |
| 35 | + f_h.write(textwrap.dedent( |
| 36 | + f""" |
| 37 | + /* ULP variable definitions for the compiler. |
| 38 | + * This file is generated automatically by {UTIL} utility. |
| 39 | + */ |
| 40 | + #pragma once |
| 41 | + """ # noqa: E222 |
| 42 | + )) |
| 43 | + namespace, var_prefix = prefix.split('::') |
| 44 | + f_h.write('namespace {0} {{\n'.format(namespace)) |
| 45 | + cpp_mode = True |
| 46 | + else: |
| 47 | + f_h.write(textwrap.dedent( |
| 48 | + f""" |
| 49 | + /* ULP variable definitions for the compiler. |
| 50 | + * This file is generated automatically by {UTIL} utility. |
| 51 | + */ |
| 52 | + #pragma once |
| 53 | + #ifdef __cplusplus |
| 54 | + extern "C" {{ |
| 55 | + #endif |
| 56 | + """ # noqa: E222 |
| 57 | + )) |
37 | 58 |
|
| 59 | + expr = re.compile('^\\s*\\d+: ([a-f0-9]{8})\\s+(\\d+) OBJECT\\s+GLOBAL\\s+DEFAULT\\s+[^ ]+ (.*)$') |
| 60 | + already_defined = 'this_symbol_is_already_defined_please_use_prefix_in_ulp_embed_binary' |
38 | 61 | for line in f_sym:
|
39 |
| - # NM "posix" format output has the following structure: |
40 |
| - # symbol_name symbol_type addr_hex [size_hex] |
41 |
| - parts = line.split() |
42 |
| - name = parts[0] |
43 |
| - addr = int(parts[2], 16) + base_addr |
44 |
| - f_h.write('extern uint32_t ulp_{0};\n'.format(name)) |
45 |
| - f_ld.write('PROVIDE ( ulp_{0} = 0x{1:08x} );\n'.format(name, addr)) |
| 62 | + # readelf format output has the following structure: |
| 63 | + # index: addr_hex size TYPE SCOPE DEFAULT junk symbol_name |
| 64 | + # So match the line with a regular expression to parse it first |
| 65 | + groups = expr.match(line) |
| 66 | + if groups is None: # Ignore non global or non object |
| 67 | + continue |
| 68 | + addr = int(groups.group(1), 16) + base_addr |
| 69 | + size = int(groups.group(2)) |
| 70 | + name = var_prefix + groups.group(3) |
| 71 | + f_h.write('extern uint32_t {0}{1};\n'.format(name, '[{0}]'.format(int(size / 4)) if size > 4 else '')) |
| 72 | + f_ld.write('{0} = DEFINED({0}) ? {2} : 0x{1:08x};\n'.format( |
| 73 | + name_mangling(namespace + '::' + name) if cpp_mode else name, addr, already_defined)) |
46 | 74 |
|
47 |
| - f_h.write(textwrap.dedent( |
48 |
| - """ |
49 |
| - #ifdef __cplusplus |
50 |
| - } |
51 |
| - #endif |
52 |
| - """ |
53 |
| - )) |
| 75 | + if cpp_mode: |
| 76 | + f_h.write('}\n') |
| 77 | + else: |
| 78 | + f_h.write(textwrap.dedent( |
| 79 | + """ |
| 80 | + #ifdef __cplusplus |
| 81 | + } |
| 82 | + #endif |
| 83 | + """ |
| 84 | + )) |
54 | 85 |
|
55 | 86 |
|
56 | 87 | def main() -> None:
|
57 | 88 | description = ('This application generates .h and .ld files for symbols defined in input file. '
|
58 | 89 | 'The input symbols file can be generated using nm utility like this: '
|
59 |
| - '<PREFIX>nm -g -f posix <elf_file> > <symbols_file>') |
| 90 | + '<PREFIX>readelf -sW <elf_file> > <symbols_file>') |
60 | 91 |
|
61 | 92 | parser = argparse.ArgumentParser(description=description)
|
62 | 93 | parser.add_argument('-s', '--symfile', required=True, help='symbols file name', metavar='SYMFILE', type=argparse.FileType('r'))
|
63 | 94 | parser.add_argument('-o', '--outputfile', required=True, help='destination .h and .ld files name prefix', metavar='OUTFILE')
|
64 | 95 | parser.add_argument('--base-addr', required=True, help='base address of the ULP memory, to be added to each symbol')
|
| 96 | + parser.add_argument('-p', '--prefix', required=False, help='prefix for generated header file', default='ulp_') |
65 | 97 |
|
66 | 98 | args = parser.parse_args()
|
67 | 99 |
|
68 | 100 | with open(args.outputfile + '.h', 'w') as f_h, open(args.outputfile + '.ld', 'w') as f_ld:
|
69 |
| - gen_ld_h_from_sym(args.symfile, f_ld, f_h, int(args.base_addr, 0)) |
| 101 | + gen_ld_h_from_sym(args.symfile, f_ld, f_h, int(args.base_addr, 0), args.prefix) |
70 | 102 |
|
71 | 103 |
|
72 | 104 | if __name__ == '__main__':
|
|
0 commit comments