From c1157860c5e9ca45e41859e013ed83919e7397f0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 11 Jan 2023 16:10:17 -0700 Subject: [PATCH] binman: Provide general support for updating ELF symbols The current support for updating variables in a binary is hard-coded to work with U-Boot: - It assumes the image starts at __image_copy_start - It uses the existing U-Boot-specific entry types It is useful for other projects to use these feature. Add properties to enable writing symbols for any blob, a way of specifying the base symbol and a way of providing the ELF filename to allow symbol lookup to take place. With this it is possible to update a Zephyr image, such as zephyr.bin after it has been built. Signed-off-by: Simon Glass --- tools/binman/binman.rst | 25 ++++++++++++++++++++++ tools/binman/elf.py | 8 +++++-- tools/binman/entry.py | 3 ++- tools/binman/etype/blob.py | 6 ++++++ tools/binman/etype/u_boot_spl.py | 1 - tools/binman/ftest.py | 19 +++++++++++++++++ tools/binman/test/273_blob_symbol.dts | 24 +++++++++++++++++++++ tools/binman/test/Makefile | 9 +++++++- tools/binman/test/blob_syms.c | 20 ++++++++++++++++++ tools/binman/test/blob_syms.lds | 30 +++++++++++++++++++++++++++ 10 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 tools/binman/test/273_blob_symbol.dts create mode 100644 tools/binman/test/blob_syms.c create mode 100644 tools/binman/test/blob_syms.lds diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst index 97e2d4e55d..980a1ac5bd 100644 --- a/tools/binman/binman.rst +++ b/tools/binman/binman.rst @@ -487,6 +487,13 @@ 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. +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 +filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the +start of the binary image (this defaults to `__image_copy_start` which is what +U-Boot uses). See `testBlobSymbol()` for an example. + .. _binman_fdt: Access to binman entry offsets at run time (fdt) @@ -798,6 +805,24 @@ overlap: packed with other entries, but their contents are written over other entries in the section. Overlapping entries must have an explicit offset and size. +write-symbols: + Indicates that the blob should be updated with symbol values calculated by + binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See + binman_syms_ for more information. + +elf-filename: + Sets the file name of a blob's associated ELF file. For example, if the + blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows + binman to locate symbols and understand the structure of the blob. See + binman_syms_ for more information. + +elf-base-sym: + Sets the name of the ELF symbol that points to the start of a blob. For + U-Boot this is `__image_copy_start` and that is the default used by binman + if this property is missing. For other projects, a difference symbol may be + needed. Add this symbol to the properties for the blob so that symbols can + be read correctly. See binman_syms_ for more information. + Examples of the above options can be found in the tests. See the tools/binman/test directory. diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 73f318b81d..9ac00ed9cc 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -210,7 +210,8 @@ def GetPackString(sym, msg): raise ValueError('%s has size %d: only 4 and 8 are supported' % (msg, sym.size)) -def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): +def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False, + base_sym=None): """Replace all symbols in an entry with their correct values The entry contents is updated so that values for referenced symbols will be @@ -223,7 +224,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): entry entry: Entry to process section: Section which can be used to lookup symbol values + base_sym: Base symbol marking the start of the image """ + if not base_sym: + base_sym = '__image_copy_start' fname = tools.get_input_filename(elf_fname) syms = GetSymbols(fname, ['image', 'binman']) if is_elf: @@ -243,7 +247,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False): if not syms: tout.debug('LookupAndWriteSymbols: no syms') return - base = syms.get('__image_copy_start') + base = syms.get(base_sym) if not base and not is_elf: tout.debug('LookupAndWriteSymbols: no base') return diff --git a/tools/binman/entry.py b/tools/binman/entry.py index 0c94665f7a..aca08e62d3 100644 --- a/tools/binman/entry.py +++ b/tools/binman/entry.py @@ -144,6 +144,7 @@ class Entry(object): self.absent = False self.optional = False self.overlap = False + self.elf_base_sym = None @staticmethod def FindEntryClass(etype, expanded): @@ -676,7 +677,7 @@ 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) + is_elf, self.elf_base_sym) def CheckEntries(self): """Check that the entry offsets are correct diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py index 70dea7158e..c7ddcedffb 100644 --- a/tools/binman/etype/blob.py +++ b/tools/binman/etype/blob.py @@ -35,6 +35,12 @@ class Entry_blob(Entry): super().__init__(section, etype, node, auto_write_symbols=auto_write_symbols) self._filename = fdt_util.GetString(self._node, 'filename', self.etype) + self.elf_fname = fdt_util.GetString(self._node, 'elf-filename', + self.elf_fname) + self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym') + if not self.auto_write_symbols: + if fdt_util.GetBool(self._node, 'write-symbols'): + self.auto_write_symbols = True def ObtainContents(self, fake_size=0): self._filename = self.GetDefaultFilename() diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py index be1610569f..7f710c857d 100644 --- a/tools/binman/etype/u_boot_spl.py +++ b/tools/binman/etype/u_boot_spl.py @@ -34,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob): def __init__(self, section, etype, node): super().__init__(section, etype, node, auto_write_symbols=True) self.elf_fname = 'spl/u-boot-spl' - self.auto_write_symbols = True def GetDefaultFilename(self): return 'spl/u-boot-spl.bin' diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index aea8a5f758..17b0431d4f 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -6262,6 +6262,25 @@ fdt fdtmap Extract the devicetree blob from the fdtmap "Node '/binman/inset': 'fill' entry is missing properties: size", str(exc.exception)) + def testBlobSymbol(self): + """Test a blob with symbols read from an ELF file""" + elf_fname = self.ElfTestFile('blob_syms') + TestFunctional._MakeInputFile('blob_syms', tools.read_file(elf_fname)) + TestFunctional._MakeInputFile('blob_syms.bin', + tools.read_file(self.ElfTestFile('blob_syms.bin'))) + + data = self._DoReadFile('273_blob_symbol.dts') + + syms = elf.GetSymbols(elf_fname, ['binman', 'image']) + addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym') + self.assertEqual(syms['_binman_sym_magic'].address, addr) + self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4) + self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8) + + sym_values = struct.pack('; + #size-cells = <1>; + + binman { + blob { + filename = "blob_syms.bin"; + write-symbols; + elf-filename = "blob_syms"; + elf-base-sym = "__my_start_sym"; + }; + + inset { + type = "null"; + offset = <4>; + size = <8>; + overlap; + }; + }; +}; diff --git a/tools/binman/test/Makefile b/tools/binman/test/Makefile index bea8567c9b..cd66a3038b 100644 --- a/tools/binman/test/Makefile +++ b/tools/binman/test/Makefile @@ -30,11 +30,12 @@ LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds +LDS_BLOB := -T $(SRC)blob_syms.lds TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \ u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \ u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \ - u_boot_binman_embed u_boot_binman_embed_sm elf_sections + u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin all: $(TARGETS) @@ -71,6 +72,12 @@ u_boot_binman_embed: u_boot_binman_embed.c u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED) u_boot_binman_embed_sm: u_boot_binman_embed_sm.c +blob_syms.bin: blob_syms + $(OBJCOPY) -O binary $< -R .note.gnu.build-id $@ + +blob_syms: CFLAGS += $(LDS_BLOB) +blob_syms: blob_syms.c + elf_sections: CFLAGS += $(LDS_EFL_SECTIONS) elf_sections: elf_sections.c diff --git a/tools/binman/test/blob_syms.c b/tools/binman/test/blob_syms.c new file mode 100644 index 0000000000..d652c79aa9 --- /dev/null +++ b/tools/binman/test/blob_syms.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2017 Google, Inc + * + * Simple program to create some binman symbols. This is used by binman tests. + */ + +typedef unsigned long ulong; + +#include +#include + +DECLARE_BINMAN_MAGIC_SYM; + +unsigned long val1 = 123; +unsigned long val2 = 456; +binman_sym_declare(unsigned long, inset, offset); +unsigned long val3 = 789; +unsigned long val4 = 999; +binman_sym_declare(unsigned long, inset, size); diff --git a/tools/binman/test/blob_syms.lds b/tools/binman/test/blob_syms.lds new file mode 100644 index 0000000000..787e38dd85 --- /dev/null +++ b/tools/binman/test/blob_syms.lds @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2016 Google, Inc + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0x00000010; + _start = .; + + . = ALIGN(4); + .text : + { + __my_start_sym = .; + *(.text*) + } + + . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + } + .interp : { *(.interp*) } + +} -- 2.39.5