aboutsummaryrefslogtreecommitdiffstats
path: root/psp_out/mkelf.py
blob: 3a2078951b7e6f6ebb1472a46afa9e73ef49523d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/usr/bin/env python3
"""Wrap a raw ARM/Thumb firmware image in a minimal ELF32 so IDA auto-detects
processor (EM_ARM), load address, and Thumb entry — no CLI / no -parm needed.

usage: mkelf.py <raw.bin> <base_hex> <out.elf> [--arm]
"""
import struct, sys, os

def mkelf(raw: bytes, base: int, thumb: bool = True) -> bytes:
    EHSIZE, PHENTSIZE = 52, 32
    DATA_OFF = 0x1000
    entry = base | (1 if thumb else 0)          # bit0 set => Thumb entry
    eh = b'\x7fELF'                              # magic
    eh += bytes([1, 1, 1, 0, 0])                 # 32-bit, LSB, ELFv1, SysV ABI
    eh += b'\x00' * 7
    eh += struct.pack('<HHI', 2, 40, 1)          # ET_EXEC, EM_ARM, version
    eh += struct.pack('<III', entry, EHSIZE, 0)  # entry, phoff, shoff
    eh += struct.pack('<I', 0x05000000)          # EF_ARM_EABI_VER5
    eh += struct.pack('<HHHHHH', EHSIZE, PHENTSIZE, 1, 0, 0, 0)
    ph = struct.pack('<IIIIIIII', 1, DATA_OFF, base, base,
                     len(raw), len(raw), 7, 0x1000)   # PT_LOAD, RWX
    out = bytearray(eh + ph)
    out += b'\x00' * (DATA_OFF - len(out))
    out += raw
    return bytes(out)

if __name__ == '__main__':
    raw_p, base_s, out_p = sys.argv[1], sys.argv[2], sys.argv[3]
    thumb = '--arm' not in sys.argv
    data = open(raw_p, 'rb').read()
    open(out_p, 'wb').write(mkelf(data, int(base_s, 16), thumb))
    print(f"{os.path.basename(raw_p)} -> {os.path.basename(out_p)}  "
          f"base={base_s} thumb={thumb} size={len(data):,}")