xref: /titanic_51/usr/src/tools/btxld/btxld.c (revision 150a695268c611611ebabadb00df2a16f2f81fa7)
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