elf2ecoff.c revision 1.26 1 1.26 tsutsui /* $NetBSD: elf2ecoff.c,v 1.26 2009/12/19 10:27:13 tsutsui Exp $ */
2 1.2 jonathan
3 1.1 jonathan /*
4 1.8 jonathan * Copyright (c) 1997 Jonathan Stone
5 1.8 jonathan * All rights reserved.
6 1.1 jonathan * Copyright (c) 1995
7 1.1 jonathan * Ted Lemon (hereinafter referred to as the author)
8 1.1 jonathan *
9 1.1 jonathan * Redistribution and use in source and binary forms, with or without
10 1.1 jonathan * modification, are permitted provided that the following conditions
11 1.1 jonathan * are met:
12 1.1 jonathan * 1. Redistributions of source code must retain the above copyright
13 1.1 jonathan * notice, this list of conditions and the following disclaimer.
14 1.1 jonathan * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 jonathan * notice, this list of conditions and the following disclaimer in the
16 1.1 jonathan * documentation and/or other materials provided with the distribution.
17 1.1 jonathan * 3. The name of the author may not be used to endorse or promote products
18 1.1 jonathan * derived from this software without specific prior written permission.
19 1.1 jonathan *
20 1.1 jonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
21 1.1 jonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.1 jonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.1 jonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
24 1.1 jonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.1 jonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.1 jonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.1 jonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.1 jonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.1 jonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.1 jonathan * SUCH DAMAGE.
31 1.1 jonathan */
32 1.1 jonathan
33 1.1 jonathan /* elf2ecoff.c
34 1.1 jonathan
35 1.1 jonathan This program converts an elf executable to an ECOFF executable.
36 1.1 jonathan No symbol table is retained. This is useful primarily in building
37 1.1 jonathan net-bootable kernels for machines (e.g., DECstation and Alpha) which
38 1.1 jonathan only support the ECOFF object file format. */
39 1.1 jonathan
40 1.21 lukem #if HAVE_NBTOOL_CONFIG_H
41 1.21 lukem #include "nbtool_config.h"
42 1.20 tv #endif
43 1.20 tv
44 1.1 jonathan #include <sys/types.h>
45 1.11 simonb #include <err.h>
46 1.12 kleink #include <errno.h>
47 1.1 jonathan #include <fcntl.h>
48 1.1 jonathan #include <unistd.h>
49 1.3 jonathan #include <sys/exec_elf.h>
50 1.1 jonathan #include <stdio.h>
51 1.1 jonathan #include <sys/exec_ecoff.h>
52 1.6 jonathan #include <stdlib.h>
53 1.1 jonathan #include <string.h>
54 1.1 jonathan #include <limits.h>
55 1.3 jonathan
56 1.6 jonathan #define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
57 1.6 jonathan
58 1.1 jonathan struct sect {
59 1.9 lukem unsigned long vaddr;
60 1.9 lukem unsigned long len;
61 1.1 jonathan };
62 1.1 jonathan
63 1.8 jonathan struct elf_syms {
64 1.9 lukem int nsymbols;
65 1.8 jonathan Elf32_Sym *elf_syms;
66 1.9 lukem off_t stringsize;
67 1.9 lukem char *stringtab;
68 1.8 jonathan };
69 1.8 jonathan
70 1.8 jonathan struct ecoff_syms {
71 1.9 lukem int nsymbols;
72 1.8 jonathan struct ecoff_extsym *ecoff_syms;
73 1.9 lukem off_t stringsize;
74 1.9 lukem char *stringtab;
75 1.8 jonathan };
76 1.8 jonathan
77 1.9 lukem int debug = 0;
78 1.6 jonathan
79 1.9 lukem int phcmp(Elf32_Phdr * h1, Elf32_Phdr * h2);
80 1.6 jonathan
81 1.8 jonathan
82 1.23 tsutsui char *saveRead(int file, off_t offset, off_t len, const char *name);
83 1.23 tsutsui void safewrite(int outfile, const void *buf, off_t len, const char *msg);
84 1.9 lukem void copy(int, int, off_t, off_t);
85 1.9 lukem void combine(struct sect * base, struct sect * new, int paddable);
86 1.9 lukem void translate_syms(struct elf_syms *, struct ecoff_syms *);
87 1.9 lukem void
88 1.9 lukem elf_symbol_table_to_ecoff(int out, int in,
89 1.9 lukem struct ecoff_exechdr * ep,
90 1.9 lukem off_t symoff, off_t symsize,
91 1.9 lukem off_t stroff, off_t strsize);
92 1.9 lukem
93 1.9 lukem
94 1.9 lukem int
95 1.9 lukem make_ecoff_section_hdrs(struct ecoff_exechdr * ep,
96 1.9 lukem struct ecoff_scnhdr * esecs);
97 1.9 lukem
98 1.9 lukem void
99 1.9 lukem write_ecoff_symhdr(int outfile, struct ecoff_exechdr * ep,
100 1.9 lukem struct ecoff_symhdr * symhdrp,
101 1.9 lukem long nesyms, long extsymoff, long extstroff,
102 1.9 lukem long strsize);
103 1.8 jonathan
104 1.9 lukem void pad16(int fd, int size, const char *msg);
105 1.22 simonb void bswap32_region(int32_t* , int);
106 1.6 jonathan
107 1.9 lukem int *symTypeTable;
108 1.16 bouyer int needswap;
109 1.1 jonathan
110 1.8 jonathan
111 1.8 jonathan
112 1.8 jonathan
113 1.8 jonathan void
114 1.9 lukem elf_read_syms(struct elf_syms * elfsymsp, int infile,
115 1.9 lukem off_t symoff, off_t symsize, off_t stroff, off_t strsize);
116 1.8 jonathan
117 1.8 jonathan
118 1.6 jonathan int
119 1.9 lukem main(int argc, char **argv, char **envp)
120 1.1 jonathan {
121 1.9 lukem Elf32_Ehdr ex;
122 1.9 lukem Elf32_Phdr *ph;
123 1.9 lukem Elf32_Shdr *sh;
124 1.9 lukem char *shstrtab;
125 1.9 lukem int strtabix, symtabix;
126 1.23 tsutsui size_t i;
127 1.23 tsutsui int pad;
128 1.9 lukem struct sect text, data, bss; /* a.out-compatible sections */
129 1.9 lukem struct sect rdata, sdata, sbss; /* ECOFF-only sections */
130 1.9 lukem
131 1.9 lukem struct ecoff_exechdr ep;
132 1.9 lukem struct ecoff_scnhdr esecs[6];
133 1.9 lukem struct ecoff_symhdr symhdr;
134 1.9 lukem
135 1.9 lukem int infile, outfile;
136 1.9 lukem unsigned long cur_vma = ULONG_MAX;
137 1.9 lukem int symflag = 0;
138 1.9 lukem int nsecs = 0;
139 1.16 bouyer int mipsel;
140 1.16 bouyer
141 1.9 lukem
142 1.9 lukem text.len = data.len = bss.len = 0;
143 1.9 lukem text.vaddr = data.vaddr = bss.vaddr = 0;
144 1.9 lukem
145 1.9 lukem rdata.len = sdata.len = sbss.len = 0;
146 1.9 lukem rdata.vaddr = sdata.vaddr = sbss.vaddr = 0;
147 1.9 lukem
148 1.9 lukem /* Check args... */
149 1.9 lukem if (argc < 3 || argc > 4) {
150 1.9 lukem usage:
151 1.9 lukem fprintf(stderr,
152 1.9 lukem "usage: elf2ecoff <elf executable> <ECOFF executable> [-s]\n");
153 1.9 lukem exit(1);
154 1.9 lukem }
155 1.9 lukem if (argc == 4) {
156 1.9 lukem if (strcmp(argv[3], "-s"))
157 1.9 lukem goto usage;
158 1.9 lukem symflag = 1;
159 1.1 jonathan }
160 1.9 lukem /* Try the input file... */
161 1.9 lukem if ((infile = open(argv[1], O_RDONLY)) < 0) {
162 1.9 lukem fprintf(stderr, "Can't open %s for read: %s\n",
163 1.9 lukem argv[1], strerror(errno));
164 1.9 lukem exit(1);
165 1.9 lukem }
166 1.9 lukem /* Read the header, which is at the beginning of the file... */
167 1.9 lukem i = read(infile, &ex, sizeof ex);
168 1.9 lukem if (i != sizeof ex) {
169 1.9 lukem fprintf(stderr, "ex: %s: %s.\n",
170 1.9 lukem argv[1], i ? strerror(errno) : "End of file reached");
171 1.9 lukem exit(1);
172 1.9 lukem }
173 1.16 bouyer if (ex.e_ident[EI_DATA] == ELFDATA2LSB)
174 1.16 bouyer mipsel = 1;
175 1.16 bouyer else if (ex.e_ident[EI_DATA] == ELFDATA2MSB)
176 1.16 bouyer mipsel = 0;
177 1.16 bouyer else {
178 1.16 bouyer fprintf(stderr, "invalid ELF byte order %d\n",
179 1.16 bouyer ex.e_ident[EI_DATA]);
180 1.16 bouyer exit(1);
181 1.16 bouyer }
182 1.16 bouyer #if BYTE_ORDER == BIG_ENDIAN
183 1.16 bouyer if (mipsel)
184 1.16 bouyer needswap = 1;
185 1.16 bouyer else
186 1.16 bouyer needswap = 0;
187 1.16 bouyer #elif BYTE_ORDER == LITTLE_ENDIAN
188 1.16 bouyer if (mipsel)
189 1.16 bouyer needswap = 0;
190 1.16 bouyer else
191 1.16 bouyer needswap = 1;
192 1.16 bouyer #else
193 1.16 bouyer #error "unknown endian"
194 1.16 bouyer #endif
195 1.16 bouyer
196 1.16 bouyer if (needswap) {
197 1.16 bouyer ex.e_type = bswap16(ex.e_type);
198 1.16 bouyer ex.e_machine = bswap16(ex.e_machine);
199 1.16 bouyer ex.e_version = bswap32(ex.e_version);
200 1.16 bouyer ex.e_entry = bswap32(ex.e_entry);
201 1.16 bouyer ex.e_phoff = bswap32(ex.e_phoff);
202 1.16 bouyer ex.e_shoff = bswap32(ex.e_shoff);
203 1.16 bouyer ex.e_flags = bswap32(ex.e_flags);
204 1.16 bouyer ex.e_ehsize = bswap16(ex.e_ehsize);
205 1.16 bouyer ex.e_phentsize = bswap16(ex.e_phentsize);
206 1.16 bouyer ex.e_phnum = bswap16(ex.e_phnum);
207 1.16 bouyer ex.e_shentsize = bswap16(ex.e_shentsize);
208 1.16 bouyer ex.e_shnum = bswap16(ex.e_shnum);
209 1.16 bouyer ex.e_shstrndx = bswap16(ex.e_shstrndx);
210 1.16 bouyer }
211 1.16 bouyer
212 1.9 lukem /* Read the program headers... */
213 1.9 lukem ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff,
214 1.9 lukem ex.e_phnum * sizeof(Elf32_Phdr), "ph");
215 1.16 bouyer if (needswap)
216 1.22 simonb bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum);
217 1.9 lukem /* Read the section headers... */
218 1.9 lukem sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff,
219 1.9 lukem ex.e_shnum * sizeof(Elf32_Shdr), "sh");
220 1.16 bouyer if (needswap)
221 1.22 simonb bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum);
222 1.16 bouyer
223 1.9 lukem /* Read in the section string table. */
224 1.9 lukem shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset,
225 1.9 lukem sh[ex.e_shstrndx].sh_size, "shstrtab");
226 1.9 lukem
227 1.9 lukem
228 1.9 lukem /* Look for the symbol table and string table... Also map section
229 1.9 lukem * indices to symbol types for a.out */
230 1.9 lukem symtabix = 0;
231 1.9 lukem strtabix = 0;
232 1.9 lukem for (i = 0; i < ex.e_shnum; i++) {
233 1.9 lukem char *name = shstrtab + sh[i].sh_name;
234 1.9 lukem if (!strcmp(name, ".symtab"))
235 1.9 lukem symtabix = i;
236 1.9 lukem else
237 1.9 lukem if (!strcmp(name, ".strtab"))
238 1.9 lukem strtabix = i;
239 1.1 jonathan
240 1.9 lukem }
241 1.6 jonathan
242 1.9 lukem /* Figure out if we can cram the program header into an ECOFF
243 1.9 lukem * header... Basically, we can't handle anything but loadable
244 1.9 lukem * segments, but we can ignore some kinds of segments. We can't
245 1.9 lukem * handle holes in the address space. Segments may be out of order,
246 1.9 lukem * so we sort them first. */
247 1.9 lukem
248 1.9 lukem qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr),
249 1.9 lukem (int (*) (const void *, const void *)) phcmp);
250 1.9 lukem
251 1.9 lukem for (i = 0; i < ex.e_phnum; i++) {
252 1.9 lukem /* Section types we can ignore... */
253 1.13 drochner if (ph[i].p_type == PT_NULL || ph[i].p_type == PT_NOTE ||
254 1.13 drochner ph[i].p_type == PT_PHDR ||
255 1.13 drochner ph[i].p_type == PT_MIPS_REGINFO) {
256 1.9 lukem
257 1.9 lukem if (debug) {
258 1.26 tsutsui fprintf(stderr, " skipping PH %zu type %d flags 0x%x\n",
259 1.9 lukem i, ph[i].p_type, ph[i].p_flags);
260 1.9 lukem }
261 1.9 lukem continue;
262 1.9 lukem }
263 1.9 lukem /* Section types we can't handle... */
264 1.9 lukem else
265 1.13 drochner if (ph[i].p_type != PT_LOAD) {
266 1.26 tsutsui fprintf(stderr, "Program header %zu type %d can't be converted.\n",
267 1.9 lukem i, ph[i].p_type);
268 1.9 lukem exit(1);
269 1.9 lukem }
270 1.9 lukem /* Writable (data) segment? */
271 1.9 lukem if (ph[i].p_flags & PF_W) {
272 1.9 lukem struct sect ndata, nbss;
273 1.9 lukem
274 1.9 lukem ndata.vaddr = ph[i].p_vaddr;
275 1.9 lukem ndata.len = ph[i].p_filesz;
276 1.9 lukem nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz;
277 1.9 lukem nbss.len = ph[i].p_memsz - ph[i].p_filesz;
278 1.9 lukem
279 1.9 lukem if (debug) {
280 1.9 lukem fprintf(stderr,
281 1.26 tsutsui " combinining PH %zu type %d flags 0x%x with data, ndata = %ld, nbss =%ld\n", i, ph[i].p_type, ph[i].p_flags, ndata.len, nbss.len);
282 1.9 lukem }
283 1.9 lukem combine(&data, &ndata, 0);
284 1.9 lukem combine(&bss, &nbss, 1);
285 1.9 lukem } else {
286 1.9 lukem struct sect ntxt;
287 1.9 lukem
288 1.9 lukem ntxt.vaddr = ph[i].p_vaddr;
289 1.9 lukem ntxt.len = ph[i].p_filesz;
290 1.9 lukem if (debug) {
291 1.9 lukem
292 1.9 lukem fprintf(stderr,
293 1.26 tsutsui " combinining PH %zu type %d flags 0x%x with text, len = %ld\n",
294 1.9 lukem i, ph[i].p_type, ph[i].p_flags, ntxt.len);
295 1.9 lukem }
296 1.9 lukem combine(&text, &ntxt, 0);
297 1.9 lukem }
298 1.9 lukem /* Remember the lowest segment start address. */
299 1.9 lukem if (ph[i].p_vaddr < cur_vma)
300 1.9 lukem cur_vma = ph[i].p_vaddr;
301 1.1 jonathan }
302 1.1 jonathan
303 1.9 lukem /* Sections must be in order to be converted... */
304 1.9 lukem if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr ||
305 1.9 lukem text.vaddr + text.len > data.vaddr || data.vaddr + data.len > bss.vaddr) {
306 1.9 lukem fprintf(stderr, "Sections ordering prevents a.out conversion.\n");
307 1.9 lukem exit(1);
308 1.9 lukem }
309 1.9 lukem /* If there's a data section but no text section, then the loader
310 1.9 lukem * combined everything into one section. That needs to be the text
311 1.9 lukem * section, so just make the data section zero length following text. */
312 1.9 lukem if (data.len && !text.len) {
313 1.9 lukem text = data;
314 1.9 lukem data.vaddr = text.vaddr + text.len;
315 1.9 lukem data.len = 0;
316 1.9 lukem }
317 1.9 lukem /* If there is a gap between text and data, we'll fill it when we copy
318 1.9 lukem * the data, so update the length of the text segment as represented
319 1.9 lukem * in a.out to reflect that, since a.out doesn't allow gaps in the
320 1.9 lukem * program address space. */
321 1.9 lukem if (text.vaddr + text.len < data.vaddr)
322 1.9 lukem text.len = data.vaddr - text.vaddr;
323 1.9 lukem
324 1.9 lukem /* We now have enough information to cons up an a.out header... */
325 1.9 lukem ep.a.magic = ECOFF_OMAGIC;
326 1.9 lukem ep.a.vstamp = 2 * 256 + 10; /* compatible with version 2.10 */
327 1.9 lukem ep.a.tsize = text.len;
328 1.9 lukem ep.a.dsize = data.len;
329 1.9 lukem ep.a.bsize = bss.len;
330 1.9 lukem ep.a.entry = ex.e_entry;
331 1.9 lukem ep.a.text_start = text.vaddr;
332 1.9 lukem ep.a.data_start = data.vaddr;
333 1.9 lukem ep.a.bss_start = bss.vaddr;
334 1.9 lukem ep.a.gprmask = 0xf3fffffe;
335 1.10 perry memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask);
336 1.9 lukem ep.a.gp_value = 0; /* unused. */
337 1.9 lukem
338 1.16 bouyer if (mipsel)
339 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEL;
340 1.16 bouyer else
341 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEB;
342 1.15 bouyer
343 1.9 lukem ep.f.f_nscns = 6;
344 1.9 lukem ep.f.f_timdat = 0; /* bogus */
345 1.9 lukem ep.f.f_symptr = 0;
346 1.9 lukem ep.f.f_nsyms = sizeof(struct ecoff_symhdr);
347 1.9 lukem ep.f.f_opthdr = sizeof ep.a;
348 1.9 lukem ep.f.f_flags = 0x100f; /* Stripped, not sharable. */
349 1.9 lukem
350 1.10 perry memset(esecs, 0, sizeof(esecs));
351 1.9 lukem
352 1.9 lukem /* Make ECOFF section headers, with empty stubs for
353 1.9 lukem * .rdata/.sdata/.sbss. */
354 1.9 lukem make_ecoff_section_hdrs(&ep, esecs);
355 1.9 lukem
356 1.9 lukem nsecs = ep.f.f_nscns;
357 1.9 lukem
358 1.16 bouyer if (needswap) {
359 1.16 bouyer ep.f.f_magic = bswap16(ep.f.f_magic);
360 1.16 bouyer ep.f.f_nscns = bswap16(ep.f.f_nscns);
361 1.16 bouyer ep.f.f_timdat = bswap32(ep.f.f_timdat);
362 1.16 bouyer ep.f.f_symptr = bswap32(ep.f.f_symptr);
363 1.16 bouyer ep.f.f_nsyms = bswap32(ep.f.f_nsyms);
364 1.16 bouyer ep.f.f_opthdr = bswap16(ep.f.f_opthdr);
365 1.16 bouyer ep.f.f_flags = bswap16(ep.f.f_flags);
366 1.16 bouyer ep.a.magic = bswap16(ep.a.magic);
367 1.16 bouyer ep.a.vstamp = bswap16(ep.a.vstamp);
368 1.16 bouyer ep.a.tsize = bswap32(ep.a.tsize);
369 1.16 bouyer ep.a.dsize = bswap32(ep.a.dsize);
370 1.16 bouyer ep.a.bsize = bswap32(ep.a.bsize);
371 1.16 bouyer ep.a.entry = bswap32(ep.a.entry);
372 1.16 bouyer ep.a.text_start = bswap32(ep.a.text_start);
373 1.16 bouyer ep.a.data_start = bswap32(ep.a.data_start);
374 1.16 bouyer ep.a.bss_start = bswap32(ep.a.bss_start);
375 1.16 bouyer ep.a.gprmask = bswap32(ep.a.gprmask);
376 1.22 simonb bswap32_region((int32_t*)ep.a.cprmask, sizeof(ep.a.cprmask));
377 1.16 bouyer ep.a.gp_value = bswap32(ep.a.gp_value);
378 1.16 bouyer for (i = 0; i < sizeof(esecs) / sizeof(esecs[0]); i++) {
379 1.16 bouyer esecs[i].s_paddr = bswap32(esecs[i].s_paddr);
380 1.16 bouyer esecs[i].s_vaddr = bswap32(esecs[i].s_vaddr);
381 1.16 bouyer esecs[i].s_size = bswap32(esecs[i].s_size);
382 1.16 bouyer esecs[i].s_scnptr = bswap32(esecs[i].s_scnptr);
383 1.16 bouyer esecs[i].s_relptr = bswap32(esecs[i].s_relptr);
384 1.16 bouyer esecs[i].s_lnnoptr = bswap32(esecs[i].s_lnnoptr);
385 1.16 bouyer esecs[i].s_nreloc = bswap16(esecs[i].s_nreloc);
386 1.16 bouyer esecs[i].s_nlnno = bswap16(esecs[i].s_nlnno);
387 1.16 bouyer esecs[i].s_flags = bswap32(esecs[i].s_flags);
388 1.16 bouyer }
389 1.16 bouyer }
390 1.16 bouyer
391 1.9 lukem /* Make the output file... */
392 1.9 lukem if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) {
393 1.9 lukem fprintf(stderr, "Unable to create %s: %s\n", argv[2], strerror(errno));
394 1.9 lukem exit(1);
395 1.9 lukem }
396 1.11 simonb /* Truncate file... */
397 1.11 simonb if (ftruncate(outfile, 0)) {
398 1.11 simonb warn("ftruncate %s", argv[2]);
399 1.11 simonb }
400 1.9 lukem /* Write the headers... */
401 1.9 lukem safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write: %s\n");
402 1.11 simonb if (debug)
403 1.24 matt fprintf(stderr, "wrote %zu byte file header.\n", sizeof(ep.f));
404 1.9 lukem
405 1.9 lukem safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write: %s\n");
406 1.11 simonb if (debug)
407 1.24 matt fprintf(stderr, "wrote %zu byte a.out header.\n", sizeof(ep.a));
408 1.9 lukem
409 1.9 lukem safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs,
410 1.9 lukem "esecs: write: %s\n");
411 1.11 simonb if (debug)
412 1.24 matt fprintf(stderr, "wrote %zu bytes of section headers.\n",
413 1.11 simonb sizeof(esecs[0]) * nsecs);
414 1.9 lukem
415 1.9 lukem
416 1.9 lukem pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15);
417 1.9 lukem if (pad) {
418 1.9 lukem pad = 16 - pad;
419 1.9 lukem pad16(outfile, pad, "ipad: write: %s\n");
420 1.11 simonb if (debug)
421 1.11 simonb fprintf(stderr, "wrote %d byte pad.\n", pad);
422 1.9 lukem }
423 1.9 lukem /* Copy the loadable sections. Zero-fill any gaps less than 64k;
424 1.9 lukem * complain about any zero-filling, and die if we're asked to
425 1.9 lukem * zero-fill more than 64k. */
426 1.9 lukem for (i = 0; i < ex.e_phnum; i++) {
427 1.9 lukem /* Unprocessable sections were handled above, so just verify
428 1.9 lukem * that the section can be loaded before copying. */
429 1.13 drochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) {
430 1.9 lukem if (cur_vma != ph[i].p_vaddr) {
431 1.9 lukem unsigned long gap = ph[i].p_vaddr - cur_vma;
432 1.9 lukem char obuf[1024];
433 1.9 lukem if (gap > 65536) {
434 1.9 lukem fprintf(stderr, "Intersegment gap (%ld bytes) too large.\n",
435 1.9 lukem gap);
436 1.9 lukem exit(1);
437 1.9 lukem }
438 1.11 simonb if (debug)
439 1.11 simonb fprintf(stderr, "Warning: %ld byte intersegment gap.\n", gap);
440 1.9 lukem memset(obuf, 0, sizeof obuf);
441 1.9 lukem while (gap) {
442 1.9 lukem int count = write(outfile, obuf, (gap > sizeof obuf
443 1.9 lukem ? sizeof obuf : gap));
444 1.9 lukem if (count < 0) {
445 1.9 lukem fprintf(stderr, "Error writing gap: %s\n",
446 1.9 lukem strerror(errno));
447 1.9 lukem exit(1);
448 1.9 lukem }
449 1.9 lukem gap -= count;
450 1.9 lukem }
451 1.9 lukem }
452 1.11 simonb if (debug)
453 1.11 simonb fprintf(stderr, "writing %d bytes...\n", ph[i].p_filesz);
454 1.9 lukem copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz);
455 1.9 lukem cur_vma = ph[i].p_vaddr + ph[i].p_filesz;
456 1.9 lukem }
457 1.9 lukem }
458 1.9 lukem
459 1.9 lukem
460 1.9 lukem if (debug)
461 1.9 lukem fprintf(stderr, "writing syms at offset 0x%lx\n",
462 1.9 lukem (u_long) ep.f.f_symptr + sizeof(symhdr));
463 1.9 lukem
464 1.9 lukem /* Copy and translate the symbol table... */
465 1.9 lukem elf_symbol_table_to_ecoff(outfile, infile, &ep,
466 1.9 lukem sh[symtabix].sh_offset, sh[symtabix].sh_size,
467 1.9 lukem sh[strtabix].sh_offset, sh[strtabix].sh_size);
468 1.9 lukem
469 1.9 lukem /*
470 1.9 lukem * Write a page of padding for boot PROMS that read entire pages.
471 1.9 lukem * Without this, they may attempt to read past the end of the
472 1.9 lukem * data section, incur an error, and refuse to boot.
473 1.9 lukem */
474 1.1 jonathan {
475 1.9 lukem char obuf[4096];
476 1.9 lukem memset(obuf, 0, sizeof obuf);
477 1.9 lukem if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) {
478 1.9 lukem fprintf(stderr, "Error writing PROM padding: %s\n",
479 1.9 lukem strerror(errno));
480 1.9 lukem exit(1);
481 1.1 jonathan }
482 1.9 lukem }
483 1.6 jonathan
484 1.9 lukem /* Looks like we won... */
485 1.9 lukem exit(0);
486 1.1 jonathan }
487 1.1 jonathan
488 1.6 jonathan void
489 1.9 lukem copy(out, in, offset, size)
490 1.9 lukem int out, in;
491 1.9 lukem off_t offset, size;
492 1.9 lukem {
493 1.9 lukem char ibuf[4096];
494 1.23 tsutsui size_t remaining, cur, count;
495 1.9 lukem
496 1.14 soren /* Go to the start of the ELF symbol table... */
497 1.9 lukem if (lseek(in, offset, SEEK_SET) < 0) {
498 1.9 lukem perror("copy: lseek");
499 1.9 lukem exit(1);
500 1.9 lukem }
501 1.9 lukem remaining = size;
502 1.9 lukem while (remaining) {
503 1.9 lukem cur = remaining;
504 1.9 lukem if (cur > sizeof ibuf)
505 1.9 lukem cur = sizeof ibuf;
506 1.9 lukem remaining -= cur;
507 1.9 lukem if ((count = read(in, ibuf, cur)) != cur) {
508 1.9 lukem fprintf(stderr, "copy: read: %s\n",
509 1.9 lukem count ? strerror(errno) : "premature end of file");
510 1.9 lukem exit(1);
511 1.9 lukem }
512 1.9 lukem safewrite(out, ibuf, cur, "copy: write: %s\n");
513 1.1 jonathan }
514 1.1 jonathan }
515 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's
516 1.1 jonathan okay for there to be padding between. */
517 1.6 jonathan void
518 1.9 lukem combine(base, new, pad)
519 1.9 lukem struct sect *base, *new;
520 1.9 lukem int pad;
521 1.9 lukem {
522 1.9 lukem if (!base->len)
523 1.9 lukem *base = *new;
524 1.9 lukem else
525 1.9 lukem if (new->len) {
526 1.9 lukem if (base->vaddr + base->len != new->vaddr) {
527 1.9 lukem if (pad)
528 1.9 lukem base->len = new->vaddr - base->vaddr;
529 1.9 lukem else {
530 1.9 lukem fprintf(stderr,
531 1.9 lukem "Non-contiguous data can't be converted.\n");
532 1.9 lukem exit(1);
533 1.9 lukem }
534 1.9 lukem }
535 1.9 lukem base->len += new->len;
536 1.9 lukem }
537 1.1 jonathan }
538 1.1 jonathan
539 1.3 jonathan int
540 1.9 lukem phcmp(h1, h2)
541 1.9 lukem Elf32_Phdr *h1, *h2;
542 1.1 jonathan {
543 1.9 lukem if (h1->p_vaddr > h2->p_vaddr)
544 1.9 lukem return 1;
545 1.9 lukem else
546 1.9 lukem if (h1->p_vaddr < h2->p_vaddr)
547 1.9 lukem return -1;
548 1.9 lukem else
549 1.9 lukem return 0;
550 1.1 jonathan }
551 1.1 jonathan
552 1.8 jonathan char
553 1.9 lukem *
554 1.23 tsutsui saveRead(int file, off_t offset, off_t len, const char *name)
555 1.1 jonathan {
556 1.9 lukem char *tmp;
557 1.9 lukem int count;
558 1.9 lukem off_t off;
559 1.9 lukem if ((off = lseek(file, offset, SEEK_SET)) < 0) {
560 1.9 lukem fprintf(stderr, "%s: fseek: %s\n", name, strerror(errno));
561 1.9 lukem exit(1);
562 1.9 lukem }
563 1.9 lukem if (!(tmp = (char *) malloc(len))) {
564 1.9 lukem fprintf(stderr, "%s: Can't allocate %ld bytes.\n", name, (long) len);
565 1.9 lukem exit(1);
566 1.9 lukem }
567 1.9 lukem count = read(file, tmp, len);
568 1.9 lukem if (count != len) {
569 1.9 lukem fprintf(stderr, "%s: read: %s.\n",
570 1.9 lukem name, count ? strerror(errno) : "End of file reached");
571 1.9 lukem exit(1);
572 1.9 lukem }
573 1.9 lukem return tmp;
574 1.6 jonathan }
575 1.6 jonathan
576 1.8 jonathan void
577 1.23 tsutsui safewrite(int outfile, const void *buf, off_t len, const char *msg)
578 1.8 jonathan {
579 1.9 lukem int written;
580 1.23 tsutsui written = write(outfile, buf, len);
581 1.8 jonathan if (written != len) {
582 1.9 lukem fprintf(stderr, msg, strerror(errno));
583 1.9 lukem exit(1);
584 1.8 jonathan }
585 1.8 jonathan }
586 1.8 jonathan
587 1.6 jonathan
588 1.8 jonathan /*
589 1.8 jonathan * Output only three ECOFF sections, corresponding to ELF psecs
590 1.8 jonathan * for text, data, and bss.
591 1.6 jonathan */
592 1.6 jonathan int
593 1.6 jonathan make_ecoff_section_hdrs(ep, esecs)
594 1.6 jonathan struct ecoff_exechdr *ep;
595 1.6 jonathan struct ecoff_scnhdr *esecs;
596 1.6 jonathan
597 1.6 jonathan {
598 1.8 jonathan ep->f.f_nscns = 6; /* XXX */
599 1.6 jonathan
600 1.9 lukem strcpy(esecs[0].s_name, ".text");
601 1.9 lukem strcpy(esecs[1].s_name, ".data");
602 1.9 lukem strcpy(esecs[2].s_name, ".bss");
603 1.9 lukem
604 1.9 lukem esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start;
605 1.9 lukem esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start;
606 1.9 lukem esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start;
607 1.9 lukem esecs[0].s_size = ep->a.tsize;
608 1.9 lukem esecs[1].s_size = ep->a.dsize;
609 1.9 lukem esecs[2].s_size = ep->a.bsize;
610 1.6 jonathan
611 1.9 lukem esecs[0].s_scnptr = ECOFF_TXTOFF(ep);
612 1.9 lukem esecs[1].s_scnptr = ECOFF_DATOFF(ep);
613 1.6 jonathan #if 0
614 1.9 lukem esecs[2].s_scnptr = esecs[1].s_scnptr +
615 1.9 lukem ECOFF_ROUND(esecs[1].s_size, ECOFF_SEGMENT_ALIGNMENT(ep));
616 1.6 jonathan #endif
617 1.6 jonathan
618 1.9 lukem esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0;
619 1.9 lukem esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0;
620 1.9 lukem esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0;
621 1.9 lukem esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0;
622 1.8 jonathan
623 1.8 jonathan esecs[1].s_flags = 0x100; /* ECOFF rdata */
624 1.8 jonathan esecs[3].s_flags = 0x200; /* ECOFF sdata */
625 1.8 jonathan esecs[4].s_flags = 0x400; /* ECOFF sbss */
626 1.8 jonathan
627 1.8 jonathan /*
628 1.8 jonathan * Set the symbol-table offset to point at the end of any
629 1.8 jonathan * sections we loaded above, so later code can use it to write
630 1.8 jonathan * symbol table info..
631 1.8 jonathan */
632 1.8 jonathan ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size;
633 1.9 lukem return (ep->f.f_nscns);
634 1.8 jonathan }
635 1.8 jonathan
636 1.8 jonathan
637 1.8 jonathan /*
638 1.8 jonathan * Write the ECOFF symbol header.
639 1.8 jonathan * Guess at how big the symbol table will be.
640 1.8 jonathan * Mark all symbols as EXTERN (for now).
641 1.8 jonathan */
642 1.8 jonathan void
643 1.8 jonathan write_ecoff_symhdr(out, ep, symhdrp, nesyms, extsymoff, extstroff, strsize)
644 1.9 lukem int out;
645 1.8 jonathan struct ecoff_exechdr *ep;
646 1.8 jonathan struct ecoff_symhdr *symhdrp;
647 1.9 lukem long nesyms, extsymoff, extstroff, strsize;
648 1.8 jonathan {
649 1.8 jonathan if (debug)
650 1.9 lukem fprintf(stderr, "writing symhdr for %ld entries at offset 0x%lx\n",
651 1.9 lukem nesyms, (u_long) ep->f.f_symptr);
652 1.8 jonathan
653 1.9 lukem ep->f.f_nsyms = sizeof(struct ecoff_symhdr);
654 1.8 jonathan
655 1.10 perry memset(symhdrp, 0, sizeof(*symhdrp));
656 1.8 jonathan symhdrp->esymMax = nesyms;
657 1.9 lukem symhdrp->magic = 0x7009;/* XXX */
658 1.8 jonathan symhdrp->cbExtOffset = extsymoff;
659 1.8 jonathan symhdrp->cbSsExtOffset = extstroff;
660 1.8 jonathan
661 1.8 jonathan symhdrp->issExtMax = strsize;
662 1.8 jonathan if (debug)
663 1.8 jonathan fprintf(stderr,
664 1.24 matt "ECOFF symhdr: symhdr %zx, strsize %lx, symsize %lx\n",
665 1.8 jonathan sizeof(*symhdrp), strsize,
666 1.8 jonathan (nesyms * sizeof(struct ecoff_extsym)));
667 1.8 jonathan
668 1.16 bouyer if (needswap) {
669 1.22 simonb bswap32_region(&symhdrp->ilineMax,
670 1.16 bouyer sizeof(*symhdrp) - sizeof(symhdrp->magic) -
671 1.16 bouyer sizeof(symhdrp->ilineMax));
672 1.16 bouyer symhdrp->magic = bswap16(symhdrp->magic);
673 1.16 bouyer symhdrp->ilineMax = bswap16(symhdrp->ilineMax);
674 1.16 bouyer }
675 1.16 bouyer
676 1.8 jonathan safewrite(out, symhdrp, sizeof(*symhdrp),
677 1.8 jonathan "writing symbol header: %s\n");
678 1.8 jonathan }
679 1.8 jonathan
680 1.8 jonathan
681 1.8 jonathan void
682 1.8 jonathan elf_read_syms(elfsymsp, in, symoff, symsize, stroff, strsize)
683 1.8 jonathan struct elf_syms *elfsymsp;
684 1.9 lukem int in;
685 1.9 lukem off_t symoff, symsize;
686 1.9 lukem off_t stroff, strsize;
687 1.8 jonathan {
688 1.8 jonathan register int nsyms;
689 1.16 bouyer int i;
690 1.9 lukem nsyms = symsize / sizeof(Elf32_Sym);
691 1.8 jonathan
692 1.8 jonathan /* Suck in the ELF symbol list... */
693 1.8 jonathan elfsymsp->elf_syms = (Elf32_Sym *)
694 1.9 lukem saveRead(in, symoff, nsyms * sizeof(Elf32_Sym),
695 1.9 lukem "ELF symboltable");
696 1.8 jonathan elfsymsp->nsymbols = nsyms;
697 1.16 bouyer if (needswap) {
698 1.16 bouyer for (i = 0; i < nsyms; i++) {
699 1.16 bouyer Elf32_Sym *s = &elfsymsp->elf_syms[i];
700 1.16 bouyer s->st_name = bswap32(s->st_name);
701 1.16 bouyer s->st_value = bswap32(s->st_value);
702 1.16 bouyer s->st_size = bswap32(s->st_size);
703 1.16 bouyer s->st_shndx = bswap16(s->st_shndx);
704 1.16 bouyer }
705 1.16 bouyer }
706 1.8 jonathan
707 1.8 jonathan /* Suck in the ELF string table... */
708 1.8 jonathan elfsymsp->stringtab = (char *)
709 1.9 lukem saveRead(in, stroff, strsize, "ELF string table");
710 1.8 jonathan elfsymsp->stringsize = strsize;
711 1.8 jonathan }
712 1.8 jonathan
713 1.8 jonathan
714 1.8 jonathan /*
715 1.9 lukem *
716 1.8 jonathan */
717 1.8 jonathan void
718 1.8 jonathan elf_symbol_table_to_ecoff(out, in, ep, symoff, symsize, stroff, strsize)
719 1.9 lukem int out, in;
720 1.8 jonathan struct ecoff_exechdr *ep;
721 1.9 lukem off_t symoff, symsize;
722 1.9 lukem off_t stroff, strsize;
723 1.8 jonathan {
724 1.8 jonathan
725 1.8 jonathan struct elf_syms elfsymtab;
726 1.8 jonathan struct ecoff_syms ecoffsymtab;
727 1.8 jonathan register u_long ecoff_symhdr_off, symtaboff, stringtaboff;
728 1.8 jonathan register u_long nextoff, symtabsize, ecoff_strsize;
729 1.16 bouyer int nsyms, i;
730 1.8 jonathan struct ecoff_symhdr symhdr;
731 1.9 lukem int padding;
732 1.9 lukem
733 1.8 jonathan /* Read in the ELF symbols. */
734 1.8 jonathan elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize);
735 1.8 jonathan
736 1.8 jonathan /* Approximate translation to ECOFF. */
737 1.8 jonathan translate_syms(&elfsymtab, &ecoffsymtab);
738 1.8 jonathan nsyms = ecoffsymtab.nsymbols;
739 1.8 jonathan
740 1.9 lukem /* Compute output ECOFF symbol- and string-table offsets. */
741 1.8 jonathan ecoff_symhdr_off = ep->f.f_symptr;
742 1.8 jonathan
743 1.8 jonathan nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr);
744 1.8 jonathan stringtaboff = nextoff;
745 1.8 jonathan ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize,
746 1.9 lukem (ECOFF_SEGMENT_ALIGNMENT(ep)));
747 1.8 jonathan
748 1.8 jonathan
749 1.8 jonathan nextoff = stringtaboff + ecoff_strsize;
750 1.8 jonathan symtaboff = nextoff;
751 1.8 jonathan symtabsize = nsyms * sizeof(struct ecoff_extsym);
752 1.8 jonathan symtabsize = ECOFF_ROUND(symtabsize, ECOFF_SEGMENT_ALIGNMENT(ep));
753 1.8 jonathan
754 1.8 jonathan /* Write out the symbol header ... */
755 1.9 lukem write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff,
756 1.9 lukem stringtaboff, ecoffsymtab.stringsize);
757 1.8 jonathan
758 1.8 jonathan /* Write out the string table... */
759 1.8 jonathan padding = ecoff_strsize - ecoffsymtab.stringsize;
760 1.9 lukem safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize,
761 1.9 lukem "string table: write: %s\n");
762 1.8 jonathan if (padding)
763 1.8 jonathan pad16(out, padding, "string table: padding: %s\n");
764 1.8 jonathan
765 1.8 jonathan
766 1.8 jonathan /* Write out the symbol table... */
767 1.9 lukem padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym));
768 1.16 bouyer
769 1.16 bouyer for (i = 0; i < nsyms; i++) {
770 1.16 bouyer struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i];
771 1.16 bouyer es->es_flags = bswap16(es->es_flags);
772 1.16 bouyer es->es_ifd = bswap16(es->es_ifd);
773 1.16 bouyer bswap32_region(&es->es_strindex,
774 1.16 bouyer sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd));
775 1.16 bouyer }
776 1.9 lukem safewrite(out, ecoffsymtab.ecoff_syms,
777 1.8 jonathan nsyms * sizeof(struct ecoff_extsym),
778 1.8 jonathan "symbol table: write: %s\n");
779 1.8 jonathan if (padding)
780 1.8 jonathan pad16(out, padding, "symbols: padding: %s\n");
781 1.8 jonathan }
782 1.8 jonathan
783 1.8 jonathan
784 1.8 jonathan
785 1.8 jonathan /*
786 1.8 jonathan * In-memory translation of ELF symbosl to ECOFF.
787 1.8 jonathan */
788 1.8 jonathan void
789 1.9 lukem translate_syms(elfp, ecoffp)
790 1.8 jonathan struct elf_syms *elfp;
791 1.8 jonathan struct ecoff_syms *ecoffp;
792 1.8 jonathan {
793 1.6 jonathan
794 1.9 lukem int i;
795 1.9 lukem char *oldstringbase;
796 1.9 lukem char *newstrings, *nsp;
797 1.9 lukem
798 1.9 lukem int nsyms, idx;
799 1.9 lukem
800 1.9 lukem nsyms = elfp->nsymbols;
801 1.9 lukem oldstringbase = elfp->stringtab;
802 1.9 lukem
803 1.9 lukem /* Allocate space for corresponding ECOFF symbols. */
804 1.10 perry memset(ecoffp, 0, sizeof(*ecoffp));
805 1.9 lukem
806 1.9 lukem ecoffp->nsymbols = 0;
807 1.9 lukem ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms);
808 1.9 lukem
809 1.9 lukem /* we are going to be no bigger than the ELF symbol table. */
810 1.9 lukem ecoffp->stringsize = elfp->stringsize;
811 1.9 lukem ecoffp->stringtab = malloc(elfp->stringsize);
812 1.9 lukem
813 1.9 lukem newstrings = (char *) ecoffp->stringtab;
814 1.9 lukem nsp = (char *) ecoffp->stringtab;
815 1.9 lukem if (!newstrings) {
816 1.9 lukem fprintf(stderr, "No memory for new string table!\n");
817 1.9 lukem exit(1);
818 1.9 lukem }
819 1.9 lukem /* Copy and translate symbols... */
820 1.9 lukem idx = 0;
821 1.9 lukem for (i = 0; i < nsyms; i++) {
822 1.9 lukem int binding, type;
823 1.9 lukem
824 1.13 drochner binding = ELF32_ST_BIND((elfp->elf_syms[i].st_info));
825 1.13 drochner type = ELF32_ST_TYPE((elfp->elf_syms[i].st_info));
826 1.9 lukem
827 1.9 lukem /* skip strange symbols */
828 1.9 lukem if (binding == 0) {
829 1.9 lukem continue;
830 1.9 lukem }
831 1.9 lukem /* Copy the symbol into the new table */
832 1.9 lukem strcpy(nsp, oldstringbase + elfp->elf_syms[i].st_name);
833 1.9 lukem ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings;
834 1.9 lukem nsp += strlen(nsp) + 1;
835 1.9 lukem
836 1.9 lukem /* translate symbol types to ECOFF XXX */
837 1.9 lukem ecoffp->ecoff_syms[idx].es_type = 1;
838 1.9 lukem ecoffp->ecoff_syms[idx].es_class = 5;
839 1.9 lukem
840 1.9 lukem /* Symbol values in executables should be compatible. */
841 1.9 lukem ecoffp->ecoff_syms[idx].es_value = elfp->elf_syms[i].st_value;
842 1.9 lukem ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff;
843 1.8 jonathan
844 1.9 lukem idx++;
845 1.8 jonathan }
846 1.8 jonathan
847 1.9 lukem ecoffp->nsymbols = idx;
848 1.9 lukem ecoffp->stringsize = nsp - newstrings;
849 1.8 jonathan }
850 1.8 jonathan /*
851 1.8 jonathan * pad to a 16-byte boundary
852 1.8 jonathan */
853 1.8 jonathan void
854 1.8 jonathan pad16(int fd, int size, const char *msg)
855 1.8 jonathan {
856 1.9 lukem safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg);
857 1.16 bouyer }
858 1.16 bouyer
859 1.16 bouyer /* swap a 32bit region */
860 1.16 bouyer void
861 1.22 simonb bswap32_region(int32_t* p, int len)
862 1.16 bouyer {
863 1.23 tsutsui size_t i;
864 1.16 bouyer
865 1.22 simonb for (i = 0; i < len / sizeof(int32_t); i++, p++)
866 1.16 bouyer *p = bswap32(*p);
867 1.1 jonathan }
868