193310Sobrien/*-
293310Sobrien * Copyright (c) 2002 Jake Burkholder
393310Sobrien * All rights reserved.
493310Sobrien *
593310Sobrien * Redistribution and use in source and binary forms, with or without
693310Sobrien * modification, are permitted provided that the following conditions
793310Sobrien * are met:
893310Sobrien * 1. Redistributions of source code must retain the above copyright
993310Sobrien *    notice, this list of conditions and the following disclaimer.
1093310Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1193310Sobrien *    notice, this list of conditions and the following disclaimer in the
1293310Sobrien *    documentation and/or other materials provided with the distribution.
1393310Sobrien *
1493310Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1593310Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1693310Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1793310Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1893310Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1993310Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2093310Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2193310Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2293310Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2393310Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2493310Sobrien * SUCH DAMAGE.
2593310Sobrien */
2693310Sobrien
2793310Sobrien#include <sys/cdefs.h>
2893310Sobrien__FBSDID("$FreeBSD$");
2993310Sobrien
3097281Sru#include <sys/types.h>
3193310Sobrien#include <sys/elf64.h>
32112767Sobrien#include <sys/endian.h>
3393310Sobrien#include <sys/mman.h>
3493310Sobrien#include <sys/stat.h>
3593310Sobrien
3693310Sobrien#include <err.h>
3793310Sobrien#include <fcntl.h>
38203799Sru#include <stdio.h>
39203799Sru#include <stdlib.h>
4097281Sru#include <string.h>
4197281Sru#include <unistd.h>
4293310Sobrien
4397281Sru#define	xe16toh(x)	((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
4497281Sru#define	xe32toh(x)	((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
4597281Sru#define	xe64toh(x)	((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
4697281Sru#define	htoxe32(x)	((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
4797281Sru
4893310Sobrienstruct exec {
4996981Sru	u_int32_t	a_magic;
5096981Sru	u_int32_t	a_text;
5196981Sru	u_int32_t	a_data;
5296981Sru	u_int32_t	a_bss;
5396981Sru	u_int32_t	a_syms;
5496981Sru	u_int32_t	a_entry;
5596981Sru	u_int32_t	a_trsize;
5696981Sru	u_int32_t	a_drsize;
5793310Sobrien};
5893310Sobrien#define A_MAGIC 0x01030107
5993310Sobrien
6093310Sobrienstatic void usage(void);
6193310Sobrien
6293310Sobrien/*
6393310Sobrien * elf to a.out converter for freebsd/sparc64 bootblocks.
6493310Sobrien */
6593310Sobrienint
6693310Sobrienmain(int ac, char **av)
6793310Sobrien{
68153504Smarcel	Elf64_Half phentsize;
69153504Smarcel	Elf64_Half machine;
70153504Smarcel	Elf64_Half phnum;
71153504Smarcel	Elf64_Xword filesz;
72153504Smarcel	Elf64_Xword memsz;
7393310Sobrien	Elf64_Addr entry;
7493310Sobrien	Elf64_Off offset;
7593310Sobrien	Elf64_Off phoff;
76153504Smarcel	Elf64_Word type;
7797281Sru	unsigned char data;
7893310Sobrien	struct stat sb;
7993310Sobrien	struct exec a;
8093310Sobrien	Elf64_Phdr *p;
8193310Sobrien	Elf64_Ehdr *e;
8293310Sobrien	void *v;
8393310Sobrien	int efd;
8493310Sobrien	int fd;
8593310Sobrien	int c;
8693310Sobrien	int i;
8793310Sobrien
8897281Sru	fd = STDIN_FILENO;
8993310Sobrien	while ((c = getopt(ac, av, "o:")) != -1)
9093310Sobrien		switch (c) {
9193310Sobrien		case 'o':
9293310Sobrien			if ((fd = open(optarg, O_CREAT|O_RDWR, 0644)) < 0)
9393310Sobrien				err(1, "%s", optarg);
9493310Sobrien			break;
9593310Sobrien		case '?':
9693310Sobrien		default:
9793310Sobrien			usage();
9893310Sobrien		}
9993310Sobrien	ac -= optind;
10093310Sobrien	av += optind;
10193310Sobrien	if (ac == 0)
10293310Sobrien		usage();
10393310Sobrien
10493310Sobrien	if ((efd = open(*av, O_RDONLY)) < 0 || fstat(efd, &sb) < 0)
10593310Sobrien		err(1, NULL);
10693310Sobrien	v = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, efd, 0);
10793310Sobrien	if ((e = v) == MAP_FAILED)
10893310Sobrien		err(1, NULL);
10993310Sobrien
11093310Sobrien	if (!IS_ELF(*e))
11193310Sobrien		errx(1, "not an elf file");
11293310Sobrien	if (e->e_ident[EI_CLASS] != ELFCLASS64)
11393310Sobrien		errx(1, "wrong class");
11497281Sru	data = e->e_ident[EI_DATA];
11597281Sru	if (data != ELFDATA2MSB && data != ELFDATA2LSB)
11693310Sobrien		errx(1, "wrong data format");
11793310Sobrien	if (e->e_ident[EI_VERSION] != EV_CURRENT)
11893310Sobrien		errx(1, "wrong elf version");
11997281Sru	machine = xe16toh(e->e_machine);
12097281Sru	if (machine != EM_SPARCV9 && machine != EM_ALPHA)
12193310Sobrien		errx(1, "wrong machine type");
12297281Sru	phentsize = xe16toh(e->e_phentsize);
12393310Sobrien	if (phentsize != sizeof(*p))
12493310Sobrien		errx(1, "phdr size mismatch");
12593310Sobrien
12697281Sru	entry = xe64toh(e->e_entry);
12797281Sru	phoff = xe64toh(e->e_phoff);
12897281Sru	phnum = xe16toh(e->e_phnum);
12993310Sobrien	p = (Elf64_Phdr *)((char *)e + phoff);
13093310Sobrien	bzero(&a, sizeof(a));
13193310Sobrien	for (i = 0; i < phnum; i++) {
13297281Sru		type = xe32toh(p[i].p_type);
13393310Sobrien		switch (type) {
13493310Sobrien		case PT_LOAD:
13593310Sobrien			if (a.a_magic != 0)
13693310Sobrien				errx(1, "too many loadable segments");
13797281Sru			filesz = xe64toh(p[i].p_filesz);
13897281Sru			memsz = xe64toh(p[i].p_memsz);
13997281Sru			offset = xe64toh(p[i].p_offset);
14097281Sru			a.a_magic = htoxe32(A_MAGIC);
14197281Sru			a.a_text = htoxe32(filesz);
14297281Sru			a.a_bss = htoxe32(memsz - filesz);
14397281Sru			a.a_entry = htoxe32(entry);
14493310Sobrien			if (write(fd, &a, sizeof(a)) != sizeof(a) ||
14597281Sru			    write(fd, (char *)e + offset, filesz) != (ssize_t)filesz)
14693310Sobrien				err(1, NULL);
14793310Sobrien			break;
14893310Sobrien		default:
14993310Sobrien			break;
15093310Sobrien		}
15193310Sobrien	}
15293310Sobrien
15393310Sobrien	return (0);
15493310Sobrien}
15593310Sobrien
15693310Sobrienstatic void
15793310Sobrienusage(void)
15893310Sobrien{
15993310Sobrien
160203799Sru	fprintf(stderr, "usage: elf2aout [-o outfile] infile\n");
161203799Sru	exit(1);
16293310Sobrien}
163