diff options
Diffstat (limited to 'package/elf2flt/src/elf2flt.c')
-rw-r--r-- | package/elf2flt/src/elf2flt.c | 2152 |
1 files changed, 2152 insertions, 0 deletions
diff --git a/package/elf2flt/src/elf2flt.c b/package/elf2flt/src/elf2flt.c new file mode 100644 index 000000000..65a116c6c --- /dev/null +++ b/package/elf2flt/src/elf2flt.c @@ -0,0 +1,2152 @@ +/* + * 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 + */ |