diff options
author | Kim Knuttila <krk@cygnus> | 1995-11-13 12:54:05 +0000 |
---|---|---|
committer | Kim Knuttila <krk@cygnus> | 1995-11-13 12:54:05 +0000 |
commit | 93b6a3f8e27ed916a82055a21055df496e9dde44 (patch) | |
tree | 94706e27201150c5fc20f3505e89009bba2d9788 /bfd/coff-ppc.c | |
parent | 863fe9d0596bd133c01cd998f33d1b58c661594b (diff) | |
download | gdb-93b6a3f8e27ed916a82055a21055df496e9dde44.zip gdb-93b6a3f8e27ed916a82055a21055df496e9dde44.tar.gz gdb-93b6a3f8e27ed916a82055a21055df496e9dde44.tar.bz2 |
Implemented IMGLUE reloc + dumping
Diffstat (limited to 'bfd/coff-ppc.c')
-rw-r--r-- | bfd/coff-ppc.c | 417 |
1 files changed, 321 insertions, 96 deletions
diff --git a/bfd/coff-ppc.c b/bfd/coff-ppc.c index ae87505..444f211 100644 --- a/bfd/coff-ppc.c +++ b/bfd/coff-ppc.c @@ -26,6 +26,9 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Current State: - objdump works - relocs generated by gas + - ld will link files, but they do not run. + - dlltool will not produce correct output in some .reloc cases, and will + not produce the right glue code for dll function calls. */ @@ -47,6 +50,126 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "libcoff.h" +/* In order not to add an int to every hash table item for every coff + linker, we define our own hash table, derived from the coff one */ + +/* PE linker hash table entries. */ + +struct ppc_coff_link_hash_entry +{ + struct coff_link_hash_entry root; /* First entry, as required */ + + /* As we wonder around the relocs, we'll keep the assigned toc_offset + here */ + bfd_vma toc_offset; /* Our addition, as required */ + int symbol_is_glue; + unsigned long int glue_insn; + char eye_catcher[8]; +}; + +/* Need a 7 char string for an eye catcher */ +#define EYE "krkjunk" + +#define CHECK_EYE(addr) \ + if (strcmp(addr, EYE) != 0) \ + { \ + fprintf(stderr,\ + "File %s, line %d, Hash check failure, bad eye %8s\n", \ + __FILE__, __LINE__, addr); \ + abort(); \ + } + +/* PE linker hash table. */ + +struct ppc_coff_link_hash_table +{ + struct coff_link_hash_table root; /* First entry, as required */ +}; + +static struct bfd_hash_entry *ppc_coff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Routine to create an entry in the link hash table. */ + +static struct bfd_hash_entry * +ppc_coff_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ppc_coff_link_hash_entry *ret = + (struct ppc_coff_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct ppc_coff_link_hash_entry *) NULL) + ret = (struct ppc_coff_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct ppc_coff_link_hash_entry)); + + if (ret == (struct ppc_coff_link_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ppc_coff_link_hash_entry *) + _bfd_coff_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->toc_offset = 1; + ret->symbol_is_glue = 0; + ret->glue_insn = 0; + strcpy(ret->eye_catcher, EYE); + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize a PE linker hash table. */ + +static boolean +ppc_coff_link_hash_table_init (table, abfd, newfunc) + struct ppc_coff_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc); +} + +/* Create a PE linker hash table. */ + +static struct bfd_link_hash_table * +ppc_coff_link_hash_table_create (abfd) + bfd *abfd; +{ + struct ppc_coff_link_hash_table *ret; + + ret = ((struct ppc_coff_link_hash_table *) + bfd_alloc (abfd, sizeof (struct ppc_coff_link_hash_table))); + if (ret == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + if (! ppc_coff_link_hash_table_init (ret, abfd, + ppc_coff_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root.root; +} + +/* Now, tailor coffcode.h to use our hash stuff */ + +#define coff_bfd_link_hash_table_create ppc_coff_link_hash_table_create + + /* The nt loader points the toc register to &toc + 32768, in order to */ /* use the complete range of a 16-bit displacement (I guess). We have */ /* to adjust for this when we fix up loads displaced off the toc reg. */ @@ -581,6 +704,7 @@ static reloc_howto_type ppc_coff_howto_table[] = /* Some really cheezy macros that can be turned on to test stderr :-) */ +#define DEBUG_RELOC #ifdef DEBUG_RELOC #define UN_IMPL(x) \ @@ -638,6 +762,43 @@ enum toc_type toc_64 }; +struct list_ele +{ + struct list_ele *next; + bfd_vma addr; + int offset; + const char *name; +}; + +extern struct list_ele *head; +extern struct list_ele *tail; + +static void +record_toc(toc_section, our_toc_offset, name) + asection *toc_section; + int our_toc_offset; + const char *name; +{ + /* add this entry to our toc addr-offset-name list */ + struct list_ele *t; + t = malloc(sizeof(struct list_ele)); + t->next = 0; + t->offset = our_toc_offset; + t->name = name; + t->addr = toc_section->output_offset + our_toc_offset; + + if (head == 0) + { + head = t; + tail = t; + } + else + { + tail->next = t; + tail = t; + } +} + /* record a toc offset against a symbol */ static int ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) @@ -653,7 +814,7 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) int element_size; int data; int offset; - struct coff_link_hash_entry *h; + struct ppc_coff_link_hash_entry *h; struct coff_symbol_struct *target; int ret_val; const char *name; @@ -662,7 +823,11 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) h = 0; - h = obj_coff_sym_hashes (abfd)[sym]; + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + if (h != 0) + { + CHECK_EYE(h->eye_catcher); + } if (h == 0) { @@ -707,7 +872,7 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) } else { - name = h->root.root.string; + name = h->root.root.root.string; /* check to see if there's a toc slot allocated. If not, do it here. It will be used in relocate_section */ @@ -736,6 +901,25 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) return ret_val; } +/* record a toc offset against a symbol */ +static void +ppc_mark_symbol_as_glue(abfd, sym, rel) + bfd *abfd; + int sym; + struct internal_reloc *rel; +{ + struct ppc_coff_link_hash_entry *h; + + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + + CHECK_EYE(h->eye_catcher); + + h->symbol_is_glue = 1; + h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr); + + return; +} + /* Provided the symbol, returns the value reffed */ static long get_symbol_value PARAMS ((asymbol *)); @@ -882,7 +1066,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, for (; rel < relend; rel++) { long symndx; - struct coff_link_hash_entry *h; + struct ppc_coff_link_hash_entry *h; struct internal_syment *sym; bfd_vma val; @@ -895,20 +1079,20 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, unsigned short junk = EXTRACT_JUNK (rel->r_type); #ifdef DEBUG_RELOC - /* now examine flags */ - if (r_flags != 0) - { - fprintf (stderr, "Reloc with flags found!"); - if ( r_flags & IMAGE_REL_PPC_NEG ) - fprintf (stderr, " NEG"); - if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) - fprintf (stderr, " BRTAKEN"); - if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) - fprintf (stderr, " BRNTAKEN"); - if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) - fprintf (stderr, " TOCDEFN"); - fprintf(stderr, "\n"); - } + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } #endif symndx = rel->r_symndx; @@ -924,7 +1108,13 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } else { - h = obj_coff_sym_hashes (input_bfd)[symndx]; + h = (struct ppc_coff_link_hash_entry *) + (obj_coff_sym_hashes (input_bfd)[symndx]); + if (h != 0) + { + CHECK_EYE(h->eye_catcher); + } + sym = syms + symndx; } @@ -947,18 +1137,20 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } else { - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) + CHECK_EYE(h->eye_catcher); + + if (h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) { - sec = h->root.u.def.section; - val = (h->root.u.def.value + sec = h->root.root.u.def.section; + val = (h->root.root.u.def.value + sec->output_section->vma + sec->output_offset); } else { if (! ((*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, input_section, + (info, h->root.root.root.string, input_bfd, input_section, rel->r_vaddr - input_section->vma))) return false; } @@ -1001,6 +1193,17 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } } +#if 0 + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + { + /* Somehow, we are to assume that the toc has already been + done for this one, and the offset is the value of + the symbol? */ + fprintf(stderr, + "Symbol value %d\n", val); + } +#endif + /* * Amazing bit tricks present. As we may have seen earlier, we * use the 1 bit to tell us whether or not a toc offset has been @@ -1036,6 +1239,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, else { /* write out the toc entry */ + record_toc(toc_section, our_toc_offset, strdup(name)); #ifdef TOC_DEBUG fprintf(stderr, "Writing out toc_offset toc_section (%p,%p)+%d val %d for %s\n", @@ -1056,8 +1260,9 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } else { - const char *name = h->root.root.string; + const char *name = h->root.root.root.string; our_toc_offset = h->toc_offset; + if ((our_toc_offset & 1) != 0) { /* if it has been written out, it is marked with the @@ -1072,6 +1277,8 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } else { + record_toc(toc_section, our_toc_offset, strdup(name)); + #ifdef TOC_DEBUG /* write out the toc entry */ fprintf(stderr, @@ -1133,40 +1340,26 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } break; case IMAGE_REL_PPC_IFGLUE: - /* To solve this, we need to know whether or not the symbol */ - /* appearing on the call instruction is a function included */ - /* in the link or not. If it is, then we leave the nop instruction */ - /* alone, and the reloc is done. */ - - /* Actually, for dll support on NT, this is likely not necessary at - all. For any library function, a glue code stub must be supplied - to the linker, and the glue will take care of the toc reload */ - DUMP_RELOC2(howto->name, rel); -#if 0 - if (h == 0) - { - /* this better be a static function */ - fprintf(stderr, - "It's a static function.... \n"); - } - else - { - /* this is an externally visible function */ - /* is it present? */ - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - fprintf(stderr, - "The function is present. \n"); - ; - } - else - { - fprintf(stderr, - "The function is not present. \n"); - } - } -#endif + { + /* To solve this, we need to know whether or not the symbol */ + /* appearing on the call instruction is a glue function or not. */ + /* A glue function must announce itself via a IMGLUE reloc, and */ + /* the reloc contains the required toc restore instruction */ + + bfd_vma x; + const char *my_name; + DUMP_RELOC2(howto->name, rel); + + if (h != 0) + { + my_name = h->root.root.root.string; + if (h->symbol_is_glue == 1) + { + x = bfd_get_32(input_bfd, loc); + bfd_put_32(input_bfd, h->glue_insn, loc); + } + } + } break; case IMAGE_REL_PPC_SECREL: /* Unimplemented: codeview debugging information */ @@ -1180,13 +1373,14 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, symbol */ break; case IMAGE_REL_PPC_ABSOLUTE: - case IMAGE_REL_PPC_IMGLUE: { const char *my_name; if (h == 0) my_name = (syms+symndx)->_n._n_name; else - my_name = h->root.root.string; + { + my_name = h->root.root.root.string; + } fprintf(stderr, "Warning: unsupported reloc %s <file %s, section %s>\n", @@ -1198,6 +1392,23 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr); } break; + case IMAGE_REL_PPC_IMGLUE: + { + /* There is nothing to do now. This reloc was noted in the first + pass over the relocs, and the glue instruction extracted */ + const char *my_name; + if (h->symbol_is_glue == 1) + break; + my_name = h->root.root.root.string; + fprintf(stderr, + "Warning: previously missed IMGLUE reloc %s <file %s, section %s>\n", + howto->name, + bfd_get_filename(input_bfd), + input_section->name); + break; + + } + break; case IMAGE_REL_PPC_ADDR32NB: { @@ -1213,7 +1424,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, { char *target = 0; - name = h->root.root.string; + name = h->root.root.root.string; if (strcmp(".idata$2", name) == 0) target = "__idata2_magic__"; else if (strcmp(".idata$4", name) == 0) @@ -1234,15 +1445,18 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, abort(); } - val = myh->root.u.def.value + sec->output_section->vma + sec->output_offset; + val = myh->root.u.def.value + + sec->output_section->vma + sec->output_offset; if (first_thunk_address == 0) { int idata5offset; myh = coff_link_hash_lookup (coff_hash_table (info), "__idata5_magic__", false, false, true); - first_thunk_address = myh->root.u.def.value + sec->output_section->vma + - sec->output_offset - pe_data(output_bfd)->pe_opthdr.ImageBase; + first_thunk_address = myh->root.u.def.value + + sec->output_section->vma + + sec->output_offset - + pe_data(output_bfd)->pe_opthdr.ImageBase; idata5offset = myh->root.u.def.value; myh = coff_link_hash_lookup (coff_hash_table (info), @@ -1258,9 +1472,10 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } rstat = _bfd_relocate_contents (howto, - input_bfd, - val - pe_data(output_bfd)->pe_opthdr.ImageBase, - loc); + input_bfd, + val - + pe_data(output_bfd)->pe_opthdr.ImageBase, + loc); } break; @@ -1316,7 +1531,7 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, if (symndx == -1) name = "*ABS*"; else if (h != NULL) - name = h->root.root.string; + name = h->root.root.root.string; else if (sym == NULL) name = "*unknown*"; else if (sym->_n._n_n._n_zeroes == 0 @@ -1360,6 +1575,26 @@ long int import_table_size; long int first_thunk_address; long int thunk_size; +struct list_ele *head; +struct list_ele *tail; + +void +dump_toc(vfile) + void *vfile; +{ + FILE *file = vfile; + struct list_ele *t; + + fprintf(file, + " Offset Offset Name if present\n"); + + for(t = head; t != 0; t=t->next) + { + fprintf(file, + " %2x %04lx %s\n", + t->offset - 32768, t->offset, t->name); + } +} boolean ppc_allocate_toc_section (info) @@ -1455,20 +1690,20 @@ ppc_process_before_allocation (abfd, info) unsigned short junk = EXTRACT_JUNK (rel->r_type); #ifdef DEBUG_RELOC - /* now examine flags */ - if (r_flags != 0) - { - fprintf (stderr, "Reloc with flags found!"); - if ( r_flags & IMAGE_REL_PPC_NEG ) - fprintf (stderr, " NEG"); - if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) - fprintf (stderr, " BRTAKEN"); - if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) - fprintf (stderr, " BRNTAKEN"); - if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) - fprintf (stderr, " TOCDEFN"); - fprintf(stderr, "\n"); - } + /* now examine flags */ + if (r_flags != 0) + { + fprintf (stderr, "Reloc with flags found!"); + if ( r_flags & IMAGE_REL_PPC_NEG ) + fprintf (stderr, " NEG"); + if ( r_flags & IMAGE_REL_PPC_BRTAKEN ) + fprintf (stderr, " BRTAKEN"); + if ( r_flags & IMAGE_REL_PPC_BRNTAKEN ) + fprintf (stderr, " BRNTAKEN"); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + fprintf (stderr, " TOCDEFN"); + fprintf(stderr, "\n"); + } #endif DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); @@ -1479,6 +1714,9 @@ ppc_process_before_allocation (abfd, info) toc_offset = ppc_record_toc_entry(abfd, info, sec, rel->r_symndx, default_toc); break; + case IMAGE_REL_PPC_IMGLUE: + ppc_mark_symbol_as_glue(abfd, rel->r_symndx, rel); + break; default: break; } @@ -1779,8 +2017,6 @@ ppc_coff_rtype2howto (relent, internal) break; case IMAGE_REL_PPC_IMGLUE: DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal); - /* IMGLUE relocs have big numbers in them. Don't know what for yet. */ - internal->r_vaddr = 0; /* make it zero for now */ break; default: fprintf(stderr, @@ -1876,8 +2112,6 @@ fprintf(stderr, break; case IMAGE_REL_PPC_IMGLUE: DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel); - /* IMGLUE relocs have big numbers in them. Don't know what for yet. */ - rel->r_vaddr = 0; /* make it zero for now */ break; default: fprintf(stderr, @@ -2112,12 +2346,3 @@ TARGET_BIG_SYM = }; #endif - - - - - - - - - |