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 #define AOUT_H_FORCE32
31 #include <sys/param.h>
49 #define BTX_PATH "/sys/boot/i386/btx"
51 #define I_LDR 0 /* BTX loader */
52 #define I_BTX 1 /* BTX kernel */
53 #define I_CLNT 2 /* Client program */
55 #define F_BIN 0 /* Binary */
56 #define F_AOUT 1 /* ZMAGIC a.out */
57 #define F_ELF 2 /* 32-bit ELF */
58 #define F_CNT 3 /* Number of formats */
60 #define IMPURE 1 /* Writable text */
61 #define MAXU32 0xffffffff /* Maximum unsigned 32-bit quantity */
63 #define align(x, y) (((x) + (y) - 1) & ~((y) - 1))
66 uint32_t fmt
; /* Format */
67 uint32_t flags
; /* Bit flags */
68 uint32_t size
; /* Size of file */
69 uint32_t text
; /* Size of text segment */
70 uint32_t data
; /* Size of data segment */
71 uint32_t bss
; /* Size of bss segment */
72 uint32_t org
; /* Program origin */
73 uint32_t entry
; /* Program entry point */
76 static const char *const fmtlist
[] = {"bin", "aout", "elf"};
78 static const char binfo
[] =
79 "kernel: ver=%u.%02u size=%x load=%x entry=%x map=%uM "
81 static const char cinfo
[] =
82 "client: fmt=%s size=%x text=%x data=%x bss=%x entry=%x\n";
83 static const char oinfo
[] =
84 "output: fmt=%s size=%x text=%x data=%x org=%x entry=%x\n";
86 static const char *lname
=
87 BTX_PATH
"/btxldr/btxldr"; /* BTX loader */
88 static const char *bname
=
89 BTX_PATH
"/btx/btx"; /* BTX kernel */
90 static const char *oname
=
91 "a.out"; /* Output filename */
93 static int ppage
= -1; /* First page present */
94 static int wpage
= -1; /* First page writable */
96 static unsigned int format
; /* Output format */
98 static uint32_t centry
; /* Client entry address */
99 static uint32_t lentry
; /* Loader entry address */
101 static int Eflag
; /* Client entry option */
103 static int quiet
; /* Inhibit warnings */
104 static int verbose
; /* Display information */
106 static const char *tname
; /* Temporary output file */
107 static const char *fname
; /* Current input file */
109 static void cleanup(void);
110 static void btxld(const char *);
111 static void getbtx(int, struct btx_hdr
*);
112 static void gethdr(int, struct hdr
*);
113 static void puthdr(int, struct hdr
*);
114 static void copy(int, int, size_t, off_t
);
115 static size_t readx(int, void *, size_t, off_t
);
116 static void writex(int, const void *, size_t);
117 static void seekx(int, off_t
);
118 static unsigned int optfmt(const char *);
119 static uint32_t optaddr(const char *);
120 static int optpage(const char *, int);
121 static void Warn(const char *, const char *, ...);
122 static void usage(void);
125 * A link editor for BTX clients.
128 main(int argc
, char *argv
[])
132 while ((c
= getopt(argc
, argv
, "qvb:E:e:f:l:o:P:W:")) != -1)
144 centry
= optaddr(optarg
);
148 lentry
= optaddr(optarg
);
151 format
= optfmt(optarg
);
160 ppage
= optpage(optarg
, 1);
163 wpage
= optpage(optarg
, BTX_MAXCWR
);
178 * Clean up after errors.
188 * Read the input files; write the output file; display information.
191 btxld(const char *iname
)
193 char name
[FILENAME_MAX
];
195 struct hdr ihdr
, ohdr
;
196 unsigned int ldr_size
, cwr
;
201 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
202 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
203 if ((fdi
[i
] = open(fname
, O_RDONLY
)) == -1)
207 gethdr(fdi
[i
], &ihdr
);
208 if (ihdr
.fmt
!= F_BIN
)
209 Warn(fname
, "Loader format is %s; processing as %s",
210 fmtlist
[ihdr
.fmt
], fmtlist
[F_BIN
]);
211 ldr_size
= ihdr
.size
;
214 getbtx(fdi
[i
], &btx
);
217 gethdr(fdi
[i
], &ihdr
);
218 if (ihdr
.org
&& ihdr
.org
!= BTX_PGSIZE
)
220 "Client origin is 0x%x; expecting 0 or 0x%x",
221 ihdr
.org
, BTX_PGSIZE
);
224 memset(&ohdr
, 0, sizeof(ohdr
));
226 ohdr
.text
= ldr_size
;
227 ohdr
.data
= btx
.btx_textsz
+ ihdr
.size
;
231 if (wpage
> 0 || (wpage
== -1 && !(ihdr
.flags
& IMPURE
))) {
235 cwr
= howmany(ihdr
.text
, BTX_PGSIZE
);
236 if (cwr
> BTX_MAXCWR
)
240 if (ppage
> 0 || (ppage
&& wpage
&& ihdr
.org
>= BTX_PGSIZE
)) {
241 btx
.btx_flags
|= BTX_MAPONE
;
245 btx
.btx_pgctl
-= cwr
;
246 btx
.btx_entry
= Eflag
? centry
: ihdr
.entry
;
247 if (snprintf(name
, sizeof(name
), "%s.tmp", oname
) >= sizeof(name
))
248 errx(2, "%s: Filename too long", oname
);
249 if ((fdo
= open(name
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0666)) == -1)
251 if (!(tname
= strdup(name
)))
254 for (i
= I_LDR
; i
<= I_CLNT
; i
++) {
255 fname
= i
== I_LDR
? lname
: i
== I_BTX
? bname
: iname
;
258 copy(fdi
[i
], fdo
, ldr_size
, 0);
259 seekx(fdo
, ohdr
.size
+= ohdr
.text
);
262 writex(fdo
, &btx
, sizeof(btx
));
263 copy(fdi
[i
], fdo
, btx
.btx_textsz
- sizeof(btx
),
267 copy(fdi
[i
], fdo
, ihdr
.size
, 0);
268 if (ftruncate(fdo
, ohdr
.size
+= ohdr
.data
))
276 if (rename(tname
, oname
))
277 err(2, "%s: Can't rename to %s", tname
, oname
);
280 printf(binfo
, btx
.btx_majver
, btx
.btx_minver
, btx
.btx_textsz
,
281 BTX_ORIGIN(btx
), BTX_ENTRY(btx
), BTX_MAPPED(btx
) *
282 BTX_PGSIZE
/ 0x100000, !!(btx
.btx_flags
& BTX_MAPONE
),
283 BTX_MAPPED(btx
) - btx
.btx_pgctl
- BTX_PGBASE
/
284 BTX_PGSIZE
- BTX_MAPPED(btx
) * 4 / BTX_PGSIZE
);
285 printf(cinfo
, fmtlist
[ihdr
.fmt
], ihdr
.size
, ihdr
.text
,
286 ihdr
.data
, ihdr
.bss
, ihdr
.entry
);
287 printf(oinfo
, fmtlist
[ohdr
.fmt
], ohdr
.size
, ohdr
.text
,
288 ohdr
.data
, ohdr
.org
, ohdr
.entry
);
293 * Read BTX file header.
296 getbtx(int fd
, struct btx_hdr
* btx
)
298 if (readx(fd
, btx
, sizeof(*btx
), 0) != sizeof(*btx
) ||
299 btx
->btx_magic
[0] != BTX_MAG0
||
300 btx
->btx_magic
[1] != BTX_MAG1
||
301 btx
->btx_magic
[2] != BTX_MAG2
)
302 errx(1, "%s: Not a BTX kernel", fname
);
306 * Get file size and read a.out or ELF header.
309 gethdr(int fd
, struct hdr
*hdr
)
312 const struct exec
*ex
;
313 const Elf32_Ehdr
*ee
;
314 const Elf32_Phdr
*ep
;
316 unsigned int fmt
, x
, n
, i
;
318 memset(hdr
, 0, sizeof(*hdr
));
321 if (sb
.st_size
> MAXU32
)
322 errx(1, "%s: Too big", fname
);
323 hdr
->size
= sb
.st_size
;
324 if ((p
= mmap(NULL
, hdr
->size
, PROT_READ
, MAP_SHARED
, fd
,
327 for (fmt
= F_CNT
- 1; !hdr
->fmt
&& fmt
; fmt
--)
331 if (hdr
->size
>= sizeof(struct exec
) && !N_BADMAG(*ex
)) {
334 if (x
== OMAGIC
|| x
== NMAGIC
) {
336 Warn(fname
, "Treating %s NMAGIC as OMAGIC",
338 hdr
->flags
|= IMPURE
;
340 hdr
->text
= ex
->a_text
;
341 hdr
->data
= ex
->a_data
;
342 hdr
->bss
= ex
->a_bss
;
343 hdr
->entry
= ex
->a_entry
;
344 if (ex
->a_entry
>= BTX_PGSIZE
)
345 hdr
->org
= BTX_PGSIZE
;
350 if (hdr
->size
>= sizeof(Elf32_Ehdr
) && IS_ELF(*ee
)) {
352 for (n
= i
= 0; i
< ee
->e_phnum
; i
++) {
353 ep
= (void *)((uint8_t *)p
+ ee
->e_phoff
+
354 ee
->e_phentsize
* i
);
355 if (ep
->p_type
== PT_LOAD
)
358 hdr
->text
= ep
->p_filesz
;
359 hdr
->org
= ep
->p_paddr
;
360 if (ep
->p_flags
& PF_W
)
361 hdr
->flags
|= IMPURE
;
364 hdr
->data
= ep
->p_filesz
;
365 hdr
->bss
= ep
->p_memsz
- ep
->p_filesz
;
369 "Ignoring extra %s PT_LOAD segments",
373 hdr
->entry
= ee
->e_entry
;
376 if (munmap(p
, hdr
->size
))
381 * Write a.out or ELF header.
384 puthdr(int fd
, struct hdr
*hdr
)
391 memset(&ex
, 0, sizeof(ex
));
392 N_SETMAGIC(ex
, ZMAGIC
, MID_ZERO
, 0);
393 hdr
->text
= N_ALIGN(ex
, hdr
->text
);
394 ex
.a_text
= hdr
->text
;
395 hdr
->data
= N_ALIGN(ex
, hdr
->data
);
396 ex
.a_data
= hdr
->data
;
397 ex
.a_entry
= hdr
->entry
;
398 writex(fd
, &ex
, sizeof(ex
));
399 hdr
->size
= N_ALIGN(ex
, sizeof(ex
));
400 seekx(fd
, hdr
->size
);
404 eh
.e
.e_entry
= hdr
->entry
;
405 eh
.p
[0].p_vaddr
= eh
.p
[0].p_paddr
= hdr
->org
;
406 eh
.p
[0].p_filesz
= eh
.p
[0].p_memsz
= hdr
->text
;
407 eh
.p
[1].p_offset
= eh
.p
[0].p_offset
+ eh
.p
[0].p_filesz
;
408 eh
.p
[1].p_vaddr
= eh
.p
[1].p_paddr
= align(eh
.p
[0].p_paddr
+
410 eh
.p
[1].p_filesz
= eh
.p
[1].p_memsz
= hdr
->data
;
411 eh
.sh
[2].sh_addr
= eh
.p
[0].p_vaddr
;
412 eh
.sh
[2].sh_offset
= eh
.p
[0].p_offset
;
413 eh
.sh
[2].sh_size
= eh
.p
[0].p_filesz
;
414 eh
.sh
[3].sh_addr
= eh
.p
[1].p_vaddr
;
415 eh
.sh
[3].sh_offset
= eh
.p
[1].p_offset
;
416 eh
.sh
[3].sh_size
= eh
.p
[1].p_filesz
;
417 writex(fd
, &eh
, sizeof(eh
));
418 hdr
->size
= sizeof(eh
);
423 * Safe copy from input file to output file.
426 copy(int fdi
, int fdo
, size_t nbyte
, off_t offset
)
432 if ((n
= sizeof(buf
)) > nbyte
)
434 if (readx(fdi
, buf
, n
, offset
) != n
)
435 errx(2, "%s: Short read", fname
);
443 * Safe read from input file.
446 readx(int fd
, void *buf
, size_t nbyte
, off_t offset
)
450 if (offset
!= -1 && lseek(fd
, offset
, SEEK_SET
) != offset
)
452 if ((n
= read(fd
, buf
, nbyte
)) == -1)
458 * Safe write to output file.
461 writex(int fd
, const void *buf
, size_t nbyte
)
465 if ((n
= write(fd
, buf
, nbyte
)) == -1)
468 errx(2, "%s: Short write", tname
);
472 * Safe seek in output file.
475 seekx(int fd
, off_t offset
)
477 if (lseek(fd
, offset
, SEEK_SET
) != offset
)
482 * Convert an option argument to a format code.
485 optfmt(const char *arg
)
489 for (i
= 0; i
< F_CNT
&& strcmp(arg
, fmtlist
[i
]); i
++);
491 errx(1, "%s: Unknown format", arg
);
496 * Convert an option argument to an address.
499 optaddr(const char *arg
)
505 x
= strtoul(arg
, &s
, 0);
506 if (errno
|| !*arg
|| *s
|| x
> MAXU32
)
507 errx(1, "%s: Illegal address", arg
);
512 * Convert an option argument to a page number.
515 optpage(const char *arg
, int hi
)
521 x
= strtol(arg
, &s
, 0);
522 if (errno
|| !*arg
|| *s
|| x
< 0 || x
> hi
)
523 errx(1, "%s: Illegal page number", arg
);
531 Warn(const char *locus
, const char *fmt
, ...)
537 asprintf(&s
, "%s: Warning: %s", locus
, fmt
);
546 * Display usage information.
551 fprintf(stderr
, "%s\n%s\n",
552 "usage: btxld [-qv] [-b file] [-E address] [-e address] [-f format]",
553 " [-l file] [-o filename] [-P page] [-W page] file");