GNU General Public License for more details.
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. */
+ along with this program; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
/* This file is based on a preliminary PowerPC ELF ABI. The
information may not match the final PowerPC ELF ABI. It includes
#define DTP_OFFSET 0x8000
/* Will references to this symbol always reference the symbol
- in this object? */
+ in this object? STV_PROTECTED is excluded from the visibility test
+ here so that function pointer comparisons work properly. Since
+ function symbols not defined in an app are set to their .plt entry,
+ it's necessary for shared libs to also reference the .plt even
+ though the symbol is really local to the shared lib. */
#define SYMBOL_REFERENCES_LOCAL(INFO, H) \
((! INFO->shared \
|| INFO->symbolic \
&& (H->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)
/* Will _calls_ to this symbol always call the version in this object? */
-#define SYMBOL_CALLS_LOCAL(INFO, H) \
+#define SYMBOL_CALLS_LOCAL(INFO, H) \
((! INFO->shared \
|| INFO->symbolic \
|| H->dynindx == -1 \
struct ppc_elf_dyn_relocs *dyn_relocs;
/* Contexts in which symbol is used in the GOT (or TOC).
- TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
+ TLS_GD .. TLS_TLS bits are or'd into the mask as the
corresponding relocs are encountered during check_relocs.
tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
indicate the corresponding GOT entry type is not needed. */
return &ret->elf.root;
}
+/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
+ copying dynamic variables from a shared lib into an app's dynbss
+ section, and instead use a dynamic relocation to point into the
+ shared lib. */
+#define ELIMINATE_COPY_RELOCS 1
+
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
edir->tls_mask |= eind->tls_mask;
- _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
+ if (ELIMINATE_COPY_RELOCS
+ && ind->root.type != bfd_link_hash_indirect
+ && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0)
+ /* If called to transfer flags for a weakdef during processing
+ of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF.
+ We clear it ourselves for ELIMINATE_COPY_RELOCS. */
+ dir->elf_link_hash_flags |=
+ (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
+ | ELF_LINK_HASH_REF_REGULAR
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+ else
+ _bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
\f
static reloc_howto_type *ppc_elf_howto_table[(int) R_PPC_max];
{
unsigned int i, type;
- for (i = 0; i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); i++)
+ for (i = 0;
+ i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]);
+ i++)
{
type = ppc_elf_howto_raw[i].type;
- BFD_ASSERT (type < sizeof (ppc_elf_howto_table) / sizeof (ppc_elf_howto_table[0]));
+ if (type >= (sizeof (ppc_elf_howto_table)
+ / sizeof (ppc_elf_howto_table[0])))
+ abort ();
ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i];
}
}
2/ The branch is predicted as not taken.
3/ The branch is taken.
4/ The branch is located in the last 5 words of a page.
- (The EOP limit is 5 by default but may be specified as any value from 1-10.)
+ (The EOP limit is 5 by default but may be specified as any value
+ from 1-10.)
Our software solution is to detect these problematic branches in a
linker pass and modify them as follows:
switch (which)
{
default:
- (*_bfd_error_handler) (_("%s: Unknown special linker type %d"),
+ (*_bfd_error_handler) (_("%s: unknown special linker type %d"),
bfd_get_filename (abfd),
(int) which);
return bfd_set_section_flags (abfd, s, flags);
}
-/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
- copying dynamic variables from a shared lib into an app's dynbss
- section, and instead use a dynamic relocation to point into the
- shared lib. */
-#define ELIMINATE_COPY_RELOCS 1
-
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
/* Clear procedure linkage table information for any symbol that
won't need a .plt entry. */
if (! htab->elf.dynamic_sections_created
- || SYMBOL_CALLS_LOCAL (info, h)
+ || SYMBOL_CALLS_LOCAL (info, h)
|| h->plt.refcount <= 0)
{
/* A PLT entry is not required/allowed when:
|| h->weakdef->root.type == bfd_link_hash_defweak);
h->root.u.def.section = h->weakdef->root.u.def.section;
h->root.u.def.value = h->weakdef->root.u.def.value;
+ if (ELIMINATE_COPY_RELOCS)
+ h->elf_link_hash_flags
+ = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF)
+ | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF));
return TRUE;
}
htab = ppc_elf_hash_table (info);
if (htab->elf.dynamic_sections_created
- && h->plt.refcount > 0)
+ && h->plt.refcount > 0
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
{
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1
else
htab->got->_raw_size += 4;
dyn = htab->elf.dynamic_sections_created;
- if (info->shared
- || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
+ 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->_raw_size
pp = &p->next;
}
}
+
+ /* Also discard relocs on undefined weak syms with non-default
+ visibility. */
+ if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
+ && h->root.type == bfd_link_hash_undefweak)
+ eh->dyn_relocs = NULL;
}
else if (ELIMINATE_COPY_RELOCS)
{
case R_PPC_REL14_BRNTAKEN:
case R_PPC_REL32:
if (h == NULL
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || SYMBOL_REFERENCES_LOCAL (info, h))
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
break;
/* fall through */
case R_PPC_REL14_BRNTAKEN:
case R_PPC_REL32:
if (h == NULL
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || SYMBOL_REFERENCES_LOCAL (info, h))
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
break;
/* Fall thru */
enum elf_ppc_reloc_type r_type2;
unsigned long r_symndx2;
struct elf_link_hash_entry *h2;
- bfd_vma insn1, insn2, insn3;
+ bfd_vma insn1, insn2;
bfd_vma offset;
/* The next instruction should be a call to
offset = rel[1].r_offset;
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - 2);
- insn3 = bfd_get_32 (output_bfd,
- contents + offset + 4);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
R_PPC_TPREL16_LO);
rel[1].r_offset += 2;
}
- if (insn3 == NOP
- || insn3 == CROR_151515 || insn3 == CROR_313131)
- {
- insn3 = insn2;
- insn2 = NOP;
- rel[1].r_offset += 4;
- }
bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2);
bfd_put_32 (output_bfd, insn2, contents + offset);
- bfd_put_32 (output_bfd, insn3, contents + offset + 4);
if (tls_gd == 0)
{
/* We changed the symbol on an LD reloc. Start over
}
/* Generate relocs for the dynamic linker. */
- if (info->shared || indx != 0)
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
{
outrel.r_offset = (htab->got->output_section->vma
+ htab->got->output_offset
+ off);
+ outrel.r_addend = 0;
if (tls_ty & (TLS_LD | TLS_GD))
{
outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
- outrel.r_addend = 0;
if (tls_ty == (TLS_TLS | TLS_GD))
{
loc = htab->relgot->contents;
* sizeof (Elf32_External_Rela));
bfd_elf32_swap_reloca_out (output_bfd,
&outrel, loc);
+ outrel.r_offset += 4;
outrel.r_info
= ELF32_R_INFO (indx, R_PPC_DTPREL32);
- outrel.r_offset += 4;
}
}
else if (tls_ty == (TLS_TLS | TLS_DTPREL))
outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
else
outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
- outrel.r_addend = 0;
if (indx == 0)
- outrel.r_addend += relocation;
+ {
+ outrel.r_addend += relocation;
+ if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
+ outrel.r_addend -= htab->tls_sec->vma;
+ }
loc = htab->relgot->contents;
loc += (htab->relgot->reloc_count++
* sizeof (Elf32_External_Rela));
{
bfd_vma value = relocation;
- if ((tls_ty & (TLS_GD | TLS_TPREL | TLS_DTPREL
- | TLS_TPRELGD)) != 0)
+ if (tls_ty == (TLS_TLS | TLS_LD))
+ value = 1;
+ else if (tls_ty != 0)
{
value -= htab->tls_sec->vma + DTP_OFFSET;
- if ((tls_ty & TLS_TPREL) != 0)
+ if (tls_ty == (TLS_TLS | TLS_TPREL))
value += DTP_OFFSET - TP_OFFSET;
- }
- if (tls_ty == (TLS_TLS | TLS_GD))
- {
- bfd_put_32 (output_bfd, value,
- htab->got->contents + off + 4);
- value = 1;
+ if (tls_ty == (TLS_TLS | TLS_GD))
+ {
+ bfd_put_32 (output_bfd, value,
+ htab->got->contents + off + 4);
+ value = 1;
+ }
}
- else if (tls_ty == (TLS_TLS | TLS_LD))
- value = 1;
bfd_put_32 (output_bfd, value,
htab->got->contents + off);
}
got at entry m+n bears little relation to the entry m. */
if (addend != 0)
(*_bfd_error_handler)
- (_("%s(%s+0x%lx): non-zero addend on got reloc against `%s'"),
+ (_("%s(%s+0x%lx): non-zero addend on %s reloc against `%s'"),
bfd_archive_filename (input_bfd),
bfd_get_section_name (input_bfd, input_section),
(long) rel->r_offset,
+ howto->name,
sym_name);
}
break;
case R_PPC_LOCAL24PC:
/* It makes no sense to point a local relocation
at a symbol not in this object. */
- if (h != NULL
- && (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- && sec->output_section == NULL)
+ if (unresolved_reloc)
{
if (! (*info->callbacks->undefined_symbol) (info,
h->root.root.string,
addend -= htab->tls_sec->vma + DTP_OFFSET;
goto dodyn;
+ case R_PPC_DTPMOD32:
+ relocation = 1;
+ addend = 0;
+ goto dodyn;
+
case R_PPC_REL24:
case R_PPC_REL32:
case R_PPC_REL14:
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_UADDR32:
case R_PPC_UADDR16:
- case R_PPC_DTPMOD32:
/* r_symndx will be zero only for relocs against symbols
from removed linkonce sections, or sections discarded by
a linker script. */
/* Fall thru. */
if ((info->shared
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak)
&& (MUST_BE_DYN_RELOC (r_type)
|| (h != NULL
&& h->dynindx != -1
if (skip)
memset (&outrel, 0, sizeof outrel);
- /* h->dynindx may be -1 if this symbol was marked to
- become local. */
else if (h != NULL
&& !SYMBOL_REFERENCES_LOCAL (info, h))
{
|| (strncmp (name, ".sbss", 5) == 0
&& (name[5] == 0 || name[5] == '.'))))
{
- (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+ (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
bfd_archive_filename (input_bfd),
sym_name,
howto->name,
if (! (strncmp (name, ".sdata2", 7) == 0
|| strncmp (name, ".sbss2", 6) == 0))
{
- (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+ (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
bfd_archive_filename (input_bfd),
sym_name,
howto->name,
else
{
- (*_bfd_error_handler) (_("%s: The target (%s) of a %s relocation is in the wrong output section (%s)"),
+ (*_bfd_error_handler) (_("%s: the target (%s) of a %s relocation is in the wrong output section (%s)"),
bfd_archive_filename (input_bfd),
sym_name,
howto->name,
case R_PPC_EMB_RELST_HA:
case R_PPC_EMB_BIT_FLD:
(*_bfd_error_handler)
- (_("%s: Relocation %s is not yet supported for symbol %s."),
+ (_("%s: relocation %s is not yet supported for symbol %s."),
bfd_archive_filename (input_bfd),
howto->name,
sym_name);
case R_PPC_EMB_NADDR16_HA:
case R_PPC_EMB_RELST_HA:
/* It's just possible that this symbol is a weak symbol
- that's not actually defined anywhere. In that case,
+ that's not actually defined anywhere. In that case,
'sec' would be NULL, and we should leave the symbol
alone (it will be set to zero elsewhere in the link). */
if (sec != NULL)
- /* Add 0x10000 if sign bit in 0:15 is set. */
- addend += ((relocation + addend) & 0x8000) << 1;
+ /* Add 0x10000 if sign bit in 0:15 is set.
+ Bits 0:15 are not used. */
+ addend += 0x8000;
break;
}
&& (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
{
(*_bfd_error_handler)
- (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"),
+ (_("%s(%s+0x%lx): unresolvable %s relocation against symbol `%s'"),
bfd_archive_filename (input_bfd),
bfd_get_section_name (input_bfd, input_section),
(long) rel->r_offset,
+ howto->name,
sym_name);
ret = FALSE;
}
else
{
(*_bfd_error_handler)
- (_("%s(%s+0x%lx): reloc against `%s': error %d"),
+ (_("%s(%s+0x%lx): %s reloc against `%s': error %d"),
bfd_archive_filename (input_bfd),
bfd_get_section_name (input_bfd, input_section),
- (long) rel->r_offset, sym_name, (int) r);
+ (long) rel->r_offset, howto->name, sym_name, (int) r);
ret = FALSE;
}
}