You should have received a copy of the GNU General Public License
along with this program; if not, write to the
- Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* This file is based on a preliminary PowerPC ELF ABI. The
information may not match the final PowerPC ELF ABI. It includes
typedef struct elf_linker_section
{
- /* pointer to the section */
+ /* Pointer to the bfd section. */
asection *section;
- /* pointer to the relocations needed for this section */
- asection *rel_section;
- /* pointer to the created symbol hash value */
- struct elf_link_hash_entry *sym_hash;
- /* offset of symbol from beginning of section */
- bfd_vma sym_offset;
+ /* Section name. */
+ const char *name;
+ /* Associated bss section name. */
+ const char *bss_name;
+ /* Associated symbol name. */
+ const char *sym_name;
+ /* Value of symbol. */
+ bfd_vma sym_val;
} elf_linker_section_t;
/* Linked list of allocated pointer entries. This hangs off of the
bfd_vma addend;
/* which linker section this is */
elf_linker_section_t *lsect;
- /* whether address was written yet */
- bfd_boolean written_address_p;
} elf_linker_section_pointers_t;
struct ppc_elf_obj_tdata
return TRUE;
}
-/* Return 1 if target is one of ours. */
-
-static bfd_boolean
-is_ppc_elf_target (const struct bfd_target *targ)
-{
- extern const bfd_target bfd_elf32_powerpc_vec;
- extern const bfd_target bfd_elf32_powerpcle_vec;
-
- return targ == &bfd_elf32_powerpc_vec || targ == &bfd_elf32_powerpcle_vec;
-}
-
-/* Merge backend specific data from an object file to the output
- object file when linking. */
-
-static bfd_boolean
-ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
-{
- flagword old_flags;
- flagword new_flags;
- bfd_boolean error;
-
- if (!is_ppc_elf_target (ibfd->xvec)
- || !is_ppc_elf_target (obfd->xvec))
- return TRUE;
-
- /* Check if we have the same endianess. */
- if (! _bfd_generic_verify_endian_match (ibfd, obfd))
- return FALSE;
-
- new_flags = elf_elfheader (ibfd)->e_flags;
- old_flags = elf_elfheader (obfd)->e_flags;
- if (!elf_flags_init (obfd))
- {
- /* First call, no flags set. */
- elf_flags_init (obfd) = TRUE;
- elf_elfheader (obfd)->e_flags = new_flags;
- }
-
- /* Compatible flags are ok. */
- else if (new_flags == old_flags)
- ;
-
- /* Incompatible flags. */
- else
- {
- /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib
- to be linked with either. */
- error = FALSE;
- if ((new_flags & EF_PPC_RELOCATABLE) != 0
- && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
- {
- error = TRUE;
- (*_bfd_error_handler)
- (_("%B: compiled with -mrelocatable and linked with "
- "modules compiled normally"), ibfd);
- }
- else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
- && (old_flags & EF_PPC_RELOCATABLE) != 0)
- {
- error = TRUE;
- (*_bfd_error_handler)
- (_("%B: compiled normally and linked with "
- "modules compiled with -mrelocatable"), ibfd);
- }
-
- /* The output is -mrelocatable-lib iff both the input files are. */
- if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
- elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
-
- /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
- but each input file is either -mrelocatable or -mrelocatable-lib. */
- if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
- && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
- && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
- elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
-
- /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if
- any module uses it. */
- elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
-
- new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
- old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
-
- /* Warn about any other mismatches. */
- if (new_flags != old_flags)
- {
- error = TRUE;
- (*_bfd_error_handler)
- (_("%B: uses different e_flags (0x%lx) fields "
- "than previous modules (0x%lx)"),
- ibfd, (long) new_flags, (long) old_flags);
- }
-
- if (error)
- {
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
/* Support for core dump NOTE sections. */
static bfd_boolean
that the linker doesn't crater when trying to make more than
2 sections. */
-static struct bfd_elf_special_section const ppc_elf_special_sections[]=
+static struct bfd_elf_special_section const
+ ppc_special_sections_p[] =
+{
+ { ".plt", 4, 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static struct bfd_elf_special_section const
+ ppc_special_sections_s[] =
{
- { ".tags", 5, 0, SHT_ORDERED, SHF_ALLOC },
{ ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
{ ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
{ ".sdata2", 7, -2, SHT_PROGBITS, SHF_ALLOC },
{ ".sbss2", 6, -2, SHT_PROGBITS, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static struct bfd_elf_special_section const
+ ppc_special_sections_t[] =
+{
+ { ".tags", 5, 0, SHT_ORDERED, SHF_ALLOC },
+ { NULL, 0, 0, 0, 0 }
+};
+
+static struct bfd_elf_special_section const
+ ppc_special_sections_other[]=
+{
{ ".PPC.EMB.apuinfo", 16, 0, SHT_NOTE, 0 },
{ ".PPC.EMB.sdata0", 15, 0, SHT_PROGBITS, SHF_ALLOC },
{ ".PPC.EMB.sbss0", 14, 0, SHT_PROGBITS, SHF_ALLOC },
- { ".plt", 4, 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
- { NULL, 0, 0, 0, 0 }
+ { NULL, 0, 0, 0, 0 }
+};
+
+static struct bfd_elf_special_section const *
+ ppc_elf_special_sections[27]=
+{
+ NULL, /* 'a' */
+ NULL, /* 'b' */
+ NULL, /* 'c' */
+ NULL, /* 'd' */
+ NULL, /* 'e' */
+ NULL, /* 'f' */
+ NULL, /* 'g' */
+ NULL, /* 'h' */
+ NULL, /* 'i' */
+ NULL, /* 'j' */
+ NULL, /* 'k' */
+ NULL, /* 'l' */
+ NULL, /* 'm' */
+ NULL, /* 'n' */
+ NULL, /* 'o' */
+ ppc_special_sections_p, /* 'p' */
+ NULL, /* 'q' */
+ NULL, /* 'r' */
+ ppc_special_sections_s, /* 's' */
+ ppc_special_sections_t, /* 's' */
+ NULL, /* 'u' */
+ NULL, /* 'v' */
+ NULL, /* 'w' */
+ NULL, /* 'x' */
+ NULL, /* 'y' */
+ NULL, /* 'z' */
+ ppc_special_sections_other, /* other */
};
\f
/* Very simple linked list structure for recording apuinfo values. */
asection *relbss;
asection *dynsbss;
asection *relsbss;
- elf_linker_section_t *sdata;
- elf_linker_section_t *sdata2;
+ elf_linker_section_t sdata[2];
asection *sbss;
/* Shortcut to .__tls_get_addr. */
bfd_vma offset;
} tlsld_got;
+ /* Size of reserved GOT entries. */
+ unsigned int got_header_size;
+ /* Non-zero if allocating the header left a gap. */
+ unsigned int got_gap;
+
/* Small local sym to section mapping cache. */
struct sym_sec_cache sym_sec;
};
return NULL;
}
+ ret->sdata[0].name = ".sdata";
+ ret->sdata[0].sym_name = "_SDA_BASE_";
+ ret->sdata[0].bss_name = ".sbss";
+
+ ret->sdata[1].name = ".sdata2";
+ ret->sdata[1].sym_name = "_SDA2_BASE_";
+ ret->sdata[1].bss_name = ".sbss2";
+
return &ret->elf.root;
}
if (!bfd_set_section_flags (abfd, s, flags))
return FALSE;
- htab->relgot = bfd_make_section (abfd, ".rela.got");
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+ htab->relgot = bfd_make_section_with_flags (abfd, ".rela.got", flags);
if (!htab->relgot
- || ! bfd_set_section_flags (abfd, htab->relgot,
- (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY | SEC_LINKER_CREATED
- | SEC_READONLY))
|| ! bfd_set_section_alignment (abfd, htab->relgot, 2))
return FALSE;
| SEC_LINKER_CREATED);
htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
- htab->dynsbss = s = bfd_make_section (abfd, ".dynsbss");
- if (s == NULL
- || ! bfd_set_section_flags (abfd, s, SEC_ALLOC | SEC_LINKER_CREATED))
+ s = bfd_make_section_with_flags (abfd, ".dynsbss",
+ SEC_ALLOC | SEC_LINKER_CREATED);
+ htab->dynsbss = s;
+ if (s == NULL)
return FALSE;
if (! info->shared)
{
htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss");
- htab->relsbss = s = bfd_make_section (abfd, ".rela.sbss");
+ s = bfd_make_section_with_flags (abfd, ".rela.sbss",
+ flags | SEC_READONLY);
+ htab->relsbss = s;
if (s == NULL
- || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, 2))
return FALSE;
}
if (s == NULL)
abort ();
- flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED;
+ flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED;
return bfd_set_section_flags (abfd, s, flags);
}
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
+/* Return 1 if target is one of ours. */
+
+static bfd_boolean
+is_ppc_elf_target (const struct bfd_target *targ)
+{
+ extern const bfd_target bfd_elf32_powerpc_vec;
+ extern const bfd_target bfd_elf32_powerpcle_vec;
+
+ return targ == &bfd_elf32_powerpc_vec || targ == &bfd_elf32_powerpcle_vec;
+}
+
/* Hook called by the linker routine which adds symbols from an object
file. We use it to put .comm items in .sbss, and not .bss. */
htab = ppc_elf_hash_table (info);
if (htab->sbss == NULL)
{
- flagword flags = SEC_IS_COMMON;
+ flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED;
+
+ if (!htab->elf.dynobj)
+ htab->elf.dynobj = abfd;
- htab->sbss = bfd_make_section_anyway (abfd, ".sbss");
- if (htab->sbss == NULL
- || ! bfd_set_section_flags (abfd, htab->sbss, flags))
+ htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
+ ".sbss",
+ flags);
+ if (htab->sbss == NULL)
return FALSE;
}
return TRUE;
}
\f
-/* Enumeration to specify the special section. */
-enum elf_linker_section_enum
-{
- LINKER_SECTION_SDATA,
- LINKER_SECTION_SDATA2
-};
+/* Create a special linker section. */
-/* Create a special linker section */
-static elf_linker_section_t *
+static bfd_boolean
ppc_elf_create_linker_section (bfd *abfd,
struct bfd_link_info *info,
- enum elf_linker_section_enum which)
+ flagword flags,
+ elf_linker_section_t *lsect)
{
- elf_linker_section_t *lsect;
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
- asection *s, *sym_sec;
- bfd_size_type amt;
- flagword flags;
- const char *name;
- const char *rel_name;
- const char *sym_name;
- bfd_vma sym_offset;
-
- /* The linker creates these sections so it has somewhere to attach
- their respective symbols. Startup code (crt1.o) uses these symbols
- to initialize a register pointing to the section. If the output
- sections corresponding to these input sections were empty it would
- be OK to set the symbol to 0 (or any random number), because the
- associated register should never be used.
- FIXME: Setting a symbol this way is silly. The symbols ought to
- be set the same way other backends set gp. */
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED);
- sym_offset = 32768;
-
- switch (which)
- {
- default:
- abort ();
- return NULL;
-
- case LINKER_SECTION_SDATA: /* .sdata/.sbss section */
- name = ".sdata";
- rel_name = ".rela.sdata";
- sym_name = "_SDA_BASE_";
- break;
+ asection *s;
- case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */
- name = ".sdata2";
- rel_name = ".rela.sdata2";
- sym_name = "_SDA2_BASE_";
- flags |= SEC_READONLY;
- break;
- }
+ flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
/* Record the first bfd that needs the special sections. */
if (!htab->elf.dynobj)
htab->elf.dynobj = abfd;
- amt = sizeof (elf_linker_section_t);
- lsect = bfd_zalloc (htab->elf.dynobj, amt);
-
- lsect->sym_offset = sym_offset;
-
- /* See if the sections already exist. */
- sym_sec = s = bfd_get_section_by_name (htab->elf.dynobj, name);
- if (s == NULL || (s->flags & flags) != flags)
- {
- s = bfd_make_section_anyway (htab->elf.dynobj, name);
- if (s == NULL
- || !bfd_set_section_flags (htab->elf.dynobj, s, flags))
- return NULL;
- if (sym_sec == NULL)
- sym_sec = s;
- }
+ s = bfd_make_section_anyway_with_flags (htab->elf.dynobj,
+ lsect->name,
+ flags);
+ if (s == NULL
+ || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
+ return FALSE;
lsect->section = s;
- if (bfd_get_section_alignment (htab->elf.dynobj, s) < 2
- && !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
- return NULL;
-
- s->size = align_power (s->size, 2);
-
-#ifdef DEBUG
- fprintf (stderr, "Creating section %s, current size = %ld\n",
- name, (long) s->size);
-#endif
-
- if (sym_name)
- {
- struct elf_link_hash_entry *h;
- struct bfd_link_hash_entry *bh;
-
-#ifdef DEBUG
- fprintf (stderr, "Adding %s to section %s\n", sym_name, name);
-#endif
- bh = bfd_link_hash_lookup (info->hash, sym_name,
- FALSE, FALSE, FALSE);
-
- if ((bh == NULL || bh->type == bfd_link_hash_undefined)
- && !(_bfd_generic_link_add_one_symbol
- (info, abfd, sym_name, BSF_GLOBAL, sym_sec, sym_offset, NULL,
- FALSE, get_elf_backend_data (abfd)->collect, &bh)))
- return NULL;
- h = (struct elf_link_hash_entry *) bh;
-
- h->type = STT_OBJECT;
- lsect->sym_hash = h;
-
- if (info->shared
- && ! bfd_elf_link_record_dynamic_symbol (info, h))
- return NULL;
- }
-
- if (info->shared)
- {
- s = bfd_make_section_anyway (htab->elf.dynobj, rel_name);
- lsect->rel_section = s;
- flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_LINKER_CREATED | SEC_READONLY);
- if (s == NULL
- || ! bfd_set_section_flags (htab->elf.dynobj, s, flags)
- || ! bfd_set_section_alignment (htab->elf.dynobj, s, 2))
- return NULL;
- }
-
- return lsect;
+ return TRUE;
}
/* Find a linker generated pointer with a given addend and type. */
static bfd_boolean
elf_create_pointer_linker_section (bfd *abfd,
- struct bfd_link_info *info,
elf_linker_section_t *lsect,
struct elf_link_hash_entry *h,
const Elf_Internal_Rela *rel)
return TRUE;
ptr_linker_section_ptr = &eh->linker_section_pointer;
- /* Make sure this symbol is output as a dynamic symbol. */
- if (h->dynindx == -1)
- {
- if (! bfd_elf_link_record_dynamic_symbol (info, h))
- return FALSE;
- }
-
- if (lsect->rel_section)
- lsect->rel_section->size += sizeof (Elf32_External_Rela);
}
else
{
return TRUE;
ptr_linker_section_ptr = &ptr[r_symndx];
-
- if (info->shared)
- {
- /* If we are generating a shared object, we need to
- output a R_<xxx>_RELATIVE reloc so that the
- dynamic linker can adjust this GOT entry. */
- BFD_ASSERT (lsect->rel_section != NULL);
- lsect->rel_section->size += sizeof (Elf32_External_Rela);
- }
}
/* Allocate space for a pointer in the linker section, and allocate
linker_section_ptr->next = *ptr_linker_section_ptr;
linker_section_ptr->addend = rel->r_addend;
linker_section_ptr->lsect = lsect;
- linker_section_ptr->written_address_p = FALSE;
*ptr_linker_section_ptr = linker_section_ptr;
linker_section_ptr->offset = lsect->section->size;
if (info->relocatable)
return TRUE;
+ /* Don't do anything special with non-loaded, non-alloced sections.
+ In particular, any relocs in such sections should not affect GOT
+ and PLT reference counting (ie. we don't allow them to create GOT
+ or PLT entries), there's no possibility or desire to optimize TLS
+ relocs, and there's not much point in propagating relocs to shared
+ libs that the dynamic linker won't relocate. */
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
#ifdef DEBUG
_bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B",
sec, abfd);
if (!ppc_elf_howto_table[R_PPC_ADDR32])
ppc_elf_howto_init ();
- /* Create the linker generated sections all the time so that the
- special symbols are created. */
htab = ppc_elf_hash_table (info);
- if (htab->sdata == NULL)
- {
- htab->sdata = ppc_elf_create_linker_section (abfd, info,
- LINKER_SECTION_SDATA);
- if (htab->sdata == NULL)
- return FALSE;
- }
-
- if (htab->sdata2 == NULL)
- {
- htab->sdata2 = ppc_elf_create_linker_section (abfd, info,
- LINKER_SECTION_SDATA2);
- if (htab->sdata2 == NULL)
- return FALSE;
- }
-
symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
/* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
This shows up in particular in an R_PPC_ADDR32 in the eabi
startup code. */
- if (h && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ if (h != NULL
+ && htab->got == NULL
+ && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
{
- if (htab->got == NULL)
- {
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
- if (!ppc_elf_create_got (htab->elf.dynobj, info))
- return FALSE;
- }
+ if (htab->elf.dynobj == NULL)
+ htab->elf.dynobj = abfd;
+ if (!ppc_elf_create_got (htab->elf.dynobj, info))
+ return FALSE;
+ BFD_ASSERT (h == htab->elf.hgot);
}
r_type = ELF32_R_TYPE (rel->r_info);
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (!elf_create_pointer_linker_section (abfd, info,
- htab->sdata, h, rel))
+ if (htab->sdata[0].section == NULL
+ && !ppc_elf_create_linker_section (abfd, info, 0,
+ &htab->sdata[0]))
+ return FALSE;
+ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
+ h, rel))
return FALSE;
break;
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (!elf_create_pointer_linker_section (abfd, info,
- htab->sdata2, h, rel))
+ if (htab->sdata[1].section == NULL
+ && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY,
+ &htab->sdata[1]))
+ return FALSE;
+ if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
+ h, rel))
return FALSE;
break;
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
case R_PPC_REL32:
- if (h == NULL
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ if (h == NULL || h == htab->elf.hgot)
break;
/* fall through */
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
- && (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
&& strcmp (bfd_get_section_name (abfd, sec),
name + 5) == 0);
+ if (htab->elf.dynobj == NULL)
+ htab->elf.dynobj = abfd;
sreloc = bfd_get_section_by_name (htab->elf.dynobj, name);
if (sreloc == NULL)
{
flagword flags;
- sreloc = bfd_make_section (htab->elf.dynobj, name);
flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED);
- if ((sec->flags & SEC_ALLOC) != 0)
- flags |= SEC_ALLOC | SEC_LOAD;
+ | SEC_IN_MEMORY | SEC_LINKER_CREATED
+ | SEC_ALLOC | SEC_LOAD);
+ sreloc = bfd_make_section_with_flags (htab->elf.dynobj,
+ name,
+ flags);
if (sreloc == NULL
- || ! bfd_set_section_flags (htab->elf.dynobj,
- sreloc, flags)
|| ! bfd_set_section_alignment (htab->elf.dynobj,
sreloc, 2))
return FALSE;
return TRUE;
}
\f
+/* Merge backend specific data from an object file to the output
+ object file when linking. */
+
+static bfd_boolean
+ppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+ flagword old_flags;
+ flagword new_flags;
+ bfd_boolean error;
+
+ if (!is_ppc_elf_target (ibfd->xvec)
+ || !is_ppc_elf_target (obfd->xvec))
+ return TRUE;
+
+ /* Check if we have the same endianess. */
+ if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+ return FALSE;
+
+ new_flags = elf_elfheader (ibfd)->e_flags;
+ old_flags = elf_elfheader (obfd)->e_flags;
+ if (!elf_flags_init (obfd))
+ {
+ /* First call, no flags set. */
+ elf_flags_init (obfd) = TRUE;
+ elf_elfheader (obfd)->e_flags = new_flags;
+ }
+
+ /* Compatible flags are ok. */
+ else if (new_flags == old_flags)
+ ;
+
+ /* Incompatible flags. */
+ else
+ {
+ /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib
+ to be linked with either. */
+ error = FALSE;
+ if ((new_flags & EF_PPC_RELOCATABLE) != 0
+ && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0)
+ {
+ error = TRUE;
+ (*_bfd_error_handler)
+ (_("%B: compiled with -mrelocatable and linked with "
+ "modules compiled normally"), ibfd);
+ }
+ else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0
+ && (old_flags & EF_PPC_RELOCATABLE) != 0)
+ {
+ error = TRUE;
+ (*_bfd_error_handler)
+ (_("%B: compiled normally and linked with "
+ "modules compiled with -mrelocatable"), ibfd);
+ }
+
+ /* The output is -mrelocatable-lib iff both the input files are. */
+ if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
+ elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
+
+ /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
+ but each input file is either -mrelocatable or -mrelocatable-lib. */
+ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
+ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
+ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
+ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
+
+ /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if
+ any module uses it. */
+ elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
+
+ new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
+ old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB);
+
+ /* Warn about any other mismatches. */
+ if (new_flags != old_flags)
+ {
+ error = TRUE;
+ (*_bfd_error_handler)
+ (_("%B: uses different e_flags (0x%lx) fields "
+ "than previous modules (0x%lx)"),
+ ibfd, (long) new_flags, (long) old_flags);
+ }
+
+ if (error)
+ {
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+\f
/* Return the section that should be marked against GC for a given
relocation. */
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
+ if ((sec->flags & SEC_ALLOC) == 0)
+ return TRUE;
+
elf_section_data (sec)->local_dynrel = NULL;
htab = ppc_elf_hash_table (info);
case R_PPC_REL14_BRTAKEN:
case R_PPC_REL14_BRNTAKEN:
case R_PPC_REL32:
- if (h == NULL
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ if (h == NULL || h == htab->elf.hgot)
break;
/* Fall thru */
return TRUE;
}
\f
+/* Allocate NEED contiguous space in .got, and return the offset.
+ Handles allocation of the got header when crossing 32k. */
+
+static bfd_vma
+allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
+{
+ bfd_vma where;
+ unsigned int max_before_header = 32764;
+
+ if (need <= htab->got_gap)
+ {
+ where = max_before_header - htab->got_gap;
+ htab->got_gap -= need;
+ }
+ else
+ {
+ if (htab->got->size + need > max_before_header
+ && htab->got->size <= max_before_header)
+ {
+ htab->got_gap = max_before_header - htab->got->size;
+ htab->got->size = max_before_header + htab->got_header_size;
+ }
+ where = htab->got->size;
+ htab->got->size += need;
+ }
+ return where;
+}
+
/* Allocate space in associated reloc sections for dynamic relocs. */
static bfd_boolean
else
{
bfd_boolean dyn;
- eh->elf.got.offset = htab->got->size;
+ unsigned int need = 0;
if ((eh->tls_mask & TLS_TLS) != 0)
{
if ((eh->tls_mask & TLS_LD) != 0)
- htab->got->size += 8;
+ need += 8;
if ((eh->tls_mask & TLS_GD) != 0)
- htab->got->size += 8;
+ need += 8;
if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
- htab->got->size += 4;
+ need += 4;
if ((eh->tls_mask & TLS_DTPREL) != 0)
- htab->got->size += 4;
+ need += 4;
}
else
- htab->got->size += 4;
+ need += 4;
+ eh->elf.got.offset = allocate_got (htab, need);
dyn = htab->elf.dynamic_sections_created;
if ((info->shared
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
&& (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
|| eh->elf.root.type != bfd_link_hash_undefweak))
{
- /* All the entries we allocated need relocs. */
- htab->relgot->size
- += ((htab->got->size - eh->elf.got.offset) / 4
- * sizeof (Elf32_External_Rela));
- /* Except LD only needs one. */
+ /* All the entries we allocated need relocs.
+ Except LD only needs one. */
if ((eh->tls_mask & TLS_LD) != 0)
- htab->relgot->size -= sizeof (Elf32_External_Rela);
+ need -= 4;
+ htab->relgot->size += need * (sizeof (Elf32_External_Rela) / 4);
}
}
}
}
}
- if (htab->tlsld_got.refcount > 0)
- {
- htab->tlsld_got.offset = htab->got->size;
- htab->got->size += 8;
- if (info->shared)
- htab->relgot->size += sizeof (Elf32_External_Rela);
- }
- else
- htab->tlsld_got.offset = (bfd_vma) -1;
+ htab->got_header_size = 16;
/* Set up .got offsets for local syms, and space for local dynamic
relocs. */
char *lgot_masks;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
- asection *srel;
if (!is_ppc_elf_target (ibfd->xvec))
continue;
locsymcount = symtab_hdr->sh_info;
end_local_got = local_got + locsymcount;
lgot_masks = (char *) end_local_got;
- s = htab->got;
- srel = htab->relgot;
for (; local_got < end_local_got; ++local_got, ++lgot_masks)
if (*local_got > 0)
{
{
/* If just an LD reloc, we'll just use
htab->tlsld_got.offset. */
- if (htab->tlsld_got.offset == (bfd_vma) -1)
- {
- htab->tlsld_got.offset = s->size;
- s->size += 8;
- if (info->shared)
- srel->size += sizeof (Elf32_External_Rela);
- }
+ htab->tlsld_got.refcount += 1;
*local_got = (bfd_vma) -1;
}
else
{
- *local_got = s->size;
+ unsigned int need = 0;
if ((*lgot_masks & TLS_TLS) != 0)
{
if ((*lgot_masks & TLS_GD) != 0)
- s->size += 8;
+ need += 8;
if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
- s->size += 4;
+ need += 4;
if ((*lgot_masks & TLS_DTPREL) != 0)
- s->size += 4;
+ need += 4;
}
else
- s->size += 4;
+ need += 4;
+ *local_got = allocate_got (htab, need);
if (info->shared)
- srel->size += ((s->size - *local_got) / 4
- * sizeof (Elf32_External_Rela));
+ htab->relgot->size += (need
+ * (sizeof (Elf32_External_Rela) / 4));
}
}
else
*local_got = (bfd_vma) -1;
}
+ if (htab->tlsld_got.refcount > 0)
+ {
+ htab->tlsld_got.offset = allocate_got (htab, 8);
+ if (info->shared)
+ htab->relgot->size += sizeof (Elf32_External_Rela);
+ }
+ else
+ htab->tlsld_got.offset = (bfd_vma) -1;
+
/* Allocate space for global sym dynamic relocs. */
elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
+ if (htab->got != NULL)
+ {
+ unsigned int g_o_t = 32768;
+
+ /* If we haven't allocated the header, do so now. */
+ if (htab->got->size <= 32768)
+ {
+ g_o_t = htab->got->size;
+ htab->got->size += htab->got_header_size;
+ }
+ g_o_t += 4;
+
+ htab->elf.hgot->root.u.def.value = g_o_t;
+ }
+
/* We've now determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
continue;
if (s == htab->plt
- || s == htab->got)
+ || s == htab->got
+ || s == htab->sbss)
{
/* Strip this section if we don't need it; see the
comment below. */
}
- else if ((htab->sdata != NULL && s == htab->sdata->section)
- || (htab->sdata2 != NULL && s == htab->sdata2->section))
+ else if (s == htab->sdata[0].section
+ || s == htab->sdata[1].section)
{
- if (s->size == 0)
- /* Don't strip these sections. We need them because they
- define _SDA_BASE_ and _SDA2_BASE_. crt1.o makes a
- reference to _SDA_BASE_ to set up r13. */
- continue;
+ /* Strip these too. */
}
else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
{
if (s->size == 0)
{
- _bfd_strip_section_from_output (info, s);
+ s->flags |= SEC_EXCLUDE;
continue;
}
+ if (s == htab->sbss)
+ continue;
+
/* Allocate memory for the section contents. */
s->contents = bfd_zalloc (htab->elf.dynobj, s->size);
if (s->contents == NULL)
*again = FALSE;
- /* Nothing to do if there are no relocations. */
- if ((isec->flags & SEC_RELOC) == 0 || isec->reloc_count == 0)
+ /* Nothing to do if there are no relocations, and no need to do
+ anything with non-alloc sections. */
+ if ((isec->flags & SEC_ALLOC) == 0
+ || (isec->flags & SEC_RELOC) == 0
+ || isec->reloc_count == 0)
return TRUE;
trampoff = (isec->size + 3) & (bfd_vma) -4;
return FALSE;
}
\f
-#define bfd_put_ptr(BFD, VAL, ADDR) bfd_put_32 (BFD, VAL, ADDR)
+/* Set _SDA_BASE_, _SDA2_BASE, and sbss start and end syms. They are
+ set here rather than via PROVIDE in the default linker script,
+ because using PROVIDE inside an output section statement results in
+ unnecessary output sections. Using PROVIDE outside an output section
+ statement runs the risk of section alignment affecting where the
+ section starts. */
+bfd_boolean
+ppc_elf_set_sdata_syms (bfd *obfd, struct bfd_link_info *info)
+{
+ struct ppc_elf_link_hash_table *htab;
+ unsigned i;
+ asection *s;
+ bfd_vma val;
+
+ htab = ppc_elf_hash_table (info);
+
+ for (i = 0; i < 2; i++)
+ {
+ elf_linker_section_t *lsect = &htab->sdata[i];
+
+ s = lsect->section;
+ if (s != NULL)
+ s = s->output_section;
+ if (s == NULL)
+ s = bfd_get_section_by_name (obfd, lsect->name);
+ if (s == NULL)
+ s = bfd_get_section_by_name (obfd, lsect->bss_name);
+
+ val = 0;
+ if (s != NULL)
+ val = s->vma + 32768;
+ lsect->sym_val = val;
+
+ _bfd_elf_provide_symbol (info, lsect->sym_name, val);
+ }
+
+ s = bfd_get_section_by_name (obfd, ".sbss");
+ val = 0;
+ if (s != NULL)
+ val = s->vma;
+ _bfd_elf_provide_symbol (info, "__sbss_start", val);
+ _bfd_elf_provide_symbol (info, "___sbss_start", val);
+ if (s != NULL)
+ val += s->size;
+ _bfd_elf_provide_symbol (info, "__sbss_end", val);
+ _bfd_elf_provide_symbol (info, "___sbss_end", val);
+ return TRUE;
+}
+\f
/* Fill in the address for a pointer generated in a linker section. */
static bfd_vma
-elf_finish_pointer_linker_section (bfd *output_bfd,
- bfd *input_bfd,
- struct bfd_link_info *info,
+elf_finish_pointer_linker_section (bfd *input_bfd,
elf_linker_section_t *lsect,
struct elf_link_hash_entry *h,
bfd_vma relocation,
- const Elf_Internal_Rela *rel,
- int relative_reloc)
+ const Elf_Internal_Rela *rel)
{
elf_linker_section_pointers_t *linker_section_ptr;
struct ppc_elf_link_hash_entry *eh;
eh = (struct ppc_elf_link_hash_entry *) h;
- linker_section_ptr
- = elf_find_pointer_linker_section (eh->linker_section_pointer,
- rel->r_addend,
- lsect);
-
- BFD_ASSERT (linker_section_ptr != NULL);
-
- if (! elf_hash_table (info)->dynamic_sections_created
- || (info->shared
- && info->symbolic
- && h->def_regular))
- {
- /* This is actually a static link, or it is a
- -Bsymbolic link and the symbol is defined
- locally. We must initialize this entry in the
- global section.
-
- When doing a dynamic link, we create a .rela.<xxx>
- relocation entry to initialize the value. This
- is done in the finish_dynamic_symbol routine. */
- if (!linker_section_ptr->written_address_p)
- {
- linker_section_ptr->written_address_p = TRUE;
- bfd_put_ptr (output_bfd,
- relocation + linker_section_ptr->addend,
- (lsect->section->contents
- + linker_section_ptr->offset));
- }
- }
+ BFD_ASSERT (eh->elf.def_regular);
+ linker_section_ptr = eh->linker_section_pointer;
}
else
{
/* Handle local symbol. */
unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
- BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
- BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
- linker_section_ptr = (elf_find_pointer_linker_section
- (elf_local_ptr_offsets (input_bfd)[r_symndx],
- rel->r_addend,
- lsect));
-
- BFD_ASSERT (linker_section_ptr != NULL);
-
- /* Write out pointer if it hasn't been rewritten out before. */
- if (!linker_section_ptr->written_address_p)
- {
- linker_section_ptr->written_address_p = TRUE;
- bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
- lsect->section->contents + linker_section_ptr->offset);
-
- if (info->shared)
- {
- /* We need to generate a relative reloc for the dynamic
- linker. */
- asection *srel = lsect->rel_section;
- Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL];
- bfd_byte *erel;
- const struct elf_backend_data *bed;
- unsigned int i;
+ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
+ linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx];
+ }
- BFD_ASSERT (srel != NULL);
+ linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr,
+ rel->r_addend,
+ lsect);
+ BFD_ASSERT (linker_section_ptr != NULL);
- bed = get_elf_backend_data (output_bfd);
- for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
- {
- outrel[i].r_offset = (lsect->section->output_section->vma
- + lsect->section->output_offset
- + linker_section_ptr->offset);
- outrel[i].r_info = 0;
- outrel[i].r_addend = 0;
- }
- outrel[0].r_info = ELF32_R_INFO (0, relative_reloc);
- erel = lsect->section->contents;
- erel += (elf_section_data (lsect->section)->rel_count++
- * sizeof (Elf32_External_Rela));
- bfd_elf32_swap_reloca_out (output_bfd, outrel, erel);
- }
- }
+ /* Offset will always be a multiple of four, so use the bottom bit
+ as a "written" flag. */
+ if ((linker_section_ptr->offset & 1) == 0)
+ {
+ bfd_put_32 (lsect->section->owner,
+ relocation + linker_section_ptr->addend,
+ lsect->section->contents + linker_section_ptr->offset);
+ linker_section_ptr->offset += 1;
}
relocation = (lsect->section->output_offset
- + linker_section_ptr->offset
- - lsect->sym_offset);
+ + linker_section_ptr->offset - 1
+ - 0x8000);
#ifdef DEBUG
fprintf (stderr,
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
- sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym);
+ sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
}
}
- relocation = htab->got->output_offset + off - 4;
+ relocation = htab->got->output_offset + off;
+ relocation -= htab->elf.hgot->root.u.def.value;
/* Addends on got relocations don't make much sense.
x+off@got is actually x@got+off, and since the got is
/* If these relocations are not to a named symbol, they can be
handled right here, no need to bother the dynamic linker. */
if (SYMBOL_REFERENCES_LOCAL (info, h)
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
+ || h == htab->elf.hgot)
break;
/* fall through */
break;
/* Fall thru. */
+ if ((input_section->flags & SEC_ALLOC) == 0)
+ break;
+ /* Fall thru. */
+
if ((info->shared
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
- && (input_section->flags & SEC_ALLOC) != 0
&& h != NULL
&& h->dynindx != -1
&& !h->non_got_ref
/* Indirect .sdata relocation. */
case R_PPC_EMB_SDAI16:
- BFD_ASSERT (htab->sdata != NULL);
+ BFD_ASSERT (htab->sdata[0].section != NULL);
relocation
- = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
- htab->sdata, h, relocation,
- rel, R_PPC_RELATIVE);
+ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0],
+ h, relocation, rel);
break;
/* Indirect .sdata2 relocation. */
case R_PPC_EMB_SDA2I16:
- BFD_ASSERT (htab->sdata2 != NULL);
+ BFD_ASSERT (htab->sdata[1].section != NULL);
relocation
- = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
- htab->sdata2, h, relocation,
- rel, R_PPC_RELATIVE);
+ = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1],
+ h, relocation, rel);
break;
/* Handle the TOC16 reloc. We want to use the offset within the .got
case R_PPC_SDAREL16:
{
const char *name;
- const struct elf_link_hash_entry *sh;
BFD_ASSERT (sec != NULL);
name = bfd_get_section_name (abfd, sec->output_section);
howto->name,
name);
}
- sh = htab->sdata->sym_hash;
- addend -= (sh->root.u.def.value
- + sh->root.u.def.section->output_section->vma
- + sh->root.u.def.section->output_offset);
+ addend -= htab->sdata[0].sym_val;
}
break;
case R_PPC_EMB_SDA2REL:
{
const char *name;
- const struct elf_link_hash_entry *sh;
BFD_ASSERT (sec != NULL);
name = bfd_get_section_name (abfd, sec->output_section);
ret = FALSE;
continue;
}
- sh = htab->sdata2->sym_hash;
- addend -= (sh->root.u.def.value
- + sh->root.u.def.section->output_section->vma
- + sh->root.u.def.section->output_offset);
+ addend -= htab->sdata[1].sym_val;
}
break;
case R_PPC_EMB_RELSDA:
{
const char *name;
- const struct elf_link_hash_entry *sh;
int reg;
BFD_ASSERT (sec != NULL);
&& (name[5] == 0 || name[5] == '.'))))
{
reg = 13;
- sh = htab->sdata->sym_hash;
- addend -= (sh->root.u.def.value
- + sh->root.u.def.section->output_section->vma
- + sh->root.u.def.section->output_offset);
+ addend -= htab->sdata[0].sym_val;
}
else if (strncmp (name, ".sdata2", 7) == 0
|| strncmp (name, ".sbss2", 6) == 0)
{
reg = 2;
- sh = htab->sdata2->sym_hash;
- addend -= (sh->root.u.def.value
- + sh->root.u.def.section->output_section->vma
- + sh->root.u.def.section->output_offset);
+ addend -= htab->sdata[1].sym_val;
}
else if (strcmp (name, ".PPC.EMB.sdata0") == 0
if (r != bfd_reloc_ok)
{
- if (sym_name == NULL)
- sym_name = "(null)";
if (r == bfd_reloc_overflow)
{
if (warned)
#endif
/* Mark some specially defined symbols as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
+ if (h == htab->elf.hgot
+ || strcmp (h->root.root.string, "_DYNAMIC") == 0
|| strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
sym->st_shndx = SHN_ABS;
/* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
easily find the address of the _GLOBAL_OFFSET_TABLE_. */
- if (htab->got)
+ if (htab->got != NULL)
{
- unsigned char *contents = htab->got->contents;
- bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, contents);
+ unsigned char *p = htab->got->contents;
+ bfd_vma val;
- if (sdyn == NULL)
- bfd_put_32 (output_bfd, 0, contents + 4);
- else
- bfd_put_32 (output_bfd,
- sdyn->output_section->vma + sdyn->output_offset,
- contents + 4);
+ p += elf_hash_table (info)->hgot->root.u.def.value;
+ bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4);
+
+ val = 0;
+ if (sdyn != NULL)
+ val = sdyn->output_section->vma + sdyn->output_offset;
+ bfd_put_32 (output_bfd, val, p);
elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
}
#endif
#define elf_backend_plt_not_loaded 1
-#define elf_backend_got_symbol_offset 4
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
-#define elf_backend_got_header_size 12
#define elf_backend_rela_normal 1
#define bfd_elf32_mkobject ppc_elf_mkobject