OSDN Git Service

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