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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2019-07-08 13:18:34 -06:00
parent 45cb9d80ae
commit f58558a5ae
2 changed files with 117 additions and 0 deletions

View file

@ -5,11 +5,15 @@
# Handle various things related to ELF images # Handle various things related to ELF images
# #
from __future__ import print_function
from collections import namedtuple, OrderedDict from collections import namedtuple, OrderedDict
import command import command
import os import os
import re import re
import shutil
import struct import struct
import tempfile
import tools import tools
@ -128,3 +132,96 @@ def LookupAndWriteSymbols(elf_fname, entry, section):
(msg, name, offset, value, len(value_bytes))) (msg, name, offset, value, len(value_bytes)))
entry.data = (entry.data[:offset] + value_bytes + entry.data = (entry.data[:offset] + value_bytes +
entry.data[offset + sym.size:]) 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)

View file

@ -5,9 +5,12 @@
# Test for the elf module # Test for the elf module
import os import os
import shutil
import sys import sys
import tempfile
import unittest import unittest
import command
import elf import elf
import test_util import test_util
import tools import tools
@ -136,6 +139,23 @@ class TestElf(unittest.TestCase):
elf.debug = False elf.debug = False
self.assertTrue(len(stdout.getvalue()) > 0) 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__': if __name__ == '__main__':
unittest.main() unittest.main()