xref: /haiku/src/tools/elf2aout.c (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2002 Jake Burkholder
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 
31 #include <sys/types.h>
32 #include <sys/mman.h>
33 #include <sys/stat.h>
34 
35 #include <err.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include <elf.h>
43 
44 int elf2aout32(void *v, int fd);
45 int elf2aout64(void *v, int fd);
46 
47 #define	xe16toh(x)	((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
48 #define	xe32toh(x)	((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
49 #define	xe64toh(x)	((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
50 #define	htoxe32(x)	((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
51 
52 struct exec {
53 	u_int32_t	a_magic;
54 	u_int32_t	a_text;
55 	u_int32_t	a_data;
56 	u_int32_t	a_bss;
57 	u_int32_t	a_syms;
58 	u_int32_t	a_entry;
59 	u_int32_t	a_trsize;
60 	u_int32_t	a_drsize;
61 };
62 
63 /* we only support OMAGIC */
64 #define OMAGIC 0407
65 
66 static void usage(void);
67 
68 /* parts from NetBSD */
69 
70 #define	MID_ZERO	0x000	/* unknown - implementation dependent */
71 #define	MID_SUN010	0x001	/* sun 68010/68020 binary */
72 #define	MID_SUN020	0x002	/* sun 68020-only binary */
73 
74 #define	MID_PC386	0x064	/* 386 PC binary. (so quoth BFD) */
75 
76 #define	MID_I386	0x086	/* i386 BSD binary */
77 #define	MID_M68K	0x087	/* m68k BSD binary with 8K page sizes */
78 #define	MID_M68K4K	0x088	/* m68k BSD binary with 4K page sizes */
79 #define	MID_NS32532	0x089	/* ns32532 */
80 #define	MID_SPARC	0x08a	/* sparc */
81 #define	MID_PMAX	0x08b	/* pmax */
82 #define	MID_VAX1K	0x08c	/* VAX 1K page size binaries */
83 #define	MID_ALPHA	0x08d	/* Alpha BSD binary */
84 #define	MID_MIPS	0x08e	/* big-endian MIPS */
85 #define	MID_ARM6	0x08f	/* ARM6 */
86 #define	MID_M680002K	0x090	/* m68000 with 2K page sizes */
87 #define	MID_SH3		0x091	/* SH3 */
88 
89 #define	MID_POWERPC64	0x094	/* big-endian PowerPC 64 */
90 #define	MID_POWERPC	0x095	/* big-endian PowerPC */
91 #define	MID_VAX		0x096	/* VAX */
92 #define	MID_MIPS1	0x097	/* MIPS1 */
93 #define	MID_MIPS2	0x098	/* MIPS2 */
94 #define	MID_M88K	0x099	/* m88k BSD */
95 #define	MID_HPPA	0x09a	/* HP PARISC */
96 #define	MID_SH5_64	0x09b	/* LP64 SH5 */
97 #define	MID_SPARC64	0x09c	/* LP64 sparc */
98 #define	MID_X86_64	0x09d	/* AMD x86-64 */
99 #define	MID_SH5_32	0x09e	/* ILP32 SH5 */
100 #define	MID_IA64	0x09f	/* Itanium */
101 
102 #define	MID_AARCH64	0x0b7	/* ARM AARCH64 */
103 #define	MID_OR1K	0x0b8	/* OpenRISC 1000 */
104 #define	MID_RISCV	0x0b9	/* Risc-V */
105 
106 #define	MID_HP200	0x0c8	/* hp200 (68010) BSD binary */
107 
108 #define	MID_HP300	0x12c	/* hp300 (68020+68881) BSD binary */
109 
110 #define	MID_HPUX800     0x20b   /* hp800 HP-UX binary */
111 #define	MID_HPUX	0x20c	/* hp200/300 HP-UX binary */
112 
113 //(ex->e_machine, ex->e_ident[EI_DATA], ex->e_ident[EI_CLASS])
114 static uint32_t
115 get_mid(int m, int e, int c)
116 {
117 	switch (m) {
118 	case EM_AARCH64:
119 		return MID_AARCH64;
120 	case EM_ALPHA:
121 		return MID_ALPHA;
122 	case EM_ARM:
123 		return MID_ARM6;
124 	case EM_PARISC:
125 		return MID_HPPA;
126 	case EM_386:
127 		return MID_I386;
128 	case EM_68K:
129 		return MID_M68K;
130 /*	case EM_OR1K:
131 		return MID_OR1K;*/
132 	case EM_MIPS:
133 		if (e == ELFDATA2LSB)
134 			return MID_PMAX;
135 		else
136 			return MID_MIPS;
137 	case EM_PPC:
138 		return MID_POWERPC;
139 	case EM_PPC64:
140 		return MID_POWERPC64;
141 		break;
142 	case EM_RISCV:
143 		return MID_RISCV;
144 	case EM_SH:
145 		return MID_SH3;
146 	case EM_SPARC:
147 	case EM_SPARC32PLUS:
148 	case EM_SPARCV9:
149 		if (c == ELFCLASS32)
150 			return MID_SPARC;
151 		return MID_SPARC64;
152 	case EM_X86_64:
153 		return MID_X86_64;
154 	case EM_VAX:
155 		return MID_VAX;
156 	case EM_NONE:
157 		return MID_ZERO;
158 	default:
159 		break;
160 	}
161 	return MID_ZERO;
162 }
163 
164 int
165 elf2aout32(void *v, int fd)
166 {
167 	Elf32_Half phentsize;
168 	Elf32_Half phnum;
169 	Elf32_Word filesz;
170 	Elf32_Word memsz;
171 	Elf32_Addr entry;
172 	Elf32_Off offset;
173 	Elf32_Off phoff;
174 	Elf32_Word type;
175 
176 	Elf32_Phdr *p;
177 	Elf32_Ehdr *e = v;
178 
179 	unsigned char data = e->e_ident[EI_DATA];
180 	struct exec a;
181 	int i;
182 	uint32_t mid;
183 
184 	mid = get_mid(xe16toh(e->e_machine), e->e_ident[EI_DATA], e->e_ident[EI_CLASS]);
185 	phentsize = xe16toh(e->e_phentsize);
186 	if (phentsize != sizeof(*p))
187 		errx(1, "phdr size mismatch");
188 
189 	entry = xe32toh(e->e_entry);
190 	phoff = xe32toh(e->e_phoff);
191 	phnum = xe16toh(e->e_phnum);
192 	p = (Elf32_Phdr *)((char *)e + phoff);
193 	bzero(&a, sizeof(a));
194 	for (i = 0; i < phnum; i++) {
195 		type = xe32toh(p[i].p_type);
196 		switch (type) {
197 		case PT_LOAD:
198 			if (a.a_magic != 0)
199 				errx(1, "too many loadable segments");
200 			filesz = xe32toh(p[i].p_filesz);
201 			memsz = xe32toh(p[i].p_memsz);
202 			offset = xe32toh(p[i].p_offset);
203 			a.a_magic = htoxe32(((uint32_t)mid << 16) | OMAGIC);
204 			a.a_text = htoxe32(filesz);
205 			a.a_bss = htoxe32(memsz - filesz);
206 			a.a_entry = htoxe32(entry);
207 			if (write(fd, &a, sizeof(a)) != sizeof(a) ||
208 			    write(fd, (char *)e + offset, filesz) != (ssize_t)filesz)
209 				err(1, NULL);
210 			break;
211 		default:
212 			break;
213 		}
214 	}
215 	return (0);
216 }
217 
218 
219 int
220 elf2aout64(void *v, int fd)
221 {
222 	Elf64_Half phentsize;
223 	Elf64_Half phnum;
224 	Elf64_Xword filesz;
225 	Elf64_Xword memsz;
226 	Elf64_Addr entry;
227 	Elf64_Off offset;
228 	Elf64_Off phoff;
229 	Elf64_Word type;
230 
231 	Elf64_Phdr *p;
232 	Elf64_Ehdr *e = v;
233 
234 	unsigned char data = e->e_ident[EI_DATA];
235 	struct exec a;
236 	int i;
237 	uint32_t mid;
238 
239 	mid = get_mid(xe16toh(e->e_machine), e->e_ident[EI_DATA], e->e_ident[EI_CLASS]);
240 	phentsize = xe16toh(e->e_phentsize);
241 	if (phentsize != sizeof(*p))
242 		errx(1, "phdr size mismatch");
243 
244 	entry = xe64toh(e->e_entry);
245 	phoff = xe64toh(e->e_phoff);
246 	phnum = xe16toh(e->e_phnum);
247 	p = (Elf64_Phdr *)((char *)e + phoff);
248 	bzero(&a, sizeof(a));
249 	for (i = 0; i < phnum; i++) {
250 		type = xe32toh(p[i].p_type);
251 		switch (type) {
252 		case PT_LOAD:
253 			if (a.a_magic != 0)
254 				errx(1, "too many loadable segments");
255 			filesz = xe64toh(p[i].p_filesz);
256 			memsz = xe64toh(p[i].p_memsz);
257 			offset = xe64toh(p[i].p_offset);
258 			a.a_magic = htoxe32(((uint32_t)mid << 16) | OMAGIC);
259 			a.a_text = htoxe32(filesz);
260 			a.a_bss = htoxe32(memsz - filesz);
261 			a.a_entry = htoxe32(entry);
262 			if (write(fd, &a, sizeof(a)) != sizeof(a) ||
263 			    write(fd, (char *)e + offset, filesz) != (ssize_t)filesz)
264 				err(1, NULL);
265 			break;
266 		default:
267 			break;
268 		}
269 	}
270 	return (0);
271 }
272 
273 
274 /*
275  * elf to a.out converter for freebsd/sparc64 bootblocks.
276  */
277 int
278 main(int ac, char **av)
279 {
280 	unsigned char data;
281 	struct stat sb;
282 	Elf64_Ehdr *e;
283 	void *v;
284 	int efd;
285 	int fd;
286 	int c;
287 
288 	fd = STDIN_FILENO;
289 	while ((c = getopt(ac, av, "o:")) != -1)
290 		switch (c) {
291 		case 'o':
292 			if ((fd = open(optarg, O_CREAT|O_RDWR, 0644)) < 0)
293 				err(1, "%s", optarg);
294 			break;
295 		case '?':
296 		default:
297 			usage();
298 		}
299 	ac -= optind;
300 	av += optind;
301 	if (ac == 0)
302 		usage();
303 
304 	if ((efd = open(*av, O_RDONLY)) < 0 || fstat(efd, &sb) < 0)
305 		err(1, NULL);
306 	v = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, efd, 0);
307 	if ((e = v) == MAP_FAILED)
308 		err(1, NULL);
309 
310 	if (!IS_ELF(*e))
311 		errx(1, "not an elf file");
312 	if (e->e_ident[EI_CLASS] != ELFCLASS64 && e->e_ident[EI_CLASS] != ELFCLASS32)
313 		errx(1, "wrong class");
314 	data = e->e_ident[EI_DATA];
315 	if (data != ELFDATA2MSB && data != ELFDATA2LSB)
316 		errx(1, "wrong data format");
317 	if (e->e_ident[EI_VERSION] != EV_CURRENT)
318 		errx(1, "wrong elf version");
319 
320 	if (e->e_ident[EI_CLASS] == ELFCLASS64)
321 		return elf2aout64(v, fd);
322 	else
323 		return elf2aout32(v, fd);
324 }
325 
326 static void
327 usage(void)
328 {
329 
330 	fprintf(stderr, "usage: elf2aout [-o outfile] infile\n");
331 	exit(1);
332 }
333