OSDN Git Service

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