binman: Support positioning an entry by and ELF symbol
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>
diff --git a/tools/binman/binman.rst b/tools/binman/binman.rst
index 980a1ac..fa8abdc 100644
--- a/tools/binman/binman.rst
+++ b/tools/binman/binman.rst
@@ -823,6 +823,13 @@
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.
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index 9ac00ed..3cc8a38 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -210,6 +210,29 @@
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
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index aca08e6..5d8696e 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -145,6 +145,7 @@
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 @@
# 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 @@
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 @@
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
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 17b0431..be0aea4 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -6281,6 +6281,34 @@
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
index 0000000..e3372fc
--- /dev/null
+++ b/tools/binman/test/274_offset_from_elf.dts
@@ -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;
+ };
+ };
+};