/*
 * elf2flt.c: Convert ELF (or any BFD format) to FLAT binary format
 *
 * (c) 1999-2002, Greg Ungerer <gerg@snapgear.com>
 * Created elf2flt from coff2flt (see copyrights below). Added all the
 * 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>
 * (c) 2001-2003, arm/arm-pic/arm-big-endian support <davidm@snapgear.com>
 * (c) 2001, v850 changes, Mile Bader <miles@lsi.nec.co.jp>
 * (c) 2003, SuperH support, Paul Mundt <lethal@linux-sh.org>
 * (c) 2001, zflat support <davidm@snapgear.com>
 * (c) 2001, Changes for GOT entries Paul Dale <pauli@snapgear.com> and
 *           David McCullough <davidm@snapgear.com>
 *
 * Now supports PIC with GOT tables.  This works by taking a '.elf' file
 * and a fully linked elf executable (at address 0) and produces a flat
 * file that can be loaded with some fixups.  It still supports the old
 * style fully relocatable elf format files.
 *
 * Originally obj-res.c
 *
 * (c) 1998, Kenneth Albanowski <kjahds@kjahds.com>
 * (c) 1998, D. Jeff Dionne
 * (c) 1998, The Silver Hammer Group Ltd.
 * (c) 1996, 1997 Dionne & Associates <jeff@ryeham.ee.ryerson.ca>
 *
 * This is Free Software, under the GNU Public Licence v2 or greater.
 *
 * Relocation added March 1997, Kresten Krab Thorup 
 * krab@california.daimi.aau.dk
 */
 
#include <stdio.h>    /* Userland pieces of the ANSI C standard I/O package  */
#include <stdlib.h>   /* Userland prototypes of the ANSI C std lib functions */
#include <stdarg.h>   /* Allows va_list to exist in the these namespaces     */
#include <string.h>   /* Userland prototypes of the string handling funcs    */
#include <strings.h>
#include <unistd.h>   /* Userland prototypes of the Unix std system calls    */
#include <fcntl.h>    /* Flag value for file handling functions              */
#include <time.h>
#ifndef WIN32
#include <netinet/in.h> /* Consts and structs defined by the internet system */
#define	BINARY_FILE_OPTS
#else
#include <winsock2.h>
#define	BINARY_FILE_OPTS "b"
#endif

/* from $(INSTALLDIR)/include       */
#include <bfd.h>      /* Main header file for the BFD library                */

#if defined(TARGET_h8300)
#include <elf/h8.h>      /* TARGET_* ELF support for the BFD library            */
#elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(TARGET_nios) || defined(TARGET_nios2)
#include "cygwin-elf.h"	/* Cygwin uses a local copy */
#elif defined(TARGET_microblaze)
#include <elf/microblaze.h>	/* TARGET_* ELF support for the BFD library */
#elif defined(TARGET_bfin)
#include "elf/bfin.h"
#else
#include <elf.h>      /* TARGET_* ELF support for the BFD library            */
#endif

#if defined(__MINGW32__)
#include <getopt.h>
#endif

/* from uClinux-x.x.x/include/linux */
#include "flat.h"     /* Binary flat header description                      */

#ifdef TARGET_e1
#include <e1.h>
#endif

#ifdef TARGET_v850e
#define TARGET_v850
#endif

#if defined(TARGET_m68k)
#define	ARCH	"m68k/coldfire"
#elif defined(TARGET_arm)
#define	ARCH	"arm"
#elif defined(TARGET_sparc)
#define	ARCH	"sparc"
#elif defined(TARGET_v850)
#define	ARCH	"v850"
#elif defined(TARGET_sh)
#define	ARCH	"sh"
#elif defined(TARGET_h8300)
#define	ARCH	"h8300"
#elif defined(TARGET_microblaze)
#define ARCH	"microblaze"
#elif defined(TARGET_e1)
#define ARCH    "e1-coff"
#elif defined(TARGET_bfin)
#define ARCH	"bfin"
#define FLAT_RELOC_TYPE_TEXT 0
#define FLAT_RELOC_TYPE_DATA 1
#define FLAT_RELOC_TYPE_BSS 2
#define FLAT_RELOC_TYPE_STACK 3
#define FLAT_RELOC_PART_LO 0
#define FLAT_RELOC_PART_HI 1
#define PCREL24_MAGIC_OFFSET -1
#elif defined(TARGET_nios)
#define ARCH	"nios"
#elif defined(TARGET_nios2)
#define ARCH	"nios2"
#else
#error "Don't know how to support your CPU architecture??"
#endif

#if defined(TARGET_m68k) || defined(TARGET_h8300) || defined(TARGET_bfin)
/*
 * Define a maximum number of bytes allowed in the offset table.
 * We'll fail if the table is larger than this.
 *
 * This limit may be different for platforms other than m68k, but
 * 8000 entries is a lot,  trust me :-) (davidm)
 */
#define GOT_LIMIT 32767
/*
 * we have to mask out the shared library id here and there,  this gives
 * us the real address bits when needed
 */
#define	real_address_bits(x)	(pic_with_got ? ((x) & 0xffffff) : (x))
#else
#define	real_address_bits(x)	(x)
#endif

#ifndef O_BINARY
#define O_BINARY 0
#endif


int verbose = 0;      /* extra output when running */
int pic_with_got = 0; /* do elf/got processing with PIC code */
int load_to_ram = 0;  /* instruct loader to allocate everything into RAM */
int ktrace = 0;       /* instruct loader output kernel trace on load */
int compress = 0;     /* 1 = compress everything, 2 = compress data only */
int use_resolved = 0; /* If true, get the value of symbol references from */
		      /* the program contents, not from the relocation table. */
		      /* In this case, the input ELF file must be already */
		      /* fully resolved (using the `-q' flag with recent */
		      /* versions of GNU ld will give you a fully resolved */
		      /* output file with relocation entries).  */

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");
}


asymbol**
get_symbols (bfd *abfd, long *num)
{
  long storage_needed;
  asymbol **symbol_table;
  long number_of_symbols;
  
  storage_needed = bfd_get_symtab_upper_bound (abfd);
	  
  if (storage_needed < 0)
    abort ();
      
  if (storage_needed == 0)
    return NULL;

  symbol_table = (asymbol **) malloc (storage_needed);

  number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
  
  if (number_of_symbols < 0) 
    abort ();

  *num = number_of_symbols;
  return symbol_table;
}



int
dump_symbols(asymbol **symbol_table, long number_of_symbols)
{
  long i;
  printf("SYMBOL TABLE:\n");
  for (i=0; i<number_of_symbols; i++) {
	printf("  NAME=%s  VALUE=0x%x\n", symbol_table[i]->name,
		symbol_table[i]->value);
  }
  printf("\n");
  return(0);
}  



long
get_symbol_offset(char *name, asection *sec, asymbol **symbol_table, long number_of_symbols)
{
  long i;
  for (i=0; i<number_of_symbols; i++) {
    if (symbol_table[i]->section == sec) {
      if (!strcmp(symbol_table[i]->name, name)) {
        return symbol_table[i]->value;
      }
    }
  }
  return -1;
}  



