📄 elf2flt.c
字号:
/* * 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) 2001, arm/arm-pic/arm-big-endian support <davidm@snapgear.com> * (c) 2001, v850 changes, Mile Bader <miles@lsi.nec.co.jp> * (c) 2001, zflat support <davidm@snapgear.com> * (c) 2001, Changes for GOT entries * (Pale Dale, pauli@lineo.com, David McCullough davidm@lineo.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>#include <fcntl.h>#include <stdlib.h>#include <sys/types.h>#include <netinet/in.h>#include <getopt.h>#include <stdarg.h>#include <bfd.h>#include <elf.h>#include "flat.h"#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"#else#error "Don't know how to support you CPU archiecture??"#endif/* * 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#ifndef O_BINARY#define O_BINARY 0#endifint 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 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, ...); voidewhere (const char *format, ...) { va_list args; va_start (args, format); vsprintf (where, format, args); va_end (args);}voideinfo (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;}intdump_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);} longget_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;} longadd_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;} unsigned long *output_relocs ( bfd *abs_bfd, asymbol **symbols, int number_of_symbols, unsigned long *n_relocs, unsigned char *text, int text_len, unsigned char *data, int data_len, bfd *rel_bfd){ unsigned long *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; 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", __FILE__, __LINE__, abs_bfd, symbols, number_of_symbols, n_relocs, text, text_len, data, data_len);#endif#if 0dump_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) { 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); if (got_size > GOT_LIMIT) { fprintf(stderr, "GOT too large: %d bytes (limit = %d bytes)\n", got_size, GOT_LIMIT); exit(1); } } 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, 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 && strcmp(".text", a->name) == 0) sectionp = text; else if (strcmp(".data", a->name) == 0) sectionp = data; 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 [%x]: flags=%x vma=%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", __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--) { int relocation_needed = 0;#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; } /* Adjust the address to account for the GOT table which wasn't * present in the relative file link. */ if (pic_with_got) q->address += got_size; /* * Fixup offset in the actual section. */ addstr[0] = 0; if ((sym_addr = get_symbol_offset((char *) sym_name, sym_section, symbols, number_of_symbols)) == -1) { sym_addr = 0; } if (use_resolved) { /* Use the address of the symbol already in the program text. */ sym_addr = *((unsigned long *) (sectionp + q->address)); } else { /* Calculate the sym address ourselves. */ sym_reloc_size = bfd_get_reloc_size(q->howto); if (sym_reloc_size != 4) { printf("ERROR: bad reloc size=%d for symbol=%s\n", sym_reloc_size, sym_name); rc = -1; continue; } 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_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 *) (sectionp + q->address))); sym_vma = bfd_section_vma(abs_bfd, sym_section); sym_addr += sym_vma + q->addend; 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 *) (sectionp + q->address))); case R_ARM_PC24: sym_vma = 0; sym_addr = (sym_addr-q->address)>>(*p)->howto->rightshift; break;#endif#ifdef TARGET_v850#ifdef R_V850_32 case R_V850_32:#endif sym_vma = bfd_section_vma(abs_bfd, sym_section); sym_addr += sym_vma + q->addend; break;#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 /* TARGET_v850 */#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -