/* BFD back-end for PowerPC Microsoft Portable Executable files.
- Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+ Copyright 1990, 91, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
Original version pieced together by Kim Knuttila (krk@cygnus.com)
/* 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 "bfd.h"
#include "sysdep.h"
+
#include "libbfd.h"
-#include "obstack.h"
#include "coff/powerpc.h"
#include "coff/internal.h"
#include "libcoff.h"
+/* 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 intialized 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,\
+ "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 */
+};
+
+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. */
+ 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 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)
+ 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. */
+/* 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. */
#define TOC_LOAD_ADJUSTMENT (-32768)
#define TOC_SECTION_NAME ".private.toc"
#define IMAGE_REL_PPC_REFLO 0x0011
#define IMAGE_REL_PPC_PAIR 0x0012
+/* This is essentially the same as tocrel16, with TOCDEFN assumed */
+#define IMAGE_REL_PPC_TOCREL16_DEFN 0x0013
/* Flag bits in IMAGE_RELOCATION.TYPE */
asection *section,
bfd *output_bfd,
char **error));
+#if 0
static bfd_reloc_status_type ppc_reflo_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
asection *section,
bfd *output_bfd,
char **error));
+#endif
static bfd_reloc_status_type ppc_pair_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
bfd *output_bfd,
char **error));
+#if 0
static bfd_reloc_status_type ppc_addr32nb_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
asection *section,
bfd *output_bfd,
char **error));
-
+#endif
static bfd_reloc_status_type ppc_section_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
true, /* partial_inplace */
0xffffffff, /* src_mask */
0xffffffff, /* dst_mask */
- false) /* pcrel_offset */
+ false), /* pcrel_offset */
+
+ /* IMAGE_REL_PPC_TOCREL16_DEFN 0x0013 */
+ /* 16-bit offset from TOC base, without causing a definition */
+ /* Used: */
+ HOWTO ( (IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN), /* type */
+ 0, /* rightshift */
+ 1, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ 0, /* special_function */
+ "TOCREL16, TOCDEFN", /* name */
+ false, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 0xffff, /* dst_mask */
+ false), /* pcrel_offset */
+
};
/* Some really cheezy macros that can be turned on to test stderr :-) */
-
#ifdef DEBUG_RELOC
#define UN_IMPL(x) \
{ \
#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
toc_64
};
+enum ref_category
+{
+ priv,
+ pub,
+ data
+};
+
+struct list_ele
+{
+ struct list_ele *next;
+ bfd_vma addr;
+ enum ref_category cat;
+ int offset;
+ const char *name;
+};
+
+extern struct list_ele *head;
+extern struct list_ele *tail;
+
+static void
+record_toc(toc_section, our_toc_offset, cat, name)
+ asection *toc_section;
+ int our_toc_offset;
+ enum ref_category cat;
+ const char *name;
+{
+ /* add this entry to our toc addr-offset-name list */
+ struct list_ele *t;
+ t = (struct list_ele *) bfd_malloc (sizeof (struct list_ele));
+ if (t == NULL)
+ abort ();
+ t->next = 0;
+ t->offset = our_toc_offset;
+ t->name = name;
+ t->cat = cat;
+ t->addr = toc_section->output_offset + our_toc_offset;
+
+ if (head == 0)
+ {
+ head = t;
+ tail = t;
+ }
+ else
+ {
+ tail->next = t;
+ tail = t;
+ }
+}
+
+#ifdef COFF_IMAGE_WITH_PE
+
/* record a toc offset against a symbol */
-static int
+static boolean
ppc_record_toc_entry(abfd, info, sec, sym, toc_kind)
bfd *abfd;
struct bfd_link_info *info;
int sym;
enum toc_type toc_kind;
{
- bfd_byte *t;
- bfd_byte *old_contents;
- asection *s;
- int element_size;
- int data;
- int offset;
- struct coff_link_hash_entry *h;
- struct coff_symbol_struct *target;
- int ret_val;
+ struct ppc_coff_link_hash_entry *h;
const char *name;
int *local_syms;
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)
+ {
+ HASH_CHECK(h);
+ }
if (h == 0)
{
(int *) bfd_zalloc (abfd,
obj_raw_syment_count(abfd) * sizeof(int));
if (local_syms == 0)
- {
- bfd_set_error (bfd_error_no_memory);
- return false;
- }
+ return false;
obj_coff_local_toc_table(abfd) = local_syms;
for (i = 0; i < obj_raw_syment_count(abfd); ++i)
- local_syms[i] = 1;
+ {
+ SET_UNALLOCATED(local_syms[i]);
+ }
}
- if (local_syms[sym] == 1)
+ if (IS_UNALLOCATED(local_syms[sym]))
{
local_syms[sym] = global_toc_size;
- ret_val = global_toc_size;
global_toc_size += 4;
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "Setting toc_offset for local sym %d to %d\n",
- sym, ret_val);
-#endif
- }
- else
- {
- ret_val = local_syms[sym];
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "toc_offset already set for local sym %d to %d\n",
- sym, ret_val);
-#endif
+
+ /* The size must fit in a 16bit displacment */
+ if (global_toc_size > 65535)
+ {
+ (*_bfd_error_handler) ("TOC overflow");
+ bfd_set_error (bfd_error_file_too_big);
+ return false;
+ }
}
}
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 */
- if (h->toc_offset == 1)
+ if (IS_UNALLOCATED(h->toc_offset))
{
h->toc_offset = global_toc_size;
- ret_val = global_toc_size;
global_toc_size += 4;
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "Setting 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,
- "toc_offset already set for sym %d (%s) [h=%p] to %d\n",
- sym, name, h, ret_val);
-#endif
+
+ /* The size must fit in a 16bit displacment */
+ if (global_toc_size >= 65535)
+ {
+ (*_bfd_error_handler) ("TOC overflow");
+ bfd_set_error (bfd_error_file_too_big);
+ return false;
+ }
}
}
- return ret_val;
+ return true;
}
-\f
-/* Provided the symbol, returns the value reffed */
-static long get_symbol_value PARAMS ((asymbol *));
+/* 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;
-static long
-get_symbol_value (symbol)
- asymbol *symbol;
-{
- long relocation = 0;
+ h = (struct ppc_coff_link_hash_entry *) (obj_coff_sym_hashes (abfd)[sym]);
- if (bfd_is_com_section (symbol->section))
- {
- relocation = 0;
- }
- else
- {
- relocation = symbol->value +
- symbol->section->output_section->vma +
- symbol->section->output_offset;
- }
-
- return(relocation);
+ HASH_CHECK(h);
+
+ h->symbol_is_glue = 1;
+ h->glue_insn = bfd_get_32 (abfd, (bfd_byte *) &rel->r_vaddr);
+
+ return;
}
+#endif /* COFF_IMAGE_WITH_PE */
+\f
+
/* Return true if this relocation should
appear in the output .reloc section. */
{
return
(! howto->pc_relative)
+ && (howto->type != IMAGE_REL_PPC_ADDR32NB)
&& (howto->type != IMAGE_REL_PPC_TOCREL16)
- && (howto->type != IMAGE_REL_PPC_IMGLUE);
+ && (howto->type != IMAGE_REL_PPC_IMGLUE)
+ && (howto->type != IMAGE_REL_PPC_IFGLUE)
+ && (howto->type != IMAGE_REL_PPC_SECREL)
+ && (howto->type != IMAGE_REL_PPC_SECTION)
+ && (howto->type != IMAGE_REL_PPC_SECREL16)
+ && (howto->type != IMAGE_REL_PPC_REFHI)
+ && (howto->type != IMAGE_REL_PPC_REFLO)
+ && (howto->type != IMAGE_REL_PPC_PAIR)
+ && (howto->type != IMAGE_REL_PPC_TOCREL16_DEFN) ;
}
+#if 0
+
/* this function is in charge of performing all the ppc PE relocations */
/* Don't yet know if we want to do this this particular way ... (krk) */
/* FIXME: (it is not yet enabled) */
static boolean part1_consth_active = false;
static unsigned long part1_consth_value;
- unsigned long insn;
unsigned long sym_value;
- unsigned long unsigned_value;
unsigned short r_type;
- long signed_value;
-
unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
- bfd_byte *hit_data =addr + (bfd_byte *)(data);
- fprintf(stderr, "pe_ppc_reloc (%s)\n", TARGET_LITTLE_NAME);
-
r_type = reloc_entry->howto->type;
if (output_bfd)
return(bfd_reloc_ok);
}
+#endif /* 0 */
+
/* The reloc processing routine for the optimized COFF linker. */
static boolean
bfd_vma relocation;
reloc_howto_type *howto = 0;
-#ifdef DEBUG_RELOC
- fprintf(stderr,
- "pe_ppc_relocate_section (%s) for %s \n",
- TARGET_LITTLE_NAME,
- input_section->name);
-
-#endif
-
/* If we are performing a relocateable link, we don't need to do a
thing. The caller will take care of adjusting the reloc
addresses and symbol indices. */
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 r_type = EXTRACT_TYPE (rel->r_type);
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
- 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");
- }
-#endif
-
symndx = rel->r_symndx;
loc = contents + rel->r_vaddr - input_section->vma;
}
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)
+ {
+ HASH_CHECK(h);
+ }
+
sym = syms + symndx;
}
+ if (r_type == IMAGE_REL_PPC_IMGLUE && h == 0)
+ {
+ /* An IMGLUE reloc must have a name. Something is very wrong. */
+ abort();
+ }
+
sec = NULL;
val = 0;
}
else
{
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
+ HASH_CHECK(h);
+
+ 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;
}
switch (r_type)
{
default:
- fprintf( stderr,
- "ERROR: during reloc processing -- unsupported reloc %s\n",
- howto->name);
+ (*_bfd_error_handler)
+ ("%s: unsupported relocation type 0x%02x",
+ bfd_get_filename (input_bfd), r_type);
bfd_set_error (bfd_error_bad_value);
- abort();
return false;
case IMAGE_REL_PPC_TOCREL16:
{
{
toc_section = bfd_get_section_by_name (bfd_of_toc_owner,
TOC_SECTION_NAME);
-#ifdef TOC_DEBUG
-
- fprintf(stderr,
- "BFD of toc owner %p, section addr of %s %p\n",
- bfd_of_toc_owner, TOC_SECTION_NAME, toc_section);
-#endif
if ( toc_section == NULL )
{
- fprintf(stderr, "No Toc section!\n");
+ /* There is no toc section. Something is very wrong. */
abort();
}
}
local_toc_table = obj_coff_local_toc_table(input_bfd);
our_toc_offset = local_toc_table[symndx];
- if ((our_toc_offset & 1) != 0)
+ if (IS_WRITTEN(our_toc_offset))
{
/* if it has been written out, it is marked with the
1 bit. Fix up our offset, but do not write it out
again.
*/
- our_toc_offset &= ~1;
-#ifdef TOC_DEBUG
-
- fprintf(stderr,
- "Not writing out toc_offset of %d for %s\n", our_toc_offset, name);
-#endif
+ MAKE_ADDR_AGAIN(our_toc_offset);
}
else
{
/* write out the toc entry */
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "Writing out toc_offset toc_section (%p,%p)+%d val %d for %s\n",
- toc_section,
- toc_section->contents,
- our_toc_offset,
- val,
- name);
-#endif
+ record_toc(toc_section,
+ our_toc_offset,
+ priv,
+ strdup(name));
bfd_put_32(output_bfd,
val,
toc_section->contents + our_toc_offset);
- local_toc_table[symndx] |= 1;
+ MARK_AS_WRITTEN(local_toc_table[symndx]);
fixit = true;
}
}
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 ((r_flags & IMAGE_REL_PPC_TOCDEFN)
+ == IMAGE_REL_PPC_TOCDEFN )
+ {
+ /* 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 difference between the value of the
+ symbol and the actual location of the toc as the toc
+ index.
+
+ In fact, what is usually happening is, because the
+ Import Address Table is mapped immediately following
+ the toc, some trippy library code trying for speed on
+ dll linkage, takes advantage of that and considers
+ the IAT to be part of the toc, thus saving a load.
+ */
+
+ our_toc_offset = val -
+ (toc_section->output_section->vma +
+ toc_section->output_offset);
+
+ /* The size must still fit in a 16bit displacment */
+ if (our_toc_offset >= 65535)
+ {
+ (*_bfd_error_handler)
+ ("%s: Relocation for %s of %x exceeds Toc size limit",
+ bfd_get_filename (input_bfd), name, our_toc_offset);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+
+ record_toc(toc_section, our_toc_offset, pub, strdup(name));
+ }
+ else if (IS_WRITTEN(our_toc_offset))
{
/* if it has been written out, it is marked with the
1 bit. Fix up our offset, but do not write it out
again.
*/
- our_toc_offset &= ~1;
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "Not writing out toc_offset of %d for %s\n", our_toc_offset, name);
-#endif
+ MAKE_ADDR_AGAIN(our_toc_offset);
}
else
{
-#ifdef TOC_DEBUG
- /* write out the toc entry */
- fprintf(stderr,
- "Writing out toc_offset toc_section (%p,%p)+%d val %d for %s\n",
- toc_section,
- toc_section->contents,
- our_toc_offset,
- val,
- name);
-#endif
+ record_toc(toc_section, our_toc_offset, pub, strdup(name));
/* write out the toc entry */
bfd_put_32(output_bfd,
val,
toc_section->contents + our_toc_offset);
- h->toc_offset |= 1;
+ MARK_AS_WRITTEN(h->toc_offset);
/* The tricky part is that this is the address that */
/* needs a .reloc entry for it */
fixit = true;
bfd_vma addr = toc_section->output_section->vma
+ toc_section->output_offset + our_toc_offset;
- fprintf(stderr,
- " Toc Section reloc candidate\n");
-
if (coff_data(output_bfd)->pe)
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
+
fwrite (&addr, 1,4, (FILE *) info->base_file);
}
/* 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");
- abort();
+ (*_bfd_error_handler)
+ ("%s: Relocation exceeds allocated TOC (%x)",
+ bfd_get_filename (input_bfd),
+ toc_section->_raw_size);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
/* Now we know the relocation for this toc reference */
}
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",
bfd_get_filename(input_bfd),
input_section->name);
- fprintf(stderr,"sym %d (%s), r_vaddr %d (%x)\n",
- rel->r_symndx, my_name, rel->r_vaddr, rel->r_vaddr);
+ fprintf(stderr,"sym %ld (%s), r_vaddr %ld (%lx)\n",
+ rel->r_symndx, my_name, (long) rel->r_vaddr,
+ (unsigned long) 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;
+
+ (*_bfd_error_handler)
+ ("%s: Out of order IMGLUE reloc for %s",
+ bfd_get_filename (input_bfd), my_name);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
case IMAGE_REL_PPC_ADDR32NB:
{
struct coff_link_hash_entry *myh = 0;
const char *name = 0;
DUMP_RELOC2(howto->name, rel);
+
+ if (strncmp(".idata$2",input_section->name,8) == 0 && first_thunk_address == 0)
+ {
+ /* set magic values */
+ int idata5offset;
+ struct coff_link_hash_entry *myh = 0;
+ 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;
+
+ idata5offset = myh->root.u.def.value;
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ "__idata6_magic__",
+ false, false, true);
+
+ thunk_size = myh->root.u.def.value - idata5offset;
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ "__idata4_magic__",
+ false, false, true);
+ import_table_size = myh->root.u.def.value;
+ }
+
if (h == 0)
{ /* it is a file local symbol */
sym = syms + symndx;
{
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)
target = "__idata4_magic__";
else if (strcmp(".idata$5", name) == 0)
target = "__idata5_magic__";
- else
- abort();
-
- myh = 0;
- myh = coff_link_hash_lookup (coff_hash_table (info),
- target,
- false, false, true);
- if (myh == 0)
- {
- fprintf(stderr, "Missing idata magic cookies, this cannot work anyway...\n");
- abort();
- }
-
- val = myh->root.u.def.value + sec->output_section->vma + sec->output_offset;
- if (first_thunk_address == 0)
+ if (target != 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;
+ myh = 0;
- idata5offset = myh->root.u.def.value;
myh = coff_link_hash_lookup (coff_hash_table (info),
- "__idata6_magic__",
+ target,
false, false, true);
-
- thunk_size = myh->root.u.def.value - idata5offset;
- myh = coff_link_hash_lookup (coff_hash_table (info),
- "__idata4_magic__",
- false, false, true);
- import_table_size = myh->root.u.def.value;
+ if (myh == 0)
+ {
+ /* Missing magic cookies. Something is very wrong. */
+ abort();
+ }
+
+ 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;
+
+ idata5offset = myh->root.u.def.value;
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ "__idata6_magic__",
+ false, false, true);
+
+ thunk_size = myh->root.u.def.value - idata5offset;
+ myh = coff_link_hash_lookup (coff_hash_table (info),
+ "__idata4_magic__",
+ false, false, true);
+ import_table_size = myh->root.u.def.value;
+ }
}
}
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;
- 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);
if (coff_data(output_bfd)->pe)
{
addr -= pe_data(output_bfd)->pe_opthdr.ImageBase;
- fprintf(stderr,
- " adjusted down to %d", addr);
}
- fprintf(stderr, "\n");
-
fwrite (&addr, 1,4, (FILE *) info->base_file);
}
}
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
buf[SYMNMLEN] = '\0';
name = buf;
}
-#if 0
- else
- {
- name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
- if (name == NULL)
- return false;
- }
-#endif
if (! ((*info->callbacks->reloc_overflow)
(info, name, howto->name,
(bfd_vma) 0, input_bfd,
input_section, rel->r_vaddr - input_section->vma)))
- return false;
+ {
+ return false;
+ }
}
}
return true;
}
+
#ifdef COFF_IMAGE_WITH_PE
-long int global_toc_size = 0;
+long int global_toc_size = 4;
bfd* bfd_of_toc_owner = 0;
long int first_thunk_address;
long int thunk_size;
+struct list_ele *head;
+struct list_ele *tail;
-boolean
-ppc_allocate_toc_section (info)
- struct bfd_link_info *info;
+static char *
+h1 = "\n\t\t\tTOC MAPPING\n\n";
+static char *
+h2 = " TOC disassembly Comments Name\n";
+static char *
+h3 = " Offset spelling (if present)\n";
+
+void
+dump_toc(vfile)
+ void *vfile;
{
- asection *s;
- bfd_byte *foo;
- static char test_char = '1';
+ FILE *file = vfile;
+ struct list_ele *t;
-#ifdef DEBUG_TOC
- fprintf(stderr,
- "ppc_allocate_toc_section: allocating %s section of size %d\n",
- TOC_SECTION_NAME, global_toc_size);
-#endif
+ fprintf(file, h1);
+ fprintf(file, h2);
+ fprintf(file, h3);
+
+ for(t = head; t != 0; t=t->next)
+ {
+ char *cat;
+
+ if (t->cat == priv)
+ cat = "private ";
+ else if (t->cat == pub)
+ cat = "public ";
+ else if (t->cat == data)
+ cat = "data-in-toc ";
+
+ if (t->offset > global_toc_size)
+ {
+ if (t->offset <= global_toc_size + thunk_size)
+ cat = "IAT reference ";
+ else
+ {
+ fprintf(file,
+ "**** global_toc_size %ld(%lx), thunk_size %ld(%lx)\n",
+ global_toc_size, global_toc_size, thunk_size, thunk_size);
+ cat = "Out of bounds!";
+ }
+ }
+
+ fprintf(file,
+ " %04lx (%d)", (unsigned long) t->offset, t->offset - 32768);
+ fprintf(file,
+ " %s %s\n",
+ cat, t->name);
+
+ }
+
+ fprintf(file, "\n");
+}
+
+boolean
+ppc_allocate_toc_section (info)
+ struct bfd_link_info *info;
+{
+ asection *s;
+ bfd_byte *foo;
+ static char test_char = '1';
if ( global_toc_size == 0 ) /* FIXME: does this get me in trouble? */
return true;
if (bfd_of_toc_owner == 0)
{
- fprintf(stderr,
- "There is no bfd that owns the toc section!\n");
+ /* No toc owner? Something is very wrong. */
abort();
}
s = bfd_get_section_by_name ( bfd_of_toc_owner , TOC_SECTION_NAME);
if (s == NULL)
{
- fprintf(stderr, "No Toc section!\n");
+ /* No toc section? Something is very wrong. */
abort();
}
- foo = bfd_alloc(bfd_of_toc_owner, global_toc_size);
+ foo = (bfd_byte *) bfd_alloc(bfd_of_toc_owner, global_toc_size);
memset(foo, test_char, global_toc_size);
s->_raw_size = s->_cooked_size = global_toc_size;
asection *sec;
struct internal_reloc *i, *rel;
-#if 0
- fprintf(stderr,
- "ppc_process_before_allocation: BFD %s\n",
- bfd_get_filename(abfd));
-#endif
-
/* here we have a bfd that is to be included on the link. We have a hook
to do reloc rummaging, before section sizes are nailed down. */
for (; sec != 0; sec = sec->next)
{
- int toc_offset;
-#ifdef DEBUG_RELOC
- fprintf(stderr,
- " section %s reloc count %d\n",
- sec->name,
- sec->reloc_count);
-#endif
-
if (sec->reloc_count == 0)
continue;
{
unsigned short r_type = EXTRACT_TYPE (rel->r_type);
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
- unsigned short junk = EXTRACT_JUNK (rel->r_type);
+ boolean ok = true;
-#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");
- }
-#endif
-
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
switch(r_type)
{
case IMAGE_REL_PPC_TOCREL16:
- toc_offset = ppc_record_toc_entry(abfd, info, sec,
- rel->r_symndx, default_toc);
+ /* if TOCDEFN is on, ignore as someone else has allocated the
+ toc entry */
+ if ( (r_flags & IMAGE_REL_PPC_TOCDEFN) != IMAGE_REL_PPC_TOCDEFN )
+ ok = ppc_record_toc_entry(abfd, info, sec,
+ rel->r_symndx, default_toc);
+ if (!ok)
+ return false;
+ break;
+ case IMAGE_REL_PPC_IMGLUE:
+ ppc_mark_symbol_as_glue(abfd, rel->r_symndx, rel);
break;
default:
break;
}
}
}
+
+ return true;
}
#endif
return bfd_reloc_undefined;
}
+#if 0
+
static bfd_reloc_status_type
ppc_reflo_reloc (abfd,
reloc_entry,
return bfd_reloc_undefined;
}
+#endif
+
static bfd_reloc_status_type
ppc_pair_reloc (abfd,
reloc_entry,
return bfd_reloc_ok;
}
+#if 0
+
/* ADDR32NB : 32 bit address relative to the virtual origin. */
/* (On the alpha, this is always a linker generated thunk)*/
/* (i.e. 32bit addr relative to the image base) */
return bfd_reloc_ok;
}
+#endif
+
static bfd_reloc_status_type
ppc_secrel_reloc (abfd,
reloc_entry,
For now, we just strip this stuff to find the type, and ignore it other
than that.
*/
-
+ reloc_howto_type *howto;
unsigned short r_type = EXTRACT_TYPE (internal->r_type);
unsigned short r_flags = EXTRACT_FLAGS(internal->r_type);
unsigned short junk = EXTRACT_JUNK (internal->r_type);
/* the masking process only slices off the bottom byte for r_type. */
if ( r_type > MAX_RELOC_INDEX )
- {
- fprintf(stderr,
- "ppc_coff_rtype2howto: reloc index %d out of range [%d, %d]\n",
- internal->r_type, 0, MAX_RELOC_INDEX);
- abort();
- }
+ abort();
/* check for absolute crap */
if ( junk != 0 )
- {
- fprintf(stderr,
- "ppc_coff_rtype2howto: reloc index %d contains junk %d\n",
- internal->r_type, junk);
- abort();
- }
-
-#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");
- }
-#endif
+ abort();
switch(r_type)
{
case IMAGE_REL_PPC_ADDR16:
case IMAGE_REL_PPC_REL24:
case IMAGE_REL_PPC_ADDR24:
- case IMAGE_REL_PPC_TOCREL16:
case IMAGE_REL_PPC_ADDR32:
case IMAGE_REL_PPC_IFGLUE:
case IMAGE_REL_PPC_ADDR32NB:
case IMAGE_REL_PPC_SECTION:
case IMAGE_REL_PPC_SECREL:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
+ howto = ppc_coff_howto_table + r_type;
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 */
+ howto = ppc_coff_howto_table + r_type;
+ break;
+ case IMAGE_REL_PPC_TOCREL16:
+ DUMP_RELOC2(ppc_coff_howto_table[r_type].name, internal);
+ if (r_flags & IMAGE_REL_PPC_TOCDEFN)
+ howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
+ else
+ howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
break;
default:
fprintf(stderr,
"Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
ppc_coff_howto_table[r_type].name,
r_type);
+ howto = ppc_coff_howto_table + r_type;
break;
}
- relent->howto = ppc_coff_howto_table + r_type;
+ relent->howto = howto;
}
unsigned short r_flags = EXTRACT_FLAGS(rel->r_type);
unsigned short junk = EXTRACT_JUNK (rel->r_type);
-fprintf(stderr,
- "coff_ppc_rtype_to_howto\n");
-
/* the masking process only slices off the bottom byte for r_type. */
if ( r_type > MAX_RELOC_INDEX )
- {
- fprintf(stderr,
- "coff_ppc_rtype_to_howto: index %d out of range [%d, %d]\n",
- r_type, 0, MAX_RELOC_INDEX);
- abort();
- }
+ abort();
/* check for absolute crap */
if ( junk != 0 )
- {
- fprintf(stderr,
- "coff_ppc_rtype_to_howto: reloc index %d contains junk %d\n",
- rel->r_type, junk);
- abort();
- }
-
-#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");
- }
-#endif
-
+ abort();
+
switch(r_type)
{
case IMAGE_REL_PPC_ADDR32NB:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
*addendp -= pe_data(sec->output_section->owner)->pe_opthdr.ImageBase;
+ howto = ppc_coff_howto_table + r_type;
+ break;
+ case IMAGE_REL_PPC_TOCREL16:
+ DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
+ if (r_flags & IMAGE_REL_PPC_TOCDEFN)
+ howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16_DEFN;
+ else
+ howto = ppc_coff_howto_table + IMAGE_REL_PPC_TOCREL16;
break;
case IMAGE_REL_PPC_ADDR16:
case IMAGE_REL_PPC_REL24:
case IMAGE_REL_PPC_ADDR24:
- case IMAGE_REL_PPC_TOCREL16:
case IMAGE_REL_PPC_ADDR32:
case IMAGE_REL_PPC_IFGLUE:
case IMAGE_REL_PPC_SECTION:
case IMAGE_REL_PPC_SECREL:
DUMP_RELOC2(ppc_coff_howto_table[r_type].name, rel);
+ howto = ppc_coff_howto_table + r_type;
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 */
+ howto = ppc_coff_howto_table + r_type;
break;
default:
fprintf(stderr,
"Warning: Unsupported reloc %s [%d] used -- it may not work.\n",
ppc_coff_howto_table[r_type].name,
r_type);
+ howto = ppc_coff_howto_table + r_type;
break;
}
- howto = ppc_coff_howto_table + r_type;
return howto;
}
bfd *abfd;
bfd_reloc_code_real_type code;
{
-
-#ifdef DEBUG_RELOC
- fprintf(stderr, "ppc_coff_reloc_type_lookup for %s\n",
- bfd_get_reloc_code_name(code));
-#endif
-
switch (code)
{
+ HOW2MAP(BFD_RELOC_32_GOTOFF, IMAGE_REL_PPC_IMGLUE);
HOW2MAP(BFD_RELOC_16_GOT_PCREL, IMAGE_REL_PPC_IFGLUE);
HOW2MAP(BFD_RELOC_16, IMAGE_REL_PPC_ADDR16);
HOW2MAP(BFD_RELOC_PPC_B26, IMAGE_REL_PPC_REL24);
HOW2MAP(BFD_RELOC_PPC_BA26, IMAGE_REL_PPC_ADDR24);
HOW2MAP(BFD_RELOC_PPC_TOC16, IMAGE_REL_PPC_TOCREL16);
+ HOW2MAP(BFD_RELOC_16_GOTOFF, IMAGE_REL_PPC_TOCREL16_DEFN);
HOW2MAP(BFD_RELOC_32, IMAGE_REL_PPC_ADDR32);
HOW2MAP(BFD_RELOC_RVA, IMAGE_REL_PPC_ADDR32NB);
default:
- fprintf(stderr,
- "\treturning NULL\n");
return NULL;
}
-
- return NULL;
+ /*NOTREACHED*/
}
#undef HOW2MAP
#define coff_bfd_reloc_type_lookup ppc_coff_reloc_type_lookup
#define coff_rtype_to_howto coff_ppc_rtype_to_howto
#define coff_relocate_section coff_ppc_relocate_section
+#define coff_bfd_final_link ppc_bfd_coff_final_link
#ifndef COFF_IMAGE_WITH_PE
#define coff_swap_sym_in_hook ppc_coff_swap_sym_in_hook
\f
#ifndef COFF_IMAGE_WITH_PE
+/* FIXME:
+ What we're trying to do here is allocate a toc section (early), and attach
+ it to the last bfd to be processed. This avoids the problem of having a toc
+ written out before all files have been processed. This code allocates
+ a toc section for every file, and records the last one seen. There are
+ at least two problems with this approach:
+ 1. We allocate whole bunches of toc sections that are ignored, but at
+ at least we will not allocate a toc if no .toc is present.
+ 2. It's not clear to me that being the last bfd read necessarily means
+ that you are the last bfd closed.
+ 3. Doing it on a "swap in" hook depends on when the "swap in" is called,
+ and how often, etc. It's not clear to me that there isn't a hole here.
+*/
+
static void
ppc_coff_swap_sym_in_hook (abfd, ext1, in1)
bfd *abfd;
PTR ext1;
PTR in1;
{
- SYMENT *ext = (SYMENT *)ext1;
struct internal_syment *in = (struct internal_syment *)in1;
-#if 0
if (bfd_of_toc_owner != 0) /* we already have a toc, so go home */
return;
-#endif
if (strcmp(in->_n._n_name, ".toc") == 0)
{
flagword flags;
register asection *s;
- char *foo;
s = bfd_get_section_by_name ( abfd , TOC_SECTION_NAME);
if (s != NULL)
flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY ;
-#ifdef TOC_DEBUG
- fprintf(stderr,
- "ppc_coff_swap_sym_in_hook: about to create the %s section\n",
- TOC_SECTION_NAME);
-#endif
-
s = bfd_make_section (abfd, TOC_SECTION_NAME);
if (s == NULL
|| !bfd_set_section_flags (abfd, s, flags)
|| !bfd_set_section_alignment (abfd, s, 2))
{
- fprintf(stderr,
- "toc section allocation failed!\n");
+ /* FIXME: set appropriate bfd error */
abort();
}
}
#endif
+boolean
+ppc_bfd_coff_final_link ();
+
+#ifndef COFF_IMAGE_WITH_PE
+
+static boolean
+ppc_do_last(abfd)
+ bfd *abfd;
+{
+ if (abfd == bfd_of_toc_owner)
+ return true;
+ else
+ return false;
+}
+
+static bfd *
+ppc_get_last()
+{
+ return bfd_of_toc_owner;
+}
+
+/* this piece of machinery exists only to guarantee that the bfd that holds
+ the toc section is written last.
+
+ This does depend on bfd_make_section attaching a new section to the
+ end of the section list for the bfd.
+
+ This is otherwise intended to be functionally the same as
+ cofflink.c:_bfd_coff_final_link(). It is specifically different only
+ where the POWERPC_LE_PE macro modifies the code. It is left in as a
+ precise form of comment. krk@cygnus.com
+*/
+#define POWERPC_LE_PE
+
+
+/* Do the final link step. */
+
+boolean
+ppc_bfd_coff_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ bfd_size_type symesz;
+ struct coff_final_link_info finfo;
+ boolean debug_merge_allocated;
+ asection *o;
+ struct bfd_link_order *p;
+ size_t max_sym_count;
+ size_t max_lineno_count;
+ size_t max_reloc_count;
+ size_t max_output_reloc_count;
+ size_t max_contents_size;
+ file_ptr rel_filepos;
+ unsigned int relsz;
+ file_ptr line_filepos;
+ unsigned int linesz;
+ bfd *sub;
+ bfd_byte *external_relocs = NULL;
+ char strbuf[STRING_SIZE_SIZE];
+
+ symesz = bfd_coff_symesz (abfd);
+
+ finfo.info = info;
+ finfo.output_bfd = abfd;
+ finfo.strtab = NULL;
+ finfo.section_info = NULL;
+ finfo.last_file_index = -1;
+ finfo.last_bf_index = -1;
+ finfo.internal_syms = NULL;
+ finfo.sec_ptrs = NULL;
+ finfo.sym_indices = NULL;
+ finfo.outsyms = NULL;
+ finfo.linenos = NULL;
+ finfo.contents = NULL;
+ finfo.external_relocs = NULL;
+ finfo.internal_relocs = NULL;
+ debug_merge_allocated = false;
+
+ coff_data (abfd)->link_info = info;
+
+ finfo.strtab = _bfd_stringtab_init ();
+ if (finfo.strtab == NULL)
+ goto error_return;
+
+ if (! coff_debug_merge_hash_table_init (&finfo.debug_merge))
+ goto error_return;
+ debug_merge_allocated = true;
+
+ /* Compute the file positions for all the sections. */
+ if (! abfd->output_has_begun)
+ {
+ if (! bfd_coff_compute_section_file_positions (abfd))
+ return false;
+ }
+
+ /* Count the line numbers and relocation entries required for the
+ output file. Set the file positions for the relocs. */
+ rel_filepos = obj_relocbase (abfd);
+ relsz = bfd_coff_relsz (abfd);
+ max_contents_size = 0;
+ max_lineno_count = 0;
+ max_reloc_count = 0;
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ o->reloc_count = 0;
+ o->lineno_count = 0;
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+
+ if (p->type == bfd_indirect_link_order)
+ {
+ asection *sec;
+
+ sec = p->u.indirect.section;
+
+ /* Mark all sections which are to be included in the
+ link. This will normally be every section. We need
+ to do this so that we can identify any sections which
+ the linker has decided to not include. */
+ sec->linker_mark = true;
+
+ if (info->strip == strip_none
+ || info->strip == strip_some)
+ o->lineno_count += sec->lineno_count;
+
+ if (info->relocateable)
+ o->reloc_count += sec->reloc_count;
+
+ if (sec->_raw_size > max_contents_size)
+ max_contents_size = sec->_raw_size;
+ if (sec->lineno_count > max_lineno_count)
+ max_lineno_count = sec->lineno_count;
+ if (sec->reloc_count > max_reloc_count)
+ max_reloc_count = sec->reloc_count;
+ }
+ else if (info->relocateable
+ && (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order))
+ ++o->reloc_count;
+ }
+ if (o->reloc_count == 0)
+ o->rel_filepos = 0;
+ else
+ {
+ o->flags |= SEC_RELOC;
+ o->rel_filepos = rel_filepos;
+ rel_filepos += o->reloc_count * relsz;
+ }
+ }
+
+ /* If doing a relocateable link, allocate space for the pointers we
+ need to keep. */
+ if (info->relocateable)
+ {
+ unsigned int i;
+
+ /* We use section_count + 1, rather than section_count, because
+ the target_index fields are 1 based. */
+ finfo.section_info =
+ ((struct coff_link_section_info *)
+ bfd_malloc ((abfd->section_count + 1)
+ * sizeof (struct coff_link_section_info)));
+ if (finfo.section_info == NULL)
+ goto error_return;
+ for (i = 0; i <= abfd->section_count; i++)
+ {
+ finfo.section_info[i].relocs = NULL;
+ finfo.section_info[i].rel_hashes = NULL;
+ }
+ }
+
+ /* We now know the size of the relocs, so we can determine the file
+ positions of the line numbers. */
+ line_filepos = rel_filepos;
+ linesz = bfd_coff_linesz (abfd);
+ max_output_reloc_count = 0;
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ if (o->lineno_count == 0)
+ o->line_filepos = 0;
+ else
+ {
+ o->line_filepos = line_filepos;
+ line_filepos += o->lineno_count * linesz;
+ }
+
+ if (o->reloc_count != 0)
+ {
+ /* We don't know the indices of global symbols until we have
+ written out all the local symbols. For each section in
+ the output file, we keep an array of pointers to hash
+ table entries. Each entry in the array corresponds to a
+ reloc. When we find a reloc against a global symbol, we
+ set the corresponding entry in this array so that we can
+ fix up the symbol index after we have written out all the
+ local symbols.
+
+ Because of this problem, we also keep the relocs in
+ memory until the end of the link. This wastes memory,
+ but only when doing a relocateable link, which is not the
+ common case. */
+ BFD_ASSERT (info->relocateable);
+ finfo.section_info[o->target_index].relocs =
+ ((struct internal_reloc *)
+ bfd_malloc (o->reloc_count * sizeof (struct internal_reloc)));
+ finfo.section_info[o->target_index].rel_hashes =
+ ((struct coff_link_hash_entry **)
+ bfd_malloc (o->reloc_count
+ * sizeof (struct coff_link_hash_entry *)));
+ if (finfo.section_info[o->target_index].relocs == NULL
+ || finfo.section_info[o->target_index].rel_hashes == NULL)
+ goto error_return;
+
+ if (o->reloc_count > max_output_reloc_count)
+ max_output_reloc_count = o->reloc_count;
+ }
+
+ /* Reset the reloc and lineno counts, so that we can use them to
+ count the number of entries we have output so far. */
+ o->reloc_count = 0;
+ o->lineno_count = 0;
+ }
+
+ obj_sym_filepos (abfd) = line_filepos;
+
+ /* Figure out the largest number of symbols in an input BFD. Take
+ the opportunity to clear the output_has_begun fields of all the
+ input BFD's. */
+ max_sym_count = 0;
+ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
+ {
+ size_t sz;
+
+ sub->output_has_begun = false;
+ sz = obj_raw_syment_count (sub);
+ if (sz > max_sym_count)
+ max_sym_count = sz;
+ }
+
+ /* Allocate some buffers used while linking. */
+ finfo.internal_syms = ((struct internal_syment *)
+ bfd_malloc (max_sym_count
+ * sizeof (struct internal_syment)));
+ finfo.sec_ptrs = (asection **) bfd_malloc (max_sym_count
+ * sizeof (asection *));
+ finfo.sym_indices = (long *) bfd_malloc (max_sym_count * sizeof (long));
+ finfo.outsyms = ((bfd_byte *)
+ bfd_malloc ((size_t) ((max_sym_count + 1) * symesz)));
+ finfo.linenos = (bfd_byte *) bfd_malloc (max_lineno_count
+ * bfd_coff_linesz (abfd));
+ finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size);
+ finfo.external_relocs = (bfd_byte *) bfd_malloc (max_reloc_count * relsz);
+ if (! info->relocateable)
+ finfo.internal_relocs = ((struct internal_reloc *)
+ bfd_malloc (max_reloc_count
+ * sizeof (struct internal_reloc)));
+ if ((finfo.internal_syms == NULL && max_sym_count > 0)
+ || (finfo.sec_ptrs == NULL && max_sym_count > 0)
+ || (finfo.sym_indices == NULL && max_sym_count > 0)
+ || finfo.outsyms == NULL
+ || (finfo.linenos == NULL && max_lineno_count > 0)
+ || (finfo.contents == NULL && max_contents_size > 0)
+ || (finfo.external_relocs == NULL && max_reloc_count > 0)
+ || (! info->relocateable
+ && finfo.internal_relocs == NULL
+ && max_reloc_count > 0))
+ goto error_return;
+
+ /* We now know the position of everything in the file, except that
+ we don't know the size of the symbol table and therefore we don't
+ know where the string table starts. We just build the string
+ table in memory as we go along. We process all the relocations
+ for a single input file at once. */
+ obj_raw_syment_count (abfd) = 0;
+
+ if (coff_backend_info (abfd)->_bfd_coff_start_final_link)
+ {
+ if (! bfd_coff_start_final_link (abfd, info))
+ goto error_return;
+ }
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ for (p = o->link_order_head; p != NULL; p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order
+ && (bfd_get_flavour (p->u.indirect.section->owner)
+ == bfd_target_coff_flavour))
+ {
+ sub = p->u.indirect.section->owner;
+#ifdef POWERPC_LE_PE
+ if (! sub->output_has_begun && !ppc_do_last(sub))
+#else
+ if (! sub->output_has_begun)
+#endif
+ {
+ if (! _bfd_coff_link_input_bfd (&finfo, sub))
+ goto error_return;
+ sub->output_has_begun = true;
+ }
+ }
+ else if (p->type == bfd_section_reloc_link_order
+ || p->type == bfd_symbol_reloc_link_order)
+ {
+ if (! _bfd_coff_reloc_link_order (abfd, &finfo, o, p))
+ goto error_return;
+ }
+ else
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ goto error_return;
+ }
+ }
+ }
+
+#ifdef POWERPC_LE_PE
+ {
+ extern bfd* ppc_get_last();
+ bfd* last_one = ppc_get_last();
+ if (last_one)
+ {
+ if (! _bfd_coff_link_input_bfd (&finfo, last_one))
+ goto error_return;
+ }
+ last_one->output_has_begun = true;
+ }
+#endif
+
+ /* Free up the buffers used by _bfd_coff_link_input_bfd. */
+
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
+ debug_merge_allocated = false;
+
+ if (finfo.internal_syms != NULL)
+ {
+ free (finfo.internal_syms);
+ finfo.internal_syms = NULL;
+ }
+ if (finfo.sec_ptrs != NULL)
+ {
+ free (finfo.sec_ptrs);
+ finfo.sec_ptrs = NULL;
+ }
+ if (finfo.sym_indices != NULL)
+ {
+ free (finfo.sym_indices);
+ finfo.sym_indices = NULL;
+ }
+ if (finfo.linenos != NULL)
+ {
+ free (finfo.linenos);
+ finfo.linenos = NULL;
+ }
+ if (finfo.contents != NULL)
+ {
+ free (finfo.contents);
+ finfo.contents = NULL;
+ }
+ if (finfo.external_relocs != NULL)
+ {
+ free (finfo.external_relocs);
+ finfo.external_relocs = NULL;
+ }
+ if (finfo.internal_relocs != NULL)
+ {
+ free (finfo.internal_relocs);
+ finfo.internal_relocs = NULL;
+ }
+
+ /* The value of the last C_FILE symbol is supposed to be the symbol
+ index of the first external symbol. Write it out again if
+ necessary. */
+ if (finfo.last_file_index != -1
+ && (unsigned int) finfo.last_file.n_value != obj_raw_syment_count (abfd))
+ {
+ finfo.last_file.n_value = obj_raw_syment_count (abfd);
+ bfd_coff_swap_sym_out (abfd, (PTR) &finfo.last_file,
+ (PTR) finfo.outsyms);
+ if (bfd_seek (abfd,
+ (obj_sym_filepos (abfd)
+ + finfo.last_file_index * symesz),
+ SEEK_SET) != 0
+ || bfd_write (finfo.outsyms, symesz, 1, abfd) != symesz)
+ return false;
+ }
+
+ /* Write out the global symbols. */
+ finfo.failed = false;
+ coff_link_hash_traverse (coff_hash_table (info), _bfd_coff_write_global_sym,
+ (PTR) &finfo);
+ if (finfo.failed)
+ goto error_return;
+
+ /* The outsyms buffer is used by _bfd_coff_write_global_sym. */
+ if (finfo.outsyms != NULL)
+ {
+ free (finfo.outsyms);
+ finfo.outsyms = NULL;
+ }
+
+ if (info->relocateable)
+ {
+ /* Now that we have written out all the global symbols, we know
+ the symbol indices to use for relocs against them, and we can
+ finally write out the relocs. */
+ external_relocs = ((bfd_byte *)
+ bfd_malloc (max_output_reloc_count * relsz));
+ if (external_relocs == NULL)
+ goto error_return;
+
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ struct internal_reloc *irel;
+ struct internal_reloc *irelend;
+ struct coff_link_hash_entry **rel_hash;
+ bfd_byte *erel;
+
+ if (o->reloc_count == 0)
+ continue;
+
+ irel = finfo.section_info[o->target_index].relocs;
+ irelend = irel + o->reloc_count;
+ rel_hash = finfo.section_info[o->target_index].rel_hashes;
+ erel = external_relocs;
+ for (; irel < irelend; irel++, rel_hash++, erel += relsz)
+ {
+ if (*rel_hash != NULL)
+ {
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+ irel->r_symndx = (*rel_hash)->indx;
+ }
+ bfd_coff_swap_reloc_out (abfd, (PTR) irel, (PTR) erel);
+ }
+
+ if (bfd_seek (abfd, o->rel_filepos, SEEK_SET) != 0
+ || bfd_write ((PTR) external_relocs, relsz, o->reloc_count,
+ abfd) != relsz * o->reloc_count)
+ goto error_return;
+ }
+
+ free (external_relocs);
+ external_relocs = NULL;
+ }
+
+ /* Free up the section information. */
+ if (finfo.section_info != NULL)
+ {
+ unsigned int i;
+
+ for (i = 0; i < abfd->section_count; i++)
+ {
+ if (finfo.section_info[i].relocs != NULL)
+ free (finfo.section_info[i].relocs);
+ if (finfo.section_info[i].rel_hashes != NULL)
+ free (finfo.section_info[i].rel_hashes);
+ }
+ free (finfo.section_info);
+ finfo.section_info = NULL;
+ }
+
+ /* If we have optimized stabs strings, output them. */
+ if (coff_hash_table (info)->stab_info != NULL)
+ {
+ if (! _bfd_write_stab_strings (abfd, &coff_hash_table (info)->stab_info))
+ return false;
+ }
+
+ /* Write out the string table. */
+ if (obj_raw_syment_count (abfd) != 0)
+ {
+ if (bfd_seek (abfd,
+ (obj_sym_filepos (abfd)
+ + obj_raw_syment_count (abfd) * symesz),
+ SEEK_SET) != 0)
+ return false;
+
+#if STRING_SIZE_SIZE == 4
+ bfd_h_put_32 (abfd,
+ _bfd_stringtab_size (finfo.strtab) + STRING_SIZE_SIZE,
+ (bfd_byte *) strbuf);
+#else
+ #error Change bfd_h_put_32
+#endif
+
+ if (bfd_write (strbuf, 1, STRING_SIZE_SIZE, abfd) != STRING_SIZE_SIZE)
+ return false;
+
+ if (! _bfd_stringtab_emit (abfd, finfo.strtab))
+ return false;
+ }
+
+ _bfd_stringtab_free (finfo.strtab);
+
+ /* Setting bfd_get_symcount to 0 will cause write_object_contents to
+ not try to write out the symbols. */
+ bfd_get_symcount (abfd) = 0;
+
+ return true;
+
+ error_return:
+ if (debug_merge_allocated)
+ coff_debug_merge_hash_table_free (&finfo.debug_merge);
+ if (finfo.strtab != NULL)
+ _bfd_stringtab_free (finfo.strtab);
+ if (finfo.section_info != NULL)
+ {
+ unsigned int i;
+
+ for (i = 0; i < abfd->section_count; i++)
+ {
+ if (finfo.section_info[i].relocs != NULL)
+ free (finfo.section_info[i].relocs);
+ if (finfo.section_info[i].rel_hashes != NULL)
+ free (finfo.section_info[i].rel_hashes);
+ }
+ free (finfo.section_info);
+ }
+ if (finfo.internal_syms != NULL)
+ free (finfo.internal_syms);
+ if (finfo.sec_ptrs != NULL)
+ free (finfo.sec_ptrs);
+ if (finfo.sym_indices != NULL)
+ free (finfo.sym_indices);
+ if (finfo.outsyms != NULL)
+ free (finfo.outsyms);
+ if (finfo.linenos != NULL)
+ free (finfo.linenos);
+ if (finfo.contents != NULL)
+ free (finfo.contents);
+ if (finfo.external_relocs != NULL)
+ free (finfo.external_relocs);
+ if (finfo.internal_relocs != NULL)
+ free (finfo.internal_relocs);
+ if (external_relocs != NULL)
+ free (external_relocs);
+ return false;
+}
+#endif
\f
/* The transfer vectors that lead the outside world to all of the above. */
{
TARGET_LITTLE_NAME, /* name or coff-arm-little */
bfd_target_coff_flavour,
- false, /* data byte order is little */
- false, /* header byte order is little */
+ BFD_ENDIAN_LITTLE, /* data byte order is little */
+ BFD_ENDIAN_LITTLE, /* header byte order is little */
(HAS_RELOC | EXEC_P | /* FIXME: object flags */
HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | WP_TEXT),
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+#ifndef COFF_WITH_PE
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+#else
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
+ | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
+#endif
+
0, /* leading char */
'/', /* ar_pad_char */
15, /* ar_max_namelen??? FIXMEmgo */
{
TARGET_BIG_NAME,
bfd_target_coff_flavour,
- true, /* data byte order is big */
- true, /* header byte order is big */
+ BFD_ENDIAN_BIG, /* data byte order is big */
+ BFD_ENDIAN_BIG, /* header byte order is big */
(HAS_RELOC | EXEC_P | /* FIXME: object flags */
HAS_LINENO | HAS_DEBUG |
- HAS_SYMS | HAS_LOCALS | WP_TEXT),
+ HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
+#ifndef COFF_WITH_PE
(SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
+#else
+ (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC /* section flags */
+ | SEC_LINK_ONCE | SEC_LINK_DUPLICATES),
+#endif
+
0, /* leading char */
'/', /* ar_pad_char */
15, /* ar_max_namelen??? FIXMEmgo */
};
#endif
-
-
-
-
-
-
-
-
-