19c9f4492SRobert Nordier /* 29c9f4492SRobert Nordier * Copyright (c) 1998 Robert Nordier 39c9f4492SRobert Nordier * All rights reserved. 49c9f4492SRobert Nordier * 59c9f4492SRobert Nordier * Redistribution and use in source and binary forms, with or without 69c9f4492SRobert Nordier * modification, are permitted provided that the following conditions 79c9f4492SRobert Nordier * are met: 89c9f4492SRobert Nordier * 1. Redistributions of source code must retain the above copyright 99c9f4492SRobert Nordier * notice, this list of conditions and the following disclaimer. 109c9f4492SRobert Nordier * 2. Redistributions in binary form must reproduce the above copyright 119c9f4492SRobert Nordier * notice, this list of conditions and the following disclaimer in the 129c9f4492SRobert Nordier * documentation and/or other materials provided with the distribution. 139c9f4492SRobert Nordier * 149c9f4492SRobert Nordier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND 159c9f4492SRobert Nordier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 169c9f4492SRobert Nordier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 179c9f4492SRobert Nordier * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 189c9f4492SRobert Nordier * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 199c9f4492SRobert Nordier * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 209c9f4492SRobert Nordier * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 219c9f4492SRobert Nordier * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 229c9f4492SRobert Nordier * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 239c9f4492SRobert Nordier * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 249c9f4492SRobert Nordier * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 259c9f4492SRobert Nordier */ 269c9f4492SRobert Nordier 279c9f4492SRobert Nordier #ifndef lint 289c9f4492SRobert Nordier static const char rcsid[] = 2997d92980SPeter Wemm "$FreeBSD$"; 309c9f4492SRobert Nordier #endif /* not lint */ 319c9f4492SRobert Nordier 32ac53b225SMike Barcroft #include <sys/param.h> 3349a39408SDavid E. O'Brien #include <sys/endian.h> 349c9f4492SRobert Nordier #include <sys/stat.h> 359c9f4492SRobert Nordier #include <sys/mman.h> 369c9f4492SRobert Nordier 37093f1218SRuslan Ermilov /* XXX make this work as an i386/amd64 cross-tool */ 38093f1218SRuslan Ermilov #include <machine/exec.h> 39093f1218SRuslan Ermilov #undef __LDPGSZ 40093f1218SRuslan Ermilov #define __LDPGSZ 4096 41093f1218SRuslan Ermilov 4249a39408SDavid E. O'Brien #include <a.out.h> 439c9f4492SRobert Nordier #include <err.h> 449c9f4492SRobert Nordier #include <errno.h> 459c9f4492SRobert Nordier #include <fcntl.h> 469c9f4492SRobert Nordier #include <stdarg.h> 479c9f4492SRobert Nordier #include <stdio.h> 489c9f4492SRobert Nordier #include <stdlib.h> 499c9f4492SRobert Nordier #include <string.h> 509c9f4492SRobert Nordier #include <unistd.h> 519c9f4492SRobert Nordier 529c9f4492SRobert Nordier #include "btx.h" 539c9f4492SRobert Nordier #include "elfh.h" 549c9f4492SRobert Nordier 559c9f4492SRobert Nordier #define BTX_PATH "/sys/boot/i386/btx" 569c9f4492SRobert Nordier 579c9f4492SRobert Nordier #define I_LDR 0 /* BTX loader */ 589c9f4492SRobert Nordier #define I_BTX 1 /* BTX kernel */ 599c9f4492SRobert Nordier #define I_CLNT 2 /* Client program */ 609c9f4492SRobert Nordier 619c9f4492SRobert Nordier #define F_BIN 0 /* Binary */ 629c9f4492SRobert Nordier #define F_AOUT 1 /* ZMAGIC a.out */ 639c9f4492SRobert Nordier #define F_ELF 2 /* 32-bit ELF */ 649c9f4492SRobert Nordier #define F_CNT 3 /* Number of formats */ 659c9f4492SRobert Nordier 669c9f4492SRobert Nordier #define IMPURE 1 /* Writable text */ 679c9f4492SRobert Nordier #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ 689c9f4492SRobert Nordier 699c9f4492SRobert Nordier #define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) 709c9f4492SRobert Nordier 719c9f4492SRobert Nordier struct hdr { 72b0ca5f03SMarcel Moolenaar uint32_t fmt; /* Format */ 73b0ca5f03SMarcel Moolenaar uint32_t flags; /* Bit flags */ 74b0ca5f03SMarcel Moolenaar uint32_t size; /* Size of file */ 75b0ca5f03SMarcel Moolenaar uint32_t text; /* Size of text segment */ 76b0ca5f03SMarcel Moolenaar uint32_t data; /* Size of data segment */ 77b0ca5f03SMarcel Moolenaar uint32_t bss; /* Size of bss segment */ 78b0ca5f03SMarcel Moolenaar uint32_t org; /* Program origin */ 79b0ca5f03SMarcel Moolenaar uint32_t entry; /* Program entry point */ 809c9f4492SRobert Nordier }; 819c9f4492SRobert Nordier 829c9f4492SRobert Nordier static const char *const fmtlist[] = {"bin", "aout", "elf"}; 839c9f4492SRobert Nordier 849c9f4492SRobert Nordier static const char binfo[] = 859c9f4492SRobert Nordier "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " 869c9f4492SRobert Nordier "pgctl=%x:%x\n"; 879c9f4492SRobert Nordier static const char cinfo[] = 889c9f4492SRobert Nordier "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; 899c9f4492SRobert Nordier static const char oinfo[] = 909c9f4492SRobert Nordier "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; 919c9f4492SRobert Nordier 929c9f4492SRobert Nordier static const char *lname = 939c9f4492SRobert Nordier BTX_PATH "/btxldr/btxldr"; /* BTX loader */ 949c9f4492SRobert Nordier static const char *bname = 959c9f4492SRobert Nordier BTX_PATH "/btx/btx"; /* BTX kernel */ 969c9f4492SRobert Nordier static const char *oname = 979c9f4492SRobert Nordier "a.out"; /* Output filename */ 989c9f4492SRobert Nordier 999c9f4492SRobert Nordier static int ppage = -1; /* First page present */ 1009c9f4492SRobert Nordier static int wpage = -1; /* First page writable */ 1019c9f4492SRobert Nordier 102b0ca5f03SMarcel Moolenaar static unsigned int format; /* Output format */ 1039c9f4492SRobert Nordier 1049c9f4492SRobert Nordier static uint32_t centry; /* Client entry address */ 1059c9f4492SRobert Nordier static uint32_t lentry; /* Loader entry address */ 1069c9f4492SRobert Nordier 10738c931abSRobert Nordier static int Eflag; /* Client entry option */ 10838c931abSRobert Nordier 1099c9f4492SRobert Nordier static int quiet; /* Inhibit warnings */ 1109c9f4492SRobert Nordier static int verbose; /* Display information */ 1119c9f4492SRobert Nordier 1129c9f4492SRobert Nordier static const char *tname; /* Temporary output file */ 1139c9f4492SRobert Nordier static const char *fname; /* Current input file */ 1149c9f4492SRobert Nordier 1159c9f4492SRobert Nordier static void cleanup(void); 1169c9f4492SRobert Nordier static void btxld(const char *); 1179c9f4492SRobert Nordier static void getbtx(int, struct btx_hdr *); 1189c9f4492SRobert Nordier static void gethdr(int, struct hdr *); 1199c9f4492SRobert Nordier static void puthdr(int, struct hdr *); 1209c9f4492SRobert Nordier static void copy(int, int, size_t, off_t); 1219c9f4492SRobert Nordier static size_t readx(int, void *, size_t, off_t); 1229c9f4492SRobert Nordier static void writex(int, const void *, size_t); 1239c9f4492SRobert Nordier static void seekx(int, off_t); 124b0ca5f03SMarcel Moolenaar static unsigned int optfmt(const char *); 1259c9f4492SRobert Nordier static uint32_t optaddr(const char *); 1269c9f4492SRobert Nordier static int optpage(const char *, int); 1279c9f4492SRobert Nordier static void Warn(const char *, const char *, ...); 1289c9f4492SRobert Nordier static void usage(void); 1299c9f4492SRobert Nordier 1309c9f4492SRobert Nordier /* 1319c9f4492SRobert Nordier * A link editor for BTX clients. 1329c9f4492SRobert Nordier */ 1339c9f4492SRobert Nordier int 1349c9f4492SRobert Nordier main(int argc, char *argv[]) 1359c9f4492SRobert Nordier { 1369c9f4492SRobert Nordier int c; 1379c9f4492SRobert Nordier 1389c9f4492SRobert Nordier while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:W:")) != -1) 1399c9f4492SRobert Nordier switch (c) { 1409c9f4492SRobert Nordier case 'q': 1419c9f4492SRobert Nordier quiet = 1; 1429c9f4492SRobert Nordier break; 1439c9f4492SRobert Nordier case 'v': 1449c9f4492SRobert Nordier verbose = 1; 1459c9f4492SRobert Nordier break; 1469c9f4492SRobert Nordier case 'b': 1479c9f4492SRobert Nordier bname = optarg; 1489c9f4492SRobert Nordier break; 1499c9f4492SRobert Nordier case 'E': 1509c9f4492SRobert Nordier centry = optaddr(optarg); 15138c931abSRobert Nordier Eflag = 1; 1529c9f4492SRobert Nordier break; 1539c9f4492SRobert Nordier case 'e': 1549c9f4492SRobert Nordier lentry = optaddr(optarg); 1559c9f4492SRobert Nordier break; 1569c9f4492SRobert Nordier case 'f': 1579c9f4492SRobert Nordier format = optfmt(optarg); 1589c9f4492SRobert Nordier break; 1599c9f4492SRobert Nordier case 'l': 1609c9f4492SRobert Nordier lname = optarg; 1619c9f4492SRobert Nordier break; 1629c9f4492SRobert Nordier case 'o': 1639c9f4492SRobert Nordier oname = optarg; 1649c9f4492SRobert Nordier break; 1659c9f4492SRobert Nordier case 'P': 1669c9f4492SRobert Nordier ppage = optpage(optarg, 1); 1679c9f4492SRobert Nordier break; 1689c9f4492SRobert Nordier case 'W': 1699c9f4492SRobert Nordier wpage = optpage(optarg, BTX_MAXCWR); 1709c9f4492SRobert Nordier break; 1719c9f4492SRobert Nordier default: 1729c9f4492SRobert Nordier usage(); 1739c9f4492SRobert Nordier } 1749c9f4492SRobert Nordier argc -= optind; 1759c9f4492SRobert Nordier argv += optind; 1769c9f4492SRobert Nordier if (argc != 1) 1779c9f4492SRobert Nordier usage(); 1789c9f4492SRobert Nordier atexit(cleanup); 1799c9f4492SRobert Nordier btxld(*argv); 1809c9f4492SRobert Nordier return 0; 1819c9f4492SRobert Nordier } 1829c9f4492SRobert Nordier 1839c9f4492SRobert Nordier /* 1849c9f4492SRobert Nordier * Clean up after errors. 1859c9f4492SRobert Nordier */ 1869c9f4492SRobert Nordier static void 1879c9f4492SRobert Nordier cleanup(void) 1889c9f4492SRobert Nordier { 1899c9f4492SRobert Nordier if (tname) 1909c9f4492SRobert Nordier remove(tname); 1919c9f4492SRobert Nordier } 1929c9f4492SRobert Nordier 1939c9f4492SRobert Nordier /* 1949c9f4492SRobert Nordier * Read the input files; write the output file; display information. 1959c9f4492SRobert Nordier */ 1969c9f4492SRobert Nordier static void 1979c9f4492SRobert Nordier btxld(const char *iname) 1989c9f4492SRobert Nordier { 1999c9f4492SRobert Nordier char name[FILENAME_MAX]; 2007148ee89SRuslan Ermilov struct btx_hdr btx, btxle; 2019c9f4492SRobert Nordier struct hdr ihdr, ohdr; 202b0ca5f03SMarcel Moolenaar unsigned int ldr_size, cwr; 2039c9f4492SRobert Nordier int fdi[3], fdo, i; 2049c9f4492SRobert Nordier 205b0ca5f03SMarcel Moolenaar ldr_size = 0; 206b0ca5f03SMarcel Moolenaar 2079c9f4492SRobert Nordier for (i = I_LDR; i <= I_CLNT; i++) { 2089c9f4492SRobert Nordier fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2099c9f4492SRobert Nordier if ((fdi[i] = open(fname, O_RDONLY)) == -1) 2109c9f4492SRobert Nordier err(2, "%s", fname); 2119c9f4492SRobert Nordier switch (i) { 2129c9f4492SRobert Nordier case I_LDR: 2139c9f4492SRobert Nordier gethdr(fdi[i], &ihdr); 2149c9f4492SRobert Nordier if (ihdr.fmt != F_BIN) 2159c9f4492SRobert Nordier Warn(fname, "Loader format is %s; processing as %s", 2169c9f4492SRobert Nordier fmtlist[ihdr.fmt], fmtlist[F_BIN]); 2179c9f4492SRobert Nordier ldr_size = ihdr.size; 2189c9f4492SRobert Nordier break; 2199c9f4492SRobert Nordier case I_BTX: 2209c9f4492SRobert Nordier getbtx(fdi[i], &btx); 2219c9f4492SRobert Nordier break; 2229c9f4492SRobert Nordier case I_CLNT: 2239c9f4492SRobert Nordier gethdr(fdi[i], &ihdr); 2249c9f4492SRobert Nordier if (ihdr.org && ihdr.org != BTX_PGSIZE) 2259c9f4492SRobert Nordier Warn(fname, 2269c9f4492SRobert Nordier "Client origin is 0x%x; expecting 0 or 0x%x", 2279c9f4492SRobert Nordier ihdr.org, BTX_PGSIZE); 2289c9f4492SRobert Nordier } 2299c9f4492SRobert Nordier } 2309c9f4492SRobert Nordier memset(&ohdr, 0, sizeof(ohdr)); 2319c9f4492SRobert Nordier ohdr.fmt = format; 2329c9f4492SRobert Nordier ohdr.text = ldr_size; 2339c9f4492SRobert Nordier ohdr.data = btx.btx_textsz + ihdr.size; 2349c9f4492SRobert Nordier ohdr.org = lentry; 2359c9f4492SRobert Nordier ohdr.entry = lentry; 2369c9f4492SRobert Nordier cwr = 0; 237b0ca5f03SMarcel Moolenaar if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { 2389c9f4492SRobert Nordier if (wpage > 0) 2399c9f4492SRobert Nordier cwr = wpage; 2409c9f4492SRobert Nordier else { 2419c9f4492SRobert Nordier cwr = howmany(ihdr.text, BTX_PGSIZE); 2429c9f4492SRobert Nordier if (cwr > BTX_MAXCWR) 2439c9f4492SRobert Nordier cwr = BTX_MAXCWR; 2449c9f4492SRobert Nordier } 245b0ca5f03SMarcel Moolenaar } 2469c9f4492SRobert Nordier if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { 2479c9f4492SRobert Nordier btx.btx_flags |= BTX_MAPONE; 2489c9f4492SRobert Nordier if (!cwr) 2499c9f4492SRobert Nordier cwr++; 2509c9f4492SRobert Nordier } 2519c9f4492SRobert Nordier btx.btx_pgctl -= cwr; 25238c931abSRobert Nordier btx.btx_entry = Eflag ? centry : ihdr.entry; 2539c9f4492SRobert Nordier if (snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) 2549c9f4492SRobert Nordier errx(2, "%s: Filename too long", oname); 2559c9f4492SRobert Nordier if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) 2569c9f4492SRobert Nordier err(2, "%s", name); 2579c9f4492SRobert Nordier if (!(tname = strdup(name))) 2589c9f4492SRobert Nordier err(2, NULL); 2599c9f4492SRobert Nordier puthdr(fdo, &ohdr); 2609c9f4492SRobert Nordier for (i = I_LDR; i <= I_CLNT; i++) { 2619c9f4492SRobert Nordier fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2629c9f4492SRobert Nordier switch (i) { 2639c9f4492SRobert Nordier case I_LDR: 2649c9f4492SRobert Nordier copy(fdi[i], fdo, ldr_size, 0); 2659c9f4492SRobert Nordier seekx(fdo, ohdr.size += ohdr.text); 2669c9f4492SRobert Nordier break; 2679c9f4492SRobert Nordier case I_BTX: 2687148ee89SRuslan Ermilov btxle = btx; 26949a39408SDavid E. O'Brien btxle.btx_pgctl = htole16(btxle.btx_pgctl); 27049a39408SDavid E. O'Brien btxle.btx_textsz = htole16(btxle.btx_textsz); 27149a39408SDavid E. O'Brien btxle.btx_entry = htole32(btxle.btx_entry); 2727148ee89SRuslan Ermilov writex(fdo, &btxle, sizeof(btxle)); 2739c9f4492SRobert Nordier copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), 2749c9f4492SRobert Nordier sizeof(btx)); 2759c9f4492SRobert Nordier break; 2769c9f4492SRobert Nordier case I_CLNT: 2779c9f4492SRobert Nordier copy(fdi[i], fdo, ihdr.size, 0); 2789c9f4492SRobert Nordier if (ftruncate(fdo, ohdr.size += ohdr.data)) 2799c9f4492SRobert Nordier err(2, "%s", tname); 2809c9f4492SRobert Nordier } 2819c9f4492SRobert Nordier if (close(fdi[i])) 2829c9f4492SRobert Nordier err(2, "%s", fname); 2839c9f4492SRobert Nordier } 2849c9f4492SRobert Nordier if (close(fdo)) 2859c9f4492SRobert Nordier err(2, "%s", tname); 2869c9f4492SRobert Nordier if (rename(tname, oname)) 2879c9f4492SRobert Nordier err(2, "%s: Can't rename to %s", tname, oname); 2889c9f4492SRobert Nordier tname = NULL; 2899c9f4492SRobert Nordier if (verbose) { 2909c9f4492SRobert Nordier printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, 2919c9f4492SRobert Nordier BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * 2929c9f4492SRobert Nordier BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), 2939c9f4492SRobert Nordier BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / 2949c9f4492SRobert Nordier BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); 2959c9f4492SRobert Nordier printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, 2969c9f4492SRobert Nordier ihdr.data, ihdr.bss, ihdr.entry); 2979c9f4492SRobert Nordier printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, 2989c9f4492SRobert Nordier ohdr.data, ohdr.org, ohdr.entry); 2999c9f4492SRobert Nordier } 3009c9f4492SRobert Nordier } 3019c9f4492SRobert Nordier 3029c9f4492SRobert Nordier /* 3039c9f4492SRobert Nordier * Read BTX file header. 3049c9f4492SRobert Nordier */ 3059c9f4492SRobert Nordier static void 3069c9f4492SRobert Nordier getbtx(int fd, struct btx_hdr * btx) 3079c9f4492SRobert Nordier { 3089c9f4492SRobert Nordier if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || 3099c9f4492SRobert Nordier btx->btx_magic[0] != BTX_MAG0 || 3109c9f4492SRobert Nordier btx->btx_magic[1] != BTX_MAG1 || 3119c9f4492SRobert Nordier btx->btx_magic[2] != BTX_MAG2) 3129c9f4492SRobert Nordier errx(1, "%s: Not a BTX kernel", fname); 31349a39408SDavid E. O'Brien btx->btx_pgctl = le16toh(btx->btx_pgctl); 31449a39408SDavid E. O'Brien btx->btx_textsz = le16toh(btx->btx_textsz); 31549a39408SDavid E. O'Brien btx->btx_entry = le32toh(btx->btx_entry); 3169c9f4492SRobert Nordier } 3179c9f4492SRobert Nordier 3189c9f4492SRobert Nordier /* 3199c9f4492SRobert Nordier * Get file size and read a.out or ELF header. 3209c9f4492SRobert Nordier */ 3219c9f4492SRobert Nordier static void 3229c9f4492SRobert Nordier gethdr(int fd, struct hdr *hdr) 3239c9f4492SRobert Nordier { 3249c9f4492SRobert Nordier struct stat sb; 32549a39408SDavid E. O'Brien const struct exec *ex; 3269c9f4492SRobert Nordier const Elf32_Ehdr *ee; 3279c9f4492SRobert Nordier const Elf32_Phdr *ep; 3289c9f4492SRobert Nordier void *p; 329b0ca5f03SMarcel Moolenaar unsigned int fmt, x, n, i; 3309c9f4492SRobert Nordier 3319c9f4492SRobert Nordier memset(hdr, 0, sizeof(*hdr)); 3329c9f4492SRobert Nordier if (fstat(fd, &sb)) 3339c9f4492SRobert Nordier err(2, "%s", fname); 3349c9f4492SRobert Nordier if (sb.st_size > MAXU32) 3359c9f4492SRobert Nordier errx(1, "%s: Too big", fname); 3369c9f4492SRobert Nordier hdr->size = sb.st_size; 3379c9f4492SRobert Nordier if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 3389c9f4492SRobert Nordier 0)) == MAP_FAILED) 3399c9f4492SRobert Nordier err(2, "%s", fname); 3409c9f4492SRobert Nordier for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) 3419c9f4492SRobert Nordier switch (fmt) { 3429c9f4492SRobert Nordier case F_AOUT: 3439c9f4492SRobert Nordier ex = p; 34449a39408SDavid E. O'Brien if (hdr->size >= sizeof(struct exec) && !N_BADMAG(*ex)) { 3459c9f4492SRobert Nordier hdr->fmt = fmt; 34649a39408SDavid E. O'Brien x = N_GETMAGIC(*ex); 3479c9f4492SRobert Nordier if (x == OMAGIC || x == NMAGIC) { 3489c9f4492SRobert Nordier if (x == NMAGIC) 3499c9f4492SRobert Nordier Warn(fname, "Treating %s NMAGIC as OMAGIC", 3509c9f4492SRobert Nordier fmtlist[fmt]); 3519c9f4492SRobert Nordier hdr->flags |= IMPURE; 3529c9f4492SRobert Nordier } 35349a39408SDavid E. O'Brien hdr->text = le32toh(ex->a_text); 35449a39408SDavid E. O'Brien hdr->data = le32toh(ex->a_data); 35549a39408SDavid E. O'Brien hdr->bss = le32toh(ex->a_bss); 35649a39408SDavid E. O'Brien hdr->entry = le32toh(ex->a_entry); 35749a39408SDavid E. O'Brien if (le32toh(ex->a_entry) >= BTX_PGSIZE) 3589c9f4492SRobert Nordier hdr->org = BTX_PGSIZE; 3599c9f4492SRobert Nordier } 3609c9f4492SRobert Nordier break; 3619c9f4492SRobert Nordier case F_ELF: 3629c9f4492SRobert Nordier ee = p; 3639c9f4492SRobert Nordier if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { 3649c9f4492SRobert Nordier hdr->fmt = fmt; 36549a39408SDavid E. O'Brien for (n = i = 0; i < le16toh(ee->e_phnum); i++) { 36649a39408SDavid E. O'Brien ep = (void *)((uint8_t *)p + le32toh(ee->e_phoff) + 36749a39408SDavid E. O'Brien le16toh(ee->e_phentsize) * i); 36849a39408SDavid E. O'Brien if (le32toh(ep->p_type) == PT_LOAD) 3699c9f4492SRobert Nordier switch (n++) { 3709c9f4492SRobert Nordier case 0: 37149a39408SDavid E. O'Brien hdr->text = le32toh(ep->p_filesz); 37249a39408SDavid E. O'Brien hdr->org = le32toh(ep->p_paddr); 37349a39408SDavid E. O'Brien if (le32toh(ep->p_flags) & PF_W) 3749c9f4492SRobert Nordier hdr->flags |= IMPURE; 3759c9f4492SRobert Nordier break; 3769c9f4492SRobert Nordier case 1: 37749a39408SDavid E. O'Brien hdr->data = le32toh(ep->p_filesz); 37849a39408SDavid E. O'Brien hdr->bss = le32toh(ep->p_memsz) - 37949a39408SDavid E. O'Brien le32toh(ep->p_filesz); 3809c9f4492SRobert Nordier break; 3819c9f4492SRobert Nordier case 2: 3829c9f4492SRobert Nordier Warn(fname, 3839c9f4492SRobert Nordier "Ignoring extra %s PT_LOAD segments", 3849c9f4492SRobert Nordier fmtlist[fmt]); 3859c9f4492SRobert Nordier } 3869c9f4492SRobert Nordier } 38749a39408SDavid E. O'Brien hdr->entry = le32toh(ee->e_entry); 3889c9f4492SRobert Nordier } 3899c9f4492SRobert Nordier } 3909c9f4492SRobert Nordier if (munmap(p, hdr->size)) 3919c9f4492SRobert Nordier err(2, "%s", fname); 3929c9f4492SRobert Nordier } 3939c9f4492SRobert Nordier 3949c9f4492SRobert Nordier /* 3959c9f4492SRobert Nordier * Write a.out or ELF header. 3969c9f4492SRobert Nordier */ 3979c9f4492SRobert Nordier static void 3989c9f4492SRobert Nordier puthdr(int fd, struct hdr *hdr) 3999c9f4492SRobert Nordier { 40049a39408SDavid E. O'Brien struct exec ex; 4019c9f4492SRobert Nordier struct elfh eh; 4029c9f4492SRobert Nordier 4039c9f4492SRobert Nordier switch (hdr->fmt) { 4049c9f4492SRobert Nordier case F_AOUT: 4059c9f4492SRobert Nordier memset(&ex, 0, sizeof(ex)); 40649a39408SDavid E. O'Brien N_SETMAGIC(ex, ZMAGIC, MID_ZERO, 0); 40749a39408SDavid E. O'Brien hdr->text = N_ALIGN(ex, hdr->text); 40849a39408SDavid E. O'Brien ex.a_text = htole32(hdr->text); 40949a39408SDavid E. O'Brien hdr->data = N_ALIGN(ex, hdr->data); 41049a39408SDavid E. O'Brien ex.a_data = htole32(hdr->data); 41149a39408SDavid E. O'Brien ex.a_entry = htole32(hdr->entry); 4129c9f4492SRobert Nordier writex(fd, &ex, sizeof(ex)); 41349a39408SDavid E. O'Brien hdr->size = N_ALIGN(ex, sizeof(ex)); 4149c9f4492SRobert Nordier seekx(fd, hdr->size); 4159c9f4492SRobert Nordier break; 4169c9f4492SRobert Nordier case F_ELF: 4179c9f4492SRobert Nordier eh = elfhdr; 41849a39408SDavid E. O'Brien eh.e.e_entry = htole32(hdr->entry); 41949a39408SDavid E. O'Brien eh.p[0].p_vaddr = eh.p[0].p_paddr = htole32(hdr->org); 42049a39408SDavid E. O'Brien eh.p[0].p_filesz = eh.p[0].p_memsz = htole32(hdr->text); 42149a39408SDavid E. O'Brien eh.p[1].p_offset = htole32(le32toh(eh.p[0].p_offset) + 42249a39408SDavid E. O'Brien le32toh(eh.p[0].p_filesz)); 4237148ee89SRuslan Ermilov eh.p[1].p_vaddr = eh.p[1].p_paddr = 42449a39408SDavid E. O'Brien htole32(align(le32toh(eh.p[0].p_paddr) + le32toh(eh.p[0].p_memsz), 4257148ee89SRuslan Ermilov 4)); 42649a39408SDavid E. O'Brien eh.p[1].p_filesz = eh.p[1].p_memsz = htole32(hdr->data); 4279c9f4492SRobert Nordier eh.sh[2].sh_addr = eh.p[0].p_vaddr; 4289c9f4492SRobert Nordier eh.sh[2].sh_offset = eh.p[0].p_offset; 4299c9f4492SRobert Nordier eh.sh[2].sh_size = eh.p[0].p_filesz; 4309c9f4492SRobert Nordier eh.sh[3].sh_addr = eh.p[1].p_vaddr; 4319c9f4492SRobert Nordier eh.sh[3].sh_offset = eh.p[1].p_offset; 4329c9f4492SRobert Nordier eh.sh[3].sh_size = eh.p[1].p_filesz; 4339c9f4492SRobert Nordier writex(fd, &eh, sizeof(eh)); 4349c9f4492SRobert Nordier hdr->size = sizeof(eh); 4359c9f4492SRobert Nordier } 4369c9f4492SRobert Nordier } 4379c9f4492SRobert Nordier 4389c9f4492SRobert Nordier /* 4399c9f4492SRobert Nordier * Safe copy from input file to output file. 4409c9f4492SRobert Nordier */ 4419c9f4492SRobert Nordier static void 4429c9f4492SRobert Nordier copy(int fdi, int fdo, size_t nbyte, off_t offset) 4439c9f4492SRobert Nordier { 4449c9f4492SRobert Nordier char buf[8192]; 4459c9f4492SRobert Nordier size_t n; 4469c9f4492SRobert Nordier 4479c9f4492SRobert Nordier while (nbyte) { 4489c9f4492SRobert Nordier if ((n = sizeof(buf)) > nbyte) 4499c9f4492SRobert Nordier n = nbyte; 4509c9f4492SRobert Nordier if (readx(fdi, buf, n, offset) != n) 4519c9f4492SRobert Nordier errx(2, "%s: Short read", fname); 4529c9f4492SRobert Nordier writex(fdo, buf, n); 4539c9f4492SRobert Nordier nbyte -= n; 4549c9f4492SRobert Nordier offset = -1; 4559c9f4492SRobert Nordier } 4569c9f4492SRobert Nordier } 4579c9f4492SRobert Nordier 4589c9f4492SRobert Nordier /* 4599c9f4492SRobert Nordier * Safe read from input file. 4609c9f4492SRobert Nordier */ 4619c9f4492SRobert Nordier static size_t 4629c9f4492SRobert Nordier readx(int fd, void *buf, size_t nbyte, off_t offset) 4639c9f4492SRobert Nordier { 4649c9f4492SRobert Nordier ssize_t n; 4659c9f4492SRobert Nordier 4669c9f4492SRobert Nordier if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) 4679c9f4492SRobert Nordier err(2, "%s", fname); 4689c9f4492SRobert Nordier if ((n = read(fd, buf, nbyte)) == -1) 4699c9f4492SRobert Nordier err(2, "%s", fname); 4709c9f4492SRobert Nordier return n; 4719c9f4492SRobert Nordier } 4729c9f4492SRobert Nordier 4739c9f4492SRobert Nordier /* 4749c9f4492SRobert Nordier * Safe write to output file. 4759c9f4492SRobert Nordier */ 4769c9f4492SRobert Nordier static void 4779c9f4492SRobert Nordier writex(int fd, const void *buf, size_t nbyte) 4789c9f4492SRobert Nordier { 4799c9f4492SRobert Nordier ssize_t n; 4809c9f4492SRobert Nordier 4819c9f4492SRobert Nordier if ((n = write(fd, buf, nbyte)) == -1) 4829c9f4492SRobert Nordier err(2, "%s", tname); 4839c9f4492SRobert Nordier if (n != nbyte) 4849c9f4492SRobert Nordier errx(2, "%s: Short write", tname); 4859c9f4492SRobert Nordier } 4869c9f4492SRobert Nordier 4879c9f4492SRobert Nordier /* 4889c9f4492SRobert Nordier * Safe seek in output file. 4899c9f4492SRobert Nordier */ 4909c9f4492SRobert Nordier static void 4919c9f4492SRobert Nordier seekx(int fd, off_t offset) 4929c9f4492SRobert Nordier { 4939c9f4492SRobert Nordier if (lseek(fd, offset, SEEK_SET) != offset) 4949c9f4492SRobert Nordier err(2, "%s", tname); 4959c9f4492SRobert Nordier } 4969c9f4492SRobert Nordier 4979c9f4492SRobert Nordier /* 4989c9f4492SRobert Nordier * Convert an option argument to a format code. 4999c9f4492SRobert Nordier */ 500b0ca5f03SMarcel Moolenaar static unsigned int 5019c9f4492SRobert Nordier optfmt(const char *arg) 5029c9f4492SRobert Nordier { 503b0ca5f03SMarcel Moolenaar unsigned int i; 5049c9f4492SRobert Nordier 5059c9f4492SRobert Nordier for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); 5069c9f4492SRobert Nordier if (i == F_CNT) 5079c9f4492SRobert Nordier errx(1, "%s: Unknown format", arg); 5089c9f4492SRobert Nordier return i; 5099c9f4492SRobert Nordier } 5109c9f4492SRobert Nordier 5119c9f4492SRobert Nordier /* 5129c9f4492SRobert Nordier * Convert an option argument to an address. 5139c9f4492SRobert Nordier */ 5149c9f4492SRobert Nordier static uint32_t 5159c9f4492SRobert Nordier optaddr(const char *arg) 5169c9f4492SRobert Nordier { 5179c9f4492SRobert Nordier char *s; 5189c9f4492SRobert Nordier unsigned long x; 5199c9f4492SRobert Nordier 5209c9f4492SRobert Nordier errno = 0; 5219c9f4492SRobert Nordier x = strtoul(arg, &s, 0); 5229c9f4492SRobert Nordier if (errno || !*arg || *s || x > MAXU32) 5239c9f4492SRobert Nordier errx(1, "%s: Illegal address", arg); 5249c9f4492SRobert Nordier return x; 5259c9f4492SRobert Nordier } 5269c9f4492SRobert Nordier 5279c9f4492SRobert Nordier /* 5289c9f4492SRobert Nordier * Convert an option argument to a page number. 5299c9f4492SRobert Nordier */ 5309c9f4492SRobert Nordier static int 5319c9f4492SRobert Nordier optpage(const char *arg, int hi) 5329c9f4492SRobert Nordier { 5339c9f4492SRobert Nordier char *s; 5349c9f4492SRobert Nordier long x; 5359c9f4492SRobert Nordier 5369c9f4492SRobert Nordier errno = 0; 5379c9f4492SRobert Nordier x = strtol(arg, &s, 0); 5389c9f4492SRobert Nordier if (errno || !*arg || *s || x < 0 || x > hi) 5399c9f4492SRobert Nordier errx(1, "%s: Illegal page number", arg); 5409c9f4492SRobert Nordier return x; 5419c9f4492SRobert Nordier } 5429c9f4492SRobert Nordier 5439c9f4492SRobert Nordier /* 5449c9f4492SRobert Nordier * Display a warning. 5459c9f4492SRobert Nordier */ 5469c9f4492SRobert Nordier static void 5479c9f4492SRobert Nordier Warn(const char *locus, const char *fmt, ...) 5489c9f4492SRobert Nordier { 5499c9f4492SRobert Nordier va_list ap; 5509c9f4492SRobert Nordier char *s; 5519c9f4492SRobert Nordier 5529c9f4492SRobert Nordier if (!quiet) { 5539c9f4492SRobert Nordier asprintf(&s, "%s: Warning: %s", locus, fmt); 5549c9f4492SRobert Nordier va_start(ap, fmt); 5559c9f4492SRobert Nordier vwarnx(s, ap); 5569c9f4492SRobert Nordier va_end(ap); 5579c9f4492SRobert Nordier free(s); 5589c9f4492SRobert Nordier } 5599c9f4492SRobert Nordier } 5609c9f4492SRobert Nordier 5619c9f4492SRobert Nordier /* 5629c9f4492SRobert Nordier * Display usage information. 5639c9f4492SRobert Nordier */ 5649c9f4492SRobert Nordier static void 5659c9f4492SRobert Nordier usage(void) 5669c9f4492SRobert Nordier { 5679c9f4492SRobert Nordier fprintf(stderr, "%s\n%s\n", 5689c9f4492SRobert Nordier "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", 5699c9f4492SRobert Nordier " [-l file] [-o filename] [-P page] [-W page] file"); 5709c9f4492SRobert Nordier exit(1); 5719c9f4492SRobert Nordier } 572