OSDN Git Service

This patch is required to successfully link against libstdc++ on the Nios2
[uclinux-h8/elf2flt.git] / elf2flt.c
index 324ef3d..1cc6c03 100644 (file)
--- a/elf2flt.c
+++ b/elf2flt.c
@@ -6,11 +6,17 @@
  * ELF format file handling. Extended relocation support for all of
  * text and data.
  *
- * (c) 2001, arm/arm-pic/arm-big-endian support <davidm@snapgear.com>
+ * (c) 2006  Support the -a (use_resolved) option for TARGET_arm.
+ *           Shaun Jackman <sjackman@gmail.com>
+ * (c) 2004, Nios II support, Wentao Xu <wentao@microtronix.com>
+ * (c) 2003, H8 support, ktrace <davidm@snapgear.com>
+ * (c) 2003-2004, MicroBlaze support, John Williams <jwilliams@itee.uq.edu.au>
+ * (c) 2001-2003, arm/arm-pic/arm-big-endian support <davidm@snapgear.com>
  * (c) 2001, v850 changes, Mile Bader <miles@lsi.nec.co.jp>
+ * (c) 2003, SuperH support, Paul Mundt <lethal@linux-sh.org>
  * (c) 2001, zflat support <davidm@snapgear.com>
- * (c) 2001, Changes for GOT entries
- *           (Pale Dale, pauli@lineo.com, David McCullough davidm@lineo.com)
+ * (c) 2001, Changes for GOT entries Paul Dale <pauli@snapgear.com> and
+ *           David McCullough <davidm@snapgear.com>
  *
  * Now supports PIC with GOT tables.  This works by taking a '.elf' file
  * and a fully linked elf executable (at address 0) and produces a flat
@@ -22,8 +28,7 @@
  * (c) 1998, Kenneth Albanowski <kjahds@kjahds.com>
  * (c) 1998, D. Jeff Dionne
  * (c) 1998, The Silver Hammer Group Ltd.
- * (c) 1996, 1997 Dionne & Associates
- *           jeff@ryeham.ee.ryerson.ca
+ * (c) 1996, 1997 Dionne & Associates <jeff@ryeham.ee.ryerson.ca>
  *
  * This is Free Software, under the GNU Public Licence v2 or greater.
  *
  * krab@california.daimi.aau.dk
  */
  
-#include <stdio.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <netinet/in.h>
+#include <stdio.h>    /* Userland pieces of the ANSI C standard I/O package  */
+#include <stdlib.h>   /* Userland prototypes of the ANSI C std lib functions */
+#include <stdarg.h>   /* Allows va_list to exist in the these namespaces     */
+#include <string.h>   /* Userland prototypes of the string handling funcs    */
+#include <strings.h>
+#include <unistd.h>   /* Userland prototypes of the Unix std system calls    */
+#include <fcntl.h>    /* Flag value for file handling functions              */
+#include <time.h>
+#ifndef WIN32
+#include <netinet/in.h> /* Consts and structs defined by the internet system */
+#define        BINARY_FILE_OPTS
+#else
+#include <winsock2.h>
+#define        BINARY_FILE_OPTS "b"
+#endif
+
+/* from $(INSTALLDIR)/include       */
+#include <bfd.h>      /* Main header file for the BFD library                */
+
+#if defined(TARGET_h8300)
+#include <elf/h8.h>      /* TARGET_* ELF support for the BFD library            */
+#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(TARGET_nios) || defined(TARGET_nios2)
+#include "cygwin-elf.h"        /* Cygwin uses a local copy */
+#elif defined(TARGET_microblaze)
+#include <elf/microblaze.h>    /* TARGET_* ELF support for the BFD library */
+#elif defined(TARGET_bfin)
+#include "elf/bfin.h"
+#else
+#include <elf.h>      /* TARGET_* ELF support for the BFD library            */
+#endif
+
+#if defined(__MINGW32__)
 #include <getopt.h>
-#include <stdarg.h>
-#include <bfd.h>
-#include <elf.h>
-#include "flat.h"
+#endif
+
+/* from uClinux-x.x.x/include/linux */
+#include "flat.h"     /* Binary flat header description                      */
+
+#ifdef TARGET_e1
+#include <e1.h>
+#endif
+
+#ifdef TARGET_v850e
+#define TARGET_v850
+#endif
 
 #if defined(TARGET_m68k)
 #define        ARCH    "m68k/coldfire"
 #define        ARCH    "sparc"
 #elif defined(TARGET_v850)
 #define        ARCH    "v850"
+#elif defined(TARGET_sh)
+#define        ARCH    "sh"
+#elif defined(TARGET_h8300)
+#define        ARCH    "h8300"
+#elif defined(TARGET_microblaze)
+#define ARCH   "microblaze"
+#elif defined(TARGET_e1)
+#define ARCH    "e1-coff"
+#elif defined(TARGET_bfin)
+#define ARCH   "bfin"
+#define FLAT_RELOC_TYPE_TEXT 0
+#define FLAT_RELOC_TYPE_DATA 1
+#define FLAT_RELOC_TYPE_BSS 2
+#define FLAT_RELOC_TYPE_STACK 3
+#define FLAT_RELOC_PART_LO 0
+#define FLAT_RELOC_PART_HI 1
+#define PCREL24_MAGIC_OFFSET -1
+#elif defined(TARGET_nios)
+#define ARCH   "nios"
+#elif defined(TARGET_nios2)
+#define ARCH   "nios2"
 #else
-#error "Don't know how to support you CPU archiecture??"
+#error "Don't know how to support your CPU architecture??"
 #endif
 
+#if defined(TARGET_m68k) || defined(TARGET_h8300) || defined(TARGET_bfin)
 /*
  * Define a maximum number of bytes allowed in the offset table.
  * We'll fail if the table is larger than this.
  * 8000 entries is a lot,  trust me :-) (davidm)
  */
 #define GOT_LIMIT 32767
+/*
+ * we have to mask out the shared library id here and there,  this gives
+ * us the real address bits when needed
+ */
+#define        real_address_bits(x)    (pic_with_got ? ((x) & 0xffffff) : (x))
+#else
+#define        real_address_bits(x)    (x)
+#endif
 
 #ifndef O_BINARY
 #define O_BINARY 0
 int verbose = 0;      /* extra output when running */
 int pic_with_got = 0; /* do elf/got processing with PIC code */
 int load_to_ram = 0;  /* instruct loader to allocate everything into RAM */
+int ktrace = 0;       /* instruct loader output kernel trace on load */
 int compress = 0;     /* 1 = compress everything, 2 = compress data only */
 int use_resolved = 0; /* If true, get the value of symbol references from */
-                      /* the program contents, not from the relocation table. */
-                                         /* In this case, the input ELF file must be already */
-                                         /* fully resolved (using the `-q' flag with recent */
-                      /* versions of GNU ld will give you a fully resolved */
-                                         /* output file with relocation entries).  */
+                     /* the program contents, not from the relocation table. */
+                     /* In this case, the input ELF file must be already */
+                     /* fully resolved (using the `-q' flag with recent */
+                     /* versions of GNU ld will give you a fully resolved */
+                     /* output file with relocation entries).  */
 
 const char *progname, *filename;
 int lineno;
@@ -134,9 +205,9 @@ einfo (int type, const char *format, ...) {
   if (type & E_WARNING) {
     fprintf (stderr, "warning: ");
     nwarnings++;
-  }
-  else
+  } else {
     nerrors++;
+  }
 
   va_start (args, format);
   vfprintf (stderr, format, args);
@@ -161,11 +232,14 @@ get_symbols (bfd *abfd, long *num)
   if (storage_needed < 0)
     abort ();
       
-  if (storage_needed == 0) {
+  if (storage_needed == 0)
     return NULL;
-  }
 
   symbol_table = (asymbol **) malloc (storage_needed);
+  if (symbol_table == NULL) {
+      perror("malloc");
+      exit(1);
+  }
 
   number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
   
