/* * elf2flt.c: Convert ELF (or any BFD format) to FLAT binary format * * (c) 1999-2002, Greg Ungerer * 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 * (c) 2004, Nios II support, Wentao Xu * (c) 2003, H8 support, ktrace * (c) 2003-2004, MicroBlaze support, John Williams * (c) 2001-2003, arm/arm-pic/arm-big-endian support * (c) 2001, v850 changes, Mile Bader * (c) 2003, SuperH support, Paul Mundt * (c) 2001, zflat support * (c) 2001, Changes for GOT entries Paul Dale and * David McCullough * * 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 * (c) 1998, D. Jeff Dionne * (c) 1998, The Silver Hammer Group Ltd. * (c) 1996, 1997 Dionne & Associates * * 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 /* Userland pieces of the ANSI C standard I/O package */ #include /* Userland prototypes of the ANSI C std lib functions */ #include /* Allows va_list to exist in the these namespaces */ #include /* Userland prototypes of the string handling funcs */ #include #include /* Userland prototypes of the Unix std system calls */ #include /* Flag value for file handling functions */ #include #ifndef WIN32 #include /* Consts and structs defined by the internet system */ #define BINARY_FILE_OPTS #else #include #define BINARY_FILE_OPTS "b" #endif /* from $(INSTALLDIR)/include */ #include /* Main header file for the BFD library */ #if defined(TARGET_h8300) #include /* 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 /* TARGET_* ELF support for the BFD library */ #elif defined(TARGET_bfin) #include "elf/bfin.h" #else #include /* TARGET_* ELF support for the BFD library */ #endif #if defined(__MINGW32__) #include #endif /* from uClinux-x.x.x/include/linux */ #include "flat.h" /* Binary flat header description */ #ifdef TARGET_e1 #include #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; iname, 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; isection == 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; iname, "_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; isection->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 \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 \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 \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 \n"); goto DIS29_RELOCATION; case R_E1_DIS29H: DBG_E1("Handling Reloc \n"); goto DIS29_RELOCATION; case R_E1_DIS29B: DBG_E1("Handling Reloc \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 \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 \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 \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 ] [-s stack-size] " "[-o ] \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> %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 */