long
get_gp_value(asymbol **symbol_table, long number_of_symbols)
{
  long i;
  for (i=0; i<number_of_symbols; i++) {
      if (!strcmp(symbol_table[i]->name, "_gp"))
		return symbol_table[i]->value;
  }
  return -1;
}
 


long
add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
{
  long i, comsize;
  long offset;

  comsize = 0;
  for (i=0; i<number_of_symbols; i++) {
    if (strcmp("*COM*", symbol_table[i]->section->name) == 0) {
      offset = bss_len + comsize;
      comsize += symbol_table[i]->value;
      symbol_table[i]->value = offset;
    }
  }
  return comsize;
}  

#ifdef TARGET_bfin
/* FUNCTION : weak_und_symbol
   ABSTRACT : return true if symbol is weak and undefined.
*/
static int
weak_und_symbol(const char *reloc_section_name,
                struct bfd_symbol *symbol)
{
    if (!(strstr (reloc_section_name, "text")
	  || strstr (reloc_section_name, "data")
	  || strstr (reloc_section_name, "bss"))) {
	if (symbol->flags & BSF_WEAK) {
#ifdef DEBUG_BFIN
	    fprintf(stderr, "found weak undefined symbol %s\n", symbol->name);
#endif
	    return TRUE;
	}
    }
    return FALSE;
}