@@ -200,7 +274,7 @@ get_symbol_offset(char *name, asection *sec, asymbol **symbol_table, long number
   for (i=0; i<number_of_symbols; i++) {
     if (symbol_table[i]->section == sec) {
       if (!strcmp(symbol_table[i]->name, name)) {
-       return symbol_table[i]->value;
+        return symbol_table[i]->value;
       }
     }
   }
@@ -210,6 +284,19 @@ get_symbol_offset(char *name, asection *sec, asymbol **symbol_table, long number
 
 
 long
+get_gp_value(asymbol **symbol_table, long number_of_symbols)
+{
+  long i;
+  for (i=0; i<number_of_symbols; i++) {
+      if (!strcmp(symbol_table[i]->name, "_gp"))
+               return symbol_table[i]->value;
+  }
+  return -1;
+}
+
+
+long
 add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
 {
   long i, comsize;
@@ -226,18 +313,85 @@ add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
   return comsize;
 }  
 
+#ifdef TARGET_bfin
+/* FUNCTION : weak_und_symbol
+   ABSTRACT : return true if symbol is weak and undefined.
+*/
+static int
+weak_und_symbol(const char *reloc_section_name,
+                struct bfd_symbol *symbol)
+{
+    if (!(strstr (reloc_section_name, "text")
+         || strstr (reloc_section_name, "data")
+         || strstr (reloc_section_name, "bss"))) {
+       if (symbol->flags & BSF_WEAK) {
+#ifdef DEBUG_BFIN
+           fprintf(stderr, "found weak undefined symbol %s\n", symbol->name);
+#endif
+           return TRUE;
+       }
+    }
+    return FALSE;
+}
+
+static int
+bfin_set_reloc (uint32_t *reloc, 
+               const char *reloc_section_name, 
+               const char *sym_name,
+               struct bfd_symbol *symbol,
+               int sp, int hilo, int32_t offset)
+{
+    unsigned int type;
+    uint32_t val;
+
+    if (strstr (reloc_section_name, "text"))
+       type = FLAT_RELOC_TYPE_TEXT;
+    else if (strstr (reloc_section_name, "data"))
+       type = FLAT_RELOC_TYPE_DATA;
+    else if (strstr (reloc_section_name, "bss"))
+       type = FLAT_RELOC_TYPE_BSS;
+    else if (strstr (reloc_section_name, "stack"))
+       type = FLAT_RELOC_TYPE_STACK;
+    else if (symbol->flags & BSF_WEAK){
+       /* weak symbol support ... if a weak symbol is undefined at the
+          end of a final link, it should return 0 rather than error
+          We will assume text section for the moment.
+       */
+       type = FLAT_RELOC_TYPE_TEXT;
+    } else if (strstr (reloc_section_name, "*ABS*")){
+       /* (A data section initialization of something in the shared libc's text section
+          does not resolve - i.e. a global pointer to function initialized with
+          a libc function).
+          The text section here is appropriate as the section information
+          of the shared library is lost. The loader will do some calcs.
+       */
+       type = FLAT_RELOC_TYPE_TEXT;
+    } else {
+       printf ("Unknown Type - relocation for %s in bad section - %s\n", sym_name, reloc_section_name);
+       return 1;
+    }
+
+    val = (offset & ((1 << 26) - 1)) << 6;
+    val |= (sp & (1 << 3) - 1) << 3;
+    val |= (hilo & 1) << 2;
+    val |= (type & (1 << 2) - 1);
+    *reloc = val;
+    return 0;
+}
+#endif
 
 
-unsigned long *
+uint32_t *
 output_relocs (
   bfd *abs_bfd,
   asymbol **symbols,
   int number_of_symbols,
   unsigned long *n_relocs,
-  unsigned char *text, int text_len, unsigned char *data, int data_len,
+  unsigned char *text, int text_len, unsigned long text_vma,
+  unsigned char *data, int data_len, unsigned long data_vma,
   bfd *rel_bfd)
 {
-  unsigned long                *flat_relocs;
+  uint32_t             *flat_relocs;
   asection             *a, *sym_section, *r;
   arelent              **relpp, **p, *q;
   const char           *sym_name, *section_name;
@@ -249,12 +403,13 @@ output_relocs (
   int                  flat_reloc_count;
   int                  sym_reloc_size, rc;
   int                  got_size = 0;
+  int                  bad_relocs = 0;
   asymbol              **symb;
   long                 nsymb;
   
 #if 0
-  printf("%s(%d): output_relocs(abs_bfd=%d,synbols=%x,number_of_symbols=%d"
-       "n_relocs=%x,text=%x,text_len=%d,data=%x,data_len=%d)\n",
+  printf("%s(%d): output_relocs(abs_bfd=%d,synbols=0x%x,number_of_symbols=%d"
+       "n_relocs=0x%x,text=0x%x,text_len=%d,data=0x%x,data_len=%d)\n",
        __FILE__, __LINE__, abs_bfd, symbols, number_of_symbols, n_relocs,
        text, text_len, data, data_len);
 #endif
@@ -274,7 +429,7 @@ dump_symbols(symbols, number_of_symbols);
    * Also note that both the relocatable and absolute versions have this
    * terminator even though the relocatable one doesn't have the GOT!
    */
-  if (pic_with_got) {
+  if (pic_with_got && !use_resolved) {
     unsigned long *lp = (unsigned long *)data;
     /* Should call ntohl(*lp) here but is isn't going to matter */
     while (*lp != 0xffffffff) lp++;
@@ -282,18 +437,20 @@ dump_symbols(symbols, number_of_symbols);
     if (verbose)
            printf("GOT table contains %d entries (%d bytes)\n",
                            got_size/sizeof(unsigned long), got_size);
+#ifdef TARGET_m68k
     if (got_size > GOT_LIMIT) {
            fprintf(stderr, "GOT too large: %d bytes (limit = %d bytes)\n",
                            got_size, GOT_LIMIT);
            exit(1);
     }
+#endif
   }
 
   for (a = abs_bfd->sections; (a != (asection *) NULL); a = a->next) {
        section_vma = bfd_section_vma(abs_bfd, a);
 
        if (verbose)
-               printf("SECTION: %s [%x]: flags=%x vma=%x\n", a->name, a,
+               printf("SECTION: %s [0x%x]: flags=0x%x vma=0x%x\n", a->name, a,
                        a->flags, section_vma);
 
 //     if (bfd_is_abs_section(a))
@@ -309,10 +466,10 @@ dump_symbols(symbols, number_of_symbols);
         *      Only relocate things in the data sections if we are PIC/GOT.
         *      otherwise do text as well
         */
-       if (!pic_with_got && strcmp(".text", a->name) == 0)
-               sectionp = text;
-       else if (strcmp(".data", a->name) == 0)
-               sectionp = data;
+       if (!pic_with_got && (a->flags & SEC_CODE))
+               sectionp = text + (a->vma - text_vma);
+       else if (a->flags & SEC_DATA)
+               sectionp = data + (a->vma - data_vma);
        else
                continue;
 
@@ -326,20 +483,25 @@ dump_symbols(symbols, number_of_symbols);
        if (r == NULL)
          continue;
        if (verbose)
-         printf(" RELOCS: %s [%x]: flags=%x vma=%x\n", r->name, r,
+         printf(" RELOCS: %s [0x%x]: flags=0x%x vma=0x%x\n", r->name, r,
                        r->flags, bfd_section_vma(abs_bfd, r));
        if ((r->flags & SEC_RELOC) == 0)
          continue;
        relsize = bfd_get_reloc_upper_bound(rel_bfd, r);
        if (relsize <= 0) {
                if (verbose)
-                       printf("%s(%d): no relocation entries section=%x\n",
+                       printf("%s(%d): no relocation entries section=0x%x\n",
                                __FILE__, __LINE__, r->name);
                continue;
        }
 
        symb = get_symbols(rel_bfd, &nsymb);
-       relpp = (arelent **) xmalloc(relsize);
+       relpp = (arelent **) malloc(relsize);
+       if (relpp == NULL) {
+         perror("malloc");
+         exit(1);
+       }
+
        relcount = bfd_canonicalize_reloc(rel_bfd, r, relpp, symb);
        if (relcount <= 0) {
                if (verbose)
@@ -348,8 +510,22 @@ dump_symbols(symbols, number_of_symbols);
                continue;
        } else {
                for (p = relpp; (relcount && (*p != NULL)); p++, relcount--) {
+                       unsigned char *r_mem;
                        int relocation_needed = 0;
 
+#ifdef TARGET_microblaze
+                       /* The MICROBLAZE_XX_NONE relocs can be skipped.
+                          They represent PC relative branches that the
+                          linker has already resolved */
+                               
+                       switch ((*p)->howto->type) 
+                       {
+                       case R_MICROBLAZE_NONE:
+                       case R_MICROBLAZE_64_NONE:
+                               continue;
+                       }
+#endif /* TARGET_microblaze */
+
 #ifdef TARGET_v850
                        /* Skip this relocation entirely if possible (we
                           do this early, before doing any other
@@ -415,36 +591,188 @@ dump_symbols(symbols, number_of_symbols);
                                rc = -1;
                                continue;
                        }
+#ifndef TARGET_bfin
                        /* Adjust the address to account for the GOT table which wasn't
                         * present in the relative file link.
                         */
-                       if (pic_with_got)
+                       if (pic_with_got && !use_resolved)
                          q->address += got_size;
-                                       
+#endif
+
+                       /* A pointer to what's being relocated, used often
+                          below.  */
+                       r_mem = sectionp + q->address;
+
                        /*
                         *      Fixup offset in the actual section.
                         */
                        addstr[0] = 0;
+#ifndef TARGET_e1
                        if ((sym_addr = get_symbol_offset((char *) sym_name,
                            sym_section, symbols, number_of_symbols)) == -1) {
                                sym_addr = 0;
                        }
-
+#else
+                       sym_addr = (*(q->sym_ptr_ptr))->value;
+#endif                 
                        if (use_resolved) {
                                /* Use the address of the symbol already in
-                                  the program text.  */
-                               sym_addr = *((unsigned long *)
-                                            (sectionp + q->address));
-                               relocation_needed = 1;
+                                  the program text.  How this is handled may
+                                  still depend on the particular relocation
+                                  though.  */
+                               switch (q->howto->type) {
+                                       int r2_type;
+#ifdef TARGET_v850
+                               case R_V850_HI16_S:
+                                       /* We specially handle adjacent
+                                          HI16_S/ZDA_15_16_OFFSET and
+                                          HI16_S/LO16 pairs that reference the
+                                          same address (these are usually
+                                          movhi/ld and movhi/movea pairs,
+                                          respectively).  */
+                                       if (relcount == 0)
+                                               r2_type = R_V850_NONE;
+                                       else
+                                               r2_type = p[1]->howto->type;
+                                       if ((r2_type == R_V850_ZDA_15_16_OFFSET
+                                            || r2_type == R_V850_LO16)
+                                           && (p[0]->sym_ptr_ptr
+                                               == p[1]->sym_ptr_ptr)
+                                           && (p[0]->addend == p[1]->addend))
+                                       {
+                                               relocation_needed = 1;
+
+                                               switch (r2_type) {
+                                               case R_V850_ZDA_15_16_OFFSET:
+                                                       pflags = 0x10000000;
+                                                       break;
+                                               case R_V850_LO16:
+                                                       pflags = 0x20000000;
+                                                       break;
+                                               }
+
+                                               /* We don't really need the
+                                                  actual value -- the bits
+                                                  produced by the linker are
+                                                  what we want in the final
+                                                  flat file -- but get it
+                                                  anyway if useful for
+                                                  debugging.  */
+                                               if (verbose) {
+                                                       unsigned char *r2_mem =
+                                                               sectionp
+                                                               + p[1]->address;
+                                                       /* little-endian */
+                                                       int hi = r_mem[0]
+                                                               + (r_mem[1] << 8);
+                                                       int lo = r2_mem[0]
+                                                               + (r2_mem[1] << 8);
+                                                       /* Sign extend LO.  */
+                                                       lo = (lo ^ 0x8000)
+                                                               - 0x8000;
+
+                                                       /* Maybe ignore the LSB
+                                                          of LO, which is
+                                                          actually part of the
+                                                          instruction.  */
+                                                       if (r2_type != R_V850_LO16)
+                                                               lo &= ~1;
+
+                                                       sym_addr =
+                                                               (hi << 16)
+                                                               + lo;
+                                               }
+                                       } else
+                                               goto bad_resolved_reloc;
+                                       break;
+
+                               case R_V850_LO16:
+                                       /* See if this is actually the
+                                          2nd half of a pair.  */
+                                       if (p > relpp
+                                           && (p[-1]->howto->type
+                                               == R_V850_HI16_S)
+                                           && (p[-1]->sym_ptr_ptr
+                                               == p[0]->sym_ptr_ptr)
+                                           && (p[-1]->addend == p[0]->addend))
+                                               break; /* not an error */
+                                       else
+                                               goto bad_resolved_reloc;
+
+                               case R_V850_HI16:
+                                       goto bad_resolved_reloc;
+                               default:
+                                       goto good_32bit_resolved_reloc;
+#elif defined(TARGET_arm)
+                               case R_ARM_ABS32:
+                                       relocation_needed = 1;
+                                       break;
+                               case R_ARM_REL32:
+                               case R_ARM_THM_PC11:
+                               case R_ARM_THM_PC22:
+                                       relocation_needed = 0;
+                                       break;
+                               default:
+                                       goto bad_resolved_reloc;
+#elif defined(TARGET_m68k)
+                               case R_68K_32:
+                                       goto good_32bit_resolved_reloc;
+                               case R_68K_PC32:
+                               case R_68K_PC16:
+                                       /* The linker has already resolved
+                                          PC relocs for us.  In PIC links,
+                                          the symbol must be in the data
+                                          segment.  */
+                               case R_68K_NONE:
+                                       continue;
+                               default:
+                                       goto bad_resolved_reloc;
+#else
+                               default:
+                                       /* The default is to assume that the
+                                          relocation is relative and has
+                                          already been fixed up by the
+                                          linker (perhaps we ought to make
+                                          give an error by default, and
+                                          require `safe' relocations to be
+                                          enumberated explicitly?).  */
+                                       goto good_32bit_resolve_reloc;
+#endif
+                               good_32bit_resolved_reloc:
+                                       if (bfd_big_endian (abs_bfd))
+                                               sym_addr =
+                                                       (r_mem[0] << 24)
+                                                       + (r_mem[1] << 16)
+                                                       + (r_mem[2] << 8) 
+                                                       + r_mem[3];
+                                       else
+                                               sym_addr =
+                                                       r_mem[0]
+                                                       + (r_mem[1] << 8)
+                                                       + (r_mem[2] << 16)
+                                                       + (r_mem[3] << 24);
+                                       relocation_needed = 1;
+                                       break;
+
+                               bad_resolved_reloc:
+                                       printf("ERROR: reloc type %s unsupported in this context\n",
+                                              q->howto->name);
+                                       bad_relocs++;
+                                       break;
+                               }
                        } else {
                                /* Calculate the sym address ourselves.  */
                                sym_reloc_size = bfd_get_reloc_size(q->howto);
+
+#if !defined(TARGET_h8300) && !defined(TARGET_e1) && !defined(TARGET_bfin) && !defined(TARGET_m68k)
                                if (sym_reloc_size != 4) {
-                                       printf("ERROR: bad reloc size=%d for symbol=%s\n",
-                                                       sym_reloc_size, sym_name);
+                                       printf("ERROR: bad reloc type %d size=%d for symbol=%s\n",
+                                                       (*p)->howto->type, sym_reloc_size, sym_name);
+                                       bad_relocs++;
                                        rc = -1;
                                        continue;
                                }
+#endif
 
                                switch ((*p)->howto->type) {
 
@@ -454,6 +782,7 @@ dump_symbols(symbols, number_of_symbols);
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
                                        break;
+                               case R_68K_PC16:
                                case R_68K_PC32:
                                        sym_vma = 0;
                                        sym_addr += sym_vma + q->addend;
@@ -472,10 +801,14 @@ dump_symbols(symbols, number_of_symbols);
                                                        sym_vma, (*(q->sym_ptr_ptr))->value,
                                                        q->address, sym_addr,
                                                        (*p)->howto->rightshift,
-                                                       *((unsigned long *) (sectionp + q->address)));
+                                                       *(unsigned long *)r_mem);
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
                                        break;
+                               case R_ARM_GOT32:
+                               case R_ARM_GOTPC:
+                                       /* Should be fine as is */
+                                       break;
                                case R_ARM_PLT32:
                                        if (verbose)
                                                fprintf(stderr,
@@ -485,7 +818,7 @@ dump_symbols(symbols, number_of_symbols);
                                                        sym_vma, (*(q->sym_ptr_ptr))->value,
                                                        q->address, sym_addr,
                                                        (*p)->howto->rightshift,
-                                                       *((unsigned long *) (sectionp + q->address)));
+                                                       *(unsigned long *)r_mem);
                                case R_ARM_PC24:
                                        sym_vma = 0;
                                        sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift;
@@ -512,6 +845,306 @@ dump_symbols(symbols, number_of_symbols);
 #endif /* R_V850_ZDA_16_16_OFFSET || R_V850_ZDA_16_16_SPLIT_OFFSET */
 #endif /* TARGET_v850 */
 
+#ifdef TARGET_h8300
+                               case R_H8_DIR24R8:
+                                       if (sym_reloc_size != 4) {
+                                               printf("R_H8_DIR24R8 size %d\n", sym_reloc_size);
+                                               bad_relocs++;
+                                               continue;
+                                       }
+                                       relocation_needed = 1;
+                                       sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       q->address -= 1;
+                                       r_mem -= 1; /* tracks q->address */
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr |= (*(unsigned char *)r_mem<<24);
+                                       break;
+                               case R_H8_DIR24A8:
+                                       if (sym_reloc_size != 4) {
+                                               printf("R_H8_DIR24A8 size %d\n", sym_reloc_size);
+                                               bad_relocs++;
+                                               continue;
+                                       }
+                                       /* Absolute symbol done not relocation */
+                                       relocation_needed = !bfd_is_abs_section(sym_section);
+                                       sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       break;
+                               case R_H8_DIR32:
+                               case R_H8_DIR32A16: /* currently 32,  could be made 16 */
+                                       if (sym_reloc_size != 4) {
+                                               printf("R_H8_DIR32 size %d\n", sym_reloc_size);
+                                               bad_relocs++;
+                                               continue;
+                                       }
+                                       relocation_needed = 1;
+                                       sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       break;
+                               case R_H8_PCREL16:
+                                       sym_vma = 0;
+                                       sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= (q->address + 2);
+                                       if (bfd_big_endian(abs_bfd))
+                                       *(unsigned short *)r_mem =
+                                               bfd_big_endian(abs_bfd) ? htons(sym_addr) : sym_addr;
+                                       continue;
+                               case R_H8_PCREL8:
+                                       sym_vma = 0;
+                                       sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= (q->address + 1);
+                                       *(unsigned char *)r_mem = sym_addr;
+                                       continue;
+#endif
+
+#ifdef TARGET_microblaze
+                               case R_MICROBLAZE_64:
+               /* The symbol is split over two consecutive instructions.  
+                  Flag this to the flat loader by setting the high bit of 
+                  the relocation symbol. */
+                               {
+                                       unsigned char *p = r_mem;
+                                       unsigned long offset;
+                                       pflags=0x80000000;
+
+                                       /* work out the relocation */
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       /* grab any offset from the text */
+                                       offset = (p[2]<<24) + (p[3] << 16) + (p[6] << 8) + (p[7]);
+                                       /* Update the address */
+                                       sym_addr += offset + sym_vma + q->addend;
+                                       /* Write relocated pointer back */
+                                       p[2] = (sym_addr >> 24) & 0xff;
+                                       p[3] = (sym_addr >> 16) & 0xff;
+                                       p[6] = (sym_addr >>  8) & 0xff;
+                                       p[7] =  sym_addr        & 0xff;
+
+                                       /* create a new reloc entry */
+                                       flat_relocs = realloc(flat_relocs,
+                                               (flat_reloc_count + 1) * sizeof(uint32_t));
+                                       flat_relocs[flat_reloc_count] = pflags | (section_vma + q->address);
+                                       flat_reloc_count++;
+                                       relocation_needed = 0;
+                                       pflags = 0;
+                       sprintf(&addstr[0], "+0x%x", sym_addr - (*(q->sym_ptr_ptr))->value -
+                                        bfd_section_vma(abs_bfd, sym_section));
+                       if (verbose)
+                               printf("  RELOC[%d]: offset=0x%x symbol=%s%s "
+                                       "section=%s size=%d "
+                                       "fixup=0x%x (reloc=0x%x)\n", flat_reloc_count,
+                                       q->address, sym_name, addstr,
+                                       section_name, sym_reloc_size,
+                                       sym_addr, section_vma + q->address);
+                       if (verbose)
+                               printf("reloc[%d] = 0x%x\n", flat_reloc_count,
+                                        section_vma + q->address);
+
+                                       continue;
+                               }
+                               case R_MICROBLAZE_32:
+                               {       
+                                       unsigned char *p = r_mem;
+                                       unsigned long offset;
+
+                                       /* grab any offset from the text */
+                                       offset = (p[0]<<24) + (p[1] << 16) + (p[2] << 8) + (p[3]);
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       /* This is a horrible kludge.  For some
+                                          reason, *sometimes* the offset is in
+                                          both addend and the code.  Detect
+                                          it, and cancel the effect.  Otherwise
+                                          the offset gets added twice - ouch.
+                                          There should be a better test
+                                          for this condition, based on the
+                                          BFD data structures */
+                                       if(offset==q->addend)
+                                               offset=0;
+
+                                       sym_addr += offset + sym_vma + q->addend;
+                                       relocation_needed = 1;
+                                       break;
+                               }
+                               case R_MICROBLAZE_64_PCREL:
+                                       sym_vma = 0;
+                                       //sym_addr = (*(q->sym_ptr_ptr))->value;
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= (q->address + 4);
+                                       sym_addr = htonl(sym_addr);
+                                       /* insert 16 MSB */
+                                       * ((unsigned short *) (r_mem+2)) |= (sym_addr) & 0xFFFF;
+                                       /* then 16 LSB */
+                                       * ((unsigned short *) (r_mem+6)) |= (sym_addr >> 16) & 0xFFFF;
+                                       /* We've done all the work, so continue
+                                          to next reloc instead of break */
+                                       continue;
+
+#endif /* TARGET_microblaze */
+                                       
+#ifdef TARGET_nios2
+#define  htoniosl(x)   (x)
+#define  niostohl(x)   (x)
+                       switch ((*p)->howto->type) 
+                       {
+                               case R_NIOS2_BFD_RELOC_32:
+                                       relocation_needed = 1;
+                                       pflags = (FLAT_NIOS2_R_32 << 28);
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       /* modify target, in target order */
+                                       *(unsigned long *)r_mem = htoniosl(sym_addr);
+                                       break;
+                               case R_NIOS2_CALL26:
+                               {
+                                       unsigned long exist_val;
+                                       relocation_needed = 1;
+                                       pflags = (FLAT_NIOS2_R_CALL26 << 28);
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       
+                                       /* modify target, in target order */
+                                       // exist_val = niostohl(*(unsigned long *)r_mem);
+                                       exist_val = ((sym_addr >> 2) << 6);
+                                       *(unsigned long *)r_mem = htoniosl(exist_val);
+                                       break;
+                               }
+                               case R_NIOS2_HIADJ16:
+                               case R_NIOS2_HI16:
+                               {
+                                       unsigned long exist_val;
+                                       int r2_type;
+                                       /* handle the adjacent HI/LO pairs */
+                                       if (relcount == 0)
+                                               r2_type = R_NIOS2_NONE;
+                                       else
+                                               r2_type = p[1]->howto->type;
+                                       if ((r2_type == R_NIOS2_LO16)
+                                           && (p[0]->sym_ptr_ptr == p[1]->sym_ptr_ptr)
+                                           && (p[0]->addend == p[1]->addend)) 
+                                           {
+                                                       unsigned char * r2_mem = sectionp + p[1]->address;
+                                                       if (p[1]->address - q->address!=4)
+                                                               printf("Err: HI/LO not adjacent %d\n", p[1]->address - q->address);
+                                                       relocation_needed = 1;
+                                                       pflags = (q->howto->type == R_NIOS2_HIADJ16) 
+                                                               ? FLAT_NIOS2_R_HIADJ_LO : FLAT_NIOS2_R_HI_LO;
+                                                       pflags <<= 28;
+                                               
+                                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                                       sym_addr += sym_vma + q->addend;
+
+                                                       /* modify high 16 bits, in target order */
+                                                       exist_val = niostohl(*(unsigned long *)r_mem);
+                                                       exist_val =  ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+                                                       if (q->howto->type == R_NIOS2_HIADJ16)
+                                                               exist_val |= ((((sym_addr >> 16) + ((sym_addr >> 15) & 1)) & 0xFFFF) << 6);
+                                                       else
+                                                               exist_val |= (((sym_addr >> 16) & 0xFFFF) << 6);
+                                                       *(unsigned long *)r_mem = htoniosl(exist_val);
+
+                                                       /* modify low 16 bits, in target order */
+                                                       exist_val = niostohl(*(unsigned long *)r2_mem);
+                                                       exist_val =  ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+                                                       exist_val |= ((sym_addr & 0xFFFF) << 6);
+                                                       *(unsigned long *)r2_mem = htoniosl(exist_val);
+                                               
+                                               } else 
+                                                       goto NIOS2_RELOC_ERR;
+                                       }
+                                       break;
+
+                               case R_NIOS2_GPREL:
+                               {
+                                       unsigned long exist_val, temp;
+                                       //long gp = get_symbol_offset("_gp", sym_section, symbols, number_of_symbols);
+                                       long gp = get_gp_value(symbols, number_of_symbols);
+                                       if (gp == -1) {
+                                               printf("Err: unresolved symbol _gp when relocating %s\n", sym_name);
+                                               goto NIOS2_RELOC_ERR;
+                                       }
+                                       /* _gp holds a absolute value, otherwise the ld cannot generate correct code */
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       //printf("sym=%x, %d, _gp=%x, %d\n", sym_addr+sym_vma, sym_addr+sym_vma, gp, gp);
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= gp;
+                                       //printf("sym - _gp=%x, %d\n", sym_addr, sym_addr);
+                                       /* modify the target, in target order (little_endian) */
+                                       exist_val = niostohl(*(unsigned long *)r_mem);
+                                       temp = ((exist_val >> 6) & 0x3ff0000) | (sym_addr & 0xffff);
+                                       temp <<= 6;
+                                       temp |= (exist_val & 0x3f);
+                                       *(unsigned long *)r_mem = htoniosl(temp);
+                                       if (verbose)
+                                               printf("omit: offset=0x%x symbol=%s%s "
+                                                               "section=%s size=%d "
+                                                               "fixup=0x%x (reloc=0x%x) GPREL\n", 
+                                                               q->address, sym_name, addstr,
+                                                               section_name, sym_reloc_size,
+                                                               sym_addr, section_vma + q->address);
+                                       continue;
+                               }
+                               case R_NIOS2_PCREL16:
+                               {
+                                       unsigned long exist_val;
+                                       sym_vma = 0;
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= (q->address + 4);
+                                       /* modify the target, in target order (little_endian) */
+                                       exist_val = niostohl(*(unsigned long *)r_mem);
+                                       exist_val =  ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+                                       exist_val |= ((sym_addr & 0xFFFF) << 6);
+                                       *(unsigned long *)r_mem = htoniosl(exist_val);
+                                       if (verbose)
+                                               printf("omit: offset=0x%x symbol=%s%s "
+                                                               "section=%s size=%d "
+                                                               "fixup=0x%x (reloc=0x%x) PCREL\n", 
+                                                               q->address, sym_name, addstr,
+                                                               section_name, sym_reloc_size,
+                                                               sym_addr, section_vma + q->address);
+                                       continue;
+                               }
+
+                               case R_NIOS2_LO16:
+                                       /* check if this is actually the 2nd half of a pair */
+                                       if ((p > relpp)
+                                               && ((p[-1]->howto->type == R_NIOS2_HIADJ16) 
+                                                       || (p[-1]->howto->type == R_NIOS2_HI16))
+                                           && (p[-1]->sym_ptr_ptr == p[0]->sym_ptr_ptr)
+                                           && (p[-1]->addend == p[0]->addend)) {
+                                               if (verbose)
+                                                       printf("omit: offset=0x%x symbol=%s%s "
+                                                               "section=%s size=%d LO16\n", 
+                                                               q->address, sym_name, addstr,
+                                                               section_name, sym_reloc_size);
+                                               continue;
+                                       }
+
+                                       /* error, fall through */
+
+                               case R_NIOS2_S16:
+                               case R_NIOS2_U16:
+                               case R_NIOS2_CACHE_OPX:
+                               case R_NIOS2_IMM5:
+                               case R_NIOS2_IMM6:
+                               case R_NIOS2_IMM8:
+                               case R_NIOS2_BFD_RELOC_16:
+                               case R_NIOS2_BFD_RELOC_8:
+                               case R_NIOS2_GNU_VTINHERIT:
+                               case R_NIOS2_GNU_VTENTRY:
+                               case R_NIOS2_UJMP:
+                               case R_NIOS2_CJMP:
+                               case R_NIOS2_CALLR:
+NIOS2_RELOC_ERR:
+                                       printf("Err: unexpected reloc type %s(%d)\n", q->howto->name, q->howto->type);
+                                       bad_relocs++;
+                                       continue;
+                       }
+#endif /* TARGET_nios2 */
+
 #ifdef TARGET_sparc
                                case R_SPARC_32:
                                case R_SPARC_UA32:
@@ -527,14 +1160,20 @@ dump_symbols(symbols, number_of_symbols);
                                case R_SPARC_WDISP30:
                                        sym_addr = (((*(q->sym_ptr_ptr))->value-
                                                q->address) >> 2) & 0x3fffffff;
-                                       sym_addr |= (ntohl(*((unsigned long *) (sectionp + q->address))) & 0xc0000000);
+                                       sym_addr |= (
+                                               ntohl(*(unsigned long *)r_mem)
+                                               & 0xc0000000
+                                               );
                                        break;
                                case R_SPARC_HI22:
                                        relocation_needed = 1;
                                        pflags = 0x80000000;
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
-                                       sym_addr |= (htonl(*((unsigned long *) (sectionp + q->address))) & 0xffc00000);
+                                       sym_addr |= (
+                                               htonl(*(unsigned long *)r_mem)
+                                               & 0xffc00000
+                                               );
                                        break;
                                case R_SPARC_LO10:
                                        relocation_needed = 1;
@@ -542,13 +1181,311 @@ dump_symbols(symbols, number_of_symbols);
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
                                        sym_addr &= 0x000003ff;
-                                       sym_addr |= (htonl(*((unsigned long *) (sectionp + q->address))) & 0xfffffc00);
+                                       sym_addr |= (
+                                               htonl(*(unsigned long *)r_mem)
+                                               & 0xfffffc00
+                                               );
                                        break;
 #endif /* TARGET_sparc */
 
+#ifdef TARGET_bfin
+                               case R_pcrel12_jump:
+                               case R_pcrel12_jump_s:
+                               case R_pcrel24:
+                               case R_pcrel24_jump_l:
+                               case R_pcrel24_jump_x:
+                               case R_pcrel24_call_x:
+                               case R_pcrel10:
+                               case R_pcrel11:
+                               case R_pcrel5m2:
+                                 sym_addr += q->addend;// get the symbol addr
+                                 sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                 sym_addr -= q->address; // make it PC relative 
+                                 // implicitly assumes code section and symbol section are same
+                                 break;
+                               case R_got:
+                                   /* Ignore these.  */
+                                   break;
+
+                               case R_rimm16:
+                                   sym_addr += q->addend;
+                                   if(weak_und_symbol(sym_section->name, (*(q->sym_ptr_ptr))))
+                                       continue;
+                                   if(0xFFFF0000 & sym_addr){
+                                       fprintf (stderr, "Relocation overflow for rN = %s\n",sym_name);
+                                       bad_relocs++;
+                                   }
+                                   flat_relocs = (uint32_t *)
+                                       (realloc (flat_relocs, (flat_reloc_count + 1) * sizeof (uint32_t)));
+                                   if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
+                                                       sym_section->name, sym_name,
+                                                       (*(q->sym_ptr_ptr)),
+                                                       0, FLAT_RELOC_PART_LO, 
+                                                       section_vma + q->address))
+                                       bad_relocs++;
+                                   flat_reloc_count++;
+                                   break;
+                                   
+                               case R_luimm16:
+                               case R_huimm16:
+                               {
+                                   unsigned int sp;
+                                   unsigned int reloc_count_incr;
+                                   unsigned int hi_lo;
+
+                                   if (q->howto->type == R_luimm16)
+                                       hi_lo = FLAT_RELOC_PART_LO;
+                                   else
+                                       hi_lo = FLAT_RELOC_PART_HI;
+                               
+                                   sym_addr += q->addend;
+
+                                   flat_relocs = (uint32_t *)
+                                       (realloc (flat_relocs, (flat_reloc_count + 2) * sizeof (uint32_t)));
+                                   reloc_count_incr = 1;
+                                   if (weak_und_symbol (sym_section->name, (*(q->sym_ptr_ptr))))
+                                       continue;
+                                   if (0xFFFF0000 & sym_addr) {
+                                       /* value is > 16 bits - use an extra field */
+                                       /* see if we have already output that symbol */
+                                       /* reloc may be addend from symbol and       */
+                                       /* we can only store 16 bit offsets          */
+                                       sp = 1;
+                                       if ((*(q->sym_ptr_ptr))->udata.i == 0
+                                           || flat_relocs[(*(q->sym_ptr_ptr))->udata.i] != sym_addr
+                                           || ((*(q->sym_ptr_ptr))->udata.i & 0xFFFF0000))
+                                       {
+                                           reloc_count_incr = 2;
+                                           flat_relocs[flat_reloc_count + 1] = sym_addr;
+                                           (*(q->sym_ptr_ptr))->udata.i = flat_reloc_count + 1;
+                                           sym_addr = 0; // indication to loader to read next
+                                       } else{
+                                           sym_addr = (*(q->sym_ptr_ptr))->udata.i;
+                                       }
+                                   } else {
+                                       sp = 0;
+                                   }
+
+                                   if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
+                                                       sym_section->name, sym_name,
+                                                       (*(q->sym_ptr_ptr)),
+                                                       sp, hi_lo,
+                                                       section_vma + q->address))
+                                       bad_relocs++;
+                                   flat_reloc_count += reloc_count_incr;
+                                   break;
+                               }
+                               case R_byte4_data:
+                                   sym_addr += q->addend;
+
+                                   if (weak_und_symbol (sym_section->name, *q->sym_ptr_ptr))
+                                       continue;
+
+                                   flat_relocs = (uint32_t *)
+                                       (realloc (flat_relocs, (flat_reloc_count + 1) * sizeof (uint32_t)));
+                                   if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
+                                                       sym_section->name, sym_name,
+                                                       (*(q->sym_ptr_ptr)),
+                                                       2, FLAT_RELOC_PART_LO, 
+                                                       section_vma + q->address))
+                                       bad_relocs++;
+
+                                   flat_reloc_count++;
+                                   break;
+
+#endif //TARGET_bfin
+
+#ifdef TARGET_sh
+                               case R_SH_DIR32:
+                                       relocation_needed = 1;
+                                       sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                       sym_addr += sym_vma + q->addend;
+                                       break;
+                               case R_SH_REL32:
+                                       sym_vma = 0;
+                                       sym_addr += sym_vma + q->addend;
+                                       sym_addr -= q->address;
+                                       break;
+#endif /* TARGET_sh */
+
+#ifdef TARGET_e1
+#define  htoe1l(x)              htonl(x)
+                                       
+#if 0 
+#define  DEBUG_E1
+#endif
+
+#ifdef   DEBUG_E1
+#define  DBG_E1                 printf
+#else
+#define  DBG_E1(x, ...  )
+#endif
+
+#define _32BITS_RELOC 0x00000000
+#define _30BITS_RELOC 0x80000000
+#define _28BITS_RELOC 0x40000000
+                                       {
+                               char *p;
+                               unsigned long   sec_vma, exist_val, S;
+                               case R_E1_CONST31:
+                                               relocation_needed = 1;
+                                               DBG_E1("Handling Reloc <CONST31>\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
+                                                                               sec_vma, sym_addr, q->address);
+                                               sym_addr = sec_vma + sym_addr;
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);        
+                                               DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
+                                               sym_addr += exist_val;
+                                               pflags = _30BITS_RELOC;
+                                               break;
+                               case R_E1_CONST31_PCREL:
+                                               relocation_needed = 0;
+                                               DBG_E1("Handling Reloc <CONST31_PCREL>\n");
+                                               DBG_E1("DONT RELOCATE AT LOADING\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
+                                                                               sec_vma, sym_addr, q->address);
+                                               sym_addr =  sec_vma + sym_addr;
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
+
+                                               DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
+                                                                                                                                               section_vma );
+                                               q->address = q->address + section_vma;
+                                               DBG_E1("q->address += section_vma : 0x%x\n", q->address );
+
+                                               if( (sym_addr = (sym_addr - q->address - 6)) < 0 )
+                                                               DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
+                                               DBG_E1( "sym_addr := sym_addr - q->address  - "
+                                                               "sizeof(CONST31_PCREL): [0x%x]\n",
+                                                               sym_addr );
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);              
+                                               DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
+                                               sym_addr |= exist_val;
+                                               DBG_E1("sym_addr |=  exist_val) : [0x%x]\n", sym_addr );
+                                               break;
+                               case R_E1_DIS29W_PCREL:
+                                               relocation_needed = 0;
+                                               DBG_E1("Handling Reloc <DIS29W_PCREL>\n");
+                                               DBG_E1("DONT RELOCATE AT LOADING\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
+                                                                               sec_vma, sym_addr, q->address);
+                                               sym_addr =  sec_vma + sym_addr;
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
+
+                                               DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
+                                                                                                                                               section_vma );
+                                               q->address = q->address + section_vma;
+                                               DBG_E1("q->address += section_vma : 0x%x\n", q->address );
+
+                                               if( (sym_addr = (sym_addr - q->address - 6)) < 0 )
+                                                               DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
+                                               DBG_E1( "sym_addr := sym_addr - q->address  - "
+                                                               "sizeof(CONST31_PCREL): [0x%x]\n",
+                                                               sym_addr );
+                                               DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);       
+                                               DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
+                                               sym_addr += exist_val;
+                                               break;
+                               case R_E1_DIS29W:
+                                               DBG_E1("Handling Reloc <DIS29W>\n");
+                                               goto DIS29_RELOCATION;
+                               case R_E1_DIS29H:
+                                               DBG_E1("Handling Reloc <DIS29H>\n");
+                                               goto DIS29_RELOCATION;
+                               case R_E1_DIS29B:
+                                               DBG_E1("Handling Reloc <DIS29B>\n");
+DIS29_RELOCATION:
+                                               relocation_needed = 1;
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%08x]\n",
+                                                                               sec_vma, sym_addr);
+                                               sym_addr =  sec_vma + sym_addr;
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%08x]\n", sym_addr);
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                
+                                               DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
+                                               sym_addr +=  exist_val;
+                                               DBG_E1("sym_addr +=  exist_val : [0x%08x]\n", sym_addr);
+                                               pflags = _28BITS_RELOC;
+                                               break;
+                               case R_E1_IMM32_PCREL:
+                                               relocation_needed = 0;
+                                               DBG_E1("Handling Reloc <IMM32_PCREL>\n");
+                                               DBG_E1("DONT RELOCATE AT LOADING\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
+                                                                               sec_vma, sym_addr);
+                                               sym_addr =  sec_vma + sym_addr;
+
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
+                                               DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
+                                                                                                                                               section_vma );
+                                               q->address = q->address + section_vma;
+                                               DBG_E1("q->address += section_vma : 0x%x\n", q->address );
+
+                                               if( (sym_addr = (sym_addr - q->address - 6 )) < 0 )
+                                                               DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
+                                               DBG_E1( "sym_addr := sym_addr - q->address  - "
+                                                               "sizeof(CONST31_PCREL): [0x%x]\n",
+                                                               sym_addr );
+                                               DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                 
+                                               DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
+                                               sym_addr += exist_val;
+                                               break;
+                               case R_E1_IMM32:
+                                               relocation_needed = 1;
+                                               DBG_E1("Handling Reloc <IMM32>\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
+                                                                               sec_vma, sym_addr);
+                                               sym_addr =  sec_vma + sym_addr;
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
+                                               DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                     
+                                               DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
+                                               sym_addr += exist_val;
+                                               pflags = _32BITS_RELOC;
+                                               break;
+                               case R_E1_WORD:
+                                               relocation_needed = 1;
+                                               DBG_E1("Handling Reloc <WORD>\n");
+                                               sec_vma = bfd_section_vma(abs_bfd, sym_section);
+                                               DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
+                                                                               sec_vma, sym_addr);
+                                               sym_addr =  sec_vma + sym_addr;
+                                               DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
+                                               exist_val = *(unsigned long*)((unsigned long)sectionp + q->address );
+                                               DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
+                                               exist_val = htoe1l(exist_val);
+                                               DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
+                                               sym_addr +=  exist_val;
+                                               DBG_E1("sym_addr +=  exist_val : [0x%08x]\n", sym_addr);
+                                               pflags = _32BITS_RELOC;
+                                               break;
+                               }
+#undef _32BITS_RELOC
+#undef _30BITS_RELOC
+#undef _28BITS_RELOC
+#endif
                                default:
                                        /* missing support for other types of relocs */
                                        printf("ERROR: bad reloc type %d\n", (*p)->howto->type);
