binman: Support positioning an entry by and ELF symbol
authorSimon Glass <sjg@chromium.org>
Wed, 11 Jan 2023 23:10:19 +0000 (16:10 -0700)
committerSimon Glass <sjg@chromium.org>
Wed, 18 Jan 2023 21:55:41 +0000 (14:55 -0700)
In some cases it is useful to position an entry over the top of a symbol
in an ELF file. For example, if the symbol holds a version string then it
allows the string to be accessed from the fdtmap.

Add support for this.

Suggested-by: Pali Rohár <pali@kernel.org>
Suggested-by: Keith Short <keithshort@chromium.org>
Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/binman.rst
tools/binman/elf.py
tools/binman/entry.py
tools/binman/ftest.py
tools/binman/test/274_offset_from_elf.dts [new file with mode: 0644]

index 980a1ac5bdee47b252247a3d904ac5ae93fff15e..fa8abdcd86a2dfb92d2bd71b3bc959a4286e3bb9 100644 (file)
@@ -823,6 +823,13 @@ elf-base-sym:
     needed. Add this symbol to the properties for the blob so that symbols can
     be read correctly. See binman_syms_ for more information.
 
+offset-from-elf:
+    Sets the offset of an entry based on a symbol value in an another entry.
+    The format is <&phandle>, "sym_name", <offset> where phandle is the entry
+    containing the blob (with associated ELF file providing symbols), <sym_name>
+    is the symbol to lookup (relative to elf-base-sym) and <offset> is an offset
+    to add to that value.
+
 Examples of the above options can be found in the tests. See the
 tools/binman/test directory.
 
index 9ac00ed9ccf1fa00878cfd04b96db9fce3bc671d..3cc8a3844950e3f9905c2308bffb698f7ff400e5 100644 (file)
@@ -210,6 +210,29 @@ def GetPackString(sym, msg):
         raise ValueError('%s has size %d: only 4 and 8 are supported' %
                          (msg, sym.size))
 
+def GetSymbolOffset(elf_fname, sym_name, base_sym=None):
+    """Read the offset of a symbol compared to base symbol
+
+    This is useful for obtaining the value of a single symbol relative to the
+    base of a binary blob.
+
+    Args:
+        elf_fname: Filename of the ELF file to read
+        sym_name (str): Name of symbol to read
+        base_sym (str): Base symbol to sue to calculate the offset (or None to
+            use '__image_copy_start'
+
+    Returns:
+        int: Offset of the symbol relative to the base symbol
+    """
+    if not base_sym:
+        base_sym = '__image_copy_start'
+    fname = tools.get_input_filename(elf_fname)
+    syms = GetSymbols(fname, [base_sym, sym_name])
+    base = syms[base_sym].address
+    val = syms[sym_name].address
+    return val - base
+
 def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
                           base_sym=None):
     """Replace all symbols in an entry with their correct values
index aca08e62d3a0c14bd1afd64a00295e15f9d207a7..5d8696e32a509643773ada955ab0f79af155d3eb 100644 (file)
@@ -145,6 +145,7 @@ class Entry(object):
         self.optional = False
         self.overlap = False
         self.elf_base_sym = None
+        self.offset_from_elf = None
 
     @staticmethod
     def FindEntryClass(etype, expanded):
@@ -303,6 +304,8 @@ class Entry(object):
 
         # This is only supported by blobs and sections at present
         self.compress = fdt_util.GetString(self._node, 'compress', 'none')
+        self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
+                                                             'offset-from-elf')
 
     def GetDefaultFilename(self):
         return None
@@ -499,7 +502,10 @@ class Entry(object):
             if self.offset_unset:
                 self.Raise('No offset set with offset-unset: should another '
                            'entry provide this correct offset?')
-            self.offset = tools.align(offset, self.align)
+            elif self.offset_from_elf:
+                self.offset = self.lookup_offset()
+            else:
+                self.offset = tools.align(offset, self.align)
         needed = self.pad_before + self.contents_size + self.pad_after
         needed = tools.align(needed, self.align_size)
         size = self.size
@@ -1328,3 +1334,14 @@ features to produce new behaviours.
                 int: entry address of ELF file
         """
         return None
+
+    def lookup_offset(self):
+        node, sym_name, offset = self.offset_from_elf
+        entry = self.section.FindEntryByNode(node)
+        if not entry:
+            self.Raise("Cannot find entry for node '%s'" % node.name)
+        if not entry.elf_fname:
+            entry.Raise("Need elf-fname property '%s'" % node.name)
+        val = elf.GetSymbolOffset(entry.elf_fname, sym_name,
+                                  entry.elf_base_sym)
+        return val + offset
index 17b0431d4f39596ea04e885e07b6adfe69b1ddc7..be0aea49ce9b738be8341fdde49b65a5e2d57759 100644 (file)
@@ -6281,6 +6281,34 @@ fdt         fdtmap                Extract the devicetree blob from the fdtmap
         expected = sym_values
         self.assertEqual(expected, data[:len(expected)])
 
+    def testOffsetFromElf(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('274_offset_from_elf.dts')
+
+        syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
+        base = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
+
+        image = control.images['image']
+        entries = image.GetEntries()
+
+        self.assertIn('inset', entries)
+        inset = entries['inset']
+
+        self.assertEqual(base + 4, inset.offset);
+        self.assertEqual(base + 4, inset.image_pos);
+        self.assertEqual(4, inset.size);
+
+        self.assertIn('inset2', entries)
+        inset = entries['inset2']
+        self.assertEqual(base + 8, inset.offset);
+        self.assertEqual(base + 8, inset.image_pos);
+        self.assertEqual(4, inset.size);
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/tools/binman/test/274_offset_from_elf.dts b/tools/binman/test/274_offset_from_elf.dts
new file mode 100644 (file)
index 0000000..e3372fc
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               blob: blob {
+                       filename = "blob_syms.bin";
+                       elf-filename = "blob_syms";
+                       elf-base-sym = "__my_start_sym";
+               };
+
+               inset {
+                       type = "null";
+                       offset-from-elf = <&blob>, "val3", <0>;
+                       size = <4>;
+                       overlap;
+               };
+
+               inset2 {
+                       type = "null";
+                       offset-from-elf = <&blob>, "val3", <4>;
+                       size = <4>;
+                       overlap;
+               };
+       };
+};