+/* This file is compiled more than once, but we only compile the
+ final_link routine once. */
+extern bfd_boolean ppc_bfd_coff_final_link (bfd *, struct bfd_link_info *);
+extern void dump_toc (void *);
+
+/* The toc is a set of bfd_vma fields. We use the fact that valid
+ addresses are even (i.e. the bit representing "1" is off) to allow
+ us to encode a little extra information in the field
+ - Unallocated addresses are initialized to 1.
+ - Allocated addresses are even numbers.
+ The first time we actually write a reference to the toc in the bfd,
+ we want to record that fact in a fixup file (if it is asked for), so
+ we keep track of whether or not an address has been written by marking
+ the low order bit with a "1" upon writing. */
+
+#define SET_UNALLOCATED(x) ((x) = 1)
+#define IS_UNALLOCATED(x) ((x) == 1)
+
+#define IS_WRITTEN(x) ((x) & 1)
+#define MARK_AS_WRITTEN(x) ((x) |= 1)
+#define MAKE_ADDR_AGAIN(x) ((x) &= ~1)
+
+/* Turn on this check if you suspect something amiss in the hash tables. */
+#ifdef DEBUG_HASH
+
+/* Need a 7 char string for an eye catcher. */
+#define EYE "krkjunk"
+
+#define HASH_CHECK_DCL char eye_catcher[8];
+#define HASH_CHECK_INIT(ret) strcpy(ret->eye_catcher, EYE)
+#define HASH_CHECK(addr) \
+ if (strcmp (addr->eye_catcher, EYE) != 0) \
+ { \
+ fprintf (stderr,\
+ /* xgettext: c-format */ \
+ _("File %s, line %d, Hash check failure, bad eye %8s\n"), \
+ __FILE__, __LINE__, addr->eye_catcher); \
+ abort (); \
+ }
+
+#else
+
+#define HASH_CHECK_DCL
+#define HASH_CHECK_INIT(ret)
+#define HASH_CHECK(addr)
+
+#endif
+
+/* 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;
+
+ HASH_CHECK_DCL
+};
+
+/* PE linker hash table. */
+
+struct ppc_coff_link_hash_table
+{
+ struct coff_link_hash_table root; /* First entry, as required. */
+};
+
+/* Routine to create an entry in the link hash table. */
+
+static struct bfd_hash_entry *
+ppc_coff_link_hash_newfunc (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. */
+ SET_UNALLOCATED (ret->toc_offset);
+ ret->symbol_is_glue = 0;
+ ret->glue_insn = 0;
+
+ HASH_CHECK_INIT (ret);
+ }
+
+ return (struct bfd_hash_entry *) ret;
+}
+
+/* Initialize a PE linker hash table. */
+
+static bfd_boolean
+ppc_coff_link_hash_table_init (struct ppc_coff_link_hash_table *table,
+ bfd *abfd,
+ struct bfd_hash_entry *(*newfunc)
+ (struct bfd_hash_entry *,
+ struct bfd_hash_table *,
+ const char *),
+ unsigned int entsize)
+{
+ return _bfd_coff_link_hash_table_init (&table->root, abfd, newfunc, entsize);
+}
+
+/* Create a PE linker hash table. */
+
+static struct bfd_link_hash_table *
+ppc_coff_link_hash_table_create (bfd *abfd)
+{
+ struct ppc_coff_link_hash_table *ret;
+ size_t amt = sizeof (struct ppc_coff_link_hash_table);
+
+ ret = (struct ppc_coff_link_hash_table *) bfd_malloc (amt);
+ if (ret == NULL)
+ return NULL;
+ if (!ppc_coff_link_hash_table_init (ret, abfd,
+ ppc_coff_link_hash_newfunc,
+ sizeof (struct ppc_coff_link_hash_entry)))
+ {
+ free (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. We have to adjust
+ for this when we fix up loads displaced off the toc reg. */