OSDN Git Service

Fixed some spelling mistakes.
[uclinux-h8/elf2flt.git] / elf2flt.c
1 /*
2  * elf2flt.c: Convert ELF (or any BFD format) to FLAT binary format
3  *
4  * (c) 1999-2002, Greg Ungerer <gerg@snapgear.com>
5  * Created elf2flt from coff2flt (see copyrights below). Added all the
6  * ELF format file handling. Extended relocation support for all of
7  * text and data.
8  *
9  * (c) 2001, arm/arm-pic/arm-big-endian support <davidm@snapgear.com>
10  * (c) 2001, v850 changes, Mile Bader <miles@lsi.nec.co.jp>
11  * (c) 2001, zflat support <davidm@snapgear.com>
12  * (c) 2001, Changes for GOT entries
13  *           (Pale Dale, pauli@lineo.com, David McCullough davidm@lineo.com)
14  *
15  * Now supports PIC with GOT tables.  This works by taking a '.elf' file
16  * and a fully linked elf executable (at address 0) and produces a flat
17  * file that can be loaded with some fixups.  It still supports the old
18  * style fully relocatable elf format files.
19  *
20  * Originally obj-res.c
21  *
22  * (c) 1998, Kenneth Albanowski <kjahds@kjahds.com>
23  * (c) 1998, D. Jeff Dionne
24  * (c) 1998, The Silver Hammer Group Ltd.
25  * (c) 1996, 1997 Dionne & Associates
26  *           jeff@ryeham.ee.ryerson.ca
27  *
28  * This is Free Software, under the GNU Public Licence v2 or greater.
29  *
30  * Relocation added March 1997, Kresten Krab Thorup 
31  * krab@california.daimi.aau.dk
32  */
33  
34 #include <stdio.h>    /* Userland pieces of the ANSI C standard I/O package  */
35 #include <stdlib.h>   /* Userland prototypes of the ANSI C std lib functions */
36 #include <stdarg.h>   /* Allows va_list to exist in the these namespaces     */
37 #include <string.h>   /* Userland prototypes of the string handling funcs    */
38 #include <strings.h>
39 #include <unistd.h>   /* Userland prototypes of the Unix std system calls    */
40 #include <fcntl.h>    /* Flag value for file handling functions              */
41 #include <time.h>
42
43 #include <netinet/in.h> /* Consts and structs defined by the internet system */
44
45 /* from $(INSTALLDIR)/include       */
46 #include <bfd.h>      /* Main header file for the BFD library                */
47
48 #include <elf.h>      /* TARGET_* ELF support for the BFD library            */
49
50 /* from uClinux-x.x.x/include/linux */
51 #include "flat.h"     /* Binary flat header description                      */
52
53
54 #ifdef TARGET_v850e
55 #define TARGET_v850
56 #endif
57
58 #if defined(TARGET_m68k)
59 #define ARCH    "m68k/coldfire"
60 #elif defined(TARGET_arm)
61 #define ARCH    "arm"
62 #elif defined(TARGET_sparc)
63 #define ARCH    "sparc"
64 #elif defined(TARGET_v850)
65 #define ARCH    "v850"
66 #else
67 #error "Don't know how to support your CPU architecture??"
68 #endif
69
70 /*
71  * Define a maximum number of bytes allowed in the offset table.
72  * We'll fail if the table is larger than this.
73  *
74  * This limit may be different for platforms other than m68k, but
75  * 8000 entries is a lot,  trust me :-) (davidm)
76  */
77 #define GOT_LIMIT 32767
78
79 #ifndef O_BINARY
80 #define O_BINARY 0
81 #endif
82
83
84 int verbose = 0;      /* extra output when running */
85 int pic_with_got = 0; /* do elf/got processing with PIC code */
86 int load_to_ram = 0;  /* instruct loader to allocate everything into RAM */
87 int compress = 0;     /* 1 = compress everything, 2 = compress data only */
88 int use_resolved = 0; /* If true, get the value of symbol references from */
89                       /* the program contents, not from the relocation table. */
90                       /* In this case, the input ELF file must be already */
91                       /* fully resolved (using the `-q' flag with recent */
92                       /* versions of GNU ld will give you a fully resolved */
93                       /* output file with relocation entries).  */
94
95 const char *progname, *filename;
96 int lineno;
97
98 int nerrors = 0;
99 int nwarnings = 0;
100
101 static char where[200];
102
103 enum {
104   /* Use exactly one of these: */
105   E_NOFILE = 0,         /* "progname: " */
106   E_FILE = 1,           /* "filename: " */
107   E_FILELINE = 2,       /* "filename:lineno: " */
108   E_FILEWHERE = 3,      /* "filename:%s: " -- set %s with ewhere() */
109           
110   /* Add in any of these with |': */
111   E_WARNING = 0x10,
112   E_PERROR = 0x20
113 };
114                   
115 void ewhere (const char *format, ...);
116 void einfo (int type, const char *format, ...);
117                   
118
119 void
120 ewhere (const char *format, ...) {
121   va_list args;
122   va_start (args, format);
123   vsprintf (where, format, args);
124   va_end (args);
125 }
126
127
128 void
129 einfo (int type, const char *format, ...) {
130   va_list args;
131
132   switch (type & 0x0f) {
133   case E_NOFILE:
134     fprintf (stderr, "%s: ", progname);
135     break;
136   case E_FILE:
137     fprintf (stderr, "%s: ", filename);
138     break;
139   case E_FILELINE:
140     ewhere ("%d", lineno);
141     /* fall-through */
142   case E_FILEWHERE:
143     fprintf (stderr, "%s:%s: ", filename, where);
144     break;
145   }
146
147   if (type & E_WARNING) {
148     fprintf (stderr, "warning: ");
149     nwarnings++;
150   } else {
151     nerrors++;
152   }
153
154   va_start (args, format);
155   vfprintf (stderr, format, args);
156   va_end (args);
157
158   if (type & E_PERROR)
159     perror ("");
160   else
161     fprintf (stderr, "\n");
162 }
163
164
165 asymbol**
166 get_symbols (bfd *abfd, long *num)
167 {
168   long storage_needed;
169   asymbol **symbol_table;
170   long number_of_symbols;
171   
172   storage_needed = bfd_get_symtab_upper_bound (abfd);
173           
174   if (storage_needed < 0)
175     abort ();
176       
177   if (storage_needed == 0)
178     return NULL;
179
180   symbol_table = (asymbol **) malloc (storage_needed);
181
182   number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
183   
184   if (number_of_symbols < 0) 
185     abort ();
186
187   *num = number_of_symbols;
188   return symbol_table;
189 }
190
191
192
193 int
194 dump_symbols(asymbol **symbol_table, long number_of_symbols)
195 {
196   long i;
197   printf("SYMBOL TABLE:\n");
198   for (i=0; i<number_of_symbols; i++) {
199         printf("  NAME=%s  VALUE=0x%x\n", symbol_table[i]->name,
200                 symbol_table[i]->value);
201   }
202   printf("\n");
203   return(0);
204 }  
205
206
207
208 long
209 get_symbol_offset(char *name, asection *sec, asymbol **symbol_table, long number_of_symbols)
210 {
211   long i;
212   for (i=0; i<number_of_symbols; i++) {
213     if (symbol_table[i]->section == sec) {
214       if (!strcmp(symbol_table[i]->name, name)) {
215         return symbol_table[i]->value;
216       }
217     }
218   }
219   return -1;
220 }  
221
222
223
224 long
225 add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
226 {
227   long i, comsize;
228   long offset;
229
230   comsize = 0;
231   for (i=0; i<number_of_symbols; i++) {
232     if (strcmp("*COM*", symbol_table[i]->section->name) == 0) {
233       offset = bss_len + comsize;
234       comsize += symbol_table[i]->value;
235       symbol_table[i]->value = offset;
236     }
237   }
238   return comsize;
239 }  
240
241
242
243 unsigned long *
244 output_relocs (
245   bfd *abs_bfd,
246   asymbol **symbols,
247   int number_of_symbols,
248   unsigned long *n_relocs,
249   unsigned char *text, int text_len, unsigned char *data, int data_len,
250   bfd *rel_bfd)
251 {
252   unsigned long         *flat_relocs;
253   asection              *a, *sym_section, *r;
254   arelent               **relpp, **p, *q;
255   const char            *sym_name, *section_name;
256   unsigned char         *sectionp;
257   unsigned long         pflags;
258   char                  addstr[16];
259   long                  sym_addr, sym_vma, section_vma;
260   int                   relsize, relcount;
261   int                   flat_reloc_count;
262   int                   sym_reloc_size, rc;
263   int                   got_size = 0;
264   asymbol               **symb;
265   long                  nsymb;
266   
267 #if 0
268   printf("%s(%d): output_relocs(abs_bfd=%d,synbols=%x,number_of_symbols=%d"
269         "n_relocs=%x,text=%x,text_len=%d,data=%x,data_len=%d)\n",
270         __FILE__, __LINE__, abs_bfd, symbols, number_of_symbols, n_relocs,
271         text, text_len, data, data_len);
272 #endif
273
274 #if 0
275 dump_symbols(symbols, number_of_symbols);
276 #endif
277
278   *n_relocs = 0;
279   flat_relocs = NULL;
280   flat_reloc_count = 0;
281   rc = 0;
282   pflags = 0;
283
284   /* Determine how big our offset table is in bytes.
285    * This isn't too difficult as we've terminated the table with -1.
286    * Also note that both the relocatable and absolute versions have this
287    * terminator even though the relocatable one doesn't have the GOT!
288    */
289   if (pic_with_got) {
290     unsigned long *lp = (unsigned long *)data;
291     /* Should call ntohl(*lp) here but is isn't going to matter */
292     while (*lp != 0xffffffff) lp++;
293     got_size = ((unsigned char *)lp) - data;
294     if (verbose)
295             printf("GOT table contains %d entries (%d bytes)\n",
296                             got_size/sizeof(unsigned long), got_size);
297     if (got_size > GOT_LIMIT) {
298             fprintf(stderr, "GOT too large: %d bytes (limit = %d bytes)\n",
299                             got_size, GOT_LIMIT);
300             exit(1);
301     }
302   }
303
304   for (a = abs_bfd->sections; (a != (asection *) NULL); a = a->next) {
305         section_vma = bfd_section_vma(abs_bfd, a);
306
307         if (verbose)
308                 printf("SECTION: %s [%x]: flags=%x vma=%x\n", a->name, a,
309                         a->flags, section_vma);
310
311 //      if (bfd_is_abs_section(a))
312 //              continue;
313         if (bfd_is_und_section(a))
314                 continue;
315         if (bfd_is_com_section(a))
316                 continue;
317 //      if ((a->flags & SEC_RELOC) == 0)
318 //              continue;
319
320         /*
321          *      Only relocate things in the data sections if we are PIC/GOT.
322          *      otherwise do text as well
323          */
324         if (!pic_with_got && strcmp(".text", a->name) == 0)
325                 sectionp = text;
326         else if (strcmp(".data", a->name) == 0)
327                 sectionp = data;
328         else
329                 continue;
330
331         /* Now search for the equivalent section in the relocation binary
332          * and use that relocation information to build reloc entries
333          * for this one.
334          */
335         for (r=rel_bfd->sections; r != NULL; r=r->next)
336                 if (strcmp(a->name, r->name) == 0)
337                         break;
338         if (r == NULL)
339           continue;
340         if (verbose)
341           printf(" RELOCS: %s [%x]: flags=%x vma=%x\n", r->name, r,
342                         r->flags, bfd_section_vma(abs_bfd, r));
343         if ((r->flags & SEC_RELOC) == 0)
344           continue;
345         relsize = bfd_get_reloc_upper_bound(rel_bfd, r);
346         if (relsize <= 0) {
347                 if (verbose)
348                         printf("%s(%d): no relocation entries section=%x\n",
349                                 __FILE__, __LINE__, r->name);
350                 continue;
351         }
352
353         symb = get_symbols(rel_bfd, &nsymb);
354         relpp = (arelent **) xmalloc(relsize);
355         relcount = bfd_canonicalize_reloc(rel_bfd, r, relpp, symb);
356         if (relcount <= 0) {
357                 if (verbose)
358                         printf("%s(%d): no relocation entries section=%s\n",
359                         __FILE__, __LINE__, r->name);
360                 continue;
361         } else {
362                 for (p = relpp; (relcount && (*p != NULL)); p++, relcount--) {
363                         int relocation_needed = 0;
364
365 #ifdef TARGET_v850
366                         /* Skip this relocation entirely if possible (we
367                            do this early, before doing any other
368                            processing on it).  */
369                         switch ((*p)->howto->type) {
370 #ifdef R_V850_9_PCREL
371                         case R_V850_9_PCREL:
372 #endif
373 #ifdef R_V850_22_PCREL
374                         case R_V850_22_PCREL:
375 #endif
376 #ifdef R_V850_SDA_16_16_OFFSET
377                         case R_V850_SDA_16_16_OFFSET:
378 #endif
379 #ifdef R_V850_SDA_15_16_OFFSET
380                         case R_V850_SDA_15_16_OFFSET:
381 #endif
382 #ifdef R_V850_ZDA_15_16_OFFSET
383                         case R_V850_ZDA_15_16_OFFSET:
384 #endif
385 #ifdef R_V850_TDA_6_8_OFFSET
386                         case R_V850_TDA_6_8_OFFSET:
387 #endif
388 #ifdef R_V850_TDA_7_8_OFFSET
389                         case R_V850_TDA_7_8_OFFSET:
390 #endif
391 #ifdef R_V850_TDA_7_7_OFFSET
392                         case R_V850_TDA_7_7_OFFSET:
393 #endif
394 #ifdef R_V850_TDA_16_16_OFFSET
395                         case R_V850_TDA_16_16_OFFSET:
396 #endif
397 #ifdef R_V850_TDA_4_5_OFFSET
398                         case R_V850_TDA_4_5_OFFSET:
399 #endif
400 #ifdef R_V850_TDA_4_4_OFFSET
401                         case R_V850_TDA_4_4_OFFSET:
402 #endif
403 #ifdef R_V850_SDA_16_16_SPLIT_OFFSET
404                         case R_V850_SDA_16_16_SPLIT_OFFSET:
405 #endif
406 #ifdef R_V850_CALLT_6_7_OFFSET
407                         case R_V850_CALLT_6_7_OFFSET:
408 #endif
409 #ifdef R_V850_CALLT_16_16_OFFSET
410                         case R_V850_CALLT_16_16_OFFSET:
411 #endif
412                                 /* These are relative relocations, which
413                                    have already been fixed up by the
414                                    linker at this point, so just ignore
415                                    them.  */ 
416                                 continue;
417                         }
418 #endif /* USE_V850_RELOCS */
419
420                         q = *p;
421                         if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
422                                 sym_name = (*(q->sym_ptr_ptr))->name;
423                                 sym_section = (*(q->sym_ptr_ptr))->section;
424                                 section_name=(*(q->sym_ptr_ptr))->section->name;
425                         } else {
426                                 printf("ERROR: undefined relocation entry\n");
427                                 rc = -1;
428                                 continue;
429                         }
430                         /* Adjust the address to account for the GOT table which wasn't
431                          * present in the relative file link.
432                          */
433                         if (pic_with_got)
434                           q->address += got_size;
435                                         
436                         /*
437                          *      Fixup offset in the actual section.
438                          */
439                         addstr[0] = 0;
440                         if ((sym_addr = get_symbol_offset((char *) sym_name,
441                             sym_section, symbols, number_of_symbols)) == -1) {
442                                 sym_addr = 0;
443                         }
444
445                         if (use_resolved) {
446                                 /* Use the address of the symbol already in
447                                    the program text.  */
448                                 sym_addr = *((unsigned long *)
449                                              (sectionp + q->address));
450                                 relocation_needed = 1;
451                         } else {
452                                 /* Calculate the sym address ourselves.  */
453                                 sym_reloc_size = bfd_get_reloc_size(q->howto);
454                                 if (sym_reloc_size != 4) {
455                                         printf("ERROR: bad reloc size=%d for symbol=%s\n",
456                                                         sym_reloc_size, sym_name);
457                                         rc = -1;
458                                         continue;
459                                 }
460
461                                 switch ((*p)->howto->type) {
462
463 #if defined(TARGET_m68k)
464                                 case R_68K_32:
465                                         relocation_needed = 1;
466                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
467                                         sym_addr += sym_vma + q->addend;
468                                         break;
469                                 case R_68K_PC32:
470                                         sym_vma = 0;
471                                         sym_addr += sym_vma + q->addend;
472                                         sym_addr -= q->address;
473                                         break;
474 #endif
475
476 #if defined(TARGET_arm)
477                                 case R_ARM_ABS32:
478                                         relocation_needed = 1;
479                                         if (verbose)
480                                                 fprintf(stderr,
481                                                         "%s vma=0x%x, value=0x%x, address=0x%x "
482                                                         "sym_addr=0x%x rs=0x%x, opcode=0x%x\n",
483                                                         "ABS32",
484                                                         sym_vma, (*(q->sym_ptr_ptr))->value,
485                                                         q->address, sym_addr,
486                                                         (*p)->howto->rightshift,
487                                                         *((unsigned long *) (sectionp + q->address)));
488                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
489                                         sym_addr += sym_vma + q->addend;
490                                         break;
491                                 case R_ARM_PLT32:
492                                         if (verbose)
493                                                 fprintf(stderr,
494                                                         "%s vma=0x%x, value=0x%x, address=0x%x "
495                                                         "sym_addr=0x%x rs=0x%x, opcode=0x%x\n",
496                                                         "PLT32",
497                                                         sym_vma, (*(q->sym_ptr_ptr))->value,
498                                                         q->address, sym_addr,
499                                                         (*p)->howto->rightshift,
500                                                         *((unsigned long *) (sectionp + q->address)));
501                                 case R_ARM_PC24:
502                                         sym_vma = 0;
503                                         sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift;
504                                         break;
505 #endif
506
507 #ifdef TARGET_v850
508                                 case R_V850_32:
509                                         relocation_needed = 1;
510                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
511                                         sym_addr += sym_vma + q->addend;
512                                         break;
513 #if defined(R_V850_ZDA_16_16_OFFSET) || defined(R_V850_ZDA_16_16_SPLIT_OFFSET)
514 #ifdef R_V850_ZDA_16_16_OFFSET
515                                 case R_V850_ZDA_16_16_OFFSET:
516 #endif
517 #ifdef R_V850_ZDA_16_16_SPLIT_OFFSET
518                                 case R_V850_ZDA_16_16_SPLIT_OFFSET:
519 #endif
520                                         /* Can't support zero-relocations.  */
521                                         printf ("ERROR: %s+0x%x: zero relocations not supported\n",
522                                                         sym_name, q->addend);
523                                         continue;
524 #endif /* R_V850_ZDA_16_16_OFFSET || R_V850_ZDA_16_16_SPLIT_OFFSET */
525 #endif /* TARGET_v850 */
526
527 #ifdef TARGET_sparc
528                                 case R_SPARC_32:
529                                 case R_SPARC_UA32:
530                                         relocation_needed = 1;
531                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
532                                         sym_addr += sym_vma + q->addend;
533                                         break;
534                                 case R_SPARC_PC22:
535                                         sym_vma = 0;
536                                         sym_addr += sym_vma + q->addend;
537                                         sym_addr -= q->address;
538                                         break;
539                                 case R_SPARC_WDISP30:
540                                         sym_addr = (((*(q->sym_ptr_ptr))->value-
541                                                 q->address) >> 2) & 0x3fffffff;
542                                         sym_addr |= (ntohl(*((unsigned long *) (sectionp + q->address))) & 0xc0000000);
543                                         break;
544                                 case R_SPARC_HI22:
545                                         relocation_needed = 1;
546                                         pflags = 0x80000000;
547                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
548                                         sym_addr += sym_vma + q->addend;
549                                         sym_addr |= (htonl(*((unsigned long *) (sectionp + q->address))) & 0xffc00000);
550                                         break;
551                                 case R_SPARC_LO10:
552                                         relocation_needed = 1;
553                                         pflags = 0x40000000;
554                                         sym_vma = bfd_section_vma(abs_bfd, sym_section);
555                                         sym_addr += sym_vma + q->addend;
556                                         sym_addr &= 0x000003ff;
557                                         sym_addr |= (htonl(*((unsigned long *) (sectionp + q->address))) & 0xfffffc00);
558                                         break;
559 #endif /* TARGET_sparc */
560
561                                 default:
562                                         /* missing support for other types of relocs */
563                                         printf("ERROR: bad reloc type %d\n", (*p)->howto->type);
564                                         continue;
565                                 }
566                         }
567
568                         sprintf(&addstr[0], "+0x%x", sym_addr - (*(q->sym_ptr_ptr))->value -
569                                          bfd_section_vma(abs_bfd, sym_section));
570
571
572                         /*
573                          * for full elf relocation we have to write back the start_code
574                          * relative value to use.
575                          */
576                         if (!pic_with_got) {
577 #if defined(TARGET_arm)
578                                 union {
579                                         unsigned char c[4];
580                                         unsigned long l;
581                                 } tmp;
582                                 long hl;
583                                 int i0, i1, i2, i3;
584
585                                 /*
586                                  * horrible nasty hack to support different endianess
587                                  */
588                                 if (!bfd_big_endian(abs_bfd)) {
589                                         i0 = 0;
590                                         i1 = 1;
591                                         i2 = 2;
592                                         i3 = 3;
593                                 } else {
594                                         i0 = 3;
595                                         i1 = 2;
596                                         i2 = 1;
597                                         i3 = 0;
598                                 }
599
600                                 tmp.l = *((unsigned long *) (sectionp + q->address));
601                                 hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
602                                 if (((*p)->howto->type != R_ARM_PC24) &&
603                                     ((*p)->howto->type != R_ARM_PLT32))
604                                         hl |= (tmp.c[i3] << 24);
605                                 else if (tmp.c[i2] & 0x80)
606                                         hl |= 0xff000000; /* sign extend */
607                                 hl += sym_addr;
608                                 tmp.c[i0] = hl & 0xff;
609                                 tmp.c[i1] = (hl >> 8) & 0xff;
610                                 tmp.c[i2] = (hl >> 16) & 0xff;
611                                 if (((*p)->howto->type != R_ARM_PC24) &&
612                                     ((*p)->howto->type != R_ARM_PLT32))
613                                         tmp.c[i3] = (hl >> 24) & 0xff;
614                                 if ((*p)->howto->type == R_ARM_ABS32)
615                                         *((unsigned long *) (sectionp + q->address)) = htonl(hl);
616                                 else
617                                         *((unsigned long *) (sectionp + q->address)) = tmp.l;
618 #else /* ! TARGET_arm */
619                                 *((unsigned long *) (sectionp + q->address)) = htonl(sym_addr);
620 #endif
621                         }
622
623                         if (verbose)
624                                 printf("  RELOC[%d]: offset=%x symbol=%s%s "
625                                         "section=%s size=%d "
626                                         "fixup=%x (reloc=0x%x)\n", flat_reloc_count,
627                                         q->address, sym_name, addstr,
628                                         section_name, sym_reloc_size,
629                                         sym_addr, section_vma + q->address);
630
631                         /*
632                          *      Create relocation entry (PC relative doesn't need this).
633                          */
634                         if (relocation_needed) {
635                                 flat_relocs = realloc(flat_relocs,
636                                         (flat_reloc_count + 1) * sizeof(unsigned long));
637                                 flat_relocs[flat_reloc_count] = pflags |
638                                         (section_vma + q->address);
639
640                                 if (verbose)
641                                         printf("reloc[%d] = 0x%x\n", flat_reloc_count,
642                                                         section_vma + q->address);
643                                 flat_reloc_count++;
644                                 relocation_needed = 0;
645                                 pflags = 0;
646                         }
647
648 #if 0
649 printf("%s(%d): symbol name=%s address=%x section=%s -> RELOC=%x\n",
650         __FILE__, __LINE__, sym_name, q->address, section_name,
651         flat_relocs[flat_reloc_count]);
652 #endif
653                 }
654         }
655   }
656
657   if (rc < 0)
658         return(NULL);
659
660     *n_relocs = flat_reloc_count;
661     return flat_relocs;
662 }
663
664
665
666 #if 0
667 /* shared lib symbols stuff */
668
669 long
670 get_symbol(char *name, asection *sec, asymbol **symbol_table, long number_of_symbols)
671 {
672   long i;
673   for (i=0; i<number_of_symbols; i++) {
674     if (symbol_table[i]->section == sec) {
675       if (!strcmp(symbol_table[i]->name, name)) {
676         return symbol_table[i]->value;
677       }
678     }
679   }
680   return -1;
681 }  
682
683 int
684 output_offset_table(int fd, char *ename, bfd *abfd, asymbol **symbol_table, long number_of_symbols)
685 {
686   long i;
687   FILE *ef;
688   char buf[80];
689   char libname[80];
690   long etext_addr;
691   long sym_addr;
692
693   int foobar = 0;
694   int count = 0;
695   signed short *tab = malloc(32768); /* we don't know how many yet*/
696
697   asection *text_section = bfd_get_section_by_name (abfd, ".text");
698
699   if (!(ef = fopen(ename, "r"))) {
700     fprintf (stderr,"Can't open %s\n",ename);
701     exit(1);
702   }
703
704   fgets(libname, 80, ef);
705
706   if (number_of_symbols < 0) {
707     fprintf (stderr,"Corrupt symbol table!\n");
708     exit(1);
709   }
710
711   if ((etext_addr = get_symbol("etext",
712                                text_section,
713                                symbol_table,
714                                number_of_symbols)) == -1) {
715     fprintf (stderr,"Can't find the symbol etext\n");
716     exit(1);
717   }
718
719   fgets(buf, 80, ef);
720   while (!feof(ef)) {
721     buf[strlen(buf)-1] = 0; /* Arrrgh! linefeeds */
722
723     if ((sym_addr = get_symbol(buf,
724                                text_section,
725                                symbol_table,
726                                number_of_symbols)) == -1) {
727       fprintf (stderr,"Can't find the symbol %s\n",buf);
728       foobar++;
729     } else {
730       tab[++count] = htons(sym_addr - etext_addr);
731     }
732     fgets(buf, 80, ef);
733   }
734
735   fclose(ef);
736
737   if (foobar) {
738     fprintf (stderr,"*** %d symbols not found\n",foobar);
739     exit(10);
740   }
741
742   strcpy((char *)&tab[++count],libname);
743   tab[0] = htons(count * 2);
744   write(fd, tab, count * 2 + strlen(libname) + 2);
745   return 0;
746 }
747 #endif
748
749
750 static char * program;
751
752 static void usage(void)
753 {  
754     fprintf(stderr, "Usage: %s [vrzd] [-p <abs-pic-file>] [-s stack-size] "
755         "[-o <output-file>] <elf-file>\n\n"
756         "       -v              : verbose operation\n"
757         "       -r              : force load to RAM\n"
758         "       -z              : compress code/data/relocs\n"
759         "       -d              : compress data/relocs\n"
760         "       -a              : use existing symbol references\n"
761         "                         instead of recalculating from\n"
762         "                         relocation info\n"
763         "       -p abs-pic-file : GOT/PIC processing with files\n"
764         "       -s stacksize    : set application stack size\n"
765         "       -o output-file  : output file name\n\n",
766         program);
767         fprintf(stderr, "Compiled for " ARCH " architecture\n\n");
768     exit(2);
769 }
770
771
772
773 int main(int argc, char *argv[])
774 {
775   int fd;
776   bfd *rel_bfd, *abs_bfd;
777   asection *s;
778   char *ofile=NULL, *pfile=NULL;
779   char *fname = NULL;
780   int opt;
781   int i;
782   int stack;
783   char  cmd[1024];
784   FILE *gf = NULL;
785
786
787   asymbol **symbol_table;
788   long number_of_symbols;
789
790   unsigned long data_len;
791   unsigned long bss_len;
792   unsigned long text_len;
793   unsigned long reloc_len;
794
795   unsigned long data_vma;
796   unsigned long bss_vma;
797   unsigned long text_vma;
798
799   void *text;
800   void *data;
801   unsigned long *reloc;
802   
803   struct flat_hdr hdr;
804
805
806   program = argv[0];
807   progname = argv[0];
808
809   if (argc < 2)
810         usage();
811   
812   stack = 4096;
813
814   while ((opt = getopt(argc, argv, "avzdrp:s:o:")) != -1) {
815     switch (opt) {
816     case 'v':
817       verbose++;
818       break;
819     case 'r':
820       load_to_ram++;
821       break;
822     case 'z':
823       compress = 1;
824       break;
825     case 'd':
826       compress = 2;
827       break;
828     case 'p':
829       pfile = optarg;
830       break;
831     case 'o':
832       ofile = optarg;
833       break;
834     case 'a':
835       use_resolved = 1;
836       break;
837     case 's':
838       stack = atoi(optarg);
839       break;
840     default:
841       fprintf(stderr, "%s Unknown option\n", argv[0]);
842       usage();
843       break;
844     }
845   }
846   
847   /*
848    * if neither the -r or -p options was given,  default to
849    * a RAM load as that is the only option that makes sense.
850    */
851   if (!load_to_ram && !pfile)
852     load_to_ram = 1;
853
854   filename = fname = argv[argc-1];
855
856   if (!(rel_bfd = bfd_openr(fname, 0))) {
857     fprintf(stderr, "Can't open %s\n", fname);
858     exit(1);
859   }
860
861   if (bfd_check_format (rel_bfd, bfd_object) == 0) {
862     fprintf(stderr, "File is not an object file\n");
863     exit(2);
864   }
865
866   if (pfile) {
867     pic_with_got = 1;
868
869     if (!(abs_bfd = bfd_openr(pfile, 0))) {
870       fprintf(stderr, "Can't open %s\n", pfile);
871       exit(1);
872     }
873
874     if (bfd_check_format (abs_bfd, bfd_object) == 0) {
875       fprintf(stderr, "File is not an object file\n");
876       exit(2);
877     }
878   } else {
879     abs_bfd = rel_bfd; /* one file does all */
880   }
881
882   if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC)) {
883     fprintf (stderr, "%s: Input file contains no relocation info\n", fname);
884     exit (2);
885   }
886
887   if (use_resolved && !(bfd_get_file_flags(abs_bfd) & EXEC_P)) {
888     /* `Absolute' file is not absolute, so neither are address
889        contained therein.  */
890     fprintf (stderr,
891              "%s: `-a' option specified with non-fully-resolved input file\n",
892              bfd_get_filename (abs_bfd));
893     exit (2);
894   }
895
896   symbol_table = get_symbols(abs_bfd, &number_of_symbols);
897
898   s = bfd_get_section_by_name (abs_bfd, ".text");
899   text_vma = s->vma;
900   text_len = s->_raw_size;
901   text = malloc(text_len);
902
903   if (verbose) {
904     printf("TEXT -> vma=%x len=%x\n", text_vma, text_len);
905     printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
906                         s->lma, s->_cooked_size, s->output_offset,
907                         s->alignment_power, s->filepos);
908   }
909
910   if (bfd_get_section_contents(abs_bfd,
911                                s, 
912                                text,
913                                0,
914                                s->_raw_size) == false) {
915     fprintf(stderr, "read error section %s\n", s->name);
916     exit(2);
917   }
918
919   s = bfd_get_section_by_name (abs_bfd, ".data");
920   data_vma = s->vma;
921   data_len = s->_raw_size;
922   data = malloc(data_len);
923
924   if (verbose) {
925      printf("DATA -> vma=%x len=%x\n", data_vma, data_len);
926      printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
927                         s->lma, s->_cooked_size, s->output_offset,
928                         s->alignment_power, s->filepos);
929   }
930   if ((text_vma + text_len) != data_vma) {
931     if ((text_vma + text_len) > data_vma) {
932       printf("ERROR: text=%x overlaps data=%x ?\n", text_len, data_vma);
933       exit(1);
934     }
935     if (verbose)
936       printf("WARNING: data=%x does not directly follow text=%x\n",
937                         data_vma, text_len);
938     text_len = data_vma - text_vma;
939   }
940
941   if (bfd_get_section_contents(abs_bfd,
942                                s, 
943                                data,
944                                0,
945                                s->_raw_size) == false) {
946     fprintf(stderr, "read error section %s\n", s->name);
947     exit(2);
948   }
949
950   s = bfd_get_section_by_name (abs_bfd, ".bss");
951   bss_len = s->_raw_size;
952   bss_vma = s->vma;
953   bss_len += add_com_to_bss(symbol_table, number_of_symbols, bss_len);
954
955   if (verbose) {
956         printf("BSS  -> vma=%x len=%x\n", bss_vma, bss_len);
957     printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
958                         s->lma, s->_cooked_size, s->output_offset,
959                         s->alignment_power, s->filepos);
960   }
961
962   if ((text_vma + text_len + data_len) != bss_vma) {
963     if ((text_vma + text_len + data_len) > bss_vma) {
964       printf("ERROR: text=%x + data=%x overlaps bss=%x ?\n", text_len,
965                         data_len, bss_vma);
966       exit(1);
967     }
968     if (verbose)
969       printf("WARNING: bss=%x does not directly follow text=%x + data=%x(%x)\n",
970                 bss_vma, text_len, data_len, text_len + data_len);
971       data_len = bss_vma - data_vma;
972   }
973
974   reloc = (unsigned long *) output_relocs (abs_bfd, symbol_table,
975       number_of_symbols, &reloc_len, text, text_len, data, data_len, rel_bfd);
976
977   if (reloc == NULL)
978     printf("No relocations in code!\n");
979
980   /* Fill in the binflt_flat header */
981   memcpy(hdr.magic,"bFLT",4);
982   hdr.rev         = htonl(FLAT_VERSION);
983   hdr.entry       = htonl(16 * 4 + bfd_get_start_address(abs_bfd));
984   hdr.data_start  = htonl(16 * 4 + text_len);
985   hdr.data_end    = htonl(16 * 4 + text_len + data_len);
986   hdr.bss_end     = htonl(16 * 4 + text_len + data_len + bss_len);
987   hdr.stack_size  = htonl(stack); /* FIXME */
988   hdr.reloc_start = htonl(16 * 4 + text_len + data_len);
989   hdr.reloc_count = htonl(reloc_len);
990   hdr.flags       = htonl(0
991           | (load_to_ram ? FLAT_FLAG_RAM : 0)
992           | (pic_with_got ? FLAT_FLAG_GOTPIC : 0)
993           | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
994           );
995   hdr.build_date = htonl((unsigned long)time(NULL));
996   bzero(hdr.filler, sizeof(hdr.filler));
997
998   for (i=0; i<reloc_len; i++) reloc[i] = htonl(reloc[i]);
999
1000   if (verbose) {
1001     printf("SIZE: .text=0x%04x, .data=0x%04x, .bss=0x%04x",
1002         text_len, data_len, bss_len);
1003     if (reloc)
1004       printf(", relocs=0x%04x", reloc_len);
1005     printf("\n");
1006   }
1007   
1008   if (!ofile) {
1009     ofile = malloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
1010     strcpy(ofile, fname);
1011     strcat(ofile, ".bflt");
1012   }
1013
1014   if ((fd = open (ofile, O_WRONLY|O_BINARY|O_CREAT|O_TRUNC, 0744)) < 0) {
1015     fprintf (stderr, "Can't open output file %s\n", ofile);
1016     exit(4);
1017   }
1018
1019   write(fd, &hdr, sizeof(hdr));
1020   close(fd);
1021
1022   /*
1023    * get the compression command ready
1024    */
1025   sprintf(cmd, "gzip -f -9 >> %s", ofile);
1026
1027 #define START_COMPRESSOR do { \
1028                 if (gf) fclose(gf); \
1029                 if (!(gf = popen(cmd, "w"))) { \
1030                         fprintf(stderr, "Can't run cmd %s\n", cmd); \
1031                         exit(4); \
1032                 } \
1033         } while (0)
1034
1035   gf = fopen(ofile, "a");
1036   if (!gf) {
1037         fprintf(stderr, "Can't opne file %s for writing\n", ofile); \
1038         exit(4);
1039   }
1040
1041   if (compress == 1)
1042         START_COMPRESSOR;
1043
1044   fwrite(text, text_len, 1, gf);
1045
1046   if (compress == 2)
1047         START_COMPRESSOR;
1048
1049   fwrite(data, data_len, 1, gf);
1050   if (reloc)
1051     fwrite(reloc, reloc_len*4, 1, gf);
1052   fclose(gf);
1053
1054   exit(0);
1055 }
1056