2 * Copyright (c) 1998 Robert Nordier
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
19 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
20 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: src/usr.sbin/btxld/btxld.c,v 1.4 2000/01/04 14:10:36 marcel Exp $
29 #define AOUT_H_FORCE32
30 #include <sys/param.h>
48 #define BTX_PATH "/sys/boot/i386/btx"
50 #define I_LDR 0 /* BTX loader */
51 #define I_BTX 1 /* BTX kernel */
52 #define I_CLNT 2 /* Client program */
54 #define F_BIN 0 /* Binary */
55 #define F_AOUT 1 /* ZMAGIC a.out */
56 #define F_ELF 2 /* 32-bit ELF */
57 #define F_CNT 3 /* Number of formats */
59 #define IMPURE 1 /* Writable text */
60 #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */
63 uint32_t fmt
; /* Format */
64 uint32_t flags
; /* Bit flags */
65 uint32_t size
; /* Size of file */
66 uint32_t text
; /* Size of text segment */
67 uint32_t data
; /* Size of data segment */
68 uint32_t bss
; /* Size of bss segment */
69 uint32_t org
; /* Program origin */
70 uint32_t entry
; /* Program entry point */
73 static const char *const fmtlist
[] = {"bin", "aout", "elf"};
75 static const char binfo
[] =
76 "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM "
78 static const char cinfo
[] =
79 "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n";
80 static const char oinfo
[] =
81 "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n";
83 static const char *lname
=
84 BTX_PATH
"/btxldr/btxldr"; /* BTX loader */
85 static const char *bname
=
86 BTX_PATH
"/btx/btx"; /* BTX kernel */
87 static const char *oname
=
88 "a.out"; /* Output filename */
90 static int ppage
= -1; /* First page present */
91 static int wpage
= -1; /* First page writable */
93 static unsigned int format
; /* Output format */
95 static uint32_t centry
; /* Client entry address */
96 static uint32_t lentry
; /* Loader entry address */
98 static int Eflag
; /* Client entry option */
100 static int quiet
; /* Inhibit warnings */
101 static int verbose
; /* Display information */
103 static const char *tname
; /* Temporary output file */
104 static const char *fname
; /* Current input file */
106 static void cleanup(void);
107 static void btxld(const char *);
108 static void getbtx(int, struct btx_hdr
*);
109 static void gethdr(int, struct hdr
*);
110 static void puthdr(int, struct hdr
*);
111 static void copy(int, int, size_t, off_t
);
112 static size_t readx(int, void *, size_t, off_t
);
113 static void writex(int, const void *, size_t);
114 static void seekx(int, off_t
);
115 static unsigned int optfmt(const char *);
116 static uint32_t optaddr(const char *);
117 static int optpage(const char *, int);
118 static void Warn(const char *, const char *, ...) __printflike(2, 3);
119 static void usage(void);
122 * A link editor for BTX clients.
125 main(int argc
, char *argv
[])
129 while ((c
= getopt(argc
, argv
, "qvb:E:e:f:l:o:P:W:")) != -1)
141 centry
= optaddr(optarg
);
145 lentry
= optaddr(optarg
);
148 format
= optfmt(optarg
);
157 ppage
= optpage(optarg
, 1);
160 wpage
= optpage(optarg
, BTX_MAXCWR
);
175 * Clean up after errors.
185 * Read the input files; write the output file; display information.
188 btxld(const char *iname
)
190 char name
[FILENAME_MAX
];
192 struct hdr ihdr
, ohdr
;
193 unsigned int ldr_size
, cwr
;
198 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
199 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
200 if ((fdi
[i
] = open(fname
, O_RDONLY
)) == -1)
204 gethdr(fdi
[i
], &ihdr
);
205 if (ihdr
.fmt
!= F_BIN
)
206 Warn(fname
, "Loader format is %s; processing as %s",
207 fmtlist
[ihdr
.fmt
], fmtlist
[F_BIN
]);
208 ldr_size
= ihdr
.size
;
211 getbtx(fdi
[i
], &btx
);
214 gethdr(fdi
[i
], &ihdr
);
215 if (ihdr
.org
&& ihdr
.org
!= BTX_PGSIZE
)
217 "Client origin is 0x%x; expecting 0 or 0x%x",
218 ihdr
.org
, BTX_PGSIZE
);
221 memset(&ohdr
, 0, sizeof(ohdr
));
223 ohdr
.text
= ldr_size
;
224 ohdr
.data
= btx
.btx_textsz
+ ihdr
.size
;
228 if (wpage
> 0 || (wpage
== -1 && !(ihdr
.flags
& IMPURE
))) {
232 cwr
= howmany(ihdr
.text
, BTX_PGSIZE
);
233 if (cwr
> BTX_MAXCWR
)
237 if (ppage
> 0 || (ppage
&& wpage
&& ihdr
.org
>= BTX_PGSIZE
)) {
238 btx
.btx_flags
|= BTX_MAPONE
;
242 btx
.btx_pgctl
-= cwr
;
243 btx
.btx_entry
= Eflag
? centry
: ihdr
.entry
;
244 if ((size_t)snprintf(name
, sizeof(name
), "%s.tmp", oname
) >= sizeof(name
))
245 errx(2, "%s: Filename too long", oname
);
246 if ((fdo
= open(name
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666)) == -1)
248 if (!(tname
= strdup(name
)))
251 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
252 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
255 copy(fdi
[i
], fdo
, ldr_size
, 0);
256 seekx(fdo
, ohdr
.size
+= ohdr
.text
);
259 writex(fdo
, &btx
, sizeof(btx
));
260 copy(fdi
[i
], fdo
, btx
.btx_textsz
- sizeof(btx
),
264 copy(fdi
[i
], fdo
, ihdr
.size
, 0);
265 if (ftruncate(fdo
, ohdr
.size
+= ohdr
.data
))
273 if (rename(tname
, oname
))
274 err(2, "%s: Can't rename to %s", tname
, oname
);
277 printf(binfo
, btx
.btx_majver
, btx
.btx_minver
, btx
.btx_textsz
,
278 BTX_ORIGIN(btx
), BTX_ENTRY(btx
), BTX_MAPPED(btx
) *
279 BTX_PGSIZE
/ 0x100000, !!(btx
.btx_flags
& BTX_MAPONE
),
280 BTX_MAPPED(btx
) - btx
.btx_pgctl
- BTX_PGBASE
/
281 BTX_PGSIZE
- BTX_MAPPED(btx
) * 4 / BTX_PGSIZE
);
282 printf(cinfo
, fmtlist
[ihdr
.fmt
], ihdr
.size
, ihdr
.text
,
283 ihdr
.data
, ihdr
.bss
, ihdr
.entry
);
284 printf(oinfo
, fmtlist
[ohdr
.fmt
], ohdr
.size
, ohdr
.text
,
285 ohdr
.data
, ohdr
.org
, ohdr
.entry
);
290 * Read BTX file header.
293 getbtx(int fd
, struct btx_hdr
* btx
)
295 if (readx(fd
, btx
, sizeof(*btx
), 0) != sizeof(*btx
) ||
296 btx
->btx_magic
[0] != BTX_MAG0
||
297 btx
->btx_magic
[1] != BTX_MAG1
||
298 btx
->btx_magic
[2] != BTX_MAG2
)
299 errx(1, "%s: Not a BTX kernel", fname
);
303 * Get file size and read a.out or ELF header.
306 gethdr(int fd
, struct hdr
*hdr
)
309 const struct exec
*ex
;
310 const Elf32_Ehdr
*ee
;
311 const Elf32_Phdr
*ep
;
313 unsigned int fmt
, x
, n
, i
;
315 memset(hdr
, 0, sizeof(*hdr
));
318 if (sb
.st_size
> MAXU32
)
319 errx(1, "%s: Too big", fname
);
320 hdr
->size
= sb
.st_size
;
321 if ((p
= mmap(NULL
, hdr
->size
, PROT_READ
, MAP_SHARED
, fd
,
324 for (fmt
= F_CNT
- 1; !hdr
->fmt
&& fmt
; fmt
--)
328 if (hdr
->size
>= sizeof(struct exec
) && !N_BADMAG(*ex
)) {
331 if (x
== OMAGIC
|| x
== NMAGIC
) {
333 Warn(fname
, "Treating %s NMAGIC as OMAGIC",
335 hdr
->flags
|= IMPURE
;
337 hdr
->text
= ex
->a_text
;
338 hdr
->data
= ex
->a_data
;
339 hdr
->bss
= ex
->a_bss
;
340 hdr
->entry
= ex
->a_entry
;
341 if (ex
->a_entry
>= BTX_PGSIZE
)
342 hdr
->org
= BTX_PGSIZE
;
347 if (hdr
->size
>= sizeof(Elf32_Ehdr
) && IS_ELF(*ee
)) {
349 for (n
= i
= 0; i
< ee
->e_phnum
; i
++) {
350 ep
= (void *)((uint8_t *)p
+ ee
->e_phoff
+
351 ee
->e_phentsize
* i
);
352 if (ep
->p_type
== PT_LOAD
)
355 hdr
->text
= ep
->p_filesz
;
356 hdr
->org
= ep
->p_paddr
;
357 if (ep
->p_flags
& PF_W
)
358 hdr
->flags
|= IMPURE
;
361 hdr
->data
= ep
->p_filesz
;
362 hdr
->bss
= ep
->p_memsz
- ep
->p_filesz
;
366 "Ignoring extra %s PT_LOAD segments",
370 hdr
->entry
= ee
->e_entry
;
373 if (munmap(p
, hdr
->size
))
378 * Write a.out or ELF header.
381 puthdr(int fd
, struct hdr
*hdr
)
388 memset(&ex
, 0, sizeof(ex
));
389 N_SETMAGIC(ex
, ZMAGIC
, MID_ZERO
, 0);
390 hdr
->text
= N_ALIGN(ex
, hdr
->text
);
391 ex
.a_text
= hdr
->text
;
392 hdr
->data
= N_ALIGN(ex
, hdr
->data
);
393 ex
.a_data
= hdr
->data
;
394 ex
.a_entry
= hdr
->entry
;
395 writex(fd
, &ex
, sizeof(ex
));
396 hdr
->size
= N_ALIGN(ex
, sizeof(ex
));
397 seekx(fd
, hdr
->size
);
401 eh
.e
.e_entry
= hdr
->entry
;
402 eh
.p
[0].p_vaddr
= eh
.p
[0].p_paddr
= hdr
->org
;
403 eh
.p
[0].p_filesz
= eh
.p
[0].p_memsz
= hdr
->text
;
404 eh
.p
[1].p_offset
= eh
.p
[0].p_offset
+ eh
.p
[0].p_filesz
;
405 eh
.p
[1].p_vaddr
= eh
.p
[1].p_paddr
=
406 roundup2(eh
.p
[0].p_paddr
+ eh
.p
[0].p_memsz
, 4);
407 eh
.p
[1].p_filesz
= eh
.p
[1].p_memsz
= hdr
->data
;
408 eh
.sh
[2].sh_addr
= eh
.p
[0].p_vaddr
;
409 eh
.sh
[2].sh_offset
= eh
.p
[0].p_offset
;
410 eh
.sh
[2].sh_size
= eh
.p
[0].p_filesz
;
411 eh
.sh
[3].sh_addr
= eh
.p
[1].p_vaddr
;
412 eh
.sh
[3].sh_offset
= eh
.p
[1].p_offset
;
413 eh
.sh
[3].sh_size
= eh
.p
[1].p_filesz
;
414 writex(fd
, &eh
, sizeof(eh
));
415 hdr
->size
= sizeof(eh
);
420 * Safe copy from input file to output file.
423 copy(int fdi
, int fdo
, size_t nbyte
, off_t offset
)
429 if ((n
= sizeof(buf
)) > nbyte
)
431 if (readx(fdi
, buf
, n
, offset
) != n
)
432 errx(2, "%s: Short read", fname
);
440 * Safe read from input file.
443 readx(int fd
, void *buf
, size_t nbyte
, off_t offset
)
447 if (offset
!= -1 && lseek(fd
, offset
, SEEK_SET
) != offset
)
449 if ((n
= read(fd
, buf
, nbyte
)) == -1)
455 * Safe write to output file.
458 writex(int fd
, const void *buf
, size_t nbyte
)
462 if ((n
= write(fd
, buf
, nbyte
)) == -1)
464 if ((size_t)n
!= nbyte
)
465 errx(2, "%s: Short write", tname
);
469 * Safe seek in output file.
472 seekx(int fd
, off_t offset
)
474 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
479 * Convert an option argument to a format code.
482 optfmt(const char *arg
)
486 for (i
= 0; i
< F_CNT
&& strcmp(arg
, fmtlist
[i
]); i
++);
488 errx(1, "%s: Unknown format", arg
);
493 * Convert an option argument to an address.
496 optaddr(const char *arg
)
502 x
= strtoul(arg
, &s
, 0);
503 if (errno
|| !*arg
|| *s
|| x
> MAXU32
)
504 errx(1, "%s: Illegal address", arg
);
509 * Convert an option argument to a page number.
512 optpage(const char *arg
, int hi
)
518 x
= strtol(arg
, &s
, 0);
519 if (errno
|| !*arg
|| *s
|| x
< 0 || x
> hi
)
520 errx(1, "%s: Illegal page number", arg
);
528 Warn(const char *locus
, const char *fmt
, ...)
534 asprintf(&s
, "%s: Warning: %s", locus
, fmt
);
543 * Display usage information.
548 fprintf(stderr
, "%s\n%s\n",
549 "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]",
550 " [-l file] [-o filename] [-P page] [-W page] file");