static int
bfin_set_reloc (uint32_t *reloc, 
		const char *reloc_section_name, 
		const char *sym_name,
		struct bfd_symbol *symbol,
		int sp, int hilo, int32_t offset)
{
    unsigned int type;
    uint32_t val;

    if (strstr (reloc_section_name, "text"))
	type = FLAT_RELOC_TYPE_TEXT;
    else if (strstr (reloc_section_name, "data"))
	type = FLAT_RELOC_TYPE_DATA;
    else if (strstr (reloc_section_name, "bss"))
	type = FLAT_RELOC_TYPE_BSS;
    else if (strstr (reloc_section_name, "stack"))
	type = FLAT_RELOC_TYPE_STACK;
    else if (symbol->flags & BSF_WEAK){
	/* weak symbol support ... if a weak symbol is undefined at the
	   end of a final link, it should return 0 rather than error
	   We will assume text section for the moment.
	*/
	type = FLAT_RELOC_TYPE_TEXT;
    } else if (strstr (reloc_section_name, "*ABS*")){
	/* (A data section initialization of something in the shared libc's text section
	   does not resolve - i.e. a global pointer to function initialized with
	   a libc function).
	   The text section here is appropriate as the section information
	   of the shared library is lost. The loader will do some calcs.
	*/
	type = FLAT_RELOC_TYPE_TEXT;
    } else {
	printf ("Unknown Type - relocation for %s in bad section - %s\n", sym_name, reloc_section_name);
	return 1;
    }

    val = (offset & ((1 << 26) - 1)) << 6;
    val |= (sp & (1 << 3) - 1) << 3;
    val |= (hilo & 1) << 2;
    val |= (type & (1 << 2) - 1);
    *reloc = val;
    return 0;
}
#endif


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,
  bfd *rel_bfd)
{
  uint32_t		*flat_relocs;
  asection		*a, *sym_section, *r;
  arelent		**relpp, **p, *q;
  const char		*sym_name, *section_name;
  unsigned char		*sectionp;
  unsigned long		pflags;
  char			addstr[16];
  long			sym_addr, sym_vma, section_vma;
  int			relsize, relcount;
  int			flat_reloc_count;
  int			sym_reloc_size, rc;
  int			got_size = 0;
  int			bad_relocs = 0;
  asymbol		**symb;
  long			nsymb;
  
#if 0
  printf("%s(%d): output_relocs(abs_bfd=%d,synbols=0x%x,number_of_symbols=%d"
	"n_relocs=0x%x,text=0x%x,text_len=%d,data=0x%x,data_len=%d)\n",
	__FILE__, __LINE__, abs_bfd, symbols, number_of_symbols, n_relocs,
	text, text_len, data, data_len);
#endif

#if 0
dump_symbols(symbols, number_of_symbols);
#endif

  *n_relocs = 0;
  flat_relocs = NULL;
  flat_reloc_count = 0;
  rc = 0;
  pflags = 0;

  /* Determine how big our offset table is in bytes.
   * This isn't too difficult as we've terminated the table with -1.
   * 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 && !use_resolved) {
    unsigned long *lp = (unsigned long *)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);
#ifdef TARGET_m68k
    if (got_size > GOT_LIMIT) {
	    fprintf(stderr, "GOT too large: %d bytes (limit = %d bytes)\n",
			    got_size, GOT_LIMIT);
	    exit(1);
    }
#endif
  }

  for (a = abs_bfd->sections; (a != (asection *) NULL); a = a->next) {
  	section_vma = bfd_section_vma(abs_bfd, a);

	if (verbose)
		printf("SECTION: %s [0x%x]: flags=0x%x vma=0x%x\n", a->name, a,
			a->flags, section_vma);

//	if (bfd_is_abs_section(a))
//		continue;
	if (bfd_is_und_section(a))
		continue;
	if (bfd_is_com_section(a))
		continue;
//	if ((a->flags & SEC_RELOC) == 0)
//		continue;

	/*
	 *	Only relocate things in the data sections if we are PIC/GOT.
	 *	otherwise do text as well
	 */
	if (!pic_with_got && (a->flags & SEC_CODE))
		sectionp = text + (a->vma - text_vma);
	else if (a->flags & SEC_DATA)
		sectionp = data + (a->vma - data_vma);
	else
		continue;

	/* Now search for the equivalent section in the relocation binary
	 * and use that relocation information to build reloc entries
	 * for this one.
	 */
	for (r=rel_bfd->sections; r != NULL; r=r->next)
		if (strcmp(a->name, r->name) == 0)
			break;
	if (r == NULL)
	  continue;
	if (verbose)
	  printf(" RELOCS: %s [0x%x]: flags=0x%x vma=0x%x\n", r->name, r,
			r->flags, bfd_section_vma(abs_bfd, r));
  	if ((r->flags & SEC_RELOC) == 0)
  	  continue;
	relsize = bfd_get_reloc_upper_bound(rel_bfd, r);
	if (relsize <= 0) {
		if (verbose)
			printf("%s(%d): no relocation entries section=0x%x\n",
				__FILE__, __LINE__, r->name);
		continue;
	}

	symb = get_symbols(rel_bfd, &nsymb);
	relpp = (arelent **) xmalloc(relsize);
	relcount = bfd_canonicalize_reloc(rel_bfd, r, relpp, symb);
	if (relcount <= 0) {
		if (verbose)
			printf("%s(%d): no relocation entries section=%s\n",
			__FILE__, __LINE__, r->name);
		continue;
	} else {
		for (p = relpp; (relcount && (*p != NULL)); p++, relcount--) {
			unsigned char *r_mem;
			int relocation_needed = 0;

#ifdef TARGET_microblaze
			/* The MICROBLAZE_XX_NONE relocs can be skipped.
			   They represent PC relative branches that the
			   linker has already resolved */
				
			switch ((*p)->howto->type) 
			{
			case R_MICROBLAZE_NONE:
			case R_MICROBLAZE_64_NONE:
				continue;
			}
#endif /* TARGET_microblaze */

#ifdef TARGET_v850
			/* Skip this relocation entirely if possible (we
			   do this early, before doing any other
			   processing on it).  */
			switch ((*p)->howto->type) {
#ifdef R_V850_9_PCREL
			case R_V850_9_PCREL:
#endif
#ifdef R_V850_22_PCREL
			case R_V850_22_PCREL:
#endif
#ifdef R_V850_SDA_16_16_OFFSET
			case R_V850_SDA_16_16_OFFSET:
#endif
#ifdef R_V850_SDA_15_16_OFFSET
			case R_V850_SDA_15_16_OFFSET:
#endif
#ifdef R_V850_ZDA_15_16_OFFSET
			case R_V850_ZDA_15_16_OFFSET:
#endif
#ifdef R_V850_TDA_6_8_OFFSET
			case R_V850_TDA_6_8_OFFSET:
#endif
#ifdef R_V850_TDA_7_8_OFFSET
			case R_V850_TDA_7_8_OFFSET:
#endif
#ifdef R_V850_TDA_7_7_OFFSET
			case R_V850_TDA_7_7_OFFSET:
#endif
#ifdef R_V850_TDA_16_16_OFFSET
			case R_V850_TDA_16_16_OFFSET:
#endif
#ifdef R_V850_TDA_4_5_OFFSET
			case R_V850_TDA_4_5_OFFSET:
#endif
#ifdef R_V850_TDA_4_4_OFFSET
			case R_V850_TDA_4_4_OFFSET:
#endif
#ifdef R_V850_SDA_16_16_SPLIT_OFFSET
			case R_V850_SDA_16_16_SPLIT_OFFSET:
#endif
#ifdef R_V850_CALLT_6_7_OFFSET
			case R_V850_CALLT_6_7_OFFSET:
#endif
#ifdef R_V850_CALLT_16_16_OFFSET
			case R_V850_CALLT_16_16_OFFSET:
#endif
				/* These are relative relocations, which
				   have already been fixed up by the
				   linker at this point, so just ignore
				   them.  */ 
				continue;
			}
#endif /* USE_V850_RELOCS */

			q = *p;
			if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
				sym_name = (*(q->sym_ptr_ptr))->name;
				sym_section = (*(q->sym_ptr_ptr))->section;
				section_name=(*(q->sym_ptr_ptr))->section->name;
			} else {
				printf("ERROR: undefined relocation entry\n");
				rc = -1;
				continue;
			}
#ifndef TARGET_bfin
			/* Adjust the address to account for the GOT table which wasn't
			 * present in the relative file link.
			 */
			if (pic_with_got && !use_resolved)
			  q->address += got_size;
#endif

			/* A pointer to what's being relocated, used often
			   below.  */
			r_mem = sectionp + q->address;

			/*
			 *	Fixup offset in the actual section.
			 */
			addstr[0] = 0;
#ifndef TARGET_e1
  			if ((sym_addr = get_symbol_offset((char *) sym_name,
			    sym_section, symbols, number_of_symbols)) == -1) {
				sym_addr = 0;
			}
#else
			sym_addr = (*(q->sym_ptr_ptr))->value;
#endif			
			if (use_resolved) {
				/* Use the address of the symbol already in
				   the program text.  How this is handled may
				   still depend on the particular relocation
				   though.  */
				switch (q->howto->type) {
					int r2_type;
#ifdef TARGET_v850
				case R_V850_HI16_S:
					/* We specially handle adjacent
					   HI16_S/ZDA_15_16_OFFSET and
					   HI16_S/LO16 pairs that reference the
					   same address (these are usually
					   movhi/ld and movhi/movea pairs,
					   respectively).  */
					if (relcount == 0)
						r2_type = R_V850_NONE;
					else
						r2_type = p[1]->howto->type;
					if ((r2_type == R_V850_ZDA_15_16_OFFSET
					     || r2_type == R_V850_LO16)
					    && (p[0]->sym_ptr_ptr
						== p[1]->sym_ptr_ptr)
					    && (p[0]->addend == p[1]->addend))
					{
						relocation_needed = 1;

						switch (r2_type) {
						case R_V850_ZDA_15_16_OFFSET:
							pflags = 0x10000000;
							break;
						case R_V850_LO16:
							pflags = 0x20000000;
							break;
						}

						/* We don't really need the
						   actual value -- the bits
						   produced by the linker are
						   what we want in the final
						   flat file -- but get it
						   anyway if useful for
						   debugging.  */
						if (verbose) {
							unsigned char *r2_mem =
								sectionp
								+ p[1]->address;
							/* little-endian */
							int hi = r_mem[0]
								+ (r_mem[1] << 8);
							int lo = r2_mem[0]
								+ (r2_mem[1] << 8);
							/* Sign extend LO.  */
							lo = (lo ^ 0x8000)
								- 0x8000;

							/* Maybe ignore the LSB
							   of LO, which is
							   actually part of the
							   instruction.  */
							if (r2_type != R_V850_LO16)
								lo &= ~1;

							sym_addr =
								(hi << 16)
								+ lo;
						}
					} else
						goto bad_resolved_reloc;
					break;

				case R_V850_LO16:
					/* See if this is actually the
					   2nd half of a pair.  */
					if (p > relpp
					    && (p[-1]->howto->type
						== R_V850_HI16_S)
					    && (p[-1]->sym_ptr_ptr
						== p[0]->sym_ptr_ptr)
					    && (p[-1]->addend == p[0]->addend))
						break; /* not an error */
					else
						goto bad_resolved_reloc;

				case R_V850_HI16:
					goto bad_resolved_reloc;
				default:
					goto good_32bit_resolved_reloc;
#elif defined(TARGET_arm)
				case R_ARM_ABS32:
					relocation_needed = 1;
					break;
				case R_ARM_REL32:
				case R_ARM_THM_PC11:
				case R_ARM_THM_PC22:
					relocation_needed = 0;
					break;
				default:
					goto bad_resolved_reloc;
#elif defined(TARGET_m68k)
				case R_68K_32:
					goto good_32bit_resolved_reloc;
				case R_68K_PC32:
				case R_68K_PC16:
					/* The linker has already resolved
					   PC relocs for us.  In PIC links,
					   the symbol must be in the data
					   segment.  */
				case R_68K_NONE:
					continue;
				default:
					goto bad_resolved_reloc;
#else
				default:
					/* The default is to assume that the
					   relocation is relative and has
					   already been fixed up by the
					   linker (perhaps we ought to make
					   give an error by default, and
					   require `safe' relocations to be
					   enumberated explicitly?).  */
					goto good_32bit_resolved_reloc;
#endif
				good_32bit_resolved_reloc:
					if (bfd_big_endian (abs_bfd))
						sym_addr =
							(r_mem[0] << 24)
							+ (r_mem[1] << 16)
							+ (r_mem[2] << 8) 
							+ r_mem[3];
					else
						sym_addr =
							r_mem[0]
							+ (r_mem[1] << 8)
							+ (r_mem[2] << 16)
							+ (r_mem[3] << 24);
					relocation_needed = 1;
					break;

				bad_resolved_reloc:
					printf("ERROR: reloc type %s unsupported in this context\n",
					       q->howto->name);
					bad_relocs++;
					break;
				}
			} else {
				/* Calculate the sym address ourselves.  */
				sym_reloc_size = bfd_get_reloc_size(q->howto);

#if !defined(TARGET_h8300) && !defined(TARGET_e1) && !defined(TARGET_bfin) && !defined(TARGET_m68k)
				if (sym_reloc_size != 4) {
					printf("ERROR: bad reloc type %d size=%d for symbol=%s\n",
							(*p)->howto->type, sym_reloc_size, sym_name);
					bad_relocs++;
					rc = -1;
					continue;
				}
#endif

				switch ((*p)->howto->type) {

#if defined(TARGET_m68k)
				case R_68K_32:
					relocation_needed = 1;
					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;
					sym_addr -= q->address;
					break;
#endif

#if defined(TARGET_arm)
				case R_ARM_ABS32:
					relocation_needed = 1;
					if (verbose)
						fprintf(stderr,
							"%s vma=0x%x, value=0x%x, address=0x%x "
							"sym_addr=0x%x rs=0x%x, opcode=0x%x\n",
							"ABS32",
							sym_vma, (*(q->sym_ptr_ptr))->value,
							q->address, sym_addr,
							(*p)->howto->rightshift,
							*(unsigned long *)r_mem);
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
				case R_ARM_GOT32:
				case R_ARM_GOTPC:
					/* Should be fine as is */
					break;
				case R_ARM_PLT32:
					if (verbose)
						fprintf(stderr,
							"%s vma=0x%x, value=0x%x, address=0x%x "
							"sym_addr=0x%x rs=0x%x, opcode=0x%x\n",
							"PLT32",
							sym_vma, (*(q->sym_ptr_ptr))->value,
							q->address, sym_addr,
							(*p)->howto->rightshift,
							*(unsigned long *)r_mem);
				case R_ARM_PC24:
					sym_vma = 0;
					sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift;
					break;
#endif

#ifdef TARGET_v850
				case R_V850_32:
					relocation_needed = 1;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
#if defined(R_V850_ZDA_16_16_OFFSET) || defined(R_V850_ZDA_16_16_SPLIT_OFFSET)
#ifdef R_V850_ZDA_16_16_OFFSET
				case R_V850_ZDA_16_16_OFFSET:
#endif
#ifdef R_V850_ZDA_16_16_SPLIT_OFFSET
				case R_V850_ZDA_16_16_SPLIT_OFFSET:
#endif
					/* Can't support zero-relocations.  */
					printf ("ERROR: %s+0x%x: zero relocations not supported\n",
							sym_name, q->addend);
					continue;
#endif /* R_V850_ZDA_16_16_OFFSET || R_V850_ZDA_16_16_SPLIT_OFFSET */
#endif /* TARGET_v850 */

#ifdef TARGET_h8300
				case R_H8_DIR24R8:
					if (sym_reloc_size != 4) {
						printf("R_H8_DIR24R8 size %d\n", sym_reloc_size);
						bad_relocs++;
						continue;
					}
					relocation_needed = 1;
					sym_addr = (*(q->sym_ptr_ptr))->value;
					q->address -= 1;
					r_mem -= 1; /* tracks q->address */
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					sym_addr |= (*(unsigned char *)r_mem<<24);
					break;
				case R_H8_DIR24A8:
					if (sym_reloc_size != 4) {
						printf("R_H8_DIR24A8 size %d\n", sym_reloc_size);
						bad_relocs++;
						continue;
					}
					/* Absolute symbol done not relocation */
					relocation_needed = !bfd_is_abs_section(sym_section);
					sym_addr = (*(q->sym_ptr_ptr))->value;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
				case R_H8_DIR32:
				case R_H8_DIR32A16: /* currently 32,  could be made 16 */
					if (sym_reloc_size != 4) {
						printf("R_H8_DIR32 size %d\n", sym_reloc_size);
						bad_relocs++;
						continue;
					}
					relocation_needed = 1;
					sym_addr = (*(q->sym_ptr_ptr))->value;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
				case R_H8_PCREL16:
					sym_vma = 0;
					sym_addr = (*(q->sym_ptr_ptr))->value;
					sym_addr += sym_vma + q->addend;
					sym_addr -= (q->address + 2);
					if (bfd_big_endian(abs_bfd))
					*(unsigned short *)r_mem =
						bfd_big_endian(abs_bfd) ? htons(sym_addr) : sym_addr;
					continue;
				case R_H8_PCREL8:
					sym_vma = 0;
					sym_addr = (*(q->sym_ptr_ptr))->value;
					sym_addr += sym_vma + q->addend;
					sym_addr -= (q->address + 1);
					*(unsigned char *)r_mem = sym_addr;
					continue;
#endif

#ifdef TARGET_microblaze
				case R_MICROBLAZE_64:
		/* The symbol is split over two consecutive instructions.  
		   Flag this to the flat loader by setting the high bit of 
		   the relocation symbol. */
				{
					unsigned char *p = r_mem;
					unsigned long offset;
					pflags=0x80000000;

					/* work out the relocation */
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					/* grab any offset from the text */
					offset = (p[2]<<24) + (p[3] << 16) + (p[6] << 8) + (p[7]);
					/* Update the address */
					sym_addr += offset + sym_vma + q->addend;
					/* Write relocated pointer back */
					p[2] = (sym_addr >> 24) & 0xff;
					p[3] = (sym_addr >> 16) & 0xff;
					p[6] = (sym_addr >>  8) & 0xff;
					p[7] =  sym_addr        & 0xff;

					/* create a new reloc entry */
					flat_relocs = realloc(flat_relocs,
						(flat_reloc_count + 1) * sizeof(uint32_t));
					flat_relocs[flat_reloc_count] = pflags | (section_vma + q->address);
					flat_reloc_count++;
					relocation_needed = 0;
					pflags = 0;
			sprintf(&addstr[0], "+0x%x", sym_addr - (*(q->sym_ptr_ptr))->value -
					 bfd_section_vma(abs_bfd, sym_section));
			if (verbose)
				printf("  RELOC[%d]: offset=0x%x symbol=%s%s "
					"section=%s size=%d "
					"fixup=0x%x (reloc=0x%x)\n", flat_reloc_count,
					q->address, sym_name, addstr,
					section_name, sym_reloc_size,
					sym_addr, section_vma + q->address);
			if (verbose)
				printf("reloc[%d] = 0x%x\n", flat_reloc_count,
					 section_vma + q->address);

					continue;
				}
				case R_MICROBLAZE_32:
				{	
					unsigned char *p = r_mem;
					unsigned long offset;

					/* grab any offset from the text */
					offset = (p[0]<<24) + (p[1] << 16) + (p[2] << 8) + (p[3]);
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					/* This is a horrible kludge.  For some
					   reason, *sometimes* the offset is in
					   both addend and the code.  Detect
					   it, and cancel the effect.  Otherwise
					   the offset gets added twice - ouch.
					   There should be a better test
					   for this condition, based on the
					   BFD data structures */
					if(offset==q->addend)
						offset=0;

					sym_addr += offset + sym_vma + q->addend;
					relocation_needed = 1;
					break;
				}
				case R_MICROBLAZE_64_PCREL:
					sym_vma = 0;
					//sym_addr = (*(q->sym_ptr_ptr))->value;
					sym_addr += sym_vma + q->addend;
					sym_addr -= (q->address + 4);
					sym_addr = htonl(sym_addr);
					/* insert 16 MSB */
					* ((unsigned short *) (r_mem+2)) |= (sym_addr) & 0xFFFF;
					/* then 16 LSB */
					* ((unsigned short *) (r_mem+6)) |= (sym_addr >> 16) & 0xFFFF;
					/* We've done all the work, so continue
					   to next reloc instead of break */
					continue;

#endif /* TARGET_microblaze */
					
#ifdef TARGET_nios2
#define  htoniosl(x)	(x)
#define  niostohl(x)	(x)
				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:
					relocation_needed = 1;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
				case R_SPARC_PC22:
					sym_vma = 0;
					sym_addr += sym_vma + q->addend;
					sym_addr -= q->address;
					break;
				case R_SPARC_WDISP30:
					sym_addr = (((*(q->sym_ptr_ptr))->value-
						q->address) >> 2) & 0x3fffffff;
					sym_addr |= (
						ntohl(*(unsigned long *)r_mem)
						& 0xc0000000
						);
					break;
				case R_SPARC_HI22:
					relocation_needed = 1;
					pflags = 0x80000000;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					sym_addr |= (
						htonl(*(unsigned long *)r_mem)
						& 0xffc00000
						);
					break;
				case R_SPARC_LO10:
					relocation_needed = 1;
					pflags = 0x40000000;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					sym_addr &= 0x000003ff;
					sym_addr |= (
						htonl(*(unsigned long *)r_mem)
						& 0xfffffc00
						);
					break;
#endif /* TARGET_sparc */

#ifdef TARGET_bfin
				case R_pcrel12_jump:
				case R_pcrel12_jump_s:
				case R_pcrel24:
				case R_pcrel24_jump_l:
				case R_pcrel24_jump_x:
				case R_pcrel24_call_x:
				case R_pcrel10:
				case R_pcrel11:
				case R_pcrel5m2:
				  sym_addr += q->addend;// get the symbol addr
				  sym_vma = bfd_section_vma(abs_bfd, sym_section);
				  sym_addr -= q->address; // make it PC relative 
				  // implicitly assumes code section and symbol section are same
				  break;
				case R_got:
				    /* Ignore these.  */
				    break;

				case R_rimm16:
				    sym_addr += q->addend;
				    if(weak_und_symbol(sym_section->name, (*(q->sym_ptr_ptr))))
					continue;
				    if(0xFFFF0000 & sym_addr){
					fprintf (stderr, "Relocation overflow for rN = %s\n",sym_name);
					bad_relocs++;
				    }
				    flat_relocs = (uint32_t *)
					(realloc (flat_relocs, (flat_reloc_count + 1) * sizeof (uint32_t)));
				    if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
							sym_section->name, sym_name,
							(*(q->sym_ptr_ptr)),
							0, FLAT_RELOC_PART_LO, 
							section_vma + q->address))
					bad_relocs++;
				    flat_reloc_count++;
				    break;
				    
				case R_luimm16:
				case R_huimm16:
				{
				    unsigned int sp;
				    unsigned int reloc_count_incr;
				    unsigned int hi_lo;

				    if (q->howto->type == R_luimm16)
					hi_lo = FLAT_RELOC_PART_LO;
				    else
					hi_lo = FLAT_RELOC_PART_HI;
				
				    sym_addr += q->addend;

				    flat_relocs = (uint32_t *)
					(realloc (flat_relocs, (flat_reloc_count + 2) * sizeof (uint32_t)));
				    reloc_count_incr = 1;
				    if (weak_und_symbol (sym_section->name, (*(q->sym_ptr_ptr))))
					continue;
				    if (0xFFFF0000 & sym_addr) {
					/* value is > 16 bits - use an extra field */
					/* see if we have already output that symbol */
					/* reloc may be addend from symbol and       */
					/* we can only store 16 bit offsets	     */
					sp = 1;
					if ((*(q->sym_ptr_ptr))->udata.i == 0
					    || flat_relocs[(*(q->sym_ptr_ptr))->udata.i] != sym_addr
					    || ((*(q->sym_ptr_ptr))->udata.i & 0xFFFF0000))
					{
					    reloc_count_incr = 2;
					    flat_relocs[flat_reloc_count + 1] = sym_addr;
					    (*(q->sym_ptr_ptr))->udata.i = flat_reloc_count + 1;
					    sym_addr = 0; // indication to loader to read next
					} else{
					    sym_addr = (*(q->sym_ptr_ptr))->udata.i;
					}
				    } else {
					sp = 0;
				    }

				    if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
							sym_section->name, sym_name,
							(*(q->sym_ptr_ptr)),
							sp, hi_lo,
							section_vma + q->address))
					bad_relocs++;
				    flat_reloc_count += reloc_count_incr;
				    break;
				}
				case R_byte4_data:
				    sym_addr += q->addend;

				    if (weak_und_symbol (sym_section->name, *q->sym_ptr_ptr))
					continue;

				    flat_relocs = (uint32_t *)
					(realloc (flat_relocs, (flat_reloc_count + 1) * sizeof (uint32_t)));
				    if (bfin_set_reloc (flat_relocs + flat_reloc_count, 
							sym_section->name, sym_name,
							(*(q->sym_ptr_ptr)),
							2, FLAT_RELOC_PART_LO, 
							section_vma + q->address))
					bad_relocs++;

				    flat_reloc_count++;
				    break;

