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