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> 339c9f4492SRobert Nordier #include <sys/stat.h> 349c9f4492SRobert Nordier #include <sys/mman.h> 359c9f4492SRobert Nordier 369c9f4492SRobert Nordier #include <err.h> 379c9f4492SRobert Nordier #include <errno.h> 389c9f4492SRobert Nordier #include <fcntl.h> 399c9f4492SRobert Nordier #include <stdarg.h> 409c9f4492SRobert Nordier #include <stdio.h> 419c9f4492SRobert Nordier #include <stdlib.h> 429c9f4492SRobert Nordier #include <string.h> 439c9f4492SRobert Nordier #include <unistd.h> 449c9f4492SRobert Nordier 459c9f4492SRobert Nordier #include "btx.h" 469c9f4492SRobert Nordier #include "elfh.h" 477148ee89SRuslan Ermilov #include "endian.h" 487148ee89SRuslan Ermilov #include "i386_a.out.h" 499c9f4492SRobert Nordier 509c9f4492SRobert Nordier #define BTX_PATH "/sys/boot/i386/btx" 519c9f4492SRobert Nordier 529c9f4492SRobert Nordier #define I_LDR 0 /* BTX loader */ 539c9f4492SRobert Nordier #define I_BTX 1 /* BTX kernel */ 549c9f4492SRobert Nordier #define I_CLNT 2 /* Client program */ 559c9f4492SRobert Nordier 569c9f4492SRobert Nordier #define F_BIN 0 /* Binary */ 579c9f4492SRobert Nordier #define F_AOUT 1 /* ZMAGIC a.out */ 589c9f4492SRobert Nordier #define F_ELF 2 /* 32-bit ELF */ 599c9f4492SRobert Nordier #define F_CNT 3 /* Number of formats */ 609c9f4492SRobert Nordier 619c9f4492SRobert Nordier #define IMPURE 1 /* Writable text */ 629c9f4492SRobert Nordier #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */ 639c9f4492SRobert Nordier 649c9f4492SRobert Nordier #define align(x, y) (((x) + (y) - 1) & ~((y) - 1)) 659c9f4492SRobert Nordier 669c9f4492SRobert Nordier struct hdr { 67b0ca5f03SMarcel Moolenaar uint32_t fmt; /* Format */ 68b0ca5f03SMarcel Moolenaar uint32_t flags; /* Bit flags */ 69b0ca5f03SMarcel Moolenaar uint32_t size; /* Size of file */ 70b0ca5f03SMarcel Moolenaar uint32_t text; /* Size of text segment */ 71b0ca5f03SMarcel Moolenaar uint32_t data; /* Size of data segment */ 72b0ca5f03SMarcel Moolenaar uint32_t bss; /* Size of bss segment */ 73b0ca5f03SMarcel Moolenaar uint32_t org; /* Program origin */ 74b0ca5f03SMarcel Moolenaar uint32_t entry; /* Program entry point */ 759c9f4492SRobert Nordier }; 769c9f4492SRobert Nordier 779c9f4492SRobert Nordier static const char *const fmtlist[] = {"bin", "aout", "elf"}; 789c9f4492SRobert Nordier 799c9f4492SRobert Nordier static const char binfo[] = 809c9f4492SRobert Nordier "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM " 819c9f4492SRobert Nordier "pgctl=%x:%x\n"; 829c9f4492SRobert Nordier static const char cinfo[] = 839c9f4492SRobert Nordier "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n"; 849c9f4492SRobert Nordier static const char oinfo[] = 859c9f4492SRobert Nordier "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n"; 869c9f4492SRobert Nordier 879c9f4492SRobert Nordier static const char *lname = 889c9f4492SRobert Nordier BTX_PATH "/btxldr/btxldr"; /* BTX loader */ 899c9f4492SRobert Nordier static const char *bname = 909c9f4492SRobert Nordier BTX_PATH "/btx/btx"; /* BTX kernel */ 919c9f4492SRobert Nordier static const char *oname = 929c9f4492SRobert Nordier "a.out"; /* Output filename */ 939c9f4492SRobert Nordier 949c9f4492SRobert Nordier static int ppage = -1; /* First page present */ 959c9f4492SRobert Nordier static int wpage = -1; /* First page writable */ 969c9f4492SRobert Nordier 97b0ca5f03SMarcel Moolenaar static unsigned int format; /* Output format */ 989c9f4492SRobert Nordier 999c9f4492SRobert Nordier static uint32_t centry; /* Client entry address */ 1009c9f4492SRobert Nordier static uint32_t lentry; /* Loader entry address */ 1019c9f4492SRobert Nordier 10238c931abSRobert Nordier static int Eflag; /* Client entry option */ 10338c931abSRobert Nordier 1049c9f4492SRobert Nordier static int quiet; /* Inhibit warnings */ 1059c9f4492SRobert Nordier static int verbose; /* Display information */ 1069c9f4492SRobert Nordier 1079c9f4492SRobert Nordier static const char *tname; /* Temporary output file */ 1089c9f4492SRobert Nordier static const char *fname; /* Current input file */ 1099c9f4492SRobert Nordier 1109c9f4492SRobert Nordier static void cleanup(void); 1119c9f4492SRobert Nordier static void btxld(const char *); 1129c9f4492SRobert Nordier static void getbtx(int, struct btx_hdr *); 1139c9f4492SRobert Nordier static void gethdr(int, struct hdr *); 1149c9f4492SRobert Nordier static void puthdr(int, struct hdr *); 1159c9f4492SRobert Nordier static void copy(int, int, size_t, off_t); 1169c9f4492SRobert Nordier static size_t readx(int, void *, size_t, off_t); 1179c9f4492SRobert Nordier static void writex(int, const void *, size_t); 1189c9f4492SRobert Nordier static void seekx(int, off_t); 119b0ca5f03SMarcel Moolenaar static unsigned int optfmt(const char *); 1209c9f4492SRobert Nordier static uint32_t optaddr(const char *); 1219c9f4492SRobert Nordier static int optpage(const char *, int); 1229c9f4492SRobert Nordier static void Warn(const char *, const char *, ...); 1239c9f4492SRobert Nordier static void usage(void); 1249c9f4492SRobert Nordier 1259c9f4492SRobert Nordier /* 1269c9f4492SRobert Nordier * A link editor for BTX clients. 1279c9f4492SRobert Nordier */ 1289c9f4492SRobert Nordier int 1299c9f4492SRobert Nordier main(int argc, char *argv[]) 1309c9f4492SRobert Nordier { 1319c9f4492SRobert Nordier int c; 1329c9f4492SRobert Nordier 1339c9f4492SRobert Nordier while ((c = getopt(argc, argv, "qvb:E:e:f:l:o:P:W:")) != -1) 1349c9f4492SRobert Nordier switch (c) { 1359c9f4492SRobert Nordier case 'q': 1369c9f4492SRobert Nordier quiet = 1; 1379c9f4492SRobert Nordier break; 1389c9f4492SRobert Nordier case 'v': 1399c9f4492SRobert Nordier verbose = 1; 1409c9f4492SRobert Nordier break; 1419c9f4492SRobert Nordier case 'b': 1429c9f4492SRobert Nordier bname = optarg; 1439c9f4492SRobert Nordier break; 1449c9f4492SRobert Nordier case 'E': 1459c9f4492SRobert Nordier centry = optaddr(optarg); 14638c931abSRobert Nordier Eflag = 1; 1479c9f4492SRobert Nordier break; 1489c9f4492SRobert Nordier case 'e': 1499c9f4492SRobert Nordier lentry = optaddr(optarg); 1509c9f4492SRobert Nordier break; 1519c9f4492SRobert Nordier case 'f': 1529c9f4492SRobert Nordier format = optfmt(optarg); 1539c9f4492SRobert Nordier break; 1549c9f4492SRobert Nordier case 'l': 1559c9f4492SRobert Nordier lname = optarg; 1569c9f4492SRobert Nordier break; 1579c9f4492SRobert Nordier case 'o': 1589c9f4492SRobert Nordier oname = optarg; 1599c9f4492SRobert Nordier break; 1609c9f4492SRobert Nordier case 'P': 1619c9f4492SRobert Nordier ppage = optpage(optarg, 1); 1629c9f4492SRobert Nordier break; 1639c9f4492SRobert Nordier case 'W': 1649c9f4492SRobert Nordier wpage = optpage(optarg, BTX_MAXCWR); 1659c9f4492SRobert Nordier break; 1669c9f4492SRobert Nordier default: 1679c9f4492SRobert Nordier usage(); 1689c9f4492SRobert Nordier } 1699c9f4492SRobert Nordier argc -= optind; 1709c9f4492SRobert Nordier argv += optind; 1719c9f4492SRobert Nordier if (argc != 1) 1729c9f4492SRobert Nordier usage(); 1739c9f4492SRobert Nordier atexit(cleanup); 1749c9f4492SRobert Nordier btxld(*argv); 1759c9f4492SRobert Nordier return 0; 1769c9f4492SRobert Nordier } 1779c9f4492SRobert Nordier 1789c9f4492SRobert Nordier /* 1799c9f4492SRobert Nordier * Clean up after errors. 1809c9f4492SRobert Nordier */ 1819c9f4492SRobert Nordier static void 1829c9f4492SRobert Nordier cleanup(void) 1839c9f4492SRobert Nordier { 1849c9f4492SRobert Nordier if (tname) 1859c9f4492SRobert Nordier remove(tname); 1869c9f4492SRobert Nordier } 1879c9f4492SRobert Nordier 1889c9f4492SRobert Nordier /* 1899c9f4492SRobert Nordier * Read the input files; write the output file; display information. 1909c9f4492SRobert Nordier */ 1919c9f4492SRobert Nordier static void 1929c9f4492SRobert Nordier btxld(const char *iname) 1939c9f4492SRobert Nordier { 1949c9f4492SRobert Nordier char name[FILENAME_MAX]; 1957148ee89SRuslan Ermilov struct btx_hdr btx, btxle; 1969c9f4492SRobert Nordier struct hdr ihdr, ohdr; 197b0ca5f03SMarcel Moolenaar unsigned int ldr_size, cwr; 1989c9f4492SRobert Nordier int fdi[3], fdo, i; 1999c9f4492SRobert Nordier 200b0ca5f03SMarcel Moolenaar ldr_size = 0; 201b0ca5f03SMarcel Moolenaar 2029c9f4492SRobert Nordier for (i = I_LDR; i <= I_CLNT; i++) { 2039c9f4492SRobert Nordier fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2049c9f4492SRobert Nordier if ((fdi[i] = open(fname, O_RDONLY)) == -1) 2059c9f4492SRobert Nordier err(2, "%s", fname); 2069c9f4492SRobert Nordier switch (i) { 2079c9f4492SRobert Nordier case I_LDR: 2089c9f4492SRobert Nordier gethdr(fdi[i], &ihdr); 2099c9f4492SRobert Nordier if (ihdr.fmt != F_BIN) 2109c9f4492SRobert Nordier Warn(fname, "Loader format is %s; processing as %s", 2119c9f4492SRobert Nordier fmtlist[ihdr.fmt], fmtlist[F_BIN]); 2129c9f4492SRobert Nordier ldr_size = ihdr.size; 2139c9f4492SRobert Nordier break; 2149c9f4492SRobert Nordier case I_BTX: 2159c9f4492SRobert Nordier getbtx(fdi[i], &btx); 2169c9f4492SRobert Nordier break; 2179c9f4492SRobert Nordier case I_CLNT: 2189c9f4492SRobert Nordier gethdr(fdi[i], &ihdr); 2199c9f4492SRobert Nordier if (ihdr.org && ihdr.org != BTX_PGSIZE) 2209c9f4492SRobert Nordier Warn(fname, 2219c9f4492SRobert Nordier "Client origin is 0x%x; expecting 0 or 0x%x", 2229c9f4492SRobert Nordier ihdr.org, BTX_PGSIZE); 2239c9f4492SRobert Nordier } 2249c9f4492SRobert Nordier } 2259c9f4492SRobert Nordier memset(&ohdr, 0, sizeof(ohdr)); 2269c9f4492SRobert Nordier ohdr.fmt = format; 2279c9f4492SRobert Nordier ohdr.text = ldr_size; 2289c9f4492SRobert Nordier ohdr.data = btx.btx_textsz + ihdr.size; 2299c9f4492SRobert Nordier ohdr.org = lentry; 2309c9f4492SRobert Nordier ohdr.entry = lentry; 2319c9f4492SRobert Nordier cwr = 0; 232b0ca5f03SMarcel Moolenaar if (wpage > 0 || (wpage == -1 && !(ihdr.flags & IMPURE))) { 2339c9f4492SRobert Nordier if (wpage > 0) 2349c9f4492SRobert Nordier cwr = wpage; 2359c9f4492SRobert Nordier else { 2369c9f4492SRobert Nordier cwr = howmany(ihdr.text, BTX_PGSIZE); 2379c9f4492SRobert Nordier if (cwr > BTX_MAXCWR) 2389c9f4492SRobert Nordier cwr = BTX_MAXCWR; 2399c9f4492SRobert Nordier } 240b0ca5f03SMarcel Moolenaar } 2419c9f4492SRobert Nordier if (ppage > 0 || (ppage && wpage && ihdr.org >= BTX_PGSIZE)) { 2429c9f4492SRobert Nordier btx.btx_flags |= BTX_MAPONE; 2439c9f4492SRobert Nordier if (!cwr) 2449c9f4492SRobert Nordier cwr++; 2459c9f4492SRobert Nordier } 2469c9f4492SRobert Nordier btx.btx_pgctl -= cwr; 24738c931abSRobert Nordier btx.btx_entry = Eflag ? centry : ihdr.entry; 2489c9f4492SRobert Nordier if (snprintf(name, sizeof(name), "%s.tmp", oname) >= sizeof(name)) 2499c9f4492SRobert Nordier errx(2, "%s: Filename too long", oname); 2509c9f4492SRobert Nordier if ((fdo = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666)) == -1) 2519c9f4492SRobert Nordier err(2, "%s", name); 2529c9f4492SRobert Nordier if (!(tname = strdup(name))) 2539c9f4492SRobert Nordier err(2, NULL); 2549c9f4492SRobert Nordier puthdr(fdo, &ohdr); 2559c9f4492SRobert Nordier for (i = I_LDR; i <= I_CLNT; i++) { 2569c9f4492SRobert Nordier fname = i == I_LDR ? lname : i == I_BTX ? bname : iname; 2579c9f4492SRobert Nordier switch (i) { 2589c9f4492SRobert Nordier case I_LDR: 2599c9f4492SRobert Nordier copy(fdi[i], fdo, ldr_size, 0); 2609c9f4492SRobert Nordier seekx(fdo, ohdr.size += ohdr.text); 2619c9f4492SRobert Nordier break; 2629c9f4492SRobert Nordier case I_BTX: 2637148ee89SRuslan Ermilov btxle = btx; 2647148ee89SRuslan Ermilov btxle.btx_pgctl = HTOLE16(btxle.btx_pgctl); 2657148ee89SRuslan Ermilov btxle.btx_textsz = HTOLE16(btxle.btx_textsz); 2667148ee89SRuslan Ermilov btxle.btx_entry = HTOLE32(btxle.btx_entry); 2677148ee89SRuslan Ermilov writex(fdo, &btxle, sizeof(btxle)); 2689c9f4492SRobert Nordier copy(fdi[i], fdo, btx.btx_textsz - sizeof(btx), 2699c9f4492SRobert Nordier sizeof(btx)); 2709c9f4492SRobert Nordier break; 2719c9f4492SRobert Nordier case I_CLNT: 2729c9f4492SRobert Nordier copy(fdi[i], fdo, ihdr.size, 0); 2739c9f4492SRobert Nordier if (ftruncate(fdo, ohdr.size += ohdr.data)) 2749c9f4492SRobert Nordier err(2, "%s", tname); 2759c9f4492SRobert Nordier } 2769c9f4492SRobert Nordier if (close(fdi[i])) 2779c9f4492SRobert Nordier err(2, "%s", fname); 2789c9f4492SRobert Nordier } 2799c9f4492SRobert Nordier if (close(fdo)) 2809c9f4492SRobert Nordier err(2, "%s", tname); 2819c9f4492SRobert Nordier if (rename(tname, oname)) 2829c9f4492SRobert Nordier err(2, "%s: Can't rename to %s", tname, oname); 2839c9f4492SRobert Nordier tname = NULL; 2849c9f4492SRobert Nordier if (verbose) { 2859c9f4492SRobert Nordier printf(binfo, btx.btx_majver, btx.btx_minver, btx.btx_textsz, 2869c9f4492SRobert Nordier BTX_ORIGIN(btx), BTX_ENTRY(btx), BTX_MAPPED(btx) * 2879c9f4492SRobert Nordier BTX_PGSIZE / 0x100000, !!(btx.btx_flags & BTX_MAPONE), 2889c9f4492SRobert Nordier BTX_MAPPED(btx) - btx.btx_pgctl - BTX_PGBASE / 2899c9f4492SRobert Nordier BTX_PGSIZE - BTX_MAPPED(btx) * 4 / BTX_PGSIZE); 2909c9f4492SRobert Nordier printf(cinfo, fmtlist[ihdr.fmt], ihdr.size, ihdr.text, 2919c9f4492SRobert Nordier ihdr.data, ihdr.bss, ihdr.entry); 2929c9f4492SRobert Nordier printf(oinfo, fmtlist[ohdr.fmt], ohdr.size, ohdr.text, 2939c9f4492SRobert Nordier ohdr.data, ohdr.org, ohdr.entry); 2949c9f4492SRobert Nordier } 2959c9f4492SRobert Nordier } 2969c9f4492SRobert Nordier 2979c9f4492SRobert Nordier /* 2989c9f4492SRobert Nordier * Read BTX file header. 2999c9f4492SRobert Nordier */ 3009c9f4492SRobert Nordier static void 3019c9f4492SRobert Nordier getbtx(int fd, struct btx_hdr * btx) 3029c9f4492SRobert Nordier { 3039c9f4492SRobert Nordier if (readx(fd, btx, sizeof(*btx), 0) != sizeof(*btx) || 3049c9f4492SRobert Nordier btx->btx_magic[0] != BTX_MAG0 || 3059c9f4492SRobert Nordier btx->btx_magic[1] != BTX_MAG1 || 3069c9f4492SRobert Nordier btx->btx_magic[2] != BTX_MAG2) 3079c9f4492SRobert Nordier errx(1, "%s: Not a BTX kernel", fname); 3087148ee89SRuslan Ermilov btx->btx_pgctl = LE16TOH(btx->btx_pgctl); 3097148ee89SRuslan Ermilov btx->btx_textsz = LE16TOH(btx->btx_textsz); 3107148ee89SRuslan Ermilov btx->btx_entry = LE32TOH(btx->btx_entry); 3119c9f4492SRobert Nordier } 3129c9f4492SRobert Nordier 3139c9f4492SRobert Nordier /* 3149c9f4492SRobert Nordier * Get file size and read a.out or ELF header. 3159c9f4492SRobert Nordier */ 3169c9f4492SRobert Nordier static void 3179c9f4492SRobert Nordier gethdr(int fd, struct hdr *hdr) 3189c9f4492SRobert Nordier { 3199c9f4492SRobert Nordier struct stat sb; 3207148ee89SRuslan Ermilov const struct i386_exec *ex; 3219c9f4492SRobert Nordier const Elf32_Ehdr *ee; 3229c9f4492SRobert Nordier const Elf32_Phdr *ep; 3239c9f4492SRobert Nordier void *p; 324b0ca5f03SMarcel Moolenaar unsigned int fmt, x, n, i; 3259c9f4492SRobert Nordier 3269c9f4492SRobert Nordier memset(hdr, 0, sizeof(*hdr)); 3279c9f4492SRobert Nordier if (fstat(fd, &sb)) 3289c9f4492SRobert Nordier err(2, "%s", fname); 3299c9f4492SRobert Nordier if (sb.st_size > MAXU32) 3309c9f4492SRobert Nordier errx(1, "%s: Too big", fname); 3319c9f4492SRobert Nordier hdr->size = sb.st_size; 3329c9f4492SRobert Nordier if ((p = mmap(NULL, hdr->size, PROT_READ, MAP_SHARED, fd, 3339c9f4492SRobert Nordier 0)) == MAP_FAILED) 3349c9f4492SRobert Nordier err(2, "%s", fname); 3359c9f4492SRobert Nordier for (fmt = F_CNT - 1; !hdr->fmt && fmt; fmt--) 3369c9f4492SRobert Nordier switch (fmt) { 3379c9f4492SRobert Nordier case F_AOUT: 3389c9f4492SRobert Nordier ex = p; 3397148ee89SRuslan Ermilov if (hdr->size >= sizeof(struct i386_exec) && !I386_N_BADMAG(*ex)) { 3409c9f4492SRobert Nordier hdr->fmt = fmt; 3417148ee89SRuslan Ermilov x = I386_N_GETMAGIC(*ex); 3429c9f4492SRobert Nordier if (x == OMAGIC || x == NMAGIC) { 3439c9f4492SRobert Nordier if (x == NMAGIC) 3449c9f4492SRobert Nordier Warn(fname, "Treating %s NMAGIC as OMAGIC", 3459c9f4492SRobert Nordier fmtlist[fmt]); 3469c9f4492SRobert Nordier hdr->flags |= IMPURE; 3479c9f4492SRobert Nordier } 3487148ee89SRuslan Ermilov hdr->text = LE32TOH(ex->a_text); 3497148ee89SRuslan Ermilov hdr->data = LE32TOH(ex->a_data); 3507148ee89SRuslan Ermilov hdr->bss = LE32TOH(ex->a_bss); 3517148ee89SRuslan Ermilov hdr->entry = LE32TOH(ex->a_entry); 3527148ee89SRuslan Ermilov if (LE32TOH(ex->a_entry) >= BTX_PGSIZE) 3539c9f4492SRobert Nordier hdr->org = BTX_PGSIZE; 3549c9f4492SRobert Nordier } 3559c9f4492SRobert Nordier break; 3569c9f4492SRobert Nordier case F_ELF: 3579c9f4492SRobert Nordier ee = p; 3589c9f4492SRobert Nordier if (hdr->size >= sizeof(Elf32_Ehdr) && IS_ELF(*ee)) { 3599c9f4492SRobert Nordier hdr->fmt = fmt; 3607148ee89SRuslan Ermilov for (n = i = 0; i < LE16TOH(ee->e_phnum); i++) { 3617148ee89SRuslan Ermilov ep = (void *)((uint8_t *)p + LE32TOH(ee->e_phoff) + 3627148ee89SRuslan Ermilov LE16TOH(ee->e_phentsize) * i); 3637148ee89SRuslan Ermilov if (LE32TOH(ep->p_type) == PT_LOAD) 3649c9f4492SRobert Nordier switch (n++) { 3659c9f4492SRobert Nordier case 0: 3667148ee89SRuslan Ermilov hdr->text = LE32TOH(ep->p_filesz); 3677148ee89SRuslan Ermilov hdr->org = LE32TOH(ep->p_paddr); 3687148ee89SRuslan Ermilov if (LE32TOH(ep->p_flags) & PF_W) 3699c9f4492SRobert Nordier hdr->flags |= IMPURE; 3709c9f4492SRobert Nordier break; 3719c9f4492SRobert Nordier case 1: 3727148ee89SRuslan Ermilov hdr->data = LE32TOH(ep->p_filesz); 3737148ee89SRuslan Ermilov hdr->bss = LE32TOH(ep->p_memsz) - 3747148ee89SRuslan Ermilov LE32TOH(ep->p_filesz); 3759c9f4492SRobert Nordier break; 3769c9f4492SRobert Nordier case 2: 3779c9f4492SRobert Nordier Warn(fname, 3789c9f4492SRobert Nordier "Ignoring extra %s PT_LOAD segments", 3799c9f4492SRobert Nordier fmtlist[fmt]); 3809c9f4492SRobert Nordier } 3819c9f4492SRobert Nordier } 3827148ee89SRuslan Ermilov hdr->entry = LE32TOH(ee->e_entry); 3839c9f4492SRobert Nordier } 3849c9f4492SRobert Nordier } 3859c9f4492SRobert Nordier if (munmap(p, hdr->size)) 3869c9f4492SRobert Nordier err(2, "%s", fname); 3879c9f4492SRobert Nordier } 3889c9f4492SRobert Nordier 3899c9f4492SRobert Nordier /* 3909c9f4492SRobert Nordier * Write a.out or ELF header. 3919c9f4492SRobert Nordier */ 3929c9f4492SRobert Nordier static void 3939c9f4492SRobert Nordier puthdr(int fd, struct hdr *hdr) 3949c9f4492SRobert Nordier { 3957148ee89SRuslan Ermilov struct i386_exec ex; 3969c9f4492SRobert Nordier struct elfh eh; 3979c9f4492SRobert Nordier 3989c9f4492SRobert Nordier switch (hdr->fmt) { 3999c9f4492SRobert Nordier case F_AOUT: 4009c9f4492SRobert Nordier memset(&ex, 0, sizeof(ex)); 4017148ee89SRuslan Ermilov I386_N_SETMAGIC(ex, ZMAGIC, MID_ZERO, 0); 4027148ee89SRuslan Ermilov hdr->text = I386_N_ALIGN(ex, hdr->text); 4037148ee89SRuslan Ermilov ex.a_text = HTOLE32(hdr->text); 4047148ee89SRuslan Ermilov hdr->data = I386_N_ALIGN(ex, hdr->data); 4057148ee89SRuslan Ermilov ex.a_data = HTOLE32(hdr->data); 4067148ee89SRuslan Ermilov ex.a_entry = HTOLE32(hdr->entry); 4079c9f4492SRobert Nordier writex(fd, &ex, sizeof(ex)); 4087148ee89SRuslan Ermilov hdr->size = I386_N_ALIGN(ex, sizeof(ex)); 4099c9f4492SRobert Nordier seekx(fd, hdr->size); 4109c9f4492SRobert Nordier break; 4119c9f4492SRobert Nordier case F_ELF: 4129c9f4492SRobert Nordier eh = elfhdr; 4137148ee89SRuslan Ermilov eh.e.e_entry = HTOLE32(hdr->entry); 4147148ee89SRuslan Ermilov eh.p[0].p_vaddr = eh.p[0].p_paddr = HTOLE32(hdr->org); 4157148ee89SRuslan Ermilov eh.p[0].p_filesz = eh.p[0].p_memsz = HTOLE32(hdr->text); 4167148ee89SRuslan Ermilov eh.p[1].p_offset = HTOLE32(LE32TOH(eh.p[0].p_offset) + 4177148ee89SRuslan Ermilov LE32TOH(eh.p[0].p_filesz)); 4187148ee89SRuslan Ermilov eh.p[1].p_vaddr = eh.p[1].p_paddr = 4197148ee89SRuslan Ermilov HTOLE32(align(LE32TOH(eh.p[0].p_paddr) + LE32TOH(eh.p[0].p_memsz), 4207148ee89SRuslan Ermilov 4)); 4217148ee89SRuslan Ermilov eh.p[1].p_filesz = eh.p[1].p_memsz = HTOLE32(hdr->data); 4229c9f4492SRobert Nordier eh.sh[2].sh_addr = eh.p[0].p_vaddr; 4239c9f4492SRobert Nordier eh.sh[2].sh_offset = eh.p[0].p_offset; 4249c9f4492SRobert Nordier eh.sh[2].sh_size = eh.p[0].p_filesz; 4259c9f4492SRobert Nordier eh.sh[3].sh_addr = eh.p[1].p_vaddr; 4269c9f4492SRobert Nordier eh.sh[3].sh_offset = eh.p[1].p_offset; 4279c9f4492SRobert Nordier eh.sh[3].sh_size = eh.p[1].p_filesz; 4289c9f4492SRobert Nordier writex(fd, &eh, sizeof(eh)); 4299c9f4492SRobert Nordier hdr->size = sizeof(eh); 4309c9f4492SRobert Nordier } 4319c9f4492SRobert Nordier } 4329c9f4492SRobert Nordier 4339c9f4492SRobert Nordier /* 4349c9f4492SRobert Nordier * Safe copy from input file to output file. 4359c9f4492SRobert Nordier */ 4369c9f4492SRobert Nordier static void 4379c9f4492SRobert Nordier copy(int fdi, int fdo, size_t nbyte, off_t offset) 4389c9f4492SRobert Nordier { 4399c9f4492SRobert Nordier char buf[8192]; 4409c9f4492SRobert Nordier size_t n; 4419c9f4492SRobert Nordier 4429c9f4492SRobert Nordier while (nbyte) { 4439c9f4492SRobert Nordier if ((n = sizeof(buf)) > nbyte) 4449c9f4492SRobert Nordier n = nbyte; 4459c9f4492SRobert Nordier if (readx(fdi, buf, n, offset) != n) 4469c9f4492SRobert Nordier errx(2, "%s: Short read", fname); 4479c9f4492SRobert Nordier writex(fdo, buf, n); 4489c9f4492SRobert Nordier nbyte -= n; 4499c9f4492SRobert Nordier offset = -1; 4509c9f4492SRobert Nordier } 4519c9f4492SRobert Nordier } 4529c9f4492SRobert Nordier 4539c9f4492SRobert Nordier /* 4549c9f4492SRobert Nordier * Safe read from input file. 4559c9f4492SRobert Nordier */ 4569c9f4492SRobert Nordier static size_t 4579c9f4492SRobert Nordier readx(int fd, void *buf, size_t nbyte, off_t offset) 4589c9f4492SRobert Nordier { 4599c9f4492SRobert Nordier ssize_t n; 4609c9f4492SRobert Nordier 4619c9f4492SRobert Nordier if (offset != -1 && lseek(fd, offset, SEEK_SET) != offset) 4629c9f4492SRobert Nordier err(2, "%s", fname); 4639c9f4492SRobert Nordier if ((n = read(fd, buf, nbyte)) == -1) 4649c9f4492SRobert Nordier err(2, "%s", fname); 4659c9f4492SRobert Nordier return n; 4669c9f4492SRobert Nordier } 4679c9f4492SRobert Nordier 4689c9f4492SRobert Nordier /* 4699c9f4492SRobert Nordier * Safe write to output file. 4709c9f4492SRobert Nordier */ 4719c9f4492SRobert Nordier static void 4729c9f4492SRobert Nordier writex(int fd, const void *buf, size_t nbyte) 4739c9f4492SRobert Nordier { 4749c9f4492SRobert Nordier ssize_t n; 4759c9f4492SRobert Nordier 4769c9f4492SRobert Nordier if ((n = write(fd, buf, nbyte)) == -1) 4779c9f4492SRobert Nordier err(2, "%s", tname); 4789c9f4492SRobert Nordier if (n != nbyte) 4799c9f4492SRobert Nordier errx(2, "%s: Short write", tname); 4809c9f4492SRobert Nordier } 4819c9f4492SRobert Nordier 4829c9f4492SRobert Nordier /* 4839c9f4492SRobert Nordier * Safe seek in output file. 4849c9f4492SRobert Nordier */ 4859c9f4492SRobert Nordier static void 4869c9f4492SRobert Nordier seekx(int fd, off_t offset) 4879c9f4492SRobert Nordier { 4889c9f4492SRobert Nordier if (lseek(fd, offset, SEEK_SET) != offset) 4899c9f4492SRobert Nordier err(2, "%s", tname); 4909c9f4492SRobert Nordier } 4919c9f4492SRobert Nordier 4929c9f4492SRobert Nordier /* 4939c9f4492SRobert Nordier * Convert an option argument to a format code. 4949c9f4492SRobert Nordier */ 495b0ca5f03SMarcel Moolenaar static unsigned int 4969c9f4492SRobert Nordier optfmt(const char *arg) 4979c9f4492SRobert Nordier { 498b0ca5f03SMarcel Moolenaar unsigned int i; 4999c9f4492SRobert Nordier 5009c9f4492SRobert Nordier for (i = 0; i < F_CNT && strcmp(arg, fmtlist[i]); i++); 5019c9f4492SRobert Nordier if (i == F_CNT) 5029c9f4492SRobert Nordier errx(1, "%s: Unknown format", arg); 5039c9f4492SRobert Nordier return i; 5049c9f4492SRobert Nordier } 5059c9f4492SRobert Nordier 5069c9f4492SRobert Nordier /* 5079c9f4492SRobert Nordier * Convert an option argument to an address. 5089c9f4492SRobert Nordier */ 5099c9f4492SRobert Nordier static uint32_t 5109c9f4492SRobert Nordier optaddr(const char *arg) 5119c9f4492SRobert Nordier { 5129c9f4492SRobert Nordier char *s; 5139c9f4492SRobert Nordier unsigned long x; 5149c9f4492SRobert Nordier 5159c9f4492SRobert Nordier errno = 0; 5169c9f4492SRobert Nordier x = strtoul(arg, &s, 0); 5179c9f4492SRobert Nordier if (errno || !*arg || *s || x > MAXU32) 5189c9f4492SRobert Nordier errx(1, "%s: Illegal address", arg); 5199c9f4492SRobert Nordier return x; 5209c9f4492SRobert Nordier } 5219c9f4492SRobert Nordier 5229c9f4492SRobert Nordier /* 5239c9f4492SRobert Nordier * Convert an option argument to a page number. 5249c9f4492SRobert Nordier */ 5259c9f4492SRobert Nordier static int 5269c9f4492SRobert Nordier optpage(const char *arg, int hi) 5279c9f4492SRobert Nordier { 5289c9f4492SRobert Nordier char *s; 5299c9f4492SRobert Nordier long x; 5309c9f4492SRobert Nordier 5319c9f4492SRobert Nordier errno = 0; 5329c9f4492SRobert Nordier x = strtol(arg, &s, 0); 5339c9f4492SRobert Nordier if (errno || !*arg || *s || x < 0 || x > hi) 5349c9f4492SRobert Nordier errx(1, "%s: Illegal page number", arg); 5359c9f4492SRobert Nordier return x; 5369c9f4492SRobert Nordier } 5379c9f4492SRobert Nordier 5389c9f4492SRobert Nordier /* 5399c9f4492SRobert Nordier * Display a warning. 5409c9f4492SRobert Nordier */ 5419c9f4492SRobert Nordier static void 5429c9f4492SRobert Nordier Warn(const char *locus, const char *fmt, ...) 5439c9f4492SRobert Nordier { 5449c9f4492SRobert Nordier va_list ap; 5459c9f4492SRobert Nordier char *s; 5469c9f4492SRobert Nordier 5479c9f4492SRobert Nordier if (!quiet) { 5489c9f4492SRobert Nordier asprintf(&s, "%s: Warning: %s", locus, fmt); 5499c9f4492SRobert Nordier va_start(ap, fmt); 5509c9f4492SRobert Nordier vwarnx(s, ap); 5519c9f4492SRobert Nordier va_end(ap); 5529c9f4492SRobert Nordier free(s); 5539c9f4492SRobert Nordier } 5549c9f4492SRobert Nordier } 5559c9f4492SRobert Nordier 5569c9f4492SRobert Nordier /* 5579c9f4492SRobert Nordier * Display usage information. 5589c9f4492SRobert Nordier */ 5599c9f4492SRobert Nordier static void 5609c9f4492SRobert Nordier usage(void) 5619c9f4492SRobert Nordier { 5629c9f4492SRobert Nordier fprintf(stderr, "%s\n%s\n", 5639c9f4492SRobert Nordier "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]", 5649c9f4492SRobert Nordier " [-l file] [-o filename] [-P page] [-W page] file"); 5659c9f4492SRobert Nordier exit(1); 5669c9f4492SRobert Nordier } 567