OSDN Git Service

Unify the duplicated windows and other system fallback logic in stubs.h
[uclinux-h8/elf2flt.git] / elf2flt.c
index c8d6201..5e9c698 100644 (file)
--- a/elf2flt.c
+++ b/elf2flt.c
@@ -6,6 +6,8 @@
  * ELF format file handling. Extended relocation support for all of
  * text and data.
  *
+ * (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>
 #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 */
-#else
-#include <winsock2.h>
-#endif
 
 /* from $(INSTALLDIR)/include       */
 #include <bfd.h>      /* Main header file for the BFD library                */
+#include <libiberty.h>
+
+#include "stubs.h"
+const char *elf2flt_progname;
 
 #if defined(TARGET_h8300)
 #include <elf/h8.h>      /* TARGET_* ELF support for the BFD library            */
 #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
 
+/* Always include Blackfin-specific defines in addition to common ELF stuff
+ * above as the common elf headers often do not have our relocs.
+ */
+#if defined(TARGET_bfin) && !defined(R_BFIN_RIMM16)
+#include "elf/bfin.h"
+#endif
+
 #if defined(__MINGW32__)
 #include <getopt.h>
 #endif
 
 /* from uClinux-x.x.x/include/linux */
 #include "flat.h"     /* Binary flat header description                      */
+#include "compress.h"
 
 #ifdef TARGET_e1
 #include <e1.h>
 #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)
@@ -138,7 +138,7 @@ 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 docompress = 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 */
@@ -146,80 +146,14 @@ int use_resolved = 0; /* If true, get the value of symbol references from */
                      /* versions of GNU ld will give you a fully resolved */
                      /* output file with relocation entries).  */
 
-const char *progname, *filename;
-int lineno;
-
-int nerrors = 0;
-int nwarnings = 0;
-
-static char where[200];
-
-enum {
-  /* Use exactly one of these: */
-  E_NOFILE = 0,         /* "progname: " */
-  E_FILE = 1,           /* "filename: " */
-  E_FILELINE = 2,       /* "filename:lineno: " */
-  E_FILEWHERE = 3,      /* "filename:%s: " -- set %s with ewhere() */
-          
-  /* Add in any of these with |': */
-  E_WARNING = 0x10,
-  E_PERROR = 0x20
-};
-                  
-void ewhere (const char *format, ...);
-void einfo (int type, const char *format, ...);
-                  
-
-void
-ewhere (const char *format, ...) {
-  va_list args;
-  va_start (args, format);
-  vsprintf (where, format, args);
-  va_end (args);
-}
-
-
-void
-einfo (int type, const char *format, ...) {
-  va_list args;
-
-  switch (type & 0x0f) {
-  case E_NOFILE:
-    fprintf (stderr, "%s: ", progname);
-    break;
-  case E_FILE:
-    fprintf (stderr, "%s: ", filename);
-    break;
-  case E_FILELINE:
-    ewhere ("%d", lineno);
-    /* fall-through */
-  case E_FILEWHERE:
-    fprintf (stderr, "%s:%s: ", filename, where);
-    break;
-  }
-
-  if (type & E_WARNING) {
-    fprintf (stderr, "warning: ");
-    nwarnings++;
-  } else {
-    nerrors++;
-  }
-
-  va_start (args, format);
-  vfprintf (stderr, format, args);
-  va_end (args);
-
-  if (type & E_PERROR)
-    perror ("");
-  else
-    fprintf (stderr, "\n");
-}
-
+/* Set if the text section contains any relocations.  If it does, we must
+   set the load_to_ram flag.  */
+int text_has_relocs = 0;
 
 asymbol**
 get_symbols (bfd *abfd, long *num)
 {
-  long storage_needed;
+  int32_t storage_needed;
   asymbol **symbol_table;
   long number_of_symbols;
   
@@ -231,7 +165,7 @@ get_symbols (bfd *abfd, long *num)
   if (storage_needed == 0)
     return NULL;
 
-  symbol_table = (asymbol **) malloc (storage_needed);
+  symbol_table = xmalloc (storage_needed);
 
   number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
   
@@ -275,6 +209,7 @@ get_symbol_offset(char *name, asection *sec, asymbol **symbol_table, long number
 
 
 
+#ifdef TARGET_nios2
 long
 get_gp_value(asymbol **symbol_table, long number_of_symbols)
 {
@@ -285,14 +220,15 @@ get_gp_value(asymbol **symbol_table, long number_of_symbols)
   }
   return -1;
 }
+#endif
 
 
-long
-add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
+
+int32_t
+add_com_to_bss(asymbol **symbol_table, int32_t number_of_symbols, int32_t bss_len)
 {
-  long i, comsize;
-  long offset;
+  int32_t i, comsize;
+  int32_t offset;
 
   comsize = 0;
   for (i=0; i<number_of_symbols; i++) {
@@ -306,119 +242,6 @@ add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
 }  
 
 #ifdef TARGET_bfin
-/* stack to handle "arithmetic" relocations */
-#define RELOC_STACK_SIZE 100
-static bfd_vma reloc_stack[RELOC_STACK_SIZE];
-static unsigned int reloc_stack_tos = 0;
-static char sym_section_name[80];
-static asection *stack_sym_section = 0;
-
-static void
-reloc_stack_set_section(asection *section, const char *sym_section_name_in)
-{
-    /* TODO : we can add checks to make sure we do not
-       add different section names to the same arithmetic
-       expression.  */
-    strcpy(sym_section_name, sym_section_name_in);
-    stack_sym_section = section;
-}
-
-static const char *
-reloc_stack_get_section_name()
-{
-    return sym_section_name;
-}
-static asection *reloc_stack_get_section()
-{
-    return stack_sym_section;
-}
-
-#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
-
-static void
-reloc_stack_push(bfd_vma value)
-{
-  reloc_stack[reloc_stack_tos++] = value;
-}
-
-static bfd_vma
-reloc_stack_pop()
-{
-  return reloc_stack[--reloc_stack_tos];
-}
-
-static bfd_vma
-reloc_stack_operate(unsigned int oper)
-{
-    bfd_vma value;
-    switch(oper){
-    case 0xE2 :
-       value = reloc_stack[reloc_stack_tos - 2] + reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE3 :
-       value = reloc_stack[reloc_stack_tos - 2] - reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE4 :
-       value = reloc_stack[reloc_stack_tos - 2] * reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE5 :
-       value = reloc_stack[reloc_stack_tos - 2] / reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE6 :
-       value = reloc_stack[reloc_stack_tos - 2] % reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE7 :
-       value = reloc_stack[reloc_stack_tos - 2] << reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE8 :
-       value = reloc_stack[reloc_stack_tos - 2] >> reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE9 :
-       value = reloc_stack[reloc_stack_tos - 2] & reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEA :
-       value = reloc_stack[reloc_stack_tos - 2] | reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEB :
-       value = reloc_stack[reloc_stack_tos - 2] ^ reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEC :
-       value = reloc_stack[reloc_stack_tos - 2] && reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xED :
-       value = reloc_stack[reloc_stack_tos - 2] || reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEF :
-       value = -reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos --;
-       break;
-    case 0xF0 :
-       value = ~reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 1;
-       break;
-    default :
-       fprintf(stderr, "bfin relocation : Internal bug\n");
-       return 0;
-    }
-
-    // now push the new value back on stack
-    reloc_stack_push(value);
-
-    return value;
-}
-
 /* FUNCTION : weak_und_symbol
    ABSTRACT : return true if symbol is weak and undefined.
 */
@@ -440,60 +263,61 @@ weak_und_symbol(const char *reloc_section_name,
 }
 
 static int
-bfin_set_reloc (uint32_t *reloc, 
-               const char *reloc_section_name, 
+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)
+               int sp, int32_t offset)
 {
-    unsigned int type;
+    unsigned int type = 0;
     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;
+    if (strstr (reloc_section_name, "stack")) {
+           if (verbose)
+                   printf ("Stack-relative reloc, offset %08lx\n", offset);
+           /* This must be a stack_start reloc for stack checking.  */
+           type = 1;
     }
-
-    val = (offset & ((1 << 26) - 1)) << 6;
-    val |= (sp & (1 << 3) - 1) << 3;
-    val |= (hilo & 1) << 2;
-    val |= (type & (1 << 2) - 1);
+    val = (offset & ((1 << 26) - 1));
+    val |= (sp & (1 << 3) - 1) << 26;
+    val |= type << 29;
     *reloc = val;
     return 0;
 }
-#endif
 
+static bfd *compare_relocs_bfd;
+
+static int
+compare_relocs (const void *pa, const void *pb)
+{
+       const arelent *const *a = pa, *const *b = pb;
+       const arelent *ra = *a, *rb = *b;
+       unsigned long va, vb;
+       uint32_t a_vma, b_vma;
+
+       if (!ra->sym_ptr_ptr || !*ra->sym_ptr_ptr)
+               return -1;
+       else if (!rb->sym_ptr_ptr || !*rb->sym_ptr_ptr)
+               return 1;
+
+       a_vma = bfd_section_vma(compare_relocs_bfd,
+                               (*(ra->sym_ptr_ptr))->section);
+       b_vma = bfd_section_vma(compare_relocs_bfd,
+                               (*(rb->sym_ptr_ptr))->section);
+       va = (*(ra->sym_ptr_ptr))->value + a_vma + ra->addend;
+       vb = (*(rb->sym_ptr_ptr))->value + b_vma + rb->addend;
+       return va - vb;
+}
+#endif
 
 uint32_t *
 output_relocs (
   bfd *abs_bfd,
   asymbol **symbols,
   int number_of_symbols,
-  unsigned long *n_relocs,
-  unsigned char *text, int text_len, unsigned long text_vma,
-  unsigned char *data, int data_len, unsigned long data_vma,
+  uint32_t *n_relocs,
+  unsigned char *text, int text_len, uint32_t text_vma,
+  unsigned char *data, int data_len, uint32_t data_vma,
   bfd *rel_bfd)
 {
   uint32_t             *flat_relocs;
@@ -503,7 +327,7 @@ output_relocs (
   unsigned char                *sectionp;
   unsigned long                pflags;
   char                 addstr[16];
-  long                 sym_addr, sym_vma, section_vma;
+  uint32_t             sym_addr, sym_vma, section_vma;
   int                  relsize, relcount;
   int                  flat_reloc_count;
   int                  sym_reloc_size, rc;
@@ -511,6 +335,9 @@ output_relocs (
   int                  bad_relocs = 0;
   asymbol              **symb;
   long                 nsymb;
+#ifdef TARGET_bfin
+  unsigned long                persistent_data = 0;
+#endif
   
 #if 0
   printf("%s(%d): output_relocs(abs_bfd=%d,synbols=0x%x,number_of_symbols=%d"
@@ -534,20 +361,18 @@ 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) {
-    unsigned long *lp = (unsigned long *)data;
+  if (pic_with_got && !use_resolved) {
+    uint32_t *lp = (uint32_t *)data;
     /* Should call ntohl(*lp) here but is isn't going to matter */
     while (*lp != 0xffffffff) lp++;
     got_size = ((unsigned char *)lp) - data;
     if (verbose)
            printf("GOT table contains %d entries (%d bytes)\n",
-                           got_size/sizeof(unsigned long), got_size);
+                           got_size/sizeof(uint32_t), 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);
-    }
+    if (got_size > GOT_LIMIT)
+           fatal("GOT too large: %d bytes (limit = %d bytes)",
+                       got_size, GOT_LIMIT);
 #endif
   }
 
@@ -601,7 +426,8 @@ dump_symbols(symbols, number_of_symbols);
        }
 
        symb = get_symbols(rel_bfd, &nsymb);
-       relpp = (arelent **) xmalloc(relsize);
+       relpp = xmalloc(relsize);
+
        relcount = bfd_canonicalize_reloc(rel_bfd, r, relpp, symb);
        if (relcount <= 0) {
                if (verbose)
@@ -609,6 +435,10 @@ dump_symbols(symbols, number_of_symbols);
                        __FILE__, __LINE__, r->name);
                continue;
        } else {
+#ifdef TARGET_bfin
+               compare_relocs_bfd = abs_bfd;
+               qsort (relpp, relcount, sizeof *relpp, compare_relocs);
+#endif
                for (p = relpp; (relcount && (*p != NULL)); p++, relcount--) {
                        unsigned char *r_mem;
                        int relocation_needed = 0;
@@ -622,170 +452,11 @@ dump_symbols(symbols, number_of_symbols);
                        {
                        case R_MICROBLAZE_NONE:
                        case R_MICROBLAZE_64_NONE:
+                       case R_MICROBLAZE_32_PCREL_LO:
                                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_v850
                        /* Skip this relocation entirely if possible (we
                           do this early, before doing any other
@@ -842,16 +513,6 @@ NIOS2_RELOC_ERR:
 #endif /* USE_V850_RELOCS */
 
                        q = *p;
-#ifdef TARGET_bfin
-                       if ((q->sym_ptr_ptr && *q->sym_ptr_ptr) &&
-                            (!is_reloc_stack_empty() && strstr((*(q->sym_ptr_ptr))->name, "operator"))){
-                               /* must be an arith reloc ... get the value from the stack */
-                               sym_name = (*(q->sym_ptr_ptr))->name;
-                               sym_section = reloc_stack_get_section();
-                               section_name = reloc_stack_get_section_name();
-                       }
-                       else
-#endif
                        if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
                                sym_name = (*(q->sym_ptr_ptr))->name;
                                sym_section = (*(q->sym_ptr_ptr))->section;
@@ -865,7 +526,7 @@ NIOS2_RELOC_ERR:
                        /* 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
 
@@ -877,7 +538,7 @@ NIOS2_RELOC_ERR:
                         *      Fixup offset in the actual section.
                         */
                        addstr[0] = 0;
-#ifndef TARGET_e1
+#if !defined TARGET_e1 && !defined TARGET_bfin
                        if ((sym_addr = get_symbol_offset((char *) sym_name,
                            sym_section, symbols, number_of_symbols)) == -1) {
                                sym_addr = 0;
@@ -953,7 +614,7 @@ NIOS2_RELOC_ERR:
                                                                + lo;
                                                }
                                        } else
-                                               goto bad_v850_reloc_err;
+                                               goto bad_resolved_reloc;
                                        break;
 
                                case R_V850_LO16:
@@ -967,16 +628,96 @@ NIOS2_RELOC_ERR:
                                            && (p[-1]->addend == p[0]->addend))
                                                break; /* not an error */
                                        else
-                                               goto bad_v850_reloc_err;
+                                               goto bad_resolved_reloc;
 
                                case R_V850_HI16:
-                               bad_v850_reloc_err:
-                                       printf("ERROR: reloc type %s unsupported in this context\n",
-                                              q->howto->name);
-                                       bad_relocs++;
+                                       goto bad_resolved_reloc;
+                               default:
+                                       goto good_32bit_resolved_reloc;
+#elif defined(TARGET_arm)
+                               case R_ARM_ABS32:
+                                       relocation_needed = 1;
                                        break;
-#endif /* TARGET_V850 */
+                               case R_ARM_REL32:
+                               case R_ARM_THM_PC11:
+                               case R_ARM_THM_PC22:
+                               case R_ARM_PC24:
+                               case R_ARM_PLT32:
+                               case R_ARM_GOTPC:
+                               case R_ARM_GOT32:
+                                       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;
+#elif defined TARGET_bfin
+                               case R_BFIN_RIMM16:
+                               case R_BFIN_LUIMM16:
+                               case R_BFIN_HUIMM16:
+                                   sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                   sym_addr += sym_vma + q->addend;
+
+                                   if (weak_und_symbol(sym_section->name, (*(q->sym_ptr_ptr))))
+                                       continue;
+                                   if (q->howto->type == R_BFIN_RIMM16 && (0xFFFF0000 & sym_addr)) {
+                                       fprintf (stderr, "Relocation overflow for rN = %s\n",sym_name);
+                                       bad_relocs++;
+                                   }
+                                   if ((0xFFFF0000 & sym_addr) != persistent_data) {
+                                   flat_relocs = (uint32_t *)
+                                       (realloc (flat_relocs, (flat_reloc_count + 1) * sizeof (uint32_t)));
+                                           if (verbose)
+                                                   printf ("New persistent data for %08lx\n", sym_addr);
+                                           persistent_data = 0xFFFF0000 & sym_addr;
+                                           flat_relocs[flat_reloc_count++]
+                                                   = (sym_addr >> 16) | (3 << 26);
+                                   }
 
+                                   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)),
+                                                       q->howto->type == R_BFIN_HUIMM16 ? 1 : 0,
+                                                       section_vma + q->address))
+                                       bad_relocs++;
+                                   if (a->flags & SEC_CODE)
+                                       text_has_relocs = 1;
+                                   flat_reloc_count++;
+                                   break;
+
+                               case R_BFIN_BYTE4_DATA:
+                                   sym_vma = bfd_section_vma(abs_bfd, sym_section);
+                                   sym_addr += sym_vma + 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, section_vma + q->address))
+                                       bad_relocs++;
+                                   if (a->flags & SEC_CODE)
+                                       text_has_relocs = 1;
+
+                                   flat_reloc_count++;
+                                   break;
+#else
                                default:
                                        /* The default is to assume that the
                                           relocation is relative and has
@@ -985,6 +726,9 @@ NIOS2_RELOC_ERR:
                                           give an error by default, and
                                           require `safe' relocations to be
                                           enumberated explicitly?).  */
