| /* |
| * 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 |
| */ |