[PATCH 13/45] binman: Support writing symbols into ELF files
Simon Glass
sjg at chromium.org
Sun Sep 25 17:02:16 CEST 2022
In some cases we may package the ELF version of SPL builds instead of the
binary .bin file. Add support for this.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
tools/binman/elf.py | 41 +++++++++++++++----
tools/binman/entry.py | 5 ++-
tools/binman/etype/section.py | 2 +-
tools/binman/etype/u_boot_spl_elf.py | 3 +-
tools/binman/etype/u_boot_tpl_elf.py | 3 +-
tools/binman/etype/u_boot_vpl_elf.py | 25 ++++++++++++
tools/binman/ftest.py | 57 +++++++++++++++++++++++++++
tools/binman/test/256_symbols_elf.dts | 27 +++++++++++++
8 files changed, 151 insertions(+), 12 deletions(-)
create mode 100644 tools/binman/etype/u_boot_vpl_elf.py
create mode 100644 tools/binman/test/256_symbols_elf.dts
diff --git a/tools/binman/elf.py b/tools/binman/elf.py
index fec2116880b..fe50bf542c3 100644
--- a/tools/binman/elf.py
+++ b/tools/binman/elf.py
@@ -210,7 +210,7 @@ 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):
+def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
"""Replace all symbols in an entry with their correct values
The entry contents is updated so that values for referenced symbols will be
@@ -226,27 +226,52 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
"""
fname = tools.get_input_filename(elf_fname)
syms = GetSymbols(fname, ['image', 'binman'])
+ if is_elf:
+ if not ELF_TOOLS:
+ msg = ("Section '%s': entry '%s'" %
+ (section.GetPath(), entry.GetPath()))
+ raise ValueError(f'{msg}: Cannot write symbols to an ELF file without Python elftools')
+ new_syms = {}
+ with open(fname, 'rb') as fd:
+ elf = ELFFile(fd)
+ for name, sym in syms.items():
+ offset = _GetFileOffset(elf, sym.address)
+ new_syms[name] = Symbol(sym.section, sym.address, sym.size,
+ sym.weak, offset)
+ syms = new_syms
+
if not syms:
+ tout.debug('LookupAndWriteSymbols: no syms')
return
base = syms.get('__image_copy_start')
- if not base:
+ if not base and not is_elf:
+ tout.debug('LookupAndWriteSymbols: no base')
return
+ base_addr = 0 if is_elf else base.address
for name, sym in syms.items():
if name.startswith('_binman'):
msg = ("Section '%s': Symbol '%s'\n in entry '%s'" %
(section.GetPath(), name, entry.GetPath()))
- offset = sym.address - base.address
- if offset < 0 or offset + sym.size > entry.contents_size:
- raise ValueError('%s has offset %x (size %x) but the contents '
- 'size is %x' % (entry.GetPath(), offset,
- sym.size, entry.contents_size))
+ if is_elf:
+ # For ELF files, use the file offset
+ offset = sym.offset
+ else:
+ # For blobs use the offset of the symbol, calculated by
+ # subtracting the base address which by definition is at the
+ # start
+ offset = sym.address - base.address
+ if offset < 0 or offset + sym.size > entry.contents_size:
+ raise ValueError('%s has offset %x (size %x) but the contents '
+ 'size is %x' % (entry.GetPath(), offset,
+ sym.size,
+ entry.contents_size))
pack_string = GetPackString(sym, msg)
if name == '_binman_sym_magic':
value = BINMAN_SYM_MAGIC_VALUE
else:
# Look up the symbol in our entry tables.
value = section.GetImage().LookupImageSymbol(name, sym.weak,
- msg, base.address)
+ msg, base_addr)
if value is None:
value = -1
pack_string = pack_string.lower()
diff --git a/tools/binman/entry.py b/tools/binman/entry.py
index bdf53ddd922..1be31a05e00 100644
--- a/tools/binman/entry.py
+++ b/tools/binman/entry.py
@@ -656,7 +656,10 @@ class Entry(object):
section: Section containing the entry
"""
if self.auto_write_symbols:
- elf.LookupAndWriteSymbols(self.elf_fname, self, section.GetImage())
+ # 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)
def CheckEntries(self):
"""Check that the entry offsets are correct
diff --git a/tools/binman/etype/section.py b/tools/binman/etype/section.py
index b68c6fd037b..c56b962c20c 100644
--- a/tools/binman/etype/section.py
+++ b/tools/binman/etype/section.py
@@ -550,7 +550,7 @@ class Entry_section(Entry):
for name in entries:
if name.startswith(root):
rest = name[len(root):]
- if rest in ['', '-img', '-nodtb']:
+ if rest in ['', '-elf', '-img', '-nodtb']:
entry = entries[name]
return entry, entry_name, prop_name
diff --git a/tools/binman/etype/u_boot_spl_elf.py b/tools/binman/etype/u_boot_spl_elf.py
index 7f1236bcbb3..7b7b4e01495 100644
--- a/tools/binman/etype/u_boot_spl_elf.py
+++ b/tools/binman/etype/u_boot_spl_elf.py
@@ -18,7 +18,8 @@ class Entry_u_boot_spl_elf(Entry_blob):
be relocated to any address for execution.
"""
def __init__(self, section, etype, node):
- super().__init__(section, etype, node)
+ super().__init__(section, etype, node, auto_write_symbols=True)
+ self.elf_fname = 'spl/u-boot-spl'
def GetDefaultFilename(self):
return 'spl/u-boot-spl'
diff --git a/tools/binman/etype/u_boot_tpl_elf.py b/tools/binman/etype/u_boot_tpl_elf.py
index 3f24d3aa7bc..fd100019b39 100644
--- a/tools/binman/etype/u_boot_tpl_elf.py
+++ b/tools/binman/etype/u_boot_tpl_elf.py
@@ -18,7 +18,8 @@ class Entry_u_boot_tpl_elf(Entry_blob):
be relocated to any address for execution.
"""
def __init__(self, section, etype, node):
- super().__init__(section, etype, node)
+ super().__init__(section, etype, node, auto_write_symbols=True)
+ self.elf_fname = 'tpl/u-boot-tpl'
def GetDefaultFilename(self):
return 'tpl/u-boot-tpl'
diff --git a/tools/binman/etype/u_boot_vpl_elf.py b/tools/binman/etype/u_boot_vpl_elf.py
new file mode 100644
index 00000000000..2c686790194
--- /dev/null
+++ b/tools/binman/etype/u_boot_vpl_elf.py
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2022 Google LLC
+# Written by Simon Glass <sjg at chromium.org>
+#
+# Entry-type module for U-Boot VPL ELF image
+#
+
+from binman.entry import Entry
+from binman.etype.blob import Entry_blob
+
+class Entry_u_boot_vpl_elf(Entry_blob):
+ """U-Boot VPL ELF image
+
+ Properties / Entry arguments:
+ - filename: Filename of VPL u-boot (default 'vpl/u-boot-vpl')
+
+ This is the U-Boot VPL ELF image. It does not include a device tree but can
+ be relocated to any address for execution.
+ """
+ def __init__(self, section, etype, node):
+ super().__init__(section, etype, node, auto_write_symbols=True)
+ self.elf_fname = 'vpl/u-boot-vpl'
+
+ def GetDefaultFilename(self):
+ return 'vpl/u-boot-vpl'
diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
index 4bdd08046bb..9ae293d918a 100644
--- a/tools/binman/ftest.py
+++ b/tools/binman/ftest.py
@@ -5965,6 +5965,63 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
self.assertIn('Expected __bss_size symbol in vpl/u-boot-vpl',
str(e.exception))
+ def testSymbolsElf(self):
+ """Test binman can assign symbols embedded in an ELF file"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ self._SetupTplElf('u_boot_binman_syms')
+ self._SetupVplElf('u_boot_binman_syms')
+ self._SetupSplElf('u_boot_binman_syms')
+ data = self._DoReadFileDtb('256_symbols_elf.dts')[0]
+ image_fname = tools.get_output_filename('image.bin')
+
+ image = control.images['image']
+ entries = image.GetEntries()
+
+ for entry in entries.values():
+ # No symbols in u-boot and it has faked contents anyway
+ if entry.name == 'u-boot':
+ continue
+ edata = data[entry.image_pos:entry.image_pos + entry.size]
+ efname = tools.get_output_filename(f'edata-{entry.name}')
+ tools.write_file(efname, edata)
+
+ syms = elf.GetSymbolFileOffset(efname, ['_binman_u_boot'])
+ re_name = re.compile('_binman_(u_boot_(.*))_prop_(.*)')
+ for name, sym in syms.items():
+ msg = 'test'
+ val = elf.GetSymbolValue(sym, edata, msg)
+ entry_m = re_name.match(name)
+ if entry_m:
+ ename, prop = entry_m.group(1), entry_m.group(3)
+ entry, entry_name, prop_name = image.LookupEntry(entries,
+ name, msg)
+ if prop_name == 'offset':
+ expect_val = entry.offset
+ elif prop_name == 'image_pos':
+ expect_val = entry.image_pos
+ elif prop_name == 'size':
+ expect_val = entry.size
+ self.assertEqual(expect_val, val)
+
+ def testSymbolsElfBad(self):
+ """Check error when trying to write symbols without the elftools lib"""
+ if not elf.ELF_TOOLS:
+ self.skipTest('Python elftools not available')
+ self._SetupTplElf('u_boot_binman_syms')
+ self._SetupVplElf('u_boot_binman_syms')
+ self._SetupSplElf('u_boot_binman_syms')
+ try:
+ elf.ELF_TOOLS = False
+ with self.assertRaises(ValueError) as exc:
+ self._DoReadFileDtb('256_symbols_elf.dts')
+ finally:
+ elf.ELF_TOOLS = True
+ self.assertIn(
+ "Section '/binman': entry '/binman/u-boot-spl-elf': "
+ 'Cannot write symbols to an ELF file without Python elftools',
+ str(exc.exception))
+
if __name__ == "__main__":
unittest.main()
diff --git a/tools/binman/test/256_symbols_elf.dts b/tools/binman/test/256_symbols_elf.dts
new file mode 100644
index 00000000000..0fae118fc12
--- /dev/null
+++ b/tools/binman/test/256_symbols_elf.dts
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ binman {
+ pad-byte = <0xff>;
+ u-boot-spl-elf {
+ };
+
+ u-boot {
+ };
+
+ u-boot-spl2 {
+ type = "u-boot-spl-elf";
+ };
+
+ u-boot-tpl-elf {
+ };
+
+ u-boot-vpl-elf {
+ };
+ };
+};
--
2.37.3.998.g577e59143f-goog
More information about the U-Boot
mailing list