#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <elf.h>
int elf2aout32(void *v, int fd);
int elf2aout64(void *v, int fd);
#define xe16toh(x) ((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
#define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
#define xe64toh(x) ((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
#define htoxe32(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
struct exec {
u_int32_t a_magic;
u_int32_t a_text;
u_int32_t a_data;
u_int32_t a_bss;
u_int32_t a_syms;
u_int32_t a_entry;
u_int32_t a_trsize;
u_int32_t a_drsize;
};
#define OMAGIC 0407
static void usage(void);
#define MID_ZERO 0x000
#define MID_SUN010 0x001
#define MID_SUN020 0x002
#define MID_PC386 0x064
#define MID_I386 0x086
#define MID_M68K 0x087
#define MID_M68K4K 0x088
#define MID_NS32532 0x089
#define MID_SPARC 0x08a
#define MID_PMAX 0x08b
#define MID_VAX1K 0x08c
#define MID_ALPHA 0x08d
#define MID_MIPS 0x08e
#define MID_ARM6 0x08f
#define MID_M680002K 0x090
#define MID_SH3 0x091
#define MID_POWERPC64 0x094
#define MID_POWERPC 0x095
#define MID_VAX 0x096
#define MID_MIPS1 0x097
#define MID_MIPS2 0x098
#define MID_M88K 0x099
#define MID_HPPA 0x09a
#define MID_SH5_64 0x09b
#define MID_SPARC64 0x09c
#define MID_X86_64 0x09d
#define MID_SH5_32 0x09e
#define MID_IA64 0x09f
#define MID_AARCH64 0x0b7
#define MID_OR1K 0x0b8
#define MID_RISCV 0x0b9
#define MID_HP200 0x0c8
#define MID_HP300 0x12c
#define MID_HPUX800 0x20b
#define MID_HPUX 0x20c
static uint32_t
get_mid(int m, int e, int c)
{
switch (m) {
case EM_AARCH64:
return MID_AARCH64;
case EM_ALPHA:
return MID_ALPHA;
case EM_ARM:
return MID_ARM6;
case EM_PARISC:
return MID_HPPA;
case EM_386:
return MID_I386;
case EM_68K:
return MID_M68K;
case EM_MIPS:
if (e == ELFDATA2LSB)
return MID_PMAX;
else
return MID_MIPS;
case EM_PPC:
return MID_POWERPC;
case EM_PPC64:
return MID_POWERPC64;
break;
case EM_RISCV:
return MID_RISCV;
case EM_SH:
return MID_SH3;
case EM_SPARC:
case EM_SPARC32PLUS:
case EM_SPARCV9:
if (c == ELFCLASS32)
return MID_SPARC;
return MID_SPARC64;
case EM_X86_64:
return MID_X86_64;
case EM_VAX:
return MID_VAX;
case EM_NONE:
return MID_ZERO;
default:
break;
}
return MID_ZERO;
}
int
elf2aout32(void *v, int fd)
{
Elf32_Half phentsize;
Elf32_Half phnum;
Elf32_Word filesz;
Elf32_Word memsz;
Elf32_Addr entry;
Elf32_Off offset;
Elf32_Off phoff;
Elf32_Word type;
Elf32_Phdr *p;
Elf32_Ehdr *e = v;
unsigned char data = e->e_ident[EI_DATA];
struct exec a;
int i;
uint32_t mid;
mid = get_mid(xe16toh(e->e_machine), e->e_ident[EI_DATA], e->e_ident[EI_CLASS]);
phentsize = xe16toh(e->e_phentsize);
if (phentsize != sizeof(*p))
errx(1, "phdr size mismatch");
entry = xe32toh(e->e_entry);
phoff = xe32toh(e->e_phoff);
phnum = xe16toh(e->e_phnum);
p = (Elf32_Phdr *)((char *)e + phoff);
bzero(&a, sizeof(a));
for (i = 0; i < phnum; i++) {
type = xe32toh(p[i].p_type);
switch (type) {
case PT_LOAD:
if (a.a_magic != 0)
errx(1, "too many loadable segments");
filesz = xe32toh(p[i].p_filesz);
memsz = xe32toh(p[i].p_memsz);
offset = xe32toh(p[i].p_offset);
a.a_magic = htoxe32(((uint32_t)mid << 16) | OMAGIC);
a.a_text = htoxe32(filesz);
a.a_bss = htoxe32(memsz - filesz);
a.a_entry = htoxe32(entry);
if (write(fd, &a, sizeof(a)) != sizeof(a) ||
write(fd, (char *)e + offset, filesz) != (ssize_t)filesz)
err(1, NULL);
break;
default:
break;
}
}
return (0);
}
int
elf2aout64(void *v, int fd)
{
Elf64_Half phentsize;
Elf64_Half phnum;
Elf64_Xword filesz;
Elf64_Xword memsz;
Elf64_Addr entry;
Elf64_Off offset;
Elf64_Off phoff;
Elf64_Word type;
Elf64_Phdr *p;
Elf64_Ehdr *e = v;
unsigned char data = e->e_ident[EI_DATA];
struct exec a;
int i;
uint32_t mid;
mid = get_mid(xe16toh(e->e_machine), e->e_ident[EI_DATA], e->e_ident[EI_CLASS]);
phentsize = xe16toh(e->e_phentsize);
if (phentsize != sizeof(*p))
errx(1, "phdr size mismatch");
entry = xe64toh(e->e_entry);
phoff = xe64toh(e->e_phoff);
phnum = xe16toh(e->e_phnum);
p = (Elf64_Phdr *)((char *)e + phoff);
bzero(&a, sizeof(a));
for (i = 0; i < phnum; i++) {
type = xe32toh(p[i].p_type);
switch (type) {
case PT_LOAD:
if (a.a_magic != 0)
errx(1, "too many loadable segments");
filesz = xe64toh(p[i].p_filesz);
memsz = xe64toh(p[i].p_memsz);
offset = xe64toh(p[i].p_offset);
a.a_magic = htoxe32(((uint32_t)mid << 16) | OMAGIC);
a.a_text = htoxe32(filesz);
a.a_bss = htoxe32(memsz - filesz);
a.a_entry = htoxe32(entry);
if (write(fd, &a, sizeof(a)) != sizeof(a) ||
write(fd, (char *)e + offset, filesz) != (ssize_t)filesz)
err(1, NULL);
break;
default:
break;
}
}
return (0);
}
int
main(int ac, char **av)
{
unsigned char data;
struct stat sb;
Elf64_Ehdr *e;
void *v;
int efd;
int fd;
int c;
fd = STDIN_FILENO;
while ((c = getopt(ac, av, "o:")) != -1)
switch (c) {
case 'o':
if ((fd = open(optarg, O_CREAT|O_RDWR, 0644)) < 0)
err(1, "%s", optarg);
break;
case '?':
default:
usage();
}
ac -= optind;
av += optind;
if (ac == 0)
usage();
if ((efd = open(*av, O_RDONLY)) < 0 || fstat(efd, &sb) < 0)
err(1, NULL);
v = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, efd, 0);
if ((e = v) == MAP_FAILED)
err(1, NULL);
if (!IS_ELF(*e))
errx(1, "not an elf file");
if (e->e_ident[EI_CLASS] != ELFCLASS64 && e->e_ident[EI_CLASS] != ELFCLASS32)
errx(1, "wrong class");
data = e->e_ident[EI_DATA];
if (data != ELFDATA2MSB && data != ELFDATA2LSB)
errx(1, "wrong data format");
if (e->e_ident[EI_VERSION] != EV_CURRENT)
errx(1, "wrong elf version");
if (e->e_ident[EI_CLASS] == ELFCLASS64)
return elf2aout64(v, fd);
else
return elf2aout32(v, fd);
}
static void
usage(void)
{
fprintf(stderr, "usage: elf2aout [-o outfile] infile\n");
exit(1);
}