10cc5983cSToomas Soome /* 20cc5983cSToomas Soome * Copyright (c) 1998 Robert Nordier 30cc5983cSToomas Soome * All rights reserved. 40cc5983cSToomas Soome * 50cc5983cSToomas Soome * Redistribution and use in source and binary forms, with or without 60cc5983cSToomas Soome * modification, are permitted provided that the following conditions 70cc5983cSToomas Soome * are met: 80cc5983cSToomas Soome * 1. Redistributions of source code must retain the above copyright 90cc5983cSToomas Soome * notice, this list of conditions and the following disclaimer. 100cc5983cSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 110cc5983cSToomas Soome * notice, this list of conditions and the following disclaimer in the 120cc5983cSToomas Soome * documentation and/or other materials provided with the distribution. 130cc5983cSToomas Soome * 140cc5983cSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 150cc5983cSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160cc5983cSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 170cc5983cSToomas Soome * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 180cc5983cSToomas Soome * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 190cc5983cSToomas Soome * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 200cc5983cSToomas Soome * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 210cc5983cSToomas Soome * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 220cc5983cSToomas Soome * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 230cc5983cSToomas Soome * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 240cc5983cSToomas Soome * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 250cc5983cSToomas Soome */ 260cc5983cSToomas Soome 270cc5983cSToomas Soome #include <sys/param.h> 280cc5983cSToomas Soome #include "endian.h" 290cc5983cSToomas Soome #include <sys/stat.h> 300cc5983cSToomas Soome #include <sys/mman.h> 310cc5983cSToomas Soome 320cc5983cSToomas Soome /* XXX make this work as an i386/amd64 cross-tool */ 330cc5983cSToomas Soome #undef __LDPGSZ 340cc5983cSToomas Soome #define __LDPGSZ 4096 350cc5983cSToomas Soome 360cc5983cSToomas Soome #include <netinet/in.h> 370cc5983cSToomas Soome 380cc5983cSToomas Soome #include "imgact_aout.h" 390cc5983cSToomas Soome #include <err.h> 400cc5983cSToomas Soome #include <errno.h> 410cc5983cSToomas Soome #include <fcntl.h> 420cc5983cSToomas Soome #include <stdarg.h> 430cc5983cSToomas Soome #include <stdio.h> 440cc5983cSToomas Soome #include <stdlib.h> 450cc5983cSToomas Soome #include <string.h> 460cc5983cSToomas Soome #include <unistd.h> 470cc5983cSToomas Soome 480cc5983cSToomas Soome #include "btx.h" 490cc5983cSToomas Soome #include "elfh.h" 500cc5983cSToomas Soome 510cc5983cSToomas Soome #define BTX_PATH "/sys/boot/i386/btx" 520cc5983cSToomas Soome 530cc5983cSToomas Soome #define I_LDR 0 /* BTX loader */ 540cc5983cSToomas Soome #define I_BTX 1 /* BTX kernel */ 550cc5983cSToomas Soome #define I_CLNT 2 /* Client program */ 560cc5983cSToomas Soome 570cc5983cSToomas Soome #define F_BIN 0 /* Binary */ 580cc5983cSToomas Soome #define F_AOUT 1 /* ZMAGIC a.out */ 590cc5983cSToomas Soome #define F_ELF 2 /* 32-bit ELF */ 600cc5983cSToomas Soome #define F_CNT 3 /* Number of formats */ 610cc5983cSToomas Soome 620cc5983cSToomas Soome #define IMPURE 1 /* Writable text */ 630cc5983cSToomas Soome #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ 640cc5983cSToomas Soome 650cc5983cSToomas Soome #define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) 660cc5983cSToomas Soome 670cc5983cSToomas Soome struct hdr { 680cc5983cSToomas Soome uint32_t fmt; /* Format */ 690cc5983cSToomas Soome uint32_t flags; /* Bit flags */ 700cc5983cSToomas Soome uint32_t size; /* Size of file */ 710cc5983cSToomas Soome uint32_t text; /* Size of text segment */ 720cc5983cSToomas Soome uint32_t data; /* Size of data segment */ 730cc5983cSToomas Soome uint32_t bss; /* Size of bss segment */ 740cc5983cSToomas Soome uint32_t org; /* Program origin */ 750cc5983cSToomas Soome uint32_t entry; /* Program entry point */ 760cc5983cSToomas Soome }; 770cc5983cSToomas Soome 780cc5983cSToomas Soome static const char *const fmtlist[] = {"bin", "aout", "elf"}; 790cc5983cSToomas Soome 800cc5983cSToomas Soome static const char binfo[] = 810cc5983cSToomas Soome "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " 820cc5983cSToomas Soome "pgctl=%x:%x\n"; 830cc5983cSToomas Soome static const char cinfo[] = 840cc5983cSToomas Soome "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; 850cc5983cSToomas Soome static const char oinfo[] = 860cc5983cSToomas Soome "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; 870cc5983cSToomas Soome 88*b960a270SToomas Soome /* BTX loader and kernel is only provided from command line */ 89*b960a270SToomas Soome static const char *lname = NULL; 90*b960a270SToomas Soome static const char *bname = NULL; 910cc5983cSToomas Soome static const char *oname = 920cc5983cSToomas Soome "a.out"; /* Output filename */ 930cc5983cSToomas Soome 940cc5983cSToomas Soome static int ppage = -1; /* First page present */ 950cc5983cSToomas Soome static int wpage = -1; /* First page writable */ 960cc5983cSToomas Soome 970cc5983cSToomas Soome static unsigned int format; /* Output format */ 980cc5983cSToomas Soome 990cc5983cSToomas Soome static uint32_t centry; /* Client entry address */ 1000cc5983cSToomas Soome static uint32_t lentry; /* Loader entry address */ 1010cc5983cSToomas Soome 1020cc5983cSToomas Soome static int Eflag; /* Client entry option */ 1030cc5983cSToomas Soome 1040cc5983cSToomas Soome static int quiet; /* Inhibit warnings */ 1050cc5983cSToomas Soome static int verbose; /* Display information */ 1060cc5983cSToomas Soome 1070cc5983cSToomas Soome static const char *tname; /* Temporary output file */ 1080cc5983cSToomas Soome static const char *fname; /* Current input file */ 1090cc5983cSToomas Soome 1100cc5983cSToomas Soome static void cleanup(void); 1110cc5983cSToomas Soome static void btxld(const char *); 1120cc5983cSToomas Soome static void getbtx(int, struct btx_hdr *); 1130cc5983cSToomas Soome static void gethdr(int, struct hdr *); 1140cc5983cSToomas Soome static void puthdr(int, struct hdr *); 1150cc5983cSToomas Soome static void copy(int, int, size_t, off_t); 1160cc5983cSToomas Soome static size_t readx(int, void *, size_t, off_t); 1170cc5983cSToomas Soome static void writex(int, const void *, size_t); 1180cc5983cSToomas Soome static void seekx(int, off_t); 1190cc5983cSToomas Soome static unsigned int optfmt(const char *); 1200cc5983cSToomas Soome static uint32_t optaddr(const char *); 1210cc5983cSToomas Soome static int optpage(const char *, int); 1220cc5983cSToomas Soome static void Warn(const char *, const char *, ...); 1230cc5983cSToomas Soome static void usage(void); 1240cc5983cSToomas Soome extern void add_version(const char *, char *); 1250cc5983cSToomas Soome 1260cc5983cSToomas Soome /* 1270cc5983cSToomas Soome * A link editor for BTX clients. 1280cc5983cSToomas Soome */ 1290cc5983cSToomas Soome int 1300cc5983cSToomas Soome main(int argc, char *argv[]) 1310cc5983cSToomas Soome { 1320cc5983cSToomas Soome int c; 1330cc5983cSToomas Soome char *version = NULL; 1340cc5983cSToomas Soome 1350cc5983cSToomas Soome while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:V:W:")) != -1) 1360cc5983cSToomas Soome switch (c) { 1370cc5983cSToomas Soome case 'q': 1380cc5983cSToomas Soome quiet = 1; 1390cc5983cSToomas Soome break; 1400cc5983cSToomas Soome case 'v': 1410cc5983cSToomas Soome verbose = 1; 1420cc5983cSToomas Soome break; 1430cc5983cSToomas Soome case 'b': 1440cc5983cSToomas Soome bname = optarg; 1450cc5983cSToomas Soome break; 1460cc5983cSToomas Soome case 'E': 1470cc5983cSToomas Soome centry = optaddr(optarg); 1480cc5983cSToomas Soome Eflag = 1; 1490cc5983cSToomas Soome break; 1500cc5983cSToomas Soome case 'e': 1510cc5983cSToomas Soome lentry = optaddr(optarg); 1520cc5983cSToomas Soome break; 1530cc5983cSToomas Soome case 'f': 1540cc5983cSToomas Soome format = optfmt(optarg); 1550cc5983cSToomas Soome break; 1560cc5983cSToomas Soome case 'l': 1570cc5983cSToomas Soome lname = optarg; 1580cc5983cSToomas Soome break; 1590cc5983cSToomas Soome case 'o': 1600cc5983cSToomas Soome oname = optarg; 1610cc5983cSToomas Soome break; 1620cc5983cSToomas Soome case 'P': 1630cc5983cSToomas Soome ppage = optpage(optarg, 1); 1640cc5983cSToomas Soome break; 1650cc5983cSToomas Soome case 'V': 1660cc5983cSToomas Soome version = optarg; 1670cc5983cSToomas Soome break; 1680cc5983cSToomas Soome case 'W': 1690cc5983cSToomas Soome wpage = optpage(optarg, BTX_MAXCWR); 1700cc5983cSToomas Soome break; 1710cc5983cSToomas Soome default: 1720cc5983cSToomas Soome usage(); 1730cc5983cSToomas Soome } 1740cc5983cSToomas Soome argc -= optind; 1750cc5983cSToomas Soome argv += optind; 1760cc5983cSToomas Soome if (argc != 1) 1770cc5983cSToomas Soome usage(); 1780cc5983cSToomas Soome atexit(cleanup); 179*b960a270SToomas Soome if (lname != NULL && bname != NULL) 180*b960a270SToomas Soome btxld(*argv); 1810cc5983cSToomas Soome if (version != NULL) 1820cc5983cSToomas Soome add_version(oname, version); 1830cc5983cSToomas Soome return 0; 1840cc5983cSToomas Soome } 1850cc5983cSToomas Soome 1860cc5983cSToomas Soome /* 1870cc5983cSToomas Soome * Clean up after errors. 1880cc5983cSToomas Soome */ 1890cc5983cSToomas Soome static void 1900cc5983cSToomas Soome cleanup(void) 1910cc5983cSToomas Soome { 1920cc5983cSToomas Soome if (tname) 1930cc5983cSToomas Soome remove(tname); 1940cc5983cSToomas Soome } 1950cc5983cSToomas Soome 1960cc5983cSToomas Soome /* 1970cc5983cSToomas Soome * Read the input files; write the output file; display information. 1980cc5983cSToomas Soome */ 1990cc5983cSToomas Soome static void 2000cc5983cSToomas Soome btxld(const char *iname) 2010cc5983cSToomas Soome { 2020cc5983cSToomas Soome char name[FILENAME_MAX]; 2030cc5983cSToomas Soome struct btx_hdr btx, btxle; 2040cc5983cSToomas Soome struct hdr ihdr, ohdr; 2050cc5983cSToomas Soome unsigned int ldr_size, cwr; 2060cc5983cSToomas Soome int fdi[3], fdo, i; 2070cc5983cSToomas Soome 2080cc5983cSToomas Soome ldr_size = 0; 2090cc5983cSToomas Soome 2100cc5983cSToomas Soome for (i = I_LDR; i <= I_CLNT; i++) { 2110cc5983cSToomas Soome fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2120cc5983cSToomas Soome if ((fdi[i] = open(fname, O_RDONLY)) == -1) 2130cc5983cSToomas Soome err(2, "%s", fname); 2140cc5983cSToomas Soome switch (i) { 2150cc5983cSToomas Soome case I_LDR: 2160cc5983cSToomas Soome gethdr(fdi[i], &ihdr); 2170cc5983cSToomas Soome if (ihdr.fmt != F_BIN) 2180cc5983cSToomas Soome Warn(fname, "Loader format is %s; processing as %s", 2190cc5983cSToomas Soome fmtlist[ihdr.fmt], fmtlist[F_BIN]); 2200cc5983cSToomas Soome ldr_size = ihdr.size; 2210cc5983cSToomas Soome break; 2220cc5983cSToomas Soome case I_BTX: 2230cc5983cSToomas Soome getbtx(fdi[i], &btx); 2240cc5983cSToomas Soome break; 2250cc5983cSToomas Soome case I_CLNT: 2260cc5983cSToomas Soome gethdr(fdi[i], &ihdr); 2270cc5983cSToomas Soome if (ihdr.org && ihdr.org != BTX_PGSIZE) 2280cc5983cSToomas Soome Warn(fname, 2290cc5983cSToomas Soome "Client origin is 0x%x; expecting 0 or 0x%x", 2300cc5983cSToomas Soome ihdr.org, BTX_PGSIZE); 2310cc5983cSToomas Soome } 2320cc5983cSToomas Soome } 2330cc5983cSToomas Soome memset(&ohdr, 0, sizeof(ohdr)); 2340cc5983cSToomas Soome ohdr.fmt = format; 2350cc5983cSToomas Soome ohdr.text = ldr_size; 2360cc5983cSToomas Soome ohdr.data = btx.btx_textsz + ihdr.size; 2370cc5983cSToomas Soome ohdr.org = lentry; 2380cc5983cSToomas Soome ohdr.entry = lentry; 2390cc5983cSToomas Soome cwr = 0; 2400cc5983cSToomas Soome if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { 2410cc5983cSToomas Soome if (wpage > 0) 2420cc5983cSToomas Soome cwr = wpage; 2430cc5983cSToomas Soome else { 2440cc5983cSToomas Soome cwr = howmany(ihdr.text, BTX_PGSIZE); 2450cc5983cSToomas Soome if (cwr > BTX_MAXCWR) 2460cc5983cSToomas Soome cwr = BTX_MAXCWR; 2470cc5983cSToomas Soome } 2480cc5983cSToomas Soome } 2490cc5983cSToomas Soome if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { 2500cc5983cSToomas Soome btx.btx_flags |= BTX_MAPONE; 2510cc5983cSToomas Soome if (!cwr) 2520cc5983cSToomas Soome cwr++; 2530cc5983cSToomas Soome } 2540cc5983cSToomas Soome btx.btx_pgctl -= cwr; 2550cc5983cSToomas Soome btx.btx_entry = Eflag ? centry : ihdr.entry; 2560cc5983cSToomas Soome if ((size_t)snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) 2570cc5983cSToomas Soome errx(2, "%s: Filename too long", oname); 2580cc5983cSToomas Soome if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) 2590cc5983cSToomas Soome err(2, "%s", name); 2600cc5983cSToomas Soome if (!(tname = strdup(name))) 2610cc5983cSToomas Soome err(2, NULL); 2620cc5983cSToomas Soome puthdr(fdo, &ohdr); 2630cc5983cSToomas Soome for (i = I_LDR; i <= I_CLNT; i++) { 2640cc5983cSToomas Soome fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2650cc5983cSToomas Soome switch (i) { 2660cc5983cSToomas Soome case I_LDR: 2670cc5983cSToomas Soome copy(fdi[i], fdo, ldr_size, 0); 2680cc5983cSToomas Soome seekx(fdo, ohdr.size += ohdr.text); 2690cc5983cSToomas Soome break; 2700cc5983cSToomas Soome case I_BTX: 2710cc5983cSToomas Soome btxle = btx; 2720cc5983cSToomas Soome btxle.btx_pgctl = htole16(btxle.btx_pgctl); 2730cc5983cSToomas Soome btxle.btx_textsz = htole16(btxle.btx_textsz); 2740cc5983cSToomas Soome btxle.btx_entry = htole32(btxle.btx_entry); 2750cc5983cSToomas Soome writex(fdo, &btxle, sizeof(btxle)); 2760cc5983cSToomas Soome copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), 2770cc5983cSToomas Soome sizeof(btx)); 2780cc5983cSToomas Soome break; 2790cc5983cSToomas Soome case I_CLNT: 2800cc5983cSToomas Soome copy(fdi[i], fdo, ihdr.size, 0); 2810cc5983cSToomas Soome if (ftruncate(fdo, ohdr.size += ohdr.data)) 2820cc5983cSToomas Soome err(2, "%s", tname); 2830cc5983cSToomas Soome } 2840cc5983cSToomas Soome if (close(fdi[i])) 2850cc5983cSToomas Soome err(2, "%s", fname); 2860cc5983cSToomas Soome } 2870cc5983cSToomas Soome if (close(fdo)) 2880cc5983cSToomas Soome err(2, "%s", tname); 2890cc5983cSToomas Soome if (rename(tname, oname)) 2900cc5983cSToomas Soome err(2, "%s: Can't rename to %s", tname, oname); 2910cc5983cSToomas Soome tname = NULL; 2920cc5983cSToomas Soome if (verbose) { 2930cc5983cSToomas Soome printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, 2940cc5983cSToomas Soome BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * 2950cc5983cSToomas Soome BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), 2960cc5983cSToomas Soome BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / 2970cc5983cSToomas Soome BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); 2980cc5983cSToomas Soome printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, 2990cc5983cSToomas Soome ihdr.data, ihdr.bss, ihdr.entry); 3000cc5983cSToomas Soome printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, 3010cc5983cSToomas Soome ohdr.data, ohdr.org, ohdr.entry); 3020cc5983cSToomas Soome } 3030cc5983cSToomas Soome } 3040cc5983cSToomas Soome 3050cc5983cSToomas Soome /* 3060cc5983cSToomas Soome * Read BTX file header. 3070cc5983cSToomas Soome */ 3080cc5983cSToomas Soome static void 3090cc5983cSToomas Soome getbtx(int fd, struct btx_hdr * btx) 3100cc5983cSToomas Soome { 3110cc5983cSToomas Soome if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || 3120cc5983cSToomas Soome btx->btx_magic[0] != BTX_MAG0 || 3130cc5983cSToomas Soome btx->btx_magic[1] != BTX_MAG1 || 3140cc5983cSToomas Soome btx->btx_magic[2] != BTX_MAG2) 3150cc5983cSToomas Soome errx(1, "%s: Not a BTX kernel", fname); 3160cc5983cSToomas Soome btx->btx_pgctl = le16toh(btx->btx_pgctl); 3170cc5983cSToomas Soome btx->btx_textsz = le16toh(btx->btx_textsz); 3180cc5983cSToomas Soome btx->btx_entry = le32toh(btx->btx_entry); 3190cc5983cSToomas Soome } 3200cc5983cSToomas Soome 3210cc5983cSToomas Soome /* 3220cc5983cSToomas Soome * Get file size and read a.out or ELF header. 3230cc5983cSToomas Soome */ 3240cc5983cSToomas Soome static void 3250cc5983cSToomas Soome gethdr(int fd, struct hdr *hdr) 3260cc5983cSToomas Soome { 3270cc5983cSToomas Soome struct stat sb; 3280cc5983cSToomas Soome const struct exec *ex; 3290cc5983cSToomas Soome const Elf32_Ehdr *ee; 3300cc5983cSToomas Soome const Elf32_Phdr *ep; 3310cc5983cSToomas Soome void *p; 3320cc5983cSToomas Soome unsigned int fmt, x, n, i; 3330cc5983cSToomas Soome 3340cc5983cSToomas Soome memset(hdr, 0, sizeof(*hdr)); 3350cc5983cSToomas Soome if (fstat(fd, &sb)) 3360cc5983cSToomas Soome err(2, "%s", fname); 3370cc5983cSToomas Soome if (sb.st_size > MAXU32) 3380cc5983cSToomas Soome errx(1, "%s: Too big", fname); 3390cc5983cSToomas Soome hdr->size = sb.st_size; 3400cc5983cSToomas Soome if (!hdr->size) 3410cc5983cSToomas Soome return; 3420cc5983cSToomas Soome if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 3430cc5983cSToomas Soome 0)) == MAP_FAILED) 3440cc5983cSToomas Soome err(2, "%s", fname); 3450cc5983cSToomas Soome for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) 3460cc5983cSToomas Soome switch (fmt) { 3470cc5983cSToomas Soome case F_AOUT: 3480cc5983cSToomas Soome ex = p; 3490cc5983cSToomas Soome if (hdr->size >= sizeof(struct exec) && !N_BADMAG(*ex)) { 3500cc5983cSToomas Soome hdr->fmt = fmt; 3510cc5983cSToomas Soome x = N_GETMAGIC(*ex); 3520cc5983cSToomas Soome if (x == OMAGIC || x == NMAGIC) { 3530cc5983cSToomas Soome if (x == NMAGIC) 3540cc5983cSToomas Soome Warn(fname, "Treating %s NMAGIC as OMAGIC", 3550cc5983cSToomas Soome fmtlist[fmt]); 3560cc5983cSToomas Soome hdr->flags |= IMPURE; 3570cc5983cSToomas Soome } 3580cc5983cSToomas Soome hdr->text = le32toh(ex->a_text); 3590cc5983cSToomas Soome hdr->data = le32toh(ex->a_data); 3600cc5983cSToomas Soome hdr->bss = le32toh(ex->a_bss); 3610cc5983cSToomas Soome hdr->entry = le32toh(ex->a_entry); 3620cc5983cSToomas Soome if (le32toh(ex->a_entry) >= BTX_PGSIZE) 3630cc5983cSToomas Soome hdr->org = BTX_PGSIZE; 3640cc5983cSToomas Soome } 3650cc5983cSToomas Soome break; 3660cc5983cSToomas Soome case F_ELF: 3670cc5983cSToomas Soome ee = p; 3680cc5983cSToomas Soome if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { 3690cc5983cSToomas Soome hdr->fmt = fmt; 3700cc5983cSToomas Soome for (n = i = 0; i < le16toh(ee->e_phnum); i++) { 3710cc5983cSToomas Soome ep = (void *)((uint8_t *)p + le32toh(ee->e_phoff) + 3720cc5983cSToomas Soome le16toh(ee->e_phentsize) * i); 3730cc5983cSToomas Soome if (le32toh(ep->p_type) == PT_LOAD) 3740cc5983cSToomas Soome switch (n++) { 3750cc5983cSToomas Soome case 0: 3760cc5983cSToomas Soome hdr->text = le32toh(ep->p_filesz); 3770cc5983cSToomas Soome hdr->org = le32toh(ep->p_paddr); 3780cc5983cSToomas Soome if (le32toh(ep->p_flags) & PF_W) 3790cc5983cSToomas Soome hdr->flags |= IMPURE; 3800cc5983cSToomas Soome break; 3810cc5983cSToomas Soome case 1: 3820cc5983cSToomas Soome hdr->data = le32toh(ep->p_filesz); 3830cc5983cSToomas Soome hdr->bss = le32toh(ep->p_memsz) - 3840cc5983cSToomas Soome le32toh(ep->p_filesz); 3850cc5983cSToomas Soome break; 3860cc5983cSToomas Soome case 2: 3870cc5983cSToomas Soome Warn(fname, 3880cc5983cSToomas Soome "Ignoring extra %s PT_LOAD segments", 3890cc5983cSToomas Soome fmtlist[fmt]); 3900cc5983cSToomas Soome } 3910cc5983cSToomas Soome } 3920cc5983cSToomas Soome hdr->entry = le32toh(ee->e_entry); 3930cc5983cSToomas Soome } 3940cc5983cSToomas Soome } 3950cc5983cSToomas Soome if (munmap(p, hdr->size)) 3960cc5983cSToomas Soome err(2, "%s", fname); 3970cc5983cSToomas Soome } 3980cc5983cSToomas Soome 3990cc5983cSToomas Soome /* 4000cc5983cSToomas Soome * Write a.out or ELF header. 4010cc5983cSToomas Soome */ 4020cc5983cSToomas Soome static void 4030cc5983cSToomas Soome puthdr(int fd, struct hdr *hdr) 4040cc5983cSToomas Soome { 4050cc5983cSToomas Soome struct exec ex; 4060cc5983cSToomas Soome struct elfh eh; 4070cc5983cSToomas Soome 4080cc5983cSToomas Soome switch (hdr->fmt) { 4090cc5983cSToomas Soome case F_AOUT: 4100cc5983cSToomas Soome memset(&ex, 0, sizeof(ex)); 4110cc5983cSToomas Soome N_SETMAGIC(ex, ZMAGIC, MID_I386, 0); 4120cc5983cSToomas Soome hdr->text = N_ALIGN(ex, hdr->text); 4130cc5983cSToomas Soome ex.a_text = htole32(hdr->text); 4140cc5983cSToomas Soome hdr->data = N_ALIGN(ex, hdr->data); 4150cc5983cSToomas Soome ex.a_data = htole32(hdr->data); 4160cc5983cSToomas Soome ex.a_entry = htole32(hdr->entry); 4170cc5983cSToomas Soome writex(fd, &ex, sizeof(ex)); 4180cc5983cSToomas Soome hdr->size = N_ALIGN(ex, sizeof(ex)); 4190cc5983cSToomas Soome seekx(fd, hdr->size); 4200cc5983cSToomas Soome break; 4210cc5983cSToomas Soome case F_ELF: 4220cc5983cSToomas Soome eh = elfhdr; 4230cc5983cSToomas Soome eh.e.e_entry = htole32(hdr->entry); 4240cc5983cSToomas Soome eh.p[0].p_vaddr = eh.p[0].p_paddr = htole32(hdr->org); 4250cc5983cSToomas Soome eh.p[0].p_filesz = eh.p[0].p_memsz = htole32(hdr->text); 4260cc5983cSToomas Soome eh.p[1].p_offset = htole32(le32toh(eh.p[0].p_offset) + 4270cc5983cSToomas Soome le32toh(eh.p[0].p_filesz)); 4280cc5983cSToomas Soome eh.p[1].p_vaddr = eh.p[1].p_paddr = 4290cc5983cSToomas Soome htole32(align(le32toh(eh.p[0].p_paddr) + le32toh(eh.p[0].p_memsz), 4300cc5983cSToomas Soome 4096)); 4310cc5983cSToomas Soome eh.p[1].p_filesz = eh.p[1].p_memsz = htole32(hdr->data); 4320cc5983cSToomas Soome eh.sh[2].sh_addr = eh.p[0].p_vaddr; 4330cc5983cSToomas Soome eh.sh[2].sh_offset = eh.p[0].p_offset; 4340cc5983cSToomas Soome eh.sh[2].sh_size = eh.p[0].p_filesz; 4350cc5983cSToomas Soome eh.sh[3].sh_addr = eh.p[1].p_vaddr; 4360cc5983cSToomas Soome eh.sh[3].sh_offset = eh.p[1].p_offset; 4370cc5983cSToomas Soome eh.sh[3].sh_size = eh.p[1].p_filesz; 4380cc5983cSToomas Soome writex(fd, &eh, sizeof(eh)); 4390cc5983cSToomas Soome hdr->size = sizeof(eh); 4400cc5983cSToomas Soome } 4410cc5983cSToomas Soome } 4420cc5983cSToomas Soome 4430cc5983cSToomas Soome /* 4440cc5983cSToomas Soome * Safe copy from input file to output file. 4450cc5983cSToomas Soome */ 4460cc5983cSToomas Soome static void 4470cc5983cSToomas Soome copy(int fdi, int fdo, size_t nbyte, off_t offset) 4480cc5983cSToomas Soome { 4490cc5983cSToomas Soome char buf[8192]; 4500cc5983cSToomas Soome size_t n; 4510cc5983cSToomas Soome 4520cc5983cSToomas Soome while (nbyte) { 4530cc5983cSToomas Soome if ((n = sizeof(buf)) > nbyte) 4540cc5983cSToomas Soome n = nbyte; 4550cc5983cSToomas Soome if (readx(fdi, buf, n, offset) != n) 4560cc5983cSToomas Soome errx(2, "%s: Short read", fname); 4570cc5983cSToomas Soome writex(fdo, buf, n); 4580cc5983cSToomas Soome nbyte -= n; 4590cc5983cSToomas Soome offset = -1; 4600cc5983cSToomas Soome } 4610cc5983cSToomas Soome } 4620cc5983cSToomas Soome 4630cc5983cSToomas Soome /* 4640cc5983cSToomas Soome * Safe read from input file. 4650cc5983cSToomas Soome */ 4660cc5983cSToomas Soome static size_t 4670cc5983cSToomas Soome readx(int fd, void *buf, size_t nbyte, off_t offset) 4680cc5983cSToomas Soome { 4690cc5983cSToomas Soome ssize_t n; 4700cc5983cSToomas Soome 4710cc5983cSToomas Soome if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) 4720cc5983cSToomas Soome err(2, "%s", fname); 4730cc5983cSToomas Soome if ((n = read(fd, buf, nbyte)) == -1) 4740cc5983cSToomas Soome err(2, "%s", fname); 4750cc5983cSToomas Soome return n; 4760cc5983cSToomas Soome } 4770cc5983cSToomas Soome 4780cc5983cSToomas Soome /* 4790cc5983cSToomas Soome * Safe write to output file. 4800cc5983cSToomas Soome */ 4810cc5983cSToomas Soome static void 4820cc5983cSToomas Soome writex(int fd, const void *buf, size_t nbyte) 4830cc5983cSToomas Soome { 4840cc5983cSToomas Soome ssize_t n; 4850cc5983cSToomas Soome 4860cc5983cSToomas Soome if ((n = write(fd, buf, nbyte)) == -1) 4870cc5983cSToomas Soome err(2, "%s", tname); 4880cc5983cSToomas Soome if ((size_t)n != nbyte) 4890cc5983cSToomas Soome errx(2, "%s: Short write", tname); 4900cc5983cSToomas Soome } 4910cc5983cSToomas Soome 4920cc5983cSToomas Soome /* 4930cc5983cSToomas Soome * Safe seek in output file. 4940cc5983cSToomas Soome */ 4950cc5983cSToomas Soome static void 4960cc5983cSToomas Soome seekx(int fd, off_t offset) 4970cc5983cSToomas Soome { 4980cc5983cSToomas Soome if (lseek(fd, offset, SEEK_SET) != offset) 4990cc5983cSToomas Soome err(2, "%s", tname); 5000cc5983cSToomas Soome } 5010cc5983cSToomas Soome 5020cc5983cSToomas Soome /* 5030cc5983cSToomas Soome * Convert an option argument to a format code. 5040cc5983cSToomas Soome */ 5050cc5983cSToomas Soome static unsigned int 5060cc5983cSToomas Soome optfmt(const char *arg) 5070cc5983cSToomas Soome { 5080cc5983cSToomas Soome unsigned int i; 5090cc5983cSToomas Soome 5100cc5983cSToomas Soome for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); 5110cc5983cSToomas Soome if (i == F_CNT) 5120cc5983cSToomas Soome errx(1, "%s: Unknown format", arg); 5130cc5983cSToomas Soome return i; 5140cc5983cSToomas Soome } 5150cc5983cSToomas Soome 5160cc5983cSToomas Soome /* 5170cc5983cSToomas Soome * Convert an option argument to an address. 5180cc5983cSToomas Soome */ 5190cc5983cSToomas Soome static uint32_t 5200cc5983cSToomas Soome optaddr(const char *arg) 5210cc5983cSToomas Soome { 5220cc5983cSToomas Soome char *s; 5230cc5983cSToomas Soome unsigned long x; 5240cc5983cSToomas Soome 5250cc5983cSToomas Soome errno = 0; 5260cc5983cSToomas Soome x = strtoul(arg, &s, 0); 5270cc5983cSToomas Soome if (errno || !*arg || *s || x > MAXU32) 5280cc5983cSToomas Soome errx(1, "%s: Illegal address", arg); 5290cc5983cSToomas Soome return x; 5300cc5983cSToomas Soome } 5310cc5983cSToomas Soome 5320cc5983cSToomas Soome /* 5330cc5983cSToomas Soome * Convert an option argument to a page number. 5340cc5983cSToomas Soome */ 5350cc5983cSToomas Soome static int 5360cc5983cSToomas Soome optpage(const char *arg, int hi) 5370cc5983cSToomas Soome { 5380cc5983cSToomas Soome char *s; 5390cc5983cSToomas Soome long x; 5400cc5983cSToomas Soome 5410cc5983cSToomas Soome errno = 0; 5420cc5983cSToomas Soome x = strtol(arg, &s, 0); 5430cc5983cSToomas Soome if (errno || !*arg || *s || x < 0 || x > hi) 5440cc5983cSToomas Soome errx(1, "%s: Illegal page number", arg); 5450cc5983cSToomas Soome return x; 5460cc5983cSToomas Soome } 5470cc5983cSToomas Soome 5480cc5983cSToomas Soome /* 5490cc5983cSToomas Soome * Display a warning. 5500cc5983cSToomas Soome */ 5510cc5983cSToomas Soome static void 5520cc5983cSToomas Soome Warn(const char *locus, const char *fmt, ...) 5530cc5983cSToomas Soome { 5540cc5983cSToomas Soome va_list ap; 5550cc5983cSToomas Soome char *s; 5560cc5983cSToomas Soome 5570cc5983cSToomas Soome if (!quiet) { 5580cc5983cSToomas Soome asprintf(&s, "%s: Warning: %s", locus, fmt); 5590cc5983cSToomas Soome va_start(ap, fmt); 5600cc5983cSToomas Soome vwarnx(s, ap); 5610cc5983cSToomas Soome va_end(ap); 5620cc5983cSToomas Soome free(s); 5630cc5983cSToomas Soome } 5640cc5983cSToomas Soome } 5650cc5983cSToomas Soome 5660cc5983cSToomas Soome /* 5670cc5983cSToomas Soome * Display usage information. 5680cc5983cSToomas Soome */ 5690cc5983cSToomas Soome static void 5700cc5983cSToomas Soome usage(void) 5710cc5983cSToomas Soome { 5720cc5983cSToomas Soome fprintf(stderr, "%s\n%s\n", 5730cc5983cSToomas Soome "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", 5740cc5983cSToomas Soome " [-l file] [-o filename] [-P page] [-W page] file"); 5750cc5983cSToomas Soome exit(1); 5760cc5983cSToomas Soome } 577