X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=elf2flt.c;h=7844a7c9a5247f1e10e7497f5a3a63d0c537580d;hb=23c458d73c6bccca7102d79e6ec4e31757a09236;hp=7bc4e78f258d0598db7032ebc2817d23bee1d1f9;hpb=c82eb01c2b45f580f175f6511d348a75ea41d5a7;p=uclinux-h8%2Felf2flt.git diff --git a/elf2flt.c b/elf2flt.c index 7bc4e78..7844a7c 100644 --- a/elf2flt.c +++ b/elf2flt.c @@ -6,11 +6,14 @@ * ELF format file handling. Extended relocation support for all of * text and data. * - * (c) 2001, arm/arm-pic/arm-big-endian support + * (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 - * (Pale Dale, pauli@lineo.com, David McCullough davidm@lineo.com) + * (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 @@ -22,8 +25,7 @@ * (c) 1998, Kenneth Albanowski * (c) 1998, D. Jeff Dionne * (c) 1998, The Silver Hammer Group Ltd. - * (c) 1996, 1997 Dionne & Associates - * jeff@ryeham.ee.ryerson.ca + * (c) 1996, 1997 Dionne & Associates * * This is Free Software, under the GNU Public Licence v2 or greater. * @@ -39,17 +41,31 @@ #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 */ +#else +#include +#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__) +#include "cygwin-elf.h" /* Cygwin uses a local copy */ +#elif defined(TARGET_microblaze) +#include /* TARGET_* ELF support for the BFD library */ +#else #include /* TARGET_* ELF support for the BFD library */ +#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 @@ -63,10 +79,19 @@ #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" #else -#error "Don't know how to support you CPU archiecture??" +#error "Don't know how to support your CPU architecture??" #endif +#if defined(TARGET_m68k) || defined(TARGET_h8300) /* * Define a maximum number of bytes allowed in the offset table. * We'll fail if the table is larger than this. @@ -75,6 +100,14 @@ * 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 @@ -84,6 +117,7 @@ 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. */ @@ -246,7 +280,8 @@ output_relocs ( asymbol **symbols, int number_of_symbols, unsigned long *n_relocs, - unsigned char *text, int text_len, unsigned char *data, int data_len, + unsigned char *text, int text_len, unsigned long text_vma, + unsigned char *data, int data_len, unsigned long data_vma, bfd *rel_bfd) { unsigned long *flat_relocs; @@ -261,12 +296,13 @@ output_relocs ( 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=%x,number_of_symbols=%d" - "n_relocs=%x,text=%x,text_len=%d,data=%x,data_len=%d)\n", + 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 @@ -294,18 +330,20 @@ dump_symbols(symbols, number_of_symbols); 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 [%x]: flags=%x vma=%x\n", a->name, a, + 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)) @@ -321,10 +359,10 @@ dump_symbols(symbols, number_of_symbols); * Only relocate things in the data sections if we are PIC/GOT. * otherwise do text as well */ - if (!pic_with_got && strcmp(".text", a->name) == 0) - sectionp = text; - else if (strcmp(".data", a->name) == 0) - sectionp = data; + 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; @@ -338,14 +376,14 @@ dump_symbols(symbols, number_of_symbols); if (r == NULL) continue; if (verbose) - printf(" RELOCS: %s [%x]: flags=%x vma=%x\n", r->name, r, + 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=%x\n", + printf("%s(%d): no relocation entries section=0x%x\n", __FILE__, __LINE__, r->name); continue; } @@ -360,8 +398,22 @@ dump_symbols(symbols, number_of_symbols); 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 @@ -433,30 +485,149 @@ dump_symbols(symbols, number_of_symbols); if (pic_with_got) q->address += got_size; + /* 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. */ - sym_addr = *((unsigned long *) - (sectionp + q->address)); - relocation_needed = 1; + 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_v850_reloc_err; + 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_v850_reloc_err; + + case R_V850_HI16: + bad_v850_reloc_err: + printf("ERROR: reloc type %s unsupported in this context\n", + q->howto->name); + bad_relocs++; + break; +#endif /* TARGET_V850 */ + + 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?). */ + 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; + } } else { /* Calculate the sym address ourselves. */ sym_reloc_size = bfd_get_reloc_size(q->howto); + +#if !defined(TARGET_h8300) && !defined(TARGET_e1) if (sym_reloc_size != 4) { - printf("ERROR: bad reloc size=%d for symbol=%s\n", - sym_reloc_size, sym_name); + 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) { @@ -484,10 +655,14 @@ dump_symbols(symbols, number_of_symbols); sym_vma, (*(q->sym_ptr_ptr))->value, q->address, sym_addr, (*p)->howto->rightshift, - *((unsigned long *) (sectionp + q->address))); + *(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, @@ -497,7 +672,7 @@ dump_symbols(symbols, number_of_symbols); sym_vma, (*(q->sym_ptr_ptr))->value, q->address, sym_addr, (*p)->howto->rightshift, - *((unsigned long *) (sectionp + q->address))); + *(unsigned long *)r_mem); case R_ARM_PC24: sym_vma = 0; sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift; @@ -524,6 +699,146 @@ dump_symbols(symbols, number_of_symbols); #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(unsigned long)); + 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_sparc case R_SPARC_32: case R_SPARC_UA32: @@ -539,14 +854,20 @@ dump_symbols(symbols, number_of_symbols); case R_SPARC_WDISP30: sym_addr = (((*(q->sym_ptr_ptr))->value- q->address) >> 2) & 0x3fffffff; - sym_addr |= (ntohl(*((unsigned long *) (sectionp + q->address))) & 0xc0000000); + 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 *) (sectionp + q->address))) & 0xffc00000); + sym_addr |= ( + htonl(*(unsigned long *)r_mem) + & 0xffc00000 + ); break; case R_SPARC_LO10: relocation_needed = 1; @@ -554,13 +875,204 @@ dump_symbols(symbols, number_of_symbols); sym_vma = bfd_section_vma(abs_bfd, sym_section); sym_addr += sym_vma + q->addend; sym_addr &= 0x000003ff; - sym_addr |= (htonl(*((unsigned long *) (sectionp + q->address))) & 0xfffffc00); + sym_addr |= ( + htonl(*(unsigned long *)r_mem) + & 0xfffffc00 + ); break; #endif /* TARGET_sparc */ +#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; } } @@ -570,8 +1082,8 @@ dump_symbols(symbols, number_of_symbols); /* - * for full elf relocation we have to write back the start_code - * relative value to use. + * for full elf relocation we have to write back the + * start_code relative value to use. */ if (!pic_with_got) { #if defined(TARGET_arm) @@ -597,7 +1109,7 @@ dump_symbols(symbols, number_of_symbols); i3 = 0; } - tmp.l = *((unsigned long *) (sectionp + q->address)); + tmp.l = *(unsigned long *)r_mem; hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16); if (((*p)->howto->type != R_ARM_PC24) && ((*p)->howto->type != R_ARM_PLT32)) @@ -612,18 +1124,71 @@ dump_symbols(symbols, number_of_symbols); ((*p)->howto->type != R_ARM_PLT32)) tmp.c[i3] = (hl >> 24) & 0xff; if ((*p)->howto->type == R_ARM_ABS32) - *((unsigned long *) (sectionp + q->address)) = htonl(hl); + *(unsigned long *)r_mem = htonl(hl); else - *((unsigned long *) (sectionp + q->address)) = tmp.l; -#else /* ! TARGET_arm */ - *((unsigned long *) (sectionp + q->address)) = htonl(sym_addr); -#endif + *(unsigned long *)r_mem = tmp.l; + +#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 */ + 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 */ } if (verbose) - printf(" RELOC[%d]: offset=%x symbol=%s%s " + printf(" RELOC[%d]: offset=0x%x symbol=%s%s " "section=%s size=%d " - "fixup=%x (reloc=0x%x)\n", flat_reloc_count, + "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); @@ -634,19 +1199,45 @@ dump_symbols(symbols, number_of_symbols); if (relocation_needed) { flat_relocs = realloc(flat_relocs, (flat_reloc_count + 1) * sizeof(unsigned long)); +#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++; relocation_needed = 0; pflags = 0; } #if 0 -printf("%s(%d): symbol name=%s address=%x section=%s -> RELOC=%x\n", +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 @@ -654,11 +1245,16 @@ printf("%s(%d): symbol name=%s address=%x section=%s -> RELOC=%x\n", } } + if (bad_relocs) { + printf("%d bad relocs\n", bad_relocs); + exit(1); + } + if (rc < 0) - return(NULL); + return(0); - *n_relocs = flat_reloc_count; - return flat_relocs; + *n_relocs = flat_reloc_count; + return flat_relocs; } @@ -696,7 +1292,7 @@ output_offset_table(int fd, char *ename, bfd *abfd, asymbol **symbol_table, long asection *text_section = bfd_get_section_by_name (abfd, ".text"); - if (!(ef = fopen(ename, "r"))) { + if (!(ef = fopen(ename, "rb"))) { fprintf (stderr,"Can't open %s\n",ename); exit(1); } @@ -755,11 +1351,13 @@ static void usage(void) "[-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", @@ -769,13 +1367,30 @@ static void usage(void) } +/* 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. */ + bzero(zeroes, 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; + char *ofile=NULL, *pfile=NULL, *abs_file = NULL, *rel_file = NULL; char *fname = NULL; int opt; int i; @@ -787,14 +1402,16 @@ int main(int argc, char *argv[]) asymbol **symbol_table; long number_of_symbols; - unsigned long data_len; - unsigned long bss_len; - unsigned long text_len; + unsigned long data_len = 0; + unsigned long bss_len = 0; + unsigned long text_len = 0; unsigned long reloc_len; - unsigned long data_vma; - unsigned long bss_vma; - unsigned long text_vma; + unsigned long data_vma = ~0; + unsigned long bss_vma = ~0; + unsigned long text_vma = ~0; + + unsigned long text_offs; void *text; void *data; @@ -802,6 +1419,7 @@ int main(int argc, char *argv[]) struct flat_hdr hdr; + int gf_is_pipe = 0; program = argv[0]; progname = argv[0]; @@ -809,9 +1427,13 @@ int main(int argc, char *argv[]) if (argc < 2) usage(); +#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, "avzdrp:s:o:")) != -1) { + while ((opt = getopt(argc, argv, "avzdrkp:s:o:R:")) != -1) { switch (opt) { case 'v': verbose++; @@ -819,6 +1441,9 @@ int main(int argc, char *argv[]) case 'r': load_to_ram++; break; + case 'k': + ktrace++; + break; case 'z': compress = 1; break; @@ -837,6 +1462,9 @@ int main(int argc, char *argv[]) case 's': stack = atoi(optarg); break; + case 'R': + rel_file = optarg; + break; default: fprintf(stderr, "%s Unknown option\n", argv[0]); usage(); @@ -853,8 +1481,17 @@ int main(int argc, char *argv[]) filename = fname = argv[argc-1]; - if (!(rel_bfd = bfd_openr(fname, 0))) { - fprintf(stderr, "Can't open %s\n", fname); + 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); } @@ -863,11 +1500,11 @@ int main(int argc, char *argv[]) exit(2); } - if (pfile) { - pic_with_got = 1; - - if (!(abs_bfd = bfd_openr(pfile, 0))) { - fprintf(stderr, "Can't open %s\n", pfile); + 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); } @@ -875,12 +1512,10 @@ int main(int argc, char *argv[]) fprintf(stderr, "File is not an object file\n"); exit(2); } - } else { - abs_bfd = rel_bfd; /* one file does all */ } if (! (bfd_get_file_flags(rel_bfd) & HAS_RELOC)) { - fprintf (stderr, "%s: Input file contains no relocation info\n", fname); + fprintf (stderr, "%s: Input file contains no relocation info\n", rel_file); exit (2); } @@ -895,100 +1530,129 @@ int main(int argc, char *argv[]) symbol_table = get_symbols(abs_bfd, &number_of_symbols); - s = bfd_get_section_by_name (abs_bfd, ".text"); - text_vma = s->vma; - text_len = s->_raw_size; - text = malloc(text_len); - - if (verbose) { - printf("TEXT -> vma=%x len=%x\n", text_vma, text_len); - printf(" lma=%x clen=%x oo=%x ap=%x fp=%x\n", - s->lma, s->_cooked_size, s->output_offset, - s->alignment_power, s->filepos); + /* 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 (bfd_get_section_contents(abs_bfd, - s, - text, - 0, - s->_raw_size) == false) { - fprintf(stderr, "read error section %s\n", s->name); - exit(2); + if (text_len == 0) { + fprintf (stderr, "%s: no .text section", abs_file); + exit (2); } - s = bfd_get_section_by_name (abs_bfd, ".data"); - data_vma = s->vma; - data_len = s->_raw_size; - data = malloc(data_len); + text = malloc(text_len); - if (verbose) { - printf("DATA -> vma=%x len=%x\n", data_vma, data_len); - printf(" lma=%x clen=%x oo=%x ap=%x fp=%x\n", - s->lma, s->_cooked_size, s->output_offset, - s->alignment_power, s->filepos); + 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=%x overlaps data=%x ?\n", 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=%x does not directly follow text=%x\n", + printf("WARNING: data=0x%x does not directly follow text=0x%x\n", data_vma, text_len); text_len = data_vma - text_vma; } - if (bfd_get_section_contents(abs_bfd, - s, - data, - 0, - s->_raw_size) == false) { - fprintf(stderr, "read error section %s\n", s->name); - exit(2); - } + /* 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); + } - s = bfd_get_section_by_name (abs_bfd, ".bss"); - bss_len = s->_raw_size; - bss_vma = s->vma; + /* Put common symbols in bss. */ bss_len += add_com_to_bss(symbol_table, number_of_symbols, bss_len); - if (verbose) { - printf("BSS -> vma=%x len=%x\n", bss_vma, bss_len); - printf(" lma=%x clen=%x oo=%x ap=%x fp=%x\n", - s->lma, s->_cooked_size, s->output_offset, - s->alignment_power, s->filepos); - } + if (verbose) + printf("BSS -> vma=0x%x len=0x%x\n", bss_vma, bss_len); - if ((text_vma + text_len + data_len) != bss_vma) { - if ((text_vma + text_len + data_len) > bss_vma) { - printf("ERROR: text=%x + data=%x overlaps bss=%x ?\n", text_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=%x does not directly follow text=%x + data=%x(%x)\n", + 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; + data_len = bss_vma - data_vma; } - reloc = (unsigned long *) output_relocs (abs_bfd, symbol_table, - number_of_symbols, &reloc_len, text, text_len, data, data_len, rel_bfd); + reloc = (unsigned long *) + output_relocs(abs_bfd, symbol_table, number_of_symbols, &reloc_len, + text, text_len, text_vma, data, data_len, data_vma, rel_bfd); 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(16 * 4 + bfd_get_start_address(abs_bfd)); - hdr.data_start = htonl(16 * 4 + text_len); - hdr.data_end = htonl(16 * 4 + text_len + data_len); - hdr.bss_end = htonl(16 * 4 + text_len + data_len + bss_len); + hdr.data_start = htonl(16 * 4 + text_offs + text_len); + hdr.data_end = htonl(16 * 4 + text_offs + text_len + data_len); + hdr.bss_end = htonl(16 * 4 + text_offs + text_len + data_len + bss_len); hdr.stack_size = htonl(stack); /* FIXME */ - hdr.reloc_start = htonl(16 * 4 + text_len + data_len); + hdr.reloc_start = htonl(16 * 4 + 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) ); @@ -1025,32 +1689,48 @@ int main(int argc, char *argv[]) sprintf(cmd, "gzip -f -9 >> %s", ofile); #define START_COMPRESSOR do { \ - if (gf) fclose(gf); \ - if (!(gf = popen(cmd, "w"))) { \ + if (gf) \ + if (gf_is_pipe) \ + pclose(gf); \ + else \ + fclose(gf); \ + if (!(gf = popen(cmd, "wb"))) { \ fprintf(stderr, "Can't run cmd %s\n", cmd); \ exit(4); \ } \ + gf_is_pipe = 1; \ } while (0) - gf = fopen(ofile, "a"); + gf = fopen(ofile, "ab"); /* Add 'b' to support non-posix (ie windows) */ if (!gf) { - fprintf(stderr, "Can't opne file %s for writing\n", ofile); \ + fprintf(stderr, "Can't open file %s for writing\n", ofile); \ exit(4); } if (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); + fwrite(reloc, reloc_len * 4, 1, gf); + + if(gf_is_pipe) + pclose(gf); + else fclose(gf); exit(0); } -