#endif //TARGET_bfin

#ifdef TARGET_sh
				case R_SH_DIR32:
					relocation_needed = 1;
					sym_vma = bfd_section_vma(abs_bfd, sym_section);
					sym_addr += sym_vma + q->addend;
					break;
				case R_SH_REL32:
					sym_vma = 0;
					sym_addr += sym_vma + q->addend;
					sym_addr -= q->address;
					break;
#endif /* TARGET_sh */

#ifdef TARGET_e1
#define  htoe1l(x)              htonl(x)
					
#if 0 
#define  DEBUG_E1
#endif

#ifdef   DEBUG_E1
#define  DBG_E1                 printf
#else
#define  DBG_E1(x, ...  )
#endif

#define _32BITS_RELOC 0x00000000
#define _30BITS_RELOC 0x80000000
#define _28BITS_RELOC 0x40000000
					{
				char *p;
				unsigned long   sec_vma, exist_val, S;
				case R_E1_CONST31:
						relocation_needed = 1;
						DBG_E1("Handling Reloc <CONST31>\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
										sec_vma, sym_addr, q->address);
						sym_addr = sec_vma + sym_addr;
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);        
						DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
						sym_addr += exist_val;
						pflags = _30BITS_RELOC;
						break;
				case R_E1_CONST31_PCREL:
						relocation_needed = 0;
						DBG_E1("Handling Reloc <CONST31_PCREL>\n");
						DBG_E1("DONT RELOCATE AT LOADING\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
										sec_vma, sym_addr, q->address);
						sym_addr =  sec_vma + sym_addr;
						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );

						DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
																		section_vma );
						q->address = q->address + section_vma;
						DBG_E1("q->address += section_vma : 0x%x\n", q->address );

						if( (sym_addr = (sym_addr - q->address - 6)) < 0 )
								DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
						DBG_E1( "sym_addr := sym_addr - q->address  - "
								"sizeof(CONST31_PCREL): [0x%x]\n",
								sym_addr );
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);              
						DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
						sym_addr |= exist_val;
						DBG_E1("sym_addr |=  exist_val) : [0x%x]\n", sym_addr );
						break;
				case R_E1_DIS29W_PCREL:
						relocation_needed = 0;
						DBG_E1("Handling Reloc <DIS29W_PCREL>\n");
						DBG_E1("DONT RELOCATE AT LOADING\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x], q->address : [0x%x]\n",
										sec_vma, sym_addr, q->address);
						sym_addr =  sec_vma + sym_addr;
						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );

						DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
																		section_vma );
						q->address = q->address + section_vma;
						DBG_E1("q->address += section_vma : 0x%x\n", q->address );

						if( (sym_addr = (sym_addr - q->address - 6)) < 0 )
								DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
						DBG_E1( "sym_addr := sym_addr - q->address  - "
								"sizeof(CONST31_PCREL): [0x%x]\n",
								sym_addr );
						DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);       
						DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
						sym_addr += exist_val;
						break;
				case R_E1_DIS29W:
						DBG_E1("Handling Reloc <DIS29W>\n");
						goto DIS29_RELOCATION;
				case R_E1_DIS29H:
						DBG_E1("Handling Reloc <DIS29H>\n");
						goto DIS29_RELOCATION;
				case R_E1_DIS29B:
						DBG_E1("Handling Reloc <DIS29B>\n");
