* 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>
#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
#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
-#ifdef TARGET_m68k
+#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.
for (i=0; i<number_of_symbols; i++) {
if (symbol_table[i]->section == sec) {
if (!strcmp(symbol_table[i]->name, name)) {
- return symbol_table[i]->value;
+ return symbol_table[i]->value;
}
}
}
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;
return comsize;
}
+#ifdef TARGET_bfin
+/* FUNCTION : weak_und_symbol
+ ABSTRACT : return true if symbol is weak and undefined.
+*/
+static int
+weak_und_symbol(const char *reloc_section_name,
+ struct bfd_symbol *symbol)
+{
+ if (!(strstr (reloc_section_name, "text")
+ || strstr (reloc_section_name, "data")
+ || strstr (reloc_section_name, "bss"))) {
+ if (symbol->flags & BSF_WEAK) {
+#ifdef DEBUG_BFIN
+ fprintf(stderr, "found weak undefined symbol %s\n", symbol->name);
+#endif
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int
+bfin_set_reloc (uint32_t *reloc,
+ const char *reloc_section_name,
+ const char *sym_name,
+ struct bfd_symbol *symbol,
+ int sp, int hilo, int32_t offset)
+{
+ unsigned int type;
+ uint32_t val;
+
+ if (strstr (reloc_section_name, "text"))
+ type = FLAT_RELOC_TYPE_TEXT;
+ else if (strstr (reloc_section_name, "data"))
+ type = FLAT_RELOC_TYPE_DATA;
+ else if (strstr (reloc_section_name, "bss"))
+ type = FLAT_RELOC_TYPE_BSS;
+ else if (strstr (reloc_section_name, "stack"))
+ type = FLAT_RELOC_TYPE_STACK;
+ else if (symbol->flags & BSF_WEAK){
+ /* weak symbol support ... if a weak symbol is undefined at the
+ end of a final link, it should return 0 rather than error
+ We will assume text section for the moment.
+ */
+ type = FLAT_RELOC_TYPE_TEXT;
+ } else if (strstr (reloc_section_name, "*ABS*")){
+ /* (A data section initialization of something in the shared libc's text section
+ does not resolve - i.e. a global pointer to function initialized with
+ a libc function).
+ The text section here is appropriate as the section information
+ of the shared library is lost. The loader will do some calcs.
+ */
+ type = FLAT_RELOC_TYPE_TEXT;
+ } else {
+ printf ("Unknown Type - relocation for %s in bad section - %s\n", sym_name, reloc_section_name);
+ return 1;
+ }
+
+ val = (offset & ((1 << 26) - 1)) << 6;
+ val |= (sp & (1 << 3) - 1) << 3;
+ val |= (hilo & 1) << 2;
+ val |= (type & (1 << 2) - 1);
+ *reloc = val;
+ return 0;
+}
+#endif
-unsigned long *
+uint32_t *
output_relocs (
bfd *abs_bfd,
asymbol **symbols,
unsigned char *data, int data_len, unsigned long data_vma,
bfd *rel_bfd)
{
- unsigned long *flat_relocs;
+ uint32_t *flat_relocs;
asection *a, *sym_section, *r;
arelent **relpp, **p, *q;
const char *sym_name, *section_name;
continue;
}
#endif /* TARGET_microblaze */
-
+
#ifdef TARGET_v850
/* Skip this relocation entirely if possible (we
do this early, before doing any other
rc = -1;
continue;
}
+#ifndef TARGET_bfin
/* Adjust the address to account for the GOT table which wasn't
* present in the relative file link.
*/
- if (pic_with_got)
+ if (pic_with_got && !use_resolved)
q->address += got_size;
-
+#endif
+
/* A pointer to what's being relocated, used often
below. */
r_mem = sectionp + q->address;
* Fixup offset in the actual section.
*/
addstr[0] = 0;
+#ifndef TARGET_e1
if ((sym_addr = get_symbol_offset((char *) sym_name,
sym_section, symbols, number_of_symbols)) == -1) {
sym_addr = 0;
}
-
+#else
+ sym_addr = (*(q->sym_ptr_ptr))->value;
+#endif
if (use_resolved) {
/* Use the address of the symbol already in
the program text. How this is handled may
break;
#endif /* TARGET_V850 */
+#if defined(TARGET_arm)
+ case R_ARM_ABS32:
+ relocation_needed = 1;
+ break;
+ case R_ARM_REL32:
+ case R_ARM_THM_PC22:
+ relocation_needed = 0;
+ break;
+ default:
+ printf("ERROR: reloc type %s unsupported in this context\n",
+ q->howto->name);
+ bad_relocs++;
+ break;
+#else
default:
/* The default is to assume that the
relocation is relative and has
+ (r_mem[2] << 16)
+ (r_mem[3] << 24);
relocation_needed = 1;
+#endif
}
} else {
/* Calculate the sym address ourselves. */
sym_reloc_size = bfd_get_reloc_size(q->howto);
-#ifndef TARGET_h8300
+#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);
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;
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;
/* create a new reloc entry */
flat_relocs = realloc(flat_relocs,
- (flat_reloc_count + 1) * sizeof(unsigned long));
+ (flat_reloc_count + 1) * sizeof(uint32_t));
flat_relocs[flat_reloc_count] = pflags | (section_vma + q->address);
flat_reloc_count++;
relocation_needed = 0;
/* grab any offset from the text */
offset = (p[0]<<24) + (p[1] << 16) + (p[2] << 8) + (p[3]);
- //sym_addr = (*(q->sym_ptr_ptr))->value;
sym_vma = bfd_section_vma(abs_bfd, sym_section);
- sym_addr += offset + sym_vma + q->addend;
+ /* 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;
}
#endif /* TARGET_microblaze */
+#ifdef TARGET_nios2
+#define htoniosl(x) (x)
+#define niostohl(x) (x)
+ switch ((*p)->howto->type)
+ {
+ case R_NIOS2_BFD_RELOC_32:
+ relocation_needed = 1;
+ pflags = (FLAT_NIOS2_R_32 << 28);
+ sym_vma = bfd_section_vma(abs_bfd, sym_section);
+ sym_addr += sym_vma + q->addend;
+ /* modify target, in target order */
+ *(unsigned long *)r_mem = htoniosl(sym_addr);
+ break;
+ case R_NIOS2_CALL26:
+ {
+ unsigned long exist_val;
+ relocation_needed = 1;
+ pflags = (FLAT_NIOS2_R_CALL26 << 28);
+ sym_vma = bfd_section_vma(abs_bfd, sym_section);
+ sym_addr += sym_vma + q->addend;
+
+ /* modify target, in target order */
+ // exist_val = niostohl(*(unsigned long *)r_mem);
+ exist_val = ((sym_addr >> 2) << 6);
+ *(unsigned long *)r_mem = htoniosl(exist_val);
+ break;
+ }
+ case R_NIOS2_HIADJ16:
+ case R_NIOS2_HI16:
+ {
+ unsigned long exist_val;
+ int r2_type;
+ /* handle the adjacent HI/LO pairs */
+ if (relcount == 0)
+ r2_type = R_NIOS2_NONE;
+ else
+ r2_type = p[1]->howto->type;
+ if ((r2_type == R_NIOS2_LO16)
+ && (p[0]->sym_ptr_ptr == p[1]->sym_ptr_ptr)
+ && (p[0]->addend == p[1]->addend))
+ {
+ unsigned char * r2_mem = sectionp + p[1]->address;
+ if (p[1]->address - q->address!=4)
+ printf("Err: HI/LO not adjacent %d\n", p[1]->address - q->address);
+ relocation_needed = 1;
+ pflags = (q->howto->type == R_NIOS2_HIADJ16)
+ ? FLAT_NIOS2_R_HIADJ_LO : FLAT_NIOS2_R_HI_LO;
+ pflags <<= 28;
+
+ sym_vma = bfd_section_vma(abs_bfd, sym_section);
+ sym_addr += sym_vma + q->addend;
+
+ /* modify high 16 bits, in target order */
+ exist_val = niostohl(*(unsigned long *)r_mem);
+ exist_val = ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+ if (q->howto->type == R_NIOS2_HIADJ16)
+ exist_val |= ((((sym_addr >> 16) + ((sym_addr >> 15) & 1)) & 0xFFFF) << 6);
+ else
+ exist_val |= (((sym_addr >> 16) & 0xFFFF) << 6);
+ *(unsigned long *)r_mem = htoniosl(exist_val);
+
+ /* modify low 16 bits, in target order */
+ exist_val = niostohl(*(unsigned long *)r2_mem);
+ exist_val = ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+ exist_val |= ((sym_addr & 0xFFFF) << 6);
+ *(unsigned long *)r2_mem = htoniosl(exist_val);
+
+ } else
+ goto NIOS2_RELOC_ERR;
+ }
+ break;
+
+ case R_NIOS2_GPREL:
+ {
+ unsigned long exist_val, temp;
+ //long gp = get_symbol_offset("_gp", sym_section, symbols, number_of_symbols);
+ long gp = get_gp_value(symbols, number_of_symbols);
+ if (gp == -1) {
+ printf("Err: unresolved symbol _gp when relocating %s\n", sym_name);
+ goto NIOS2_RELOC_ERR;
+ }
+ /* _gp holds a absolute value, otherwise the ld cannot generate correct code */
+ sym_vma = bfd_section_vma(abs_bfd, sym_section);
+ //printf("sym=%x, %d, _gp=%x, %d\n", sym_addr+sym_vma, sym_addr+sym_vma, gp, gp);
+ sym_addr += sym_vma + q->addend;
+ sym_addr -= gp;
+ //printf("sym - _gp=%x, %d\n", sym_addr, sym_addr);
+ /* modify the target, in target order (little_endian) */
+ exist_val = niostohl(*(unsigned long *)r_mem);
+ temp = ((exist_val >> 6) & 0x3ff0000) | (sym_addr & 0xffff);
+ temp <<= 6;
+ temp |= (exist_val & 0x3f);
+ *(unsigned long *)r_mem = htoniosl(temp);
+ if (verbose)
+ printf("omit: offset=0x%x symbol=%s%s "
+ "section=%s size=%d "
+ "fixup=0x%x (reloc=0x%x) GPREL\n",
+ q->address, sym_name, addstr,
+ section_name, sym_reloc_size,
+ sym_addr, section_vma + q->address);
+ continue;
+ }
+ case R_NIOS2_PCREL16:
+ {
+ unsigned long exist_val;
+ sym_vma = 0;
+ sym_addr += sym_vma + q->addend;
+ sym_addr -= (q->address + 4);
+ /* modify the target, in target order (little_endian) */
+ exist_val = niostohl(*(unsigned long *)r_mem);
+ exist_val = ((exist_val >> 22) << 22) | (exist_val & 0x3f);
+ exist_val |= ((sym_addr & 0xFFFF) << 6);
+ *(unsigned long *)r_mem = htoniosl(exist_val);
+ if (verbose)
+ printf("omit: offset=0x%x symbol=%s%s "
+ "section=%s size=%d "
+ "fixup=0x%x (reloc=0x%x) PCREL\n",
+ q->address, sym_name, addstr,
+ section_name, sym_reloc_size,
+ sym_addr, section_vma + q->address);
+ continue;
+ }
+
+ case R_NIOS2_LO16:
+ /* check if this is actually the 2nd half of a pair */
+ if ((p > relpp)
+ && ((p[-1]->howto->type == R_NIOS2_HIADJ16)
+ || (p[-1]->howto->type == R_NIOS2_HI16))
+ && (p[-1]->sym_ptr_ptr == p[0]->sym_ptr_ptr)
+ && (p[-1]->addend == p[0]->addend)) {
+ if (verbose)
+ printf("omit: offset=0x%x symbol=%s%s "
+ "section=%s size=%d LO16\n",
+ q->address, sym_name, addstr,
+ section_name, sym_reloc_size);
+ continue;
+ }
+
+ /* error, fall through */
+
+ case R_NIOS2_S16:
+ case R_NIOS2_U16:
+ case R_NIOS2_CACHE_OPX:
+ case R_NIOS2_IMM5:
+ case R_NIOS2_IMM6:
+ case R_NIOS2_IMM8:
+ case R_NIOS2_BFD_RELOC_16:
+ case R_NIOS2_BFD_RELOC_8:
+ case R_NIOS2_GNU_VTINHERIT:
+ case R_NIOS2_GNU_VTENTRY:
+ case R_NIOS2_UJMP:
+ case R_NIOS2_CJMP:
+ case R_NIOS2_CALLR:
+NIOS2_RELOC_ERR:
+ printf("Err: unexpected reloc type %s(%d)\n", q->howto->name, q->howto->type);
+ bad_relocs++;
+ continue;
+ }
+#endif /* TARGET_nios2 */
+
#ifdef TARGET_sparc
case R_SPARC_32:
case R_SPARC_UA32:
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;
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);
tmp.l = *(unsigned long *)r_mem;
hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
- if (((*p)->howto->type != R_ARM_PC24) &&
- ((*p)->howto->type != R_ARM_PLT32))
+ if (use_resolved ||
+ (((*p)->howto->type != R_ARM_PC24) &&
+ ((*p)->howto->type != R_ARM_PLT32)))
hl |= (tmp.c[i3] << 24);
else if (tmp.c[i2] & 0x80)
hl |= 0xff000000; /* sign extend */
- hl += sym_addr;
+ if (!use_resolved)
+ hl += sym_addr;
tmp.c[i0] = hl & 0xff;
tmp.c[i1] = (hl >> 8) & 0xff;
tmp.c[i2] = (hl >> 16) & 0xff;
- if (((*p)->howto->type != R_ARM_PC24) &&
- ((*p)->howto->type != R_ARM_PLT32))
+ if (use_resolved ||
+ (((*p)->howto->type != R_ARM_PC24) &&
+ ((*p)->howto->type != R_ARM_PLT32)))
tmp.c[i3] = (hl >> 24) & 0xff;
if ((*p)->howto->type == R_ARM_ABS32)
*(unsigned long *)r_mem = htonl(hl);
else
*(unsigned long *)r_mem = tmp.l;
-#else /* ! TARGET_arm */
+#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
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
#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 "
* Create relocation entry (PC relative doesn't need this).
*/
if (relocation_needed) {
+#ifndef TARGET_bfin
flat_relocs = realloc(flat_relocs,
- (flat_reloc_count + 1) * sizeof(unsigned long));
+ (flat_reloc_count + 1) * sizeof(uint32_t));
+#ifndef TARGET_e1
flat_relocs[flat_reloc_count] = pflags |
(section_vma + q->address);
if (verbose)
printf("reloc[%d] = 0x%x\n", flat_reloc_count,
section_vma + q->address);
+#else
+ switch ((*p)->howto->type) {
+ case R_E1_CONST31:
+ case R_E1_CONST31_PCREL:
+ case R_E1_DIS29W_PCREL:
+ case R_E1_DIS29W:
+ case R_E1_DIS29H:
+ case R_E1_DIS29B:
+ case R_E1_IMM32_PCREL:
+ case R_E1_IMM32:
+ flat_relocs[flat_reloc_count] = pflags |
+ (section_vma + q->address + OPCODE_SIZE);
+ if (verbose)
+ printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
+ flat_relocs[flat_reloc_count] );
+ break;
+ case R_E1_WORD:
+ flat_relocs[flat_reloc_count] = pflags |
+ (section_vma + q->address);
+ if (verbose)
+ printf("RELOCATION TABLE : reloc[%d] = [0x%x]\n", flat_reloc_count,
+ flat_relocs[flat_reloc_count] );
+ break;
+ }
+#endif
flat_reloc_count++;
+#endif
relocation_needed = 0;
pflags = 0;
}
-#if 0
-/* shared lib symbols stuff */
-
-long
-get_symbol(char *name, asection *sec, asymbol **symbol_table, long number_of_symbols)
-{
- long i;
- for (i=0; i<number_of_symbols; i++) {
- if (symbol_table[i]->section == sec) {
- if (!strcmp(symbol_table[i]->name, name)) {
- return symbol_table[i]->value;
- }
- }
- }
- return -1;
-}
-
-int
-output_offset_table(int fd, char *ename, bfd *abfd, asymbol **symbol_table, long number_of_symbols)
-{
- long i;
- FILE *ef;
- char buf[80];
- char libname[80];
- long etext_addr;
- long sym_addr;
-
- int foobar = 0;
- int count = 0;
- signed short *tab = malloc(32768); /* we don't know how many yet*/
-
- asection *text_section = bfd_get_section_by_name (abfd, ".text");
-
- if (!(ef = fopen(ename, "r"))) {
- fprintf (stderr,"Can't open %s\n",ename);
- exit(1);
- }
-
- fgets(libname, 80, ef);
-
- if (number_of_symbols < 0) {
- fprintf (stderr,"Corrupt symbol table!\n");
- exit(1);
- }
-
- if ((etext_addr = get_symbol("etext",
- text_section,
- symbol_table,
- number_of_symbols)) == -1) {
- fprintf (stderr,"Can't find the symbol etext\n");
- exit(1);
- }
-
- fgets(buf, 80, ef);
- while (!feof(ef)) {
- buf[strlen(buf)-1] = 0; /* Arrrgh! linefeeds */
-
- if ((sym_addr = get_symbol(buf,
- text_section,
- symbol_table,
- number_of_symbols)) == -1) {
- fprintf (stderr,"Can't find the symbol %s\n",buf);
- foobar++;
- } else {
- tab[++count] = htons(sym_addr - etext_addr);
- }
- fgets(buf, 80, ef);
- }
-
- fclose(ef);
-
- if (foobar) {
- fprintf (stderr,"*** %d symbols not found\n",foobar);
- exit(10);
- }
-
- strcpy((char *)&tab[++count],libname);
- tab[0] = htons(count * 2);
- write(fd, tab, count * 2 + strlen(libname) + 2);
- return 0;
-}
-#endif
-
-
static char * program;
static void usage(void)
char cmd[1024];
FILE *gf = NULL;
-
asymbol **symbol_table;
long number_of_symbols;
void *text;
void *data;
- unsigned long *reloc;
+ uint32_t *reloc;
struct flat_hdr hdr;
+ int gf_is_pipe = 0;
program = argv[0];
progname = argv[0];
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) {
/* 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;
} 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) {
if (s->flags & SEC_CODE)
if (!bfd_get_section_contents(abs_bfd, s,
text + (s->vma - text_vma), 0,
- s->_raw_size))
+ bfd_section_size(abs_bfd, s)))
{
fprintf(stderr, "read error section %s\n", s->name);
exit(2);
if (s->flags & SEC_DATA)
if (!bfd_get_section_contents(abs_bfd, s,
data + (s->vma - data_vma), 0,
- s->_raw_size))
+ bfd_section_size(abs_bfd, s)))
{
fprintf(stderr, "read error section %s\n", s->name);
exit(2);
data_len = bss_vma - data_vma;
}
- reloc = (unsigned long *)
- output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len,
- text, text_len, text_vma, data, data_len, data_vma, rel_bfd);
+ reloc = output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len,
+ text, text_len, text_vma, data, data_len, data_vma,
+ rel_bfd);
if (reloc == NULL)
printf("No relocations in code!\n");
/* 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_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.entry = htonl(sizeof(hdr) + bfd_get_start_address(abs_bfd));
+ hdr.data_start = htonl(sizeof(hdr) + text_offs + text_len);
+ hdr.data_end = htonl(sizeof(hdr) + text_offs + text_len +data_len);
+ hdr.bss_end = htonl(sizeof(hdr) + text_offs + text_len +data_len+bss_len);
hdr.stack_size = htonl(stack); /* FIXME */
- hdr.reloc_start = htonl(16 * 4 + text_offs + text_len + data_len);
+ hdr.reloc_start = htonl(sizeof(hdr) + text_offs + text_len +data_len);
hdr.reloc_count = htonl(reloc_len);
hdr.flags = htonl(0
| (load_to_ram ? FLAT_FLAG_RAM : 0)
sprintf(cmd, "gzip -f -9 >> %s", ofile);
#define START_COMPRESSOR do { \
- if (gf) fclose(gf); \
- if (!(gf = popen(cmd, "w"))) { \
+ if (gf) \
+ if (gf_is_pipe) \
+ pclose(gf); \
+ else \
+ fclose(gf); \
+ if (!(gf = popen(cmd, "w" BINARY_FILE_OPTS))) { \
fprintf(stderr, "Can't run cmd %s\n", cmd); \
exit(4); \
} \
+ gf_is_pipe = 1; \
} while (0)
- gf = fopen(ofile, "a");
+ gf = fopen(ofile, "ab"); /* Add 'b' to support non-posix (ie windows) */
if (!gf) {
- fprintf(stderr, "Can't opne file %s for writing\n", ofile); \
+ fprintf(stderr, "Can't open file %s for writing\n", ofile); \
exit(4);
}
if (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
+ */