+                                       bad_relocs++;
                                        continue;
                                }
                        }
@@ -558,8 +1495,8 @@ dump_symbols(symbols, number_of_symbols);
 
 
                        /*
-                        * for full elf relocation we have to write back the start_code
-                        * relative value to use.
+                        * for full elf relocation we have to write back the
+                        * start_code relative value to use.
                         */
                        if (!pic_with_got) {
 #if defined(TARGET_arm)
@@ -585,31 +1522,165 @@ dump_symbols(symbols, number_of_symbols);
                                        i3 = 0;
                                }
 
-                               tmp.l = *((unsigned long *) (sectionp + q->address));
+                               tmp.l = *(unsigned long *)r_mem;
                                hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
-                               if ((*p)->howto->type != R_ARM_PC24)
+                               if (use_resolved ||
+                                       (((*p)->howto->type != R_ARM_PC24) &&
+                                       ((*p)->howto->type != R_ARM_PLT32)))
                                        hl |= (tmp.c[i3] << 24);
                                else if (tmp.c[i2] & 0x80)
                                        hl |= 0xff000000; /* sign extend */
-                               hl += sym_addr;
+                               if (!use_resolved)
+                                       hl += sym_addr;
                                tmp.c[i0] = hl & 0xff;
                                tmp.c[i1] = (hl >> 8) & 0xff;
                                tmp.c[i2] = (hl >> 16) & 0xff;
