From f58558a5ae785fdbdaadbe172a2bb86158f01d4f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 8 Jul 2019 13:18:34 -0600 Subject: [PATCH] binman: Add a function to create a sample ELF file It is useful to create an ELF file for testing purposes, with just the right attributes used by the test. Add a function to handle this, along with a test that it works correctly. Signed-off-by: Simon Glass --- tools/binman/elf.py | 97 ++++++++++++++++++++++++++++++++++++++++ tools/binman/elf_test.py | 20 +++++++++ 2 files changed, 117 insertions(+) diff --git a/tools/binman/elf.py b/tools/binman/elf.py index 828681d76d..82ea8c3857 100644 --- a/tools/binman/elf.py +++ b/tools/binman/elf.py @@ -5,11 +5,15 @@ # Handle various things related to ELF images # +from __future__ import print_function + from collections import namedtuple, OrderedDict import command import os import re +import shutil import struct +import tempfile import tools @@ -128,3 +132,96 @@ def LookupAndWriteSymbols(elf_fname, entry, section): (msg, name, offset, value, len(value_bytes))) entry.data = (entry.data[:offset] + value_bytes + entry.data[offset + sym.size:]) + +def MakeElf(elf_fname, text, data): + """Make an elf file with the given data in a single section + + The output file has a several section including '.text' and '.data', + containing the info provided in arguments. + + Args: + elf_fname: Output filename + text: Text (code) to put in the file's .text section + data: Data to put in the file's .data section + """ + outdir = tempfile.mkdtemp(prefix='binman.elf.') + s_file = os.path.join(outdir, 'elf.S') + + # Spilt the text into two parts so that we can make the entry point two + # bytes after the start of the text section + text_bytes1 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[:2]] + text_bytes2 = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in text[2:]] + data_bytes = ['\t.byte\t%#x' % tools.ToByte(byte) for byte in data] + with open(s_file, 'w') as fd: + print('''/* Auto-generated C program to produce an ELF file for testing */ + +.section .text +.code32 +.globl _start +.type _start, @function +%s +_start: +%s +.ident "comment" + +.comm fred,8,4 + +.section .empty +.globl _empty +_empty: +.byte 1 + +.globl ernie +.data +.type ernie, @object +.size ernie, 4 +ernie: +%s +''' % ('\n'.join(text_bytes1), '\n'.join(text_bytes2), '\n'.join(data_bytes)), + file=fd) + lds_file = os.path.join(outdir, 'elf.lds') + + # Use a linker script to set the alignment and text address. + with open(lds_file, 'w') as fd: + print('''/* Auto-generated linker script to produce an ELF file for testing */ + +PHDRS +{ + text PT_LOAD ; + data PT_LOAD ; + empty PT_LOAD FLAGS ( 6 ) ; + note PT_NOTE ; +} + +SECTIONS +{ + . = 0xfef20000; + ENTRY(_start) + .text . : SUBALIGN(0) + { + *(.text) + } :text + .data : { + *(.data) + } :data + _bss_start = .; + .empty : { + *(.empty) + } :empty + .note : { + *(.comment) + } :note + .bss _bss_start (OVERLAY) : { + *(.bss) + } +} +''', file=fd) + # -static: Avoid requiring any shared libraries + # -nostdlib: Don't link with C library + # -Wl,--build-id=none: Don't generate a build ID, so that we just get the + # text section at the start + # -m32: Build for 32-bit x86 + # -T...: Specifies the link script, which sets the start address + stdout = command.Output('cc', '-static', '-nostdlib', '-Wl,--build-id=none', + '-m32','-T', lds_file, '-o', elf_fname, s_file) + shutil.rmtree(outdir) diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py index 42d94cbbbe..3172982427 100644 --- a/tools/binman/elf_test.py +++ b/tools/binman/elf_test.py @@ -5,9 +5,12 @@ # Test for the elf module import os +import shutil import sys +import tempfile import unittest +import command import elf import test_util import tools @@ -136,6 +139,23 @@ class TestElf(unittest.TestCase): elf.debug = False self.assertTrue(len(stdout.getvalue()) > 0) + def testMakeElf(self): + """Test for the MakeElf function""" + outdir = tempfile.mkdtemp(prefix='elf.') + expected_text = b'1234' + expected_data = b'wxyz' + elf_fname = os.path.join(outdir, 'elf') + bin_fname = os.path.join(outdir, 'elf') + + # Make an Elf file and then convert it to a fkat binary file. This + # should produce the original data. + elf.MakeElf(elf_fname, expected_text, expected_data) + stdout = command.Output('objcopy', '-O', 'binary', elf_fname, bin_fname) + with open(bin_fname, 'rb') as fd: + data = fd.read() + self.assertEqual(expected_text + expected_data, data) + shutil.rmtree(outdir) + if __name__ == '__main__': unittest.main() -- 2.25.1