1*150a6952SToomas Soome /* 2*150a6952SToomas Soome * Copyright (c) 1998 Robert Nordier 3*150a6952SToomas Soome * All rights reserved. 4*150a6952SToomas Soome * 5*150a6952SToomas Soome * Redistribution and use in source and binary forms, with or without 6*150a6952SToomas Soome * modification, are permitted provided that the following conditions 7*150a6952SToomas Soome * are met: 8*150a6952SToomas Soome * 1. Redistributions of source code must retain the above copyright 9*150a6952SToomas Soome * notice, this list of conditions and the following disclaimer. 10*150a6952SToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 11*150a6952SToomas Soome * notice, this list of conditions and the following disclaimer in the 12*150a6952SToomas Soome * documentation and/or other materials provided with the distribution. 13*150a6952SToomas Soome * 14*150a6952SToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 15*150a6952SToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*150a6952SToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17*150a6952SToomas Soome * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 18*150a6952SToomas Soome * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 19*150a6952SToomas Soome * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20*150a6952SToomas Soome * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 21*150a6952SToomas Soome * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22*150a6952SToomas Soome * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 23*150a6952SToomas Soome * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24*150a6952SToomas Soome * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25*150a6952SToomas Soome */ 26*150a6952SToomas Soome 27*150a6952SToomas Soome #include <sys/param.h> 28*150a6952SToomas Soome #include "endian.h" 29*150a6952SToomas Soome #include <sys/stat.h> 30*150a6952SToomas Soome #include <sys/mman.h> 31*150a6952SToomas Soome 32*150a6952SToomas Soome /* XXX make this work as an i386/amd64 cross-tool */ 33*150a6952SToomas Soome #undef __LDPGSZ 34*150a6952SToomas Soome #define __LDPGSZ 4096 35*150a6952SToomas Soome 36*150a6952SToomas Soome #include <netinet/in.h> 37*150a6952SToomas Soome 38*150a6952SToomas Soome #include "imgact_aout.h" 39*150a6952SToomas Soome #include <err.h> 40*150a6952SToomas Soome #include <errno.h> 41*150a6952SToomas Soome #include <fcntl.h> 42*150a6952SToomas Soome #include <stdarg.h> 43*150a6952SToomas Soome #include <stdio.h> 44*150a6952SToomas Soome #include <stdlib.h> 45*150a6952SToomas Soome #include <string.h> 46*150a6952SToomas Soome #include <unistd.h> 47*150a6952SToomas Soome 48*150a6952SToomas Soome #include "btx.h" 49*150a6952SToomas Soome #include "elfh.h" 50*150a6952SToomas Soome 51*150a6952SToomas Soome #define BTX_PATH "/sys/boot/i386/btx" 52*150a6952SToomas Soome 53*150a6952SToomas Soome #define I_LDR 0 /* BTX loader */ 54*150a6952SToomas Soome #define I_BTX 1 /* BTX kernel */ 55*150a6952SToomas Soome #define I_CLNT 2 /* Client program */ 56*150a6952SToomas Soome 57*150a6952SToomas Soome #define F_BIN 0 /* Binary */ 58*150a6952SToomas Soome #define F_AOUT 1 /* ZMAGIC a.out */ 59*150a6952SToomas Soome #define F_ELF 2 /* 32-bit ELF */ 60*150a6952SToomas Soome #define F_CNT 3 /* Number of formats */ 61*150a6952SToomas Soome 62*150a6952SToomas Soome #define IMPURE 1 /* Writable text */ 63*150a6952SToomas Soome #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ 64*150a6952SToomas Soome 65*150a6952SToomas Soome #define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) 66*150a6952SToomas Soome 67*150a6952SToomas Soome struct hdr { 68*150a6952SToomas Soome uint32_t fmt; /* Format */ 69*150a6952SToomas Soome uint32_t flags; /* Bit flags */ 70*150a6952SToomas Soome uint32_t size; /* Size of file */ 71*150a6952SToomas Soome uint32_t text; /* Size of text segment */ 72*150a6952SToomas Soome uint32_t data; /* Size of data segment */ 73*150a6952SToomas Soome uint32_t bss; /* Size of bss segment */ 74*150a6952SToomas Soome uint32_t org; /* Program origin */ 75*150a6952SToomas Soome uint32_t entry; /* Program entry point */ 76*150a6952SToomas Soome }; 77*150a6952SToomas Soome 78*150a6952SToomas Soome static const char *const fmtlist[] = {"bin", "aout", "elf"}; 79*150a6952SToomas Soome 80*150a6952SToomas Soome static const char binfo[] = 81*150a6952SToomas Soome "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " 82*150a6952SToomas Soome "pgctl=%x:%x\n"; 83*150a6952SToomas Soome static const char cinfo[] = 84*150a6952SToomas Soome "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; 85*150a6952SToomas Soome static const char oinfo[] = 86*150a6952SToomas Soome "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; 87*150a6952SToomas Soome 88*150a6952SToomas Soome static const char *lname = 89*150a6952SToomas Soome BTX_PATH "/btxldr/btxldr"; /* BTX loader */ 90*150a6952SToomas Soome static const char *bname = 91*150a6952SToomas Soome BTX_PATH "/btx/btx"; /* BTX kernel */ 92*150a6952SToomas Soome static const char *oname = 93*150a6952SToomas Soome "a.out"; /* Output filename */ 94*150a6952SToomas Soome 95*150a6952SToomas Soome static int ppage = -1; /* First page present */ 96*150a6952SToomas Soome static int wpage = -1; /* First page writable */ 97*150a6952SToomas Soome 98*150a6952SToomas Soome static unsigned int format; /* Output format */ 99*150a6952SToomas Soome 100*150a6952SToomas Soome static uint32_t centry; /* Client entry address */ 101*150a6952SToomas Soome static uint32_t lentry; /* Loader entry address */ 102*150a6952SToomas Soome 103*150a6952SToomas Soome static int Eflag; /* Client entry option */ 104*150a6952SToomas Soome 105*150a6952SToomas Soome static int quiet; /* Inhibit warnings */ 106*150a6952SToomas Soome static int verbose; /* Display information */ 107*150a6952SToomas Soome 108*150a6952SToomas Soome static const char *tname; /* Temporary output file */ 109*150a6952SToomas Soome static const char *fname; /* Current input file */ 110*150a6952SToomas Soome 111*150a6952SToomas Soome static void cleanup(void); 112*150a6952SToomas Soome static void btxld(const char *); 113*150a6952SToomas Soome static void getbtx(int, struct btx_hdr *); 114*150a6952SToomas Soome static void gethdr(int, struct hdr *); 115*150a6952SToomas Soome static void puthdr(int, struct hdr *); 116*150a6952SToomas Soome static void copy(int, int, size_t, off_t); 117*150a6952SToomas Soome static size_t readx(int, void *, size_t, off_t); 118*150a6952SToomas Soome static void writex(int, const void *, size_t); 119*150a6952SToomas Soome static void seekx(int, off_t); 120*150a6952SToomas Soome static unsigned int optfmt(const char *); 121*150a6952SToomas Soome static uint32_t optaddr(const char *); 122*150a6952SToomas Soome static int optpage(const char *, int); 123*150a6952SToomas Soome static void Warn(const char *, const char *, ...); 124*150a6952SToomas Soome static void usage(void); 125*150a6952SToomas Soome extern void add_version(const char *, char *); 126*150a6952SToomas Soome 127*150a6952SToomas Soome /* 128*150a6952SToomas Soome * A link editor for BTX clients. 129*150a6952SToomas Soome */ 130*150a6952SToomas Soome int 131*150a6952SToomas Soome main(int argc, char *argv[]) 132*150a6952SToomas Soome { 133*150a6952SToomas Soome int c; 134*150a6952SToomas Soome char *version = NULL; 135*150a6952SToomas Soome 136*150a6952SToomas Soome while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:V:W:")) != -1) 137*150a6952SToomas Soome switch (c) { 138*150a6952SToomas Soome case 'q': 139*150a6952SToomas Soome quiet = 1; 140*150a6952SToomas Soome break; 141*150a6952SToomas Soome case 'v': 142*150a6952SToomas Soome verbose = 1; 143*150a6952SToomas Soome break; 144*150a6952SToomas Soome case 'b': 145*150a6952SToomas Soome bname = optarg; 146*150a6952SToomas Soome break; 147*150a6952SToomas Soome case 'E': 148*150a6952SToomas Soome centry = optaddr(optarg); 149*150a6952SToomas Soome Eflag = 1; 150*150a6952SToomas Soome break; 151*150a6952SToomas Soome case 'e': 152*150a6952SToomas Soome lentry = optaddr(optarg); 153*150a6952SToomas Soome break; 154*150a6952SToomas Soome case 'f': 155*150a6952SToomas Soome format = optfmt(optarg); 156*150a6952SToomas Soome break; 157*150a6952SToomas Soome case 'l': 158*150a6952SToomas Soome lname = optarg; 159*150a6952SToomas Soome break; 160*150a6952SToomas Soome case 'o': 161*150a6952SToomas Soome oname = optarg; 162*150a6952SToomas Soome break; 163*150a6952SToomas Soome case 'P': 164*150a6952SToomas Soome ppage = optpage(optarg, 1); 165*150a6952SToomas Soome break; 166*150a6952SToomas Soome case 'V': 167*150a6952SToomas Soome version = optarg; 168*150a6952SToomas Soome break; 169*150a6952SToomas Soome case 'W': 170*150a6952SToomas Soome wpage = optpage(optarg, BTX_MAXCWR); 171*150a6952SToomas Soome break; 172*150a6952SToomas Soome default: 173*150a6952SToomas Soome usage(); 174*150a6952SToomas Soome } 175*150a6952SToomas Soome argc -= optind; 176*150a6952SToomas Soome argv += optind; 177*150a6952SToomas Soome if (argc != 1) 178*150a6952SToomas Soome usage(); 179*150a6952SToomas Soome atexit(cleanup); 180*150a6952SToomas Soome btxld(*argv); 181*150a6952SToomas Soome if (version != NULL) 182*150a6952SToomas Soome add_version(oname, version); 183*150a6952SToomas Soome return 0; 184*150a6952SToomas Soome } 185*150a6952SToomas Soome 186*150a6952SToomas Soome /* 187*150a6952SToomas Soome * Clean up after errors. 188*150a6952SToomas Soome */ 189*150a6952SToomas Soome static void 190*150a6952SToomas Soome cleanup(void) 191*150a6952SToomas Soome { 192*150a6952SToomas Soome if (tname) 193*150a6952SToomas Soome remove(tname); 194*150a6952SToomas Soome } 195*150a6952SToomas Soome 196*150a6952SToomas Soome /* 197*150a6952SToomas Soome * Read the input files; write the output file; display information. 198*150a6952SToomas Soome */ 199*150a6952SToomas Soome static void 200*150a6952SToomas Soome btxld(const char *iname) 201*150a6952SToomas Soome { 202*150a6952SToomas Soome char name[FILENAME_MAX]; 203*150a6952SToomas Soome struct btx_hdr btx, btxle; 204*150a6952SToomas Soome struct hdr ihdr, ohdr; 205*150a6952SToomas Soome unsigned int ldr_size, cwr; 206*150a6952SToomas Soome int fdi[3], fdo, i; 207*150a6952SToomas Soome 208*150a6952SToomas Soome ldr_size = 0; 209*150a6952SToomas Soome 210*150a6952SToomas Soome for (i = I_LDR; i <= I_CLNT; i++) { 211*150a6952SToomas Soome fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 212*150a6952SToomas Soome if ((fdi[i] = open(fname, O_RDONLY)) == -1) 213*150a6952SToomas Soome err(2, "%s", fname); 214*150a6952SToomas Soome switch (i) { 215*150a6952SToomas Soome case I_LDR: 216*150a6952SToomas Soome gethdr(fdi[i], &ihdr); 217*150a6952SToomas Soome if (ihdr.fmt != F_BIN) 218*150a6952SToomas Soome Warn(fname, "Loader format is %s; processing as %s", 219*150a6952SToomas Soome fmtlist[ihdr.fmt], fmtlist[F_BIN]); 220*150a6952SToomas Soome ldr_size = ihdr.size; 221*150a6952SToomas Soome break; 222*150a6952SToomas Soome case I_BTX: 223*150a6952SToomas Soome getbtx(fdi[i], &btx); 224*150a6952SToomas Soome break; 225*150a6952SToomas Soome case I_CLNT: 226*150a6952SToomas Soome gethdr(fdi[i], &ihdr); 227*150a6952SToomas Soome if (ihdr.org && ihdr.org != BTX_PGSIZE) 228*150a6952SToomas Soome Warn(fname, 229*150a6952SToomas Soome "Client origin is 0x%x; expecting 0 or 0x%x", 230*150a6952SToomas Soome ihdr.org, BTX_PGSIZE); 231*150a6952SToomas Soome } 232*150a6952SToomas Soome } 233*150a6952SToomas Soome memset(&ohdr, 0, sizeof(ohdr)); 234*150a6952SToomas Soome ohdr.fmt = format; 235*150a6952SToomas Soome ohdr.text = ldr_size; 236*150a6952SToomas Soome ohdr.data = btx.btx_textsz + ihdr.size; 237*150a6952SToomas Soome ohdr.org = lentry; 238*150a6952SToomas Soome ohdr.entry = lentry; 239*150a6952SToomas Soome cwr = 0; 240*150a6952SToomas Soome if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { 241*150a6952SToomas Soome if (wpage > 0) 242*150a6952SToomas Soome cwr = wpage; 243*150a6952SToomas Soome else { 244*150a6952SToomas Soome cwr = howmany(ihdr.text, BTX_PGSIZE); 245*150a6952SToomas Soome if (cwr > BTX_MAXCWR) 246*150a6952SToomas Soome cwr = BTX_MAXCWR; 247*150a6952SToomas Soome } 248*150a6952SToomas Soome } 249*150a6952SToomas Soome if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { 250*150a6952SToomas Soome btx.btx_flags |= BTX_MAPONE; 251*150a6952SToomas Soome if (!cwr) 252*150a6952SToomas Soome cwr++; 253*150a6952SToomas Soome } 254*150a6952SToomas Soome btx.btx_pgctl -= cwr; 255*150a6952SToomas Soome btx.btx_entry = Eflag ? centry : ihdr.entry; 256*150a6952SToomas Soome if ((size_t)snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) 257*150a6952SToomas Soome errx(2, "%s: Filename too long", oname); 258*150a6952SToomas Soome if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) 259*150a6952SToomas Soome err(2, "%s", name); 260*150a6952SToomas Soome if (!(tname = strdup(name))) 261*150a6952SToomas Soome err(2, NULL); 262*150a6952SToomas Soome puthdr(fdo, &ohdr); 263*150a6952SToomas Soome for (i = I_LDR; i <= I_CLNT; i++) { 264*150a6952SToomas Soome fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 265*150a6952SToomas Soome switch (i) { 266*150a6952SToomas Soome case I_LDR: 267*150a6952SToomas Soome copy(fdi[i], fdo, ldr_size, 0); 268*150a6952SToomas Soome seekx(fdo, ohdr.size += ohdr.text); 269*150a6952SToomas Soome break; 270*150a6952SToomas Soome case I_BTX: 271*150a6952SToomas Soome btxle = btx; 272*150a6952SToomas Soome btxle.btx_pgctl = htole16(btxle.btx_pgctl); 273*150a6952SToomas Soome btxle.btx_textsz = htole16(btxle.btx_textsz); 274*150a6952SToomas Soome btxle.btx_entry = htole32(btxle.btx_entry); 275*150a6952SToomas Soome writex(fdo, &btxle, sizeof(btxle)); 276*150a6952SToomas Soome copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), 277*150a6952SToomas Soome sizeof(btx)); 278*150a6952SToomas Soome break; 279*150a6952SToomas Soome case I_CLNT: 280*150a6952SToomas Soome copy(fdi[i], fdo, ihdr.size, 0); 281*150a6952SToomas Soome if (ftruncate(fdo, ohdr.size += ohdr.data)) 282*150a6952SToomas Soome err(2, "%s", tname); 283*150a6952SToomas Soome } 284*150a6952SToomas Soome if (close(fdi[i])) 285*150a6952SToomas Soome err(2, "%s", fname); 286*150a6952SToomas Soome } 287*150a6952SToomas Soome if (close(fdo)) 288*150a6952SToomas Soome err(2, "%s", tname); 289*150a6952SToomas Soome if (rename(tname, oname)) 290*150a6952SToomas Soome err(2, "%s: Can't rename to %s", tname, oname); 291*150a6952SToomas Soome tname = NULL; 292*150a6952SToomas Soome if (verbose) { 293*150a6952SToomas Soome printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, 294*150a6952SToomas Soome BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * 295*150a6952SToomas Soome BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), 296*150a6952SToomas Soome BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / 297*150a6952SToomas Soome BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); 298*150a6952SToomas Soome printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, 299*150a6952SToomas Soome ihdr.data, ihdr.bss, ihdr.entry); 300*150a6952SToomas Soome printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, 301*150a6952SToomas Soome ohdr.data, ohdr.org, ohdr.entry); 302*150a6952SToomas Soome } 303*150a6952SToomas Soome } 304*150a6952SToomas Soome 305*150a6952SToomas Soome /* 306*150a6952SToomas Soome * Read BTX file header. 307*150a6952SToomas Soome */ 308*150a6952SToomas Soome static void 309*150a6952SToomas Soome getbtx(int fd, struct btx_hdr * btx) 310*150a6952SToomas Soome { 311*150a6952SToomas Soome if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || 312*150a6952SToomas Soome btx->btx_magic[0] != BTX_MAG0 || 313*150a6952SToomas Soome btx->btx_magic[1] != BTX_MAG1 || 314*150a6952SToomas Soome btx->btx_magic[2] != BTX_MAG2) 315*150a6952SToomas Soome errx(1, "%s: Not a BTX kernel", fname); 316*150a6952SToomas Soome btx->btx_pgctl = le16toh(btx->btx_pgctl); 317*150a6952SToomas Soome btx->btx_textsz = le16toh(btx->btx_textsz); 318*150a6952SToomas Soome btx->btx_entry = le32toh(btx->btx_entry); 319*150a6952SToomas Soome } 320*150a6952SToomas Soome 321*150a6952SToomas Soome /* 322*150a6952SToomas Soome * Get file size and read a.out or ELF header. 323*150a6952SToomas Soome */ 324*150a6952SToomas Soome static void 325*150a6952SToomas Soome gethdr(int fd, struct hdr *hdr) 326*150a6952SToomas Soome { 327*150a6952SToomas Soome struct stat sb; 328*150a6952SToomas Soome const struct exec *ex; 329*150a6952SToomas Soome const Elf32_Ehdr *ee; 330*150a6952SToomas Soome const Elf32_Phdr *ep; 331*150a6952SToomas Soome void *p; 332*150a6952SToomas Soome unsigned int fmt, x, n, i; 333*150a6952SToomas Soome 334*150a6952SToomas Soome memset(hdr, 0, sizeof(*hdr)); 335*150a6952SToomas Soome if (fstat(fd, &sb)) 336*150a6952SToomas Soome err(2, "%s", fname); 337*150a6952SToomas Soome if (sb.st_size > MAXU32) 338*150a6952SToomas Soome errx(1, "%s: Too big", fname); 339*150a6952SToomas Soome hdr->size = sb.st_size; 340*150a6952SToomas Soome if (!hdr->size) 341*150a6952SToomas Soome return; 342*150a6952SToomas Soome if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 343*150a6952SToomas Soome 0)) == MAP_FAILED) 344*150a6952SToomas Soome err(2, "%s", fname); 345*150a6952SToomas Soome for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) 346*150a6952SToomas Soome switch (fmt) { 347*150a6952SToomas Soome case F_AOUT: 348*150a6952SToomas Soome ex = p; 349*150a6952SToomas Soome if (hdr->size >= sizeof(struct exec) && !N_BADMAG(*ex)) { 350*150a6952SToomas Soome hdr->fmt = fmt; 351*150a6952SToomas Soome x = N_GETMAGIC(*ex); 352*150a6952SToomas Soome if (x == OMAGIC || x == NMAGIC) { 353*150a6952SToomas Soome if (x == NMAGIC) 354*150a6952SToomas Soome Warn(fname, "Treating %s NMAGIC as OMAGIC", 355*150a6952SToomas Soome fmtlist[fmt]); 356*150a6952SToomas Soome hdr->flags |= IMPURE; 357*150a6952SToomas Soome } 358*150a6952SToomas Soome hdr->text = le32toh(ex->a_text); 359*150a6952SToomas Soome hdr->data = le32toh(ex->a_data); 360*150a6952SToomas Soome hdr->bss = le32toh(ex->a_bss); 361*150a6952SToomas Soome hdr->entry = le32toh(ex->a_entry); 362*150a6952SToomas Soome if (le32toh(ex->a_entry) >= BTX_PGSIZE) 363*150a6952SToomas Soome hdr->org = BTX_PGSIZE; 364*150a6952SToomas Soome } 365*150a6952SToomas Soome break; 366*150a6952SToomas Soome case F_ELF: 367*150a6952SToomas Soome ee = p; 368*150a6952SToomas Soome if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { 369*150a6952SToomas Soome hdr->fmt = fmt; 370*150a6952SToomas Soome for (n = i = 0; i < le16toh(ee->e_phnum); i++) { 371*150a6952SToomas Soome ep = (void *)((uint8_t *)p + le32toh(ee->e_phoff) + 372*150a6952SToomas Soome le16toh(ee->e_phentsize) * i); 373*150a6952SToomas Soome if (le32toh(ep->p_type) == PT_LOAD) 374*150a6952SToomas Soome switch (n++) { 375*150a6952SToomas Soome case 0: 376*150a6952SToomas Soome hdr->text = le32toh(ep->p_filesz); 377*150a6952SToomas Soome hdr->org = le32toh(ep->p_paddr); 378*150a6952SToomas Soome if (le32toh(ep->p_flags) & PF_W) 379*150a6952SToomas Soome hdr->flags |= IMPURE; 380*150a6952SToomas Soome break; 381*150a6952SToomas Soome case 1: 382*150a6952SToomas Soome hdr->data = le32toh(ep->p_filesz); 383*150a6952SToomas Soome hdr->bss = le32toh(ep->p_memsz) - 384*150a6952SToomas Soome le32toh(ep->p_filesz); 385*150a6952SToomas Soome break; 386*150a6952SToomas Soome case 2: 387*150a6952SToomas Soome Warn(fname, 388*150a6952SToomas Soome "Ignoring extra %s PT_LOAD segments", 389*150a6952SToomas Soome fmtlist[fmt]); 390*150a6952SToomas Soome } 391*150a6952SToomas Soome } 392*150a6952SToomas Soome hdr->entry = le32toh(ee->e_entry); 393*150a6952SToomas Soome } 394*150a6952SToomas Soome } 395*150a6952SToomas Soome if (munmap(p, hdr->size)) 396*150a6952SToomas Soome err(2, "%s", fname); 397*150a6952SToomas Soome } 398*150a6952SToomas Soome 399*150a6952SToomas Soome /* 400*150a6952SToomas Soome * Write a.out or ELF header. 401*150a6952SToomas Soome */ 402*150a6952SToomas Soome static void 403*150a6952SToomas Soome puthdr(int fd, struct hdr *hdr) 404*150a6952SToomas Soome { 405*150a6952SToomas Soome struct exec ex; 406*150a6952SToomas Soome struct elfh eh; 407*150a6952SToomas Soome 408*150a6952SToomas Soome switch (hdr->fmt) { 409*150a6952SToomas Soome case F_AOUT: 410*150a6952SToomas Soome memset(&ex, 0, sizeof(ex)); 411*150a6952SToomas Soome N_SETMAGIC(ex, ZMAGIC, MID_I386, 0); 412*150a6952SToomas Soome hdr->text = N_ALIGN(ex, hdr->text); 413*150a6952SToomas Soome ex.a_text = htole32(hdr->text); 414*150a6952SToomas Soome hdr->data = N_ALIGN(ex, hdr->data); 415*150a6952SToomas Soome ex.a_data = htole32(hdr->data); 416*150a6952SToomas Soome ex.a_entry = htole32(hdr->entry); 417*150a6952SToomas Soome writex(fd, &ex, sizeof(ex)); 418*150a6952SToomas Soome hdr->size = N_ALIGN(ex, sizeof(ex)); 419*150a6952SToomas Soome seekx(fd, hdr->size); 420*150a6952SToomas Soome break; 421*150a6952SToomas Soome case F_ELF: 422*150a6952SToomas Soome eh = elfhdr; 423*150a6952SToomas Soome eh.e.e_entry = htole32(hdr->entry); 424*150a6952SToomas Soome eh.p[0].p_vaddr = eh.p[0].p_paddr = htole32(hdr->org); 425*150a6952SToomas Soome eh.p[0].p_filesz = eh.p[0].p_memsz = htole32(hdr->text); 426*150a6952SToomas Soome eh.p[1].p_offset = htole32(le32toh(eh.p[0].p_offset) + 427*150a6952SToomas Soome le32toh(eh.p[0].p_filesz)); 428*150a6952SToomas Soome eh.p[1].p_vaddr = eh.p[1].p_paddr = 429*150a6952SToomas Soome htole32(align(le32toh(eh.p[0].p_paddr) + le32toh(eh.p[0].p_memsz), 430*150a6952SToomas Soome 4096)); 431*150a6952SToomas Soome eh.p[1].p_filesz = eh.p[1].p_memsz = htole32(hdr->data); 432*150a6952SToomas Soome eh.sh[2].sh_addr = eh.p[0].p_vaddr; 433*150a6952SToomas Soome eh.sh[2].sh_offset = eh.p[0].p_offset; 434*150a6952SToomas Soome eh.sh[2].sh_size = eh.p[0].p_filesz; 435*150a6952SToomas Soome eh.sh[3].sh_addr = eh.p[1].p_vaddr; 436*150a6952SToomas Soome eh.sh[3].sh_offset = eh.p[1].p_offset; 437*150a6952SToomas Soome eh.sh[3].sh_size = eh.p[1].p_filesz; 438*150a6952SToomas Soome writex(fd, &eh, sizeof(eh)); 439*150a6952SToomas Soome hdr->size = sizeof(eh); 440*150a6952SToomas Soome } 441*150a6952SToomas Soome } 442*150a6952SToomas Soome 443*150a6952SToomas Soome /* 444*150a6952SToomas Soome * Safe copy from input file to output file. 445*150a6952SToomas Soome */ 446*150a6952SToomas Soome static void 447*150a6952SToomas Soome copy(int fdi, int fdo, size_t nbyte, off_t offset) 448*150a6952SToomas Soome { 449*150a6952SToomas Soome char buf[8192]; 450*150a6952SToomas Soome size_t n; 451*150a6952SToomas Soome 452*150a6952SToomas Soome while (nbyte) { 453*150a6952SToomas Soome if ((n = sizeof(buf)) > nbyte) 454*150a6952SToomas Soome n = nbyte; 455*150a6952SToomas Soome if (readx(fdi, buf, n, offset) != n) 456*150a6952SToomas Soome errx(2, "%s: Short read", fname); 457*150a6952SToomas Soome writex(fdo, buf, n); 458*150a6952SToomas Soome nbyte -= n; 459*150a6952SToomas Soome offset = -1; 460*150a6952SToomas Soome } 461*150a6952SToomas Soome } 462*150a6952SToomas Soome 463*150a6952SToomas Soome /* 464*150a6952SToomas Soome * Safe read from input file. 465*150a6952SToomas Soome */ 466*150a6952SToomas Soome static size_t 467*150a6952SToomas Soome readx(int fd, void *buf, size_t nbyte, off_t offset) 468*150a6952SToomas Soome { 469*150a6952SToomas Soome ssize_t n; 470*150a6952SToomas Soome 471*150a6952SToomas Soome if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) 472*150a6952SToomas Soome err(2, "%s", fname); 473*150a6952SToomas Soome if ((n = read(fd, buf, nbyte)) == -1) 474*150a6952SToomas Soome err(2, "%s", fname); 475*150a6952SToomas Soome return n; 476*150a6952SToomas Soome } 477*150a6952SToomas Soome 478*150a6952SToomas Soome /* 479*150a6952SToomas Soome * Safe write to output file. 480*150a6952SToomas Soome */ 481*150a6952SToomas Soome static void 482*150a6952SToomas Soome writex(int fd, const void *buf, size_t nbyte) 483*150a6952SToomas Soome { 484*150a6952SToomas Soome ssize_t n; 485*150a6952SToomas Soome 486*150a6952SToomas Soome if ((n = write(fd, buf, nbyte)) == -1) 487*150a6952SToomas Soome err(2, "%s", tname); 488*150a6952SToomas Soome if ((size_t)n != nbyte) 489*150a6952SToomas Soome errx(2, "%s: Short write", tname); 490*150a6952SToomas Soome } 491*150a6952SToomas Soome 492*150a6952SToomas Soome /* 493*150a6952SToomas Soome * Safe seek in output file. 494*150a6952SToomas Soome */ 495*150a6952SToomas Soome static void 496*150a6952SToomas Soome seekx(int fd, off_t offset) 497*150a6952SToomas Soome { 498*150a6952SToomas Soome if (lseek(fd, offset, SEEK_SET) != offset) 499*150a6952SToomas Soome err(2, "%s", tname); 500*150a6952SToomas Soome } 501*150a6952SToomas Soome 502*150a6952SToomas Soome /* 503*150a6952SToomas Soome * Convert an option argument to a format code. 504*150a6952SToomas Soome */ 505*150a6952SToomas Soome static unsigned int 506*150a6952SToomas Soome optfmt(const char *arg) 507*150a6952SToomas Soome { 508*150a6952SToomas Soome unsigned int i; 509*150a6952SToomas Soome 510*150a6952SToomas Soome for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); 511*150a6952SToomas Soome if (i == F_CNT) 512*150a6952SToomas Soome errx(1, "%s: Unknown format", arg); 513*150a6952SToomas Soome return i; 514*150a6952SToomas Soome } 515*150a6952SToomas Soome 516*150a6952SToomas Soome /* 517*150a6952SToomas Soome * Convert an option argument to an address. 518*150a6952SToomas Soome */ 519*150a6952SToomas Soome static uint32_t 520*150a6952SToomas Soome optaddr(const char *arg) 521*150a6952SToomas Soome { 522*150a6952SToomas Soome char *s; 523*150a6952SToomas Soome unsigned long x; 524*150a6952SToomas Soome 525*150a6952SToomas Soome errno = 0; 526*150a6952SToomas Soome x = strtoul(arg, &s, 0); 527*150a6952SToomas Soome if (errno || !*arg || *s || x > MAXU32) 528*150a6952SToomas Soome errx(1, "%s: Illegal address", arg); 529*150a6952SToomas Soome return x; 530*150a6952SToomas Soome } 531*150a6952SToomas Soome 532*150a6952SToomas Soome /* 533*150a6952SToomas Soome * Convert an option argument to a page number. 534*150a6952SToomas Soome */ 535*150a6952SToomas Soome static int 536*150a6952SToomas Soome optpage(const char *arg, int hi) 537*150a6952SToomas Soome { 538*150a6952SToomas Soome char *s; 539*150a6952SToomas Soome long x; 540*150a6952SToomas Soome 541*150a6952SToomas Soome errno = 0; 542*150a6952SToomas Soome x = strtol(arg, &s, 0); 543*150a6952SToomas Soome if (errno || !*arg || *s || x < 0 || x > hi) 544*150a6952SToomas Soome errx(1, "%s: Illegal page number", arg); 545*150a6952SToomas Soome return x; 546*150a6952SToomas Soome } 547*150a6952SToomas Soome 548*150a6952SToomas Soome /* 549*150a6952SToomas Soome * Display a warning. 550*150a6952SToomas Soome */ 551*150a6952SToomas Soome static void 552*150a6952SToomas Soome Warn(const char *locus, const char *fmt, ...) 553*150a6952SToomas Soome { 554*150a6952SToomas Soome va_list ap; 555*150a6952SToomas Soome char *s; 556*150a6952SToomas Soome 557*150a6952SToomas Soome if (!quiet) { 558*150a6952SToomas Soome asprintf(&s, "%s: Warning: %s", locus, fmt); 559*150a6952SToomas Soome va_start(ap, fmt); 560*150a6952SToomas Soome vwarnx(s, ap); 561*150a6952SToomas Soome va_end(ap); 562*150a6952SToomas Soome free(s); 563*150a6952SToomas Soome } 564*150a6952SToomas Soome } 565*150a6952SToomas Soome 566*150a6952SToomas Soome /* 567*150a6952SToomas Soome * Display usage information. 568*150a6952SToomas Soome */ 569*150a6952SToomas Soome static void 570*150a6952SToomas Soome usage(void) 571*150a6952SToomas Soome { 572*150a6952SToomas Soome fprintf(stderr, "%s\n%s\n", 573*150a6952SToomas Soome "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", 574*150a6952SToomas Soome " [-l file] [-o filename] [-P page] [-W page] file"); 575*150a6952SToomas Soome exit(1); 576*150a6952SToomas Soome } 577