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