-                               if ((*p)->howto->type != R_ARM_PC24)
+                               if (use_resolved ||
+                                       (((*p)->howto->type != R_ARM_PC24) &&
+                                       ((*p)->howto->type != R_ARM_PLT32)))
                                        tmp.c[i3] = (hl >> 24) & 0xff;
                                if ((*p)->howto->type == R_ARM_ABS32)
-                                       *((unsigned long *) (sectionp + q->address)) = htonl(hl);
+                                       *(unsigned long *)r_mem = htonl(hl);
                                else
-                                       *((unsigned long *) (sectionp + q->address)) = tmp.l;
-#else /* ! TARGET_arm */
-                               *((unsigned long *) (sectionp + q->address)) = htonl(sym_addr);
+                                       *(unsigned long *)r_mem = tmp.l;
+
+#elif defined(TARGET_bfin)
+                               if ((*p)->howto->type == R_pcrel24
+                                   || (*p)->howto->type == R_pcrel24_jump_l
+                                   || (*p)->howto->type == R_pcrel24_jump_x
+                                   || (*p)->howto->type == R_pcrel24_call_x)
+                               {
+                                   sym_addr += 2*-1*PCREL24_MAGIC_OFFSET;
+                                   *((unsigned short *)(sectionp + q->address) + 1 + PCREL24_MAGIC_OFFSET)
+                                       = (sym_addr >> 1) & 0xffff;
+                                   *((unsigned short *)(sectionp + q->address) + PCREL24_MAGIC_OFFSET)
+                                       = (0xff00 & *((unsigned short *) (sectionp + q->address) + PCREL24_MAGIC_OFFSET)
+                                          | ((sym_addr >> 17) & 0xff));
+                               } else if ((*p)->howto->type == R_byte4_data) {
+                                   *((uint32_t *)(sectionp + q->address)) = sym_addr;
+                               } else if ((*p)->howto->type == R_pcrel12_jump
+                                          || (*p)->howto->type == R_pcrel12_jump_s) {
+                                   *((unsigned short *)(sectionp + q->address))
+                                       = (0xf000 & *((unsigned short *)(sectionp + q->address))
+                                          | ((sym_addr >> 1) & 0xfff));
+                               } else if ((*p)->howto->type == R_pcrel10) {
+                                   *((unsigned short *)(sectionp + q->address))
+                                       = (~0x3ff & *((unsigned short *)(sectionp + q->address))
+                                          | ((sym_addr >> 1) & 0x3ff));
+                               } else if ((*p)->howto->type == R_rimm16
+                                          || (*p)->howto->type == R_huimm16
+                                          || (*p)->howto->type == R_luimm16) {
+                                   /* for l and h we set the lower 16 bits which is only when it will be used */
+                                   *((unsigned short *) (sectionp + q->address)) = (unsigned short) sym_addr;
+                               } else if ((*p)->howto->type == R_pcrel5m2) {
+                                   *((unsigned short *)(sectionp + q->address))
+                                       = (0xfff0 & *((unsigned short *)(sectionp + q->address))
+                                          | ((sym_addr >> 1) & 0xf));
+                               } else if ((*p)->howto->type == R_pcrel11){
+                                   *((unsigned short *)(sectionp + q->address))
+                                       = (0xfc00 & *((unsigned short *)(sectionp + q->address))
+                                          | ((sym_addr >> 1) & 0x3ff));
+                               } else if (0xE0 <= (*p)->howto->type && 0xF3 >= (*p)->howto->type) {
+                                   //arith relocs dont generate a real relocation
+                               } else {
+                                   printf("Blackfin relocation fail for reloc type: 0x%x\n", (*p)->howto->type);
+                               }
+#elif defined(TARGET_e1)
+#define OPCODE_SIZE 2           /* Add 2 bytes, counting the opcode size*/
+                               switch ((*p)->howto->type) {
+                               case R_E1_CONST31:
+                               case R_E1_CONST31_PCREL:
+                               case R_E1_DIS29W_PCREL:
+                               case R_E1_DIS29W:
+                               case R_E1_DIS29H:
+                               case R_E1_DIS29B:
+                               case R_E1_IMM32_PCREL:
+                               case R_E1_IMM32:
+                                               DBG_E1("In addr + 2:[0x%x] <- write [0x%x]\n",
+                                                               (sectionp + q->address + 2), sym_addr );
+                                               *((unsigned long *) (sectionp + q->address + OPCODE_SIZE)) =
+                                               htonl(sym_addr);
+                               break;
+                               case R_E1_WORD:
+                                               DBG_E1("In addr : [0x%x] <- write [0x%x]\n",
+                                                               (sectionp + q->address), sym_addr );
+                                               *((unsigned long *) (sectionp + q->address )) = htonl(sym_addr);
+                               break;
+                               default:
+                                               printf("ERROR:Unhandled Relocation. Exiting...\n");
+                                               exit(0);
+                               break;
+                               }
+#else /* ! TARGET_arm && ! TARGET_e1 */
+
+                               switch (q->howto->type) {
+#ifdef TARGET_v850
+                               case R_V850_HI16_S:
+                               case R_V850_HI16:
+                               case R_V850_LO16:
+                                       /* Do nothing -- for cases we handle,
+                                          the bits produced by the linker are
+                                          what we want in the final flat file
+                                          (and other cases are errors).  Note
+                                          that unlike most relocated values,
+                                          it is stored in little-endian order,
+                                          but this is necessary to avoid
+                                          trashing the low-bit, and the float
+                                          loaders knows about it.  */
+                                       break;
+#endif /* TARGET_V850 */
+
+#ifdef TARGET_nios2
+                               case R_NIOS2_BFD_RELOC_32:
+                               case R_NIOS2_CALL26:
+                               case R_NIOS2_HIADJ16:
+                               case R_NIOS2_HI16:
+                                       /* do nothing */
+                                       break;
+#endif /* TARGET_nios2 */
+
+#if defined(TARGET_m68k)
+                               case R_68K_PC16:
+                                       if (sym_addr < -0x8000 || sym_addr > 0x7fff) {
+                                               fprintf (stderr, "Relocation overflow for R_68K_PC16 relocation against %s\n", sym_name);
+                                               bad_relocs++;
+                                       } else {
+                                               r_mem[0] = (sym_addr >>  8) & 0xff;
+                                               r_mem[1] =  sym_addr        & 0xff;
+                                       }
+                                       break;
 #endif
+
+                               default:
+                                       /* The alignment of the build host
+                                          might be stricter than that of the
+                                          target, so be careful.  We store in
+                                          network byte order. */
+                                       r_mem[0] = (sym_addr >> 24) & 0xff;
+                                       r_mem[1] = (sym_addr >> 16) & 0xff;
+                                       r_mem[2] = (sym_addr >>  8) & 0xff;
+                                       r_mem[3] =  sym_addr        & 0xff;
+                               }
+#endif /* !TARGET_arm */
                        }
 
