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 $
27 * $DragonFly: src/usr.sbin/btxld/btxld.c,v 1.3 2004/08/19 21:38:30 joerg Exp $
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 */
62 #define align(x, y) (((x) + (y) - 1) & ~((y) - 1))
65 uint32_t fmt
; /* Format */
66 uint32_t flags
; /* Bit flags */
67 uint32_t size
; /* Size of file */
68 uint32_t text
; /* Size of text segment */
69 uint32_t data
; /* Size of data segment */
70 uint32_t bss
; /* Size of bss segment */
71 uint32_t org
; /* Program origin */
72 uint32_t entry
; /* Program entry point */
75 static const char *const fmtlist
[] = {"bin", "aout", "elf"};
77 static const char binfo
[] =
78 "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM "
80 static const char cinfo
[] =
81 "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n";
82 static const char oinfo
[] =
83 "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n";
85 static const char *lname
=
86 BTX_PATH
"/btxldr/btxldr"; /* BTX loader */
87 static const char *bname
=
88 BTX_PATH
"/btx/btx"; /* BTX kernel */
89 static const char *oname
=
90 "a.out"; /* Output filename */
92 static int ppage
= -1; /* First page present */
93 static int wpage
= -1; /* First page writable */
95 static unsigned int format
; /* Output format */
97 static uint32_t centry
; /* Client entry address */
98 static uint32_t lentry
; /* Loader entry address */
100 static int Eflag
; /* Client entry option */
102 static int quiet
; /* Inhibit warnings */
103 static int verbose
; /* Display information */
105 static const char *tname
; /* Temporary output file */
106 static const char *fname
; /* Current input file */
108 static void cleanup(void);
109 static void btxld(const char *);
110 static void getbtx(int, struct btx_hdr
*);
111 static void gethdr(int, struct hdr
*);
112 static void puthdr(int, struct hdr
*);
113 static void copy(int, int, size_t, off_t
);
114 static size_t readx(int, void *, size_t, off_t
);
115 static void writex(int, const void *, size_t);
116 static void seekx(int, off_t
);
117 static unsigned int optfmt(const char *);
118 static uint32_t optaddr(const char *);
119 static int optpage(const char *, int);
120 static void Warn(const char *, const char *, ...);
121 static void usage(void);
124 * A link editor for BTX clients.
127 main(int argc
, char *argv
[])
131 while ((c
= getopt(argc
, argv
, "qvb:E:e:f:l:o:P:W:")) != -1)
143 centry
= optaddr(optarg
);
147 lentry
= optaddr(optarg
);
150 format
= optfmt(optarg
);
159 ppage
= optpage(optarg
, 1);
162 wpage
= optpage(optarg
, BTX_MAXCWR
);
177 * Clean up after errors.
187 * Read the input files; write the output file; display information.
190 btxld(const char *iname
)
192 char name
[FILENAME_MAX
];
194 struct hdr ihdr
, ohdr
;
195 unsigned int ldr_size
, cwr
;
200 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
201 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
202 if ((fdi
[i
] = open(fname
, O_RDONLY
)) == -1)
206 gethdr(fdi
[i
], &ihdr
);
207 if (ihdr
.fmt
!= F_BIN
)
208 Warn(fname
, "Loader format is %s; processing as %s",
209 fmtlist
[ihdr
.fmt
], fmtlist
[F_BIN
]);
210 ldr_size
= ihdr
.size
;
213 getbtx(fdi
[i
], &btx
);
216 gethdr(fdi
[i
], &ihdr
);
217 if (ihdr
.org
&& ihdr
.org
!= BTX_PGSIZE
)
219 "Client origin is 0x%x; expecting 0 or 0x%x",
220 ihdr
.org
, BTX_PGSIZE
);
223 memset(&ohdr
, 0, sizeof(ohdr
));
225 ohdr
.text
= ldr_size
;
226 ohdr
.data
= btx
.btx_textsz
+ ihdr
.size
;
230 if (wpage
> 0 || (wpage
== -1 && !(ihdr
.flags
& IMPURE
))) {
234 cwr
= howmany(ihdr
.text
, BTX_PGSIZE
);
235 if (cwr
> BTX_MAXCWR
)
239 if (ppage
> 0 || (ppage
&& wpage
&& ihdr
.org
>= BTX_PGSIZE
)) {
240 btx
.btx_flags
|= BTX_MAPONE
;
244 btx
.btx_pgctl
-= cwr
;
245 btx
.btx_entry
= Eflag
? centry
: ihdr
.entry
;
246 if (snprintf(name
, sizeof(name
), "%s.tmp", oname
) >= sizeof(name
))
247 errx(2, "%s: Filename too long", oname
);
248 if ((fdo
= open(name
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666)) == -1)
250 if (!(tname
= strdup(name
)))
253 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
254 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
257 copy(fdi
[i
], fdo
, ldr_size
, 0);
258 seekx(fdo
, ohdr
.size
+= ohdr
.text
);
261 writex(fdo
, &btx
, sizeof(btx
));
262 copy(fdi
[i
], fdo
, btx
.btx_textsz
- sizeof(btx
),
266 copy(fdi
[i
], fdo
, ihdr
.size
, 0);
267 if (ftruncate(fdo
, ohdr
.size
+= ohdr
.data
))
275 if (rename(tname
, oname
))
276 err(2, "%s: Can't rename to %s", tname
, oname
);
279 printf(binfo
, btx
.btx_majver
, btx
.btx_minver
, btx
.btx_textsz
,
280 BTX_ORIGIN(btx
), BTX_ENTRY(btx
), BTX_MAPPED(btx
) *
281 BTX_PGSIZE
/ 0x100000, !!(btx
.btx_flags
& BTX_MAPONE
),
282 BTX_MAPPED(btx
) - btx
.btx_pgctl
- BTX_PGBASE
/
283 BTX_PGSIZE
- BTX_MAPPED(btx
) * 4 / BTX_PGSIZE
);
284 printf(cinfo
, fmtlist
[ihdr
.fmt
], ihdr
.size
, ihdr
.text
,
285 ihdr
.data
, ihdr
.bss
, ihdr
.entry
);
286 printf(oinfo
, fmtlist
[ohdr
.fmt
], ohdr
.size
, ohdr
.text
,
287 ohdr
.data
, ohdr
.org
, ohdr
.entry
);
292 * Read BTX file header.
295 getbtx(int fd
, struct btx_hdr
* btx
)
297 if (readx(fd
, btx
, sizeof(*btx
), 0) != sizeof(*btx
) ||
298 btx
->btx_magic
[0] != BTX_MAG0
||
299 btx
->btx_magic
[1] != BTX_MAG1
||
300 btx
->btx_magic
[2] != BTX_MAG2
)
301 errx(1, "%s: Not a BTX kernel", fname
);
305 * Get file size and read a.out or ELF header.
308 gethdr(int fd
, struct hdr
*hdr
)
311 const struct exec
*ex
;
312 const Elf32_Ehdr
*ee
;
313 const Elf32_Phdr
*ep
;
315 unsigned int fmt
, x
, n
, i
;
317 memset(hdr
, 0, sizeof(*hdr
));
320 if (sb
.st_size
> MAXU32
)
321 errx(1, "%s: Too big", fname
);
322 hdr
->size
= sb
.st_size
;
323 if ((p
= mmap(NULL
, hdr
->size
, PROT_READ
, MAP_SHARED
, fd
,
326 for (fmt
= F_CNT
- 1; !hdr
->fmt
&& fmt
; fmt
--)
330 if (hdr
->size
>= sizeof(struct exec
) && !N_BADMAG(*ex
)) {
333 if (x
== OMAGIC
|| x
== NMAGIC
) {
335 Warn(fname
, "Treating %s NMAGIC as OMAGIC",
337 hdr
->flags
|= IMPURE
;
339 hdr
->text
= ex
->a_text
;
340 hdr
->data
= ex
->a_data
;
341 hdr
->bss
= ex
->a_bss
;
342 hdr
->entry
= ex
->a_entry
;
343 if (ex
->a_entry
>= BTX_PGSIZE
)
344 hdr
->org
= BTX_PGSIZE
;
349 if (hdr
->size
>= sizeof(Elf32_Ehdr
) && IS_ELF(*ee
)) {
351 for (n
= i
= 0; i
< ee
->e_phnum
; i
++) {
352 ep
= (void *)((uint8_t *)p
+ ee
->e_phoff
+
353 ee
->e_phentsize
* i
);
354 if (ep
->p_type
== PT_LOAD
)
357 hdr
->text
= ep
->p_filesz
;
358 hdr
->org
= ep
->p_paddr
;
359 if (ep
->p_flags
& PF_W
)
360 hdr
->flags
|= IMPURE
;
363 hdr
->data
= ep
->p_filesz
;
364 hdr
->bss
= ep
->p_memsz
- ep
->p_filesz
;
368 "Ignoring extra %s PT_LOAD segments",
372 hdr
->entry
= ee
->e_entry
;
375 if (munmap(p
, hdr
->size
))
380 * Write a.out or ELF header.
383 puthdr(int fd
, struct hdr
*hdr
)
390 memset(&ex
, 0, sizeof(ex
));
391 N_SETMAGIC(ex
, ZMAGIC
, MID_ZERO
, 0);
392 hdr
->text
= N_ALIGN(ex
, hdr
->text
);
393 ex
.a_text
= hdr
->text
;
394 hdr
->data
= N_ALIGN(ex
, hdr
->data
);
395 ex
.a_data
= hdr
->data
;
396 ex
.a_entry
= hdr
->entry
;
397 writex(fd
, &ex
, sizeof(ex
));
398 hdr
->size
= N_ALIGN(ex
, sizeof(ex
));
399 seekx(fd
, hdr
->size
);
403 eh
.e
.e_entry
= hdr
->entry
;
404 eh
.p
[0].p_vaddr
= eh
.p
[0].p_paddr
= hdr
->org
;
405 eh
.p
[0].p_filesz
= eh
.p
[0].p_memsz
= hdr
->text
;
406 eh
.p
[1].p_offset
= eh
.p
[0].p_offset
+ eh
.p
[0].p_filesz
;
407 eh
.p
[1].p_vaddr
= eh
.p
[1].p_paddr
= align(eh
.p
[0].p_paddr
+
409 eh
.p
[1].p_filesz
= eh
.p
[1].p_memsz
= hdr
->data
;
410 eh
.sh
[2].sh_addr
= eh
.p
[0].p_vaddr
;
411 eh
.sh
[2].sh_offset
= eh
.p
[0].p_offset
;
412 eh
.sh
[2].sh_size
= eh
.p
[0].p_filesz
;
413 eh
.sh
[3].sh_addr
= eh
.p
[1].p_vaddr
;
414 eh
.sh
[3].sh_offset
= eh
.p
[1].p_offset
;
415 eh
.sh
[3].sh_size
= eh
.p
[1].p_filesz
;
416 writex(fd
, &eh
, sizeof(eh
));
417 hdr
->size
= sizeof(eh
);
422 * Safe copy from input file to output file.
425 copy(int fdi
, int fdo
, size_t nbyte
, off_t offset
)
431 if ((n
= sizeof(buf
)) > nbyte
)
433 if (readx(fdi
, buf
, n
, offset
) != n
)
434 errx(2, "%s: Short read", fname
);
442 * Safe read from input file.
445 readx(int fd
, void *buf
, size_t nbyte
, off_t offset
)
449 if (offset
!= -1 && lseek(fd
, offset
, SEEK_SET
) != offset
)
451 if ((n
= read(fd
, buf
, nbyte
)) == -1)
457 * Safe write to output file.
460 writex(int fd
, const void *buf
, size_t nbyte
)
464 if ((n
= write(fd
, buf
, nbyte
)) == -1)
467 errx(2, "%s: Short write", tname
);
471 * Safe seek in output file.
474 seekx(int fd
, off_t offset
)
476 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
481 * Convert an option argument to a format code.
484 optfmt(const char *arg
)
488 for (i
= 0; i
< F_CNT
&& strcmp(arg
, fmtlist
[i
]); i
++);
490 errx(1, "%s: Unknown format", arg
);
495 * Convert an option argument to an address.
498 optaddr(const char *arg
)
504 x
= strtoul(arg
, &s
, 0);
505 if (errno
|| !*arg
|| *s
|| x
> MAXU32
)
506 errx(1, "%s: Illegal address", arg
);
511 * Convert an option argument to a page number.
514 optpage(const char *arg
, int hi
)
520 x
= strtol(arg
, &s
, 0);
521 if (errno
|| !*arg
|| *s
|| x
< 0 || x
> hi
)
522 errx(1, "%s: Illegal page number", arg
);
530 Warn(const char *locus
, const char *fmt
, ...)
536 asprintf(&s
, "%s: Warning: %s", locus
, fmt
);
545 * Display usage information.
550 fprintf(stderr
, "%s\n%s\n",
551 "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]",
552 " [-l file] [-o filename] [-P page] [-W page] file");