OSDN Git Service

Build elf2flt with headers from binutils 2.15.94+.
[uclinux-h8/elf2flt.git] / elf2flt.c
index e177fa2..d0b7851 100644 (file)
--- a/elf2flt.c
+++ b/elf2flt.c
 #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                */
 
 #if defined(TARGET_h8300)
 #include <elf/h8.h>      /* TARGET_* ELF support for the BFD library            */
+#elif defined(TARGET_microblaze)
+#include <elf/microblaze.h>    /* TARGET_* ELF support for the BFD library */
+#elif defined(__CYGWIN__)
+#include "cygwin-elf.h"        /* Cygwin uses a local copy */
 #else
 #include <elf.h>      /* TARGET_* ELF support for the BFD library            */
 #endif
@@ -55,6 +62,9 @@
 /* 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
 #define        ARCH    "h8300"
 #elif defined(TARGET_microblaze)
 #define ARCH   "microblaze"
+#elif defined(TARGET_e1)
+#define ARCH    "e1-coff"
 #else
 #error "Don't know how to support your CPU architecture??"
 #endif
 
-#ifdef TARGET_m68k
+#if defined(TARGET_m68k) || defined(TARGET_h8300)
 /*
  * Define a maximum number of bytes allowed in the offset table.
  * We'll fail if the table is larger than this.
@@ -347,9 +359,9 @@ dump_symbols(symbols, number_of_symbols);
         *      otherwise do text as well
         */
        if (!pic_with_got && (a->flags & SEC_CODE))
-               sectionp = text;
+               sectionp = text + (a->vma - text_vma);
        else if (a->flags & SEC_DATA)
-               sectionp = data;
+               sectionp = data + (a->vma - data_vma);
        else
                continue;
 
@@ -480,32 +492,49 @@ dump_symbols(symbols, number_of_symbols);
                         *      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.  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 pairs that
-                                          reference the same address (these
-                                          are usually movhi/ld pairs).  */
-                                       if (relcount > 1
-                                           && (p[1]->howto->type
-                                               == R_V850_ZDA_15_16_OFFSET)
+                                          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;
-                                               pflags = 0x80000000;
+
+                                               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
@@ -526,25 +555,43 @@ dump_symbols(symbols, number_of_symbols);
                                                        /* Sign extend LO.  */
                                                        lo = (lo ^ 0x8000)
                                                                - 0x8000;
-                                                       /* Ignore the LSB of
-                                                          LO, which is
+
+                                                       /* Maybe ignore the LSB
+                                                          of LO, which is
                                                           actually part of the
                                                           instruction.  */
-                                                       lo &= ~1;
+                                                       if (r2_type != R_V850_LO16)
+                                                               lo &= ~1;
+
                                                        sym_addr =
                                                                (hi << 16)
                                                                + lo;
                                                }
                                        } else
-                               case R_V850_HI16:
+                                               goto bad_v850_reloc_err;
+                                       break;
+
                                case R_V850_LO16:
-                                       {
-                                               printf("ERROR: reloc type %s unsupported in this context\n",
-                                                      q->howto->name);
-                                               bad_relocs++;
-                                       }
+                                       /* 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_v850_reloc_err;
+
+                               case R_V850_HI16:
+                               bad_v850_reloc_err:
+                                       printf("ERROR: reloc type %s unsupported in this context\n",
+                                              q->howto->name);
+                                       bad_relocs++;
                                        break;
 #endif /* TARGET_V850 */
+
                                default:
                                        /* The default is to assume that the
                                           relocation is relative and has
@@ -571,7 +618,7 @@ dump_symbols(symbols, number_of_symbols);
                                /* Calculate the sym address ourselves.  */
                                sym_reloc_size = bfd_get_reloc_size(q->howto);
 
-#ifndef TARGET_h8300
+#if !defined(TARGET_h8300) && !defined(TARGET_e1)
                                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);
@@ -672,7 +719,8 @@ dump_symbols(symbols, number_of_symbols);
                                                bad_relocs++;
                                                continue;
                                        }
