/* PowerPC64-specific support for 64-bit ELF.
- Copyright (C) 1999-2014 Free Software Foundation, Inc.
+ Copyright (C) 1999-2015 Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra.
#define ELF_TARGET_ID PPC64_ELF_DATA
#define ELF_MACHINE_CODE EM_PPC64
#define ELF_MAXPAGESIZE 0x10000
-#define ELF_COMMONPAGESIZE 0x1000
+#define ELF_COMMONPAGESIZE 0x10000
#define elf_info_to_howto ppc64_elf_info_to_howto
#define elf_backend_want_got_sym 0
/* TOC base pointers offset from start of TOC. */
#define TOC_BASE_OFF 0x8000
+/* TOC base alignment. */
+#define TOC_BASE_ALIGN 256
/* Offset of tp and dtp pointers from start of TLS block. */
#define TP_OFFSET 0x7000
/* This reloc does nothing. */
HOWTO (R_PPC64_NONE, /* type */
0, /* rightshift */
- 2, /* size (0 = byte, 1 = short, 2 = long) */
- 32, /* bitsize */
+ 3, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
FALSE, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
/* Search SYMS for a symbol of the given VALUE. */
static asymbol *
-sym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value)
+sym_exists_at (asymbol **syms, long lo, long hi, unsigned int id, bfd_vma value)
{
long mid;
- if (id == -1)
+ if (id == (unsigned) -1)
{
while (lo < hi)
{
}
/* Create synthetic symbols, effectively restoring "dot-symbol" function
- entry syms. Also generate @plt symbols for the glink branch table. */
+ entry syms. Also generate @plt symbols for the glink branch table.
+ Returns count of synthetic symbols in RET or -1 on error. */
static long
ppc64_elf_get_synthetic_symtab (bfd *abfd,
}
}
+ if (size == 0)
+ goto done;
s = *ret = bfd_malloc (size);
if (s == NULL)
{
if (opd != NULL && !bfd_malloc_and_get_section (abfd, opd, &contents))
{
+ free_contents_and_exit_err:
+ count = -1;
free_contents_and_exit:
if (contents)
free (contents);
- count = -1;
goto done;
}
void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
- goto free_contents_and_exit;
+ goto free_contents_and_exit_err;
extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
{
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
- goto free_contents_and_exit;
+ goto free_contents_and_exit_err;
plt_count = relplt->size / sizeof (Elf64_External_Rela);
size += plt_count * sizeof (asymbol);
}
}
+ if (size == 0)
+ goto free_contents_and_exit;
s = *ret = bfd_malloc (size);
if (s == NULL)
- goto free_contents_and_exit;
+ goto free_contents_and_exit_err;
names = (char *) (s + count + plt_count + (resolv_vma != 0));
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
case R_PPC64_TPREL64:
- return !info->executable;
+ return !bfd_link_executable (info);
}
}
ppc_stub_global_entry
};
+/* Information on stub grouping. */
+struct map_stub
+{
+ /* The stub section. */
+ asection *stub_sec;
+ /* This is the section to which stubs in the group will be attached. */
+ asection *link_sec;
+};
+
struct ppc_stub_hash_entry {
/* Base hash table entry structure. */
enum ppc_stub_type stub_type;
- /* The stub section. */
- asection *stub_sec;
+ /* Group information. */
+ struct map_stub *group;
/* Offset within stub_sec of the beginning of this stub. */
bfd_vma stub_offset;
struct ppc_link_hash_entry *h;
struct plt_entry *plt_ent;
- /* Where this stub is being called from, or, in the case of combined
- stub sections, the first input section in the group. */
- asection *id_sec;
-
/* Symbol st_other. */
unsigned char other;
};
/* Various options and other info passed from the linker. */
struct ppc64_elf_params *params;
- /* Array to keep track of which stub sections have been created, and
- information on stub grouping. */
- struct map_stub {
- /* This is the section to which stubs in the group will be attached. */
- asection *link_sec;
- /* The stub section. */
- asection *stub_sec;
- /* Along with elf_gp, specifies the TOC pointer used in this group. */
+ /* The size of sec_info below. */
+ unsigned int sec_info_arr_size;
+
+ /* Per-section array of extra section info. Done this way rather
+ than as part of ppc64_elf_section_data so we have the info for
+ non-ppc64 sections. */
+ struct
+ {
+ /* Along with elf_gp, specifies the TOC pointer used by this section. */
bfd_vma toc_off;
- } *stub_group;
+
+ union
+ {
+ /* The section group that this section belongs to. */
+ struct map_stub *group;
+ /* A temp section list pointer. */
+ asection *list;
+ } u;
+ } *sec_info;
/* Temp used when calculating TOC pointers. */
bfd_vma toc_curr;
bfd *toc_bfd;
asection *toc_first_sec;
- /* Highest input section id. */
- int top_id;
-
- /* Highest output section index. */
- int top_index;
-
/* Used when adding symbols. */
struct ppc_link_hash_entry *dot_syms;
- /* List of input sections for each output section. */
- asection **input_list;
-
/* Shortcuts to get to dynamic linker sections. */
asection *dynbss;
asection *relbss;
/* Initialize the local fields. */
eh = (struct ppc_stub_hash_entry *) entry;
eh->stub_type = ppc_stub_none;
- eh->stub_sec = NULL;
+ eh->group = NULL;
eh->stub_offset = 0;
eh->target_value = 0;
eh->target_section = NULL;
eh->h = NULL;
eh->plt_ent = NULL;
- eh->id_sec = NULL;
eh->other = 0;
}
|| ! bfd_set_section_alignment (dynobj, htab->brlt, 3))
return FALSE;
- if (!info->shared)
+ if (!bfd_link_pic (info))
return TRUE;
flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
htab->elf.dynobj = params->stub_bfd;
htab->params = params;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
return create_linkage_sections (htab->elf.dynobj, info);
struct ppc_link_hash_table *htab)
{
struct ppc_stub_hash_entry *stub_entry;
- const asection *id_sec;
+ struct map_stub *group;
/* If this input section is part of a group of sections sharing one
stub section, then use the id of the first section in the group.
Stub names need to include a section id, as there may well be
more than one stub used to reach say, printf, and we need to
distinguish between them. */
- id_sec = htab->stub_group[input_section->id].link_sec;
+ group = htab->sec_info[input_section->id].u.group;
if (h != NULL && h->u.stub_cache != NULL
&& h->u.stub_cache->h == h
- && h->u.stub_cache->id_sec == id_sec)
+ && h->u.stub_cache->group == group)
{
stub_entry = h->u.stub_cache;
}
{
char *stub_name;
- stub_name = ppc_stub_name (id_sec, sym_sec, h, rel);
+ stub_name = ppc_stub_name (group->link_sec, sym_sec, h, rel);
if (stub_name == NULL)
return NULL;
struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ struct map_stub *group;
asection *link_sec;
asection *stub_sec;
struct ppc_stub_hash_entry *stub_entry;
- link_sec = htab->stub_group[section->id].link_sec;
- stub_sec = htab->stub_group[section->id].stub_sec;
+ group = htab->sec_info[section->id].u.group;
+ link_sec = group->link_sec;
+ stub_sec = group->stub_sec;
if (stub_sec == NULL)
{
- stub_sec = htab->stub_group[link_sec->id].stub_sec;
- if (stub_sec == NULL)
- {
- size_t namelen;
- bfd_size_type len;
- char *s_name;
+ size_t namelen;
+ bfd_size_type len;
+ char *s_name;
- namelen = strlen (link_sec->name);
- len = namelen + sizeof (STUB_SUFFIX);
- s_name = bfd_alloc (htab->params->stub_bfd, len);
- if (s_name == NULL)
- return NULL;
+ namelen = strlen (link_sec->name);
+ len = namelen + sizeof (STUB_SUFFIX);
+ s_name = bfd_alloc (htab->params->stub_bfd, len);
+ if (s_name == NULL)
+ return NULL;
- memcpy (s_name, link_sec->name, namelen);
- memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
- stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
- if (stub_sec == NULL)
- return NULL;
- htab->stub_group[link_sec->id].stub_sec = stub_sec;
- }
- htab->stub_group[section->id].stub_sec = stub_sec;
+ memcpy (s_name, link_sec->name, namelen);
+ memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX));
+ stub_sec = (*htab->params->add_stub_section) (s_name, link_sec);
+ if (stub_sec == NULL)
+ return NULL;
+ group->stub_sec = stub_sec;
}
/* Enter this entry into the linker stub hash table. */
return NULL;
}
- stub_entry->stub_sec = stub_sec;
+ stub_entry->group = group;
stub_entry->stub_offset = 0;
- stub_entry->id_sec = link_sec;
return stub_entry;
}
return FALSE;
htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
- if (!info->shared)
+ if (!bfd_link_pic (info))
htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
if (!htab->elf.sgot || !htab->elf.splt || !htab->elf.srelplt || !htab->dynbss
- || (!info->shared && !htab->relbss))
+ || (!bfd_link_pic (info) && !htab->relbss))
abort ();
return TRUE;
|| ELF_ST_BIND (isym->st_info) == STB_GNU_UNIQUE)
&& (ibfd->flags & DYNAMIC) == 0
&& bfd_get_flavour (info->output_bfd) == bfd_target_elf_flavour)
- elf_tdata (info->output_bfd)->has_gnu_symbols = TRUE;
+ elf_tdata (info->output_bfd)->has_gnu_symbols = elf_gnu_symbol_any;
if (*sec != NULL
&& strcmp ((*sec)->name, ".opd") == 0)
/* If the symbol is a function defined in .opd, and the function
code is in a discarded group, let it appear to be undefined. */
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& (*sec)->reloc_count != 0
&& opd_entry_value (*sec, *value, &code_sec, NULL,
FALSE) != (bfd_vma) -1
isym->st_shndx = SHN_UNDEF;
}
}
+ else if (*sec != NULL
+ && strcmp ((*sec)->name, ".toc") == 0
+ && ELF_ST_TYPE (isym->st_info) == STT_OBJECT)
+ {
+ struct ppc_link_hash_table *htab = ppc_hash_table (info);
+ if (htab != NULL)
+ htab->params->object_in_toc = 1;
+ }
if ((STO_PPC64_LOCAL_MASK & isym->st_other) != 0)
{
fdh = lookup_fdh (eh, htab);
if (fdh == NULL)
{
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& (eh->elf.root.type == bfd_link_hash_undefined
|| eh->elf.root.type == bfd_link_hash_undefweak)
&& eh->elf.ref_regular)
asection **opd_sym_map;
struct elf_link_hash_entry *tga, *dottga;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
/* Don't do anything special with non-loaded, non-alloced sections.
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
- if (info->shared)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
tls_type = TLS_TLS | TLS_TPREL;
goto dogottls;
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
- if (h != NULL && !info->shared && abiversion (abfd) != 1)
+ if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1)
{
if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
return FALSE;
/* Not supported as a dynamic relocation. */
case R_PPC64_ADDR64_LOCAL:
- if (info->shared)
+ if (bfd_link_pic (info))
{
if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
ppc_howto_init ();
case R_PPC64_TPREL64:
tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
- if (info->shared)
+ if (bfd_link_pic (info))
info->flags |= DF_STATIC_TLS;
goto dotlstoc;
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
- if (info->shared)
+ if (bfd_link_pic (info))
{
info->flags |= DF_STATIC_TLS;
goto dodyn;
case R_PPC64_ADDR16_HIGHESTA:
case R_PPC64_ADDR16_LO:
case R_PPC64_ADDR16_LO_DS:
- if (h != NULL && !info->shared && abiversion (abfd) != 1
+ if (h != NULL && !bfd_link_pic (info) && abiversion (abfd) != 1
&& rel->r_addend == 0)
{
/* We may need a .plt entry if this reloc refers to a
case R_PPC64_UADDR32:
case R_PPC64_UADDR64:
case R_PPC64_TOC:
- if (h != NULL && !info->shared)
+ if (h != NULL && !bfd_link_pic (info))
/* We may need a copy reloc. */
h->non_got_ref = 1;
dynamic library if we manage to avoid copy relocs for the
symbol. */
dodyn:
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
&& (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular))
- || (!info->shared
+ || (!bfd_link_pic (info)
&& ifunc != NULL))
{
/* We must copy these reloc types into the output file.
ppc64_elf_tdata (opd_bfd)->opd.contents = contents;
}
+ /* PR 17512: file: 64b9dfbb. */
+ if (offset + 7 >= opd_sec->size || offset + 7 < offset)
+ return (bfd_vma) -1;
+
val = bfd_get_64 (opd_bfd, contents + offset);
if (code_sec != NULL)
{
relocs = ppc64_elf_tdata (opd_bfd)->opd.relocs;
if (relocs == NULL)
relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE);
+ /* PR 17512: file: df8e1fd6. */
+ if (relocs == NULL)
+ return (bfd_vma) -1;
/* Go find the opd reloc at the sym address. */
lo = relocs;
- BFD_ASSERT (lo != NULL);
hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */
val = (bfd_vma) -1;
while (lo < hi)
if (rh != NULL)
{
rh = elf_follow_link (rh);
- BFD_ASSERT (rh->root.type == bfd_link_hash_defined
- || rh->root.type == bfd_link_hash_defweak);
- val = rh->root.u.def.value;
- sec = rh->root.u.def.section;
- if (sec->owner != opd_bfd)
+ if (rh->root.type != bfd_link_hash_defined
+ && rh->root.type != bfd_link_hash_defweak)
+ break;
+ if (rh->root.u.def.section->owner == opd_bfd)
{
- sec = NULL;
- val = (bfd_vma) -1;
+ val = rh->root.u.def.value;
+ sec = rh->root.u.def.section;
}
}
}
if ((eh->elf.root.type == bfd_link_hash_defined
|| eh->elf.root.type == bfd_link_hash_defweak)
&& (eh->elf.ref_dynamic
- || (eh->elf.def_regular
+ || ((eh->elf.def_regular || ELF_COMMON_DEF_P (&eh->elf))
&& ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
&& ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
- && (!info->executable
+ && (!bfd_link_executable (info)
|| info->export_dynamic
|| (eh->elf.dynamic
&& d != NULL
struct got_entry **local_got_ents;
const Elf_Internal_Rela *rel, *relend;
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
return TRUE;
if ((sec->flags & SEC_ALLOC) == 0)
fdh = lookup_fdh (fh, htab);
if (fdh == NULL
- && !info->executable
+ && !bfd_link_executable (info)
&& (fh->elf.root.type == bfd_link_hash_undefined
|| fh->elf.root.type == bfd_link_hash_undefweak))
{
if (fdh != NULL
&& !fdh->elf.forced_local
- && (!info->executable
+ && (!bfd_link_executable (info)
|| fdh->elf.def_dynamic
|| fdh->elf.ref_dynamic
|| (fdh->elf.root.type == bfd_link_hash_undefweak
if (htab == NULL)
return FALSE;
- if (!info->relocatable
+ if (!bfd_link_relocatable (info)
&& htab->elf.hgot != NULL)
{
_bfd_elf_link_hash_hide_symbol (info, htab->elf.hgot, TRUE);
/* Make .TOC. defined so as to prevent it being made dynamic.
The wrong value here is fixed later in ppc64_elf_set_toc. */
+ if (!htab->elf.hgot->def_regular
+ || htab->elf.hgot->root.type != bfd_link_hash_defined)
+ {
+ htab->elf.hgot->root.type = bfd_link_hash_defined;
+ htab->elf.hgot->root.u.def.value = 0;
+ htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr;
+ htab->elf.hgot->def_regular = 1;
+ htab->elf.hgot->root.linker_def = 1;
+ }
htab->elf.hgot->type = STT_OBJECT;
- htab->elf.hgot->root.type = bfd_link_hash_defined;
- htab->elf.hgot->root.u.def.value = 0;
- htab->elf.hgot->root.u.def.section = bfd_abs_section_ptr;
- htab->elf.hgot->def_regular = 1;
htab->elf.hgot->other = ((htab->elf.hgot->other & ~ELF_ST_VISIBILITY (-1))
| STV_HIDDEN);
}
only references to the symbol are via the global offset table.
For such cases we need not do anything here; the relocations will
be handled correctly by relocate_section. */
- if (info->shared)
+ if (bfd_link_pic (info))
return TRUE;
/* If there are no references to this symbol that do not use the
if (!h->def_dynamic || !h->ref_regular || h->def_regular)
return TRUE;
+ /* If -z nocopyreloc was given, don't generate them either. */
+ if (info->nocopyreloc)
+ {
+ h->non_got_ref = 0;
+ return TRUE;
+ }
+
/* If we didn't find any dynamic relocs in read-only sections, then
we'll be keeping the dynamic relocs and avoiding the copy reloc. */
if (ELIMINATE_COPY_RELOCS && !readonly_dynrelocs (h))
return TRUE;
}
+ /* Protected variables do not work with .dynbss. The copy in
+ .dynbss won't be used by the shared library with the protected
+ definition for the variable. Text relocations are preferable
+ to an incorrect program. */
+ if (h->protected_def)
+ {
+ h->non_got_ref = 0;
+ return TRUE;
+ }
+
if (h->plt.plist != NULL)
{
/* We should never get here, but unfortunately there are versions
s = htab->dynbss;
- return _bfd_elf_adjust_dynamic_copy (h, s);
+ return _bfd_elf_adjust_dynamic_copy (info, h, s);
}
/* If given a function descriptor symbol, hide both the function code
case R_PPC64_TPREL16_HIGHERA:
case R_PPC64_TPREL16_HIGHEST:
case R_PPC64_TPREL16_HIGHESTA:
- if (!info->shared)
+ if (!bfd_link_pic (info))
return TRUE;
case R_PPC64_TPREL64:
return FALSE;
}
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (must_be_dyn_reloc (info, r_type)
|| (h != NULL
&& (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
|| !h->def_regular))))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
|| !h->def_regular)))
return FALSE;
}
-/* qsort comparison function sorting relocs by r_offset. */
-
-static int
-sort_r_offset (const void *p, const void *q)
-{
- const Elf_Internal_Rela *a = (const Elf_Internal_Rela *) p;
- const Elf_Internal_Rela *b = (const Elf_Internal_Rela *) q;
-
- if (a->r_offset < b->r_offset)
- return -1;
- else if (a->r_offset > b->r_offset)
- return 1;
- return 0;
-}
-
/* Remove unused Official Procedure Descriptor entries. Currently we
only remove those associated with functions in discarded link-once
sections, or weakly defined functions that have been overridden. It
info->keep_memory);
if (relstart == NULL)
return FALSE;
- qsort (relstart, sec->reloc_count, sizeof (*relstart), sort_r_offset);
/* First run through the relocs to check they are sane, and to
determine whether we need to edit this opd section. */
}
opd->adjust[OPD_NDX (rel->r_offset)] = -1;
- if (NO_OPD_RELOCS || info->relocatable)
+ if (NO_OPD_RELOCS || bfd_link_relocatable (info))
rel = next_rel;
else
while (1)
/* If we are doing a final link and the last .opd entry is just 16 byte
long, add a 8 byte padding after it. */
- if (need_pad != NULL && !info->relocatable)
+ if (need_pad != NULL && !bfd_link_relocatable (info))
{
bfd_byte *p;
unsigned char *toc_ref;
int pass;
- if (info->relocatable || !info->executable)
+ if (!bfd_link_executable (info))
return TRUE;
htab = ppc_hash_table (info);
htab->elf.irelplt->size += rentsize;
htab->got_reli_size += rentsize;
}
- else if ((info->shared
+ else if ((bfd_link_pic (info)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
&& (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak))
if ((htab->elf.dynamic_sections_created
&& h->dynindx != -1
- && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+ && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h))
|| h->type == STT_GNU_IFUNC)
{
struct plt_entry *pent;
space for relocs that have become local due to symbol visibility
changes. */
- if (info->shared)
+ if (bfd_link_pic (info))
{
/* Relocs that use pc_count are those that appear on a call insn,
or certain REL relocs (see must_be_dyn_reloc) that can be
if (htab->elf.dynamic_sections_created)
{
/* Set the contents of the .interp section to the interpreter. */
- if (info->executable)
+ if (bfd_link_executable (info))
{
s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
htab->elf.irelplt->size += rel_size;
htab->got_reli_size += rel_size;
}
- else if (info->shared)
+ else if (bfd_link_pic (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size;
if (htab->glink != NULL)
htab->glink->rawsize = htab->glink->size;
- if (!htab->opd_abi && !info->shared)
+ if (!htab->opd_abi && !bfd_link_pic (info))
elf_link_hash_traverse (&htab->elf, size_global_entry_stubs, info);
first_tlsld = NULL;
ent->got.offset = s->size;
ent->owner = ibfd;
s->size += 16;
- if (info->shared)
+ if (bfd_link_pic (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
#define add_dynamic_entry(TAG, VAL) \
_bfd_elf_add_dynamic_entry (info, TAG, VAL)
- if (info->executable)
+ if (bfd_link_executable (info))
{
if (!add_dynamic_entry (DT_DEBUG, 0))
return FALSE;
size += 4;
if (htab->params->plt_static_chain)
size += 4;
- if (htab->params->plt_thread_safe)
+ if (htab->params->plt_thread_safe
+ && htab->elf.dynamic_sections_created
+ && stub_entry->h != NULL
+ && stub_entry->h->elf.dynindx != -1)
size += 8;
if (PPC_HA (off + 8 + 8 * htab->params->plt_static_chain) != PPC_HA (off))
size += 4;
{
int stub_align = 1 << htab->params->plt_stub_align;
unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
- bfd_vma stub_off = stub_entry->stub_sec->size;
+ bfd_vma stub_off = stub_entry->group->stub_sec->size;
if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
> ((stub_size - 1) & -stub_align))
bfd *obfd = htab->params->stub_bfd;
bfd_boolean plt_load_toc = htab->opd_abi;
bfd_boolean plt_static_chain = htab->params->plt_static_chain;
- bfd_boolean plt_thread_safe = htab->params->plt_thread_safe;
+ bfd_boolean plt_thread_safe = (htab->params->plt_thread_safe
+ && htab->elf.dynamic_sections_created
+ && stub_entry->h != NULL
+ && stub_entry->h->elf.dynindx != -1);
bfd_boolean use_fake_dep = plt_thread_safe;
bfd_vma cmp_branch_off = 0;
if (!ALWAYS_USE_FAKE_DEP
&& plt_load_toc
&& plt_thread_safe
- && !(stub_entry->h != NULL
- && (stub_entry->h == htab->tls_get_addr_fd
- || stub_entry->h == htab->tls_get_addr)
+ && !((stub_entry->h == htab->tls_get_addr_fd
+ || stub_entry->h == htab->tls_get_addr)
&& !htab->params->no_tls_get_addr_opt))
{
bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
to = (glinkoff
+ htab->glink->output_offset
+ htab->glink->output_section->vma);
- from = (p - stub_entry->stub_sec->contents
+ from = (p - stub_entry->group->stub_sec->contents
+ 4 * (ALWAYS_EMIT_R2SAVE
|| stub_entry->stub_type == ppc_stub_plt_call_r2save)
+ 4 * (PPC_HA (offset) != 0)
!= PPC_HA (offset))
+ 4 * (plt_static_chain != 0)
+ 20
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ + stub_entry->group->stub_sec->output_offset
+ + stub_entry->group->stub_sec->output_section->vma);
cmp_branch_off = to - from;
use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
}
p = build_plt_stub (htab, stub_entry, p, offset, r);
bfd_put_32 (obfd, BCTRL, p - 4);
- bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4;
bfd_put_32 (obfd, LD_R2_0R1 + STK_TOC (htab), p), p += 4;
+ bfd_put_32 (obfd, LD_R11_0R1 + STK_LINKER (htab), p), p += 4;
bfd_put_32 (obfd, MTLR_R11, p), p += 4;
bfd_put_32 (obfd, BLR, p), p += 4;
struct ppc_stub_hash_entry *stub_entry)
{
struct ppc_link_hash_table *htab = ppc_hash_table (info);
- bfd_vma r2off = htab->stub_group[stub_entry->target_section->id].toc_off;
+ bfd_vma r2off = htab->sec_info[stub_entry->target_section->id].toc_off;
if (r2off == 0)
{
info->callbacks->einfo (_("%P: cannot find opd entry toc for `%T'\n"),
stub_entry->h->elf.root.root.string);
bfd_set_error (bfd_error_bad_value);
- return 0;
+ return (bfd_vma) -1;
}
if (!bfd_get_section_contents (opd->owner, opd, buf, opd_off + 8, 8))
- return 0;
+ return (bfd_vma) -1;
r2off = bfd_get_64 (opd->owner, buf);
r2off -= elf_gp (info->output_bfd);
}
- r2off -= htab->stub_group[stub_entry->id_sec->id].toc_off;
+ r2off -= htab->sec_info[stub_entry->group->link_sec->id].toc_off;
return r2off;
}
return FALSE;
/* Make a note of the offset within the stubs for this entry. */
- stub_entry->stub_offset = stub_entry->stub_sec->size;
- loc = stub_entry->stub_sec->contents + stub_entry->stub_offset;
+ stub_entry->stub_offset = stub_entry->group->stub_sec->size;
+ loc = stub_entry->group->stub_sec->contents + stub_entry->stub_offset;
htab->stub_count[stub_entry->stub_type - 1] += 1;
switch (stub_entry->stub_type)
/* And this is where we are coming from. */
off -= (stub_entry->stub_offset
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ + stub_entry->group->stub_sec->output_offset
+ + stub_entry->group->stub_sec->output_section->vma);
size = 4;
if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
{
bfd_vma r2off = get_r2off (info, stub_entry);
- if (r2off == 0)
+ if (r2off == (bfd_vma) -1)
{
htab->stub_error = TRUE;
return FALSE;
}
bfd_put_32 (htab->params->stub_bfd, STD_R2_0R1 + STK_TOC (htab), loc);
loc += 4;
- size = 12;
+ size = 8;
if (PPC_HA (r2off) != 0)
{
- size = 16;
bfd_put_32 (htab->params->stub_bfd,
ADDIS_R2_R2 | PPC_HA (r2off), loc);
loc += 4;
+ size += 4;
+ }
+ if (PPC_LO (r2off) != 0)
+ {
+ bfd_put_32 (htab->params->stub_bfd,
+ ADDI_R2_R2 | PPC_LO (r2off), loc);
+ loc += 4;
+ size += 4;
}
- bfd_put_32 (htab->params->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc);
- loc += 4;
off -= size - 4;
}
bfd_put_32 (htab->params->stub_bfd, B_DOT | (off & 0x3fffffc), loc);
if (info->emitrelocations)
{
- r = get_relocs (stub_entry->stub_sec, 1);
+ r = get_relocs (stub_entry->group->stub_sec, 1);
if (r == NULL)
return FALSE;
- r->r_offset = loc - stub_entry->stub_sec->contents;
+ r->r_offset = loc - stub_entry->group->stub_sec->contents;
r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
r->r_addend = dest;
if (stub_entry->h != NULL)
off = (dest
- elf_gp (htab->brlt->output_section->owner)
- - htab->stub_group[stub_entry->id_sec->id].toc_off);
+ - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
if (info->emitrelocations)
{
- r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0));
+ r = get_relocs (stub_entry->group->stub_sec, 1 + (PPC_HA (off) != 0));
if (r == NULL)
return FALSE;
- r[0].r_offset = loc - stub_entry->stub_sec->contents;
+ r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
if (bfd_big_endian (info->output_bfd))
r[0].r_offset += 2;
if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
{
bfd_vma r2off = get_r2off (info, stub_entry);
- if (r2off == 0 && htab->opd_abi)
+ if (r2off == (bfd_vma) -1)
{
htab->stub_error = TRUE;
return FALSE;
struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
/* If the old-ABI "dot-symbol" is undefined make it weak so
- we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.
- FIXME: We used to define the symbol on one of the call
- stubs instead, which is why we test symbol section id
- against htab->top_id in various places. Likely all
- these checks could now disappear. */
+ we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL. */
if (fh->elf.root.type == bfd_link_hash_undefined)
fh->elf.root.type = bfd_link_hash_undefweak;
/* Stop undo_symbol_twiddle changing it back to undefined. */
off = (dest
- elf_gp (plt->output_section->owner)
- - htab->stub_group[stub_entry->id_sec->id].toc_off);
+ - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
{
{
unsigned pad = plt_stub_pad (htab, stub_entry, off);
- stub_entry->stub_sec->size += pad;
- stub_entry->stub_offset = stub_entry->stub_sec->size;
+ stub_entry->group->stub_sec->size += pad;
+ stub_entry->stub_offset = stub_entry->group->stub_sec->size;
loc += pad;
}
r = NULL;
if (info->emitrelocations)
{
- r = get_relocs (stub_entry->stub_sec,
+ r = get_relocs (stub_entry->group->stub_sec,
((PPC_HA (off) != 0)
+ (htab->opd_abi
? 2 + (htab->params->plt_static_chain
: 1)));
if (r == NULL)
return FALSE;
- r[0].r_offset = loc - stub_entry->stub_sec->contents;
+ r[0].r_offset = loc - stub_entry->group->stub_sec->contents;
if (bfd_big_endian (info->output_bfd))
r[0].r_offset += 2;
r[0].r_addend = dest;
return FALSE;
}
- stub_entry->stub_sec->size += size;
+ stub_entry->group->stub_sec->size += size;
if (htab->params->emit_stub_syms)
{
if (h->root.type == bfd_link_hash_new)
{
h->root.type = bfd_link_hash_defined;
- h->root.u.def.section = stub_entry->stub_sec;
+ h->root.u.def.section = stub_entry->group->stub_sec;
h->root.u.def.value = stub_entry->stub_offset;
h->ref_regular = 1;
h->def_regular = 1;
h->ref_regular_nonweak = 1;
h->forced_local = 1;
h->non_elf = 0;
+ h->root.linker_def = 1;
}
}
off += (plt->output_offset
+ plt->output_section->vma
- elf_gp (plt->output_section->owner)
- - htab->stub_group[stub_entry->id_sec->id].toc_off);
+ - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
size = plt_stub_size (htab, stub_entry, off);
if (htab->params->plt_stub_align)
size += plt_stub_pad (htab, stub_entry, off);
if (info->emitrelocations)
{
- stub_entry->stub_sec->reloc_count
+ stub_entry->group->stub_sec->reloc_count
+= ((PPC_HA (off) != 0)
+ (htab->opd_abi
? 2 + (htab->params->plt_static_chain
&& PPC_HA (off + 16) == PPC_HA (off))
: 1));
- stub_entry->stub_sec->flags |= SEC_RELOC;
+ stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
}
else
off = (stub_entry->target_value
+ stub_entry->target_section->output_offset
+ stub_entry->target_section->output_section->vma);
- off -= (stub_entry->stub_sec->size
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ off -= (stub_entry->group->stub_sec->size
+ + stub_entry->group->stub_sec->output_offset
+ + stub_entry->group->stub_sec->output_section->vma);
/* Reset the stub type from the plt variant in case we now
can reach with a shorter stub. */
if (stub_entry->stub_type == ppc_stub_long_branch_r2off)
{
r2off = get_r2off (info, stub_entry);
- if (r2off == 0 && htab->opd_abi)
+ if (r2off == (bfd_vma) -1)
{
htab->stub_error = TRUE;
return FALSE;
}
- size = 12;
+ size = 8;
if (PPC_HA (r2off) != 0)
- size = 16;
+ size += 4;
+ if (PPC_LO (r2off) != 0)
+ size += 4;
off -= size - 4;
}
Do the same for -R objects without function descriptors. */
if (off + (1 << 25) >= (bfd_vma) (1 << 26) - local_off
|| (stub_entry->stub_type == ppc_stub_long_branch_r2off
- && r2off == 0))
+ && r2off == 0
+ && htab->sec_info[stub_entry->target_section->id].toc_off == 0))
{
struct ppc_branch_hash_entry *br_entry;
+ htab->brlt->output_offset
+ htab->brlt->output_section->vma
- elf_gp (htab->brlt->output_section->owner)
- - htab->stub_group[stub_entry->id_sec->id].toc_off);
+ - htab->sec_info[stub_entry->group->link_sec->id].toc_off);
if (info->emitrelocations)
{
- stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0);
- stub_entry->stub_sec->flags |= SEC_RELOC;
+ stub_entry->group->stub_sec->reloc_count
+ += 1 + (PPC_HA (off) != 0);
+ stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
}
else if (info->emitrelocations)
{
- stub_entry->stub_sec->reloc_count += 1;
- stub_entry->stub_sec->flags |= SEC_RELOC;
+ stub_entry->group->stub_sec->reloc_count += 1;
+ stub_entry->group->stub_sec->flags |= SEC_RELOC;
}
}
- stub_entry->stub_sec->size += size;
+ stub_entry->group->stub_sec->size += size;
return TRUE;
}
int
ppc64_elf_setup_section_lists (struct bfd_link_info *info)
{
- bfd *input_bfd;
- int top_id, top_index, id;
- asection *section;
- asection **input_list;
+ unsigned int id;
bfd_size_type amt;
struct ppc_link_hash_table *htab = ppc_hash_table (info);
if (htab == NULL)
return -1;
- /* Find the top input section id. */
- for (input_bfd = info->input_bfds, top_id = 3;
- input_bfd != NULL;
- input_bfd = input_bfd->link.next)
- {
- for (section = input_bfd->sections;
- section != NULL;
- section = section->next)
- {
- if (top_id < section->id)
- top_id = section->id;
- }
- }
-
- htab->top_id = top_id;
- amt = sizeof (struct map_stub) * (top_id + 1);
- htab->stub_group = bfd_zmalloc (amt);
- if (htab->stub_group == NULL)
+ htab->sec_info_arr_size = bfd_get_next_section_id ();
+ amt = sizeof (*htab->sec_info) * (htab->sec_info_arr_size);
+ htab->sec_info = bfd_zmalloc (amt);
+ if (htab->sec_info == NULL)
return -1;
/* Set toc_off for com, und, abs and ind sections. */
for (id = 0; id < 3; id++)
- htab->stub_group[id].toc_off = TOC_BASE_OFF;
-
- /* We can't use output_bfd->section_count here to find the top output
- section index as some sections may have been removed, and
- strip_excluded_output_sections doesn't renumber the indices. */
- for (section = info->output_bfd->sections, top_index = 0;
- section != NULL;
- section = section->next)
- {
- if (top_index < section->index)
- top_index = section->index;
- }
-
- htab->top_index = top_index;
- amt = sizeof (asection *) * (top_index + 1);
- input_list = bfd_zmalloc (amt);
- htab->input_list = input_list;
- if (input_list == NULL)
- return -1;
+ htab->sec_info[id].toc_off = TOC_BASE_OFF;
return 1;
}
addr = (htab->toc_first_sec->output_offset
+ htab->toc_first_sec->output_section->vma);
htab->toc_curr = addr;
+ htab->toc_curr &= -TOC_BASE_ALIGN;
}
/* toc_curr is the base address of this toc group. Set elf_gp
htab->elf.irelplt->size += rel_size;
htab->got_reli_size += rel_size;
}
- else if (info->shared)
+ else if (bfd_link_pic (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size;
asection *s = ppc64_elf_tdata (ibfd)->got;
ent->got.offset = s->size;
s->size += 16;
- if (info->shared)
+ if (bfd_link_pic (info))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += sizeof (Elf64_External_Rela);
{
long adjust;
- adjust = opd->adjust[OPD_NDX (sym->st_value)];
+ adjust = opd->adjust[OPD_NDX (sym_value)];
if (adjust == -1)
/* Assume deleted functions won't ever be called. */
continue;
return FALSE;
if ((isec->output_section->flags & SEC_CODE) != 0
- && isec->output_section->index <= htab->top_index)
+ && isec->output_section->id < htab->sec_info_arr_size)
{
- asection **list = htab->input_list + isec->output_section->index;
- /* Steal the link_sec pointer for our list. */
-#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec)
/* This happens to make the list in reverse order,
which is what we want. */
- PREV_SEC (isec) = *list;
- *list = isec;
+ htab->sec_info[isec->id].u.list
+ = htab->sec_info[isec->output_section->id].u.list;
+ htab->sec_info[isec->output_section->id].u.list = isec;
}
if (htab->multi_toc_needed)
htab->toc_curr = elf_gp (isec->owner);
}
- htab->stub_group[isec->id].toc_off = htab->toc_curr;
+ htab->sec_info[isec->id].toc_off = htab->toc_curr;
return TRUE;
}
if (i->has_toc_reloc)
{
if (toc_off == 0)
- toc_off = htab->stub_group[i->id].toc_off;
- else if (toc_off != htab->stub_group[i->id].toc_off)
+ toc_off = htab->sec_info[i->id].toc_off;
+ else if (toc_off != htab->sec_info[i->id].toc_off)
return FALSE;
}
for (i = o->map_head.s; i != NULL; i = i->map_head.s)
if (i->makes_toc_func_call)
{
- toc_off = htab->stub_group[i->id].toc_off;
+ toc_off = htab->sec_info[i->id].toc_off;
break;
}
/* Make sure the whole pasted function uses the same toc offset. */
if (toc_off != 0)
for (i = o->map_head.s; i != NULL; i = i->map_head.s)
- htab->stub_group[i->id].toc_off = toc_off;
+ htab->sec_info[i->id].toc_off = toc_off;
}
return TRUE;
}
_init and _fini functions into multiple parts. Putting a stub in
the middle of a function is not a good idea. */
-static void
-group_sections (struct ppc_link_hash_table *htab,
+static bfd_boolean
+group_sections (struct bfd_link_info *info,
bfd_size_type stub_group_size,
bfd_boolean stubs_always_before_branch)
{
- asection **list;
+ struct ppc_link_hash_table *htab;
+ asection *osec;
bfd_size_type stub14_group_size;
bfd_boolean suppress_size_errors;
+ htab = ppc_hash_table (info);
+ if (htab == NULL)
+ return FALSE;
+
suppress_size_errors = FALSE;
stub14_group_size = stub_group_size >> 10;
if (stub_group_size == 1)
suppress_size_errors = TRUE;
}
- list = htab->input_list + htab->top_index;
- do
+ for (osec = info->output_bfd->sections; osec != NULL; osec = osec->next)
{
- asection *tail = *list;
+ asection *tail;
+
+ if (osec->id >= htab->sec_info_arr_size)
+ continue;
+
+ tail = htab->sec_info[osec->id].u.list;
while (tail != NULL)
{
asection *curr;
bfd_size_type total;
bfd_boolean big_sec;
bfd_vma curr_toc;
+ struct map_stub *group;
curr = tail;
total = tail->size;
if (big_sec && !suppress_size_errors)
(*_bfd_error_handler) (_("%B section %A exceeds stub group size"),
tail->owner, tail);
- curr_toc = htab->stub_group[tail->id].toc_off;
+ curr_toc = htab->sec_info[tail->id].toc_off;
- while ((prev = PREV_SEC (curr)) != NULL
+ while ((prev = htab->sec_info[curr->id].u.list) != NULL
&& ((total += curr->output_offset - prev->output_offset)
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
? stub14_group_size : stub_group_size))
- && htab->stub_group[prev->id].toc_off == curr_toc)
+ && htab->sec_info[prev->id].toc_off == curr_toc)
curr = prev;
/* OK, the size from the start of CURR to the end is less
only break if stubs added make the total size more than
2^25, ie. for the default stub_group_size, if stubs total
more than 2097152 bytes, or nearly 75000 plt call stubs. */
+ group = bfd_alloc (curr->owner, sizeof (*group));
+ if (group == NULL)
+ return FALSE;
+ group->link_sec = curr;
+ group->stub_sec = NULL;
do
{
- prev = PREV_SEC (tail);
+ prev = htab->sec_info[tail->id].u.list;
/* Set up this stub group. */
- htab->stub_group[tail->id].link_sec = curr;
+ htab->sec_info[tail->id].u.group = group;
}
while (tail != curr && (tail = prev) != NULL);
< (ppc64_elf_section_data (prev) != NULL
&& ppc64_elf_section_data (prev)->has_14bit_branch
? stub14_group_size : stub_group_size))
- && htab->stub_group[prev->id].toc_off == curr_toc)
+ && htab->sec_info[prev->id].toc_off == curr_toc)
{
tail = prev;
- prev = PREV_SEC (tail);
- htab->stub_group[tail->id].link_sec = curr;
+ prev = htab->sec_info[tail->id].u.list;
+ htab->sec_info[tail->id].u.group = group;
}
}
tail = prev;
}
}
- while (list-- != htab->input_list);
- free (htab->input_list);
-#undef PREV_SEC
+ return TRUE;
}
static const unsigned char glink_eh_frame_cie[] =
if (htab == NULL)
return FALSE;
- if (htab->params->plt_thread_safe == -1 && !info->executable)
+ if (htab->params->plt_thread_safe == -1 && !bfd_link_executable (info))
htab->params->plt_thread_safe = 1;
if (!htab->opd_abi)
htab->params->plt_thread_safe = 0;
else
stub_group_size = htab->params->group_size;
- group_sections (htab, stub_group_size, stubs_always_before_branch);
+ if (!group_sections (info, stub_group_size, stubs_always_before_branch))
+ return FALSE;
while (1)
{
fact a call needing a TOC adjustment. */
if (code_sec != NULL
&& code_sec->output_section != NULL
- && (htab->stub_group[code_sec->id].toc_off
- != htab->stub_group[section->id].toc_off)
+ && (htab->sec_info[code_sec->id].toc_off
+ != htab->sec_info[section->id].toc_off)
&& (code_sec->has_toc_reloc
|| code_sec->makes_toc_func_call))
stub_type = ppc_stub_long_branch_r2off;
stub_type = ppc_stub_plt_call_r2save;
/* Support for grouping stub sections. */
- id_sec = htab->stub_group[section->id].link_sec;
+ id_sec = htab->sec_info[section->id].u.group->link_sec;
/* Get the name of this stub. */
stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
ppc64_elf_set_toc (struct bfd_link_info *info, bfd *obfd)
{
asection *s;
- bfd_vma TOCstart;
+ bfd_vma TOCstart, adjust;
+
+ if (info != NULL)
+ {
+ struct elf_link_hash_entry *h;
+ struct elf_link_hash_table *htab = elf_hash_table (info);
+
+ if (is_elf_hash_table (htab)
+ && htab->hgot != NULL)
+ h = htab->hgot;
+ else
+ {
+ h = elf_link_hash_lookup (htab, ".TOC.", FALSE, FALSE, TRUE);
+ if (is_elf_hash_table (htab))
+ htab->hgot = h;
+ }
+ if (h != NULL
+ && h->root.type == bfd_link_hash_defined
+ && !h->root.linker_def
+ && (!is_elf_hash_table (htab)
+ || h->def_regular))
+ {
+ TOCstart = (h->root.u.def.value - TOC_BASE_OFF
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.section->output_section->vma);
+ _bfd_set_gp_value (obfd, TOCstart);
+ return TOCstart;
+ }
+ }
/* The TOC consists of sections .got, .toc, .tocbss, .plt in that
order. The TOC starts where the first of these sections starts. */
if (s != NULL)
TOCstart = s->output_section->vma + s->output_offset;
+ /* Force alignment. */
+ adjust = TOCstart & (TOC_BASE_ALIGN - 1);
+ TOCstart -= adjust;
_bfd_set_gp_value (obfd, TOCstart);
if (info != NULL && s != NULL)
{
if (htab->elf.hgot != NULL)
{
- htab->elf.hgot->root.u.def.value = TOC_BASE_OFF;
+ htab->elf.hgot->root.u.def.value = TOC_BASE_OFF - adjust;
htab->elf.hgot->root.u.def.section = s;
}
}
{
struct bfd_link_hash_entry *bh = NULL;
_bfd_generic_link_add_one_symbol (info, obfd, ".TOC.", BSF_GLOBAL,
- s, TOC_BASE_OFF, NULL, FALSE,
- FALSE, &bh);
+ s, TOC_BASE_OFF - adjust,
+ NULL, FALSE, FALSE, &bh);
}
}
return TOCstart;
h->ref_regular_nonweak = 1;
h->forced_local = 1;
h->non_elf = 0;
+ h->root.linker_def = 1;
}
}
h->ref_regular_nonweak = 1;
h->forced_local = 1;
h->non_elf = 0;
+ h->root.linker_def = 1;
}
}
plt0 = (htab->elf.splt->output_section->vma
ppc64_elf_howto_table[r_type], 0,
contents);
- if (info->relocatable)
+ if (bfd_link_relocatable (info))
continue;
if (h != NULL && &h->elf == htab->elf.hgot)
{
- relocation = (TOCstart
- + htab->stub_group[input_section->id].toc_off);
+ relocation = TOCstart + htab->sec_info[input_section->id].toc_off;
sec = bfd_abs_section_ptr;
unresolved_reloc = FALSE;
}
htab->tls_get_addr,
htab->tls_get_addr_fd))
offset = rel[1].r_offset;
+ /* We read the low GOT_TLS (or TOC16) insn because we
+ need to keep the destination reg. It may be
+ something other than the usual r3, and moved to r3
+ before the call by intervening code. */
+ insn1 = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
- insn1 &= (1 << 26) - (1 << 2);
+ insn1 &= (0x1f << 21) | (0x1f << 16);
insn1 |= 58 << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
if (offset != (bfd_vma) -1)
else
{
/* LE */
- insn1 = 0x3c6d0000; /* addis 3,13,0 */
+ insn1 &= 0x1f << 21;
+ insn1 |= 0x3c0d0000; /* addis r,13,0 */
insn2 = 0x38630000; /* addi 3,3,0 */
if (tls_gd == 0)
{
. lis 2,.TOC.@ha
. addi 2,2,.TOC.@l
if .TOC. is in range. */
- if (!info->shared
+ if (!bfd_link_pic (info)
&& !info->traditional_format
&& h != NULL && &h->elf == htab->elf.hgot
&& rel + 1 < relend
/* Munge up the value and addend so that we call the stub
rather than the procedure directly. */
relocation = (stub_entry->stub_offset
- + stub_entry->stub_sec->output_offset
- + stub_entry->stub_sec->output_section->vma);
+ + stub_entry->group->stub_sec->output_offset
+ + stub_entry->group->stub_sec->output_section->vma);
addend = 0;
reloc_dest = DEST_STUB;
if (h != NULL)
{
bfd_boolean dyn = htab->elf.dynamic_sections_created;
- if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared,
+ if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, bfd_link_pic (info),
&h->elf)
- || (info->shared
+ || (bfd_link_pic (info)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf)))
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
if (ifunc)
relgot = htab->elf.irelplt;
- else if ((info->shared || indx != 0)
+ else if ((bfd_link_pic (info) || indx != 0)
&& (h == NULL
|| (tls_type == (TLS_TLS | TLS_LD)
&& !h->elf.def_dynamic)
{
outrel.r_addend += relocation;
if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
- outrel.r_addend -= htab->elf.tls_sec->vma;
+ {
+ if (htab->elf.tls_sec == NULL)
+ outrel.r_addend = 0;
+ else
+ outrel.r_addend -= htab->elf.tls_sec->vma;
+ }
}
loc = relgot->contents;
loc += (relgot->reloc_count++
relocation = 1;
else if (tls_type != 0)
{
- relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
- if (tls_type == (TLS_TLS | TLS_TPREL))
- relocation += DTP_OFFSET - TP_OFFSET;
+ if (htab->elf.tls_sec == NULL)
+ relocation = 0;
+ else
+ {
+ relocation -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (tls_type == (TLS_TLS | TLS_TPREL))
+ relocation += DTP_OFFSET - TP_OFFSET;
+ }
if (tls_type == (TLS_TLS | TLS_GD))
{
abort ();
relocation = got->output_section->vma + got->output_offset + off;
- addend = -(TOCstart + htab->stub_group[input_section->id].toc_off);
+ addend = -(TOCstart + htab->sec_info[input_section->id].toc_off);
}
break;
/* Relocation value is TOC base. */
relocation = TOCstart;
if (r_symndx == STN_UNDEF)
- relocation += htab->stub_group[input_section->id].toc_off;
+ relocation += htab->sec_info[input_section->id].toc_off;
else if (unresolved_reloc)
;
- else if (sec != NULL && sec->id <= htab->top_id)
- relocation += htab->stub_group[sec->id].toc_off;
+ else if (sec != NULL && sec->id < htab->sec_info_arr_size)
+ relocation += htab->sec_info[sec->id].toc_off;
else
unresolved_reloc = TRUE;
goto dodyn;
case R_PPC64_TOC16_DS:
case R_PPC64_TOC16_LO_DS:
case R_PPC64_TOC16_HA:
- addend -= TOCstart + htab->stub_group[input_section->id].toc_off;
+ addend -= TOCstart + htab->sec_info[input_section->id].toc_off;
break;
/* Relocate against the beginning of the section. */
bfd_put_32 (output_bfd, insn, p);
break;
}
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
- if (info->shared)
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (bfd_link_pic (info))
/* The TPREL16 relocs shouldn't really be used in shared
libs as they will result in DT_TEXTREL being set, but
support them anyway. */
case R_PPC64_DTPREL16_HIGHERA:
case R_PPC64_DTPREL16_HIGHEST:
case R_PPC64_DTPREL16_HIGHESTA:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
case R_PPC64_ADDR64_LOCAL:
goto dodyn;
case R_PPC64_TPREL64:
- addend -= htab->elf.tls_sec->vma + TP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
goto dodyn;
case R_PPC64_DTPREL64:
- addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (htab->elf.tls_sec != NULL)
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
/* Fall thru */
/* Relocations that may need to be propagated if this is a
if (NO_OPD_RELOCS && is_opd)
break;
- if ((info->shared
+ if ((bfd_link_pic (info)
&& (h == NULL
|| ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|| h->elf.root.type != bfd_link_hash_undefweak)
&& (must_be_dyn_reloc (info, r_type)
|| !SYMBOL_CALLS_LOCAL (info, &h->elf)))
|| (ELIMINATE_COPY_RELOCS
- && !info->shared
+ && !bfd_link_pic (info)
&& h != NULL
&& h->elf.dynindx != -1
&& !h->elf.non_got_ref
&& !h->elf.def_regular)
- || (!info->shared
+ || (!bfd_link_pic (info)
&& (h != NULL
? h->elf.type == STT_GNU_IFUNC
: ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
if (r == bfd_reloc_overflow)
{
- if (warned)
- continue;
- if (h != NULL
- && h->elf.root.type == bfd_link_hash_undefweak
- && howto->pc_relative)
+ /* On code like "if (foo) foo();" don't report overflow
+ on a branch to zero when foo is undefined. */
+ if (!warned
+ && (reloc_dest == DEST_STUB
+ || !(h != NULL
+ && (h->elf.root.type == bfd_link_hash_undefweak
+ || h->elf.root.type == bfd_link_hash_undefined)
+ && is_branch_reloc (r_type))))
{
- /* Assume this is a call protected by other code that
- detects the symbol is undefined. If this is the case,
- we can safely ignore the overflow. If not, the
- program is hosed anyway, and a little warning isn't
- going to help. */
-
- continue;
+ if (!((*info->callbacks->reloc_overflow)
+ (info, &h->elf.root, sym_name,
+ reloc_name, orig_rel.r_addend,
+ input_bfd, input_section, rel->r_offset)))
+ return FALSE;
}
-
- if (!((*info->callbacks->reloc_overflow)
- (info, &h->elf.root, sym_name,
- reloc_name, orig_rel.r_addend,
- input_bfd, input_section, rel->r_offset)))
- return FALSE;
}
else
{
adjusted. Worse, reloc symbol indices will be for the output
file rather than the input. Save a copy of the relocs for
opd_entry_value. */
- if (is_opd && (info->emitrelocations || info->relocatable))
+ if (is_opd && (info->emitrelocations || bfd_link_relocatable (info)))
{
bfd_size_type amt;
amt = input_section->reloc_count * sizeof (Elf_Internal_Rela);
return 1;
value = elfsym->st_value - input_sec->output_offset;
- if (!info->relocatable)
+ if (!bfd_link_relocatable (info))
value -= input_sec->output_section->vma;
adjust = opd->adjust[OPD_NDX (value)];