From 4566a1d1d36a0b379454b3bab527eb57b174dcaf Mon Sep 17 00:00:00 2001 From: Robert Nordier Date: Mon, 19 Jul 1999 18:00:18 +0000 Subject: [PATCH] kgzip is a kzip(8) replacement able to compress and link bootable 32-bit binaries in both ELF and a.out format. Development sponsored by Global Technology Associates, Inc. Reviewed/tested by: abial --- usr.sbin/kgzip/Makefile | 12 +++ usr.sbin/kgzip/elfhdr.c | 163 ++++++++++++++++++++++++++++++ usr.sbin/kgzip/elfhdr.h | 81 +++++++++++++++ usr.sbin/kgzip/kgz.h | 57 +++++++++++ usr.sbin/kgzip/kgzcmp.c | 215 ++++++++++++++++++++++++++++++++++++++++ usr.sbin/kgzip/kgzip.8 | 130 ++++++++++++++++++++++++ usr.sbin/kgzip/kgzip.c | 159 +++++++++++++++++++++++++++++ usr.sbin/kgzip/kgzip.h | 47 +++++++++ usr.sbin/kgzip/kgzld.c | 80 +++++++++++++++ usr.sbin/kgzip/xio.c | 122 +++++++++++++++++++++++ 10 files changed, 1066 insertions(+) create mode 100644 usr.sbin/kgzip/Makefile create mode 100644 usr.sbin/kgzip/elfhdr.c create mode 100644 usr.sbin/kgzip/elfhdr.h create mode 100644 usr.sbin/kgzip/kgz.h create mode 100644 usr.sbin/kgzip/kgzcmp.c create mode 100644 usr.sbin/kgzip/kgzip.8 create mode 100644 usr.sbin/kgzip/kgzip.c create mode 100644 usr.sbin/kgzip/kgzip.h create mode 100644 usr.sbin/kgzip/kgzld.c create mode 100644 usr.sbin/kgzip/xio.c diff --git a/usr.sbin/kgzip/Makefile b/usr.sbin/kgzip/Makefile new file mode 100644 index 000000000000..404303b11f04 --- /dev/null +++ b/usr.sbin/kgzip/Makefile @@ -0,0 +1,12 @@ +# $Id: $ + +PROG= kgzip +SRCS= kgzip.c elfhdr.c kgzcmp.c kgzld.c xio.c +MAN8= kgzip.8 +CFLAGS+=-pedantic \ + -W -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wpointer-arith -Wredundant-decls -Wshadow -Wstrict-prototypes \ + -Wwrite-strings + +.include diff --git a/usr.sbin/kgzip/elfhdr.c b/usr.sbin/kgzip/elfhdr.c new file mode 100644 index 000000000000..61bf4435429f --- /dev/null +++ b/usr.sbin/kgzip/elfhdr.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include +#include "elfhdr.h" + +#define KGZ_FIX_NSIZE 0 /* Run-time fixup */ + +/* + * Relocatable header template. + */ +const struct kgz_elfhdr elfhdr = { + /* ELF header */ + { + { + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, /* e_ident */ + ELFCLASS32, ELFDATA2LSB, EV_CURRENT, 0, + 'F', 'r', 'e', 'e', 'B', 'S', 'D', 0 + }, + ET_EXEC, /* e_type */ + EM_386, /* e_machine */ + EV_CURRENT, /* e_version */ + 0, /* e_entry */ + 0, /* e_phoff */ + offsetof(struct kgz_elfhdr, sh), /* e_shoff */ + 0, /* e_flags */ + sizeof(Elf32_Ehdr), /* e_ehsize */ + 0, /* e_phentsize */ + 0, /* e_phnum */ + sizeof(Elf32_Shdr), /* e_shentsize */ + KGZ_SHNUM, /* e_shnum */ + KGZ_SH_SHSTRTAB /* e_shstrndx */ + }, + /* Section header */ + { + { + 0, /* sh_name */ + SHT_NULL, /* sh_type */ + 0, /* sh_flags */ + 0, /* sh_addr */ + 0, /* sh_offset */ + 0, /* sh_size */ + SHN_UNDEF, /* sh_link */ + 0, /* sh_info */ + 0, /* sh_addralign */ + 0 /* sh_entsize */ + }, + { + offsetof(struct kgz_shstrtab, symtab), /* sh_name */ + SHT_SYMTAB, /* sh_type */ + 0, /* sh_flags */ + 0, /* sh_addr */ + offsetof(struct kgz_elfhdr, st), /* sh_offset */ + sizeof(Elf32_Sym) * KGZ_STNUM, /* sh_size */ + KGZ_SH_STRTAB, /* sh_link */ + 1, /* sh_info */ + 4, /* sh_addralign */ + sizeof(Elf32_Sym) /* sh_entsize */ + }, + { + offsetof(struct kgz_shstrtab, shstrtab), /* sh_name */ + SHT_STRTAB, /* sh_type */ + 0, /* sh_flags */ + 0, /* sh_addr */ + offsetof(struct kgz_elfhdr, shstrtab), /* sh_offset */ + sizeof(struct kgz_shstrtab), /* sh_size */ + SHN_UNDEF, /* sh_link */ + 0, /* sh_info */ + 1, /* sh_addralign */ + 0 /* sh_entsize */ + }, + { + offsetof(struct kgz_shstrtab, strtab), /* sh_name */ + SHT_STRTAB, /* sh_type */ + 0, /* sh_flags */ + 0, /* sh_addr */ + offsetof(struct kgz_elfhdr, strtab), /* sh_offset */ + sizeof(struct kgz_strtab), /* sh_size */ + SHN_UNDEF, /* sh_link */ + 0, /* sh_info */ + 1, /* sh_addralign */ + 0 /* sh_entsize */ + }, + { + offsetof(struct kgz_shstrtab, data), /* sh_name */ + SHT_PROGBITS, /* sh_type */ + SHF_ALLOC | SHF_WRITE, /* sh_flags */ + 0, /* sh_addr */ + sizeof(struct kgz_elfhdr), /* sh_offset */ + sizeof(struct kgz_hdr) + KGZ_FIX_NSIZE, /* sh_size */ + SHN_UNDEF, /* sh_link */ + 0, /* sh_info */ + 4, /* sh_addralign */ + 0 /* sh_entsize */ + } + }, + /* Symbol table */ + { + { + 0, /* st_name */ + 0, /* st_value */ + 0, /* st_size */ + 0, /* st_info */ + 0, /* st_other */ + SHN_UNDEF /* st_shndx */ + }, + { + offsetof(struct kgz_strtab, kgz), /* st_name */ + 0, /* st_value */ + sizeof(struct kgz_hdr), /* st_size */ + ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), /* st_info */ + 0, /* st_other */ + KGZ_SH_DATA /* st_shndx */ + }, + { + offsetof(struct kgz_strtab, kgz_ndata), /* st_name */ + sizeof(struct kgz_hdr), /* st_value */ + KGZ_FIX_NSIZE, /* st_size */ + ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), /* st_info */ + 0, /* st_other */ + KGZ_SH_DATA /* st_shndx */ + } + }, + /* Section header string table */ + { + KGZ_SHSTR_ZERO, /* zero */ + KGZ_SHSTR_SYMTAB, /* symtab */ + KGZ_SHSTR_SHSTRTAB, /* shstrtab */ + KGZ_SHSTR_STRTAB, /* strtab */ + KGZ_SHSTR_DATA /* data */ + }, + /* String table */ + { + KGZ_STR_ZERO, /* zero */ + KGZ_STR_KGZ, /* kgz */ + KGZ_STR_KGZ_NDATA /* kgz_ndata */ + } +}; diff --git a/usr.sbin/kgzip/elfhdr.h b/usr.sbin/kgzip/elfhdr.h new file mode 100644 index 000000000000..685f620ca7d0 --- /dev/null +++ b/usr.sbin/kgzip/elfhdr.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include +#include "kgz.h" + +/* Section header indices */ +#define KGZ_SH_SYMTAB 1 +#define KGZ_SH_SHSTRTAB 2 +#define KGZ_SH_STRTAB 3 +#define KGZ_SH_DATA 4 +#define KGZ_SHNUM 5 + +/* Section header strings */ +#define KGZ_SHSTR_ZERO "" +#define KGZ_SHSTR_SYMTAB ".symtab" +#define KGZ_SHSTR_SHSTRTAB ".shstrtab" +#define KGZ_SHSTR_STRTAB ".strtab" +#define KGZ_SHSTR_DATA ".data" + +/* Section header string table */ +struct kgz_shstrtab { + char zero[sizeof(KGZ_SHSTR_ZERO)]; + char symtab[sizeof(KGZ_SHSTR_SYMTAB)]; + char shstrtab[sizeof(KGZ_SHSTR_SHSTRTAB)]; + char strtab[sizeof(KGZ_SHSTR_STRTAB)]; + char data[sizeof(KGZ_SHSTR_DATA)]; +}; + +/* Symbol table indices */ +#define KGZ_ST_KGZ 1 +#define KGZ_ST_KGZ_NDATA 2 +#define KGZ_STNUM 3 + +/* Symbol table strings */ +#define KGZ_STR_ZERO "" +#define KGZ_STR_KGZ "kgz" +#define KGZ_STR_KGZ_NDATA "kgz_ndata" + +/* String table */ +struct kgz_strtab { + char zero[sizeof(KGZ_STR_ZERO)]; + char kgz[sizeof(KGZ_STR_KGZ)]; + char kgz_ndata[sizeof(KGZ_STR_KGZ_NDATA)]; +}; + +/* Relocatable header format */ +struct kgz_elfhdr { + Elf32_Ehdr e; + Elf32_Shdr sh[KGZ_SHNUM]; + Elf32_Sym st[KGZ_STNUM]; + struct kgz_shstrtab shstrtab; + struct kgz_strtab strtab; +}; + +extern const struct kgz_elfhdr elfhdr; diff --git a/usr.sbin/kgzip/kgz.h b/usr.sbin/kgzip/kgz.h new file mode 100644 index 000000000000..301a56f52980 --- /dev/null +++ b/usr.sbin/kgzip/kgz.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#ifndef _KGZ_H_ +#define _KGZ_H_ + +#include + +/* + * KGZ definitions: kgzip(8) output. + */ + +/* Values for ident[]. */ +#define KGZ_ID0 'K' +#define KGZ_ID1 'G' +#define KGZ_ID2 'Z' +#define KGZ_ID3 '\0' + +/* KGZ header. */ +struct kgz_hdr { + char ident[4]; /* identification */ + uint32_t dload; /* decoded image load address */ + uint32_t dsize; /* decoded image size */ + uint32_t isize; /* image size in memory */ + uint32_t entry; /* program entry point */ + uint32_t nsize; /* encoded image size */ +}; + +extern struct kgz_hdr kgz; /* header */ +extern uint8_t kgz_ndata[]; /* encoded image */ + +#endif /* !_KGZ_H_ */ diff --git a/usr.sbin/kgzip/kgzcmp.c b/usr.sbin/kgzip/kgzcmp.c new file mode 100644 index 000000000000..a684b3e53713 --- /dev/null +++ b/usr.sbin/kgzip/kgzcmp.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#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 *); +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 *, + struct kgz_hdr *, const struct exec *); + +/* + * Compress executable and output it in relocatable object format. + */ +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); + if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, + 0666)) == -1) + err(1, "%s", ido.fname); + kh->ident[0] = KGZ_ID0; + kh->ident[1] = KGZ_ID1; + kh->ident[2] = KGZ_ID2; + kh->ident[3] = KGZ_ID3; + xseek(&ido, KGZOFF); + mk_data(&idi, &ido, kh); + 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)); + xwrite(&ido, kh, sizeof(*kh)); + xclose(&ido); + xclose(&idi); +} + +/* + * Make encoded (compressed) data. + */ +static void +mk_data(const struct iodesc * idi, const struct iodesc * ido, + struct kgz_hdr * kh) +{ + union { + struct exec ex; + Elf32_Ehdr ee; + } hdr; + struct stat sb; + struct iodesc idp; + int fd[2]; + pid_t pid; + size_t n; + int fmt, status, e; + + n = xread(idi, &hdr, sizeof(hdr), 0); + fmt = 0; + if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) + fmt = F_ELF; + else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC) + fmt = F_AOUT; + if (!fmt) + errx(1, "%s: Format not supported", idi->fname); + if (pipe(fd)) + err(1, NULL); + switch (pid = fork()) { + case -1: + err(1, NULL); + case 0: + close(fd[1]); + dup2(fd[0], STDIN_FILENO); + close(fd[0]); + close(idi->fd); + dup2(ido->fd, STDOUT_FILENO); + close(ido->fd); + execlp("gzip", "gzip", "-9", NULL); + warn(NULL); + _exit(1); + default: + close(fd[0]); + idp.fname = "(pipe)"; + idp.fd = fd[1]; + e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : + fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; + close(fd[1]); + if ((pid = waitpid(pid, &status, 0)) == -1) + err(1, NULL); + if (WIFSIGNALED(status) || WEXITSTATUS(status)) + exit(1); + } + if (e) + errx(1, "%s: Invalid format", idi->fname); + if (fstat(ido->fd, &sb)) + err(1, ido->fname); + kh->nsize = sb.st_size - KGZOFF; +} + +/* + * "Load" an ELF-format executable. + */ +static int +ld_elf(const struct iodesc * idi, const struct iodesc * ido, + struct kgz_hdr * kh, const Elf32_Ehdr * e) +{ + Elf32_Phdr p; + size_t load, addr, n; + unsigned x, i; + + load = addr = n = 0; + for (x = i = 0; i < e->e_phnum; i++) { + if (xread(idi, &p, sizeof(p), + e->e_phoff + i * e->e_phentsize) != e->e_phentsize) + return -1; + if (p.p_type != PT_LOAD) + continue; + if (!x) + load = addr = p.p_vaddr; + else { + if (p.p_vaddr < addr) + return -1; + n = p.p_vaddr - addr; + if (n) { + xzero(ido, n); + addr += n; + } + } + if (p.p_memsz < p.p_filesz) + return -1; + n = p.p_memsz - p.p_filesz; + xcopy(idi, ido, p.p_filesz, p.p_offset); + addr += p.p_filesz; + x++; + } + if (!x) + return -1; + kh->dload = load; + kh->dsize = addr - load; + kh->isize = kh->dsize + n; + kh->entry = e->e_entry; + return 0; +} + +/* + * "Load" an a.out-format executable. + */ +static int +ld_aout(const struct iodesc * idi, const struct iodesc * ido, + struct kgz_hdr * kh, const struct exec * a) +{ + size_t load, addr; + + load = addr = N_TXTADDR(*a); + xcopy(idi, ido, a->a_text, N_TXTOFF(*a)); + addr += a->a_text; + if (N_DATADDR(*a) != addr) + return -1; + xcopy(idi, ido, a->a_data, N_DATOFF(*a)); + addr += a->a_data; + kh->dload = load; + kh->dsize = addr - load; + kh->isize = kh->dsize + a->a_bss; + kh->entry = a->a_entry; + return 0; +} diff --git a/usr.sbin/kgzip/kgzip.8 b/usr.sbin/kgzip/kgzip.8 new file mode 100644 index 000000000000..5af0bad20701 --- /dev/null +++ b/usr.sbin/kgzip/kgzip.8 @@ -0,0 +1,130 @@ +.\" Copyright (c) 1999 Global Technology Associates, Inc. +.\" 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS +.\" 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. +.\" +.\" $Id:$ +.\" +.Dd July 19, 1999 +.Dt KGZIP 8 +.Os FreeBSD +.Sh NAME +.Nm kgzip +.Nd compress a kernel +.Sh SYNOPSIS +.Nm kgzip +.Op Fl cv +.Op Fl l Ar loader +.Op Fl o Ar output +.Ar file +.Sh DESCRIPTION +The +.Nm +utility compresses a kernel or some other bootable binary. Operation +is in two phases as follows: +.Bl -enum +.It +A load image of the executable file is built which omits all but +the +.Sq text +and +.Sq data +segments. This image is compressed using +.Xr gzip 1 +and output as data in relocatable object format. +.It +The object file is linked with a special self-hosting loader, producing +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. +.Pp +If the +.Ar file +operand has a +.Sq .o +suffix, input is assumed to be for the link phase, and the first phase +is omitted. +.Pp +The options are: +.Bl -tag -width Fl +.It Fl c +Omit the link phase. +.It Fl v +Display object file information. +.It Fl l Ar loader +Link +.Ar loader +as the loader. +.It Fl o Ar output +Name the output file +.Ar output . +The default is to use the input name with the suffix +.Sq .o +(for relocatables) or +.Sq .kgz +(for executables). +.El +.Sh NOTES +Global variables equivalent to the following are defined in the output: +.Bd -literal +struct kgz_hdr { + char ident[4]; /* identification: "KGZ" */ + uint32_t dload; /* decoded image load address */ + uint32_t dsize; /* decoded image size */ + uint32_t isize; /* image size in memory */ + uint32_t entry; /* entry point */ + uint32_t nsize; /* encoded image size */ +} kgz; + +uint8_t kgz_ndata[]; /* encoded data */ +.Ed +.Pp +The encoded data is simply +.Xr gzip 1 +output: a header (with no optional fields); compressed data; and 32-bit +CRC and size values. +.Sh FILES +.Bl -tag -width /usr/lib/kgzldr.o -compact +.It Pa /usr/lib/kgzldr.o +The default loader +.El +.Sh SEE ALSO +.Xr gzip 1 , +.Xr ld 1 , +.Xr a.out 5 , +.Xr boot 8 , +.Xr loader 8 +.Sh DIAGNOSTICS +Exit status is 0 on success and >0 on error. +.Sh AUTHORS +.An Robert Nordier Aq rnordier@FreeBSD.org . +.Sh BUGS +As symbols are lost, the usefulness of this utility for compressing +kernels is limited to situations where +.Xr loader 8 +cannot be used; otherwise the preferred method of compressing a kernel +is simply to +.Xr gzip 1 +it. diff --git a/usr.sbin/kgzip/kgzip.c b/usr.sbin/kgzip/kgzip.c new file mode 100644 index 000000000000..e20f85bf29f8 --- /dev/null +++ b/usr.sbin/kgzip/kgzip.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + */ + +#ifndef lint +static const char rcsid[] = + "$Id:$"; +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include + +#include "kgzip.h" + +#define FN_SRC 0 /* Filename: source */ +#define FN_OBJ 1 /* Filename: relocatable */ +#define FN_KGZ 2 /* Filename: executable */ +#define FN_CNT 3 /* Number of filenames */ + +#define SFX_OBJ ".o" /* Filename suffix: relocatable */ +#define SFX_KGZ ".kgz" /* Filename suffix: executable */ +#define SFX_MAX 5 /* Size of larger filename suffix */ + +#define TMP_PREFIX "kgz" /* Temporary file prefix */ + +const char *loader = "/usr/lib/kgzldr.o"; /* Default loader */ + +static const char *tname; /* Name of temporary file */ + +static void cleanup(void); +static void mk_fn(int, const char *, const char *, char *[]); +static void usage(void); + +/* + * Compress a kernel. + */ +int +main(int argc, char *argv[]) +{ + static char *fn[FN_CNT]; + struct kgz_hdr kh; + const char *output; + int cflag, vflag, c; + + output = NULL; + cflag = vflag = 0; + while ((c = getopt(argc, argv, "cvl:o:")) != -1) + switch (c) { + case 'c': + cflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'l': + loader = optarg; + break; + case 'o': + output = optarg; + break; + default: + usage(); + } + argc -= optind; + argv += optind; + if (argc != 1) + usage(); + atexit(cleanup); + mk_fn(cflag, *argv, output, fn); + memset(&kh, 0, sizeof(kh)); + if (fn[FN_SRC]) + kgzcmp(&kh, fn[FN_SRC], fn[FN_OBJ]); + if (!cflag) + kgzld(&kh, fn[FN_OBJ], fn[FN_KGZ]); + if (vflag) + printf("dload=%#x dsize=%#x isize=%#x entry=%#x nsize=%#x\n", + kh.dload, kh.dsize, kh.isize, kh.entry, kh.nsize); + return 0; +} + +/* + * Clean up after processing. + */ +static void +cleanup(void) +{ + if (tname) + unlink(tname); +} + +/* + * Make the required filenames. + */ +static void +mk_fn(int cflag, const char *f1, const char *f2, char *fn[]) +{ + const char *p, *s; + size_t n; + int i; + + i = 0; + s = strrchr(f1, 0); + n = sizeof(SFX_OBJ) - 1; + if ((size_t)(s - f1) > n && !memcmp(s - n, SFX_OBJ, n)) { + s -= n; + i++; + } + fn[i++] = (char *)f1; + if (i == FN_OBJ && !cflag) { + if (!(tname = tempnam(NULL, TMP_PREFIX))) + err(1, NULL); + fn[i++] = (char *)tname; + } + if (!(fn[i] = (char *)f2)) { + p = (p = strrchr(f1, '/')) ? p + 1 : f1; + n = (size_t)(s - p); + if (!(fn[i] = malloc(n + SFX_MAX))) + err(1, NULL); + memcpy(fn[i], p, n); + strcpy(fn[i] + n, i == FN_OBJ ? SFX_OBJ : SFX_KGZ); + } +} + +/* + * Display usage information. + */ +static void +usage(void) +{ + fprintf(stderr, + "usage: kgzip [-cv] [-l file] [-o filename] file\n"); + exit(1); +} diff --git a/usr.sbin/kgzip/kgzip.h b/usr.sbin/kgzip/kgzip.h new file mode 100644 index 000000000000..64507d50a1b5 --- /dev/null +++ b/usr.sbin/kgzip/kgzip.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include "kgz.h" + +/* Used by I/O routines */ +struct iodesc { + const char *fname; /* File name */ + int fd; /* File descriptor */ +}; + +extern const char *loader; /* Default loader */ + +void kgzcmp(struct kgz_hdr *, const char *, const char *); +void kgzld(struct kgz_hdr *, const char *, const char *); + +void xclose(const struct iodesc *); +void xcopy(const struct iodesc *, const struct iodesc *, size_t, off_t); +void xzero(const struct iodesc *, size_t); +size_t xread(const struct iodesc *, void *, size_t, off_t); +void xwrite(const struct iodesc *, const void *, size_t); +void xseek(const struct iodesc *, off_t); diff --git a/usr.sbin/kgzip/kgzld.c b/usr.sbin/kgzip/kgzld.c new file mode 100644 index 000000000000..75bc7fc90a8f --- /dev/null +++ b/usr.sbin/kgzip/kgzld.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "elfhdr.h" +#include "kgzip.h" + +#define KGZOFF sizeof(struct kgz_elfhdr) + +#define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) + +/* + * Link KGZ file and loader. + */ +void +kgzld(struct kgz_hdr * kh, const char *f1, const char *f2) +{ + char addr[16]; + struct iodesc idi; + pid_t pid; + size_t n; + int status; + + 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); + xclose(&idi); + if (n != sizeof(*kh) || strcmp(kh->ident, "KGZ")) + errx(1, "%s: Invalid format", idi.fname); + } + sprintf(addr, "%#x", align(kh->dload + kh->dsize, 0x1000)); + switch (pid = fork()) { + case -1: + err(1, NULL); + case 0: + execlp("ld", "ld", "-Ttext", addr, "-o", f2, loader, f1, NULL); + warn(NULL); + _exit(1); + default: + if ((pid = waitpid(pid, &status, 0)) == -1) + err(1, NULL); + if (WIFSIGNALED(status) || WEXITSTATUS(status)) + exit(1); + } +} diff --git a/usr.sbin/kgzip/xio.c b/usr.sbin/kgzip/xio.c new file mode 100644 index 000000000000..ed04f6625a9b --- /dev/null +++ b/usr.sbin/kgzip/xio.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1999 Global Technology Associates, Inc. + * 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 AND CONTRIBUTORS``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 OR CONTRIBUTORS + * 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. + * + * $Id:$ + */ + +#include +#include +#include +#include + +#include "kgzip.h" + +/* + * Close a file. + */ +void +xclose(const struct iodesc *id) +{ + if (close(id->fd)) + err(1, "%s", id->fname); +} + +/* + * Copy bytes from one file to another. + */ +void +xcopy(const struct iodesc * idi, const struct iodesc * ido, + size_t nbyte, off_t offset) +{ + char buf[8192]; + size_t n; + + while (nbyte) { + if ((n = sizeof(buf)) > nbyte) + n = nbyte; + if (xread(idi, buf, n, offset) != n) + errx(1, "%s: Short read", idi->fname); + xwrite(ido, buf, n); + nbyte -= n; + offset = -1; + } +} + +/* + * Write binary zeroes to a file. + */ +void +xzero(const struct iodesc * id, size_t nbyte) +{ + char buf[8192]; + size_t n; + + memset(buf, 0, sizeof(buf)); + while (nbyte) { + if ((n = sizeof(buf)) > nbyte) + n = nbyte; + xwrite(id, buf, n); + nbyte -= n; + } +} + +/* + * Read from a file. + */ +size_t +xread(const struct iodesc * id, void *buf, size_t nbyte, off_t offset) +{ + ssize_t n; + + if (offset != -1 && lseek(id->fd, offset, SEEK_SET) != offset) + err(1, "%s", id->fname); + if ((n = read(id->fd, buf, nbyte)) == -1) + err(1, "%s", id->fname); + return (size_t)n; +} + +/* + * Write to a file. + */ +void +xwrite(const struct iodesc * id, const void *buf, size_t nbyte) +{ + ssize_t n; + + if ((n = write(id->fd, buf, nbyte)) == -1) + err(1, "%s", id->fname); + if ((size_t)n != nbyte) + errx(1, "%s: Short write", id->fname); +} + +/* + * Reposition within a file. + */ +void +xseek(const struct iodesc *id, off_t offset) +{ + if (lseek(id->fd, offset, SEEK_SET) != offset) + err(1, "%s", id->fname); +}