+                                       goto good_32bit_resolved_reloc;
+#endif
+                               good_32bit_resolved_reloc:
                                        if (bfd_big_endian (abs_bfd))
                                                sym_addr =
                                                        (r_mem[0] << 24)
@@ -998,12 +742,19 @@ NIOS2_RELOC_ERR:
                                                        + (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)
+#if !defined(TARGET_h8300) && !defined(TARGET_e1) && !defined(TARGET_bfin) && !defined(TARGET_m68k)
                                if (sym_reloc_size != 4) {
                                        printf("ERROR: bad reloc type %d size=%d for symbol=%s\n",
                                                        (*p)->howto->type, sym_reloc_size, sym_name);
@@ -1021,6 +772,7 @@ NIOS2_RELOC_ERR:
                                        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;
@@ -1039,7 +791,7 @@ NIOS2_RELOC_ERR:
                                                        sym_vma, (*(q->sym_ptr_ptr))->value,
                                                        q->address, sym_addr,
                                                        (*p)->howto->rightshift,
-                                                       *(unsigned long *)r_mem);
+                                                       *(uint32_t *)r_mem);
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
                                        break;
@@ -1056,7 +808,7 @@ NIOS2_RELOC_ERR:
                                                        sym_vma, (*(q->sym_ptr_ptr))->value,
                                                        q->address, sym_addr,
                                                        (*p)->howto->rightshift,
