summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2013-09-21 21:00:02 +0000
committermiod <miod@openbsd.org>2013-09-21 21:00:02 +0000
commite5a355a2833dee45b4fe91308e9c40ad365126e6 (patch)
tree16352f4c8380128c2746362167ce4577b0fe8ac1
parentregen (diff)
downloadwireguard-openbsd-e5a355a2833dee45b4fe91308e9c40ad365126e6.tar.xz
wireguard-openbsd-e5a355a2833dee45b4fe91308e9c40ad365126e6.zip
Grok ELF files. Good enough to netboot kernels on AV530 again.
-rw-r--r--sys/arch/aviion/stand/a2coff/a2coff.811
-rw-r--r--sys/arch/aviion/stand/a2coff/a2coff.c303
2 files changed, 232 insertions, 82 deletions
diff --git a/sys/arch/aviion/stand/a2coff/a2coff.8 b/sys/arch/aviion/stand/a2coff/a2coff.8
index 7eb254b4ba7..c1d92f770ef 100644
--- a/sys/arch/aviion/stand/a2coff/a2coff.8
+++ b/sys/arch/aviion/stand/a2coff/a2coff.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: a2coff.8,v 1.2 2007/05/31 19:20:02 jmc Exp $
+.\" $OpenBSD: a2coff.8,v 1.3 2013/09/21 21:00:02 miod Exp $
.\"
.\" Copyright (c) 2006, Miodrag Vallat
.\"
@@ -23,12 +23,12 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: May 31 2007 $
+.Dd $Mdocdate: September 21 2013 $
.Dt A2COFF 8 aviion
.Os
.Sh NAME
.Nm a2coff
-.Nd convert standalone a.out binaries to 88KBCS COFF format
+.Nd convert standalone a.out or ELF binaries to 88KBCS COFF format
.Sh SYNOPSIS
.Nm a2coff
.Ar source
@@ -37,9 +37,10 @@
.Nm a2coff
converts standalone binaries, such as kernels or boot blocks, from
.Xr a.out 5
-format to COFF format, suitable for booting from the
+or ELF format to COFF format, suitable for booting from the
.Tn Data General
.Tn AViiON
PROMs.
.Sh SEE ALSO
-.Xr a.out 5
+.Xr a.out 5 ,
+.Xr elf 5
diff --git a/sys/arch/aviion/stand/a2coff/a2coff.c b/sys/arch/aviion/stand/a2coff/a2coff.c
index 5c6fa2033a2..a2066d10cbb 100644
--- a/sys/arch/aviion/stand/a2coff/a2coff.c
+++ b/sys/arch/aviion/stand/a2coff/a2coff.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: a2coff.c,v 1.4 2011/10/09 17:10:39 miod Exp $ */
+/* $OpenBSD: a2coff.c,v 1.5 2013/09/21 21:00:02 miod Exp $ */
/*
- * Copyright (c) 2006, Miodrag Vallat
+ * Copyright (c) 2006, 2013, Miodrag Vallat
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,7 +30,7 @@
* Also, bss is merged into the data section to cope with PROMs which
* do not zero-fill the bss upon loading (sad but true).
*
- * This should really only be used to build a BSD/dg88k bootloader.
+ * This should really only be used to build a BSD/aviion bootloader.
*/
#include <unistd.h>
@@ -47,6 +47,7 @@
#undef __LDPGSZ
#define __LDPGSZ 0x1000
#endif /* m88k */
+#include <sys/exec_elf.h>
#define ECOFF_ALIGN 0x200
@@ -120,6 +121,8 @@ struct ecoff_exechdr {
#define round(qty, pow2) (((qty) + (pow2 - 1)) & ~(pow2 - 1UL))
+int convert_aout(const char *, int, int, struct exec *);
+int convert_elf(const char *, int, int, Elf_Ehdr *);
void copybits(int, int, u_int32_t);
void usage(void);
void zerobits(int, u_int32_t);
@@ -127,13 +130,13 @@ void zerobits(int, u_int32_t);
int
main(int argc, char *argv[])
{
- struct exec head;
- struct ecoff_exechdr ehead;
- struct ecoff_scnhdr escn[3];
+ union {
+ struct exec aout;
+ Elf_Ehdr elf;
+ } head;
int infd, outfd;
- off_t outpos;
- uint32_t chunk;
int n;
+ int rc;
if (argc != 3)
usage();
@@ -142,22 +145,80 @@ main(int argc, char *argv[])
if (infd < 0)
err(1, argv[1]);
+ n = read(infd, &head, sizeof(head));
+ if (n < sizeof(head))
+ err(1, "read");
+
+ if (!IS_ELF(head.elf) && !N_BADMAG(head.aout))
+ err(1, "%s: bad magic", argv[1]);
+
outfd = open(argv[2], O_WRONLY | O_TRUNC | O_CREAT, 0644);
if (outfd < 0)
err(1, argv[2]);
- n = read(infd, &head, sizeof(head));
- if (n < sizeof(head))
- err(1, "read");
+ if (IS_ELF(head.elf))
+ rc = convert_elf(argv[1], infd, outfd, &head.elf);
+ else
+ rc = convert_aout(argv[1], infd, outfd, &head.aout);
+
+ close(infd);
+ close(outfd);
+ exit(rc);
+}
+
+char buf[4096];
+#define min(a ,b) ((a) < (b) ? (a) : (b))
- if (N_BADMAG(head)) {
- printf("%s: bad magic number\n", argv[1]);
- exit(1);
+void
+copybits(int from, int to, u_int32_t count)
+{
+ int chunk;
+
+ while (count != 0) {
+ chunk = min(count, sizeof buf);
+ if (read(from, buf, chunk) != chunk)
+ err(1, "read");
+ if (write(to, buf, chunk) != chunk)
+ err(1, "write");
+ count -= chunk;
}
+}
- if (head.a_trsize || head.a_drsize) {
- printf("%s: has relocations\n", argv[1]);
- exit(1);
+void
+zerobits(int to, u_int32_t count)
+{
+ int chunk;
+
+ bzero(buf, sizeof buf);
+ while (count != 0) {
+ chunk = min(count, sizeof buf);
+ if (write(to, buf, chunk) != chunk)
+ err(1, "write");
+ count -= chunk;
+ }
+}
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s infile outfile\n", __progname);
+ exit(1);
+}
+
+int
+convert_aout(const char *infile, int infd, int outfd, struct exec *head)
+{
+ struct ecoff_exechdr ehead;
+ struct ecoff_scnhdr escn[3];
+ off_t outpos;
+ uint32_t chunk;
+ int n;
+
+ if (head->a_trsize || head->a_drsize) {
+ printf("%s: has relocations\n", infile);
+ return 1;
}
/*
@@ -173,14 +234,14 @@ main(int argc, char *argv[])
ehead.f.f_flags = 0x020f;
/* F_RELFLG | F_EXEC | F_LNNO | 8 | F_AR16WR */
- ehead.a.magic = N_GETMAGIC(head);
+ ehead.a.magic = N_GETMAGIC(*head); /* ZMAGIC */
ehead.a.vstamp = 0; /* ignored */
- ehead.a.tsize = head.a_text; /* ignored */
- ehead.a.dsize = head.a_data; /* ignored */
- ehead.a.bsize = head.a_bss; /* ignored */
- ehead.a.entry = head.a_entry;
- ehead.a.text_start = N_TXTADDR(head); /* ignored */
- ehead.a.data_start = N_DATADDR(head); /* ignored */
+ ehead.a.tsize = head->a_text; /* ignored */
+ ehead.a.dsize = head->a_data; /* ignored */
+ ehead.a.bsize = head->a_bss; /* ignored */
+ ehead.a.entry = head->a_entry;
+ ehead.a.text_start = N_TXTADDR(*head); /* ignored */
+ ehead.a.data_start = N_DATADDR(*head); /* ignored */
n = write(outfd, &ehead, sizeof(ehead));
if (n != sizeof(ehead))
@@ -193,8 +254,8 @@ main(int argc, char *argv[])
*/
strncpy(escn[0].s_name, ".text", sizeof escn[0].s_name);
- escn[0].s_paddr = N_TXTADDR(head); /* ignored, 1:1 mapping */
- escn[0].s_size = round(head.a_text, 8);
+ escn[0].s_paddr = N_TXTADDR(*head); /* ignored, 1:1 mapping */
+ escn[0].s_size = round(head->a_text, 8);
escn[0].s_scnptr = round(sizeof(ehead) + sizeof(escn), 0x10);
escn[0].s_relptr = 0;
escn[0].s_lnnoptr = 0;
@@ -202,17 +263,18 @@ main(int argc, char *argv[])
escn[0].s_flags = 0x20; /* STYP_TEXT */
strncpy(escn[1].s_name, ".data", sizeof escn[1].s_name);
- escn[1].s_paddr = N_DATADDR(head); /* ignored, 1:1 mapping */
+ escn[1].s_paddr = N_DATADDR(*head); /* ignored, 1:1 mapping */
escn[1].s_scnptr = escn[0].s_scnptr + escn[0].s_size;
- escn[1].s_size = round(head.a_data + head.a_bss, 8);
+ escn[1].s_size = round(head->a_data + head->a_bss, 8);
escn[1].s_relptr = 0;
escn[1].s_lnnoptr = 0;
escn[1].s_nlnno = 0;
escn[1].s_flags = 0x40; /* STYP_DATA */
strncpy(escn[2].s_name, ".bss", sizeof escn[2].s_name);
- escn[2].s_paddr = N_BSSADDR(head) + head.a_bss; /* ignored, 1:1 mapping */
- escn[2].s_scnptr = 0; /* nothing in the file */
+ escn[2].s_paddr = N_BSSADDR(*head) + head->a_bss;
+ /* ignored, 1:1 mapping */
+ escn[2].s_scnptr = 0; /* nothing in the file */
escn[2].s_size = 0;
escn[2].s_relptr = 0;
escn[2].s_lnnoptr = 0;
@@ -220,9 +282,9 @@ main(int argc, char *argv[])
escn[2].s_flags = 0x80; /* STYP_BSS */
/* adjust load addresses */
- escn[0].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
- escn[1].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
- escn[2].s_paddr += (head.a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
+ escn[0].s_paddr += (head->a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
+ escn[1].s_paddr += (head->a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
+ escn[2].s_paddr += (head->a_entry & ~(__LDPGSZ - 1)) - __LDPGSZ;
escn[0].s_vaddr = escn[0].s_paddr;
escn[1].s_vaddr = escn[1].s_paddr;
escn[2].s_vaddr = escn[2].s_paddr;
@@ -237,11 +299,13 @@ main(int argc, char *argv[])
#ifdef DEBUG
printf("copying %s: source %lx dest %lx size %x\n",
- escn[0].s_name, N_TXTOFF(head), escn[0].s_scnptr, head.a_text);
+ escn[0].s_name, N_TXTOFF(*head), escn[0].s_scnptr, head->a_text);
#endif
- lseek(outfd, escn[0].s_scnptr, SEEK_SET);
- lseek(infd, N_TXTOFF(head), SEEK_SET);
- copybits(infd, outfd, head.a_text);
+ if (lseek(outfd, escn[0].s_scnptr, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ if (lseek(infd, N_TXTOFF(*head), SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ copybits(infd, outfd, head->a_text);
/*
* Copy data section
@@ -249,13 +313,15 @@ main(int argc, char *argv[])
#ifdef DEBUG
printf("copying %s: source %lx dest %lx size %x\n",
- escn[1].s_name, N_DATOFF(head), escn[1].s_scnptr, head.a_data);
+ escn[1].s_name, N_DATOFF(*head), escn[1].s_scnptr, head->a_data);
#endif
- lseek(outfd, escn[1].s_scnptr, SEEK_SET);
+ if (lseek(outfd, escn[1].s_scnptr, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
outpos = escn[1].s_scnptr;
- lseek(infd, N_DATOFF(head), SEEK_SET);
- copybits(infd, outfd, head.a_data);
- outpos += head.a_data;
+ if (lseek(infd, N_DATOFF(*head), SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ copybits(infd, outfd, head->a_data);
+ outpos += head->a_data;
/*
* ``Copy'' bss section
@@ -263,9 +329,9 @@ main(int argc, char *argv[])
#ifdef DEBUG
printf("copying %s: size %lx\n",
- escn[2].s_name, round(head.a_data + head.a_bss, 8) - head.a_data);
+ escn[2].s_name, round(head->a_data + head->a_bss, 8) - head->a_data);
#endif
- chunk = round(head.a_data + head.a_bss, 8) - head.a_data;
+ chunk = round(head->a_data + head->a_bss, 8) - head->a_data;
zerobits(outfd, chunk);
outpos += chunk;
@@ -277,48 +343,131 @@ main(int argc, char *argv[])
if ((outpos % ECOFF_ALIGN) != 0)
zerobits(outfd, ECOFF_ALIGN - (outpos % ECOFF_ALIGN));
- close(infd);
- close(outfd);
- exit(0);
+ return 0;
}
-char buf[4096];
-#define min(a ,b) ((a) < (b) ? (a) : (b))
-
-void
-copybits(int from, int to, u_int32_t count)
+int
+convert_elf(const char *infile, int infd, int outfd, Elf_Ehdr *ehdr)
{
- int chunk;
+ struct ecoff_exechdr ehead;
+ struct ecoff_scnhdr escn[2];
+ Elf_Phdr phdr[2];
+ off_t outpos;
+ int n;
- while (count != 0) {
- chunk = min(count, sizeof buf);
- if (read(from, buf, chunk) != chunk)
+ if (ehdr->e_phnum > 2) {
+ printf("%s: too many program headers\n", infile);
+ return 1;
+ }
+
+ memset(phdr, 0, sizeof phdr);
+ for (n = 0; n < ehdr->e_phnum; n++) {
+ if (lseek(infd, ehdr->e_phoff + n * ehdr->e_phentsize,
+ SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ if (read(infd, phdr + n, sizeof phdr[0]) != sizeof(phdr[0]))
err(1, "read");
- if (write(to, buf, chunk) != chunk)
- err(1, "write");
- count -= chunk;
}
-}
-void
-zerobits(int to, u_int32_t count)
-{
- int chunk;
+ /*
+ * Header
+ */
- bzero(buf, sizeof buf);
- while (count != 0) {
- chunk = min(count, sizeof buf);
- if (write(to, buf, chunk) != chunk)
- err(1, "write");
- count -= chunk;
+ memset(&ehead, 0, sizeof ehead);
+ memset(&escn, 0, sizeof escn);
+
+ ehead.f.f_magic = 0x016d; /* MC88OMAGIC */
+ ehead.f.f_nscns = ehdr->e_phnum;
+ ehead.f.f_opthdr = sizeof ehead.a;
+ ehead.f.f_flags = 0x020f;
+ /* F_RELFLG | F_EXEC | F_LNNO | 8 | F_AR16WR */
+
+ ehead.a.magic = ZMAGIC;
+ ehead.a.tsize = phdr[0].p_filesz; /* ignored */
+ ehead.a.dsize = phdr[1].p_filesz; /* ignored */
+ ehead.a.bsize = 0; /* ignored */
+ ehead.a.entry = ehdr->e_entry;
+ ehead.a.text_start = phdr[0].p_paddr; /* ignored */
+ ehead.a.data_start = phdr[1].p_paddr; /* ignored */
+
+ n = write(outfd, &ehead, sizeof(ehead));
+ if (n != sizeof(ehead))
+ err(1, "write");
+
+ /*
+ * Sections.
+ * Note that we merge .bss into .data since the PROM may not
+ * clear it and locore does not do this either.
+ */
+
+ strncpy(escn[0].s_name, ".text", sizeof escn[0].s_name);
+ escn[0].s_paddr = phdr[0].p_paddr; /* ignored, 1:1 mapping */
+ escn[0].s_size = round(phdr[0].p_memsz, 8);
+ escn[0].s_scnptr = round(sizeof(ehead) + sizeof(escn), 0x10);
+ escn[0].s_flags = 0x20; /* STYP_TEXT */
+
+ if (ehdr->e_phnum > 1) {
+ strncpy(escn[1].s_name, ".data", sizeof escn[1].s_name);
+ escn[1].s_paddr = phdr[1].p_paddr; /* ignored, 1:1 mapping */
+ escn[1].s_scnptr = escn[0].s_scnptr + escn[0].s_size;
+ escn[1].s_size = round(phdr[1].p_memsz, 8);
+ escn[1].s_flags = 0x40; /* STYP_DATA */
}
-}
-__dead void
-usage(void)
-{
- extern char *__progname;
+ /* adjust load addresses */
+ escn[0].s_vaddr = escn[0].s_paddr;
+ escn[1].s_vaddr = escn[1].s_paddr;
- fprintf(stderr, "usage: %s infile outfile\n", __progname);
- exit(1);
+ n = write(outfd, &escn, sizeof(escn));
+ if (n != sizeof(escn))
+ err(1, "write");
+
+ /*
+ * Copy ``text'' section (first program header: text, rodata, and
+ * maybe data and bss if they are contiguous)
+ */
+
+#ifdef DEBUG
+ printf("copying %s: source %lx dest %lx size %x\n",
+ escn[0].s_name, phdr[0].p_offset, escn[0].s_scnptr,
+ phdr[0].p_filesz);
+#endif
+ if (lseek(outfd, escn[0].s_scnptr, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ if (lseek(infd, phdr[0].p_offset, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ copybits(infd, outfd, phdr[0].p_filesz);
+ if (escn[0].s_size != phdr[0].p_filesz)
+ zerobits(outfd, escn[0].s_size - phdr[0].p_filesz);
+ outpos = escn[0].s_scnptr + escn[0].s_size;
+
+ /*
+ * Copy ``data'' section (second program header, if any)
+ */
+
+ if (ehdr->e_phnum > 1) {
+#ifdef DEBUG
+ printf("copying %s: source %lx dest %lx size %x\n",
+ escn[1].s_name, phdr[1].p_offset, escn[1].s_scnptr,
+ phdr[1].p_filesz);
+#endif
+ if (lseek(outfd, escn[1].s_scnptr, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ if (lseek(infd, phdr[1].p_offset, SEEK_SET) == (off_t) -1)
+ err(1, "seek");
+ copybits(infd, outfd, phdr[1].p_filesz);
+ if (escn[1].s_size != phdr[1].p_filesz)
+ zerobits(outfd, escn[1].s_size - phdr[1].p_filesz);
+ outpos = escn[1].s_scnptr + escn[1].s_size;
+ }
+
+ /*
+ * Round file to a multiple of 512 bytes, since older PROM
+ * (at least rev 1.20 on AV530) will reject files not being
+ * properly rounded.
+ */
+ if ((outpos % ECOFF_ALIGN) != 0)
+ zerobits(outfd, ECOFF_ALIGN - (outpos % ECOFF_ALIGN));
+
+ return 0;
}