DIS29_RELOCATION:
						relocation_needed = 1;
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%08x]\n",
										sec_vma, sym_addr);
						sym_addr =  sec_vma + sym_addr;
						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%08x]\n", sym_addr);
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                
						DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
						sym_addr +=  exist_val;
						DBG_E1("sym_addr +=  exist_val : [0x%08x]\n", sym_addr);
						pflags = _28BITS_RELOC;
						break;
				case R_E1_IMM32_PCREL:
						relocation_needed = 0;
						DBG_E1("Handling Reloc <IMM32_PCREL>\n");
						DBG_E1("DONT RELOCATE AT LOADING\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
										sec_vma, sym_addr);
						sym_addr =  sec_vma + sym_addr;

						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
						DBG_E1("q->address : 0x%x, section_vma : 0x%x\n", q->address,
																		section_vma );
						q->address = q->address + section_vma;
						DBG_E1("q->address += section_vma : 0x%x\n", q->address );

						if( (sym_addr = (sym_addr - q->address - 6 )) < 0 )
								DBG_E1("NEGATIVE OFFSET in PC Relative instruction\n");
						DBG_E1( "sym_addr := sym_addr - q->address  - "
								"sizeof(CONST31_PCREL): [0x%x]\n",
								sym_addr );
						DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                 
 						DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
						sym_addr += exist_val;
						break;
				case R_E1_IMM32:
						relocation_needed = 1;
						DBG_E1("Handling Reloc <IMM32>\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
										sec_vma, sym_addr);
						sym_addr =  sec_vma + sym_addr;
						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
						DBG_E1("sectionp:[0x%x], q->address:[0x%x]\n", sectionp, q->address );
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address + 2);                     
	 					DBG_E1("Original:exist_val : [0x%08x]\n",exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n",exist_val);
						sym_addr += exist_val;
						pflags = _32BITS_RELOC;
						break;
				case R_E1_WORD:
						relocation_needed = 1;
						DBG_E1("Handling Reloc <WORD>\n");
						sec_vma = bfd_section_vma(abs_bfd, sym_section);
						DBG_E1("sec_vma : [0x%x], sym_addr : [0x%x]\n",
										sec_vma, sym_addr);
						sym_addr =  sec_vma + sym_addr;
						DBG_E1("sym_addr =  sec_vma + sym_addr : [0x%x]\n", sym_addr );
						exist_val = *(unsigned long*)((unsigned long)sectionp + q->address );
						DBG_E1("Orig:exist_val : [0x%08x]\n", exist_val);
						exist_val = htoe1l(exist_val);
						DBG_E1("HtoBE:exist_val : [0x%08x]\n", exist_val);
						sym_addr +=  exist_val;
						DBG_E1("sym_addr +=  exist_val : [0x%08x]\n", sym_addr);
						pflags = _32BITS_RELOC;
						break;
				}