-                                                       *(unsigned long *)r_mem);
+                                                       *(uint32_t *)r_mem);
                                case R_ARM_PC24:
                                        sym_vma = 0;
                                        sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift;
@@ -1147,15 +899,11 @@ NIOS2_RELOC_ERR:
                   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;
+                                       sym_addr += sym_vma + q->addend;
                                        /* Write relocated pointer back */
                                        p[2] = (sym_addr >> 24) & 0xff;
                                        p[3] = (sym_addr >> 16) & 0xff;
@@ -1187,42 +935,184 @@ NIOS2_RELOC_ERR:
                                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;
+                                       sym_addr += 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;
+                                       * ((unsigned short *) (r_mem+2)) = (sym_addr) & 0xFFFF;
                                        /* then 16 LSB */
-                                       * ((unsigned short *) (r_mem+6)) |= (sym_addr >> 16) & 0xFFFF;
+                                       * ((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)
+                               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:
@@ -1239,7 +1129,7 @@ NIOS2_RELOC_ERR:
                                        sym_addr = (((*(q->sym_ptr_ptr))->value-
                                                q->address) >> 2) & 0x3fffffff;
                                        sym_addr |= (
-                                               ntohl(*(unsigned long *)r_mem)
+                                               ntohl(*(uint32_t *)r_mem)
                                                & 0xc0000000
                                                );
                                        break;
@@ -1249,7 +1139,7 @@ NIOS2_RELOC_ERR:
                                        sym_vma = bfd_section_vma(abs_bfd, sym_section);
                                        sym_addr += sym_vma + q->addend;
                                        sym_addr |= (
-                                               htonl(*(unsigned long *)r_mem)
+                                               htonl(*(uint32_t *)r_mem)
                                                & 0xffc00000
                                                );
                                        break;
@@ -1260,141 +1150,12 @@ NIOS2_RELOC_ERR:
                                        sym_addr += sym_vma + q->addend;
                                        sym_addr &= 0x000003ff;
                                        sym_addr |= (
-                                               htonl(*(unsigned long *)r_mem)
+                                               htonl(*(uint32_t *)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_rimm16:
-                                   if (is_reloc_stack_empty ())
-                                   {
-                                       sym_addr += q->addend;
-                                   } else {
-                                       sym_addr = reloc_stack_pop ();
-                                   }
-                                   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;
-                               
-                                   if (is_reloc_stack_empty ())
-                                       sym_addr += q->addend;
-                                   else
-                                       sym_addr = reloc_stack_pop ();
-                                   
-                                   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:
-                                   if (is_reloc_stack_empty ())
-                                       sym_addr += q->addend;
-                                   else
-                                       sym_addr = reloc_stack_pop ();
-                                   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;
-
-                               case 0xE0: 
-                                  /* push */
-                                 sym_addr += q->addend;
-                                 reloc_stack_push(sym_addr);
-                                 reloc_stack_set_section(sym_section, section_name);
-                                 break;
-
-                               case 0xE1:
-                                 /* const */
-                                 reloc_stack_push(q->addend);
-                               break;
-
-                               case 0xE2 ... 0xF2:
-                                 reloc_stack_operate((*p)->howto->type);
-                                 break;
-
-#endif //TARGET_bfin
 
 #ifdef TARGET_sh
                                case R_SH_DIR32:
@@ -1603,9 +1364,9 @@ DIS29_RELOCATION:
 #if defined(TARGET_arm)
                                union {
                                        unsigned char c[4];
-                                       unsigned long l;
+                                       uint32_t l;
                                } tmp;
-                               long hl;
+                               int32_t hl;
                                int i0, i1, i2, i3;
 
                                /*
@@ -1623,66 +1384,27 @@ DIS29_RELOCATION:
                                        i3 = 0;
                                }
 
-                               tmp.l = *(unsigned long *)r_mem;
+                               tmp.l = *(uint32_t *)r_mem;
                                hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
-                               if (((*p)->howto->type != R_ARM_PC24) &&
-                                   ((*p)->howto->type != R_ARM_PLT32))
+                               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) &&
-                                   ((*p)->howto->type != R_ARM_PLT32))
+                               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 *)r_mem = htonl(hl);
+                                       *(uint32_t *)r_mem = htonl(hl);
                                else
-                                       *(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);
-                               }
+                                       *(uint32_t *)r_mem = tmp.l;
 #elif defined(TARGET_e1)
 #define OPCODE_SIZE 2           /* Add 2 bytes, counting the opcode size*/
                                switch ((*p)->howto->type) {
@@ -1709,7 +1431,17 @@ DIS29_RELOCATION:
                                                exit(0);
                                break;
                                }
-#else /* ! TARGET_arm && ! TARGET_e1 */
+#elif defined TARGET_bfin
+                               if ((*p)->howto->type == R_BFIN_RIMM16
+                                   || (*p)->howto->type == R_BFIN_HUIMM16
+                                   || (*p)->howto->type == R_BFIN_LUIMM16)
+                               {
+                                       /* for l and h we set the lower 16 bits which is only when it will be used */
+                                       bfd_putl16 (sym_addr, sectionp + q->address);
+                               } else if ((*p)->howto->type == R_BFIN_BYTE4_DATA) {
+                                       bfd_putl32 (sym_addr, sectionp + q->address);
+                               }
+#else /* ! TARGET_arm && ! TARGET_e1 && ! TARGET_bfin */
 
                                switch (q->howto->type) {
 #ifdef TARGET_v850
@@ -1737,6 +1469,18 @@ DIS29_RELOCATION:
                                        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
@@ -1750,19 +1494,6 @@ DIS29_RELOCATION:
 #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=0x%x symbol=%s%s "
                                        "section=%s size=%d "
@@ -1811,7 +1542,7 @@ DIS29_RELOCATION:
                                }
 #endif
                                flat_reloc_count++;
-#endif
+#endif //TARGET_bfin
                                relocation_needed = 0;
                                pflags = 0;
                        }
@@ -1839,10 +1570,8 @@ printf("%s(%d): symbol name=%s address=0x%x section=%s -> RELOC=0x%x\n",
 
 
 
-static char * program;
-
 static void usage(void)
-{  
+{
     fprintf(stderr, "Usage: %s [vrzd] [-p <abs-pic-file>] [-s stack-size] "
        "[-o <output-file>] <elf-file>\n\n"
        "       -v              : verbose operation\n"
@@ -1857,26 +1586,26 @@ static void usage(void)
        "       -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",
-       program);
+       elf2flt_progname);
        fprintf(stderr, "Compiled for " ARCH " architecture\n\n");
     exit(2);
 }
 
 
 /* Write NUM zeroes to STREAM.  */
-static void write_zeroes (unsigned long num, FILE *stream)
+static void write_zeroes (unsigned long num, stream *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.  */
-    bzero(zeroes, 1024);
+    memset(zeroes, 0x00, 1024);
     while (num > sizeof(zeroes)) {
-      fwrite(zeroes, sizeof(zeroes), 1, stream);
+      fwrite_stream(zeroes, sizeof(zeroes), 1, stream);
       num -= sizeof(zeroes);
     }
     if (num > 0)
-      fwrite(zeroes, num, 1, stream);
+      fwrite_stream(zeroes, num, 1, stream);
   }
 }
 
@@ -1891,44 +1620,39 @@ int main(int argc, char *argv[])
   int opt;
   int i;
   int stack;
-  char  cmd[1024];
-  FILE *gf = NULL;
+  stream gf;
 
   asymbol **symbol_table;
   long number_of_symbols;
 
-  unsigned long data_len = 0;
-  unsigned long bss_len = 0;
-  unsigned long text_len = 0;
-  unsigned long reloc_len;
+  uint32_t data_len = 0;
+  uint32_t bss_len = 0;
+  uint32_t text_len = 0;
+  uint32_t reloc_len;
 
-  unsigned long data_vma = ~0;
-  unsigned long bss_vma = ~0;
-  unsigned long text_vma = ~0;
+  uint32_t data_vma = ~0;
+  uint32_t bss_vma = ~0;
+  uint32_t text_vma = ~0;
 
-  unsigned long text_offs;
+  uint32_t text_offs;
 
   void *text;
   void *data;
   uint32_t *reloc;
-  
-  struct flat_hdr hdr;
 
-  int gf_is_pipe = 0;
+  struct flat_hdr hdr;
 
-  program = argv[0];
-  progname = argv[0];
+  elf2flt_progname = argv[0];
+  xmalloc_set_program_name(elf2flt_progname);
 
   if (argc < 2)
        usage();
-  
-  if (sizeof(hdr) != 64) {
-    fprintf(stderr,
+
+  if (sizeof(hdr) != 64)
+    fatal(
            "Potential flat header incompatibility detected\n"
-           "header size should be 64 but is %d\n",
+           "header size should be 64 but is %d",
            sizeof(hdr));
-    exit(64);
-  }
 
 #ifndef TARGET_e1
   stack = 4096;
@@ -1948,10 +1672,10 @@ int main(int argc, char *argv[])
       ktrace++;
       break;
     case 'z':
-      compress = 1;
+      docompress = 1;
       break;
     case 'd':
-      compress = 2;
+      docompress = 2;
       break;
     case 'p':
       pfile = optarg;
@@ -1963,7 +1687,10 @@ 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;
@@ -1982,7 +1709,7 @@ int main(int argc, char *argv[])
   if (!load_to_ram && !pfile)
     load_to_ram = 1;
 
-  filename = fname = argv[argc-1];
+  fname = argv[argc-1];
 
   if (pfile) {
     pic_with_got = 1;
@@ -1993,49 +1720,36 @@ int main(int argc, char *argv[])
   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);
-  }
+  if (!(rel_bfd = bfd_openr(rel_file, 0)))
+    fatal_perror("Can't open '%s'", rel_file);
 
-  if (bfd_check_format (rel_bfd, bfd_object) == 0) {
-    fprintf(stderr, "File is not an object file\n");
-    exit(2);
-  }
+  if (bfd_check_format (rel_bfd, bfd_object) == 0)
+    fatal("File is not an object file");
 
   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);
-    }
+    if (!(abs_bfd = bfd_openr(abs_file, 0)))
+      fatal_perror("Can't open '%s'", abs_file);
 
