aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog12
-rw-r--r--bfd/elf64-ppc.c106
-rw-r--r--ld/testsuite/ChangeLog7
-rw-r--r--ld/testsuite/ld-powerpc/ambiguousv1.d12
-rw-r--r--ld/testsuite/ld-powerpc/ambiguousv2.d12
-rw-r--r--ld/testsuite/ld-powerpc/funref.s4
-rw-r--r--ld/testsuite/ld-powerpc/funv1.s10
-rw-r--r--ld/testsuite/ld-powerpc/funv2.s6
-rw-r--r--ld/testsuite/ld-powerpc/powerpc.exp4
-rw-r--r--ld/testsuite/ld-powerpc/startv1.s8
-rw-r--r--ld/testsuite/ld-powerpc/startv2.s5
11 files changed, 143 insertions, 43 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index c719d24..0193553 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,15 @@
+2014-03-26 Alan Modra <amodra@gmail.com>
+
+ * elf64-ppc.c (ppc64_elf_check_relocs): Account for possibly
+ needed plt entries when taking the address of functions for
+ abiversion == 0 (ie. unknown) as well as abiversion == 2.
+ Move opd setup and abiversion checks to..
+ (ppc64_elf_before_check_relocs): ..here. Renamed from
+ ppc64_elf_process_dot_syms. Set output abiversion from input and
+ input abiversion from output, if either is not set.
+ (ppc64_elf_merge_private_bfd_data): Don't merge flags here.
+ (elf_backend_check_directives): Update.
+
2014-03-25 Will Newton <will.newton@linaro.org>
* elfnn-aarch64.c (elfNN_aarch64_finish_dynamic_sections):
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c
index 74c6e25..8d965f0 100644
--- a/bfd/elf64-ppc.c
+++ b/bfd/elf64-ppc.c
@@ -95,7 +95,7 @@ static bfd_vma opd_entry_value
#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections
#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol
#define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook
-#define elf_backend_check_directives ppc64_elf_process_dot_syms
+#define elf_backend_check_directives ppc64_elf_before_check_relocs
#define elf_backend_notice_as_needed ppc64_elf_notice_as_needed
#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup
#define elf_backend_check_relocs ppc64_elf_check_relocs
@@ -3953,7 +3953,7 @@ struct ppc_link_hash_table
/* Set on error. */
unsigned int stub_error:1;
- /* Temp used by ppc64_elf_process_dot_syms. */
+ /* Temp used by ppc64_elf_before_check_relocs. */
unsigned int twiddled_syms:1;
/* Incremented every time we size stubs. */
@@ -4930,10 +4930,11 @@ add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info)
return TRUE;
}
-/* Process list of dot-symbols we made in link_hash_newfunc. */
+/* Set up opd section info and abiversion for IBFD, and process list
+ of dot-symbols we made in link_hash_newfunc. */
static bfd_boolean
-ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
+ppc64_elf_before_check_relocs (bfd *ibfd, struct bfd_link_info *info)
{
struct ppc_link_hash_table *htab;
struct ppc_link_hash_entry **p, *eh;
@@ -4946,6 +4947,57 @@ ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
if (is_ppc64_elf (ibfd))
{
+ asection *opd = bfd_get_section_by_name (ibfd, ".opd");
+
+ if (opd != NULL && opd->size != 0)
+ {
+ if (abiversion (ibfd) == 0)
+ set_abiversion (ibfd, 1);
+ else if (abiversion (ibfd) == 2)
+ {
+ info->callbacks->einfo (_("%P: %B .opd not allowed in ABI"
+ " version %d\n"),
+ ibfd, abiversion (ibfd));
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ if ((ibfd->flags & DYNAMIC) == 0
+ && (opd->flags & SEC_RELOC) != 0
+ && opd->reloc_count != 0
+ && !bfd_is_abs_section (opd->output_section))
+ {
+ /* Garbage collection needs some extra help with .opd sections.
+ We don't want to necessarily keep everything referenced by
+ relocs in .opd, as that would keep all functions. Instead,
+ if we reference an .opd symbol (a function descriptor), we
+ want to keep the function code symbol's section. This is
+ easy for global symbols, but for local syms we need to keep
+ information about the associated function section. */
+ bfd_size_type amt;
+ asection **opd_sym_map;
+
+ amt = opd->size * sizeof (*opd_sym_map) / 8;
+ opd_sym_map = bfd_zalloc (ibfd, amt);
+ if (opd_sym_map == NULL)
+ return FALSE;
+ ppc64_elf_section_data (opd)->u.opd.func_sec = opd_sym_map;
+ BFD_ASSERT (ppc64_elf_section_data (opd)->sec_type == sec_normal);
+ ppc64_elf_section_data (opd)->sec_type = sec_opd;
+ }
+ }
+
+ /* For input files without an explicit abiversion in e_flags
+ we should have flagged any with symbol st_other bits set
+ as ELFv1 and above flagged those with .opd as ELFv2.
+ Set the output abiversion if not yet set, and for any input
+ still ambiguous, take its abiversion from the output.
+ Differences in ABI are reported later. */
+ if (abiversion (info->output_bfd) == 0)
+ set_abiversion (info->output_bfd, abiversion (ibfd));
+ else if (abiversion (ibfd) == 0)
+ set_abiversion (ibfd, abiversion (info->output_bfd));
+
p = &htab->dot_syms;
while ((eh = *p) != NULL)
{
@@ -5149,34 +5201,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
sym_hashes = elf_sym_hashes (abfd);
sreloc = NULL;
opd_sym_map = NULL;
- if (strcmp (sec->name, ".opd") == 0)
- {
- /* Garbage collection needs some extra help with .opd sections.
- We don't want to necessarily keep everything referenced by
- relocs in .opd, as that would keep all functions. Instead,
- if we reference an .opd symbol (a function descriptor), we
- want to keep the function code symbol's section. This is
- easy for global symbols, but for local syms we need to keep
- information about the associated function section. */
- bfd_size_type amt;
-
- if (abiversion (abfd) == 0)
- set_abiversion (abfd, 1);
- else if (abiversion (abfd) == 2)
- {
- info->callbacks->einfo (_("%P: .opd not allowed in ABI version %d\n"),
- abiversion (abfd));
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
- }
- amt = sec->size * sizeof (*opd_sym_map) / 8;
- opd_sym_map = bfd_zalloc (abfd, amt);
- if (opd_sym_map == NULL)
- return FALSE;
- ppc64_elf_section_data (sec)->u.opd.func_sec = opd_sym_map;
- BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal);
- ppc64_elf_section_data (sec)->sec_type = sec_opd;
- }
+ if (ppc64_elf_section_data (sec) != NULL
+ && ppc64_elf_section_data (sec)->sec_type == sec_opd)
+ opd_sym_map = ppc64_elf_section_data (sec)->u.opd.func_sec;
rel_end = relocs + sec->reloc_count;
for (rel = relocs; rel < rel_end; rel++)
@@ -5350,7 +5377,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
/* We may also need a plt entry if the symbol turns out to be
an ifunc. */
- if (h != NULL && !info->shared && abiversion (abfd) == 2)
+ if (h != NULL && !info->shared && abiversion (abfd) != 1)
{
if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
return FALSE;
@@ -5634,7 +5661,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_ADDR16_HIGHESTA:
case R_PPC64_ADDR16_LO:
case R_PPC64_ADDR16_LO_DS:
- if (h != NULL && !info->shared && abiversion (abfd) == 2
+ if (h != NULL && !info->shared && abiversion (abfd) != 1
&& rel->r_addend == 0)
{
/* We may need a .plt entry if this reloc refers to a
@@ -5808,21 +5835,14 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
iflags = elf_elfheader (ibfd)->e_flags;
oflags = elf_elfheader (obfd)->e_flags;
- if (!elf_flags_init (obfd) || oflags == 0)
- {
- elf_flags_init (obfd) = TRUE;
- elf_elfheader (obfd)->e_flags = iflags;
- }
- else if (iflags == oflags || iflags == 0)
- ;
- else if (iflags & ~EF_PPC64_ABI)
+ if (iflags & ~EF_PPC64_ABI)
{
(*_bfd_error_handler)
(_("%B uses unknown e_flags 0x%lx"), ibfd, iflags);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
- else
+ else if (iflags != oflags && iflags != 0)
{
(*_bfd_error_handler)
(_("%B: ABI version %ld is not compatible with ABI version %ld output"),
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index d200277..279958e 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2014-03-26 Alan Modra <amodra@gmail.com>
+
+ * ld-powerpc/startv1.s, * ld-powerpc/startv2.s, * ld-powerpc/funref.s,
+ * ld-powerpc/funv1.s, * ld-powerpc/funv2.s,
+ * ld-powerpc/ambiguousv1.d, * ld-powerpc/ambiguousv2.d: New test files.
+ * ld-powerpc/powerpc.exp: Run new tests.
+
2014-03-25 Will Newton <will.newton@linaro.org>
* ld-aarch64/aarch64-elf.exp: Add relasz dump test.
diff --git a/ld/testsuite/ld-powerpc/ambiguousv1.d b/ld/testsuite/ld-powerpc/ambiguousv1.d
new file mode 100644
index 0000000..73beab9
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ambiguousv1.d
@@ -0,0 +1,12 @@
+#source: startv1.s
+#source: funref.s
+#as: -a64
+#ld: -melf64ppc
+#ld_after_inputfiles: tmpdir/funv1.so
+#readelf: -r --wide
+# check that we do the right thing with funref.s that doesn't have
+# anything to mark it as ELFv1 or ELFv2
+
+Relocation section .* contains 1 entries:
+.*
+.* R_PPC64_ADDR64 +0+ my_func \+ 0
diff --git a/ld/testsuite/ld-powerpc/ambiguousv2.d b/ld/testsuite/ld-powerpc/ambiguousv2.d
new file mode 100644
index 0000000..5cf047b
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/ambiguousv2.d
@@ -0,0 +1,12 @@
+#source: startv2.s
+#source: funref.s
+#as: -a64
+#ld: -melf64ppc
+#ld_after_inputfiles: tmpdir/funv2.so
+#readelf: -r --wide
+# check that we do the right thing with funref.s that doesn't have
+# anything to mark it as ELFv1 or ELFv2
+
+Relocation section .*contains 1 entries:
+.*
+.* R_PPC64_JMP_SLOT .* my_func \+ 0
diff --git a/ld/testsuite/ld-powerpc/funref.s b/ld/testsuite/ld-powerpc/funref.s
new file mode 100644
index 0000000..3f7de47
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/funref.s
@@ -0,0 +1,4 @@
+ .data
+ .globl func_tab
+func_tab:
+ .dc.a my_func
diff --git a/ld/testsuite/ld-powerpc/funv1.s b/ld/testsuite/ld-powerpc/funv1.s
new file mode 100644
index 0000000..e79009d
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/funv1.s
@@ -0,0 +1,10 @@
+ .globl my_func
+ .type my_func,@function
+ .section .opd,"aw",@progbits
+my_func:
+ .quad .Lmy_func, .TOC.@tocbase
+
+ .text
+.Lmy_func:
+ blr
+ .size my_func,.-.Lmy_func
diff --git a/ld/testsuite/ld-powerpc/funv2.s b/ld/testsuite/ld-powerpc/funv2.s
new file mode 100644
index 0000000..eaff0b3
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/funv2.s
@@ -0,0 +1,6 @@
+ .abiversion 2
+ .globl my_func
+ .type my_func,@function
+my_func:
+ blr
+ .size my_func,.-my_func
diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp
index 8a60eb7..1eaedaa 100644
--- a/ld/testsuite/ld-powerpc/powerpc.exp
+++ b/ld/testsuite/ld-powerpc/powerpc.exp
@@ -212,6 +212,8 @@ set ppc64elftests {
{tocopt4a.s tocopt4b.s} {{objdump -s tocopt4.d}} "tocopt4"}
{"TOC opt5" "-melf64ppc" "" "-a64" {tocopt5.s}
{{objdump -s tocopt5.d}} "tocopt5"}
+ {"ambig shared v1" "-shared -melf64ppc" "" "-a64" {funv1.s} {} "funv1.so"}
+ {"ambig shared v2" "-shared -melf64ppc" "" "-a64" {funv2.s} {} "funv2.so"}
}
set ppceabitests {
@@ -272,6 +274,8 @@ if [ supports_ppc64 ] then {
run_dump_test "elfv2exe"
run_dump_test "elfv2-2so"
run_dump_test "elfv2-2exe"
+ run_dump_test "ambiguousv1"
+ run_dump_test "ambiguousv2"
}
if { [istarget "powerpc*-eabi*"] } {
diff --git a/ld/testsuite/ld-powerpc/startv1.s b/ld/testsuite/ld-powerpc/startv1.s
new file mode 100644
index 0000000..c54e1b0
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/startv1.s
@@ -0,0 +1,8 @@
+ .globl _start
+ .section .opd,"aw",@progbits
+_start:
+ .quad .L_start, .TOC.@tocbase
+
+ .text
+.L_start:
+ b _start
diff --git a/ld/testsuite/ld-powerpc/startv2.s b/ld/testsuite/ld-powerpc/startv2.s
new file mode 100644
index 0000000..7187aa5
--- /dev/null
+++ b/ld/testsuite/ld-powerpc/startv2.s
@@ -0,0 +1,5 @@
+ .abiversion 2
+ .text
+ .globl _start
+_start:
+ b _start