[PATCH 6/8] binman: Provide general support for updating ELF symbols

Simon Glass sjg at chromium.org
Thu Jan 12 00:10:17 CET 2023


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 <sjg at chromium.org>
---

 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 97e2d4e55d5..980a1ac5bde 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 73f318b81d2..9ac00ed9ccf 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 0c94665f7a8..aca08e62d3a 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 70dea7158ee..c7ddcedffb8 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 be1610569fc..7f710c857db 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 aea8a5f7589..17b0431d4f3 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('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
+        expected = sym_values
+        self.assertEqual(expected, data[:len(expected)])
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/273_blob_symbol.dts b/tools/binman/test/273_blob_symbol.dts
new file mode 100644
index 00000000000..87b0aba2120
--- /dev/null
+++ b/tools/binman/test/273_blob_symbol.dts
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+	#address-cells = <1>;
+	#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 bea8567c9b4..cd66a3038be 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 00000000000..d652c79aa98
--- /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 <linux/kconfig.h>
+#include <binman_sym.h>
+
+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 00000000000..787e38dd853
--- /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.0.314.g84b9a713c41-goog



More information about the U-Boot mailing list