-    if (bfd_check_format (abs_bfd, bfd_object) == 0) {
-      fprintf(stderr, "File is not an object file\n");
-      exit(2);
-    }
+    if (bfd_check_format (abs_bfd, bfd_object) == 0)
+      fatal("File is not an object file");
   }
 
-  if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC)) {
-    fprintf (stderr, "%s: Input file contains no relocation info\n", rel_file);
-    exit (2);
-  }
+  if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC))
+    fatal("%s: Input file contains no relocation info", rel_file);
 
-  if (use_resolved && !(bfd_get_file_flags(abs_bfd) & EXEC_P)) {
+  if (use_resolved && !(bfd_get_file_flags(abs_bfd) & EXEC_P))
     /* `Absolute' file is not absolute, so neither are address
        contained therein.  */
-    fprintf (stderr,
-            "%s: `-a' option specified with non-fully-resolved input file\n",
+    fatal("%s: `-a' option specified with non-fully-resolved input file",
             bfd_get_filename (abs_bfd));
-    exit (2);
-  }
 
   symbol_table = get_symbols(abs_bfd, &number_of_symbols);
 
   /* 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;
+    uint32_t *vma, *len;
     bfd_size_type sec_size;
     bfd_vma sec_vma;
 
@@ -2064,12 +1778,10 @@ int main(int argc, char *argv[])
       *len = sec_vma + sec_size - *vma;
   }
 
-  if (text_len == 0) {
-    fprintf (stderr, "%s: no .text section", abs_file);
-    exit (2);
-  }
+  if (text_len == 0)
+    fatal("%s: no .text section", abs_file);
 
-  text = malloc(text_len);
+  text = xmalloc(text_len);
 
   if (verbose)
     printf("TEXT -> vma=0x%x len=0x%x\n", text_vma, text_len);
@@ -2081,15 +1793,12 @@ int main(int argc, char *argv[])
                                   text + (s->vma - text_vma), 0,
                                   bfd_section_size(abs_bfd, s)))
       {
-       fprintf(stderr, "read error section %s\n", s->name);
-       exit(2);
+       fatal("read error section %s", s->name);
       }
 
-  if (data_len == 0) {
-    fprintf (stderr, "%s: no .data section", abs_file);
-    exit (2);
-  }
-  data = malloc(data_len);
+  if (data_len == 0)
+    fatal("%s: no .data section", abs_file);
+  data = xmalloc(data_len);
 
   if (verbose)
     printf("DATA -> vma=0x%x len=0x%x\n", data_vma, data_len);
@@ -2112,10 +1821,12 @@ int main(int argc, char *argv[])
                                   data + (s->vma - data_vma), 0,
                                   bfd_section_size(abs_bfd, s)))
       {
-       fprintf(stderr, "read error section %s\n", s->name);
-       exit(2);
+       fatal("read error section %s", s->name);
       }
 
+  if (bss_vma == ~0)
+    bss_vma = data_vma + data_len;
+
   /* Put common symbols in bss.  */
   bss_len += add_com_to_bss(symbol_table, number_of_symbols, bss_len);
 
@@ -2134,11 +1845,11 @@ int main(int argc, char *argv[])
     data_len = bss_vma - data_vma;
   }
 
