From bce055338eabdac46d34c781753e05486898325a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 26 Aug 2024 13:11:40 -0600 Subject: [PATCH] binman: Provide a way to set the symbol base address The base address of the ELF containing symbols is normally added to any symbols written, so that the value points to the correct address in memory when everything is loaded. When the binary resides on disk, a different offset may be needed, typically 0. Provide a way to specify this. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 15 ++++++++ tools/binman/elf.py | 7 ++-- tools/binman/entry.py | 8 ++++- tools/binman/etype/blob_phase.py | 5 +++ tools/binman/ftest.py | 35 ++++++++++++++++--- tools/binman/test/336_symbols_base.dts | 23 ++++++++++++ tools/binman/test/337_symbols_base_expand.dts | 24 +++++++++++++ 7 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 tools/binman/test/336_symbols_base.dts create mode 100644 tools/binman/test/337_symbols_base_expand.dts diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 04564f4f66..f9a3a42183 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -502,6 +502,10 @@ For x86 devices (with the end-at-4gb property) this base address is not added since it is assumed that images are XIP and the offsets already include the address. +For non-x86 cases where the symbol is used as a flash offset, the symbols-base +property can be set to that offset (e.g. 0), so that the unadjusted image-pos +is written into the image. + While U-Boot's symbol updating is handled automatically by the u-boot-spl entry type (and others), it is possible to use this feature with any blob. To do this, add a `write-symbols` (boolean) property to the node, set the ELF @@ -743,6 +747,17 @@ insert-template: properties are brought into the target node. See Templates_ below for more information. +symbols-base: + When writing symbols into a binary, the value of that symbol is assumed to + be relative to the base address of the binary. This allow the binary to be + loaded in memory at its base address, so that symbols point into the binary + correctly. In some cases the binary is in fact not yet in memory, but must + be read from storage. In this case there is no base address for the symbols. + This property can be set to 0 to indicate this. Other values for + symbols-base are allowed, but care must be taken that the code which uses + the symbol is aware of the base being used. If omitted, the binary's base + address is used. + The attributes supported for images and sections are described below. Several are similar to those for entries. diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 73394830eb..c75f447881 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -234,7 +234,7 @@ def GetSymbolOffset(elf_fname, sym_name, base_sym=None): return val - base def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, - base_sym=None): + base_sym=None, base_addr=None): """Replace all symbols in an entry with their correct values The entry contents is updated so that values for referenced symbols will be @@ -249,6 +249,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, section: Section which can be used to lookup symbol values base_sym: Base symbol marking the start of the image (__image_copy_start by default) + base_addr (int): Base address to use for the entry being written. If + None then the value of base_sym is used Returns: int: Number of symbols written @@ -278,7 +280,8 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, if not base and not is_elf: tout.debug(f'LookupAndWriteSymbols: no base: elf_fname={elf_fname}, base_sym={base_sym}, is_elf={is_elf}') return 0 - base_addr = 0 if is_elf else base.address + if base_addr is None: + base_addr = 0 if is_elf else base.address count = 0 for name, sym in syms.items(): if name.startswith('_binman'): diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 7d4d469277..8ad9fe89e0 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -108,6 +108,9 @@ class Entry(object): not need to be done again. This is only used with 'binman replace', to stop sections from being rebuilt if their entries have not been replaced + symbols_base (int): Use this value as the assumed load address of the + target entry, when calculating the symbol value. If None, this is + 0 for blobs and the image-start address for ELF files """ fake_dir = None @@ -159,6 +162,7 @@ class Entry(object): self.preserve = False self.build_done = False self.no_write_symbols = False + self.symbols_base = None @staticmethod def FindEntryClass(etype, expanded): @@ -324,6 +328,7 @@ class Entry(object): self.preserve = fdt_util.GetBool(self._node, 'preserve') self.no_write_symbols = fdt_util.GetBool(self._node, 'no-write-symbols') + self.symbols_base = fdt_util.GetInt(self._node, 'symbols-base') def GetDefaultFilename(self): return None @@ -713,7 +718,8 @@ class Entry(object): # Check if we are writing symbols into an ELF file is_elf = self.GetDefaultFilename() == self.elf_fname elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage(), - is_elf, self.elf_base_sym) + is_elf, self.elf_base_sym, + self.symbols_base) def CheckEntries(self): """Check that the entry offsets are correct diff --git a/tools/binman/etype/blob_phase.py b/tools/binman/etype/blob_phase.py index 951d993405..09bb89b3b7 100644 --- a/tools/binman/etype/blob_phase.py +++ b/tools/binman/etype/blob_phase.py @@ -57,3 +57,8 @@ class Entry_blob_phase(Entry_section): if self.no_write_symbols: for entry in self._entries.values(): entry.no_write_symbols = True + + # Propagate the symbols-base property + if self.symbols_base is not None: + for entry in self._entries.values(): + entry.symbols_base = self.symbols_base diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 7b4454bd34..ecfcd6bd91 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -1500,7 +1500,8 @@ class TestFunctional(unittest.TestCase): self.assertEqual(U_BOOT_SPL_NODTB_DATA, data[:len(U_BOOT_SPL_NODTB_DATA)]) def checkSymbols(self, dts, base_data, u_boot_offset, entry_args=None, - use_expanded=False, no_write_symbols=False): + use_expanded=False, no_write_symbols=False, + symbols_base=None): """Check the image contains the expected symbol values Args: @@ -1512,6 +1513,8 @@ class TestFunctional(unittest.TestCase): value: value of that arg use_expanded: True to use expanded entries where available, e.g. 'u-boot-expanded' instead of 'u-boot' + symbols_base (int): Value to expect for symbols-base in u-boot-spl, + None if none """ elf_fname = self.ElfTestFile('u_boot_binman_syms') syms = elf.GetSymbols(elf_fname, ['binman', 'image']) @@ -1526,10 +1529,19 @@ class TestFunctional(unittest.TestCase): # The image should contain the symbols from u_boot_binman_syms.c # Note that image_pos is adjusted by the base address of the image, # which is 0x10 in our test image - vals = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00, + vals2 = (elf.BINMAN_SYM_MAGIC_VALUE, 0x00, u_boot_offset + len(U_BOOT_DATA), 0x10 + u_boot_offset, 0x04) + + # u-boot-spl has a symbols-base property, so take that into account if + # required. The caller must supply the value + vals = list(vals2) + if symbols_base is not None: + vals[3] = symbols_base + u_boot_offset + vals = tuple(vals) + sym_values = struct.pack('; + #size-cells = <1>; + + binman { + pad-byte = <0xff>; + u-boot-spl { + symbols-base = <0>; + }; + + u-boot { + offset = <0x1c>; + }; + + u-boot-spl2 { + type = "u-boot-spl"; + }; + }; +}; diff --git a/tools/binman/test/337_symbols_base_expand.dts b/tools/binman/test/337_symbols_base_expand.dts new file mode 100644 index 0000000000..5a777ae63b --- /dev/null +++ b/tools/binman/test/337_symbols_base_expand.dts @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pad-byte = <0xff>; + u-boot-spl { + symbols-base = <0>; + }; + + u-boot { + offset = <0x38>; + no-expanded; + }; + + u-boot-spl2 { + type = "u-boot-spl"; + }; + }; +}; -- 2.39.5