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>
This commit is contained in:
Simon Glass 2023-01-11 16:10:19 -07:00
parent 8f5afe21ae
commit 571bc4e67d
5 changed files with 106 additions and 1 deletions

View file

@ -823,6 +823,13 @@ elf-base-sym:
needed. Add this symbol to the properties for the blob so that symbols can needed. Add this symbol to the properties for the blob so that symbols can
be read correctly. See binman_syms_ for more information. 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 Examples of the above options can be found in the tests. See the
tools/binman/test directory. tools/binman/test directory.

View file

@ -210,6 +210,29 @@ def GetPackString(sym, msg):
raise ValueError('%s has size %d: only 4 and 8 are supported' % raise ValueError('%s has size %d: only 4 and 8 are supported' %
(msg, sym.size)) (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, def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
base_sym=None): base_sym=None):
"""Replace all symbols in an entry with their correct values """Replace all symbols in an entry with their correct values

View file

@ -145,6 +145,7 @@ class Entry(object):
self.optional = False self.optional = False
self.overlap = False self.overlap = False
self.elf_base_sym = None self.elf_base_sym = None
self.offset_from_elf = None
@staticmethod @staticmethod
def FindEntryClass(etype, expanded): def FindEntryClass(etype, expanded):
@ -303,6 +304,8 @@ class Entry(object):
# This is only supported by blobs and sections at present # This is only supported by blobs and sections at present
self.compress = fdt_util.GetString(self._node, 'compress', 'none') self.compress = fdt_util.GetString(self._node, 'compress', 'none')
self.offset_from_elf = fdt_util.GetPhandleNameOffset(self._node,
'offset-from-elf')
def GetDefaultFilename(self): def GetDefaultFilename(self):
return None return None
@ -499,7 +502,10 @@ class Entry(object):
if self.offset_unset: if self.offset_unset:
self.Raise('No offset set with offset-unset: should another ' self.Raise('No offset set with offset-unset: should another '
'entry provide this correct offset?') '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 = self.pad_before + self.contents_size + self.pad_after
needed = tools.align(needed, self.align_size) needed = tools.align(needed, self.align_size)
size = self.size size = self.size
@ -1328,3 +1334,14 @@ features to produce new behaviours.
int: entry address of ELF file int: entry address of ELF file
""" """
return None 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

View file

@ -6281,6 +6281,34 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
expected = sym_values expected = sym_values
self.assertEqual(expected, data[:len(expected)]) 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__": if __name__ == "__main__":
unittest.main() unittest.main()

View file

@ -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;
};
};
};