-  reloc = output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len,
-                       text, text_len, text_vma, data, data_len, data_vma,
-                       rel_bfd);
+  reloc = (uint32_t *)
+    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)
+  if (reloc == NULL && verbose)
     printf("No relocations in code!\n");
 
   text_offs = real_address_bits(text_vma);
@@ -2154,13 +1865,13 @@ int main(int argc, char *argv[])
   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)
+         | (load_to_ram || text_has_relocs ? 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)
+         | (docompress ? (docompress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
          );
-  hdr.build_date = htonl((unsigned long)time(NULL));
-  bzero(hdr.filler, sizeof(hdr.filler));
+  hdr.build_date = htonl((uint32_t)time(NULL));
+  memset(hdr.filler, 0x00, sizeof(hdr.filler));
 
   for (i=0; i<reloc_len; i++) reloc[i] = htonl(reloc[i]);
 
@@ -2173,67 +1884,41 @@ int main(int argc, char *argv[])
   }
   
   if (!ofile) {
-    ofile = malloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
+    ofile = xmalloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
     strcpy(ofile, fname);
     strcat(ofile, ".bflt");
   }
 
-  if ((fd = open (ofile, O_WRONLY|O_BINARY|O_CREAT|O_TRUNC, 0744)) < 0) {
-    fprintf (stderr, "Can't open output file %s\n", ofile);
-    exit(4);
-  }
+  if ((fd = open (ofile, O_WRONLY|O_BINARY|O_CREAT|O_TRUNC, 0744)) < 0)
+    fatal_perror("Can't open output file %s", ofile);
 
   write(fd, &hdr, sizeof(hdr));
   close(fd);
 
