diff options
author | Kim Knuttila <krk@cygnus> | 1995-11-16 20:51:08 +0000 |
---|---|---|
committer | Kim Knuttila <krk@cygnus> | 1995-11-16 20:51:08 +0000 |
commit | cd2b240203746798651ee052ac0ce7bd31a9263d (patch) | |
tree | bfc89e589697aa634615c5b77683be5d189f145a | |
parent | c4a14eefe288742860bae12016ed50a8bb2f82d9 (diff) | |
download | gdb-cd2b240203746798651ee052ac0ce7bd31a9263d.zip gdb-cd2b240203746798651ee052ac0ce7bd31a9263d.tar.gz gdb-cd2b240203746798651ee052ac0ce7bd31a9263d.tar.bz2 |
Reloc fixes for PowerPC PE
-rw-r--r-- | bfd/ChangeLog | 9 | ||||
-rw-r--r-- | bfd/coff-ppc.c | 177 |
2 files changed, 160 insertions, 26 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c24dfb7..ffadb6d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +Thu Nov 16 15:16:42 1995 Kim Knuttila <krk@cygnus.com> + + * coff-ppc.c (ppc_record_data_in_toc_entry): new function + (coff_ppc_relocate_section): Handle TOCDEFN attribute + (coff_ppc_relocate_section): Correct REL24 handling + (ppc_process_before_allocation): Correct TOCDEFN handling + + * peicode.h (dir_names): Added name descriptions + Thu Nov 16 03:38:03 1995 Ken Raeburn <raeburn@cygnus.com> * VERSION: Updated to cygnus-2.6. diff --git a/bfd/coff-ppc.c b/bfd/coff-ppc.c index 444f211..0683c6a 100644 --- a/bfd/coff-ppc.c +++ b/bfd/coff-ppc.c @@ -704,8 +704,6 @@ 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) \ { \ @@ -735,8 +733,10 @@ static reloc_howto_type ppc_coff_howto_table[] = #define DUMP_RELOC2(n,r) \ { \ - fprintf(stderr,"%s sym %d, r_vaddr %d\n", \ - n, r->r_symndx, r->r_vaddr); \ + fprintf(stderr,"%s sym %d, r_vaddr %d %s\n", \ + n, r->r_symndx, r->r_vaddr,\ + (((r->r_type) & IMAGE_REL_PPC_TOCDEFN) == 0) \ + ?" ":" TOCDEFN" ); \ } #else @@ -900,6 +900,123 @@ ppc_record_toc_entry(abfd, info, sec, sym, toc_kind) return ret_val; } +/* FIXME: record a toc offset against a data-in-toc symbol */ +/* Now, there is currenly some confusion on what this means. In some + compilers one sees the moral equivalent of: + .tocd + define some data + .text + refer to the data with a [tocv] qualifier + In general, one sees something to indicate that a tocd has been + seen, and that would trigger the allocation of data in toc. The IBM + docs seem to suggest that anything with the TOCDEFN qualifier should + never trigger storage allocation. However, in the kernel32.lib that + we've been using for our test bed, there are a couple of variables + referenced that fail that test. + + So it can't work that way. +*/ +static int +ppc_record_data_in_toc_entry(abfd, info, sec, sym, toc_kind) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + int sym; + enum toc_type toc_kind; +{ + bfd_byte *t; + bfd_byte *old_contents; + asection *s; + int element_size; + int data; + int offset; + struct ppc_coff_link_hash_entry *h = 0; + struct coff_symbol_struct *target; + int ret_val; + const char *name; + + int *local_syms; + + h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]); + + if (h == 0) + { + local_syms = obj_coff_local_toc_table(abfd); + if (local_syms == 0) + { + int i; + /* allocate a table */ + local_syms = + (int *) bfd_zalloc (abfd, + obj_raw_syment_count(abfd) * sizeof(int)); + if (local_syms == 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + obj_coff_local_toc_table(abfd) = local_syms; + for (i = 0; i < obj_raw_syment_count(abfd); ++i) + local_syms[i] = 1; + } + + if (local_syms[sym] == 1) + { + local_syms[sym] = global_toc_size; + ret_val = global_toc_size; + global_toc_size += 4; +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting data_in_toc_offset for local sym %d to %d\n", + sym, ret_val); +#endif + } + else + { + ret_val = local_syms[sym]; +#ifdef TOC_DEBUG + fprintf(stderr, + "data_in_toc_offset already set for local sym %d to %d\n", + sym, ret_val); +#endif + } + } + else + { + CHECK_EYE(h->eye_catcher); + + 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 */ + if (h->toc_offset == 1) + { +#if 0 + h->toc_offset = global_toc_size; +#endif + ret_val = global_toc_size; + /* We're allocating a chunk of the toc, as opposed to a slot */ + /* FIXME: alignment? */ + + global_toc_size += 4; +#ifdef TOC_DEBUG + fprintf(stderr, + "Setting data_in_toc_offset for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + else + { + ret_val = h->toc_offset; +#ifdef TOC_DEBUG + fprintf(stderr, + "data_in_toc_offset already set for sym %d (%s) [h=%p] to %d\n", + sym, name, h, ret_val); +#endif + } + } + + return ret_val; +} /* record a toc offset against a symbol */ static void @@ -1193,17 +1310,6 @@ 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 @@ -1263,7 +1369,17 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, const char *name = h->root.root.root.string; our_toc_offset = h->toc_offset; - if ((our_toc_offset & 1) != 0) + if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) == IMAGE_REL_PPC_TOCDEFN && + our_toc_offset == 1) + { + /* This is unbelievable cheese. Some knowledgable asm hacker has decided to + use r2 as a base for loading a value. He/She does this by setting the + tocdefn bit, and not supplying a toc definition. The behaviour is then + to use the value of the symbol as a toc index. Good Grief. + */ + our_toc_offset = val - (toc_section->output_section->vma + toc_section->output_offset); + } + else if ((our_toc_offset & 1) != 0) { /* if it has been written out, it is marked with the 1 bit. Fix up our offset, but do not write it out @@ -1324,7 +1440,8 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, /* FIXME: this test is conservative */ - if (our_toc_offset > toc_section->_raw_size) + if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN && + our_toc_offset > toc_section->_raw_size) { fprintf(stderr, "reloc offset is bigger than the toc size!\n"); @@ -1479,8 +1596,17 @@ coff_ppc_relocate_section (output_bfd, info, input_bfd, input_section, } break; - case IMAGE_REL_PPC_ADDR16: case IMAGE_REL_PPC_REL24: + DUMP_RELOC2(howto->name, rel); + val -= (input_section->output_section->vma + + input_section->output_offset); + + rstat = _bfd_relocate_contents (howto, + input_bfd, + val, + loc); + break; + case IMAGE_REL_PPC_ADDR16: case IMAGE_REL_PPC_ADDR24: case IMAGE_REL_PPC_ADDR32: DUMP_RELOC2(howto->name, rel); @@ -1604,12 +1730,6 @@ ppc_allocate_toc_section (info) bfd_byte *foo; static char test_char = '1'; -#ifdef DEBUG_TOC - fprintf(stderr, - "ppc_allocate_toc_section: allocating %s section of size %d\n", - TOC_SECTION_NAME, global_toc_size); -#endif - if ( global_toc_size == 0 ) /* FIXME: does this get me in trouble? */ return true; @@ -1711,8 +1831,13 @@ ppc_process_before_allocation (abfd, info) switch(r_type) { case IMAGE_REL_PPC_TOCREL16: - toc_offset = ppc_record_toc_entry(abfd, info, sec, - rel->r_symndx, default_toc); + if ( r_flags & IMAGE_REL_PPC_TOCDEFN ) + toc_offset = ppc_record_data_in_toc_entry(abfd, info, sec, + rel->r_symndx, + default_toc); + else + 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); |