+#ifdef TARGET_bfin
+                       else {
+                           if ((*p)->howto->type == R_rimm16
+                               || (*p)->howto->type == R_huimm16
+                               || (*p)->howto->type == R_luimm16)
+                           {
+                               /* for l and h we set the lower 16 bits which is only when it will be used */
+                               *((unsigned short *) (sectionp + q->address)) = (unsigned short) sym_addr;
+                           } else if ((*p)->howto->type == R_byte4_data) {
+                               *((uint32_t *)(sectionp + q->address)) = sym_addr;
+                           }
+                       }
+#endif
                        if (verbose)
-                               printf("  RELOC[%d]: offset=%x symbol=%s%s "
+                               printf("  RELOC[%d]: offset=0x%x symbol=%s%s "
                                        "section=%s size=%d "
-                                       "fixup=%x (reloc=0x%x)\n", flat_reloc_count,
+                                       "fixup=0x%x (reloc=0x%x)\n", flat_reloc_count,
                                        q->address, sym_name, addstr,
                                        section_name, sym_reloc_size,
                                        sym_addr, section_vma + q->address);
@@ -618,21 +1689,49 @@ dump_symbols(symbols, number_of_symbols);
                         *      Create relocation entry (PC relative doesn't need this).
                         */
                        if (relocation_needed) {
+#ifndef TARGET_bfin
                                flat_relocs = realloc(flat_relocs,
-                                       (flat_reloc_count + 1) * sizeof(unsigned long));
+                                       (flat_reloc_count + 1) * sizeof(uint32_t));
+#ifndef TARGET_e1
                                flat_relocs[flat_reloc_count] = pflags |
                                        (section_vma + q->address);
 
                                if (verbose)
                                        printf("reloc[%d] = 0x%x\n", flat_reloc_count,
                                                        section_vma + q->address);
+#else
+                               switch ((*p)->howto->type) {
+                               case R_E1_CONST31:
+                               case R_E1_CONST31_PCREL:
+                               case R_E1_DIS29W_PCREL:
+                               case R_E1_DIS29W:
+                               case R_E1_DIS29H:
+                               case R_E1_DIS29B:
+                               case R_E1_IMM32_PCREL:
+                               case R_E1_IMM32:
+                               flat_relocs[flat_reloc_count] = pflags |
+                                               (section_vma + q->address + OPCODE_SIZE);
+                               if (verbose)
+                                               printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
+                                                                                flat_relocs[flat_reloc_count] );
+                               break;
+                               case R_E1_WORD:
+                               flat_relocs[flat_reloc_count] = pflags |
+                                               (section_vma + q->address);
+                               if (verbose)
+                                               printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
+                                                                                flat_relocs[flat_reloc_count] );
+                               break;
+                               }
+#endif
                                flat_reloc_count++;
