binman: Support writing symbols into ELF files
In some cases the ELF version of SPL builds may be packaged, rather than a binary .bin file. Add support for this. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
3fbba5568c
commit
d2afb9edce
@ -210,7 +210,7 @@ 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 LookupAndWriteSymbols(elf_fname, entry, section):
|
def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
|
||||||
"""Replace all symbols in an entry with their correct values
|
"""Replace all symbols in an entry with their correct values
|
||||||
|
|
||||||
The entry contents is updated so that values for referenced symbols will be
|
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)
|
fname = tools.get_input_filename(elf_fname)
|
||||||
syms = GetSymbols(fname, ['image', 'binman'])
|
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:
|
if not syms:
|
||||||
|
tout.debug('LookupAndWriteSymbols: no syms')
|
||||||
return
|
return
|
||||||
base = syms.get('__image_copy_start')
|
base = syms.get('__image_copy_start')
|
||||||
if not base:
|
if not base and not is_elf:
|
||||||
|
tout.debug('LookupAndWriteSymbols: no base')
|
||||||
return
|
return
|
||||||
|
base_addr = 0 if is_elf else base.address
|
||||||
for name, sym in syms.items():
|
for name, sym in syms.items():
|
||||||
if name.startswith('_binman'):
|
if name.startswith('_binman'):
|
||||||
msg = ("Section '%s': Symbol '%s'\n in entry '%s'" %
|
msg = ("Section '%s': Symbol '%s'\n in entry '%s'" %
|
||||||
(section.GetPath(), name, entry.GetPath()))
|
(section.GetPath(), name, entry.GetPath()))
|
||||||
offset = sym.address - base.address
|
if is_elf:
|
||||||
if offset < 0 or offset + sym.size > entry.contents_size:
|
# For ELF files, use the file offset
|
||||||
raise ValueError('%s has offset %x (size %x) but the contents '
|
offset = sym.offset
|
||||||
'size is %x' % (entry.GetPath(), offset,
|
else:
|
||||||
sym.size, entry.contents_size))
|
# 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)
|
pack_string = GetPackString(sym, msg)
|
||||||
if name == '_binman_sym_magic':
|
if name == '_binman_sym_magic':
|
||||||
value = BINMAN_SYM_MAGIC_VALUE
|
value = BINMAN_SYM_MAGIC_VALUE
|
||||||
else:
|
else:
|
||||||
# Look up the symbol in our entry tables.
|
# Look up the symbol in our entry tables.
|
||||||
value = section.GetImage().LookupImageSymbol(name, sym.weak,
|
value = section.GetImage().LookupImageSymbol(name, sym.weak,
|
||||||
msg, base.address)
|
msg, base_addr)
|
||||||
if value is None:
|
if value is None:
|
||||||
value = -1
|
value = -1
|
||||||
pack_string = pack_string.lower()
|
pack_string = pack_string.lower()
|
||||||
|
@ -656,7 +656,10 @@ class Entry(object):
|
|||||||
section: Section containing the entry
|
section: Section containing the entry
|
||||||
"""
|
"""
|
||||||
if self.auto_write_symbols:
|
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):
|
def CheckEntries(self):
|
||||||
"""Check that the entry offsets are correct
|
"""Check that the entry offsets are correct
|
||||||
|
@ -550,7 +550,7 @@ class Entry_section(Entry):
|
|||||||
for name in entries:
|
for name in entries:
|
||||||
if name.startswith(root):
|
if name.startswith(root):
|
||||||
rest = name[len(root):]
|
rest = name[len(root):]
|
||||||
if rest in ['', '-img', '-nodtb']:
|
if rest in ['', '-elf', '-img', '-nodtb']:
|
||||||
entry = entries[name]
|
entry = entries[name]
|
||||||
return entry, entry_name, prop_name
|
return entry, entry_name, prop_name
|
||||||
|
|
||||||
|
@ -18,7 +18,8 @@ class Entry_u_boot_spl_elf(Entry_blob):
|
|||||||
be relocated to any address for execution.
|
be relocated to any address for execution.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
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):
|
def GetDefaultFilename(self):
|
||||||
return 'spl/u-boot-spl'
|
return 'spl/u-boot-spl'
|
||||||
|
@ -18,7 +18,8 @@ class Entry_u_boot_tpl_elf(Entry_blob):
|
|||||||
be relocated to any address for execution.
|
be relocated to any address for execution.
|
||||||
"""
|
"""
|
||||||
def __init__(self, section, etype, node):
|
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):
|
def GetDefaultFilename(self):
|
||||||
return 'tpl/u-boot-tpl'
|
return 'tpl/u-boot-tpl'
|
||||||
|
25
tools/binman/etype/u_boot_vpl_elf.py
Normal file
25
tools/binman/etype/u_boot_vpl_elf.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0+
|
||||||
|
# Copyright 2022 Google LLC
|
||||||
|
# Written by Simon Glass <sjg@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'
|
@ -6005,5 +6005,62 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
|||||||
self.assertTrue(os.path.islink(sname))
|
self.assertTrue(os.path.islink(sname))
|
||||||
self.assertEqual(os.readlink(sname), fname)
|
self.assertEqual(os.readlink(sname), fname)
|
||||||
|
|
||||||
|
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('260_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('260_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__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
27
tools/binman/test/260_symbols_elf.dts
Normal file
27
tools/binman/test/260_symbols_elf.dts
Normal file
@ -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 {
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user