#undef _32BITS_RELOC
#undef _30BITS_RELOC
#undef _28BITS_RELOC
#endif
				default:
					/* missing support for other types of relocs */
					printf("ERROR: bad reloc type %d\n", (*p)->howto->type);
					bad_relocs++;
					continue;
				}
			}

			sprintf(&addstr[0], "+0x%x", sym_addr - (*(q->sym_ptr_ptr))->value -
					 bfd_section_vma(abs_bfd, sym_section));


			/*
			 * for full elf relocation we have to write back the
			 * start_code relative value to use.
			 */
			if (!pic_with_got) {
#if defined(TARGET_arm)
				union {
					unsigned char c[4];
					unsigned long l;
				} tmp;
				long hl;
				int i0, i1, i2, i3;

				/*
				 * horrible nasty hack to support different endianess
				 */
				if (!bfd_big_endian(abs_bfd)) {
					i0 = 0;
					i1 = 1;
					i2 = 2;
					i3 = 3;
				} else {
					i0 = 3;
					i1 = 2;
					i2 = 1;
					i3 = 0;
				}

				tmp.l = *(unsigned long *)r_mem;
				hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
				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 */
				if (!use_resolved)
					hl += sym_addr;
				tmp.c[i0] = hl & 0xff;
				tmp.c[i1] = (hl >> 8) & 0xff;
				tmp.c[i2] = (hl >> 16) & 0xff;
				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);
				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);
				}
#elif defined(TARGET_e1)
#define OPCODE_SIZE 2           /* Add 2 bytes, counting the opcode size*/
				switch ((*p)->howto->type) {
				case R_E1_CONST31:
				case R_E1_CONST31_PCREL:
				case R_E1_DIS29W_PCREL:
				case R_E1_DIS29W:
				case R_E1_DIS29H:
				case R_E1_DIS29B:
				case R_E1_IMM32_PCREL:
				case R_E1_IMM32:
						DBG_E1("In addr + 2:[0x%x] <- write [0x%x]\n",
								(sectionp + q->address + 2), sym_addr );
						*((unsigned long *) (sectionp + q->address + OPCODE_SIZE)) =
						htonl(sym_addr);
				break;
				case R_E1_WORD:
						DBG_E1("In addr : [0x%x] <- write [0x%x]\n",
								(sectionp + q->address), sym_addr );
						*((unsigned long *) (sectionp + q->address )) = htonl(sym_addr);
				break;
				default:
						printf("ERROR:Unhandled Relocation. Exiting...\n");
						exit(0);
				break;
				}
