aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Knuttila <krk@cygnus>1995-11-16 20:51:08 +0000
committerKim Knuttila <krk@cygnus>1995-11-16 20:51:08 +0000
commitcd2b240203746798651ee052ac0ce7bd31a9263d (patch)
treebfc89e589697aa634615c5b77683be5d189f145a
parentc4a14eefe288742860bae12016ed50a8bb2f82d9 (diff)
downloadgdb-cd2b240203746798651ee052ac0ce7bd31a9263d.zip
gdb-cd2b240203746798651ee052ac0ce7bd31a9263d.tar.gz
gdb-cd2b240203746798651ee052ac0ce7bd31a9263d.tar.bz2
Reloc fixes for PowerPC PE
-rw-r--r--bfd/ChangeLog9
-rw-r--r--bfd/coff-ppc.c177
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);