1 1.38 christos /* $NetBSD: elf2ecoff.c,v 1.38 2025/09/13 17:08:47 christos 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.31 christos uint32_t vaddr; 60 1.31 christos uint32_t 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.36 tsutsui int debug = 0; 78 1.36 tsutsui 79 1.28 christos static int needswap; 80 1.6 jonathan 81 1.28 christos static int phcmp(Elf32_Phdr *, Elf32_Phdr *); 82 1.28 christos static char *saveRead(int, off_t, off_t, const char *); 83 1.28 christos static void safewrite(int, const void *, off_t, const char *); 84 1.28 christos static void copy(int, int, off_t, off_t); 85 1.28 christos static void combine(struct sect *, struct sect *, int); 86 1.38 christos static size_t compute_stringsize(const Elf32_Sym *elf_syms, int nsymbols, 87 1.37 tsutsui const char *elf_stringbase); 88 1.28 christos static void translate_syms(struct elf_syms *, struct ecoff_syms *); 89 1.31 christos static void elf_symbol_table_to_ecoff(int, int, struct ecoff32_exechdr *, 90 1.28 christos off_t, off_t, off_t, off_t); 91 1.31 christos static int make_ecoff_section_hdrs(struct ecoff32_exechdr *, 92 1.31 christos struct ecoff32_scnhdr *); 93 1.31 christos static void write_ecoff_symhdr(int, struct ecoff32_exechdr *, 94 1.31 christos struct ecoff32_symhdr *, int32_t, int32_t, int32_t, int32_t); 95 1.28 christos static void pad16(int, int, const char *); 96 1.28 christos static void bswap32_region(int32_t* , int); 97 1.28 christos static void elf_read_syms(struct elf_syms *, int, off_t, off_t, off_t, 98 1.28 christos off_t); 99 1.8 jonathan 100 1.8 jonathan 101 1.6 jonathan int 102 1.28 christos main(int argc, char **argv) 103 1.1 jonathan { 104 1.9 lukem Elf32_Ehdr ex; 105 1.9 lukem Elf32_Phdr *ph; 106 1.9 lukem Elf32_Shdr *sh; 107 1.9 lukem char *shstrtab; 108 1.9 lukem int strtabix, symtabix; 109 1.23 tsutsui size_t i; 110 1.23 tsutsui int pad; 111 1.9 lukem struct sect text, data, bss; /* a.out-compatible sections */ 112 1.9 lukem 113 1.31 christos struct ecoff32_exechdr ep; 114 1.31 christos struct ecoff32_scnhdr esecs[6]; 115 1.31 christos struct ecoff32_symhdr symhdr; 116 1.9 lukem 117 1.9 lukem int infile, outfile; 118 1.31 christos uint32_t cur_vma = UINT32_MAX; 119 1.9 lukem int nsecs = 0; 120 1.16 bouyer int mipsel; 121 1.16 bouyer 122 1.9 lukem 123 1.9 lukem text.len = data.len = bss.len = 0; 124 1.9 lukem text.vaddr = data.vaddr = bss.vaddr = 0; 125 1.9 lukem 126 1.9 lukem /* Check args... */ 127 1.9 lukem if (argc < 3 || argc > 4) { 128 1.9 lukem usage: 129 1.9 lukem fprintf(stderr, 130 1.28 christos "Usage: %s <elf executable> <ECOFF executable> [-s]\n", 131 1.28 christos getprogname()); 132 1.9 lukem exit(1); 133 1.9 lukem } 134 1.9 lukem if (argc == 4) { 135 1.9 lukem if (strcmp(argv[3], "-s")) 136 1.9 lukem goto usage; 137 1.1 jonathan } 138 1.9 lukem /* Try the input file... */ 139 1.28 christos if ((infile = open(argv[1], O_RDONLY)) < 0) 140 1.28 christos err(1, "Can't open %s for read", argv[1]); 141 1.9 lukem /* Read the header, which is at the beginning of the file... */ 142 1.9 lukem i = read(infile, &ex, sizeof ex); 143 1.28 christos if (i != sizeof ex) 144 1.28 christos err(1, "Short header read from %s", argv[1]); 145 1.16 bouyer if (ex.e_ident[EI_DATA] == ELFDATA2LSB) 146 1.16 bouyer mipsel = 1; 147 1.16 bouyer else if (ex.e_ident[EI_DATA] == ELFDATA2MSB) 148 1.16 bouyer mipsel = 0; 149 1.28 christos else 150 1.28 christos errx(1, "invalid ELF byte order %d", ex.e_ident[EI_DATA]); 151 1.16 bouyer #if BYTE_ORDER == BIG_ENDIAN 152 1.16 bouyer if (mipsel) 153 1.16 bouyer needswap = 1; 154 1.16 bouyer else 155 1.16 bouyer needswap = 0; 156 1.16 bouyer #elif BYTE_ORDER == LITTLE_ENDIAN 157 1.16 bouyer if (mipsel) 158 1.16 bouyer needswap = 0; 159 1.16 bouyer else 160 1.16 bouyer needswap = 1; 161 1.16 bouyer #else 162 1.16 bouyer #error "unknown endian" 163 1.16 bouyer #endif 164 1.16 bouyer 165 1.16 bouyer if (needswap) { 166 1.16 bouyer ex.e_type = bswap16(ex.e_type); 167 1.16 bouyer ex.e_machine = bswap16(ex.e_machine); 168 1.16 bouyer ex.e_version = bswap32(ex.e_version); 169 1.16 bouyer ex.e_entry = bswap32(ex.e_entry); 170 1.16 bouyer ex.e_phoff = bswap32(ex.e_phoff); 171 1.16 bouyer ex.e_shoff = bswap32(ex.e_shoff); 172 1.16 bouyer ex.e_flags = bswap32(ex.e_flags); 173 1.16 bouyer ex.e_ehsize = bswap16(ex.e_ehsize); 174 1.16 bouyer ex.e_phentsize = bswap16(ex.e_phentsize); 175 1.16 bouyer ex.e_phnum = bswap16(ex.e_phnum); 176 1.16 bouyer ex.e_shentsize = bswap16(ex.e_shentsize); 177 1.16 bouyer ex.e_shnum = bswap16(ex.e_shnum); 178 1.16 bouyer ex.e_shstrndx = bswap16(ex.e_shstrndx); 179 1.16 bouyer } 180 1.16 bouyer 181 1.9 lukem /* Read the program headers... */ 182 1.9 lukem ph = (Elf32_Phdr *) saveRead(infile, ex.e_phoff, 183 1.9 lukem ex.e_phnum * sizeof(Elf32_Phdr), "ph"); 184 1.16 bouyer if (needswap) 185 1.22 simonb bswap32_region((int32_t*)ph, sizeof(Elf32_Phdr) * ex.e_phnum); 186 1.9 lukem /* Read the section headers... */ 187 1.9 lukem sh = (Elf32_Shdr *) saveRead(infile, ex.e_shoff, 188 1.9 lukem ex.e_shnum * sizeof(Elf32_Shdr), "sh"); 189 1.16 bouyer if (needswap) 190 1.22 simonb bswap32_region((int32_t*)sh, sizeof(Elf32_Shdr) * ex.e_shnum); 191 1.16 bouyer 192 1.9 lukem /* Read in the section string table. */ 193 1.9 lukem shstrtab = saveRead(infile, sh[ex.e_shstrndx].sh_offset, 194 1.9 lukem sh[ex.e_shstrndx].sh_size, "shstrtab"); 195 1.9 lukem 196 1.9 lukem 197 1.9 lukem /* Look for the symbol table and string table... Also map section 198 1.9 lukem * indices to symbol types for a.out */ 199 1.9 lukem symtabix = 0; 200 1.9 lukem strtabix = 0; 201 1.9 lukem for (i = 0; i < ex.e_shnum; i++) { 202 1.9 lukem char *name = shstrtab + sh[i].sh_name; 203 1.9 lukem if (!strcmp(name, ".symtab")) 204 1.9 lukem symtabix = i; 205 1.9 lukem else 206 1.9 lukem if (!strcmp(name, ".strtab")) 207 1.9 lukem strtabix = i; 208 1.1 jonathan 209 1.9 lukem } 210 1.6 jonathan 211 1.28 christos /* 212 1.28 christos * Figure out if we can cram the program header into an ECOFF 213 1.9 lukem * header... Basically, we can't handle anything but loadable 214 1.9 lukem * segments, but we can ignore some kinds of segments. We can't 215 1.9 lukem * handle holes in the address space. Segments may be out of order, 216 1.28 christos * so we sort them first. 217 1.28 christos */ 218 1.9 lukem 219 1.9 lukem qsort(ph, ex.e_phnum, sizeof(Elf32_Phdr), 220 1.9 lukem (int (*) (const void *, const void *)) phcmp); 221 1.9 lukem 222 1.9 lukem for (i = 0; i < ex.e_phnum; i++) { 223 1.30 christos switch (ph[i].p_type) { 224 1.30 christos case PT_NOTE: 225 1.30 christos case PT_NULL: 226 1.30 christos case PT_PHDR: 227 1.30 christos case PT_MIPS_ABIFLAGS: 228 1.30 christos case PT_MIPS_REGINFO: 229 1.30 christos /* Section types we can ignore... */ 230 1.9 lukem if (debug) { 231 1.30 christos fprintf(stderr, " skipping PH %zu type %#x " 232 1.30 christos "flags %#x\n", 233 1.9 lukem i, ph[i].p_type, ph[i].p_flags); 234 1.9 lukem } 235 1.9 lukem continue; 236 1.30 christos default: 237 1.30 christos /* Section types we can't handle... */ 238 1.28 christos if (ph[i].p_type != PT_LOAD) 239 1.30 christos errx(1, "Program header %zu type %#x can't be " 240 1.28 christos "converted", i, ph[i].p_type); 241 1.30 christos } 242 1.9 lukem /* Writable (data) segment? */ 243 1.9 lukem if (ph[i].p_flags & PF_W) { 244 1.9 lukem struct sect ndata, nbss; 245 1.9 lukem 246 1.9 lukem ndata.vaddr = ph[i].p_vaddr; 247 1.9 lukem ndata.len = ph[i].p_filesz; 248 1.9 lukem nbss.vaddr = ph[i].p_vaddr + ph[i].p_filesz; 249 1.9 lukem nbss.len = ph[i].p_memsz - ph[i].p_filesz; 250 1.9 lukem 251 1.9 lukem if (debug) { 252 1.34 andvar fprintf(stderr, " combining PH %zu type %d " 253 1.33 christos "flags %#x with data, ndata = %d, " 254 1.31 christos "nbss =%d\n", i, ph[i].p_type, 255 1.28 christos ph[i].p_flags, ndata.len, nbss.len); 256 1.9 lukem } 257 1.9 lukem combine(&data, &ndata, 0); 258 1.9 lukem combine(&bss, &nbss, 1); 259 1.9 lukem } else { 260 1.9 lukem struct sect ntxt; 261 1.9 lukem 262 1.9 lukem ntxt.vaddr = ph[i].p_vaddr; 263 1.9 lukem ntxt.len = ph[i].p_filesz; 264 1.9 lukem if (debug) { 265 1.34 andvar fprintf(stderr, " combining PH %zu type %d " 266 1.33 christos "flags %#x with text, len = %d\n", 267 1.9 lukem i, ph[i].p_type, ph[i].p_flags, ntxt.len); 268 1.9 lukem } 269 1.9 lukem combine(&text, &ntxt, 0); 270 1.9 lukem } 271 1.9 lukem /* Remember the lowest segment start address. */ 272 1.9 lukem if (ph[i].p_vaddr < cur_vma) 273 1.9 lukem cur_vma = ph[i].p_vaddr; 274 1.1 jonathan } 275 1.1 jonathan 276 1.9 lukem /* Sections must be in order to be converted... */ 277 1.9 lukem if (text.vaddr > data.vaddr || data.vaddr > bss.vaddr || 278 1.28 christos text.vaddr + text.len > data.vaddr || 279 1.28 christos data.vaddr + data.len > bss.vaddr) 280 1.28 christos errx(1, "Sections ordering prevents a.out conversion"); 281 1.9 lukem /* If there's a data section but no text section, then the loader 282 1.9 lukem * combined everything into one section. That needs to be the text 283 1.9 lukem * section, so just make the data section zero length following text. */ 284 1.27 tsutsui if (data.len && text.len == 0) { 285 1.9 lukem text = data; 286 1.9 lukem data.vaddr = text.vaddr + text.len; 287 1.9 lukem data.len = 0; 288 1.9 lukem } 289 1.9 lukem /* If there is a gap between text and data, we'll fill it when we copy 290 1.9 lukem * the data, so update the length of the text segment as represented 291 1.9 lukem * in a.out to reflect that, since a.out doesn't allow gaps in the 292 1.9 lukem * program address space. */ 293 1.9 lukem if (text.vaddr + text.len < data.vaddr) 294 1.9 lukem text.len = data.vaddr - text.vaddr; 295 1.9 lukem 296 1.9 lukem /* We now have enough information to cons up an a.out header... */ 297 1.9 lukem ep.a.magic = ECOFF_OMAGIC; 298 1.9 lukem ep.a.vstamp = 2 * 256 + 10; /* compatible with version 2.10 */ 299 1.9 lukem ep.a.tsize = text.len; 300 1.9 lukem ep.a.dsize = data.len; 301 1.9 lukem ep.a.bsize = bss.len; 302 1.9 lukem ep.a.entry = ex.e_entry; 303 1.9 lukem ep.a.text_start = text.vaddr; 304 1.9 lukem ep.a.data_start = data.vaddr; 305 1.9 lukem ep.a.bss_start = bss.vaddr; 306 1.9 lukem ep.a.gprmask = 0xf3fffffe; 307 1.10 perry memset(&ep.a.cprmask, 0, sizeof ep.a.cprmask); 308 1.9 lukem ep.a.gp_value = 0; /* unused. */ 309 1.9 lukem 310 1.16 bouyer if (mipsel) 311 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEL; 312 1.16 bouyer else 313 1.15 bouyer ep.f.f_magic = ECOFF_MAGIC_MIPSEB; 314 1.15 bouyer 315 1.9 lukem ep.f.f_nscns = 6; 316 1.9 lukem ep.f.f_timdat = 0; /* bogus */ 317 1.9 lukem ep.f.f_symptr = 0; 318 1.31 christos ep.f.f_nsyms = sizeof(struct ecoff32_symhdr); 319 1.9 lukem ep.f.f_opthdr = sizeof ep.a; 320 1.35 andvar ep.f.f_flags = 0x100f; /* Stripped, not shareable. */ 321 1.9 lukem 322 1.10 perry memset(esecs, 0, sizeof(esecs)); 323 1.9 lukem 324 1.9 lukem /* Make ECOFF section headers, with empty stubs for 325 1.9 lukem * .rdata/.sdata/.sbss. */ 326 1.9 lukem make_ecoff_section_hdrs(&ep, esecs); 327 1.9 lukem 328 1.9 lukem nsecs = ep.f.f_nscns; 329 1.9 lukem 330 1.16 bouyer if (needswap) { 331 1.16 bouyer ep.f.f_magic = bswap16(ep.f.f_magic); 332 1.16 bouyer ep.f.f_nscns = bswap16(ep.f.f_nscns); 333 1.16 bouyer ep.f.f_timdat = bswap32(ep.f.f_timdat); 334 1.16 bouyer ep.f.f_symptr = bswap32(ep.f.f_symptr); 335 1.16 bouyer ep.f.f_nsyms = bswap32(ep.f.f_nsyms); 336 1.16 bouyer ep.f.f_opthdr = bswap16(ep.f.f_opthdr); 337 1.16 bouyer ep.f.f_flags = bswap16(ep.f.f_flags); 338 1.16 bouyer ep.a.magic = bswap16(ep.a.magic); 339 1.16 bouyer ep.a.vstamp = bswap16(ep.a.vstamp); 340 1.16 bouyer ep.a.tsize = bswap32(ep.a.tsize); 341 1.16 bouyer ep.a.dsize = bswap32(ep.a.dsize); 342 1.16 bouyer ep.a.bsize = bswap32(ep.a.bsize); 343 1.16 bouyer ep.a.entry = bswap32(ep.a.entry); 344 1.16 bouyer ep.a.text_start = bswap32(ep.a.text_start); 345 1.16 bouyer ep.a.data_start = bswap32(ep.a.data_start); 346 1.16 bouyer ep.a.bss_start = bswap32(ep.a.bss_start); 347 1.16 bouyer ep.a.gprmask = bswap32(ep.a.gprmask); 348 1.22 simonb bswap32_region((int32_t*)ep.a.cprmask, sizeof(ep.a.cprmask)); 349 1.16 bouyer ep.a.gp_value = bswap32(ep.a.gp_value); 350 1.16 bouyer for (i = 0; i < sizeof(esecs) / sizeof(esecs[0]); i++) { 351 1.16 bouyer esecs[i].s_paddr = bswap32(esecs[i].s_paddr); 352 1.16 bouyer esecs[i].s_vaddr = bswap32(esecs[i].s_vaddr); 353 1.16 bouyer esecs[i].s_size = bswap32(esecs[i].s_size); 354 1.16 bouyer esecs[i].s_scnptr = bswap32(esecs[i].s_scnptr); 355 1.16 bouyer esecs[i].s_relptr = bswap32(esecs[i].s_relptr); 356 1.16 bouyer esecs[i].s_lnnoptr = bswap32(esecs[i].s_lnnoptr); 357 1.16 bouyer esecs[i].s_nreloc = bswap16(esecs[i].s_nreloc); 358 1.16 bouyer esecs[i].s_nlnno = bswap16(esecs[i].s_nlnno); 359 1.16 bouyer esecs[i].s_flags = bswap32(esecs[i].s_flags); 360 1.16 bouyer } 361 1.16 bouyer } 362 1.16 bouyer 363 1.9 lukem /* Make the output file... */ 364 1.28 christos if ((outfile = open(argv[2], O_WRONLY | O_CREAT, 0777)) < 0) 365 1.28 christos err(1, "Unable to create %s", argv[2]); 366 1.28 christos 367 1.11 simonb /* Truncate file... */ 368 1.11 simonb if (ftruncate(outfile, 0)) { 369 1.11 simonb warn("ftruncate %s", argv[2]); 370 1.11 simonb } 371 1.9 lukem /* Write the headers... */ 372 1.28 christos safewrite(outfile, &ep.f, sizeof(ep.f), "ep.f: write"); 373 1.11 simonb if (debug) 374 1.24 matt fprintf(stderr, "wrote %zu byte file header.\n", sizeof(ep.f)); 375 1.9 lukem 376 1.28 christos safewrite(outfile, &ep.a, sizeof(ep.a), "ep.a: write"); 377 1.11 simonb if (debug) 378 1.24 matt fprintf(stderr, "wrote %zu byte a.out header.\n", sizeof(ep.a)); 379 1.9 lukem 380 1.28 christos safewrite(outfile, &esecs, sizeof(esecs[0]) * nsecs, "esecs: write"); 381 1.11 simonb if (debug) 382 1.24 matt fprintf(stderr, "wrote %zu bytes of section headers.\n", 383 1.11 simonb sizeof(esecs[0]) * nsecs); 384 1.9 lukem 385 1.9 lukem 386 1.9 lukem pad = ((sizeof ep.f + sizeof ep.a + sizeof esecs) & 15); 387 1.9 lukem if (pad) { 388 1.9 lukem pad = 16 - pad; 389 1.28 christos pad16(outfile, pad, "ipad: write"); 390 1.11 simonb if (debug) 391 1.11 simonb fprintf(stderr, "wrote %d byte pad.\n", pad); 392 1.9 lukem } 393 1.9 lukem /* Copy the loadable sections. Zero-fill any gaps less than 64k; 394 1.9 lukem * complain about any zero-filling, and die if we're asked to 395 1.9 lukem * zero-fill more than 64k. */ 396 1.9 lukem for (i = 0; i < ex.e_phnum; i++) { 397 1.9 lukem /* Unprocessable sections were handled above, so just verify 398 1.9 lukem * that the section can be loaded before copying. */ 399 1.13 drochner if (ph[i].p_type == PT_LOAD && ph[i].p_filesz) { 400 1.9 lukem if (cur_vma != ph[i].p_vaddr) { 401 1.31 christos uint32_t gap = ph[i].p_vaddr - cur_vma; 402 1.9 lukem char obuf[1024]; 403 1.28 christos if (gap > 65536) 404 1.31 christos errx(1, "Intersegment gap (%d bytes) " 405 1.28 christos "too large", gap); 406 1.11 simonb if (debug) 407 1.31 christos fprintf(stderr, "Warning: %d byte " 408 1.28 christos "intersegment gap.\n", gap); 409 1.9 lukem memset(obuf, 0, sizeof obuf); 410 1.9 lukem while (gap) { 411 1.28 christos int count = write(outfile, obuf, 412 1.28 christos (gap > sizeof obuf 413 1.28 christos ? sizeof obuf : gap)); 414 1.28 christos if (count < 0) 415 1.28 christos err(1, "Error writing gap"); 416 1.9 lukem gap -= count; 417 1.9 lukem } 418 1.9 lukem } 419 1.11 simonb if (debug) 420 1.28 christos fprintf(stderr, "writing %d bytes...\n", 421 1.28 christos ph[i].p_filesz); 422 1.9 lukem copy(outfile, infile, ph[i].p_offset, ph[i].p_filesz); 423 1.9 lukem cur_vma = ph[i].p_vaddr + ph[i].p_filesz; 424 1.9 lukem } 425 1.9 lukem } 426 1.9 lukem 427 1.9 lukem 428 1.9 lukem if (debug) 429 1.33 christos fprintf(stderr, "writing syms at offset %#x\n", 430 1.33 christos (uint32_t)(ep.f.f_symptr + sizeof(symhdr))); 431 1.9 lukem 432 1.9 lukem /* Copy and translate the symbol table... */ 433 1.9 lukem elf_symbol_table_to_ecoff(outfile, infile, &ep, 434 1.9 lukem sh[symtabix].sh_offset, sh[symtabix].sh_size, 435 1.9 lukem sh[strtabix].sh_offset, sh[strtabix].sh_size); 436 1.9 lukem 437 1.9 lukem /* 438 1.9 lukem * Write a page of padding for boot PROMS that read entire pages. 439 1.9 lukem * Without this, they may attempt to read past the end of the 440 1.9 lukem * data section, incur an error, and refuse to boot. 441 1.9 lukem */ 442 1.1 jonathan { 443 1.9 lukem char obuf[4096]; 444 1.9 lukem memset(obuf, 0, sizeof obuf); 445 1.28 christos if (write(outfile, obuf, sizeof(obuf)) != sizeof(obuf)) 446 1.28 christos err(1, "Error writing PROM padding"); 447 1.9 lukem } 448 1.6 jonathan 449 1.9 lukem /* Looks like we won... */ 450 1.28 christos return 0; 451 1.1 jonathan } 452 1.1 jonathan 453 1.28 christos static void 454 1.27 tsutsui copy(int out, int in, off_t offset, off_t size) 455 1.9 lukem { 456 1.9 lukem char ibuf[4096]; 457 1.23 tsutsui size_t remaining, cur, count; 458 1.9 lukem 459 1.14 soren /* Go to the start of the ELF symbol table... */ 460 1.28 christos if (lseek(in, offset, SEEK_SET) < 0) 461 1.28 christos err(1, "copy: lseek"); 462 1.9 lukem remaining = size; 463 1.9 lukem while (remaining) { 464 1.9 lukem cur = remaining; 465 1.9 lukem if (cur > sizeof ibuf) 466 1.9 lukem cur = sizeof ibuf; 467 1.9 lukem remaining -= cur; 468 1.28 christos if ((count = read(in, ibuf, cur)) != cur) 469 1.28 christos err(1, "copy: short read"); 470 1.28 christos safewrite(out, ibuf, cur, "copy: write"); 471 1.1 jonathan } 472 1.1 jonathan } 473 1.28 christos 474 1.1 jonathan /* Combine two segments, which must be contiguous. If pad is true, it's 475 1.1 jonathan okay for there to be padding between. */ 476 1.28 christos static void 477 1.27 tsutsui combine(struct sect *base, struct sect *new, int pad) 478 1.9 lukem { 479 1.27 tsutsui 480 1.27 tsutsui if (base->len == 0) 481 1.9 lukem *base = *new; 482 1.9 lukem else 483 1.9 lukem if (new->len) { 484 1.9 lukem if (base->vaddr + base->len != new->vaddr) { 485 1.9 lukem if (pad) 486 1.9 lukem base->len = new->vaddr - base->vaddr; 487 1.28 christos else 488 1.28 christos errx(1, "Non-contiguous data can't be " 489 1.28 christos "converted"); 490 1.9 lukem } 491 1.9 lukem base->len += new->len; 492 1.9 lukem } 493 1.1 jonathan } 494 1.1 jonathan 495 1.28 christos static int 496 1.27 tsutsui phcmp(Elf32_Phdr *h1, Elf32_Phdr *h2) 497 1.1 jonathan { 498 1.27 tsutsui 499 1.9 lukem if (h1->p_vaddr > h2->p_vaddr) 500 1.9 lukem return 1; 501 1.9 lukem else 502 1.9 lukem if (h1->p_vaddr < h2->p_vaddr) 503 1.9 lukem return -1; 504 1.9 lukem else 505 1.9 lukem return 0; 506 1.1 jonathan } 507 1.1 jonathan 508 1.28 christos static char * 509 1.23 tsutsui saveRead(int file, off_t offset, off_t len, const char *name) 510 1.1 jonathan { 511 1.9 lukem char *tmp; 512 1.9 lukem int count; 513 1.9 lukem off_t off; 514 1.27 tsutsui 515 1.28 christos if ((off = lseek(file, offset, SEEK_SET)) < 0) 516 1.28 christos err(1, "%s: fseek", name); 517 1.28 christos if ((tmp = malloc(len)) == NULL) 518 1.32 christos err(1, "%s: Can't allocate %jd bytes", name, (intmax_t)len); 519 1.9 lukem count = read(file, tmp, len); 520 1.28 christos if (count != len) 521 1.28 christos err(1, "%s: short read", name); 522 1.9 lukem return tmp; 523 1.6 jonathan } 524 1.6 jonathan 525 1.28 christos static void 526 1.23 tsutsui safewrite(int outfile, const void *buf, off_t len, const char *msg) 527 1.8 jonathan { 528 1.28 christos ssize_t written; 529 1.27 tsutsui 530 1.23 tsutsui written = write(outfile, buf, len); 531 1.28 christos if (written != len) 532 1.28 christos err(1, "%s", msg); 533 1.8 jonathan } 534 1.8 jonathan 535 1.6 jonathan 536 1.8 jonathan /* 537 1.8 jonathan * Output only three ECOFF sections, corresponding to ELF psecs 538 1.8 jonathan * for text, data, and bss. 539 1.6 jonathan */ 540 1.28 christos static int 541 1.31 christos make_ecoff_section_hdrs(struct ecoff32_exechdr *ep, struct ecoff32_scnhdr *esecs) 542 1.27 tsutsui { 543 1.6 jonathan 544 1.8 jonathan ep->f.f_nscns = 6; /* XXX */ 545 1.6 jonathan 546 1.9 lukem strcpy(esecs[0].s_name, ".text"); 547 1.9 lukem strcpy(esecs[1].s_name, ".data"); 548 1.9 lukem strcpy(esecs[2].s_name, ".bss"); 549 1.9 lukem 550 1.9 lukem esecs[0].s_paddr = esecs[0].s_vaddr = ep->a.text_start; 551 1.9 lukem esecs[1].s_paddr = esecs[1].s_vaddr = ep->a.data_start; 552 1.9 lukem esecs[2].s_paddr = esecs[2].s_vaddr = ep->a.bss_start; 553 1.9 lukem esecs[0].s_size = ep->a.tsize; 554 1.9 lukem esecs[1].s_size = ep->a.dsize; 555 1.9 lukem esecs[2].s_size = ep->a.bsize; 556 1.6 jonathan 557 1.31 christos esecs[0].s_scnptr = ECOFF32_TXTOFF(ep); 558 1.31 christos esecs[1].s_scnptr = ECOFF32_DATOFF(ep); 559 1.6 jonathan #if 0 560 1.9 lukem esecs[2].s_scnptr = esecs[1].s_scnptr + 561 1.31 christos ECOFF_ROUND(esecs[1].s_size, ECOFF32_SEGMENT_ALIGNMENT(ep)); 562 1.6 jonathan #endif 563 1.6 jonathan 564 1.9 lukem esecs[0].s_relptr = esecs[1].s_relptr = esecs[2].s_relptr = 0; 565 1.9 lukem esecs[0].s_lnnoptr = esecs[1].s_lnnoptr = esecs[2].s_lnnoptr = 0; 566 1.9 lukem esecs[0].s_nreloc = esecs[1].s_nreloc = esecs[2].s_nreloc = 0; 567 1.9 lukem esecs[0].s_nlnno = esecs[1].s_nlnno = esecs[2].s_nlnno = 0; 568 1.8 jonathan 569 1.8 jonathan esecs[1].s_flags = 0x100; /* ECOFF rdata */ 570 1.8 jonathan esecs[3].s_flags = 0x200; /* ECOFF sdata */ 571 1.8 jonathan esecs[4].s_flags = 0x400; /* ECOFF sbss */ 572 1.8 jonathan 573 1.8 jonathan /* 574 1.8 jonathan * Set the symbol-table offset to point at the end of any 575 1.8 jonathan * sections we loaded above, so later code can use it to write 576 1.8 jonathan * symbol table info.. 577 1.8 jonathan */ 578 1.8 jonathan ep->f.f_symptr = esecs[1].s_scnptr + esecs[1].s_size; 579 1.9 lukem return (ep->f.f_nscns); 580 1.8 jonathan } 581 1.8 jonathan 582 1.8 jonathan 583 1.8 jonathan /* 584 1.8 jonathan * Write the ECOFF symbol header. 585 1.8 jonathan * Guess at how big the symbol table will be. 586 1.8 jonathan * Mark all symbols as EXTERN (for now). 587 1.8 jonathan */ 588 1.28 christos static void 589 1.31 christos write_ecoff_symhdr(int out, struct ecoff32_exechdr *ep, 590 1.31 christos struct ecoff32_symhdr *symhdrp, int32_t nesyms, 591 1.31 christos int32_t extsymoff, int32_t extstroff, int32_t strsize) 592 1.8 jonathan { 593 1.27 tsutsui 594 1.8 jonathan if (debug) 595 1.28 christos fprintf(stderr, 596 1.33 christos "writing symhdr for %d entries at offset %#x\n", 597 1.31 christos nesyms, ep->f.f_symptr); 598 1.8 jonathan 599 1.31 christos ep->f.f_nsyms = sizeof(struct ecoff32_symhdr); 600 1.8 jonathan 601 1.10 perry memset(symhdrp, 0, sizeof(*symhdrp)); 602 1.8 jonathan symhdrp->esymMax = nesyms; 603 1.9 lukem symhdrp->magic = 0x7009;/* XXX */ 604 1.8 jonathan symhdrp->cbExtOffset = extsymoff; 605 1.8 jonathan symhdrp->cbSsExtOffset = extstroff; 606 1.8 jonathan 607 1.8 jonathan symhdrp->issExtMax = strsize; 608 1.8 jonathan if (debug) 609 1.8 jonathan fprintf(stderr, 610 1.31 christos "ECOFF symhdr: symhdr %zx, strsize %x, symsize %zx\n", 611 1.8 jonathan sizeof(*symhdrp), strsize, 612 1.31 christos (nesyms * sizeof(struct ecoff32_extsym))); 613 1.8 jonathan 614 1.16 bouyer if (needswap) { 615 1.22 simonb bswap32_region(&symhdrp->ilineMax, 616 1.16 bouyer sizeof(*symhdrp) - sizeof(symhdrp->magic) - 617 1.16 bouyer sizeof(symhdrp->ilineMax)); 618 1.16 bouyer symhdrp->magic = bswap16(symhdrp->magic); 619 1.16 bouyer symhdrp->ilineMax = bswap16(symhdrp->ilineMax); 620 1.16 bouyer } 621 1.27 tsutsui 622 1.8 jonathan safewrite(out, symhdrp, sizeof(*symhdrp), 623 1.28 christos "writing symbol header"); 624 1.8 jonathan } 625 1.8 jonathan 626 1.8 jonathan 627 1.28 christos static void 628 1.27 tsutsui elf_read_syms(struct elf_syms *elfsymsp, int in, off_t symoff, off_t symsize, 629 1.27 tsutsui off_t stroff, off_t strsize) 630 1.8 jonathan { 631 1.31 christos int nsyms; 632 1.16 bouyer int i; 633 1.9 lukem nsyms = symsize / sizeof(Elf32_Sym); 634 1.8 jonathan 635 1.8 jonathan /* Suck in the ELF symbol list... */ 636 1.8 jonathan elfsymsp->elf_syms = (Elf32_Sym *) 637 1.9 lukem saveRead(in, symoff, nsyms * sizeof(Elf32_Sym), 638 1.9 lukem "ELF symboltable"); 639 1.8 jonathan elfsymsp->nsymbols = nsyms; 640 1.16 bouyer if (needswap) { 641 1.16 bouyer for (i = 0; i < nsyms; i++) { 642 1.16 bouyer Elf32_Sym *s = &elfsymsp->elf_syms[i]; 643 1.16 bouyer s->st_name = bswap32(s->st_name); 644 1.16 bouyer s->st_value = bswap32(s->st_value); 645 1.16 bouyer s->st_size = bswap32(s->st_size); 646 1.16 bouyer s->st_shndx = bswap16(s->st_shndx); 647 1.16 bouyer } 648 1.16 bouyer } 649 1.8 jonathan 650 1.8 jonathan /* Suck in the ELF string table... */ 651 1.8 jonathan elfsymsp->stringtab = (char *) 652 1.9 lukem saveRead(in, stroff, strsize, "ELF string table"); 653 1.8 jonathan elfsymsp->stringsize = strsize; 654 1.8 jonathan } 655 1.8 jonathan 656 1.8 jonathan 657 1.28 christos static void 658 1.31 christos elf_symbol_table_to_ecoff(int out, int in, struct ecoff32_exechdr *ep, 659 1.27 tsutsui off_t symoff, off_t symsize, off_t stroff, off_t strsize) 660 1.8 jonathan { 661 1.8 jonathan 662 1.8 jonathan struct elf_syms elfsymtab; 663 1.8 jonathan struct ecoff_syms ecoffsymtab; 664 1.31 christos uint32_t ecoff_symhdr_off, symtaboff, stringtaboff; 665 1.31 christos uint32_t nextoff, symtabsize, ecoff_strsize; 666 1.16 bouyer int nsyms, i; 667 1.31 christos struct ecoff32_symhdr symhdr; 668 1.9 lukem int padding; 669 1.9 lukem 670 1.8 jonathan /* Read in the ELF symbols. */ 671 1.8 jonathan elf_read_syms(&elfsymtab, in, symoff, symsize, stroff, strsize); 672 1.8 jonathan 673 1.8 jonathan /* Approximate translation to ECOFF. */ 674 1.8 jonathan translate_syms(&elfsymtab, &ecoffsymtab); 675 1.8 jonathan nsyms = ecoffsymtab.nsymbols; 676 1.8 jonathan 677 1.9 lukem /* Compute output ECOFF symbol- and string-table offsets. */ 678 1.8 jonathan ecoff_symhdr_off = ep->f.f_symptr; 679 1.8 jonathan 680 1.8 jonathan nextoff = ecoff_symhdr_off + sizeof(struct ecoff_symhdr); 681 1.8 jonathan stringtaboff = nextoff; 682 1.8 jonathan ecoff_strsize = ECOFF_ROUND(ecoffsymtab.stringsize, 683 1.31 christos (ECOFF32_SEGMENT_ALIGNMENT(ep))); 684 1.8 jonathan 685 1.8 jonathan 686 1.8 jonathan nextoff = stringtaboff + ecoff_strsize; 687 1.8 jonathan symtaboff = nextoff; 688 1.8 jonathan symtabsize = nsyms * sizeof(struct ecoff_extsym); 689 1.31 christos symtabsize = ECOFF_ROUND(symtabsize, ECOFF32_SEGMENT_ALIGNMENT(ep)); 690 1.8 jonathan 691 1.8 jonathan /* Write out the symbol header ... */ 692 1.9 lukem write_ecoff_symhdr(out, ep, &symhdr, nsyms, symtaboff, 693 1.9 lukem stringtaboff, ecoffsymtab.stringsize); 694 1.8 jonathan 695 1.8 jonathan /* Write out the string table... */ 696 1.8 jonathan padding = ecoff_strsize - ecoffsymtab.stringsize; 697 1.9 lukem safewrite(out, ecoffsymtab.stringtab, ecoffsymtab.stringsize, 698 1.28 christos "string table: write"); 699 1.8 jonathan if (padding) 700 1.28 christos pad16(out, padding, "string table: padding"); 701 1.8 jonathan 702 1.8 jonathan 703 1.8 jonathan /* Write out the symbol table... */ 704 1.9 lukem padding = symtabsize - (nsyms * sizeof(struct ecoff_extsym)); 705 1.16 bouyer 706 1.16 bouyer for (i = 0; i < nsyms; i++) { 707 1.16 bouyer struct ecoff_extsym *es = &ecoffsymtab.ecoff_syms[i]; 708 1.16 bouyer es->es_flags = bswap16(es->es_flags); 709 1.16 bouyer es->es_ifd = bswap16(es->es_ifd); 710 1.16 bouyer bswap32_region(&es->es_strindex, 711 1.16 bouyer sizeof(*es) - sizeof(es->es_flags) - sizeof(es->es_ifd)); 712 1.16 bouyer } 713 1.9 lukem safewrite(out, ecoffsymtab.ecoff_syms, 714 1.8 jonathan nsyms * sizeof(struct ecoff_extsym), 715 1.28 christos "symbol table: write"); 716 1.8 jonathan if (padding) 717 1.28 christos pad16(out, padding, "symbols: padding"); 718 1.8 jonathan } 719 1.8 jonathan 720 1.37 tsutsui /* 721 1.38 christos * Compute the total ECOFF string table size. 722 1.37 tsutsui * ELF .strtab can share or overlap substrings, 723 1.37 tsutsui * but ECOFF table needs to have duplicated names. 724 1.37 tsutsui */ 725 1.37 tsutsui static size_t 726 1.38 christos compute_stringsize(const Elf32_Sym *elf_syms, int nsyms, 727 1.37 tsutsui const char *stringbase) 728 1.37 tsutsui { 729 1.37 tsutsui size_t stringsize = 0; 730 1.37 tsutsui int i; 731 1.37 tsutsui 732 1.37 tsutsui for (i = 0; i < nsyms; i++) { 733 1.37 tsutsui const Elf32_Sym *esym = &elf_syms[i]; 734 1.37 tsutsui const char *name; 735 1.8 jonathan 736 1.37 tsutsui if (ELF32_ST_BIND(esym->st_info) == STB_LOCAL) 737 1.37 tsutsui continue; 738 1.37 tsutsui name = stringbase + esym->st_name; 739 1.37 tsutsui stringsize += strlen(name) + 1; 740 1.37 tsutsui } 741 1.37 tsutsui if (stringsize == 0) 742 1.37 tsutsui stringsize = 1; /* for NUL */ 743 1.37 tsutsui 744 1.37 tsutsui return stringsize; 745 1.37 tsutsui } 746 1.8 jonathan 747 1.8 jonathan /* 748 1.34 andvar * In-memory translation of ELF symbols to ECOFF. 749 1.8 jonathan */ 750 1.28 christos static void 751 1.27 tsutsui translate_syms(struct elf_syms *elfp, struct ecoff_syms *ecoffp) 752 1.8 jonathan { 753 1.6 jonathan 754 1.9 lukem int i; 755 1.9 lukem char *oldstringbase; 756 1.9 lukem char *newstrings, *nsp; 757 1.37 tsutsui size_t stringsize; 758 1.9 lukem int nsyms, idx; 759 1.9 lukem 760 1.9 lukem nsyms = elfp->nsymbols; 761 1.9 lukem oldstringbase = elfp->stringtab; 762 1.9 lukem 763 1.9 lukem /* Allocate space for corresponding ECOFF symbols. */ 764 1.10 perry memset(ecoffp, 0, sizeof(*ecoffp)); 765 1.9 lukem 766 1.9 lukem ecoffp->nsymbols = 0; 767 1.9 lukem ecoffp->ecoff_syms = malloc(sizeof(struct ecoff_extsym) * nsyms); 768 1.9 lukem 769 1.37 tsutsui /* ECOFF string table could be bigger than the ELF one. */ 770 1.38 christos stringsize = compute_stringsize(elfp->elf_syms, nsyms, oldstringbase); 771 1.37 tsutsui if (debug) { 772 1.37 tsutsui fprintf(stderr, 773 1.37 tsutsui "%zu (0x%zx) bytes ELF string table\n", 774 1.37 tsutsui (size_t)elfp->stringsize, (size_t)elfp->stringsize); 775 1.37 tsutsui fprintf(stderr, 776 1.37 tsutsui "%zu (0x%zx) bytes required for ECOFF string table\n", 777 1.37 tsutsui stringsize, stringsize); 778 1.37 tsutsui } 779 1.37 tsutsui newstrings = malloc(stringsize); 780 1.28 christos if (newstrings == NULL) 781 1.28 christos errx(1, "No memory for new string table"); 782 1.37 tsutsui /* Copy and translate symbols... */ 783 1.37 tsutsui nsp = newstrings; 784 1.9 lukem idx = 0; 785 1.9 lukem for (i = 0; i < nsyms; i++) { 786 1.37 tsutsui const Elf32_Sym *esym = &elfp->elf_syms[i]; 787 1.37 tsutsui const char *name; 788 1.37 tsutsui size_t namelen; 789 1.9 lukem 790 1.37 tsutsui if (ELF32_ST_BIND(esym->st_info) == STB_LOCAL) 791 1.9 lukem continue; 792 1.37 tsutsui name = oldstringbase + esym->st_name; 793 1.37 tsutsui namelen = strlen(name) + 1; 794 1.37 tsutsui if (nsp + namelen > newstrings + stringsize) 795 1.37 tsutsui errx(1, "ECOFF string table overflow"); 796 1.9 lukem /* Copy the symbol into the new table */ 797 1.37 tsutsui strcpy(nsp, name); 798 1.9 lukem ecoffp->ecoff_syms[idx].es_strindex = nsp - newstrings; 799 1.37 tsutsui nsp += namelen; 800 1.9 lukem 801 1.9 lukem /* translate symbol types to ECOFF XXX */ 802 1.9 lukem ecoffp->ecoff_syms[idx].es_type = 1; 803 1.9 lukem ecoffp->ecoff_syms[idx].es_class = 5; 804 1.9 lukem 805 1.9 lukem /* Symbol values in executables should be compatible. */ 806 1.37 tsutsui ecoffp->ecoff_syms[idx].es_value = esym->st_value; 807 1.9 lukem ecoffp->ecoff_syms[idx].es_symauxindex = 0xfffff; 808 1.8 jonathan 809 1.9 lukem idx++; 810 1.8 jonathan } 811 1.8 jonathan 812 1.9 lukem ecoffp->nsymbols = idx; 813 1.37 tsutsui ecoffp->stringtab = newstrings; 814 1.9 lukem ecoffp->stringsize = nsp - newstrings; 815 1.37 tsutsui if (debug) 816 1.37 tsutsui fprintf(stderr, 817 1.37 tsutsui "%zu (0x%zx) bytes used for ECOFF string table\n", 818 1.37 tsutsui (size_t)ecoffp->stringsize, (size_t)ecoffp->stringsize); 819 1.8 jonathan } 820 1.8 jonathan /* 821 1.8 jonathan * pad to a 16-byte boundary 822 1.8 jonathan */ 823 1.28 christos static void 824 1.8 jonathan pad16(int fd, int size, const char *msg) 825 1.8 jonathan { 826 1.27 tsutsui 827 1.9 lukem safewrite(fd, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0", size, msg); 828 1.16 bouyer } 829 1.16 bouyer 830 1.16 bouyer /* swap a 32bit region */ 831 1.28 christos static void 832 1.22 simonb bswap32_region(int32_t* p, int len) 833 1.16 bouyer { 834 1.23 tsutsui size_t i; 835 1.16 bouyer 836 1.22 simonb for (i = 0; i < len / sizeof(int32_t); i++, p++) 837 1.16 bouyer *p = bswap32(*p); 838 1.1 jonathan } 839