jacking/elf2img.py

145 lines
5.0 KiB
Python

#!/usr/bin/env python3
# Copyright (C) 2018 Marcus Comstedt
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import sys
import struct
class elf:
def read_struct(this, struct_fmt, struct_fields):
fmt = this.elf_endianprefix+str.translate(struct_fmt, this.elf_format);
fields = struct.unpack(fmt, this.file.read(struct.calcsize(fmt)))
return dict(zip(struct_fields, fields))
def read_ehdr(this):
return this.read_struct('16sHHWNNNWHHHHHH',
('e_ident', 'e_type', 'e_machine', 'e_version',
'e_entry', 'e_phoff', 'e_shoff', 'e_flags',
'e_ehsize', 'e_phentsize', 'e_phnum',
'e_shentsize', 'e_shnum', 'e_shstrndx'))
def read_phdr(this):
if this.elf_wordsize == 64:
return this.read_struct('WWNNNXXX',
('p_type', 'p_flags', 'p_offset', 'p_vaddr',
'p_paddr', 'p_filesz', 'p_memsz', 'p_align'))
else:
return this.read_struct('WNNNWWWW',
('p_type', 'p_offset', 'p_vaddr', 'p_paddr',
'p_filesz', 'p_memsz', 'p_flags', 'p_align'))
def __init__(this, filename):
this.file = open(filename, 'rb')
magic = this.file.read(16)
if magic[:4] != b'\x7fELF':
raise Exception("ELF signature not found")
if magic[4] == 1:
this.elf_wordsize = 32
nativeint = 'Ii'
elif magic[4] == 2:
this.elf_wordsize = 64
nativeint = 'Qq'
else:
raise Exception("Invalid ELF file class")
if magic[5] == 1:
this.elf_endianprefix = '<'
elif magic[5] == 2:
this.elf_endianprefix = '>'
else:
raise Exception("Invalid ELF data encoding")
this.elf_format = str.maketrans('HWwXxNn', 'HIiQq'+nativeint)
this.file.seek(0)
this.ehdr = this.read_ehdr()
this.file.seek(this.ehdr['e_phoff'])
this.phdrs = [this.read_phdr() for i in range(this.ehdr['e_phnum'])]
def copy_segment(phdr, infile, outfile):
checksum = 0
infile.seek(phdr['p_offset'])
filesz = phdr['p_filesz']
memsz = phdr['p_memsz']
if (filesz > memsz):
print("Warning: File size larger than mem size, fixing...")
memsz = filesz
if (memsz & 3) != 0:
print("Warning: Unaligned memsize of segment, padding...")
memsz = (memsz + 3) & ~3
vaddr = phdr['p_vaddr']
while (memsz > 0):
chunksz = 65536 if memsz > 65536 else memsz
outfile.write(struct.pack('<2I', chunksz >> 2, vaddr))
vaddr += chunksz
memsz -= chunksz
while chunksz > 0:
slicesz = 8192 if chunksz > 8192 else chunksz
if filesz > 0:
readsz = slicesz if filesz > slicesz else filesz
block = infile.read(readsz)
if len(block) == 0:
print("Warning: EOF on reading input ELF")
filesz = 0
else:
filesz -= len(block)
else:
block = b''
if filesz == 0 and len(block) < slicesz:
block += b'\0' * (slicesz - len(block))
checksum += sum(struct.unpack('<%dI'%(len(block) >> 2), block))
outfile.write(block)
chunksz -= len(block)
return checksum
def usage():
print("elf2img.py <elffile> <imgfile>")
sys.exit(1)
#
# main
#
if len(sys.argv) != 3:
usage()
elf_filename = sys.argv[1]
img_filename = sys.argv[2]
# TODO: add flags and ELF NOTE parsing for these -sys64738
i2c_config = 0x1c
image_type = 0xb0
checksum = 0
e = elf(elf_filename)
i = open(img_filename, 'wb')
i.write(struct.pack('<4B', ord(b'C'), ord(b'Y'), i2c_config, image_type))
for p in e.phdrs:
if p['p_type'] == 1:
checksum += copy_segment(p, e.file, i)
i.write(struct.pack('<3I', 0, e.ehdr['e_entry'], checksum & 0xffffffff))
i.close()