+#endif
                                relocation_needed = 0;
                                pflags = 0;
                        }
 
 #if 0
-printf("%s(%d): symbol name=%s address=%x section=%s -> RELOC=%x\n",
+printf("%s(%d): symbol name=%s address=0x%x section=%s -> RELOC=0x%x\n",
        __FILE__, __LINE__, sym_name, q->address, section_name,
        flat_relocs[flat_reloc_count]);
 #endif
@@ -640,97 +1739,18 @@ printf("%s(%d): symbol name=%s address=%x section=%s -> RELOC=%x\n",
        }
   }
 
-  if (rc < 0)
-       return(NULL);
-
-    *n_relocs = flat_reloc_count;
-    return flat_relocs;
-}
-
-
-
-#if 0
-/* shared lib symbols stuff */
-
-long
-get_symbol(char *name, asection *sec, asymbol **symbol_table, long number_of_symbols)
-{
-  long i;
-  for (i=0; i<number_of_symbols; i++) {
-    if (symbol_table[i]->section == sec) {
-      if (!strcmp(symbol_table[i]->name, name)) {
-       return symbol_table[i]->value;
-      }
-    }
+  if (bad_relocs) {
+         printf("%d bad relocs\n", bad_relocs);
+         exit(1);
   }
-  return -1;
-}  
-
-int
-output_offset_table(int fd, char *ename, bfd *abfd, asymbol **symbol_table, long number_of_symbols)
-{
-  long i;
-  FILE *ef;
-  char buf[80];
-  char libname[80];
-  long etext_addr;
-  long sym_addr;
-
-  int foobar = 0;
-  int count = 0;
-  signed short *tab = malloc(32768); /* we don't know how many yet*/
-
-  asection *text_section = bfd_get_section_by_name (abfd, ".text");
 
-  if (!(ef = fopen(ename, "r"))) {
-    fprintf (stderr,"Can't open %s\n",ename);
-    exit(1);
-  }
-
-  fgets(libname, 80, ef);
-
-  if (number_of_symbols < 0) {
-    fprintf (stderr,"Corrupt symbol table!\n");
-    exit(1);
-  }
-
-  if ((etext_addr = get_symbol("etext",
-                              text_section,
-                              symbol_table,
-                              number_of_symbols)) == -1) {
-    fprintf (stderr,"Can't find the symbol etext\n");
-    exit(1);
-  }
-
-  fgets(buf, 80, ef);
-  while (!feof(ef)) {
-    buf[strlen(buf)-1] = 0; /* Arrrgh! linefeeds */
-
-    if ((sym_addr = get_symbol(buf,
-                              text_section,
-                              symbol_table,
-                              number_of_symbols)) == -1) {
-      fprintf (stderr,"Can't find the symbol %s\n",buf);
-      foobar++;
-    } else {
-      tab[++count] = htons(sym_addr - etext_addr);
-    }
-    fgets(buf, 80, ef);
-  }
-
-  fclose(ef);
-
-  if (foobar) {
-    fprintf (stderr,"*** %d symbols not found\n",foobar);
-    exit(10);
-  }
+  if (rc < 0)
+       return(0);
 
-  strcpy((char *)&tab[++count],libname);
-  tab[0] = htons(count * 2);
-  write(fd, tab, count * 2 + strlen(libname) + 2);
-  return 0;
+  *n_relocs = flat_reloc_count;
+  return flat_relocs;
 }
-#endif
+
 
 
 static char * program;
@@ -741,11 +1761,13 @@ static void usage(void)
        "[-o <output-file>] <elf-file>\n\n"
        "       -v              : verbose operation\n"
        "       -r              : force load to RAM\n"
+       "       -k              : enable kernel trace on load (for debug)\n"
        "       -z              : compress code/data/relocs\n"
        "       -d              : compress data/relocs\n"
        "       -a              : use existing symbol references\n"
        "                         instead of recalculating from\n"
-       "                         relocation info\n");
+       "                         relocation info\n"
+        "       -R reloc-file   : read relocations from a separate file\n"
        "       -p abs-pic-file : GOT/PIC processing with files\n"
        "       -s stacksize    : set application stack size\n"
        "       -o output-file  : output file name\n\n",
