mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-10 23:24:38 +00:00
binman: Provide general support for updating ELF symbols
The current support for updating variables in a binary is hard-coded to work with U-Boot: - It assumes the image starts at __image_copy_start - It uses the existing U-Boot-specific entry types It is useful for other projects to use these feature. Add properties to enable writing symbols for any blob, a way of specifying the base symbol and a way of providing the ELF filename to allow symbol lookup to take place. With this it is possible to update a Zephyr image, such as zephyr.bin after it has been built. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
9766f69c98
commit
c1157860c5
10 changed files with 140 additions and 5 deletions
|
@ -487,6 +487,13 @@ For x86 devices (with the end-at-4gb property) this base address is not added
|
|||
since it is assumed that images are XIP and the offsets already include the
|
||||
address.
|
||||
|
||||
While U-Boot's symbol updating is handled automatically by the u-boot-spl
|
||||
entry type (and others), it is possible to use this feature with any blob. To
|
||||
do this, add a `write-symbols` (boolean) property to the node, set the ELF
|
||||
filename using `elf-filename` and set 'elf-base-sym' to the base symbol for the
|
||||
start of the binary image (this defaults to `__image_copy_start` which is what
|
||||
U-Boot uses). See `testBlobSymbol()` for an example.
|
||||
|
||||
.. _binman_fdt:
|
||||
|
||||
Access to binman entry offsets at run time (fdt)
|
||||
|
@ -798,6 +805,24 @@ overlap:
|
|||
packed with other entries, but their contents are written over other entries
|
||||
in the section. Overlapping entries must have an explicit offset and size.
|
||||
|
||||
write-symbols:
|
||||
Indicates that the blob should be updated with symbol values calculated by
|
||||
binman. This is automatic for certain entry types, e.g. `u-boot-spl`. See
|
||||
binman_syms_ for more information.
|
||||
|
||||
elf-filename:
|
||||
Sets the file name of a blob's associated ELF file. For example, if the
|
||||
blob is `zephyr.bin` then the ELF file may be `zephyr.elf`. This allows
|
||||
binman to locate symbols and understand the structure of the blob. See
|
||||
binman_syms_ for more information.
|
||||
|
||||
elf-base-sym:
|
||||
Sets the name of the ELF symbol that points to the start of a blob. For
|
||||
U-Boot this is `__image_copy_start` and that is the default used by binman
|
||||
if this property is missing. For other projects, a difference symbol may be
|
||||
needed. Add this symbol to the properties for the blob so that symbols can
|
||||
be read correctly. See binman_syms_ for more information.
|
||||
|
||||
Examples of the above options can be found in the tests. See the
|
||||
tools/binman/test directory.
|
||||
|
||||
|
|
|
@ -210,7 +210,8 @@ 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, is_elf=False):
|
||||
def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False,
|
||||
base_sym=None):
|
||||
"""Replace all symbols in an entry with their correct values
|
||||
|
||||
The entry contents is updated so that values for referenced symbols will be
|
||||
|
@ -223,7 +224,10 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
|
|||
entry
|
||||
entry: Entry to process
|
||||
section: Section which can be used to lookup symbol values
|
||||
base_sym: Base symbol marking the start of the image
|
||||
"""
|
||||
if not base_sym:
|
||||
base_sym = '__image_copy_start'
|
||||
fname = tools.get_input_filename(elf_fname)
|
||||
syms = GetSymbols(fname, ['image', 'binman'])
|
||||
if is_elf:
|
||||
|
@ -243,7 +247,7 @@ def LookupAndWriteSymbols(elf_fname, entry, section, is_elf=False):
|
|||
if not syms:
|
||||
tout.debug('LookupAndWriteSymbols: no syms')
|
||||
return
|
||||
base = syms.get('__image_copy_start')
|
||||
base = syms.get(base_sym)
|
||||
if not base and not is_elf:
|
||||
tout.debug('LookupAndWriteSymbols: no base')
|
||||
return
|
||||
|
|
|
@ -144,6 +144,7 @@ class Entry(object):
|
|||
self.absent = False
|
||||
self.optional = False
|
||||
self.overlap = False
|
||||
self.elf_base_sym = None
|
||||
|
||||
@staticmethod
|
||||
def FindEntryClass(etype, expanded):
|
||||
|
@ -676,7 +677,7 @@ class Entry(object):
|
|||
# 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)
|
||||
is_elf, self.elf_base_sym)
|
||||
|
||||
def CheckEntries(self):
|
||||
"""Check that the entry offsets are correct
|
||||
|
|
|
@ -35,6 +35,12 @@ class Entry_blob(Entry):
|
|||
super().__init__(section, etype, node,
|
||||
auto_write_symbols=auto_write_symbols)
|
||||
self._filename = fdt_util.GetString(self._node, 'filename', self.etype)
|
||||
self.elf_fname = fdt_util.GetString(self._node, 'elf-filename',
|
||||
self.elf_fname)
|
||||
self.elf_base_sym = fdt_util.GetString(self._node, 'elf-base-sym')
|
||||
if not self.auto_write_symbols:
|
||||
if fdt_util.GetBool(self._node, 'write-symbols'):
|
||||
self.auto_write_symbols = True
|
||||
|
||||
def ObtainContents(self, fake_size=0):
|
||||
self._filename = self.GetDefaultFilename()
|
||||
|
|
|
@ -34,7 +34,6 @@ class Entry_u_boot_spl(Entry_blob):
|
|||
def __init__(self, section, etype, node):
|
||||
super().__init__(section, etype, node, auto_write_symbols=True)
|
||||
self.elf_fname = 'spl/u-boot-spl'
|
||||
self.auto_write_symbols = True
|
||||
|
||||
def GetDefaultFilename(self):
|
||||
return 'spl/u-boot-spl.bin'
|
||||
|
|
|
@ -6262,6 +6262,25 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
|
|||
"Node '/binman/inset': 'fill' entry is missing properties: size",
|
||||
str(exc.exception))
|
||||
|
||||
def testBlobSymbol(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('273_blob_symbol.dts')
|
||||
|
||||
syms = elf.GetSymbols(elf_fname, ['binman', 'image'])
|
||||
addr = elf.GetSymbolAddress(elf_fname, '__my_start_sym')
|
||||
self.assertEqual(syms['_binman_sym_magic'].address, addr)
|
||||
self.assertEqual(syms['_binman_inset_prop_offset'].address, addr + 4)
|
||||
self.assertEqual(syms['_binman_inset_prop_size'].address, addr + 8)
|
||||
|
||||
sym_values = struct.pack('<LLL', elf.BINMAN_SYM_MAGIC_VALUE, 4, 8)
|
||||
expected = sym_values
|
||||
self.assertEqual(expected, data[:len(expected)])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
24
tools/binman/test/273_blob_symbol.dts
Normal file
24
tools/binman/test/273_blob_symbol.dts
Normal file
|
@ -0,0 +1,24 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
binman {
|
||||
blob {
|
||||
filename = "blob_syms.bin";
|
||||
write-symbols;
|
||||
elf-filename = "blob_syms";
|
||||
elf-base-sym = "__my_start_sym";
|
||||
};
|
||||
|
||||
inset {
|
||||
type = "null";
|
||||
offset = <4>;
|
||||
size = <8>;
|
||||
overlap;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -30,11 +30,12 @@ LDS_BINMAN_BAD := -T $(SRC)u_boot_binman_syms_bad.lds
|
|||
LDS_BINMAN_X86 := -T $(SRC)u_boot_binman_syms_x86.lds
|
||||
LDS_BINMAN_EMBED := -T $(SRC)u_boot_binman_embed.lds
|
||||
LDS_EFL_SECTIONS := -T $(SRC)elf_sections.lds
|
||||
LDS_BLOB := -T $(SRC)blob_syms.lds
|
||||
|
||||
TARGETS = u_boot_ucode_ptr u_boot_no_ucode_ptr bss_data \
|
||||
u_boot_binman_syms u_boot_binman_syms.bin u_boot_binman_syms_bad \
|
||||
u_boot_binman_syms_size u_boot_binman_syms_x86 embed_data \
|
||||
u_boot_binman_embed u_boot_binman_embed_sm elf_sections
|
||||
u_boot_binman_embed u_boot_binman_embed_sm elf_sections blob_syms.bin
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
|
@ -71,6 +72,12 @@ u_boot_binman_embed: u_boot_binman_embed.c
|
|||
u_boot_binman_embed_sm: CFLAGS += $(LDS_BINMAN_EMBED)
|
||||
u_boot_binman_embed_sm: u_boot_binman_embed_sm.c
|
||||
|
||||
blob_syms.bin: blob_syms
|
||||
$(OBJCOPY) -O binary $< -R .note.gnu.build-id $@
|
||||
|
||||
blob_syms: CFLAGS += $(LDS_BLOB)
|
||||
blob_syms: blob_syms.c
|
||||
|
||||
elf_sections: CFLAGS += $(LDS_EFL_SECTIONS)
|
||||
elf_sections: elf_sections.c
|
||||
|
||||
|
|
20
tools/binman/test/blob_syms.c
Normal file
20
tools/binman/test/blob_syms.c
Normal file
|
@ -0,0 +1,20 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2017 Google, Inc
|
||||
*
|
||||
* Simple program to create some binman symbols. This is used by binman tests.
|
||||
*/
|
||||
|
||||
typedef unsigned long ulong;
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <binman_sym.h>
|
||||
|
||||
DECLARE_BINMAN_MAGIC_SYM;
|
||||
|
||||
unsigned long val1 = 123;
|
||||
unsigned long val2 = 456;
|
||||
binman_sym_declare(unsigned long, inset, offset);
|
||||
unsigned long val3 = 789;
|
||||
unsigned long val4 = 999;
|
||||
binman_sym_declare(unsigned long, inset, size);
|
30
tools/binman/test/blob_syms.lds
Normal file
30
tools/binman/test/blob_syms.lds
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (c) 2016 Google, Inc
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x00000010;
|
||||
_start = .;
|
||||
|
||||
. = ALIGN(4);
|
||||
.text :
|
||||
{
|
||||
__my_start_sym = .;
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
. = ALIGN(4);
|
||||
.binman_sym_table : {
|
||||
__binman_sym_start = .;
|
||||
KEEP(*(SORT(.binman_sym*)));
|
||||
__binman_sym_end = .;
|
||||
}
|
||||
.interp : { *(.interp*) }
|
||||
|
||||
}
|
Loading…
Reference in a new issue