-                                       relocation_needed = 1;
+                                       /* 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;
@@ -752,12 +800,28 @@ dump_symbols(symbols, number_of_symbols);
                                        continue;
                                }
                                case R_MICROBLAZE_32:
-                                       relocation_needed = 1;
-                                       //sym_addr = (*(q->sym_ptr_ptr))->value;
+                               {       
+                                       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);
-                                       sym_addr += sym_vma + q->addend;
-                                       break;
+                                       /* 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;
@@ -830,6 +894,180 @@ dump_symbols(symbols, number_of_symbols);
                                        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);
@@ -889,7 +1127,33 @@ dump_symbols(symbols, number_of_symbols);
                                else
                                        *(unsigned long *)r_mem = tmp.l;
 
-#else /* ! TARGET_arm */
+#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
@@ -934,12 +1198,38 @@ dump_symbols(symbols, number_of_symbols);
                        if (relocation_needed) {
                                flat_relocs = realloc(flat_relocs,
                                        (flat_reloc_count + 1) * sizeof(unsigned long));
+#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++;
                                relocation_needed = 0;
                                pflags = 0;
@@ -1001,7 +1291,7 @@ output_offset_table(int fd, char *ename, bfd *abfd, asymbol **symbol_table, long
 
   asection *text_section = bfd_get_section_by_name (abfd, ".text");
 
-  if (!(ef = fopen(ename, "r"))) {
+  if (!(ef = fopen(ename, "rb"))) {
     fprintf (stderr,"Can't open %s\n",ename);
     exit(1);
   }
@@ -1120,12 +1410,15 @@ int main(int argc, char *argv[])
   unsigned long bss_vma = ~0;
   unsigned long text_vma = ~0;
 
+  unsigned long text_offs;
+
   void *text;
   void *data;
   unsigned long *reloc;
   
   struct flat_hdr hdr;
 
+  int gf_is_pipe = 0;
 
   program = argv[0];
   progname = argv[0];
@@ -1133,7 +1426,11 @@ int main(int argc, char *argv[])
   if (argc < 2)
        usage();
   
+#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, "avzdrkp:s:o:R:")) != -1) {
     switch (opt) {
@@ -1235,6 +1532,8 @@ int main(int argc, char *argv[])
   /* 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;
@@ -1248,14 +1547,17 @@ int main(int argc, char *argv[])
     } else
       continue;
 
-    if (s->vma < *vma) {
+    sec_size = bfd_section_size(abs_bfd, s);
+    sec_vma  = bfd_section_vma(abs_bfd, s);
+
+    if (sec_vma < *vma) {
       if (*len > 0)
-       *len += s->vma - *vma;
+       *len += sec_vma - *vma;
       else
-       *len = s->_raw_size;
-      *vma = s->vma;
-    } else if (s->vma + s->_raw_size > *vma + *len)
-      *len = s->vma + s->_raw_size - *vma;
+       *len = sec_size;
+      *vma = sec_vma;
+    } else if (sec_vma + sec_size > *vma + *len)
+      *len = sec_vma + sec_size - *vma;
   }
 
   if (text_len == 0) {
@@ -1271,9 +1573,9 @@ int main(int argc, char *argv[])
   /* 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,
+      if (!bfd_get_section_contents(abs_bfd, s,
                                   text + (s->vma - text_vma), 0,
-                                  s->_raw_size) == false)
+                                  bfd_section_size(abs_bfd, s)))
       {
        fprintf(stderr, "read error section %s\n", s->name);
        exit(2);
@@ -1302,9 +1604,9 @@ int main(int argc, char *argv[])
   /* 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,
+      if (!bfd_get_section_contents(abs_bfd, s,
                                   data + (s->vma - data_vma), 0,
-                                  s->_raw_size) == false)
+                                  bfd_section_size(abs_bfd, s)))
       {
        fprintf(stderr, "read error section %s\n", s->name);
        exit(2);
@@ -1316,8 +1618,8 @@ int main(int argc, char *argv[])
   if (verbose)
     printf("BSS  -> vma=0x%x len=0x%x\n", bss_vma, bss_len);
 
-  if ((text_vma + text_len + data_len) != bss_vma) {
-    if ((text_vma + text_len + data_len) > bss_vma) {
+  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);
@@ -1325,7 +1627,7 @@ int main(int argc, char *argv[])
     if (verbose)
       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 - data_vma;
+    data_len = bss_vma - data_vma;
   }
 
   reloc = (unsigned long *)
@@ -1335,15 +1637,17 @@ int main(int argc, char *argv[])
   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.data_start  = htonl(16 * 4 + text_offs + text_len);
+  hdr.data_end    = htonl(16 * 4 + text_offs + text_len + data_len);
+  hdr.bss_end     = htonl(16 * 4 + text_offs + text_len + data_len + bss_len);
   hdr.stack_size  = htonl(stack); /* FIXME */
-  hdr.reloc_start = htonl(16 * 4 + real_address_bits(data_vma) + data_len);
+  hdr.reloc_start = htonl(16 * 4 + text_offs + text_len + data_len);
   hdr.reloc_count = htonl(reloc_len);
   hdr.flags       = htonl(0
          | (load_to_ram ? FLAT_FLAG_RAM : 0)
@@ -1384,16 +1688,21 @@ 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, "wb"))) { \
                        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);
   }
 
@@ -1402,8 +1711,8 @@ int main(int argc, char *argv[])
 
   /* Fill in any hole at the beginning of the text segment.  */
   if (verbose)
-         printf("ZERO before text len=0x%x\n", real_address_bits(text_vma));
-  write_zeroes(real_address_bits(text_vma), 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);
@@ -1411,18 +1720,15 @@ int main(int argc, char *argv[])
   if (compress == 2)
        START_COMPRESSOR;
 
-  /* Fill in any hole at the beginning of the data segment.  */
-  /* this is text relative so we don't need to mask any bits */
-  if (verbose)
-         printf("ZERO before data len=0x%x\n", data_vma - (text_vma + text_len));
-  write_zeroes(data_vma - (text_vma + text_len), gf);
-
   /* Write the data segment.  */
   fwrite(data, data_len, 1, gf);
 
   if (reloc)
     fwrite(reloc, reloc_len * 4, 1, gf);
 
+  if(gf_is_pipe)
+    pclose(gf);
+  else
   fclose(gf);
 
   exit(0);