@@ -755,13 +1777,30 @@ static void usage(void)
 }
 
 
+/* Write NUM zeroes to STREAM.  */
+static void write_zeroes (unsigned long num, FILE *stream)
+{
+  char zeroes[1024];
+  if (num > 0) {
+    /* It'd be nice if we could just use fseek, but that doesn't seem to
+       work for stdio output files.  */
+    memset(zeroes, 0x00, 1024);
+    while (num > sizeof(zeroes)) {
+      fwrite(zeroes, sizeof(zeroes), 1, stream);
+      num -= sizeof(zeroes);
+    }
+    if (num > 0)
+      fwrite(zeroes, num, 1, stream);
+  }
+}
+
 
 int main(int argc, char *argv[])
 {
   int fd;
   bfd *rel_bfd, *abs_bfd;
   asection *s;
-  char *ofile=NULL, *pfile=NULL;
+  char *ofile=NULL, *pfile=NULL, *abs_file = NULL, *rel_file = NULL;
   char *fname = NULL;
   int opt;
   int i;
@@ -769,25 +1808,27 @@ int main(int argc, char *argv[])
   char  cmd[1024];
   FILE *gf = NULL;
 
-
   asymbol **symbol_table;
   long number_of_symbols;
 
-  unsigned long data_len;
-  unsigned long bss_len;
-  unsigned long text_len;
+  unsigned long data_len = 0;
+  unsigned long bss_len = 0;
+  unsigned long text_len = 0;
   unsigned long reloc_len;
 
-  unsigned long data_vma;
-  unsigned long bss_vma;
-  unsigned long text_vma;
+  unsigned long data_vma = ~0;
+  unsigned long bss_vma = ~0;
+  unsigned long text_vma = ~0;
+
+  unsigned long text_offs;
 
   void *text;
   void *data;
-  unsigned long *reloc;
+  uint32_t *reloc;
   
   struct flat_hdr hdr;
 
+  int gf_is_pipe = 0;
 
   program = argv[0];
   progname = argv[0];
@@ -795,9 +1836,21 @@ int main(int argc, char *argv[])
   if (argc < 2)
        usage();
   
+  if (sizeof(hdr) != 64) {
+    fprintf(stderr,
+           "Potential flat header incompatibility detected\n"
+           "header size should be 64 but is %d\n",
+           sizeof(hdr));
+    exit(64);
+  }
+
+#ifndef TARGET_e1
   stack = 4096;
+#else /* We need plenty of stack for both of them (Aggregate and Register) */
+  stack = 0x2020;
+#endif
 
-  while ((opt = getopt(argc, argv, "avzdrp:s:o:")) != -1) {
+  while ((opt = getopt(argc, argv, "avzdrkp:s:o:R:")) != -1) {
     switch (opt) {
     case 'v':
       verbose++;
@@ -805,6 +1858,9 @@ int main(int argc, char *argv[])
     case 'r':
       load_to_ram++;
       break;
+    case 'k':
+      ktrace++;
+      break;
     case 'z':
       compress = 1;
       break;
@@ -821,7 +1877,13 @@ int main(int argc, char *argv[])
       use_resolved = 1;
       break;
     case 's':
-      stack = atoi(optarg);
+      if (sscanf(optarg, "%i", &stack) != 1) {
+        fprintf(stderr, "%s invalid stack size %s\n", argv[0], optarg);
+        usage();
+      }
+      break;
+    case 'R':
+      rel_file = optarg;
       break;
     default:
       fprintf(stderr, "%s Unknown option\n", argv[0]);
@@ -839,8 +1901,17 @@ int main(int argc, char *argv[])
 
   filename = fname = argv[argc-1];
 
-  if (!(rel_bfd = bfd_openr(fname, 0))) {
-    fprintf(stderr, "Can't open %s\n", fname);
+  if (pfile) {
+    pic_with_got = 1;
+    abs_file = pfile;
+  } else
+    abs_file = fname;
+
+  if (! rel_file)
+    rel_file = fname;
+
+  if (!(rel_bfd = bfd_openr(rel_file, 0))) {
+    fprintf(stderr, "Can't open %s\n", rel_file);
     exit(1);
   }
 
@@ -849,11 +1920,11 @@ int main(int argc, char *argv[])
     exit(2);
   }
 
-  if (pfile) {
-    pic_with_got = 1;
-
-    if (!(abs_bfd = bfd_openr(pfile, 0))) {
-      fprintf(stderr, "Can't open %s\n", pfile);
+  if (abs_file == rel_file)
+    abs_bfd = rel_bfd; /* one file does all */
+  else {
+    if (!(abs_bfd = bfd_openr(abs_file, 0))) {
+      fprintf(stderr, "Can't open %s\n", abs_file);
       exit(1);
     }
 
@@ -861,12 +1932,10 @@ int main(int argc, char *argv[])
       fprintf(stderr, "File is not an object file\n");
       exit(2);
     }
-  } else {
-    abs_bfd = rel_bfd; /* one file does all */
   }
 
   if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC)) {
-    fprintf (stderr, "%s: Input file contains no relocation info\n", fname);
+    fprintf (stderr, "%s: Input file contains no relocation info\n", rel_file);
     exit (2);
   }
 
@@ -881,104 +1950,142 @@ int main(int argc, char *argv[])
 
   symbol_table = get_symbols(abs_bfd, &number_of_symbols);
 
-  s = bfd_get_section_by_name (abs_bfd, ".text");
-  text_vma = s->vma;
-  text_len = s->_raw_size;
-  text = malloc(text_len);
+  /* Group output sections into text, data, and bss, and calc their sizes.  */
+  for (s = abs_bfd->sections; s != NULL; s = s->next) {
+    unsigned long *vma, *len;
+    bfd_size_type sec_size;
+    bfd_vma sec_vma;
+
+    if (s->flags & SEC_CODE) {
+      vma = &text_vma;
+      len = &text_len;
+    } else if (s->flags & SEC_DATA) {
+      vma = &data_vma;
+      len = &data_len;
+    } else if (s->flags & SEC_ALLOC) {
+      vma = &bss_vma;
+      len = &bss_len;
+    } else
+      continue;
+
+    sec_size = bfd_section_size(abs_bfd, s);
+    sec_vma  = bfd_section_vma(abs_bfd, s);
+
+    if (sec_vma < *vma) {
+      if (*len > 0)
+       *len += sec_vma - *vma;
+      else
+       *len = sec_size;
+      *vma = sec_vma;
+    } else if (sec_vma + sec_size > *vma + *len)
+      *len = sec_vma + sec_size - *vma;
+  }
 
-  if (verbose) {
-    printf("TEXT -> vma=%x len=%x\n", text_vma, text_len);
-    printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
-                       s->lma, s->_cooked_size, s->output_offset,
-                       s->alignment_power, s->filepos);
+  if (text_len == 0) {
+    fprintf (stderr, "%s: no .text section", abs_file);
+    exit (2);
   }
 
-  if (bfd_get_section_contents(abs_bfd,
-                              s, 
-                              text,
-                              0,
-                              s->_raw_size) == false) {
-    fprintf(stderr, "read error section %s\n", s->name);
-    exit(2);
+  text = malloc(text_len);
+  if (text == NULL) {
+      perror("malloc");
+      exit(1);
   }
 
-  s = bfd_get_section_by_name (abs_bfd, ".data");
-  data_vma = s->vma;
-  data_len = s->_raw_size;
-  data = malloc(data_len);
+  if (verbose)
+    printf("TEXT -> vma=0x%x len=0x%x\n", text_vma, text_len);
+
+  /* Read in all text sections.  */
+  for (s = abs_bfd->sections; s != NULL; s = s->next)
+    if (s->flags & SEC_CODE) 
+      if (!bfd_get_section_contents(abs_bfd, s,
+                                  text + (s->vma - text_vma), 0,
+                                  bfd_section_size(abs_bfd, s)))
+      {
+       fprintf(stderr, "read error section %s\n", s->name);
+       exit(2);
+      }
 
-  if (verbose) {
-     printf("DATA -> vma=%x len=%x\n", data_vma, data_len);
-     printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
-                       s->lma, s->_cooked_size, s->output_offset,
-                       s->alignment_power, s->filepos);
+  if (data_len == 0) {
+    fprintf (stderr, "%s: no .data section", abs_file);
+    exit (2);
   }
-  if (text_len != data_vma) {
-    if (text_len > data_vma) {
-      printf("ERROR: text=%x overlaps data=%x ?\n", text_len, data_vma);
+  data = malloc(data_len);
+  if (data == NULL) {
+      perror("malloc");
+      exit(1);
+  }
+
+  if (verbose)
+    printf("DATA -> vma=0x%x len=0x%x\n", data_vma, data_len);
+
+  if ((text_vma + text_len) != data_vma) {
+    if ((text_vma + text_len) > data_vma) {
+      printf("ERROR: text=0x%x overlaps data=0x%x ?\n", text_len, data_vma);
       exit(1);
     }
     if (verbose)
-      printf("WARNING: data=%x does not directly follow text=%x\n",
+      printf("WARNING: data=0x%x does not directly follow text=0x%x\n",
                        data_vma, text_len);
-    text_len = data_vma;
+    text_len = data_vma - text_vma;
   }
 
-  if (bfd_get_section_contents(abs_bfd,
-                              s, 
-                              data,
-                              0,
-                              s->_raw_size) == false) {
-    fprintf(stderr, "read error section %s\n", s->name);
-    exit(2);
-  }
+  /* Read in all data sections.  */
+  for (s = abs_bfd->sections; s != NULL; s = s->next)
+    if (s->flags & SEC_DATA) 
+      if (!bfd_get_section_contents(abs_bfd, s,
+                                  data + (s->vma - data_vma), 0,
+                                  bfd_section_size(abs_bfd, s)))
+      {
+       fprintf(stderr, "read error section %s\n", s->name);
+       exit(2);
+      }
 
-  s = bfd_get_section_by_name (abs_bfd, ".bss");
-  bss_len = s->_raw_size;
-  bss_vma = s->vma;
+  /* Put common symbols in bss.  */
   bss_len += add_com_to_bss(symbol_table, number_of_symbols, bss_len);
 
-  if (verbose) {
-       printf("BSS  -> vma=%x len=%x\n", bss_vma, bss_len);
-    printf("        lma=%x clen=%x oo=%x ap=%x fp=%x\n",
-                       s->lma, s->_cooked_size, s->output_offset,
-                       s->alignment_power, s->filepos);
-  }
+  if (verbose)
+    printf("BSS  -> vma=0x%x len=0x%x\n", bss_vma, bss_len);
 
-  if ((text_len + data_len) != bss_vma) {
-    if ((text_len + data_len) > bss_vma) {
-      printf("ERROR: text=%x + data=%x overlaps bss=%x ?\n", text_len,
+  if ((data_vma + data_len) != bss_vma) {
+    if ((data_vma + data_len) > bss_vma) {
+      printf("ERROR: text=0x%x + data=0x%x overlaps bss=0x%x ?\n", text_len,
                        data_len, bss_vma);
       exit(1);
     }
     if (verbose)
-      printf("WARNING: bss=%x does not directly follow text=%x + data=%x(%x)\n",
+      printf("WARNING: bss=0x%x does not directly follow text=0x%x + data=0x%x(0x%x)\n",
                bss_vma, text_len, data_len, text_len + data_len);
-      data_len = bss_vma - text_len;
+    data_len = bss_vma - data_vma;
   }
 
-  reloc = (unsigned long *) output_relocs (abs_bfd, symbol_table,
-      number_of_symbols, &reloc_len, text, text_len, data, data_len, rel_bfd);
+  reloc = output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len,
+                       text, text_len, text_vma, data, data_len, data_vma,
+                       rel_bfd);
 
   if (reloc == NULL)
     printf("No relocations in code!\n");
 
+  text_offs = real_address_bits(text_vma);
+
   /* Fill in the binflt_flat header */
   memcpy(hdr.magic,"bFLT",4);
   hdr.rev         = htonl(FLAT_VERSION);
-  hdr.entry       = htonl(16 * 4 + bfd_get_start_address(abs_bfd));
-  hdr.data_start  = htonl(16 * 4 + text_len);
-  hdr.data_end    = htonl(16 * 4 + text_len + data_len);
-  hdr.bss_end     = htonl(16 * 4 + text_len + data_len + bss_len);
+  hdr.entry       = htonl(sizeof(hdr) + bfd_get_start_address(abs_bfd));
+  hdr.data_start  = htonl(sizeof(hdr) + text_offs + text_len);
+  hdr.data_end    = htonl(sizeof(hdr) + text_offs + text_len +data_len);
+  hdr.bss_end     = htonl(sizeof(hdr) + text_offs + text_len +data_len+bss_len);
   hdr.stack_size  = htonl(stack); /* FIXME */
-  hdr.reloc_start = htonl(16 * 4 + text_len + data_len);
+  hdr.reloc_start = htonl(sizeof(hdr) + text_offs + text_len +data_len);
   hdr.reloc_count = htonl(reloc_len);
   hdr.flags       = htonl(0
          | (load_to_ram ? FLAT_FLAG_RAM : 0)
+         | (ktrace ? FLAT_FLAG_KTRACE : 0)
          | (pic_with_got ? FLAT_FLAG_GOTPIC : 0)
          | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
          );
-  bzero(hdr.filler, sizeof(hdr.filler));
+  hdr.build_date = htonl((unsigned long)time(NULL));
+  memset(hdr.filler, 0x00, sizeof(hdr.filler));
 
   for (i=0; i<reloc_len; i++) reloc[i] = htonl(reloc[i]);
 
@@ -992,6 +2099,10 @@ int main(int argc, char *argv[])
   
   if (!ofile) {
     ofile = malloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
+    if (ofile == NULL) {
+       perror("malloc");
+       exit(1);
+    }
     strcpy(ofile, fname);
     strcat(ofile, ".bflt");
   }
@@ -1010,32 +2121,59 @@ int main(int argc, char *argv[])
   sprintf(cmd, "gzip -f -9 >> %s", ofile);
 
 #define        START_COMPRESSOR do { \
-               if (gf) fclose(gf); \
-               if (!(gf = popen(cmd, "w"))) { \
+               if (gf) \
+                       if (gf_is_pipe) \
+                               pclose(gf); \
+                       else \
+                               fclose(gf); \
+               if (!(gf = popen(cmd, "w" BINARY_FILE_OPTS))) { \
                        fprintf(stderr, "Can't run cmd %s\n", cmd); \
                        exit(4); \
                } \
+               gf_is_pipe = 1; \
        } while (0)
 
-  gf = fopen(ofile, "a");
+  gf = fopen(ofile, "ab");     /* Add 'b' to support non-posix (ie windows) */
   if (!gf) {
-       fprintf(stderr, "Can't opne file %s for writing\n", ofile); \
+       fprintf(stderr, "Can't open file %s for writing\n", ofile); \
        exit(4);
   }
 
   if (compress == 1)
        START_COMPRESSOR;
 
+  /* Fill in any hole at the beginning of the text segment.  */
+  if (verbose)
+         printf("ZERO before text len=0x%x\n", text_offs);
+  write_zeroes(text_offs, gf);
+
+  /* Write the text segment.  */
   fwrite(text, text_len, 1, gf);
 
   if (compress == 2)
        START_COMPRESSOR;
 
+  /* Write the data segment.  */
   fwrite(data, data_len, 1, gf);
+
   if (reloc)
-    fwrite(reloc, reloc_len*4, 1, gf);
+    fwrite(reloc, reloc_len * 4, 1, gf);
+
+  if(gf_is_pipe)
+    pclose(gf);
+  else
   fclose(gf);
 
   exit(0);
 }
 
+
+/*
+ * this __MUST__ be at the VERY end of the file - do NOT move!!
+ *
+ * Local Variables:
+ * c-basic-offset: 4
+ * tab-width: 8
+ * end:
+ * vi: tabstop=8 shiftwidth=4 textwidth=79 noexpandtab
+ */