-  /*
-   * get the compression command ready
-   */
-  sprintf(cmd, "gzip -f -9 >> %s", ofile);
-
-#define        START_COMPRESSOR do { \
-               if (gf) \
-                       if (gf_is_pipe) \
-                               pclose(gf); \
-                       else \
-                               fclose(gf); \
-               if (!(gf = popen(cmd, "wb"))) { \
-                       fprintf(stderr, "Can't run cmd %s\n", cmd); \
-                       exit(4); \
-               } \
-               gf_is_pipe = 1; \
-       } while (0)
-
-  gf = fopen(ofile, "ab");     /* Add 'b' to support non-posix (ie windows) */
-  if (!gf) {
-       fprintf(stderr, "Can't open file %s for writing\n", ofile); \
-       exit(4);
-  }
+  if (fopen_stream_u(&gf, ofile, "a" BINARY_FILE_OPTS))
+    fatal_perror("Can't open file %s for writing", ofile);
 
-  if (compress == 1)
-       START_COMPRESSOR;
+  if (docompress == 1)
+    reopen_stream_compressed(&gf);
 
   /* 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);
+    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);
+  fwrite_stream(text, text_len, 1, &gf);
 
-  if (compress == 2)
-       START_COMPRESSOR;
+  if (docompress == 2)
+    reopen_stream_compressed(&gf);
 
   /* Write the data segment.  */
-  fwrite(data, data_len, 1, gf);
+  fwrite_stream(data, data_len, 1, &gf);
 
   if (reloc)
-    fwrite(reloc, reloc_len * 4, 1, gf);
+    fwrite_stream(reloc, reloc_len * 4, 1, &gf);
 
-  if(gf_is_pipe)
-    pclose(gf);
-  else
-  fclose(gf);
+  fclose_stream(&gf);
 
   exit(0);
 }