static bfd_reloc_status_type ppc64_elf_unhandled_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_vma opd_entry_value
- (asection *, bfd_vma, asection **, bfd_vma *);
+ (asection *, bfd_vma, asection **, bfd_vma *, bfd_boolean);
#define TARGET_LITTLE_SYM bfd_elf64_powerpcle_vec
#define TARGET_LITTLE_NAME "elf64-powerpcle"
{
bfd_vma dest = opd_entry_value (symbol->section,
symbol->value + reloc_entry->addend,
- NULL, NULL);
+ NULL, NULL, FALSE);
if (dest != (bfd_vma) -1)
reloc_entry->addend = dest - (symbol->value
+ symbol->section->output_section->vma
slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
goto free_contents_and_exit;
-
+
plt_count = relplt->size / sizeof (Elf64_External_Rela);
size += plt_count * sizeof (asymbol);
struct ppc_link_hash_entry *tls_get_addr;
struct ppc_link_hash_entry *tls_get_addr_fd;
+ /* The special .TOC. symbol. */
+ struct ppc_link_hash_entry *dot_toc_dot;
+
/* The size of reliplt used by got entry relocs. */
bfd_size_type got_reli_size;
".eh_frame",
flags);
if (htab->glink_eh_frame == NULL
- || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2))
+ || !bfd_set_section_alignment (dynobj, htab->glink_eh_frame, 2))
return FALSE;
}
if (! _bfd_elf_create_got_section (htab->elf.dynobj, info))
return FALSE;
- htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got");
+ htab->got = bfd_get_linker_section (htab->elf.dynobj, ".got");
if (!htab->got)
abort ();
}
return FALSE;
if (!htab->got)
- htab->got = bfd_get_section_by_name (dynobj, ".got");
- htab->plt = bfd_get_section_by_name (dynobj, ".plt");
- htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt");
- htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss");
+ htab->got = bfd_get_linker_section (dynobj, ".got");
+ htab->plt = bfd_get_linker_section (dynobj, ".plt");
+ htab->relplt = bfd_get_linker_section (dynobj, ".rela.plt");
+ htab->dynbss = bfd_get_linker_section (dynobj, ".dynbss");
if (!info->shared)
- htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+ htab->relbss = bfd_get_linker_section (dynobj, ".rela.bss");
if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss
|| (!info->shared && !htab->relbss))
/* If we were called to copy over info for a weak sym, that's all.
You might think dyn_relocs need not be copied over; After all,
both syms will be dynamic or both non-dynamic so we're just
- moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
+ moving reloc accounting around. However, ELIMINATE_COPY_RELOCS
code in ppc64_elf_adjust_dynamic_symbol needs to check for
dyn_relocs in read-only sections, and it does so on what is the
DIR sym here. */
opd_entry_value (asection *opd_sec,
bfd_vma offset,
asection **code_sec,
- bfd_vma *code_off)
+ bfd_vma *code_off,
+ bfd_boolean in_code_sec)
{
bfd *opd_bfd = opd_sec->owner;
Elf_Internal_Rela *relocs;
if (code_sec != NULL)
{
asection *sec, *likely = NULL;
- for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
- if (sec->vma <= val
- && (sec->flags & SEC_LOAD) != 0
- && (sec->flags & SEC_ALLOC) != 0)
- likely = sec;
+
+ if (in_code_sec)
+ {
+ sec = *code_sec;
+ if (sec->vma <= val
+ && val < sec->vma + sec->size)
+ likely = sec;
+ else
+ val = -1;
+ }
+ else
+ for (sec = opd_bfd->sections; sec != NULL; sec = sec->next)
+ if (sec->vma <= val
+ && (sec->flags & SEC_LOAD) != 0
+ && (sec->flags & SEC_ALLOC) != 0)
+ likely = sec;
if (likely != NULL)
{
*code_sec = likely;
unsigned long symndx = ELF64_R_SYM (look->r_info);
asection *sec;
- if (symndx < symtab_hdr->sh_info)
+ if (symndx < symtab_hdr->sh_info
+ || elf_sym_hashes (opd_bfd) == NULL)
{
Elf_Internal_Sym *sym;
sym = (Elf_Internal_Sym *) symtab_hdr->contents;
if (sym == NULL)
{
- sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr,
- symtab_hdr->sh_info,
+ size_t symcnt = symtab_hdr->sh_info;
+ if (elf_sym_hashes (opd_bfd) == NULL)
+ symcnt = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
+ sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, symcnt,
0, NULL, NULL, NULL);
if (sym == NULL)
break;
if (code_off != NULL)
*code_off = val;
if (code_sec != NULL)
- *code_sec = sec;
+ {
+ if (in_code_sec && *code_sec != sec)
+ return -1;
+ else
+ *code_sec = sec;
+ }
if (sec != NULL && sec->output_section != NULL)
val += sec->output_section->vma + sec->output_offset;
}
return val;
}
-/* Return TRUE iff the ELF symbol SYM might be a function. Set *CODE_SEC
- and *CODE_OFF to the function's entry point. */
+/* If the ELF symbol SYM might be a function in SEC, return the
+ function size and set *CODE_OFF to the function's entry point,
+ otherwise return zero. */
-static bfd_boolean
-ppc64_elf_maybe_function_sym (const asymbol *sym,
- asection **code_sec, bfd_vma *code_off)
+static bfd_size_type
+ppc64_elf_maybe_function_sym (const asymbol *sym, asection *sec,
+ bfd_vma *code_off)
{
- if (_bfd_elf_maybe_function_sym (sym, code_sec, code_off))
+ bfd_size_type size;
+
+ if ((sym->flags & (BSF_SECTION_SYM | BSF_FILE | BSF_OBJECT
+ | BSF_THREAD_LOCAL | BSF_RELC | BSF_SRELC)) != 0)
+ return 0;
+
+ size = 0;
+ if (!(sym->flags & BSF_SYNTHETIC))
+ size = ((elf_symbol_type *) sym)->internal_elf_sym.st_size;
+
+ if (strcmp (sym->section->name, ".opd") == 0)
{
- if (strcmp (sym->section->name, ".opd") == 0)
- opd_entry_value (sym->section, sym->value, code_sec, code_off);
- return TRUE;
+ if (opd_entry_value (sym->section, sym->value,
+ &sec, code_off, TRUE) == (bfd_vma) -1)
+ return 0;
+ /* An old ABI binary with dot-syms has a size of 24 on the .opd
+ symbol. This size has nothing to do with the code size of the
+ function, which is what we're supposed to return, but the
+ code size isn't available without looking up the dot-sym.
+ However, doing that would be a waste of time particularly
+ since elf_find_function will look at the dot-sym anyway.
+ Now, elf_find_function will keep the largest size of any
+ function sym found at the code address of interest, so return
+ 1 here to avoid it incorrectly caching a larger function size
+ for a small function. This does mean we return the wrong
+ size for a new-ABI function of size 24, but all that does is
+ disable caching for such functions. */
+ if (size == 24)
+ size = 1;
}
- return FALSE;
+ else
+ {
+ if (sym->section != sec)
+ return 0;
+ *code_off = sym->value;
+ }
+ if (size == 0)
+ size = 1;
+ return size;
}
/* Return true if symbol is defined in a regular object file. */
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
&& opd_entry_value (eh->elf.root.u.def.section,
eh->elf.root.u.def.value,
- &sec, NULL) != (bfd_vma) -1)
+ &sec, NULL, FALSE) != (bfd_vma) -1)
sec->flags |= SEC_KEEP;
sec = eh->elf.root.u.def.section;
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
&& opd_entry_value (eh->elf.root.u.def.section,
eh->elf.root.u.def.value,
- &code_sec, NULL) != (bfd_vma) -1)
+ &code_sec, NULL, FALSE) != (bfd_vma) -1)
code_sec->flags |= SEC_KEEP;
}
else if (get_opd_info (eh->elf.root.u.def.section) != NULL
&& opd_entry_value (eh->elf.root.u.def.section,
eh->elf.root.u.def.value,
- &rsec, NULL) != (bfd_vma) -1)
+ &rsec, NULL, FALSE) != (bfd_vma) -1)
eh->elf.root.u.def.section->gc_mark = 1;
else
rsec = h->root.u.def.section;
&& opd_entry_value (fdh->elf.root.u.def.section,
fdh->elf.root.u.def.value,
&fh->elf.root.u.def.section,
- &fh->elf.root.u.def.value) != (bfd_vma) -1)
+ &fh->elf.root.u.def.value, FALSE) != (bfd_vma) -1)
{
fh->elf.root.type = fdh->elf.root.type;
fh->elf.forced_local = 1;
{
struct ppc_link_hash_table *htab;
unsigned int i;
- const struct sfpr_def_parms funcs[] =
+ static const struct sfpr_def_parms funcs[] =
{
{ "_savegpr0_", 14, 31, savegpr0, savegpr0_tail },
{ "_restgpr0_", 14, 29, restgpr0, restgpr0_tail },
/* Provide any missing _save* and _rest* functions. */
htab->sfpr->size = 0;
- for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
- if (!sfpr_define (info, &funcs[i]))
- return FALSE;
+ if (!info->relocatable)
+ for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++)
+ if (!sfpr_define (info, &funcs[i]))
+ return FALSE;
elf_link_hash_traverse (&htab->elf, func_desc_adjust, info);
if (dsec == NULL)
{
for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next)
- if (elf_discarded_section (dsec))
+ if (discarded_section (dsec))
{
ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec;
break;
if (sec == NULL || sec->size == 0)
continue;
- if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS)
+ if (sec->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
continue;
if (sec->output_section == bfd_abs_section_ptr)
toc = bfd_get_section_by_name (ibfd, ".toc");
if (toc == NULL
|| toc->size == 0
- || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS
- || elf_discarded_section (toc))
+ || toc->sec_info_type == SEC_INFO_TYPE_JUST_SYMS
+ || discarded_section (toc))
continue;
toc_relocs = NULL;
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
if (sec->reloc_count == 0
- || !elf_discarded_section (sec)
+ || !discarded_section (sec)
|| get_opd_info (sec)
|| (sec->flags & SEC_ALLOC) == 0
|| (sec->flags & SEC_DEBUGGING) != 0)
. addi ry,rx,addr@toc@l
when addr is within 2G of the toc pointer. This then means
that the word storing "addr" in the toc is no longer needed. */
-
+
if (!ppc64_elf_tdata (ibfd)->has_small_toc_reloc
&& toc->output_section->rawsize < (bfd_vma) 1 << 31
&& toc->reloc_count != 0)
goto error_ret;
if (sym_sec == NULL
- || elf_discarded_section (sym_sec))
+ || discarded_section (sym_sec))
continue;
if (!SYMBOL_CALLS_LOCAL (info, h))
int repeat;
if (sec->reloc_count == 0
- || elf_discarded_section (sec)
+ || discarded_section (sec)
|| get_opd_info (sec)
|| (sec->flags & SEC_ALLOC) == 0
|| (sec->flags & SEC_DEBUGGING) != 0)
goto error_ret;
/* Mark toc entries referenced as used. */
- repeat = 0;
do
- for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
- {
- enum elf_ppc64_reloc_type r_type;
- unsigned long r_symndx;
- asection *sym_sec;
- struct elf_link_hash_entry *h;
- Elf_Internal_Sym *sym;
- bfd_vma val;
- enum {no_check, check_lo, check_ha} insn_check;
-
- r_type = ELF64_R_TYPE (rel->r_info);
- switch (r_type)
- {
- default:
- insn_check = no_check;
- break;
+ {
+ repeat = 0;
+ for (rel = relstart; rel < relstart + sec->reloc_count; ++rel)
+ {
+ enum elf_ppc64_reloc_type r_type;
+ unsigned long r_symndx;
+ asection *sym_sec;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+ bfd_vma val;
+ enum {no_check, check_lo, check_ha} insn_check;
- case R_PPC64_GOT_TLSLD16_HA:
- case R_PPC64_GOT_TLSGD16_HA:
- case R_PPC64_GOT_TPREL16_HA:
- case R_PPC64_GOT_DTPREL16_HA:
- case R_PPC64_GOT16_HA:
- case R_PPC64_TOC16_HA:
- insn_check = check_ha;
- break;
+ r_type = ELF64_R_TYPE (rel->r_info);
+ switch (r_type)
+ {
+ default:
+ insn_check = no_check;
+ break;
- case R_PPC64_GOT_TLSLD16_LO:
- case R_PPC64_GOT_TLSGD16_LO:
- case R_PPC64_GOT_TPREL16_LO_DS:
- case R_PPC64_GOT_DTPREL16_LO_DS:
- case R_PPC64_GOT16_LO:
- case R_PPC64_GOT16_LO_DS:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_LO_DS:
- insn_check = check_lo;
- break;
- }
+ case R_PPC64_GOT_TLSLD16_HA:
+ case R_PPC64_GOT_TLSGD16_HA:
+ case R_PPC64_GOT_TPREL16_HA:
+ case R_PPC64_GOT_DTPREL16_HA:
+ case R_PPC64_GOT16_HA:
+ case R_PPC64_TOC16_HA:
+ insn_check = check_ha;
+ break;
- if (insn_check != no_check)
- {
- bfd_vma off = rel->r_offset & ~3;
- unsigned char buf[4];
- unsigned int insn;
+ case R_PPC64_GOT_TLSLD16_LO:
+ case R_PPC64_GOT_TLSGD16_LO:
+ case R_PPC64_GOT_TPREL16_LO_DS:
+ case R_PPC64_GOT_DTPREL16_LO_DS:
+ case R_PPC64_GOT16_LO:
+ case R_PPC64_GOT16_LO_DS:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_LO_DS:
+ insn_check = check_lo;
+ break;
+ }
- if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
- {
- free (used);
- goto error_ret;
- }
- insn = bfd_get_32 (ibfd, buf);
- if (insn_check == check_lo
- ? !ok_lo_toc_insn (insn)
- : ((insn & ((0x3f << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
- {
- char str[12];
+ if (insn_check != no_check)
+ {
+ bfd_vma off = rel->r_offset & ~3;
+ unsigned char buf[4];
+ unsigned int insn;
- ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
- sprintf (str, "%#08x", insn);
- info->callbacks->einfo
- (_("%P: %H: toc optimization is not supported for"
- " %s instruction.\n"),
- ibfd, sec, rel->r_offset & ~3, str);
- }
- }
+ if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
+ {
+ free (used);
+ goto error_ret;
+ }
+ insn = bfd_get_32 (ibfd, buf);
+ if (insn_check == check_lo
+ ? !ok_lo_toc_insn (insn)
+ : ((insn & ((0x3f << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
+ {
+ char str[12];
- switch (r_type)
- {
- case R_PPC64_TOC16:
- case R_PPC64_TOC16_LO:
- case R_PPC64_TOC16_HI:
- case R_PPC64_TOC16_HA:
- case R_PPC64_TOC16_DS:
- case R_PPC64_TOC16_LO_DS:
- /* In case we're taking addresses of toc entries. */
- case R_PPC64_ADDR64:
- break;
+ ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
+ sprintf (str, "%#08x", insn);
+ info->callbacks->einfo
+ (_("%P: %H: toc optimization is not supported for"
+ " %s instruction.\n"),
+ ibfd, sec, rel->r_offset & ~3, str);
+ }
+ }
- default:
- continue;
- }
+ switch (r_type)
+ {
+ case R_PPC64_TOC16:
+ case R_PPC64_TOC16_LO:
+ case R_PPC64_TOC16_HI:
+ case R_PPC64_TOC16_HA:
+ case R_PPC64_TOC16_DS:
+ case R_PPC64_TOC16_LO_DS:
+ /* In case we're taking addresses of toc entries. */
+ case R_PPC64_ADDR64:
+ break;
- r_symndx = ELF64_R_SYM (rel->r_info);
- if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
- r_symndx, ibfd))
- {
- free (used);
- goto error_ret;
- }
+ default:
+ continue;
+ }
- if (sym_sec != toc)
- continue;
+ r_symndx = ELF64_R_SYM (rel->r_info);
+ if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms,
+ r_symndx, ibfd))
+ {
+ free (used);
+ goto error_ret;
+ }
- if (h != NULL)
- val = h->root.u.def.value;
- else
- val = sym->st_value;
- val += rel->r_addend;
+ if (sym_sec != toc)
+ continue;
- if (val >= toc->size)
- continue;
+ if (h != NULL)
+ val = h->root.u.def.value;
+ else
+ val = sym->st_value;
+ val += rel->r_addend;
- if ((skip[val >> 3] & can_optimize) != 0)
- {
- bfd_vma off;
- unsigned char opc;
+ if (val >= toc->size)
+ continue;
- switch (r_type)
- {
- case R_PPC64_TOC16_HA:
- break;
+ if ((skip[val >> 3] & can_optimize) != 0)
+ {
+ bfd_vma off;
+ unsigned char opc;
- case R_PPC64_TOC16_LO_DS:
- off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
- if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
- {
- free (used);
- goto error_ret;
- }
- if ((opc & (0x3f << 2)) == (58u << 2))
+ switch (r_type)
+ {
+ case R_PPC64_TOC16_HA:
break;
- /* Fall thru */
- default:
- /* Wrong sort of reloc, or not a ld. We may
- as well clear ref_from_discarded too. */
- skip[val >> 3] = 0;
- }
- }
+ case R_PPC64_TOC16_LO_DS:
+ off = rel->r_offset;
+ off += (bfd_big_endian (ibfd) ? -2 : 3);
+ if (!bfd_get_section_contents (ibfd, sec, &opc,
+ off, 1))
+ {
+ free (used);
+ goto error_ret;
+ }
+ if ((opc & (0x3f << 2)) == (58u << 2))
+ break;
+ /* Fall thru */
- /* For the toc section, we only mark as used if
- this entry itself isn't unused. */
- if (sec == toc
- && !used[val >> 3]
- && (used[rel->r_offset >> 3]
- || !(skip[rel->r_offset >> 3] & ref_from_discarded)))
- /* Do all the relocs again, to catch reference
- chains. */
- repeat = 1;
-
- used[val >> 3] = 1;
- }
+ default:
+ /* Wrong sort of reloc, or not a ld. We may
+ as well clear ref_from_discarded too. */
+ skip[val >> 3] = 0;
+ }
+ }
+
+ if (sec != toc)
+ used[val >> 3] = 1;
+ /* For the toc section, we only mark as used if this
+ entry itself isn't unused. */
+ else if ((used[rel->r_offset >> 3]
+ || !(skip[rel->r_offset >> 3] & ref_from_discarded))
+ && !used[val >> 3])
+ {
+ /* Do all the relocs again, to catch reference
+ chains. */
+ repeat = 1;
+ used[val >> 3] = 1;
+ }
+ }
+ }
while (repeat);
if (elf_section_data (sec)->relocs != relstart)
for (sec = ibfd->sections; sec != NULL; sec = sec->next)
{
if (sec->reloc_count == 0
- || elf_discarded_section (sec))
+ || discarded_section (sec))
continue;
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
{
- s = bfd_get_section_by_name (dynobj, ".interp");
+ s = bfd_get_linker_section (dynobj, ".interp");
if (s == NULL)
abort ();
s->size = sizeof ELF_DYNAMIC_INTERPRETER;
bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
bfd_vma to, from;
- if (pltindex > 32767)
- glinkoff += (pltindex - 32767) * 4;
+ if (pltindex > 32768)
+ glinkoff += (pltindex - 32768) * 4;
to = (glinkoff
+ htab->glink->output_offset
+ htab->glink->output_section->vma);
if (!htab->second_toc_pass)
{
/* Keep track of the first .toc or .got section for this input bfd. */
- if (htab->toc_bfd != isec->owner)
+ bfd_boolean new_bfd = htab->toc_bfd != isec->owner;
+
+ if (new_bfd)
{
htab->toc_bfd = isec->owner;
htab->toc_first_sec = isec;
/* Die if someone uses a linker script that doesn't keep input
file .toc and .got together. */
- if (elf_gp (isec->owner) != 0
+ if (new_bfd
+ && elf_gp (isec->owner) != 0
&& elf_gp (isec->owner) != off)
return FALSE;
sym_value += adjust;
}
- dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL);
+ dest = opd_entry_value (sym_sec, sym_value,
+ &sym_sec, NULL, FALSE);
if (dest == (bfd_vma) -1)
continue;
}
{
if (isec->size == 0
&& isec->output_section->size == 0
+ && !(isec->output_section->flags & SEC_KEEP)
&& !bfd_section_removed_from_list (info->output_bfd,
isec->output_section)
&& elf_section_data (isec->output_section)->dynindx == 0)
"GOMP_parallel_loop_dynamic_start",
"GOMP_parallel_loop_guided_start",
"GOMP_parallel_loop_runtime_start",
- "GOMP_parallel_sections_start",
+ "GOMP_parallel_sections_start",
};
unsigned i;
}
}
htab->plt_thread_safe = plt_thread_safe;
+ htab->dot_toc_dot = ((struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, ".TOC.",
+ FALSE, FALSE, TRUE));
stubs_always_before_branch = group_size < 0;
if (group_size < 0)
stub_group_size = -group_size;
sym_value += adjust;
}
dest = opd_entry_value (sym_sec, sym_value,
- &code_sec, &code_value);
+ &code_sec, &code_value, FALSE);
if (dest != (bfd_vma) -1)
{
destination = dest;
if (htab->glink_eh_frame != NULL
&& !bfd_is_abs_section (htab->glink_eh_frame->output_section)
- && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0)
+ && htab->glink_eh_frame->output_section->size != 0)
{
- bfd_size_type size = 0;
+ size_t size = 0, align;
for (stub_sec = htab->stub_bfd->sections;
stub_sec != NULL;
size += 24;
if (size != 0)
size += sizeof (glink_eh_frame_cie);
+ align = 1;
+ align <<= htab->glink_eh_frame->output_section->alignment_power;
+ align -= 1;
+ size = (size + align) & ~align;
htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
htab->glink_eh_frame->size = size;
}
&& htab->glink_eh_frame->size != 0)
{
bfd_vma val;
+ bfd_byte *last_fde;
+ size_t last_fde_len, size, align, pad;
p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size);
if (p == NULL)
return FALSE;
htab->glink_eh_frame->contents = p;
+ last_fde = p;
htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie));
/* CIE length (rewrite in case little-endian). */
- bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p);
+ last_fde_len = sizeof (glink_eh_frame_cie) - 4;
+ bfd_put_32 (htab->elf.dynobj, last_fde_len, p);
p += sizeof (glink_eh_frame_cie);
for (stub_sec = htab->stub_bfd->sections;
stub_sec = stub_sec->next)
if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
{
+ last_fde = p;
+ last_fde_len = 16;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 16, p);
p += 4;
}
if (htab->glink != NULL && htab->glink->size != 0)
{
+ last_fde = p;
+ last_fde_len = 20;
/* FDE length. */
bfd_put_32 (htab->elf.dynobj, 20, p);
p += 4;
*p++ = DW_CFA_restore_extended;
*p++ = 65;
}
- htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents;
+ /* Subsume any padding into the last FDE if user .eh_frame
+ sections are aligned more than glink_eh_frame. Otherwise any
+ zero padding will be seen as a terminator. */
+ size = p - htab->glink_eh_frame->contents;
+ align = 1;
+ align <<= htab->glink_eh_frame->output_section->alignment_power;
+ align -= 1;
+ pad = ((size + align) & ~align) - size;
+ htab->glink_eh_frame->size = size + pad;
+ bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde);
}
/* Build the stubs as directed by the stub hash table. */
for (; rel < relend; rel++)
{
enum elf_ppc64_reloc_type r_type;
- bfd_vma addend, orig_addend;
+ bfd_vma addend;
bfd_reloc_status_type r;
Elf_Internal_Sym *sym;
asection *sec;
struct ppc_stub_hash_entry *stub_entry;
bfd_vma max_br_offset;
bfd_vma from;
+ const Elf_Internal_Rela orig_rel = *rel;
r_type = ELF64_R_TYPE (rel->r_info);
r_symndx = ELF64_R_SYM (rel->r_info);
sym_name = NULL;
unresolved_reloc = FALSE;
warned = FALSE;
- orig_addend = rel->r_addend;
if (r_symndx < symtab_hdr->sh_info)
{
unresolved_reloc, warned);
sym_name = h_elf->root.root.string;
sym_type = h_elf->type;
+ if (sec != NULL
+ && sec->owner == output_bfd
+ && strcmp (sec->name, ".opd") == 0)
+ {
+ /* This is a symbol defined in a linker script. All
+ such are defined in output sections, even those
+ defined by simple assignment from a symbol defined in
+ an input section. Transfer the symbol to an
+ appropriate input .opd section, so that a branch to
+ this symbol will be mapped to the location specified
+ by the opd entry. */
+ struct bfd_link_order *lo;
+ for (lo = sec->map_head.link_order; lo != NULL; lo = lo->next)
+ if (lo->type == bfd_indirect_link_order)
+ {
+ asection *isec = lo->u.indirect.section;
+ if (h_elf->root.u.def.value >= isec->output_offset
+ && h_elf->root.u.def.value < (isec->output_offset
+ + isec->size))
+ {
+ h_elf->root.u.def.value -= isec->output_offset;
+ h_elf->root.u.def.section = isec;
+ sec = isec;
+ break;
+ }
+ }
+ }
+ if (h_elf == &htab->dot_toc_dot->elf)
+ {
+ relocation = (TOCstart
+ + htab->stub_group[input_section->id].toc_off);
+ sec = bfd_abs_section_ptr;
+ unresolved_reloc = FALSE;
+ }
}
h = (struct ppc_link_hash_entry *) h_elf;
- if (sec != NULL && elf_discarded_section (sec))
+ if (sec != NULL && discarded_section (sec))
RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
- rel, relend,
- ppc64_elf_howto_table[r_type],
+ rel, 1, relend,
+ ppc64_elf_howto_table[r_type], 0,
contents);
if (info->relocatable)
&& h->oh != NULL
&& h->oh->is_func_descriptor)
fdh = ppc_follow_link (h->oh);
- stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
+ stub_entry = ppc_get_stub_entry (input_section, sec, fdh, &orig_rel,
+ htab);
if (stub_entry != NULL
&& (stub_entry->stub_type == ppc_stub_plt_call
|| stub_entry->stub_type == ppc_stub_plt_call_r2save
bfd_vma off = (relocation + addend
- sec->output_section->vma
- sec->output_offset);
- bfd_vma dest = opd_entry_value (sec, off, NULL, NULL);
+ bfd_vma dest = opd_entry_value (sec, off, NULL, NULL, FALSE);
if (dest != (bfd_vma) -1)
{
relocation = dest;
;
else
{
+ BFD_ASSERT (h->elf.dynindx != -1);
indx = h->elf.dynindx;
unresolved_reloc = FALSE;
}
}
for (; ent != NULL; ent = ent->next)
- if (ent->addend == orig_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->owner == input_bfd
&& ent->tls_type == tls_type)
break;
{
struct plt_entry *ent;
for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next)
- if (ent->addend == orig_addend
+ if (ent->addend == orig_rel.r_addend
&& ent->plt.offset != (bfd_vma) -1)
{
relocation = (htab->plt->output_section->vma
else if (!SYMBOL_CALLS_LOCAL (info, &h->elf)
&& !is_opd
&& r_type != R_PPC64_TOC)
- outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+ {
+ BFD_ASSERT (h->elf.dynindx != -1);
+ outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type);
+ }
else
{
/* This symbol is local, or marked to become local,
if (!((*info->callbacks->reloc_overflow)
(info, (h ? &h->elf.root : NULL), sym_name,
ppc64_elf_howto_table[r_type]->name,
- orig_addend, input_bfd, input_section, rel->r_offset)))
+ orig_rel.r_addend, input_bfd, input_section,
+ rel->r_offset)))
return FALSE;
}
else
ppc64_elf_finish_dynamic_symbol (bfd *output_bfd,
struct bfd_link_info *info,
struct elf_link_hash_entry *h,
- Elf_Internal_Sym *sym)
+ Elf_Internal_Sym *sym ATTRIBUTE_UNUSED)
{
struct ppc_link_hash_table *htab;
struct plt_entry *ent;
bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
}
- /* Mark some specially defined symbols as absolute. */
- if (strcmp (h->root.root.string, "_DYNAMIC") == 0)
- sym->st_shndx = SHN_ABS;
-
return TRUE;
}
return FALSE;
dynobj = htab->elf.dynobj;
- sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+ sdyn = bfd_get_linker_section (dynobj, ".dynamic");
if (htab->elf.dynamic_sections_created)
{
if (htab->glink_eh_frame != NULL
- && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME
+ && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME
&& !_bfd_elf_write_section_eh_frame (output_bfd, info,
htab->glink_eh_frame,
htab->glink_eh_frame->contents))