#else /* ! TARGET_arm && ! TARGET_e1 */

				switch (q->howto->type) {
#ifdef TARGET_v850
				case R_V850_HI16_S:
				case R_V850_HI16:
				case R_V850_LO16:
					/* Do nothing -- for cases we handle,
					   the bits produced by the linker are
					   what we want in the final flat file
					   (and other cases are errors).  Note
					   that unlike most relocated values,
					   it is stored in little-endian order,
					   but this is necessary to avoid
					   trashing the low-bit, and the float
					   loaders knows about it.  */
					break;
#endif /* TARGET_V850 */

#ifdef TARGET_nios2
				case R_NIOS2_BFD_RELOC_32:
				case R_NIOS2_CALL26:
				case R_NIOS2_HIADJ16:
				case R_NIOS2_HI16:
					/* do nothing */
					break;
#endif /* TARGET_nios2 */

#if defined(TARGET_m68k)
				case R_68K_PC16:
					if (sym_addr < -0x8000 || sym_addr > 0x7fff) {
						fprintf (stderr, "Relocation overflow for R_68K_PC16 relocation against %s\n", sym_name);
						bad_relocs++;
					} else {
						r_mem[0] = (sym_addr >>  8) & 0xff;
						r_mem[1] =  sym_addr        & 0xff;
					}
					break;
#endif

				default:
					/* The alignment of the build host
					   might be stricter than that of the
					   target, so be careful.  We store in
					   network byte order. */
					r_mem[0] = (sym_addr >> 24) & 0xff;
					r_mem[1] = (sym_addr >> 16) & 0xff;
					r_mem[2] = (sym_addr >>  8) & 0xff;
					r_mem[3] =  sym_addr        & 0xff;
				}
#endif /* !TARGET_arm */
			}

#ifdef TARGET_bfin
			else {
			    if ((*p)->howto->type == R_rimm16
				|| (*p)->howto->type == R_huimm16
				|| (*p)->howto->type == R_luimm16)
			    {
				/* for l and h we set the lower 16 bits which is only when it will be used */
				*((unsigned short *) (sectionp + q->address)) = (unsigned short) sym_addr;
			    } else if ((*p)->howto->type == R_byte4_data) {
				*((uint32_t *)(sectionp + q->address)) = sym_addr;
			    }
			}
#endif
			if (verbose)
				printf("  RELOC[%d]: offset=0x%x symbol=%s%s "
					"section=%s size=%d "
					"fixup=0x%x (reloc=0x%x)\n", flat_reloc_count,
					q->address, sym_name, addstr,
					section_name, sym_reloc_size,
					sym_addr, section_vma + q->address);

			/*
			 *	Create relocation entry (PC relative doesn't need this).
			 */
			if (relocation_needed) {
#ifndef TARGET_bfin
				flat_relocs = realloc(flat_relocs,
					(flat_reloc_count + 1) * sizeof(uint32_t));
#ifndef TARGET_e1
				flat_relocs[flat_reloc_count] = pflags |
					(section_vma + q->address);

				if (verbose)
					printf("reloc[%d] = 0x%x\n", flat_reloc_count,
							section_vma + q->address);
#else
				switch ((*p)->howto->type) {
				case R_E1_CONST31:
				case R_E1_CONST31_PCREL:
				case R_E1_DIS29W_PCREL:
				case R_E1_DIS29W:
				case R_E1_DIS29H:
				case R_E1_DIS29B:
				case R_E1_IMM32_PCREL:
				case R_E1_IMM32:
				flat_relocs[flat_reloc_count] = pflags |
						(section_vma + q->address + OPCODE_SIZE);
				if (verbose)
						printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
										 flat_relocs[flat_reloc_count] );
				break;
				case R_E1_WORD:
				flat_relocs[flat_reloc_count] = pflags |
						(section_vma + q->address);
				if (verbose)
						printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
										 flat_relocs[flat_reloc_count] );
				break;
				}
#endif
				flat_reloc_count++;
#endif
				relocation_needed = 0;
				pflags = 0;
			}

#if 0
printf("%s(%d): symbol name=%s address=0x%x section=%s -> RELOC=0x%x\n",
	__FILE__, __LINE__, sym_name, q->address, section_name,
	flat_relocs[flat_reloc_count]);
#endif
		}
	}
  }

  if (bad_relocs) {
	  printf("%d bad relocs\n", bad_relocs);
	  exit(1);
  }

  if (rc < 0)
	return(0);

  *n_relocs = flat_reloc_count;
  return flat_relocs;
}



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"
	"       -r              : force load to RAM\n"
	"       -k              : enable kernel trace on load (for debug)\n"
	"       -z              : compress code/data/relocs\n"
	"       -d              : compress data/relocs\n"
	"       -a              : use existing symbol references\n"
	"                         instead of recalculating from\n"
	"                         relocation info\n"
        "       -R reloc-file   : read relocations from a separate file\n"
	"       -p abs-pic-file : GOT/PIC processing with files\n"
	"       -s stacksize    : set application stack size\n"
	"       -o output-file  : output file name\n\n",
	program);
	fprintf(stderr, "Compiled for " ARCH " architecture\n\n");
    exit(2);
}


/* Write NUM zeroes to STREAM.  */
static void write_zeroes (unsigned long num, FILE *stream)
{
  char zeroes[1024];
  if (num > 0) {
    /* It'd be nice if we could just use fseek, but that doesn't seem to
       work for stdio output files.  */
    memset(zeroes, 0x00, 1024);
    while (num > sizeof(zeroes)) {
      fwrite(zeroes, sizeof(zeroes), 1, stream);
      num -= sizeof(zeroes);
    }
    if (num > 0)
      fwrite(zeroes, num, 1, stream);
  }
}


