From 35633713e562ca094a44e69b81ee4f9e74d83b21 Mon Sep 17 00:00:00 2001 From: Robert Nordier Date: Sat, 4 Nov 2000 13:02:00 +0000 Subject: [PATCH] Add support for creating a.out output files in addition to ELF. This allows booting from compressed binaries using older bootstraps. Thanks to: dwmalone --- usr.sbin/kgzip/Makefile | 2 +- usr.sbin/kgzip/aouthdr.c | 79 ++++++++++++++++++++++++++++++++++++++++ usr.sbin/kgzip/aouthdr.h | 59 ++++++++++++++++++++++++++++++ usr.sbin/kgzip/kgzcmp.c | 44 ++++++++++++++-------- usr.sbin/kgzip/kgzip.8 | 16 ++++++-- usr.sbin/kgzip/kgzip.c | 20 ++++++++-- usr.sbin/kgzip/kgzip.h | 4 ++ usr.sbin/kgzip/kgzld.c | 28 ++++++++++++-- 8 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 usr.sbin/kgzip/aouthdr.c create mode 100644 usr.sbin/kgzip/aouthdr.h diff --git a/usr.sbin/kgzip/Makefile b/usr.sbin/kgzip/Makefile index 1bfad2d1b40a..85c3486023f0 100644 --- a/usr.sbin/kgzip/Makefile +++ b/usr.sbin/kgzip/Makefile @@ -3,7 +3,7 @@ MAINTAINER= rnordier PROG= kgzip -SRCS= kgzip.c elfhdr.c kgzcmp.c kgzld.c xio.c +SRCS= kgzip.c aouthdr.c elfhdr.c kgzcmp.c kgzld.c xio.c MAN8= kgzip.8 CFLAGS+=-pedantic \ -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ diff --git a/usr.sbin/kgzip/aouthdr.c b/usr.sbin/kgzip/aouthdr.c new file mode 100644 index 000000000000..27541e6cae11 --- /dev/null +++ b/usr.sbin/kgzip/aouthdr.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include "aouthdr.h" + +#define KGZ_FIX_NSIZE 0 /* Run-time fixup */ + +const struct kgz_aouthdr0 aouthdr0 = { + /* a.out header */ + { + MID_I386 << 020 | OMAGIC, /* a_midmag */ + 0, /* a_text */ + sizeof(struct kgz_hdr) + KGZ_FIX_NSIZE, /* a_data */ + 0, /* a_bss */ + sizeof(struct nlist) * KGZ__STNUM, /* a_syms */ + 0, /* a_entry */ + 0, /* a_trsize */ + 0 /* a_drsize */ + } +}; + +const struct kgz_aouthdr1 aouthdr1 = { + /* Symbol table */ + { + { + { + (char *)offsetof(struct kgz__strtab, + kgz) /* n_un */ + }, + N_DATA | N_EXT, /* n_type */ + AUX_OBJECT, /* n_other */ + 0, /* n_desc */ + 0 /* n_value */ + }, + { + { + (char *)offsetof(struct kgz__strtab, + kgz_ndata) /* n_un */ + }, + N_DATA | N_EXT, /* n_type */ + AUX_OBJECT, /* n_other */ + 0, /* n_desc */ + sizeof(struct kgz_hdr) /* n_value */ + } + }, + /* String table */ + { + sizeof(struct kgz__strtab), /* length */ + KGZ__STR_KGZ, /* kgz */ + KGZ__STR_KGZ_NDATA /* kgz_ndata */ + } +}; diff --git a/usr.sbin/kgzip/aouthdr.h b/usr.sbin/kgzip/aouthdr.h new file mode 100644 index 000000000000..63c2dff66904 --- /dev/null +++ b/usr.sbin/kgzip/aouthdr.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2000 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include "kgz.h" + +/* Relocatable header: part 0 */ +struct kgz_aouthdr0 { + struct exec a; +}; + +/* Symbol table entries */ +#define KGZ__STNUM 2 + +/* Symbol table strings */ +#define KGZ__STR_KGZ "_kgz" +#define KGZ__STR_KGZ_NDATA "_kgz_ndata" + +/* String table */ +struct kgz__strtab { + unsigned long length; + char kgz[sizeof(KGZ__STR_KGZ)]; + char kgz_ndata[sizeof(KGZ__STR_KGZ_NDATA)]; +}; + +/* Relocatable header: part 1 */ +struct kgz_aouthdr1 { + struct nlist st[KGZ__STNUM]; + struct kgz__strtab strtab; +}; + +extern const struct kgz_aouthdr0 aouthdr0; +extern const struct kgz_aouthdr1 aouthdr1; diff --git a/usr.sbin/kgzip/kgzcmp.c b/usr.sbin/kgzip/kgzcmp.c index a10c1678b90e..09086ada8d91 100644 --- a/usr.sbin/kgzip/kgzcmp.c +++ b/usr.sbin/kgzip/kgzcmp.c @@ -39,16 +39,12 @@ #include #include +#include "aouthdr.h" #include "elfhdr.h" #include "kgzip.h" -#define KGZOFF (sizeof(struct kgz_elfhdr) + sizeof(struct kgz_hdr)) - -#define F_AOUT 1 /* Input format: a.out */ -#define F_ELF 2 /* Input format: ELF32 */ - static void mk_data(const struct iodesc *i, const struct iodesc *, - struct kgz_hdr *); + struct kgz_hdr *, size_t); static int ld_elf(const struct iodesc *, const struct iodesc *, struct kgz_hdr *, const Elf32_Ehdr *); static int ld_aout(const struct iodesc *, const struct iodesc *, @@ -61,7 +57,6 @@ void kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) { struct iodesc idi, ido; - struct kgz_elfhdr ehdr; if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) err(1, "%s", idi.fname); @@ -72,15 +67,31 @@ kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) kh->ident[1] = KGZ_ID1; kh->ident[2] = KGZ_ID2; kh->ident[3] = KGZ_ID3; - xseek(&ido, KGZOFF); - mk_data(&idi, &ido, kh); + mk_data(&idi, &ido, kh, + (format == F_AOUT ? sizeof(struct kgz_aouthdr0) : + sizeof(struct kgz_elfhdr)) + + sizeof(struct kgz_hdr)); kh->dload &= 0xffffff; kh->entry &= 0xffffff; - xseek(&ido, 0); - ehdr = elfhdr; - ehdr.st[KGZ_ST_KGZ_NDATA].st_size = kh->nsize; - ehdr.sh[KGZ_SH_DATA].sh_size += kh->nsize; - xwrite(&ido, &ehdr, sizeof(ehdr)); + if (format == F_AOUT) { + struct kgz_aouthdr0 ahdr0 = aouthdr0; + struct kgz_aouthdr1 ahdr1 = aouthdr1; + unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1); + if (x) { + x = 16 - x; + xzero(&ido, x); + } + xwrite(&ido, &ahdr1, sizeof(ahdr1)); + ahdr0.a.a_data += kh->nsize + x; + xseek(&ido, 0); + xwrite(&ido, &ahdr0, sizeof(ahdr0)); + } else { + struct kgz_elfhdr ehdr = elfhdr; + ehdr.st[KGZ_ST_KGZ_NDATA].st_size = kh->nsize; + ehdr.sh[KGZ_SH_DATA].sh_size += kh->nsize; + xseek(&ido, 0); + xwrite(&ido, &ehdr, sizeof(ehdr)); + } xwrite(&ido, kh, sizeof(*kh)); xclose(&ido); xclose(&idi); @@ -91,7 +102,7 @@ kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) */ static void mk_data(const struct iodesc * idi, const struct iodesc * ido, - struct kgz_hdr * kh) + struct kgz_hdr * kh, size_t off) { union { struct exec ex; @@ -112,6 +123,7 @@ mk_data(const struct iodesc * idi, const struct iodesc * ido, fmt = F_AOUT; if (!fmt) errx(1, "%s: Format not supported", idi->fname); + xseek(ido, off); if (pipe(fd)) err(1, NULL); switch (pid = fork()) { @@ -143,7 +155,7 @@ mk_data(const struct iodesc * idi, const struct iodesc * ido, errx(1, "%s: Invalid format", idi->fname); if (fstat(ido->fd, &sb)) err(1, "%s", ido->fname); - kh->nsize = sb.st_size - KGZOFF; + kh->nsize = sb.st_size - off; } /* diff --git a/usr.sbin/kgzip/kgzip.8 b/usr.sbin/kgzip/kgzip.8 index 97f4ece90ba1..462a72310f37 100644 --- a/usr.sbin/kgzip/kgzip.8 +++ b/usr.sbin/kgzip/kgzip.8 @@ -33,6 +33,7 @@ .Sh SYNOPSIS .Nm kgzip .Op Fl cv +.Op Fl f Ar format .Op Fl l Ar loader .Op Fl o Ar output .Ar file @@ -57,8 +58,7 @@ an executable suitable for booting with either the second- or third-level bootstraps. .El .Pp -Supported input formats are ELF and a.out ZMAGIC; the output format -is always ELF. Only 32-bit objects are supported. +Supported object formats are 32-bit ELF and a.out ZMAGIC. .Pp If the .Ar file @@ -73,6 +73,16 @@ The options are: Omit the link phase. .It Fl v Display object file information. +.It Fl f Ar format +Use +.Ar format +as the output format, where +.Ar format +is +.Sq aout +or +.Sq elf . +The default format is ELF. .It Fl l Ar loader Link .Ar loader @@ -113,8 +123,8 @@ The default loader .Sh SEE ALSO .Xr gzip 1 , .Xr ld 1 , -.Xr elf 5 , .Xr a.out 5 , +.Xr elf 5 , .Xr boot 8 , .Xr loader 8 .Sh DIAGNOSTICS diff --git a/usr.sbin/kgzip/kgzip.c b/usr.sbin/kgzip/kgzip.c index 3c3df367426d..5e96432d5cc1 100644 --- a/usr.sbin/kgzip/kgzip.c +++ b/usr.sbin/kgzip/kgzip.c @@ -49,6 +49,7 @@ static const char rcsid[] = #define SFX_MAX 5 /* Size of larger filename suffix */ const char *loader = "/usr/lib/kgzldr.o"; /* Default loader */ +int format; /* Output format */ char *tname; /* Name of temporary file */ @@ -70,11 +71,11 @@ main(int argc, char *argv[]) tmpdir = getenv("TMPDIR"); if (asprintf(&tname, "%s/kgzXXXXXXXXXX", tmpdir == NULL ? _PATH_TMP : tmpdir) == -1) - errx(1, "Out of memory"); + errx(1, "Out of memory"); output = NULL; cflag = vflag = 0; - while ((c = getopt(argc, argv, "cvl:o:")) != -1) + while ((c = getopt(argc, argv, "cvf:l:o:")) != -1) switch (c) { case 'c': cflag = 1; @@ -82,6 +83,14 @@ main(int argc, char *argv[]) case 'v': vflag = 1; break; + case 'f': + if (!strcmp(optarg, "aout")) + format = F_AOUT; + else if (!strcmp(optarg, "elf")) + format = F_ELF; + else + errx(1, "%s: Unknown format", optarg); + break; case 'l': loader = optarg; break; @@ -98,8 +107,11 @@ main(int argc, char *argv[]) atexit(cleanup); mk_fn(cflag, *argv, output, fn); memset(&kh, 0, sizeof(kh)); - if (fn[FN_SRC]) + if (fn[FN_SRC]) { + if (!format) + format = F_ELF; kgzcmp(&kh, fn[FN_SRC], fn[FN_OBJ]); + } if (!cflag) kgzld(&kh, fn[FN_OBJ], fn[FN_KGZ]); if (vflag) @@ -159,6 +171,6 @@ static void usage(void) { fprintf(stderr, - "usage: kgzip [-cv] [-l file] [-o filename] file\n"); + "usage: kgzip [-cv] [-f format] [-l file] [-o filename] file\n"); exit(1); } diff --git a/usr.sbin/kgzip/kgzip.h b/usr.sbin/kgzip/kgzip.h index 4231c0fee5b8..f04f2a4cf14f 100644 --- a/usr.sbin/kgzip/kgzip.h +++ b/usr.sbin/kgzip/kgzip.h @@ -28,6 +28,9 @@ #include "kgz.h" +#define F_AOUT 1 /* Format: a.out */ +#define F_ELF 2 /* Format: ELF32 */ + /* Used by I/O routines */ struct iodesc { const char *fname; /* File name */ @@ -35,6 +38,7 @@ struct iodesc { }; extern const char *loader; /* Default loader */ +extern int format; /* Output format */ void kgzcmp(struct kgz_hdr *, const char *, const char *); void kgzld(struct kgz_hdr *, const char *, const char *); diff --git a/usr.sbin/kgzip/kgzld.c b/usr.sbin/kgzip/kgzld.c index a2b0086b313f..3e1d2d14f219 100644 --- a/usr.sbin/kgzip/kgzld.c +++ b/usr.sbin/kgzip/kgzld.c @@ -36,11 +36,10 @@ #include #include +#include "aouthdr.h" #include "elfhdr.h" #include "kgzip.h" -#define KGZOFF sizeof(struct kgz_elfhdr) - #define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) /* @@ -58,7 +57,23 @@ kgzld(struct kgz_hdr * kh, const char *f1, const char *f2) if (strcmp(kh->ident, "KGZ")) { if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) err(1, "%s", idi.fname); - n = xread(&idi, kh, sizeof(*kh), KGZOFF); + if (!format) { + union { + struct exec ex; + Elf32_Ehdr ee; + } hdr; + n = xread(&idi, &hdr, sizeof(hdr), 0); + if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) + format = F_ELF; + else if (n >= sizeof(hdr.ex) && + N_GETMAGIC(hdr.ex) == OMAGIC) + format = F_AOUT; + if (!format) + errx(1, "%s: Format not supported", idi.fname); + } + n = xread(&idi, kh, sizeof(*kh), + format == F_AOUT ? sizeof(struct kgz_aouthdr0) + : sizeof(struct kgz_elfhdr)); xclose(&idi); if (n != sizeof(*kh) || strcmp(kh->ident, "KGZ")) errx(1, "%s: Invalid format", idi.fname); @@ -68,7 +83,12 @@ kgzld(struct kgz_hdr * kh, const char *f1, const char *f2) case -1: err(1, NULL); case 0: - execlp("ld", "ld", "-Ttext", addr, "-o", f2, loader, f1, NULL); + if (format == F_AOUT) + execlp("ld", "ld", "-aout", "-Z", "-T", addr, "-o", f2, + loader, f1, NULL); + else + execlp("ld", "ld", "-Ttext", addr, "-o", f2, loader, f1, + NULL); warn(NULL); _exit(1); default: