/* 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.
*/
#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
+
+\f
/* 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. */
/* Some really cheezy macros that can be turned on to test stderr :-) */
+#define DEBUG_RELOC
#ifdef DEBUG_RELOC
#define UN_IMPL(x) \
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)
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;
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)
{
}
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 */
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;
+}
+
\f
/* Provided the symbol, returns the value reffed */
static long get_symbol_value PARAMS ((asymbol *));
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;
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;
}
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;
}
}
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;
}
}
}
+#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
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",
}
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
}
else
{
+ record_toc(toc_section, our_toc_offset, strdup(name));
+
#ifdef TOC_DEBUG
/* write out the toc entry */
fprintf(stderr,
}
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 */
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",
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:
{
{
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)
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),
}
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;
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
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)
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);
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;
}
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,
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,
};
#endif
-
-
-
-
-
-
-
-
-