int main(int argc, char *argv[])
{
  int fd;
  bfd *rel_bfd, *abs_bfd;
  asection *s;
  char *ofile=NULL, *pfile=NULL, *abs_file = NULL, *rel_file = NULL;
  char *fname = NULL;
  int opt;
  int i;
  int stack;
  char  cmd[1024];
  FILE *gf = NULL;

  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;

  unsigned long data_vma = ~0;
  unsigned long bss_vma = ~0;
  unsigned long text_vma = ~0;

  unsigned long text_offs;

  void *text;
  void *data;
  uint32_t *reloc;
  
  struct flat_hdr hdr;

  int gf_is_pipe = 0;

  program = argv[0];
  progname = argv[0];

  if (argc < 2)
  	usage();
  
  if (sizeof(hdr) != 64) {
    fprintf(stderr,
	    "Potential flat header incompatibility detected\n"
	    "header size should be 64 but is %d\n",
	    sizeof(hdr));
    exit(64);
  }

#ifndef TARGET_e1
  stack = 4096;
#else /* We need plenty of stack for both of them (Aggregate and Register) */
  stack = 0x2020;
#endif

  while ((opt = getopt(argc, argv, "avzdrkp:s:o:R:")) != -1) {
    switch (opt) {
    case 'v':
      verbose++;
      break;
    case 'r':
      load_to_ram++;
      break;
    case 'k':
      ktrace++;
      break;
    case 'z':
      compress = 1;
      break;
    case 'd':
      compress = 2;
      break;
    case 'p':
      pfile = optarg;
      break;
    case 'o':
      ofile = optarg;
      break;
    case 'a':
      use_resolved = 1;
      break;
    case 's':
      stack = atoi(optarg);
      break;
    case 'R':
      rel_file = optarg;
      break;
    default:
      fprintf(stderr, "%s Unknown option\n", argv[0]);
      usage();
      break;
    }
  }
  
  /*
   * if neither the -r or -p options was given,  default to
   * a RAM load as that is the only option that makes sense.
   */
  if (!load_to_ram && !pfile)
    load_to_ram = 1;

  filename = fname = argv[argc-1];

  if (pfile) {
    pic_with_got = 1;
    abs_file = pfile;
  } else
    abs_file = fname;

  if (! rel_file)
    rel_file = fname;

  if (!(rel_bfd = bfd_openr(rel_file, 0))) {
    fprintf(stderr, "Can't open %s\n", rel_file);
    exit(1);
  }

  if (bfd_check_format (rel_bfd, bfd_object) == 0) {
    fprintf(stderr, "File is not an object file\n");
    exit(2);
  }

  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 (bfd_check_format (abs_bfd, bfd_object) == 0) {
      fprintf(stderr, "File is not an object file\n");
      exit(2);
    }
  }

  if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC)) {
    fprintf (stderr, "%s: Input file contains no relocation info\n", rel_file);
    exit (2);
  }

  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",
	     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;
    bfd_size_type sec_size;
    bfd_vma sec_vma;

    if (s->flags & SEC_CODE) {
      vma = &text_vma;
      len = &text_len;
    } else if (s->flags & SEC_DATA) {
      vma = &data_vma;
      len = &data_len;
    } else if (s->flags & SEC_ALLOC) {
      vma = &bss_vma;
      len = &bss_len;
    } else
      continue;

    sec_size = bfd_section_size(abs_bfd, s);
    sec_vma  = bfd_section_vma(abs_bfd, s);

    if (sec_vma < *vma) {
      if (*len > 0)
	*len += sec_vma - *vma;
      else
	*len = sec_size;
      *vma = sec_vma;
    } else if (sec_vma + sec_size > *vma + *len)
      *len = sec_vma + sec_size - *vma;
  }

  if (text_len == 0) {
    fprintf (stderr, "%s: no .text section", abs_file);
    exit (2);
  }

  text = malloc(text_len);

  if (verbose)
    printf("TEXT -> vma=0x%x len=0x%x\n", text_vma, text_len);

  /* Read in all text sections.  */
  for (s = abs_bfd->sections; s != NULL; s = s->next)
    if (s->flags & SEC_CODE) 
      if (!bfd_get_section_contents(abs_bfd, s,
				   text + (s->vma - text_vma), 0,
				   bfd_section_size(abs_bfd, s)))
      {
	fprintf(stderr, "read error section %s\n", s->name);
	exit(2);
      }

  if (data_len == 0) {
    fprintf (stderr, "%s: no .data section", abs_file);
    exit (2);
  }
  data = malloc(data_len);

  if (verbose)
    printf("DATA -> vma=0x%x len=0x%x\n", data_vma, data_len);

  if ((text_vma + text_len) != data_vma) {
    if ((text_vma + text_len) > data_vma) {
      printf("ERROR: text=0x%x overlaps data=0x%x ?\n", text_len, data_vma);
      exit(1);
    }
    if (verbose)
      printf("WARNING: data=0x%x does not directly follow text=0x%x\n",
	  		data_vma, text_len);
    text_len = data_vma - text_vma;
  }

  /* Read in all data sections.  */
  for (s = abs_bfd->sections; s != NULL; s = s->next)
    if (s->flags & SEC_DATA) 
      if (!bfd_get_section_contents(abs_bfd, s,
				   data + (s->vma - data_vma), 0,
				   bfd_section_size(abs_bfd, s)))
      {
	fprintf(stderr, "read error section %s\n", s->name);
	exit(2);
      }

  /* Put common symbols in bss.  */
  bss_len += add_com_to_bss(symbol_table, number_of_symbols, bss_len);

  if (verbose)
    printf("BSS  -> vma=0x%x len=0x%x\n", bss_vma, bss_len);

  if ((data_vma + data_len) != bss_vma) {
    if ((data_vma + data_len) > bss_vma) {
      printf("ERROR: text=0x%x + data=0x%x overlaps bss=0x%x ?\n", text_len,
	  		data_len, bss_vma);
      exit(1);
    }
    if (verbose)
      printf("WARNING: bss=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;
  }

  reloc = output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len,
			text, text_len, text_vma, data, data_len, data_vma,
			rel_bfd);

  if (reloc == NULL)
    printf("No relocations in code!\n");

  text_offs = real_address_bits(text_vma);

  /* Fill in the binflt_flat header */
  memcpy(hdr.magic,"bFLT",4);
  hdr.rev         = htonl(FLAT_VERSION);
  hdr.entry       = htonl(sizeof(hdr) + bfd_get_start_address(abs_bfd));
  hdr.data_start  = htonl(sizeof(hdr) + text_offs + text_len);
  hdr.data_end    = htonl(sizeof(hdr) + text_offs + text_len +data_len);
  hdr.bss_end     = htonl(sizeof(hdr) + text_offs + text_len +data_len+bss_len);
  hdr.stack_size  = htonl(stack); /* FIXME */
  hdr.reloc_start = htonl(sizeof(hdr) + text_offs + text_len +data_len);
  hdr.reloc_count = htonl(reloc_len);
  hdr.flags       = htonl(0
	  | (load_to_ram ? FLAT_FLAG_RAM : 0)
	  | (ktrace ? FLAT_FLAG_KTRACE : 0)
	  | (pic_with_got ? FLAT_FLAG_GOTPIC : 0)
	  | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
	  );
  hdr.build_date = htonl((unsigned long)time(NULL));
  memset(hdr.filler, 0x00, sizeof(hdr.filler));

  for (i=0; i<reloc_len; i++) reloc[i] = htonl(reloc[i]);

  if (verbose) {
    printf("SIZE: .text=0x%04x, .data=0x%04x, .bss=0x%04x",
	text_len, data_len, bss_len);
    if (reloc)
      printf(", relocs=0x%04x", reloc_len);
    printf("\n");
  }
  
  if (!ofile) {
    ofile = malloc(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);
  }

  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, "w" BINARY_FILE_OPTS))) { \
			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 (compress == 1)
  	START_COMPRESSOR;

  /* Fill in any hole at the beginning of the text segment.  */
  if (verbose)
	  printf("ZERO before text len=0x%x\n", text_offs);
  write_zeroes(text_offs, gf);

  /* Write the text segment.  */
  fwrite(text, text_len, 1, gf);

  if (compress == 2)
  	START_COMPRESSOR;

  /* Write the data segment.  */
  fwrite(data, data_len, 1, gf);

  if (reloc)
    fwrite(reloc, reloc_len * 4, 1, gf);

  if(gf_is_pipe)
    pclose(gf);
  else
  fclose(gf);

  exit(0);
}


/*
 * this __MUST__ be at the VERY end of the file - do NOT move!!
 *
 * Local Variables:
 * c-basic-offset: 4
 * tab-width: 8
 * end:
 * vi: tabstop=8 shiftwidth=4 textwidth=79 noexpandtab
 */
