1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999 Global Technology Associates, Inc. 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 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 21 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 22 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31#define _KERNEL 32#include <sys/param.h> 33#undef _KERNEL 34#include <sys/types.h> 35#include <sys/stat.h> 36#include <sys/wait.h> 37 38#include <err.h> 39#include <fcntl.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <unistd.h> 43 44#include <a.out.h> 45 46#include "aouthdr.h" 47#include "elfhdr.h" 48#include "kgzip.h" 49 50static void mk_data(const struct iodesc *i, const struct iodesc *, 51 struct kgz_hdr *, size_t); 52static int ld_elf(const struct iodesc *, const struct iodesc *, 53 struct kgz_hdr *, const Elf32_Ehdr *); 54static int ld_aout(const struct iodesc *, const struct iodesc *, 55 struct kgz_hdr *, const struct exec *); 56 57/* 58 * Compress executable and output it in relocatable object format. 59 */ 60void 61kgzcmp(struct kgz_hdr *kh, const char *f1, const char *f2) 62{ 63 struct iodesc idi, ido; 64 struct kgz_hdr khle; 65 66 if ((idi.fd = open(idi.fname = f1, O_RDONLY)) == -1) 67 err(1, "%s", idi.fname); 68 if ((ido.fd = open(ido.fname = f2, O_CREAT | O_TRUNC | O_WRONLY, 69 0666)) == -1) 70 err(1, "%s", ido.fname); 71 kh->ident[0] = KGZ_ID0; 72 kh->ident[1] = KGZ_ID1; 73 kh->ident[2] = KGZ_ID2; 74 kh->ident[3] = KGZ_ID3; 75 mk_data(&idi, &ido, kh, 76 (format == F_AOUT ? sizeof(struct kgz_aouthdr0) : 77 sizeof(struct kgz_elfhdr)) + 78 sizeof(struct kgz_hdr)); 79 kh->dload &= 0xffffff; 80 kh->entry &= 0xffffff; 81 if (format == F_AOUT) { 82 struct kgz_aouthdr0 ahdr0 = aouthdr0; 83 struct kgz_aouthdr1 ahdr1 = aouthdr1; 84 unsigned x = (sizeof(struct kgz_hdr) + kh->nsize) & (16 - 1); 85 if (x) { 86 x = 16 - x; 87 xzero(&ido, x); 88 } 89 xwrite(&ido, &ahdr1, sizeof(ahdr1)); 90 ahdr0.a.a_data += kh->nsize + x; 91 xseek(&ido, 0); 92 xwrite(&ido, &ahdr0, sizeof(ahdr0)); 93 } else { 94 struct kgz_elfhdr ehdr = elfhdr; 95 ehdr.st[KGZ_ST_KGZ_NDATA].st_size = htole32(kh->nsize); 96 ehdr.sh[KGZ_SH_DATA].sh_size = 97 htole32(le32toh(ehdr.sh[KGZ_SH_DATA].sh_size) + kh->nsize); 98 xseek(&ido, 0); 99 xwrite(&ido, &ehdr, sizeof(ehdr)); 100 } 101 khle = *kh; 102 khle.dload = htole32(khle.dload); 103 khle.dsize = htole32(khle.dsize); 104 khle.isize = htole32(khle.isize); 105 khle.entry = htole32(khle.entry); 106 khle.nsize = htole32(khle.nsize); 107 xwrite(&ido, &khle, sizeof(khle)); 108 xclose(&ido); 109 xclose(&idi); 110} 111 112/* 113 * Make encoded (compressed) data. 114 */ 115static void 116mk_data(const struct iodesc * idi, const struct iodesc * ido, 117 struct kgz_hdr * kh, size_t off) 118{ 119 union { 120 struct exec ex; 121 Elf32_Ehdr ee; 122 } hdr; 123 struct stat sb; 124 struct iodesc idp; 125 int fd[2]; 126 pid_t pid; 127 size_t n; 128 int fmt, status, e; 129 130 n = xread(idi, &hdr, sizeof(hdr), 0); 131 fmt = 0; 132 if (n >= sizeof(hdr.ee) && IS_ELF(hdr.ee)) 133 fmt = F_ELF; 134 else if (n >= sizeof(hdr.ex) && N_GETMAGIC(hdr.ex) == ZMAGIC) 135 fmt = F_AOUT; 136 if (!fmt) 137 errx(1, "%s: Format not supported", idi->fname); 138 xseek(ido, off); 139 if (pipe(fd)) 140 err(1, NULL); 141 switch (pid = fork()) { 142 case -1: 143 err(1, NULL); 144 case 0: 145 close(fd[1]); 146 dup2(fd[0], STDIN_FILENO); 147 close(fd[0]); 148 close(idi->fd); 149 dup2(ido->fd, STDOUT_FILENO); 150 close(ido->fd); 151 execlp("gzip", "gzip", "-9n", (char *)NULL); 152 warn(NULL); 153 _exit(1); 154 default: 155 close(fd[0]); 156 idp.fname = "(pipe)"; 157 idp.fd = fd[1]; 158 e = fmt == F_ELF ? ld_elf(idi, &idp, kh, &hdr.ee) : 159 fmt == F_AOUT ? ld_aout(idi, &idp, kh, &hdr.ex) : -1; 160 close(fd[1]); 161 if ((pid = waitpid(pid, &status, 0)) == -1) 162 err(1, NULL); 163 if (WIFSIGNALED(status) || WEXITSTATUS(status)) 164 exit(1); 165 } 166 if (e) 167 errx(1, "%s: Invalid format", idi->fname); 168 if (fstat(ido->fd, &sb)) 169 err(1, "%s", ido->fname); 170 kh->nsize = sb.st_size - off; 171} 172 173/* 174 * "Load" an ELF-format executable. 175 */ 176static int 177ld_elf(const struct iodesc * idi, const struct iodesc * ido, 178 struct kgz_hdr * kh, const Elf32_Ehdr * e) 179{ 180 Elf32_Phdr p; 181 size_t load, addr, n; 182 unsigned x, i; 183 184 load = addr = n = 0; 185 for (x = i = 0; i < e->e_phnum; i++) { 186 if (xread(idi, &p, sizeof(p), 187 e->e_phoff + i * e->e_phentsize) != e->e_phentsize) 188 return -1; 189 if (p.p_type != PT_LOAD) 190 continue; 191 if (!x) 192 load = addr = p.p_vaddr; 193 else { 194 if (p.p_vaddr < addr) 195 return -1; 196 n = p.p_vaddr - addr; 197 if (n) { 198 xzero(ido, n); 199 addr += n; 200 } 201 } 202 if (p.p_memsz < p.p_filesz) 203 return -1; 204 n = p.p_memsz - p.p_filesz; 205 xcopy(idi, ido, p.p_filesz, p.p_offset); 206 addr += p.p_filesz; 207 x++; 208 } 209 if (!x) 210 return -1; 211 kh->dload = load; 212 kh->dsize = addr - load; 213 kh->isize = kh->dsize + n; 214 kh->entry = e->e_entry; 215 return 0; 216} 217 218/* 219 * "Load" an a.out-format executable. 220 */ 221static int 222ld_aout(const struct iodesc * idi, const struct iodesc * ido, 223 struct kgz_hdr * kh, const struct exec * a) 224{ 225 size_t load, addr; 226 227 load = addr = N_TXTADDR(*a); 228 xcopy(idi, ido, le32toh(a->a_text), N_TXTOFF(*a)); 229 addr += le32toh(a->a_text); 230 if (N_DATADDR(*a) != addr) 231 return -1; 232 xcopy(idi, ido, le32toh(a->a_data), N_DATOFF(*a)); 233 addr += le32toh(a->a_data); 234 kh->dload = load; 235 kh->dsize = addr - load; 236 kh->isize = kh->dsize + le32toh(a->a_bss); 237 kh->entry = le32toh(a->a_entry); 238 return 0; 239} 240