diff options
author | 2013-09-21 21:00:02 +0000 | |
---|---|---|
committer | 2013-09-21 21:00:02 +0000 | |
commit | e5a355a2833dee45b4fe91308e9c40ad365126e6 (patch) | |
tree | 16352f4c8380128c2746362167ce4577b0fe8ac1 | |
parent | regen (diff) | |
download | wireguard-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.8 | 11 | ||||
-rw-r--r-- | sys/arch/aviion/stand/a2coff/a2coff.c | 303 |
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; } |