aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog95
-rw-r--r--bfd/bfd-in2.h7
-rw-r--r--bfd/config.bfd2
-rwxr-xr-xbfd/configure2
-rw-r--r--bfd/configure.in2
-rw-r--r--bfd/elf32-sh-relocs.h163
-rw-r--r--bfd/elf32-sh.c1980
-rw-r--r--bfd/libbfd.h7
-rw-r--r--bfd/reloc.c14
-rw-r--r--bfd/targets.c4
-rw-r--r--binutils/ChangeLog6
-rw-r--r--binutils/readelf.c5
-rw-r--r--gas/ChangeLog21
-rw-r--r--gas/config/tc-sh.c111
-rw-r--r--gas/config/tc-sh.h17
-rw-r--r--gas/configure.tgt3
-rw-r--r--gas/doc/c-sh.texi8
-rw-r--r--gas/testsuite/ChangeLog12
-rw-r--r--gas/testsuite/gas/sh/basic.exp4
-rw-r--r--gas/testsuite/gas/sh/fdpic.d13
-rw-r--r--gas/testsuite/gas/sh/fdpic.s8
-rw-r--r--gas/testsuite/gas/sh/reg-prefix.d5
-rw-r--r--gas/testsuite/gas/sh/sh2a-pic.d16
-rw-r--r--gas/testsuite/gas/sh/sh2a-pic.s6
-rw-r--r--gas/testsuite/lib/gas-defs.exp1
-rw-r--r--include/elf/ChangeLog11
-rw-r--r--include/elf/sh.h18
-rw-r--r--ld/ChangeLog13
-rw-r--r--ld/configure.tgt2
-rw-r--r--ld/emulparams/shelf_fd.sh2
-rw-r--r--ld/emulparams/shlelf_fd.sh16
-rw-r--r--ld/emulparams/shlelf_linux.sh2
-rw-r--r--ld/testsuite/ChangeLog43
-rw-r--r--ld/testsuite/ld-sh/fdpic-funcdesc-shared.d32
-rw-r--r--ld/testsuite/ld-sh/fdpic-funcdesc-shared.s10
-rw-r--r--ld/testsuite/ld-sh/fdpic-funcdesc-static.d25
-rw-r--r--ld/testsuite/ld-sh/fdpic-funcdesc-static.s14
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d25
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s9
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d26
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s12
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d24
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s6
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d24
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s9
-rw-r--r--ld/testsuite/ld-sh/fdpic-goti20-shared.d24
-rw-r--r--ld/testsuite/ld-sh/fdpic-goti20-shared.s6
-rw-r--r--ld/testsuite/ld-sh/fdpic-goti20-static.d22
-rw-r--r--ld/testsuite/ld-sh/fdpic-goti20-static.s11
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d32
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s12
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d27
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s12
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d29
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s9
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d24
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s9
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d30
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s11
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotoffi20-static.d22
-rw-r--r--ld/testsuite/ld-sh/fdpic-gotoffi20-static.s11
-rw-r--r--ld/testsuite/ld-sh/fdpic-plt-be.d75
-rw-r--r--ld/testsuite/ld-sh/fdpic-plt-le.d74
-rw-r--r--ld/testsuite/ld-sh/fdpic-plt.s11
-rw-r--r--ld/testsuite/ld-sh/fdpic-plti20-be.d63
-rw-r--r--ld/testsuite/ld-sh/fdpic-plti20-le.d63
-rw-r--r--ld/testsuite/ld-sh/fdpic-stack-default.d19
-rw-r--r--ld/testsuite/ld-sh/fdpic-stack-size.d19
-rw-r--r--ld/testsuite/ld-sh/fdpic-stack.s5
-rw-r--r--ld/testsuite/ld-sh/sh.exp2
-rw-r--r--ld/testsuite/lib/ld-lib.exp1
71 files changed, 3217 insertions, 241 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 4c7593c..76924de 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,98 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * config.bfd (sh-*-uclinux* | sh[12]-*-uclinux*): Add
+ bfd_elf32_shl_vec, and FDPIC vectors to targ_selvecs.
+ * configure.in: Handle FDPIC vectors.
+ * elf32-sh-relocs.h: Add FDPIC and movi20 relocations.
+ * elf32-sh.c (DEFAULT_STACK_SIZE): Define.
+ (SYMBOL_FUNCDESC_LOCAL): Define. Use it instead of
+ SYMBOL_REFERENCES_LOCAL for function descriptors.
+ (fdpic_object_p): New.
+ (sh_reloc_map): Add FDPIC and movi20 relocations.
+ (sh_elf_info_to_howto, sh_elf_relocate_section): Handle new invalid
+ range.
+ (struct elf_sh_plt_info): Add got20 and short_plt. Update all
+ definitions.
+ (FDPIC_PLT_ENTRY_SIZE, FDPIC_PLT_LAZY_OFFSET): Define.
+ (fdpic_sh_plt_entry_be, fdpic_sh_plt_entry_le, fdpic_sh_plts): New.
+ (FDPIC_SH2A_PLT_ENTRY_SIZE, FDPIC_SH2A_PLT_LAZY_OFFSET): Define.
+ (fdpic_sh2a_plt_entry_be, fdpic_sh2a_plt_entry_le)
+ (fdpic_sh2a_short_plt_be, fdpic_sh2a_short_plt_le, fdpic_sh2a_plts):
+ New.
+ (get_plt_info): Handle FDPIC.
+ (MAX_SHORT_PLT): Define.
+ (get_plt_index, get_plt_offset): Handle short_plt.
+ (union gotref): New.
+ (struct elf_sh_link_hash_entry): Add funcdesc, rename tls_type to
+ got_type and adjust all uses. Add GOT_FUNCDESC.
+ (struct sh_elf_obj_tdata): Add local_funcdesc. Rename
+ local_got_tls_type to local_got_type.
+ (sh_elf_local_got_type): Renamed from sh_elf_local_got_tls_type. All
+ users changed.
+ (sh_elf_local_funcdesc): Define.
+ (struct elf_sh_link_hash_table): Add sfuncdesc, srelfuncdesc, fdpic_p,
+ and srofixup.
+ (sh_elf_link_hash_newfunc): Initialize new fields.
+ (sh_elf_link_hash_table_create): Set fdpic_p.
+ (sh_elf_omit_section_dynsym): New.
+ (create_got_section): Create .got.funcdesc, .rela.got.funcdesc
+ and .rofixup.
+ (allocate_dynrelocs): Allocate local function descriptors and space
+ for R_SH_FUNCDESC-related relocations, and for rofixups.
+ Handle GOT_FUNCDESC. Create fixups. Handle GOT entries which
+ require function descriptors.
+ (sh_elf_always_size_sections): Handle PT_GNU_STACK and __stacksize.
+ (sh_elf_modify_program_headers): New.
+ (sh_elf_size_dynamic_sections): Allocate function descriptors for
+ local symbols. Allocate .got.funcdesc contents. Allocate rofixups.
+ Handle local GOT entries of type GOT_FUNCDESC. Create fixups for
+ local GOT entries. Ensure that FDPIC libraries always have a PLTGOT
+ entry in the .dynamic section.
+ (sh_elf_add_dyn_reloc, sh_elf_got_offset, sh_elf_initialize_funcdesc)
+ (sh_elf_add_rofixup, sh_elf_osec_to_segment)
+ (sh_elf_osec_readonly_p, install_movi20_field): New functions.
+ (sh_elf_relocate_section): Handle new relocations, R_SH_FUNCDESC,
+ R_SH_GOTFUNCDESC and R_SH_GOTOFFFUNCDESC. Use sh_elf_got_offset
+ and .got.plt throughout to find _GLOBAL_OFFSET_TABLE_. Add rofixup
+ read-only section warnings. Handle undefined weak symbols. Generate
+ fixups for R_SH_DIR32 and GOT entries. Check for cross-segment
+ relocations and clear EF_SH_PIC. Handle 20-bit relocations.
+ Always generate R_SH_DIR32 for FDPIC instead of R_SH_RELATIVE.
+ (sh_elf_gc_sweep_hook): Handle R_SH_FUNCDESC, R_SH_GOTOFF20,
+ R_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC20, and R_SH_GOTOFFFUNCDESC.
+ Handle 20-bit relocations.
+ (sh_elf_copy_indirect_symbol): Copy function descriptor reference
+ counts.
+ (sh_elf_check_relocs): Handle new relocations. Make symbols
+ dynamic for FDPIC relocs. Account for rofixups. Error for FDPIC
+ symbol mismatches. Allocate a GOT for R_SH_DIR32. Allocate fixups
+ for R_SH_DIR32.
+ (sh_elf_copy_private_data): Copy PT_GNU_STACK size.
+ (sh_elf_merge_private_data): Copy initial flags. Do not clobber
+ non-mach flags. Set EF_SH_PIC for FDPIC. Reject FDPIC mismatches.
+ (sh_elf_finish_dynamic_symbol): Do not handle got_funcdesc entries
+ here. Rename sgot to sgotplt and srel to srelplt. Handle short_plt,
+ FDPIC descriptors, and got20. Create R_SH_FUNCDESC_VALUE for FDPIC.
+ Use install_movi20_field. Rename srel to srelgot. Always generate
+ R_SH_DIR32 for FDPIC instead of R_SH_RELATIVE.
+ (sh_elf_finish_dynamic_sections): Fill in the GOT pointer in rofixup.
+ Do not fill in reserved GOT entries for FDPIC. Correct DT_PLTGOT.
+ Rename sgot to sgotplt. Assert that the right number of rofixups
+ and dynamic relocations were allocated.
+ (sh_elf_use_relative_eh_frame, sh_elf_encode_eh_address): New.
+ (elf_backend_omit_section_dynsym): Use sh_elf_omit_section_dynsym.
+ (elf_backend_can_make_relative_eh_frame)
+ (elf_backend_can_make_lsda_relative_eh_frame)
+ (elf_backend_encode_eh_address): Define.
+ (TARGET_BIG_SYM, TARGET_BIG_NAME, TARGET_LITTLE_SYM)
+ (TARGET_LITTLE_NAME, elf_backend_modify_program_headers, elf32_bed):
+ Redefine for FDPIC vector.
+ * reloc.c: Add SH FDPIC and movi20 relocations.
+ * targets.c (_bfd_target_vector): Add FDPIC vectors.
+ * configure, bfd-in2.h, libbfd.h: Regenerated.
+
2010-05-25 Jay Krell <jay.krell@cornell.edu>
PR ld/11624
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index e9dcb2c..5c42128 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3276,6 +3276,13 @@ pc-relative or some form of GOT-indirect relocation. */
BFD_RELOC_SH_TLS_DTPMOD32,
BFD_RELOC_SH_TLS_DTPOFF32,
BFD_RELOC_SH_TLS_TPOFF32,
+ BFD_RELOC_SH_GOT20,
+ BFD_RELOC_SH_GOTOFF20,
+ BFD_RELOC_SH_GOTFUNCDESC,
+ BFD_RELOC_SH_GOTFUNCDESC20,
+ BFD_RELOC_SH_GOTOFFFUNCDESC,
+ BFD_RELOC_SH_GOTOFFFUNCDESC20,
+ BFD_RELOC_SH_FUNCDESC,
/* ARC Cores relocs.
ARC 22 bit pc-relative branch. The lowest two bits must be zero and are
diff --git a/bfd/config.bfd b/bfd/config.bfd
index d39ef18..abe1b5e 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -1257,7 +1257,7 @@ case "${targ}" in
sh-*-uclinux* | sh[12]-*-uclinux*)
targ_defvec=bfd_elf32_sh_vec
- targ_selvecs="bfd_elf32_shblin_vec bfd_elf32_shlin_vec"
+ targ_selvecs="bfd_elf32_shl_vec bfd_elf32_shblin_vec bfd_elf32_shlin_vec bfd_elf32_shfd_vec bfd_elf32_shbfd_vec"
#ifdef BFD64
targ_selvecs="${targ_selvecs} bfd_elf32_sh64lin_vec bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec"
#endif
diff --git a/bfd/configure b/bfd/configure
index d498ff2..310bb6a 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -15135,7 +15135,9 @@ do
bfd_elf32_sh64lnbsd_vec) tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
bfd_elf32_sh64nbsd_vec) tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
bfd_elf32_sh_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
+ bfd_elf32_shbfd_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
bfd_elf32_shblin_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
+ bfd_elf32_shfd_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
bfd_elf32_shl_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
bfd_elf32_shl_symbian_vec) tb="$tb elf32-sh-symbian.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
bfd_elf32_shlin_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
diff --git a/bfd/configure.in b/bfd/configure.in
index 3ca7fc7..65ae8d3 100644
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -772,7 +772,9 @@ do
bfd_elf32_sh64lnbsd_vec) tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
bfd_elf32_sh64nbsd_vec) tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
bfd_elf32_sh_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
+ bfd_elf32_shbfd_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
bfd_elf32_shblin_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
+ bfd_elf32_shfd_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
bfd_elf32_shl_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
bfd_elf32_shl_symbian_vec) tb="$tb elf32-sh-symbian.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
bfd_elf32_shlin_vec) tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
diff --git a/bfd/elf32-sh-relocs.h b/bfd/elf32-sh-relocs.h
index 70f3a7b..05f0875 100644
--- a/bfd/elf32-sh-relocs.h
+++ b/bfd/elf32-sh-relocs.h
@@ -1,4 +1,4 @@
-/* Copyright 2006, 2007 Free Software Foundation, Inc.
+/* Copyright 2006, 2007, 2010 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
@@ -1462,19 +1462,164 @@
0, /* src_mask */
((bfd_vma) 0) - 1, /* dst_mask */
FALSE), /* pcrel_offset */
+#else
+ EMPTY_HOWTO (169),
+ EMPTY_HOWTO (170),
+ EMPTY_HOWTO (171),
+ EMPTY_HOWTO (172),
+ EMPTY_HOWTO (173),
+ EMPTY_HOWTO (174),
+ EMPTY_HOWTO (175),
+ EMPTY_HOWTO (176),
+ EMPTY_HOWTO (177),
+ EMPTY_HOWTO (178),
+ EMPTY_HOWTO (179),
+ EMPTY_HOWTO (180),
+ EMPTY_HOWTO (181),
+ EMPTY_HOWTO (182),
+ EMPTY_HOWTO (183),
+ EMPTY_HOWTO (184),
+ EMPTY_HOWTO (185),
+ EMPTY_HOWTO (186),
+ EMPTY_HOWTO (187),
+ EMPTY_HOWTO (188),
+ EMPTY_HOWTO (189),
+ EMPTY_HOWTO (190),
+ EMPTY_HOWTO (191),
+ EMPTY_HOWTO (192),
+ EMPTY_HOWTO (193),
+ EMPTY_HOWTO (194),
+ EMPTY_HOWTO (195),
+ EMPTY_HOWTO (196),
+#endif
EMPTY_HOWTO (197),
EMPTY_HOWTO (198),
EMPTY_HOWTO (199),
EMPTY_HOWTO (200),
- EMPTY_HOWTO (201),
- EMPTY_HOWTO (202),
- EMPTY_HOWTO (203),
- EMPTY_HOWTO (204),
- EMPTY_HOWTO (205),
- EMPTY_HOWTO (206),
- EMPTY_HOWTO (207),
- EMPTY_HOWTO (208),
+
+ /* FDPIC-relative offset to a GOT entry, for movi20. */
+ HOWTO (R_SH_GOT20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 20, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOT20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x00f0ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* FDPIC-relative offset to a data object, for movi20. */
+ HOWTO (R_SH_GOTOFF20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 20, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOTOFF20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x00f0ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* FDPIC-relative offset to a GOT entry for a function descriptor. */
+ HOWTO (R_SH_GOTFUNCDESC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOTFUNCDESC", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* FDPIC-relative offset to a GOT entry for a function descriptor,
+ for movi20. */
+ HOWTO (R_SH_GOTFUNCDESC20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 20, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOTFUNCDESC20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x00f0ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* FDPIC-relative offset to a function descriptor. */
+ HOWTO (R_SH_GOTOFFFUNCDESC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOTOFFFUNCDESC", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* FDPIC-relative offset to a function descriptor, for movi20. */
+ HOWTO (R_SH_GOTOFFFUNCDESC20, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 20, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_GOTOFFFUNCDESC20", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x00f0ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Address of an official function descriptor. */
+ HOWTO (R_SH_FUNCDESC, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_FUNCDESC", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* Function descriptor to be filled in by the dynamic linker. */
+ HOWTO (R_SH_FUNCDESC_VALUE, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_SH_FUNCDESC_VALUE", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+#ifdef INCLUDE_SHMEDIA
EMPTY_HOWTO (209),
EMPTY_HOWTO (210),
EMPTY_HOWTO (211),
diff --git a/bfd/elf32-sh.c b/bfd/elf32-sh.c
index 23ee06a..1b0daf9 100644
--- a/bfd/elf32-sh.c
+++ b/bfd/elf32-sh.c
@@ -27,6 +27,7 @@
#include "elf-bfd.h"
#include "elf-vxworks.h"
#include "elf/sh.h"
+#include "dwarf2.h"
#include "libiberty.h"
#include "../opcodes/sh-opc.h"
@@ -54,7 +55,17 @@ static bfd_vma tpoff
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1"
+/* FDPIC binaries have a default 128K stack. */
+#define DEFAULT_STACK_SIZE 0x20000
+
#define MINUS_ONE ((bfd_vma) 0 - 1)
+
+/* Decide whether a reference to a symbol can be resolved locally or
+ not. If the symbol is protected, we want the local address, but
+ its function descriptor must be assigned by the dynamic linker. */
+#define SYMBOL_FUNCDESC_LOCAL(INFO, H) \
+ (SYMBOL_REFERENCES_LOCAL (INFO, H) \
+ || ! elf_hash_table (INFO)->dynamic_sections_created)
#define SH_PARTIAL32 TRUE
#define SH_SRC_MASK32 0xffffffff
@@ -88,6 +99,22 @@ vxworks_object_p (bfd *abfd ATTRIBUTE_UNUSED)
#endif
}
+/* Return true if OUTPUT_BFD is an FDPIC object. */
+
+static bfd_boolean
+fdpic_object_p (bfd *abfd ATTRIBUTE_UNUSED)
+{
+#if !defined INCLUDE_SHMEDIA && !defined SH_TARGET_ALREADY_DEFINED
+ extern const bfd_target bfd_elf32_shfd_vec;
+ extern const bfd_target bfd_elf32_shbfd_vec;
+
+ return (abfd->xvec == &bfd_elf32_shfd_vec
+ || abfd->xvec == &bfd_elf32_shbfd_vec);
+#else
+ return FALSE;
+#endif
+}
+
/* Return the howto table for ABFD. */
static reloc_howto_type *
@@ -333,6 +360,13 @@ static const struct elf_reloc_map sh_reloc_map[] =
{ BFD_RELOC_32_GOTOFF, R_SH_GOTOFF },
{ BFD_RELOC_SH_GOTPC, R_SH_GOTPC },
{ BFD_RELOC_SH_GOTPLT32, R_SH_GOTPLT32 },
+ { BFD_RELOC_SH_GOT20, R_SH_GOT20 },
+ { BFD_RELOC_SH_GOTOFF20, R_SH_GOTOFF20 },
+ { BFD_RELOC_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC },
+ { BFD_RELOC_SH_GOTFUNCDESC20, R_SH_GOTFUNCDESC20 },
+ { BFD_RELOC_SH_GOTOFFFUNCDESC, R_SH_GOTOFFFUNCDESC },
+ { BFD_RELOC_SH_GOTOFFFUNCDESC20, R_SH_GOTOFFFUNCDESC20 },
+ { BFD_RELOC_SH_FUNCDESC, R_SH_FUNCDESC },
#ifdef INCLUDE_SHMEDIA
{ BFD_RELOC_SH_GOT_LOW16, R_SH_GOT_LOW16 },
{ BFD_RELOC_SH_GOT_MEDLOW16, R_SH_GOT_MEDLOW16 },
@@ -447,6 +481,7 @@ sh_elf_info_to_howto (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_3 || r > R_SH_LAST_INVALID_RELOC_3);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_4 || r > R_SH_LAST_INVALID_RELOC_4);
BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_5 || r > R_SH_LAST_INVALID_RELOC_5);
+ BFD_ASSERT (r < R_SH_FIRST_INVALID_RELOC_6 || r > R_SH_LAST_INVALID_RELOC_6);
cache_ptr->howto = get_howto_table (abfd) + r;
}
@@ -1552,10 +1587,18 @@ struct elf_sh_plt_info
bfd_vma got_entry; /* the address of the symbol's .got.plt entry */
bfd_vma plt; /* .plt (or a branch to .plt on VxWorks) */
bfd_vma reloc_offset; /* the offset of the symbol's JMP_SLOT reloc */
+ bfd_boolean got20; /* TRUE if got_entry points to a movi20
+ instruction (instead of a constant pool
+ entry). */
} symbol_fields;
/* The offset of the resolver stub from the start of SYMBOL_ENTRY. */
bfd_vma symbol_resolve_offset;
+
+ /* A different PLT layout which can be used for the first
+ MAX_SHORT_PLT entries. It must share the same plt0. NULL in
+ other cases. */
+ const struct elf_sh_plt_info *short_plt;
};
#ifdef INCLUDE_SHMEDIA
@@ -1700,8 +1743,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ 0, MINUS_ONE, MINUS_ONE },
elf_sh_plt_entry_be,
ELF_PLT_ENTRY_SIZE,
- { 0, 32, 48 },
- 33 /* includes ISA encoding */
+ { 0, 32, 48, FALSE },
+ 33, /* includes ISA encoding */
+ NULL
},
{
/* Little-endian non-PIC. */
@@ -1710,8 +1754,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ 0, MINUS_ONE, MINUS_ONE },
elf_sh_plt_entry_le,
ELF_PLT_ENTRY_SIZE,
- { 0, 32, 48 },
- 33 /* includes ISA encoding */
+ { 0, 32, 48, FALSE },
+ 33, /* includes ISA encoding */
+ NULL
},
},
{
@@ -1722,8 +1767,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
elf_sh_pic_plt_entry_be,
ELF_PLT_ENTRY_SIZE,
- { 0, MINUS_ONE, 52 },
- 33 /* includes ISA encoding */
+ { 0, MINUS_ONE, 52, FALSE },
+ 33, /* includes ISA encoding */
+ NULL
},
{
/* Little-endian PIC. */
@@ -1732,8 +1778,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
elf_sh_pic_plt_entry_le,
ELF_PLT_ENTRY_SIZE,
- { 0, MINUS_ONE, 52 },
- 33 /* includes ISA encoding */
+ { 0, MINUS_ONE, 52, FALSE },
+ 33, /* includes ISA encoding */
+ NULL
},
}
};
@@ -1893,8 +1940,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, 24, 20 },
elf_sh_plt_entry_be,
ELF_PLT_ENTRY_SIZE,
- { 20, 16, 24 },
- 8
+ { 20, 16, 24, FALSE },
+ 8,
+ NULL
},
{
/* Little-endian non-PIC. */
@@ -1903,8 +1951,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, 24, 20 },
elf_sh_plt_entry_le,
ELF_PLT_ENTRY_SIZE,
- { 20, 16, 24 },
- 8
+ { 20, 16, 24, FALSE },
+ 8,
+ NULL
},
},
{
@@ -1915,8 +1964,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
elf_sh_pic_plt_entry_be,
ELF_PLT_ENTRY_SIZE,
- { 20, MINUS_ONE, 24 },
- 8
+ { 20, MINUS_ONE, 24, FALSE },
+ 8,
+ NULL
},
{
/* Little-endian PIC. */
@@ -1925,8 +1975,9 @@ static const struct elf_sh_plt_info elf_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
elf_sh_pic_plt_entry_le,
ELF_PLT_ENTRY_SIZE,
- { 20, MINUS_ONE, 24 },
- 8
+ { 20, MINUS_ONE, 24, FALSE },
+ 8,
+ NULL
},
}
};
@@ -2017,8 +2068,9 @@ static const struct elf_sh_plt_info vxworks_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, 8 },
vxworks_sh_plt_entry_be,
VXWORKS_PLT_ENTRY_SIZE,
- { 8, 14, 20 },
- 12
+ { 8, 14, 20, FALSE },
+ 12,
+ NULL
},
{
/* Little-endian non-PIC. */
@@ -2027,8 +2079,9 @@ static const struct elf_sh_plt_info vxworks_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, 8 },
vxworks_sh_plt_entry_le,
VXWORKS_PLT_ENTRY_SIZE,
- { 8, 14, 20 },
- 12
+ { 8, 14, 20, FALSE },
+ 12,
+ NULL
},
},
{
@@ -2039,8 +2092,9 @@ static const struct elf_sh_plt_info vxworks_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
vxworks_sh_pic_plt_entry_be,
VXWORKS_PLT_ENTRY_SIZE,
- { 8, MINUS_ONE, 20 },
- 12
+ { 8, MINUS_ONE, 20, FALSE },
+ 12,
+ NULL
},
{
/* Little-endian PIC. */
@@ -2049,18 +2103,184 @@ static const struct elf_sh_plt_info vxworks_sh_plts[2][2] = {
{ MINUS_ONE, MINUS_ONE, MINUS_ONE },
vxworks_sh_pic_plt_entry_le,
VXWORKS_PLT_ENTRY_SIZE,
- { 8, MINUS_ONE, 20 },
- 12
+ { 8, MINUS_ONE, 20, FALSE },
+ 12,
+ NULL
},
}
};
+/* FDPIC PLT entries. Two unimplemented optimizations for lazy
+ binding are to omit the lazy binding stub when linking with -z now
+ and to move lazy binding stubs into a separate region for better
+ cache behavior. */
+
+#define FDPIC_PLT_ENTRY_SIZE 28
+#define FDPIC_PLT_LAZY_OFFSET 20
+
+/* FIXME: The lazy binding stub requires a plt0 - which may need to be
+ duplicated if it is out of range, or which can be inlined. So
+ right now it is always inlined, which wastes a word per stub. It
+ might be easier to handle the duplication if we put the lazy
+ stubs separately. */
+
+static const bfd_byte fdpic_sh_plt_entry_be[FDPIC_PLT_ENTRY_SIZE] =
+{
+ 0xd0, 0x02, /* mov.l @(12,pc),r0 */
+ 0x01, 0xce, /* mov.l @(r0,r12),r1 */
+ 0x70, 0x04, /* add #4, r0 */
+ 0x41, 0x2b, /* jmp @r1 */
+ 0x0c, 0xce, /* mov.l @(r0,r12),r12 */
+ 0x00, 0x09, /* nop */
+ 0, 0, 0, 0, /* 0: replaced with offset of this symbol's funcdesc */
+ 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */
+ 0x60, 0xc2, /* mov.l @r12,r0 */
+ 0x40, 0x2b, /* jmp @r0 */
+ 0x53, 0xc1, /* mov.l @(4,r12),r3 */
+ 0x00, 0x09, /* nop */
+};
+
+static const bfd_byte fdpic_sh_plt_entry_le[FDPIC_PLT_ENTRY_SIZE] =
+{
+ 0x02, 0xd0, /* mov.l @(12,pc),r0 */
+ 0xce, 0x01, /* mov.l @(r0,r12),r1 */
+ 0x04, 0x70, /* add #4, r0 */
+ 0x2b, 0x41, /* jmp @r1 */
+ 0xce, 0x0c, /* mov.l @(r0,r12),r12 */
+ 0x09, 0x00, /* nop */
+ 0, 0, 0, 0, /* 0: replaced with offset of this symbol's funcdesc */
+ 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */
+ 0xc2, 0x60, /* mov.l @r12,r0 */
+ 0x2b, 0x40, /* jmp @r0 */
+ 0xc1, 0x53, /* mov.l @(4,r12),r3 */
+ 0x09, 0x00, /* nop */
+};
+
+static const struct elf_sh_plt_info fdpic_sh_plts[2] = {
+ {
+ /* Big-endian PIC. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh_plt_entry_be,
+ FDPIC_PLT_ENTRY_SIZE,
+ { 12, MINUS_ONE, 16, FALSE },
+ FDPIC_PLT_LAZY_OFFSET,
+ NULL
+ },
+ {
+ /* Little-endian PIC. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh_plt_entry_le,
+ FDPIC_PLT_ENTRY_SIZE,
+ { 12, MINUS_ONE, 16, FALSE },
+ FDPIC_PLT_LAZY_OFFSET,
+ NULL
+ },
+};
+
+/* On SH2A, we can use the movi20 instruction to generate shorter PLT
+ entries for the first 64K slots. We use the normal FDPIC PLT entry
+ past that point; we could also use movi20s, which might be faster,
+ but would not be any smaller. */
+
+#define FDPIC_SH2A_PLT_ENTRY_SIZE 24
+#define FDPIC_SH2A_PLT_LAZY_OFFSET 16
+
+static const bfd_byte fdpic_sh2a_plt_entry_be[FDPIC_SH2A_PLT_ENTRY_SIZE] =
+{
+ 0, 0, 0, 0, /* movi20 #gotofffuncdesc,r0 */
+ 0x01, 0xce, /* mov.l @(r0,r12),r1 */
+ 0x70, 0x04, /* add #4, r0 */
+ 0x41, 0x2b, /* jmp @r1 */
+ 0x0c, 0xce, /* mov.l @(r0,r12),r12 */
+ 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */
+ 0x60, 0xc2, /* mov.l @r12,r0 */
+ 0x40, 0x2b, /* jmp @r0 */
+ 0x53, 0xc1, /* mov.l @(4,r12),r3 */
+ 0x00, 0x09, /* nop */
+};
+
+static const bfd_byte fdpic_sh2a_plt_entry_le[FDPIC_SH2A_PLT_ENTRY_SIZE] =
+{
+ 0, 0, 0, 0, /* movi20 #gotofffuncdesc,r0 */
+ 0xce, 0x01, /* mov.l @(r0,r12),r1 */
+ 0x04, 0x70, /* add #4, r0 */
+ 0x2b, 0x41, /* jmp @r1 */
+ 0xce, 0x0c, /* mov.l @(r0,r12),r12 */
+ 0, 0, 0, 0, /* 1: replaced with offset into relocation table. */
+ 0xc2, 0x60, /* mov.l @r12,r0 */
+ 0x2b, 0x40, /* jmp @r0 */
+ 0xc1, 0x53, /* mov.l @(4,r12),r3 */
+ 0x09, 0x00, /* nop */
+};
+
+static const struct elf_sh_plt_info fdpic_sh2a_short_plt_be = {
+ /* Big-endian FDPIC, max index 64K. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh2a_plt_entry_be,
+ FDPIC_SH2A_PLT_ENTRY_SIZE,
+ { 0, MINUS_ONE, 12, TRUE },
+ FDPIC_SH2A_PLT_LAZY_OFFSET,
+ NULL
+};
+
+static const struct elf_sh_plt_info fdpic_sh2a_short_plt_le = {
+ /* Little-endian FDPIC, max index 64K. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh2a_plt_entry_le,
+ FDPIC_SH2A_PLT_ENTRY_SIZE,
+ { 0, MINUS_ONE, 12, TRUE },
+ FDPIC_SH2A_PLT_LAZY_OFFSET,
+ NULL
+};
+
+static const struct elf_sh_plt_info fdpic_sh2a_plts[2] = {
+ {
+ /* Big-endian PIC. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh_plt_entry_be,
+ FDPIC_PLT_ENTRY_SIZE,
+ { 12, MINUS_ONE, 16, FALSE },
+ FDPIC_PLT_LAZY_OFFSET,
+ &fdpic_sh2a_short_plt_be
+ },
+ {
+ /* Little-endian PIC. */
+ NULL,
+ 0,
+ { MINUS_ONE, MINUS_ONE, MINUS_ONE },
+ fdpic_sh_plt_entry_le,
+ FDPIC_PLT_ENTRY_SIZE,
+ { 12, MINUS_ONE, 16, FALSE },
+ FDPIC_PLT_LAZY_OFFSET,
+ &fdpic_sh2a_short_plt_le
+ },
+};
+
/* Return the type of PLT associated with ABFD. PIC_P is true if
the object is position-independent. */
static const struct elf_sh_plt_info *
-get_plt_info (bfd *abfd ATTRIBUTE_UNUSED, bfd_boolean pic_p)
+get_plt_info (bfd *abfd, bfd_boolean pic_p)
{
+ if (fdpic_object_p (abfd))
+ {
+ /* If any input file requires SH2A we can use a shorter PLT
+ sequence. */
+ if (sh_get_arch_from_bfd_mach (bfd_get_mach (abfd)) & arch_sh2a_base)
+ return &fdpic_sh2a_plts[!bfd_big_endian (abfd)];
+ else
+ return &fdpic_sh_plts[!bfd_big_endian (abfd)];
+ }
if (vxworks_object_p (abfd))
return &vxworks_sh_plts[pic_p][!bfd_big_endian (abfd)];
return &elf_sh_plts[pic_p][!bfd_big_endian (abfd)];
@@ -2078,12 +2298,31 @@ install_plt_field (bfd *output_bfd, bfd_boolean code_p ATTRIBUTE_UNUSED,
}
#endif
+/* The number of PLT entries which can use a shorter PLT, if any.
+ Currently always 64K, since only SH-2A FDPIC uses this; a
+ 20-bit movi20 can address that many function descriptors below
+ _GLOBAL_OFFSET_TABLE_. */
+#define MAX_SHORT_PLT 65536
+
/* Return the index of the PLT entry at byte offset OFFSET. */
static bfd_vma
get_plt_index (const struct elf_sh_plt_info *info, bfd_vma offset)
{
- return (offset - info->plt0_entry_size) / info->symbol_entry_size;
+ bfd_vma plt_index = 0;
+
+ offset -= info->plt0_entry_size;
+ if (info->short_plt != NULL)
+ {
+ if (offset > MAX_SHORT_PLT * info->short_plt->symbol_entry_size)
+ {
+ plt_index = MAX_SHORT_PLT;
+ offset -= MAX_SHORT_PLT * info->short_plt->symbol_entry_size;
+ }
+ else
+ info = info->short_plt;
+ }
+ return plt_index + offset / info->symbol_entry_size;
}
/* Do the inverse operation. */
@@ -2091,7 +2330,20 @@ get_plt_index (const struct elf_sh_plt_info *info, bfd_vma offset)
static bfd_vma
get_plt_offset (const struct elf_sh_plt_info *info, bfd_vma plt_index)
{
- return info->plt0_entry_size + (plt_index * info->symbol_entry_size);
+ bfd_vma offset = 0;
+
+ if (info->short_plt != NULL)
+ {
+ if (plt_index > MAX_SHORT_PLT)
+ {
+ offset = MAX_SHORT_PLT * info->short_plt->symbol_entry_size;
+ plt_index -= MAX_SHORT_PLT;
+ }
+ else
+ info = info->short_plt;
+ }
+ return (offset + info->plt0_entry_size
+ + (plt_index * info->symbol_entry_size));
}
/* The sh linker needs to keep track of the number of relocs that it
@@ -2114,6 +2366,12 @@ struct elf_sh_dyn_relocs
bfd_size_type pc_count;
};
+union gotref
+{
+ bfd_signed_vma refcount;
+ bfd_vma offset;
+};
+
/* sh ELF linker hash entry. */
struct elf_sh_link_hash_entry
@@ -2133,9 +2391,23 @@ struct elf_sh_link_hash_entry
bfd_signed_vma gotplt_refcount;
+ /* A local function descriptor, for FDPIC. The refcount counts
+ R_SH_FUNCDESC, R_SH_GOTOFFFUNCDESC, and R_SH_GOTOFFFUNCDESC20
+ relocations; the PLT and GOT entry are accounted
+ for separately. After adjust_dynamic_symbol, the offset is
+ MINUS_ONE if there is no local descriptor (dynamic linker
+ managed and no PLT entry, or undefined weak non-dynamic).
+ During check_relocs we do not yet know whether the local
+ descriptor will be canonical. */
+ union gotref funcdesc;
+
+ /* How many of the above refcounted relocations were R_SH_FUNCDESC,
+ and thus require fixups or relocations. */
+ bfd_signed_vma abs_funcdesc_refcount;
+
enum {
- GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE
- } tls_type;
+ GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE, GOT_FUNCDESC
+ } got_type;
};
#define sh_elf_hash_entry(ent) ((struct elf_sh_link_hash_entry *)(ent))
@@ -2144,15 +2416,21 @@ struct sh_elf_obj_tdata
{
struct elf_obj_tdata root;
- /* tls_type for each local got entry. */
- char *local_got_tls_type;
+ /* got_type for each local got entry. */
+ char *local_got_type;
+
+ /* Function descriptor refcount and offset for each local symbol. */
+ union gotref *local_funcdesc;
};
#define sh_elf_tdata(abfd) \
((struct sh_elf_obj_tdata *) (abfd)->tdata.any)
-#define sh_elf_local_got_tls_type(abfd) \
- (sh_elf_tdata (abfd)->local_got_tls_type)
+#define sh_elf_local_got_type(abfd) \
+ (sh_elf_tdata (abfd)->local_got_type)
+
+#define sh_elf_local_funcdesc(abfd) \
+ (sh_elf_tdata (abfd)->local_funcdesc)
#define is_sh_elf(bfd) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
@@ -2183,6 +2461,9 @@ struct elf_sh_link_hash_table
asection *srelplt;
asection *sdynbss;
asection *srelbss;
+ asection *sfuncdesc;
+ asection *srelfuncdesc;
+ asection *srofixup;
/* The (unloaded but important) VxWorks .rela.plt.unloaded section. */
asection *srelplt2;
@@ -2202,6 +2483,9 @@ struct elf_sh_link_hash_table
/* True if the target system is VxWorks. */
bfd_boolean vxworks_p;
+
+ /* True if the target system uses FDPIC. */
+ bfd_boolean fdpic_p;
};
/* Traverse an sh ELF linker hash table. */
@@ -2248,7 +2532,9 @@ sh_elf_link_hash_newfunc (struct bfd_hash_entry *entry,
#ifdef INCLUDE_SHMEDIA
ret->datalabel_got.refcount = ret->root.got.refcount;
#endif
- ret->tls_type = GOT_UNKNOWN;
+ ret->funcdesc.refcount = 0;
+ ret->abs_funcdesc_refcount = 0;
+ ret->got_type = GOT_UNKNOWN;
}
return (struct bfd_hash_entry *) ret;
@@ -2287,10 +2573,39 @@ sh_elf_link_hash_table_create (bfd *abfd)
ret->tls_ldm_got.refcount = 0;
ret->plt_info = NULL;
ret->vxworks_p = vxworks_object_p (abfd);
+ ret->fdpic_p = fdpic_object_p (abfd);
return &ret->root.root;
}
+static bfd_boolean
+sh_elf_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info, asection *p)
+{
+ struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info);
+
+ /* Non-FDPIC binaries do not need dynamic symbols for sections. */
+ if (!htab->fdpic_p)
+ return TRUE;
+
+ /* We need dynamic symbols for every section, since segments can
+ relocate independently. */
+ switch (elf_section_data (p)->this_hdr.sh_type)
+ {
+ case SHT_PROGBITS:
+ case SHT_NOBITS:
+ /* If sh_type is yet undecided, assume it could be
+ SHT_PROGBITS/SHT_NOBITS. */
+ case SHT_NULL:
+ return FALSE;
+
+ /* There shouldn't be section relative relocations
+ against any other section. */
+ default:
+ return TRUE;
+ }
+}
+
/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up
shortcuts to them in our hash table. */
@@ -2311,6 +2626,38 @@ create_got_section (bfd *dynobj, struct bfd_link_info *info)
htab->srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
if (! htab->sgot || ! htab->sgotplt || ! htab->srelgot)
abort ();
+
+ htab->sfuncdesc = bfd_make_section_with_flags (dynobj, ".got.funcdesc",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED));
+ if (htab->sfuncdesc == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->sfuncdesc, 2))
+ return FALSE;
+
+ htab->srelfuncdesc = bfd_make_section_with_flags (dynobj,
+ ".rela.got.funcdesc",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (htab->srelfuncdesc == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->srelfuncdesc, 2))
+ return FALSE;
+
+ /* Also create .rofixup. */
+ htab->srofixup = bfd_make_section_with_flags (dynobj, ".rofixup",
+ (SEC_ALLOC | SEC_LOAD
+ | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
+ | SEC_READONLY));
+ if (htab->srofixup == NULL
+ || ! bfd_set_section_alignment (dynobj, htab->srofixup, 2))
+ return FALSE;
+
return TRUE;
}
@@ -2671,6 +3018,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
{
asection *s = htab->splt;
+ const struct elf_sh_plt_info *plt_info;
/* If this is the first .plt entry, make room for the special
first entry. */
@@ -2683,20 +3031,28 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
not generating a shared library, then set the symbol to this
location in the .plt. This is required to make function
pointers compare as equal between the normal executable and
- the shared library. */
- if (! info->shared
- && !h->def_regular)
+ the shared library. Skip this for FDPIC, since the
+ function's address will be the address of the canonical
+ function descriptor. */
+ if (!htab->fdpic_p && !info->shared && !h->def_regular)
{
h->root.u.def.section = s;
h->root.u.def.value = h->plt.offset;
}
/* Make room for this entry. */
- s->size += htab->plt_info->symbol_entry_size;
+ plt_info = htab->plt_info;
+ if (plt_info->short_plt != NULL
+ && (get_plt_index (plt_info->short_plt, s->size) < MAX_SHORT_PLT))
+ plt_info = plt_info->short_plt;
+ s->size += plt_info->symbol_entry_size;
/* We also need to make an entry in the .got.plt section, which
will be placed in the .got section by the linker script. */
- htab->sgotplt->size += 4;
+ if (!htab->fdpic_p)
+ htab->sgotplt->size += 4;
+ else
+ htab->sgotplt->size += 8;
/* We also need to make an entry in the .rel.plt section. */
htab->srelplt->size += sizeof (Elf32_External_Rela);
@@ -2734,7 +3090,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
asection *s;
bfd_boolean dyn;
- int tls_type = sh_elf_hash_entry (h)->tls_type;
+ int got_type = sh_elf_hash_entry (h)->got_type;
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
@@ -2749,21 +3105,40 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
h->got.offset = s->size;
s->size += 4;
/* R_SH_TLS_GD needs 2 consecutive GOT slots. */
- if (tls_type == GOT_TLS_GD)
+ if (got_type == GOT_TLS_GD)
s->size += 4;
dyn = htab->root.dynamic_sections_created;
+ if (!dyn)
+ {
+ /* No dynamic relocations required. */
+ if (htab->fdpic_p && !info->shared
+ && h->root.type != bfd_link_hash_undefweak
+ && (got_type == GOT_NORMAL || got_type == GOT_FUNCDESC))
+ htab->srofixup->size += 4;
+ }
/* R_SH_TLS_IE_32 needs one dynamic relocation if dynamic,
R_SH_TLS_GD needs one if local symbol and two if global. */
- if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
- || (tls_type == GOT_TLS_IE && dyn))
+ else if ((got_type == GOT_TLS_GD && h->dynindx == -1)
+ || got_type == GOT_TLS_IE)
htab->srelgot->size += sizeof (Elf32_External_Rela);
- else if (tls_type == GOT_TLS_GD)
+ else if (got_type == GOT_TLS_GD)
htab->srelgot->size += 2 * sizeof (Elf32_External_Rela);
+ else if (got_type == GOT_FUNCDESC)
+ {
+ if (!info->shared && SYMBOL_FUNCDESC_LOCAL (info, h))
+ htab->srofixup->size += 4;
+ else
+ htab->srelgot->size += sizeof (Elf32_External_Rela);
+ }
else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& (info->shared
|| WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
htab->srelgot->size += sizeof (Elf32_External_Rela);
+ else if (htab->fdpic_p && !info->shared && got_type == GOT_NORMAL
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ htab->srofixup->size += 4;
}
else
h->got.offset = (bfd_vma) -1;
@@ -2794,6 +3169,46 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
eh->datalabel_got.offset = (bfd_vma) -1;
#endif
+ /* Allocate space for any dynamic relocations to function
+ descriptors, canonical or otherwise. We need to relocate the
+ reference unless it resolves to zero, which only happens for
+ undefined weak symbols (either non-default visibility, or when
+ static linking). Any GOT slot is accounted for elsewhere. */
+ if (eh->abs_funcdesc_refcount > 0
+ && (h->root.type != bfd_link_hash_undefweak
+ || (htab->root.dynamic_sections_created
+ && ! SYMBOL_CALLS_LOCAL (info, h))))
+ {
+ if (!info->shared && SYMBOL_FUNCDESC_LOCAL (info, h))
+ htab->srofixup->size += eh->abs_funcdesc_refcount * 4;
+ else
+ htab->srelgot->size
+ += eh->abs_funcdesc_refcount * sizeof (Elf32_External_Rela);
+ }
+
+ /* We must allocate a function descriptor if there are references to
+ a canonical descriptor (R_SH_GOTFUNCDESC or R_SH_FUNCDESC) and
+ the dynamic linker isn't going to allocate it. None of this
+ applies if we already created one in .got.plt, but if the
+ canonical function descriptor can be in this object, there
+ won't be a PLT entry at all. */
+ if ((eh->funcdesc.refcount > 0
+ || (h->got.offset != MINUS_ONE && eh->got_type == GOT_FUNCDESC))
+ && h->root.type != bfd_link_hash_undefweak
+ && SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ /* Make room for this function descriptor. */
+ eh->funcdesc.offset = htab->sfuncdesc->size;
+ htab->sfuncdesc->size += 8;
+
+ /* We will need a relocation or two fixups to initialize the
+ function descriptor, so allocate those too. */
+ if (!info->shared && SYMBOL_CALLS_LOCAL (info, h))
+ htab->srofixup->size += 8;
+ else
+ htab->srelfuncdesc->size += sizeof (Elf32_External_Rela);
+ }
+
if (eh->dyn_relocs == NULL)
return TRUE;
@@ -2889,6 +3304,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
{
asection *sreloc = elf_section_data (p->sec)->sreloc;
sreloc->size += p->count * sizeof (Elf32_External_Rela);
+
+ /* If we need relocations, we do not need fixups. */
+ if (htab->fdpic_p && !info->shared)
+ htab->srofixup->size -= 4 * (p->count - p->pc_count);
}
return TRUE;
@@ -2931,9 +3350,87 @@ static bfd_boolean
sh_elf_always_size_sections (bfd *output_bfd, struct bfd_link_info *info)
{
sh_elf_hash_table (info)->plt_info = get_plt_info (output_bfd, info->shared);
+
+ if (sh_elf_hash_table (info)->fdpic_p && !info->relocatable)
+ {
+ struct elf_link_hash_entry *h;
+
+ /* Force a PT_GNU_STACK segment to be created. */
+ if (! elf_tdata (output_bfd)->stack_flags)
+ elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
+
+ /* Define __stacksize if it's not defined yet. */
+ h = elf_link_hash_lookup (elf_hash_table (info), "__stacksize",
+ FALSE, FALSE, FALSE);
+ if (! h || h->root.type != bfd_link_hash_defined
+ || h->type != STT_OBJECT
+ || !h->def_regular)
+ {
+ struct bfd_link_hash_entry *bh = NULL;
+
+ if (!(_bfd_generic_link_add_one_symbol
+ (info, output_bfd, "__stacksize",
+ BSF_GLOBAL, bfd_abs_section_ptr, DEFAULT_STACK_SIZE,
+ (const char *) NULL, FALSE,
+ get_elf_backend_data (output_bfd)->collect, &bh)))
+ return FALSE;
+
+ h = (struct elf_link_hash_entry *) bh;
+ h->def_regular = 1;
+ h->type = STT_OBJECT;
+ }
+ }
return TRUE;
}
+#if !defined INCLUDE_SHMEDIA && !defined SH_TARGET_ALREADY_DEFINED
+
+static bfd_boolean
+sh_elf_modify_program_headers (bfd *output_bfd, struct bfd_link_info *info)
+{
+ struct elf_obj_tdata *tdata = elf_tdata (output_bfd);
+ struct elf_segment_map *m;
+ Elf_Internal_Phdr *p;
+
+ /* objcopy and strip preserve what's already there using
+ sh_elf_copy_private_bfd_data (). */
+ if (! info)
+ return TRUE;
+
+ for (p = tdata->phdr, m = tdata->segment_map; m != NULL; m = m->next, p++)
+ if (m->p_type == PT_GNU_STACK)
+ break;
+
+ if (m)
+ {
+ struct elf_link_hash_entry *h;
+
+ /* Obtain the pointer to the __stacksize symbol. */
+ h = elf_link_hash_lookup (elf_hash_table (info), "__stacksize",
+ FALSE, FALSE, FALSE);
+ if (h)
+ {
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ BFD_ASSERT (h->root.type == bfd_link_hash_defined);
+ }
+
+ /* Set the header p_memsz from the symbol value. We
+ intentionally ignore the symbol section. */
+ if (h && h->root.type == bfd_link_hash_defined)
+ p->p_memsz = h->root.u.def.value;
+ else
+ p->p_memsz = DEFAULT_STACK_SIZE;
+
+ p->p_align = 8;
+ }
+
+ return TRUE;
+}
+
+#endif
+
/* Set the sizes of the dynamic sections. */
static bfd_boolean
@@ -2971,7 +3468,8 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
{
bfd_signed_vma *local_got;
bfd_signed_vma *end_local_got;
- char *local_tls_type;
+ union gotref *local_funcdesc, *end_local_funcdesc;
+ char *local_got_type;
bfd_size_type locsymcount;
Elf_Internal_Shdr *symtab_hdr;
asection *srel;
@@ -3009,39 +3507,88 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
srel->size += p->count * sizeof (Elf32_External_Rela);
if ((p->sec->output_section->flags & SEC_READONLY) != 0)
info->flags |= DF_TEXTREL;
+
+ /* If we need relocations, we do not need fixups. */
+ if (htab->fdpic_p && !info->shared)
+ htab->srofixup->size -= 4 * (p->count - p->pc_count);
}
}
}
- local_got = elf_local_got_refcounts (ibfd);
- if (!local_got)
- continue;
-
symtab_hdr = &elf_symtab_hdr (ibfd);
locsymcount = symtab_hdr->sh_info;
#ifdef INCLUDE_SHMEDIA
/* Count datalabel local GOT. */
locsymcount *= 2;
#endif
- end_local_got = local_got + locsymcount;
- local_tls_type = sh_elf_local_got_tls_type (ibfd);
s = htab->sgot;
srel = htab->srelgot;
- for (; local_got < end_local_got; ++local_got)
+
+ local_got = elf_local_got_refcounts (ibfd);
+ if (local_got)
{
- if (*local_got > 0)
+ end_local_got = local_got + locsymcount;
+ local_got_type = sh_elf_local_got_type (ibfd);
+ local_funcdesc = sh_elf_local_funcdesc (ibfd);
+ for (; local_got < end_local_got; ++local_got)
{
- *local_got = s->size;
- s->size += 4;
- if (*local_tls_type == GOT_TLS_GD)
- s->size += 4;
- if (info->shared)
- srel->size += sizeof (Elf32_External_Rela);
+ if (*local_got > 0)
+ {
+ *local_got = s->size;
+ s->size += 4;
+ if (*local_got_type == GOT_TLS_GD)
+ s->size += 4;
+ if (info->shared)
+ srel->size += sizeof (Elf32_External_Rela);
+ else
+ htab->srofixup->size += 4;
+
+ if (*local_got_type == GOT_FUNCDESC)
+ {
+ if (local_funcdesc == NULL)
+ {
+ bfd_size_type size;
+
+ size = locsymcount * sizeof (union gotref);
+ local_funcdesc = (union gotref *) bfd_zalloc (ibfd,
+ size);
+ if (local_funcdesc == NULL)
+ return FALSE;
+ sh_elf_local_funcdesc (ibfd) = local_funcdesc;
+ local_funcdesc += (local_got
+ - elf_local_got_refcounts (ibfd));
+ }
+ local_funcdesc->refcount++;
+ ++local_funcdesc;
+ }
+ }
+ else
+ *local_got = (bfd_vma) -1;
+ ++local_got_type;
+ }
+ }
+
+ local_funcdesc = sh_elf_local_funcdesc (ibfd);
+ if (local_funcdesc)
+ {
+ end_local_funcdesc = local_funcdesc + locsymcount;
+
+ for (; local_funcdesc < end_local_funcdesc; ++local_funcdesc)
+ {
+ if (local_funcdesc->refcount > 0)
+ {
+ local_funcdesc->offset = htab->sfuncdesc->size;
+ htab->sfuncdesc->size += 8;
+ if (!info->shared)
+ htab->srofixup->size += 8;
+ else
+ htab->srelfuncdesc->size += sizeof (Elf32_External_Rela);
+ }
+ else
+ local_funcdesc->offset = MINUS_ONE;
}
- else
- *local_got = (bfd_vma) -1;
- ++local_tls_type;
}
+
}
if (htab->tls_ldm_got.refcount > 0)
@@ -3055,10 +3602,30 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
else
htab->tls_ldm_got.offset = -1;
+ /* Only the reserved entries should be present. For FDPIC, they go at
+ the end of .got.plt. */
+ if (htab->fdpic_p)
+ {
+ BFD_ASSERT (htab->sgotplt && htab->sgotplt->size == 12);
+ htab->sgotplt->size = 0;
+ }
+
/* Allocate global sym .plt and .got entries, and space for global
sym dynamic relocs. */
elf_link_hash_traverse (&htab->root, allocate_dynrelocs, info);
+ /* Move the reserved entries and the _GLOBAL_OFFSET_TABLE_ symbol to the
+ end of the FDPIC .got.plt. */
+ if (htab->fdpic_p)
+ {
+ htab->root.hgot->root.u.def.value = htab->sgotplt->size;
+ htab->sgotplt->size += 12;
+ }
+
+ /* At the very end of the .rofixup section is a pointer to the GOT. */
+ if (htab->fdpic_p && htab->srofixup != NULL)
+ htab->srofixup->size += 4;
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
@@ -3070,6 +3637,8 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
if (s == htab->splt
|| s == htab->sgot
|| s == htab->sgotplt
+ || s == htab->sfuncdesc
+ || s == htab->srofixup
|| s == htab->sdynbss)
{
/* Strip this section if we don't need it; see the
@@ -3143,6 +3712,12 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|| ! add_dynamic_entry (DT_JMPREL, 0))
return FALSE;
}
+ else if ((elf_elfheader (output_bfd)->e_flags & EF_SH_FDPIC)
+ && htab->sgot->size != 0)
+ {
+ if (! add_dynamic_entry (DT_PLTGOT, 0))
+ return FALSE;
+ }
if (relocs)
{
@@ -3172,6 +3747,175 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
return TRUE;
}
+/* Add a dynamic relocation to the SRELOC section. */
+
+inline static bfd_vma
+sh_elf_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
+ int reloc_type, long dynindx, bfd_vma addend)
+{
+ Elf_Internal_Rela outrel;
+ bfd_vma reloc_offset;
+
+ outrel.r_offset = offset;
+ outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
+ outrel.r_addend = addend;
+
+ reloc_offset = sreloc->reloc_count * sizeof (Elf32_External_Rela);
+ BFD_ASSERT (reloc_offset < sreloc->size);
+ bfd_elf32_swap_reloca_out (output_bfd, &outrel,
+ sreloc->contents + reloc_offset);
+ sreloc->reloc_count++;
+
+ return reloc_offset;
+}
+
+/* Add an FDPIC read-only fixup. */
+
+inline static void
+sh_elf_add_rofixup (bfd *output_bfd, asection *srofixup, bfd_vma offset)
+{
+ bfd_vma fixup_offset;
+
+ fixup_offset = srofixup->reloc_count++ * 4;
+ BFD_ASSERT (fixup_offset < srofixup->size);
+ bfd_put_32 (output_bfd, offset, srofixup->contents + fixup_offset);
+}
+
+/* Return the offset of the generated .got section from the
+ _GLOBAL_OFFSET_TABLE_ symbol. */
+
+static bfd_signed_vma
+sh_elf_got_offset (struct elf_sh_link_hash_table *htab)
+{
+ return (htab->sgot->output_offset - htab->sgotplt->output_offset
+ - htab->root.hgot->root.u.def.value);
+}
+
+/* Find the segment number in which OSEC, and output section, is
+ located. */
+
+static unsigned
+sh_elf_osec_to_segment (bfd *output_bfd, asection *osec)
+{
+ Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section (output_bfd,
+ osec);
+
+ /* FIXME: Nothing ever says what this index is relative to. The kernel
+ supplies data in terms of the number of load segments but this is
+ a phdr index and the first phdr may not be a load segment. */
+ return (p != NULL) ? p - elf_tdata (output_bfd)->phdr : -1;
+}
+
+static bfd_boolean
+sh_elf_osec_readonly_p (bfd *output_bfd, asection *osec)
+{
+ unsigned seg = sh_elf_osec_to_segment (output_bfd, osec);
+
+ return ! (elf_tdata (output_bfd)->phdr[seg].p_flags & PF_W);
+}
+
+/* Generate the initial contents of a local function descriptor, along
+ with any relocations or fixups required. */
+static bfd_boolean
+sh_elf_initialize_funcdesc (bfd *output_bfd,
+ struct bfd_link_info *info,
+ struct elf_link_hash_entry *h,
+ bfd_vma offset,
+ asection *section,
+ bfd_vma value)
+{
+ struct elf_sh_link_hash_table *htab;
+ int dynindx;
+ bfd_vma addr, seg;
+
+ htab = sh_elf_hash_table (info);
+
+ /* FIXME: The ABI says that the offset to the function goes in the
+ descriptor, along with the segment index. We're RELA, so it could
+ go in the reloc instead... */
+
+ if (h != NULL && SYMBOL_CALLS_LOCAL (info, h))
+ {
+ section = h->root.u.def.section;
+ value = h->root.u.def.value;
+ }
+
+ if (h == NULL || SYMBOL_CALLS_LOCAL (info, h))
+ {
+ dynindx = elf_section_data (section->output_section)->dynindx;
+ addr = value + section->output_offset;
+ seg = sh_elf_osec_to_segment (output_bfd, section->output_section);
+ }
+ else
+ {
+ BFD_ASSERT (h->dynindx != -1);
+ dynindx = h->dynindx;
+ addr = seg = 0;
+ }
+
+ if (!info->shared && SYMBOL_CALLS_LOCAL (info, h))
+ {
+ if (h == NULL || h->root.type != bfd_link_hash_undefweak)
+ {
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset);
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset + 4
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset);
+ }
+
+ /* There are no dynamic relocations so fill in the final
+ address and gp value (barring fixups). */
+ addr += section->output_section->vma;
+ seg = htab->root.hgot->root.u.def.value
+ + htab->root.hgot->root.u.def.section->output_section->vma
+ + htab->root.hgot->root.u.def.section->output_offset;
+ }
+ else
+ sh_elf_add_dyn_reloc (output_bfd, htab->srelfuncdesc,
+ offset
+ + htab->sfuncdesc->output_section->vma
+ + htab->sfuncdesc->output_offset,
+ R_SH_FUNCDESC_VALUE, dynindx, 0);
+
+ bfd_put_32 (output_bfd, addr, htab->sfuncdesc->contents + offset);
+ bfd_put_32 (output_bfd, seg, htab->sfuncdesc->contents + offset + 4);
+
+ return TRUE;
+}
+
+/* Install a 20-bit movi20 field starting at ADDR, which occurs in OUTPUT_BFD.
+ VALUE is the field's value. Return bfd_reloc_ok if successful or an error
+ otherwise. */
+
+static bfd_reloc_status_type
+install_movi20_field (bfd *output_bfd, unsigned long relocation,
+ bfd *input_bfd, asection *input_section,
+ bfd_byte *contents, bfd_vma offset)
+{
+ unsigned long cur_val;
+ bfd_byte *addr;
+ bfd_reloc_status_type r;
+
+ if (offset > bfd_get_section_limit (input_bfd, input_section))
+ return bfd_reloc_outofrange;
+
+ r = bfd_check_overflow (complain_overflow_signed, 20, 0,
+ bfd_arch_bits_per_address (input_bfd), relocation);
+ if (r != bfd_reloc_ok)
+ return r;
+
+ addr = contents + offset;
+ cur_val = bfd_get_16 (output_bfd, addr);
+ bfd_put_16 (output_bfd, cur_val | ((relocation & 0xf0000) >> 12), addr);
+ bfd_put_16 (output_bfd, relocation & 0xffff, addr + 2);
+
+ return bfd_reloc_ok;
+}
+
/* Relocate an SH ELF section. */
static bfd_boolean
@@ -3193,6 +3937,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
asection *sreloc;
asection *srelgot;
bfd_boolean is_vxworks_tls;
+ unsigned isec_segment, got_segment, plt_segment, check_segment[2];
BFD_ASSERT (is_sh_elf (input_bfd));
@@ -3204,6 +3949,19 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
dynobj = htab->root.dynobj;
local_got_offsets = elf_local_got_offsets (input_bfd);
+ isec_segment = sh_elf_osec_to_segment (output_bfd,
+ input_section->output_section);
+ if (htab->fdpic_p && htab->sgot)
+ got_segment = sh_elf_osec_to_segment (output_bfd,
+ htab->sgot->output_section);
+ else
+ got_segment = -1;
+ if (htab->fdpic_p && htab->splt)
+ plt_segment = sh_elf_osec_to_segment (output_bfd,
+ htab->splt->output_section);
+ else
+ plt_segment = -1;
+
sgot = htab->sgot;
sgotplt = htab->sgotplt;
splt = htab->splt;
@@ -3230,7 +3988,8 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
bfd_reloc_status_type r;
int seen_stt_datalabel = 0;
bfd_vma off;
- int tls_type;
+ int got_type;
+ const char *symname = NULL;
r_symndx = ELF32_R_SYM (rel->r_info);
@@ -3248,14 +4007,16 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|| r_type >= R_SH_max
|| (r_type >= (int) R_SH_FIRST_INVALID_RELOC
&& r_type <= (int) R_SH_LAST_INVALID_RELOC)
+ || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
+ && r_type <= (int) R_SH_LAST_INVALID_RELOC_2)
|| ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_3
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_3)
|| ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_4
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_4)
|| ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_5
&& r_type <= (int) R_SH_LAST_INVALID_RELOC_5)
- || (r_type >= (int) R_SH_FIRST_INVALID_RELOC_2
- && r_type <= (int) R_SH_LAST_INVALID_RELOC_2))
+ || ( r_type >= (int) R_SH_FIRST_INVALID_RELOC_6
+ && r_type <= (int) R_SH_LAST_INVALID_RELOC_6))
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
@@ -3271,10 +4032,18 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
h = NULL;
sym = NULL;
sec = NULL;
+ check_segment[0] = -1;
+ check_segment[1] = -1;
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
+
+ symname = bfd_elf_string_from_elf_section
+ (input_bfd, symtab_hdr->sh_link, sym->st_name);
+ if (symname == NULL || *symname == '\0')
+ symname = bfd_section_name (input_bfd, sec);
+
relocation = (sec->output_section->vma
+ sec->output_offset
+ sym->st_value);
@@ -3361,6 +4130,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
relocation = 0;
h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ symname = h->root.root.string;
while (h->root.type == bfd_link_hash_indirect
|| h->root.type == bfd_link_hash_warning)
{
@@ -3394,6 +4164,12 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|| r_type == R_SH_PLT_HI16)
&& h->plt.offset != (bfd_vma) -1)
|| ((r_type == R_SH_GOT32
+ || r_type == R_SH_GOT20
+ || r_type == R_SH_GOTFUNCDESC
+ || r_type == R_SH_GOTFUNCDESC20
+ || r_type == R_SH_GOTOFFFUNCDESC
+ || r_type == R_SH_GOTOFFFUNCDESC20
+ || r_type == R_SH_FUNCDESC
|| r_type == R_SH_GOT_LOW16
|| r_type == R_SH_GOT_MEDLOW16
|| r_type == R_SH_GOT_MEDHI16
@@ -3428,8 +4204,8 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
&& ((input_section->flags & SEC_DEBUGGING) != 0
&& h->def_dynamic))
|| (sec->output_section == NULL
- && (sh_elf_hash_entry (h)->tls_type == GOT_TLS_IE
- || sh_elf_hash_entry (h)->tls_type == GOT_TLS_GD)))
+ && (sh_elf_hash_entry (h)->got_type == GOT_TLS_IE
+ || sh_elf_hash_entry (h)->got_type == GOT_TLS_GD)))
;
else if (sec->output_section != NULL)
relocation = ((h->root.u.def.value
@@ -3482,6 +4258,16 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
if (info->relocatable)
continue;
+ /* Check for inter-segment relocations in FDPIC files. Most
+ relocations connect the relocation site to the location of
+ the target symbol, but there are some exceptions below. */
+ check_segment[0] = isec_segment;
+ if (sec != NULL)
+ check_segment[1] = sh_elf_osec_to_segment (output_bfd,
+ sec->output_section);
+ else
+ check_segment[1] = -1;
+
switch ((int) r_type)
{
final_link_relocate:
@@ -3675,6 +4461,24 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
outrel.r_addend = addend;
}
#endif
+ else if (htab->fdpic_p
+ && (h == NULL
+ || ((info->symbolic || h->dynindx == -1)
+ && h->def_regular)))
+ {
+ int dynindx;
+
+ BFD_ASSERT (sec != NULL);
+ BFD_ASSERT (sec->output_section != NULL);
+ dynindx = elf_section_data (sec->output_section)->dynindx;
+ outrel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32);
+ outrel.r_addend = relocation;
+ outrel.r_addend
+ += (howto->partial_inplace
+ ? bfd_get_32 (input_bfd, contents + rel->r_offset)
+ : addend);
+ outrel.r_addend -= sec->output_section->vma;
+ }
else
{
/* h->dynindx may be -1 if this symbol was marked to
@@ -3702,6 +4506,8 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+ check_segment[0] = check_segment[1] = -1;
+
/* If this reloc is against an external symbol, we do
not want to fiddle with the addend. Otherwise, we
need to include the symbol value so that it becomes
@@ -3709,6 +4515,34 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
if (! relocate)
continue;
}
+ else if (htab->fdpic_p && !info->shared
+ && r_type == R_SH_DIR32
+ && (input_section->flags & SEC_ALLOC) != 0)
+ {
+ bfd_vma offset;
+
+ if (sh_elf_osec_readonly_p (output_bfd,
+ input_section->output_section))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): cannot emit fixup to `%s' in read-only section"),
+ input_bfd,
+ input_section,
+ (long) rel->r_offset,
+ symname);
+ return FALSE;
+ }
+
+ offset = _bfd_elf_section_offset (output_bfd, info,
+ input_section, rel->r_offset);
+ if (offset != (bfd_vma)-1)
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset);
+
+ check_segment[0] = check_segment[1] = -1;
+ }
goto final_link_relocate;
case R_SH_GOTPLT32:
@@ -3748,6 +4582,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
force_got:
case R_SH_GOT32:
+ case R_SH_GOT20:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOT_LOW16:
case R_SH_GOT_MEDLOW16:
@@ -3760,6 +4595,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
offset table. */
BFD_ASSERT (sgot != NULL);
+ check_segment[0] = check_segment[1] = -1;
if (h != NULL)
{
@@ -3813,10 +4649,21 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
else
#endif
h->got.offset |= 1;
+
+ /* If we initialize the GOT entry here with a valid
+ symbol address, also add a fixup. */
+ if (htab->fdpic_p && !info->shared
+ && sh_elf_hash_entry (h)->got_type == GOT_NORMAL
+ && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ sgot->output_section->vma
+ + sgot->output_offset
+ + off);
}
}
- relocation = sgot->output_offset + off;
+ relocation = sh_elf_got_offset (htab) + off;
}
else
{
@@ -3866,12 +4713,30 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
outrel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
+ off);
- outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
- outrel.r_addend = relocation;
+ if (htab->fdpic_p)
+ {
+ int dynindx
+ = elf_section_data (sec->output_section)->dynindx;
+ outrel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32);
+ outrel.r_addend = relocation;
+ outrel.r_addend -= sec->output_section->vma;
+ }
+ else
+ {
+ outrel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
+ outrel.r_addend = relocation;
+ }
loc = srelgot->contents;
loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
}
+ else if (htab->fdpic_p
+ && (sh_elf_local_got_type (input_bfd) [r_symndx]
+ == GOT_NORMAL))
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ sgot->output_section->vma
+ + sgot->output_offset
+ + off);
#ifdef INCLUDE_SHMEDIA
if (rel->r_addend)
@@ -3881,33 +4746,39 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
local_got_offsets[r_symndx] |= 1;
}
- relocation = sgot->output_offset + off;
+ relocation = sh_elf_got_offset (htab) + off;
}
#ifdef GOT_BIAS
relocation -= GOT_BIAS;
#endif
- goto final_link_relocate;
+ if (r_type == R_SH_GOT20)
+ {
+ r = install_movi20_field (output_bfd, relocation + addend,
+ input_bfd, input_section, contents,
+ rel->r_offset);
+ break;
+ }
+ else
+ goto final_link_relocate;
case R_SH_GOTOFF:
+ case R_SH_GOTOFF20:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOTOFF_LOW16:
case R_SH_GOTOFF_MEDLOW16:
case R_SH_GOTOFF_MEDHI16:
case R_SH_GOTOFF_HI16:
#endif
- /* Relocation is relative to the start of the global offset
- table. */
-
- BFD_ASSERT (sgot != NULL);
-
- /* Note that sgot->output_offset is not involved in this
- calculation. We always want the start of .got. If we
- defined _GLOBAL_OFFSET_TABLE in a different way, as is
- permitted by the ABI, we might have to change this
- calculation. */
- relocation -= sgot->output_section->vma;
+ /* GOTOFF relocations are relative to _GLOBAL_OFFSET_TABLE_, which
+ we place at the start of the .got.plt section. This is the same
+ as the start of the output .got section, unless there are function
+ descriptors in front of it. */
+ BFD_ASSERT (sgotplt != NULL);
+ check_segment[0] = got_segment;
+ relocation -= sgotplt->output_section->vma + sgotplt->output_offset
+ + htab->root.hgot->root.u.def.value;
#ifdef GOT_BIAS
relocation -= GOT_BIAS;
@@ -3915,7 +4786,15 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
addend = rel->r_addend;
- goto final_link_relocate;
+ if (r_type == R_SH_GOTOFF20)
+ {
+ r = install_movi20_field (output_bfd, relocation + addend,
+ input_bfd, input_section, contents,
+ rel->r_offset);
+ break;
+ }
+ else
+ goto final_link_relocate;
case R_SH_GOTPC:
#ifdef INCLUDE_SHMEDIA
@@ -3926,8 +4805,8 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
#endif
/* Use global offset table as symbol value. */
- BFD_ASSERT (sgot != NULL);
- relocation = sgot->output_section->vma;
+ BFD_ASSERT (sgotplt != NULL);
+ relocation = sgotplt->output_section->vma + sgotplt->output_offset;
#ifdef GOT_BIAS
relocation += GOT_BIAS;
@@ -3952,6 +4831,13 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
if (h == NULL)
goto final_link_relocate;
+ /* We don't want to warn on calls to undefined weak symbols,
+ as calls to them must be protected by non-NULL tests
+ anyway, and unprotected calls would invoke undefined
+ behavior. */
+ if (h->root.type == bfd_link_hash_undefweak)
+ check_segment[0] = check_segment[1] = -1;
+
if (h->forced_local)
goto final_link_relocate;
@@ -3964,6 +4850,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
BFD_ASSERT (splt != NULL);
+ check_segment[1] = plt_segment;
relocation = (splt->output_section->vma
+ splt->output_offset
+ h->plt.offset);
@@ -3976,6 +4863,298 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
goto final_link_relocate;
+ /* Relocation is to the canonical function descriptor for this
+ symbol, possibly via the GOT. Initialize the GOT
+ entry and function descriptor if necessary. */
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
+ case R_SH_FUNCDESC:
+ {
+ int dynindx = -1;
+ asection *reloc_section;
+ bfd_vma reloc_offset;
+ int reloc_type = R_SH_FUNCDESC;
+
+ check_segment[0] = check_segment[1] = -1;
+
+ /* FIXME: See what FRV does for global symbols in the
+ executable, with --export-dynamic. Do they need ld.so
+ to allocate official descriptors? See what this code
+ does. */
+
+ relocation = 0;
+ addend = 0;
+
+ if (r_type == R_SH_FUNCDESC)
+ {
+ reloc_section = input_section;
+ reloc_offset = rel->r_offset;
+ }
+ else
+ {
+ reloc_section = htab->sgot;
+
+ if (h != NULL)
+ reloc_offset = h->got.offset;
+ else
+ {
+ BFD_ASSERT (local_got_offsets != NULL);
+ reloc_offset = local_got_offsets[r_symndx];
+ }
+ BFD_ASSERT (reloc_offset != MINUS_ONE);
+
+ if (reloc_offset & 1)
+ {
+ reloc_offset &= ~1;
+ goto funcdesc_done_got;
+ }
+ }
+
+ if (h && h->root.type == bfd_link_hash_undefweak
+ && (SYMBOL_CALLS_LOCAL (info, h)
+ || !htab->root.dynamic_sections_created))
+ /* Undefined weak symbol which will not be dynamically
+ resolved later; leave it at zero. */
+ goto funcdesc_leave_zero;
+ else if (SYMBOL_CALLS_LOCAL (info, h)
+ && ! SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ /* If the symbol needs a non-local function descriptor
+ but binds locally (i.e., its visibility is
+ protected), emit a dynamic relocation decayed to
+ section+offset. This is an optimization; the dynamic
+ linker would resolve our function descriptor request
+ to our copy of the function anyway. */
+ dynindx = elf_section_data (h->root.u.def.section
+ ->output_section)->dynindx;
+ relocation += h->root.u.def.section->output_offset
+ + h->root.u.def.value;
+ }
+ else if (! SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ /* If the symbol is dynamic and there will be dynamic
+ symbol resolution because we are or are linked with a
+ shared library, emit a FUNCDESC relocation such that
+ the dynamic linker will allocate the function
+ descriptor. */
+ BFD_ASSERT (h->dynindx != -1);
+ dynindx = h->dynindx;
+ }
+ else
+ {
+ bfd_vma offset;
+
+ /* Otherwise, we know we have a private function
+ descriptor, so reference it directly. */
+ reloc_type = R_SH_DIR32;
+ dynindx = elf_section_data (htab->sfuncdesc
+ ->output_section)->dynindx;
+
+ if (h)
+ {
+ offset = sh_elf_hash_entry (h)->funcdesc.offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!sh_elf_initialize_funcdesc (output_bfd, info, h,
+ offset, NULL, 0))
+ return FALSE;
+ sh_elf_hash_entry (h)->funcdesc.offset |= 1;
+ }
+ }
+ else
+ {
+ union gotref *local_funcdesc;
+
+ local_funcdesc = sh_elf_local_funcdesc (input_bfd);
+ offset = local_funcdesc[r_symndx].offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!sh_elf_initialize_funcdesc (output_bfd, info, NULL,
+ offset, sec,
+ sym->st_value))
+ return FALSE;
+ local_funcdesc[r_symndx].offset |= 1;
+ }
+ }
+
+ relocation = htab->sfuncdesc->output_offset + (offset & ~1);
+ }
+
+ if (!info->shared && SYMBOL_FUNCDESC_LOCAL (info, h))
+ {
+ bfd_vma offset;
+
+ if (sh_elf_osec_readonly_p (output_bfd,
+ reloc_section->output_section))
+ {
+ (*_bfd_error_handler)
+ (_("%B(%A+0x%lx): cannot emit fixup to `%s' in read-only section"),
+ input_bfd,
+ input_section,
+ (long) rel->r_offset,
+ symname);
+ return FALSE;
+ }
+
+ offset = _bfd_elf_section_offset (output_bfd, info,
+ reloc_section, reloc_offset);
+
+ if (offset != (bfd_vma)-1)
+ sh_elf_add_rofixup (output_bfd, htab->srofixup,
+ offset
+ + reloc_section->output_section->vma
+ + reloc_section->output_offset);
+ }
+ else if ((reloc_section->output_section->flags
+ & (SEC_ALLOC | SEC_LOAD)) == (SEC_ALLOC | SEC_LOAD))
+ {
+ bfd_vma offset;
+
+ if (sh_elf_osec_readonly_p (output_bfd,
+ reloc_section->output_section))
+ {
+ info->callbacks->warning
+ (info,
+ _("cannot emit dynamic relocations in read-only section"),
+ symname, input_bfd, reloc_section, reloc_offset);
+ return FALSE;
+ }
+
+ if (srelgot == NULL)
+ {
+ srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
+ BFD_ASSERT (srelgot != NULL);
+ }
+
+ offset = _bfd_elf_section_offset (output_bfd, info,
+ reloc_section, reloc_offset);
+
+ if (offset != (bfd_vma)-1)
+ sh_elf_add_dyn_reloc (output_bfd, srelgot,
+ offset
+ + reloc_section->output_section->vma
+ + reloc_section->output_offset,
+ reloc_type, dynindx, relocation);
+
+ if (r_type == R_SH_FUNCDESC)
+ {
+ r = bfd_reloc_ok;
+ break;
+ }
+ else
+ {
+ relocation = 0;
+ goto funcdesc_leave_zero;
+ }
+ }
+
+ if (SYMBOL_FUNCDESC_LOCAL (info, h))
+ relocation += htab->sfuncdesc->output_section->vma;
+ funcdesc_leave_zero:
+ if (r_type != R_SH_FUNCDESC)
+ {
+ bfd_put_32 (output_bfd, relocation,
+ reloc_section->contents + reloc_offset);
+ if (h != NULL)
+ h->got.offset |= 1;
+ else
+ local_got_offsets[r_symndx] |= 1;
+
+ funcdesc_done_got:
+
+ relocation = sh_elf_got_offset (htab) + reloc_offset;
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+ }
+ if (r_type == R_SH_GOTFUNCDESC20)
+ {
+ r = install_movi20_field (output_bfd, relocation + addend,
+ input_bfd, input_section, contents,
+ rel->r_offset);
+ break;
+ }
+ else
+ goto final_link_relocate;
+ }
+ break;
+
+ case R_SH_GOTOFFFUNCDESC:
+ case R_SH_GOTOFFFUNCDESC20:
+ /* FIXME: See R_SH_FUNCDESC comment about global symbols in the
+ executable and --export-dynamic. If such symbols get
+ ld.so-allocated descriptors we can not use R_SH_GOTOFFFUNCDESC
+ for them. */
+
+ check_segment[0] = check_segment[1] = -1;
+ relocation = 0;
+ addend = rel->r_addend;
+
+ if (h && (h->root.type == bfd_link_hash_undefweak
+ || !SYMBOL_FUNCDESC_LOCAL (info, h)))
+ {
+ _bfd_error_handler
+ (_("%B(%A+0x%lx): %s relocation against external symbol \"%s\""),
+ input_bfd, input_section, (long) rel->r_offset, howto->name,
+ h->root.root.string);
+ return FALSE;
+ }
+ else
+ {
+ bfd_vma offset;
+
+ /* Otherwise, we know we have a private function
+ descriptor, so reference it directly. */
+ if (h)
+ {
+ offset = sh_elf_hash_entry (h)->funcdesc.offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!sh_elf_initialize_funcdesc (output_bfd, info, h,
+ offset, NULL, 0))
+ return FALSE;
+ sh_elf_hash_entry (h)->funcdesc.offset |= 1;
+ }
+ }
+ else
+ {
+ union gotref *local_funcdesc;
+
+ local_funcdesc = sh_elf_local_funcdesc (input_bfd);
+ offset = local_funcdesc[r_symndx].offset;
+ BFD_ASSERT (offset != MINUS_ONE);
+ if ((offset & 1) == 0)
+ {
+ if (!sh_elf_initialize_funcdesc (output_bfd, info, NULL,
+ offset, sec,
+ sym->st_value))
+ return FALSE;
+ local_funcdesc[r_symndx].offset |= 1;
+ }
+ }
+
+ relocation = htab->sfuncdesc->output_offset + (offset & ~1);
+ }
+
+ relocation -= htab->root.hgot->root.u.def.value
+ + htab->sgotplt->output_offset;
+#ifdef GOT_BIAS
+ relocation -= GOT_BIAS;
+#endif
+
+ if (r_type == R_SH_GOTOFFFUNCDESC20)
+ {
+ r = install_movi20_field (output_bfd, relocation + addend,
+ input_bfd, input_section, contents,
+ rel->r_offset);
+ break;
+ }
+ else
+ goto final_link_relocate;
+
case R_SH_LOOP_START:
{
static bfd_vma start, end;
@@ -3996,20 +5175,21 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_SH_TLS_GD_32:
case R_SH_TLS_IE_32:
+ check_segment[0] = check_segment[1] = -1;
r_type = sh_elf_optimized_tls_reloc (info, r_type, h == NULL);
- tls_type = GOT_UNKNOWN;
+ got_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
- tls_type = sh_elf_local_got_tls_type (input_bfd) [r_symndx];
+ got_type = sh_elf_local_got_type (input_bfd) [r_symndx];
else if (h != NULL)
{
- tls_type = sh_elf_hash_entry (h)->tls_type;
+ got_type = sh_elf_hash_entry (h)->got_type;
if (! info->shared
&& (h->dynindx == -1
|| h->def_regular))
r_type = R_SH_TLS_LE_32;
}
- if (r_type == R_SH_TLS_GD_32 && tls_type == GOT_TLS_IE)
+ if (r_type == R_SH_TLS_GD_32 && got_type == GOT_TLS_IE)
r_type = R_SH_TLS_IE_32;
if (r_type == R_SH_TLS_LE_32)
@@ -4097,8 +5277,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
continue;
}
- sgot = htab->sgot;
- if (sgot == NULL)
+ if (sgot == NULL || sgotplt == NULL)
abort ();
if (h != NULL)
@@ -4118,7 +5297,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
off &= ~1;
bfd_put_32 (output_bfd, tpoff (info, relocation),
sgot->contents + off);
- bfd_put_32 (output_bfd, sgot->output_offset + off,
+ bfd_put_32 (output_bfd, sh_elf_got_offset (htab) + off,
contents + rel->r_offset);
continue;
}
@@ -4186,7 +5365,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
abort ();
if (r_type == (int) ELF32_R_TYPE (rel->r_info))
- relocation = sgot->output_offset + off;
+ relocation = sh_elf_got_offset (htab) + off;
else
{
bfd_vma offset;
@@ -4235,7 +5414,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
bfd_put_16 (output_bfd, 0x0009, contents + offset + 8);
bfd_put_16 (output_bfd, 0x0009, contents + offset + 10);
- bfd_put_32 (output_bfd, sgot->output_offset + off,
+ bfd_put_32 (output_bfd, sh_elf_got_offset (htab) + off,
contents + rel->r_offset);
continue;
@@ -4246,6 +5425,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
goto final_link_relocate;
case R_SH_TLS_LD_32:
+ check_segment[0] = check_segment[1] = -1;
if (! info->shared)
{
bfd_vma offset;
@@ -4293,8 +5473,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
continue;
}
- sgot = htab->sgot;
- if (sgot == NULL)
+ if (sgot == NULL || sgotplt == NULL)
abort ();
off = htab->tls_ldm_got.offset;
@@ -4319,12 +5498,13 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
htab->tls_ldm_got.offset |= 1;
}
- relocation = sgot->output_offset + off;
+ relocation = sh_elf_got_offset (htab) + off;
addend = rel->r_addend;
goto final_link_relocate;
case R_SH_TLS_LDO_32:
+ check_segment[0] = check_segment[1] = -1;
if (! info->shared)
relocation = tpoff (info, relocation);
else
@@ -4339,6 +5519,8 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
Elf_Internal_Rela outrel;
bfd_byte *loc;
+ check_segment[0] = check_segment[1] = -1;
+
if (! info->shared)
{
relocation = tpoff (info, relocation);
@@ -4376,6 +5558,28 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
}
relocation_done:
+ if (htab->fdpic_p && check_segment[0] != (unsigned) -1
+ && check_segment[0] != check_segment[1])
+ {
+ /* We don't want duplicate errors for undefined symbols. */
+ if (!h || h->root.type != bfd_link_hash_undefined)
+ {
+ if (info->shared)
+ {
+ info->callbacks->einfo
+ (_("%X%C: relocation to \"%s\" references a different segment\n"),
+ input_bfd, input_section, rel->r_offset, symname);
+ return FALSE;
+ }
+ else
+ info->callbacks->einfo
+ (_("%C: warning: relocation to \"%s\" references a different segment\n"),
+ input_bfd, input_section, rel->r_offset, symname);
+ }
+
+ elf_elfheader (output_bfd)->e_flags &= ~EF_SH_PIC;
+ }
+
if (r != bfd_reloc_ok)
{
switch (r)
@@ -4574,6 +5778,7 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
bfd_signed_vma *local_got_refcounts;
+ union gotref *local_funcdesc;
const Elf_Internal_Rela *rel, *relend;
if (info->relocatable)
@@ -4584,6 +5789,7 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
local_got_refcounts = elf_local_got_refcounts (abfd);
+ local_funcdesc = sh_elf_local_funcdesc (abfd);
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
@@ -4630,7 +5836,9 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
break;
case R_SH_GOT32:
+ case R_SH_GOT20:
case R_SH_GOTOFF:
+ case R_SH_GOTOFF20:
case R_SH_GOTPC:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOT_LOW16:
@@ -4650,6 +5858,8 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
#endif
case R_SH_TLS_GD_32:
case R_SH_TLS_IE_32:
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
if (h != NULL)
{
#ifdef INCLUDE_SHMEDIA
@@ -4680,7 +5890,28 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
}
break;
+ case R_SH_FUNCDESC:
+ if (h != NULL)
+ sh_elf_hash_entry (h)->abs_funcdesc_refcount -= 1;
+ else if (sh_elf_hash_table (info)->fdpic_p && !info->shared)
+ sh_elf_hash_table (info)->srofixup->size -= 4;
+
+ /* Fall through. */
+
+ case R_SH_GOTOFFFUNCDESC:
+ case R_SH_GOTOFFFUNCDESC20:
+ if (h != NULL)
+ sh_elf_hash_entry (h)->funcdesc.refcount -= 1;
+ else
+ local_funcdesc[r_symndx].refcount -= 1;
+ break;
+
case R_SH_DIR32:
+ if (sh_elf_hash_table (info)->fdpic_p && !info->shared
+ && (sec->flags & SEC_ALLOC) != 0)
+ sh_elf_hash_table (info)->srofixup->size -= 4;
+ /* Fall thru */
+
case R_SH_REL32:
if (info->shared)
break;
@@ -4800,12 +6031,16 @@ sh_elf_copy_indirect_symbol (struct bfd_link_info *info,
edir->datalabel_got.refcount += eind->datalabel_got.refcount;
eind->datalabel_got.refcount = 0;
#endif
+ edir->funcdesc.refcount += eind->funcdesc.refcount;
+ eind->funcdesc.refcount = 0;
+ edir->abs_funcdesc_refcount += eind->abs_funcdesc_refcount;
+ eind->abs_funcdesc_refcount = 0;
if (ind->root.type == bfd_link_hash_indirect
&& dir->got.refcount <= 0)
{
- edir->tls_type = eind->tls_type;
- eind->tls_type = GOT_UNKNOWN;
+ edir->got_type = eind->got_type;
+ eind->got_type = GOT_UNKNOWN;
}
if (ind->root.type != bfd_link_hash_indirect
@@ -4862,7 +6097,7 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
asection *srelgot;
asection *sreloc;
unsigned int r_type;
- int tls_type, old_tls_type;
+ int got_type, old_got_type;
sgot = NULL;
srelgot = NULL;
@@ -4919,14 +6154,49 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
|| h->def_regular))
r_type = R_SH_TLS_LE_32;
+ if (htab->fdpic_p)
+ switch (r_type)
+ {
+ case R_SH_GOTOFFFUNCDESC:
+ case R_SH_GOTOFFFUNCDESC20:
+ case R_SH_FUNCDESC:
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
+ if (h != NULL)
+ {
+ if (h->dynindx == -1)
+ switch (ELF_ST_VISIBILITY (h->other))
+ {
+ case STV_INTERNAL:
+ case STV_HIDDEN:
+ break;
+ default:
+ bfd_elf_link_record_dynamic_symbol (info, h);
+ break;
+ }
+ }
+ break;
+ }
+
/* Some relocs require a global offset table. */
if (htab->sgot == NULL)
{
switch (r_type)
{
+ case R_SH_DIR32:
+ /* This may require an rofixup. */
+ if (!htab->fdpic_p)
+ break;
case R_SH_GOTPLT32:
case R_SH_GOT32:
+ case R_SH_GOT20:
case R_SH_GOTOFF:
+ case R_SH_GOTOFF20:
+ case R_SH_FUNCDESC:
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
+ case R_SH_GOTOFFFUNCDESC:
+ case R_SH_GOTOFFFUNCDESC20:
case R_SH_GOTPC:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOTPLT_LOW16:
@@ -4953,13 +6223,10 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
case R_SH_TLS_GD_32:
case R_SH_TLS_LD_32:
case R_SH_TLS_IE_32:
- if (htab->sgot == NULL)
- {
- if (htab->root.dynobj == NULL)
- htab->root.dynobj = abfd;
- if (!create_got_section (htab->root.dynobj, info))
- return FALSE;
- }
+ if (htab->root.dynobj == NULL)
+ htab->root.dynobj = abfd;
+ if (!create_got_section (htab->root.dynobj, info))
+ return FALSE;
break;
default:
@@ -4993,6 +6260,7 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
force_got:
case R_SH_TLS_GD_32:
case R_SH_GOT32:
+ case R_SH_GOT20:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOT_LOW16:
case R_SH_GOT_MEDLOW16:
@@ -5001,16 +6269,22 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
case R_SH_GOT10BY4:
case R_SH_GOT10BY8:
#endif
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
switch (r_type)
{
default:
- tls_type = GOT_NORMAL;
+ got_type = GOT_NORMAL;
break;
case R_SH_TLS_GD_32:
- tls_type = GOT_TLS_GD;
+ got_type = GOT_TLS_GD;
break;
case R_SH_TLS_IE_32:
- tls_type = GOT_TLS_IE;
+ got_type = GOT_TLS_IE;
+ break;
+ case R_SH_GOTFUNCDESC:
+ case R_SH_GOTFUNCDESC20:
+ got_type = GOT_FUNCDESC;
break;
}
@@ -5027,7 +6301,7 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
else
#endif
h->got.refcount += 1;
- old_tls_type = sh_elf_hash_entry (h)->tls_type;
+ old_got_type = sh_elf_hash_entry (h)->got_type;
}
else
{
@@ -5056,10 +6330,10 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
#ifdef INCLUDE_SHMEDIA
/* Take care of both the datalabel and codelabel local
GOT offsets. */
- sh_elf_local_got_tls_type (abfd)
+ sh_elf_local_got_type (abfd)
= (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info);
#else
- sh_elf_local_got_tls_type (abfd)
+ sh_elf_local_got_type (abfd)
= (char *) (local_got_refcounts + symtab_hdr->sh_info);
#endif
}
@@ -5069,31 +6343,42 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
else
#endif
local_got_refcounts[r_symndx] += 1;
- old_tls_type = sh_elf_local_got_tls_type (abfd) [r_symndx];
+ old_got_type = sh_elf_local_got_type (abfd) [r_symndx];
}
/* If a TLS symbol is accessed using IE at least once,
there is no point to use dynamic model for it. */
- if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
- && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+ if (old_got_type != got_type && old_got_type != GOT_UNKNOWN
+ && (old_got_type != GOT_TLS_GD || got_type != GOT_TLS_IE))
{
- if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
- tls_type = GOT_TLS_IE;
+ if (old_got_type == GOT_TLS_IE && got_type == GOT_TLS_GD)
+ got_type = GOT_TLS_IE;
else
{
- (*_bfd_error_handler)
+ if ((old_got_type == GOT_FUNCDESC || got_type == GOT_FUNCDESC)
+ && (old_got_type == GOT_NORMAL || got_type == GOT_NORMAL))
+ (*_bfd_error_handler)
+ (_("%B: `%s' accessed both as normal and FDPIC symbol"),
+ abfd, h->root.root.string);
+ else if (old_got_type == GOT_FUNCDESC
+ || got_type == GOT_FUNCDESC)
+ (*_bfd_error_handler)
+ (_("%B: `%s' accessed both as FDPIC and thread local symbol"),
+ abfd, h->root.root.string);
+ else
+ (*_bfd_error_handler)
(_("%B: `%s' accessed both as normal and thread local symbol"),
abfd, h->root.root.string);
return FALSE;
}
}
- if (old_tls_type != tls_type)
+ if (old_got_type != got_type)
{
if (h != NULL)
- sh_elf_hash_entry (h)->tls_type = tls_type;
+ sh_elf_hash_entry (h)->got_type = got_type;
else
- sh_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
+ sh_elf_local_got_type (abfd) [r_symndx] = got_type;
}
break;
@@ -5102,6 +6387,70 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
sh_elf_hash_table(info)->tls_ldm_got.refcount += 1;
break;
+ case R_SH_FUNCDESC:
+ case R_SH_GOTOFFFUNCDESC:
+ case R_SH_GOTOFFFUNCDESC20:
+ if (rel->r_addend)
+ {
+ (*_bfd_error_handler)
+ (_("%B: Function descriptor relocation with non-zero addend"),
+ abfd);
+ return FALSE;
+ }
+
+ if (h == NULL)
+ {
+ union gotref *local_funcdesc;
+
+ /* We need a function descriptor for a local symbol. */
+ local_funcdesc = sh_elf_local_funcdesc (abfd);
+ if (local_funcdesc == NULL)
+ {
+ bfd_size_type size;
+
+ size = symtab_hdr->sh_info * sizeof (union gotref);
+#ifdef INCLUDE_SHMEDIA
+ /* Count datalabel local GOT. */
+ size *= 2;
+#endif
+ local_funcdesc = (union gotref *) bfd_zalloc (abfd, size);
+ if (local_funcdesc == NULL)
+ return FALSE;
+ sh_elf_local_funcdesc (abfd) = local_funcdesc;
+ }
+ local_funcdesc[r_symndx].refcount += 1;
+
+ if (r_type == R_SH_FUNCDESC)
+ {
+ if (!info->shared)
+ htab->srofixup->size += 4;
+ else
+ htab->srelgot->size += sizeof (Elf32_External_Rela);
+ }
+ }
+ else
+ {
+ sh_elf_hash_entry (h)->funcdesc.refcount++;
+ if (r_type == R_SH_FUNCDESC)
+ sh_elf_hash_entry (h)->abs_funcdesc_refcount++;
+
+ /* If there is a function descriptor reference, then
+ there should not be any non-FDPIC references. */
+ old_got_type = sh_elf_hash_entry (h)->got_type;
+ if (old_got_type != GOT_FUNCDESC && old_got_type != GOT_UNKNOWN)
+ {
+ if (old_got_type == GOT_NORMAL)
+ (*_bfd_error_handler)
+ (_("%B: `%s' accessed both as normal and FDPIC symbol"),
+ abfd, h->root.root.string);
+ else
+ (*_bfd_error_handler)
+ (_("%B: `%s' accessed both as FDPIC and thread local symbol"),
+ abfd, h->root.root.string);
+ }
+ }
+ break;
+
case R_SH_GOTPLT32:
#ifdef INCLUDE_SHMEDIA
case R_SH_GOTPLT_LOW16:
@@ -5267,6 +6616,13 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
p->pc_count += 1;
}
+ /* Allocate the fixup regardless of whether we need a relocation.
+ If we end up generating the relocation, we'll unallocate the
+ fixup. */
+ if (htab->fdpic_p && !info->shared
+ && r_type == R_SH_DIR32
+ && (sec->flags & SEC_ALLOC) != 0)
+ htab->srofixup->size += 4;
break;
case R_SH_TLS_LE_32:
@@ -5360,6 +6716,38 @@ sh_elf_copy_private_data (bfd * ibfd, bfd * obfd)
if (! is_sh_elf (ibfd) || ! is_sh_elf (obfd))
return TRUE;
+ /* Copy the stack size. */
+ if (elf_tdata (ibfd)->phdr && elf_tdata (obfd)->phdr
+ && fdpic_object_p (ibfd) && fdpic_object_p (obfd))
+ {
+ unsigned i;
+
+ for (i = 0; i < elf_elfheader (ibfd)->e_phnum; i++)
+ if (elf_tdata (ibfd)->phdr[i].p_type == PT_GNU_STACK)
+ {
+ Elf_Internal_Phdr *iphdr = &elf_tdata (ibfd)->phdr[i];
+
+ for (i = 0; i < elf_elfheader (obfd)->e_phnum; i++)
+ if (elf_tdata (obfd)->phdr[i].p_type == PT_GNU_STACK)
+ {
+ memcpy (&elf_tdata (obfd)->phdr[i], iphdr, sizeof (*iphdr));
+
+ /* Rewrite the phdrs, since we're only called after they
+ were first written. */
+ if (bfd_seek (obfd,
+ (bfd_signed_vma) get_elf_backend_data (obfd)
+ ->s->sizeof_ehdr, SEEK_SET) != 0
+ || get_elf_backend_data (obfd)->s
+ ->write_out_phdrs (obfd, elf_tdata (obfd)->phdr,
+ elf_elfheader (obfd)->e_phnum) != 0)
+ return FALSE;
+ break;
+ }
+
+ break;
+ }
+ }
+
return sh_elf_set_private_flags (obfd, elf_elfheader (ibfd)->e_flags);
}
#endif /* not sh_elf_copy_private_data */
@@ -5393,8 +6781,10 @@ sh_elf_merge_private_data (bfd *ibfd, bfd *obfd)
{
/* This happens when ld starts out with a 'blank' output file. */
elf_flags_init (obfd) = TRUE;
- elf_elfheader (obfd)->e_flags = EF_SH1;
+ elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
sh_elf_set_mach_from_flags (obfd);
+ if (elf_elfheader (obfd)->e_flags & EF_SH_FDPIC)
+ elf_elfheader (obfd)->e_flags |= EF_SH_PIC;
}
if (! sh_merge_bfd_arch (ibfd, obfd))
@@ -5406,9 +6796,18 @@ sh_elf_merge_private_data (bfd *ibfd, bfd *obfd)
return FALSE;
}
- elf_elfheader (obfd)->e_flags =
+ elf_elfheader (obfd)->e_flags &= ~EF_SH_MACH_MASK;
+ elf_elfheader (obfd)->e_flags |=
sh_elf_get_flags_from_mach (bfd_get_mach (obfd));
-
+
+ if (fdpic_object_p (ibfd) != fdpic_object_p (obfd))
+ {
+ _bfd_error_handler ("%B: attempt to mix FDPIC and non-FDPIC objects",
+ ibfd);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
return TRUE;
}
#endif /* not sh_elf_merge_private_data */
@@ -5420,7 +6819,11 @@ sh_elf_merge_private_data (bfd *ibfd, bfd *obfd)
static bfd_boolean
sh_elf_object_p (bfd *abfd)
{
- return sh_elf_set_mach_from_flags (abfd);
+ if (! sh_elf_set_mach_from_flags (abfd))
+ return FALSE;
+
+ return (((elf_elfheader (abfd)->e_flags & EF_SH_FDPIC) != 0)
+ == fdpic_object_p (abfd));
}
/* Finish up dynamic symbol handling. We set the contents of various
@@ -5440,13 +6843,14 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
if (h->plt.offset != (bfd_vma) -1)
{
asection *splt;
- asection *sgot;
- asection *srel;
+ asection *sgotplt;
+ asection *srelplt;
bfd_vma plt_index;
bfd_vma got_offset;
Elf_Internal_Rela rel;
bfd_byte *loc;
+ const struct elf_sh_plt_info *plt_info;
/* This symbol has an entry in the procedure linkage table. Set
it up. */
@@ -5454,9 +6858,9 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
BFD_ASSERT (h->dynindx != -1);
splt = htab->splt;
- sgot = htab->sgotplt;
- srel = htab->srelplt;
- BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
+ sgotplt = htab->sgotplt;
+ srelplt = htab->srelplt;
+ BFD_ASSERT (splt != NULL && sgotplt != NULL && srelplt != NULL);
/* Get the index in the procedure linkage table which
corresponds to this symbol. This is the index of this symbol
@@ -5464,10 +6868,21 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
first entry in the procedure linkage table is reserved. */
plt_index = get_plt_index (htab->plt_info, h->plt.offset);
+ plt_info = htab->plt_info;
+ if (plt_info->short_plt != NULL && plt_index <= MAX_SHORT_PLT)
+ plt_info = plt_info->short_plt;
+
/* Get the offset into the .got table of the entry that
- corresponds to this function. Each .got entry is 4 bytes.
- The first three are reserved. */
- got_offset = (plt_index + 3) * 4;
+ corresponds to this function. */
+ if (htab->fdpic_p)
+ /* The offset must be relative to the GOT symbol, twelve bytes
+ before the end of .got.plt. Each descriptor is eight
+ bytes. */
+ got_offset = plt_index * 8 + 12 - sgotplt->size;
+ else
+ /* Each .got entry is 4 bytes. The first three are
+ reserved. */
+ got_offset = (plt_index + 3) * 4;
#ifdef GOT_BIAS
if (info->shared)
@@ -5476,23 +6891,37 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
/* Fill in the entry in the procedure linkage table. */
memcpy (splt->contents + h->plt.offset,
- htab->plt_info->symbol_entry,
- htab->plt_info->symbol_entry_size);
+ plt_info->symbol_entry,
+ plt_info->symbol_entry_size);
- if (info->shared)
- install_plt_field (output_bfd, FALSE, got_offset,
- (splt->contents
- + h->plt.offset
- + htab->plt_info->symbol_fields.got_entry));
+ if (info->shared || htab->fdpic_p)
+ {
+ if (plt_info->symbol_fields.got20)
+ {
+ bfd_reloc_status_type r;
+ r = install_movi20_field (output_bfd, got_offset,
+ splt->owner, splt, splt->contents,
+ h->plt.offset
+ + plt_info->symbol_fields.got_entry);
+ BFD_ASSERT (r == bfd_reloc_ok);
+ }
+ else
+ install_plt_field (output_bfd, FALSE, got_offset,
+ (splt->contents
+ + h->plt.offset
+ + plt_info->symbol_fields.got_entry));
+ }
else
{
+ BFD_ASSERT (!plt_info->symbol_fields.got20);
+
install_plt_field (output_bfd, FALSE,
- (sgot->output_section->vma
- + sgot->output_offset
+ (sgotplt->output_section->vma
+ + sgotplt->output_offset
+ got_offset),
(splt->contents
+ h->plt.offset
- + htab->plt_info->symbol_fields.got_entry));
+ + plt_info->symbol_fields.got_entry));
if (htab->vxworks_p)
{
unsigned int reachable_plts, plts_per_4k;
@@ -5506,61 +6935,73 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
/* ??? It would be better to create multiple copies of
the common resolver stub. */
reachable_plts = ((4096
- - htab->plt_info->plt0_entry_size
- - (htab->plt_info->symbol_fields.plt + 4))
- / htab->plt_info->symbol_entry_size) + 1;
- plts_per_4k = (4096 / htab->plt_info->symbol_entry_size);
+ - plt_info->plt0_entry_size
+ - (plt_info->symbol_fields.plt + 4))
+ / plt_info->symbol_entry_size) + 1;
+ plts_per_4k = (4096 / plt_info->symbol_entry_size);
if (plt_index < reachable_plts)
distance = -(h->plt.offset
- + htab->plt_info->symbol_fields.plt);
+ + plt_info->symbol_fields.plt);
else
distance = -(((plt_index - reachable_plts) % plts_per_4k + 1)
- * htab->plt_info->symbol_entry_size);
+ * plt_info->symbol_entry_size);
/* Install the 'bra' with this offset. */
bfd_put_16 (output_bfd,
0xa000 | (0x0fff & ((distance - 4) / 2)),
(splt->contents
+ h->plt.offset
- + htab->plt_info->symbol_fields.plt));
+ + plt_info->symbol_fields.plt));
}
else
install_plt_field (output_bfd, TRUE,
splt->output_section->vma + splt->output_offset,
(splt->contents
+ h->plt.offset
- + htab->plt_info->symbol_fields.plt));
+ + plt_info->symbol_fields.plt));
}
+ /* Make got_offset relative to the start of .got.plt. */
#ifdef GOT_BIAS
if (info->shared)
got_offset += GOT_BIAS;
#endif
+ if (htab->fdpic_p)
+ got_offset = plt_index * 8;
- install_plt_field (output_bfd, FALSE,
- plt_index * sizeof (Elf32_External_Rela),
- (splt->contents
- + h->plt.offset
- + htab->plt_info->symbol_fields.reloc_offset));
+ if (plt_info->symbol_fields.reloc_offset != MINUS_ONE)
+ install_plt_field (output_bfd, FALSE,
+ plt_index * sizeof (Elf32_External_Rela),
+ (splt->contents
+ + h->plt.offset
+ + plt_info->symbol_fields.reloc_offset));
/* Fill in the entry in the global offset table. */
bfd_put_32 (output_bfd,
(splt->output_section->vma
+ splt->output_offset
+ h->plt.offset
- + htab->plt_info->symbol_resolve_offset),
- sgot->contents + got_offset);
+ + plt_info->symbol_resolve_offset),
+ sgotplt->contents + got_offset);
+ if (htab->fdpic_p)
+ bfd_put_32 (output_bfd,
+ sh_elf_osec_to_segment (output_bfd,
+ htab->splt->output_section),
+ sgotplt->contents + got_offset + 4);
/* Fill in the entry in the .rela.plt section. */
- rel.r_offset = (sgot->output_section->vma
- + sgot->output_offset
+ rel.r_offset = (sgotplt->output_section->vma
+ + sgotplt->output_offset
+ got_offset);
- rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_JMP_SLOT);
+ if (htab->fdpic_p)
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_FUNCDESC_VALUE);
+ else
+ rel.r_info = ELF32_R_INFO (h->dynindx, R_SH_JMP_SLOT);
rel.r_addend = 0;
#ifdef GOT_BIAS
rel.r_addend = GOT_BIAS;
#endif
- loc = srel->contents + plt_index * sizeof (Elf32_External_Rela);
+ loc = srelplt->contents + plt_index * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
if (htab->vxworks_p && !info->shared)
@@ -5575,7 +7016,7 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
rel.r_offset = (htab->splt->output_section->vma
+ htab->splt->output_offset
+ h->plt.offset
- + htab->plt_info->symbol_fields.got_entry);
+ + plt_info->symbol_fields.got_entry);
rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_SH_DIR32);
rel.r_addend = got_offset;
bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
@@ -5583,8 +7024,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
/* Create a .rela.plt.unloaded R_SH_DIR32 relocation for
the .got.plt entry, which initially points to .plt. */
- rel.r_offset = (htab->sgotplt->output_section->vma
- + htab->sgotplt->output_offset
+ rel.r_offset = (sgotplt->output_section->vma
+ + sgotplt->output_offset
+ got_offset);
rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_SH_DIR32);
rel.r_addend = 0;
@@ -5600,11 +7041,12 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
}
if (h->got.offset != (bfd_vma) -1
- && sh_elf_hash_entry (h)->tls_type != GOT_TLS_GD
- && sh_elf_hash_entry (h)->tls_type != GOT_TLS_IE)
+ && sh_elf_hash_entry (h)->got_type != GOT_TLS_GD
+ && sh_elf_hash_entry (h)->got_type != GOT_TLS_IE
+ && sh_elf_hash_entry (h)->got_type != GOT_FUNCDESC)
{
asection *sgot;
- asection *srel;
+ asection *srelgot;
Elf_Internal_Rela rel;
bfd_byte *loc;
@@ -5612,8 +7054,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
up. */
sgot = htab->sgot;
- srel = htab->srelgot;
- BFD_ASSERT (sgot != NULL && srel != NULL);
+ srelgot = htab->srelgot;
+ BFD_ASSERT (sgot != NULL && srelgot != NULL);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
@@ -5627,10 +7069,23 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
if (info->shared
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
- rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
- rel.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
+ if (htab->fdpic_p)
+ {
+ asection *sec = h->root.u.def.section;
+ int dynindx
+ = elf_section_data (sec->output_section)->dynindx;
+
+ rel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32);
+ rel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
+ rel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
}
else
{
@@ -5639,8 +7094,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
rel.r_addend = 0;
}
- loc = srel->contents;
- loc += srel->reloc_count++ * sizeof (Elf32_External_Rela);
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
}
@@ -5652,7 +7107,7 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
if (eh->datalabel_got.offset != (bfd_vma) -1)
{
asection *sgot;
- asection *srel;
+ asection *srelgot;
Elf_Internal_Rela rel;
bfd_byte *loc;
@@ -5660,8 +7115,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
Set it up. */
sgot = htab->sgot;
- srel = htab->srelgot;
- BFD_ASSERT (sgot != NULL && srel != NULL);
+ srelgot = htab->srelgot;
+ BFD_ASSERT (sgot != NULL && srelgot != NULL);
rel.r_offset = (sgot->output_section->vma
+ sgot->output_offset
@@ -5675,10 +7130,23 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
if (info->shared
&& SYMBOL_REFERENCES_LOCAL (info, h))
{
- rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
- rel.r_addend = (h->root.u.def.value
- + h->root.u.def.section->output_section->vma
- + h->root.u.def.section->output_offset);
+ if (htab->fdpic_p)
+ {
+ asection *sec = h->root.u.def.section;
+ int dynindx
+ = elf_section_data (sec->output_section)->dynindx;
+
+ rel.r_info = ELF32_R_INFO (dynindx, R_SH_DIR32);
+ rel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_offset);
+ }
+ else
+ {
+ rel.r_info = ELF32_R_INFO (0, R_SH_RELATIVE);
+ rel.r_addend = (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+ }
}
else
{
@@ -5688,8 +7156,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
rel.r_addend = 0;
}
- loc = srel->contents;
- loc += srel->reloc_count++ * sizeof (Elf32_External_Rela);
+ loc = srelgot->contents;
+ loc += srelgot->reloc_count++ * sizeof (Elf32_External_Rela);
bfd_elf32_swap_reloca_out (output_bfd, &rel, loc);
}
}
@@ -5736,14 +7204,14 @@ static bfd_boolean
sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
{
struct elf_sh_link_hash_table *htab;
- asection *sgot;
+ asection *sgotplt;
asection *sdyn;
htab = sh_elf_hash_table (info);
if (htab == NULL)
return FALSE;
- sgot = htab->sgotplt;
+ sgotplt = htab->sgotplt;
sdyn = bfd_get_section_by_name (htab->root.dynobj, ".dynamic");
if (htab->root.dynamic_sections_created)
@@ -5751,7 +7219,7 @@ sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
asection *splt;
Elf32_External_Dyn *dyncon, *dynconend;
- BFD_ASSERT (sgot != NULL && sdyn != NULL);
+ BFD_ASSERT (sgotplt != NULL && sdyn != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
@@ -5797,12 +7265,15 @@ sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
#endif
case DT_PLTGOT:
- s = htab->sgot->output_section;
- goto get_vma;
+ BFD_ASSERT (htab->root.hgot != NULL);
+ s = htab->root.hgot->root.u.def.section;
+ dyn.d_un.d_ptr = htab->root.hgot->root.u.def.value
+ + s->output_section->vma + s->output_offset;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
case DT_JMPREL:
s = htab->srelplt->output_section;
- get_vma:
BFD_ASSERT (s != NULL);
dyn.d_un.d_ptr = s->vma;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
@@ -5847,8 +7318,8 @@ sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
for (i = 0; i < ARRAY_SIZE (htab->plt_info->plt0_got_fields); i++)
if (htab->plt_info->plt0_got_fields[i] != MINUS_ONE)
install_plt_field (output_bfd, FALSE,
- (sgot->output_section->vma
- + sgot->output_offset
+ (sgotplt->output_section->vma
+ + sgotplt->output_offset
+ (i * 4)),
(splt->contents
+ htab->plt_info->plt0_got_fields[i]));
@@ -5899,20 +7370,43 @@ sh_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info)
}
/* Fill in the first three entries in the global offset table. */
- if (sgot && sgot->size > 0)
+ if (sgotplt && sgotplt->size > 0 && !htab->fdpic_p)
{
if (sdyn == NULL)
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents);
else
bfd_put_32 (output_bfd,
sdyn->output_section->vma + sdyn->output_offset,
- sgot->contents);
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
- bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
+ sgotplt->contents);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 4);
+ bfd_put_32 (output_bfd, (bfd_vma) 0, sgotplt->contents + 8);
+ }
+
+ if (sgotplt && sgotplt->size > 0)
+ elf_section_data (sgotplt->output_section)->this_hdr.sh_entsize = 4;
+
+ /* At the very end of the .rofixup section is a pointer to the GOT. */
+ if (htab->fdpic_p && htab->srofixup != NULL)
+ {
+ struct elf_link_hash_entry *hgot = htab->root.hgot;
+ bfd_vma got_value = hgot->root.u.def.value
+ + hgot->root.u.def.section->output_section->vma
+ + hgot->root.u.def.section->output_offset;
+
+ sh_elf_add_rofixup (output_bfd, htab->srofixup, got_value);
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ /* Make sure we allocated and generated the same number of fixups. */
+ BFD_ASSERT (htab->srofixup->reloc_count * 4 == htab->srofixup->size);
}
+ if (htab->srelfuncdesc)
+ BFD_ASSERT (htab->srelfuncdesc->reloc_count * sizeof (Elf32_External_Rela)
+ == htab->srelfuncdesc->size);
+
+ if (htab->srelgot)
+ BFD_ASSERT (htab->srelgot->reloc_count * sizeof (Elf32_External_Rela)
+ == htab->srelgot->size);
+
return TRUE;
}
@@ -6010,6 +7504,59 @@ sh_elf_plt_sym_val (bfd_vma i, const asection *plt,
return plt->vma + get_plt_offset (plt_info, i);
}
+/* Decide whether to attempt to turn absptr or lsda encodings in
+ shared libraries into pcrel within the given input section. */
+
+static bfd_boolean
+sh_elf_use_relative_eh_frame (bfd *input_bfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info,
+ asection *eh_frame_section ATTRIBUTE_UNUSED)
+{
+ struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info);
+
+ /* We can't use PC-relative encodings in FDPIC binaries, in general. */
+ if (htab->fdpic_p)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Adjust the contents of an eh_frame_hdr section before they're output. */
+
+static bfd_byte
+sh_elf_encode_eh_address (bfd *abfd,
+ struct bfd_link_info *info,
+ asection *osec, bfd_vma offset,
+ asection *loc_sec, bfd_vma loc_offset,
+ bfd_vma *encoded)
+{
+ struct elf_sh_link_hash_table *htab = sh_elf_hash_table (info);
+ struct elf_link_hash_entry *h;
+
+ if (!htab->fdpic_p)
+ return _bfd_elf_encode_eh_address (abfd, info, osec, offset, loc_sec,
+ loc_offset, encoded);
+
+ h = htab->root.hgot;
+ BFD_ASSERT (h && h->root.type == bfd_link_hash_defined);
+
+ if (! h || (sh_elf_osec_to_segment (abfd, osec)
+ == sh_elf_osec_to_segment (abfd, loc_sec->output_section)))
+ return _bfd_elf_encode_eh_address (abfd, info, osec, offset,
+ loc_sec, loc_offset, encoded);
+
+ BFD_ASSERT (sh_elf_osec_to_segment (abfd, osec)
+ == (sh_elf_osec_to_segment
+ (abfd, h->root.u.def.section->output_section)));
+
+ *encoded = osec->vma + offset
+ - (h->root.u.def.value
+ + h->root.u.def.section->output_section->vma
+ + h->root.u.def.section->output_offset);
+
+ return DW_EH_PE_datarel | DW_EH_PE_sdata4;
+}
+
#if !defined SH_TARGET_ALREADY_DEFINED
#define TARGET_BIG_SYM bfd_elf32_sh_vec
#define TARGET_BIG_NAME "elf32-sh"
@@ -6059,14 +7606,19 @@ sh_elf_plt_sym_val (bfd_vma i, const asection *plt,
sh_elf_always_size_sections
#define elf_backend_size_dynamic_sections \
sh_elf_size_dynamic_sections
-#define elf_backend_omit_section_dynsym \
- ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+#define elf_backend_omit_section_dynsym sh_elf_omit_section_dynsym
#define elf_backend_finish_dynamic_symbol \
sh_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
sh_elf_finish_dynamic_sections
#define elf_backend_reloc_type_class sh_elf_reloc_type_class
#define elf_backend_plt_sym_val sh_elf_plt_sym_val
+#define elf_backend_can_make_relative_eh_frame \
+ sh_elf_use_relative_eh_frame
+#define elf_backend_can_make_lsda_relative_eh_frame \
+ sh_elf_use_relative_eh_frame
+#define elf_backend_encode_eh_address \
+ sh_elf_encode_eh_address
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
@@ -6120,6 +7672,28 @@ sh_elf_plt_sym_val (bfd_vma i, const asection *plt,
#include "elf32-target.h"
+
+/* FDPIC support. */
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM bfd_elf32_shbfd_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME "elf32-shbig-fdpic"
+#undef TARGET_LITTLE_SYM
+#define TARGET_LITTLE_SYM bfd_elf32_shfd_vec
+#undef TARGET_LITTLE_NAME
+#define TARGET_LITTLE_NAME "elf32-sh-fdpic"
+#undef elf_backend_modify_program_headers
+#define elf_backend_modify_program_headers \
+ sh_elf_modify_program_headers
+
+#undef elf32_bed
+#define elf32_bed elf32_sh_fd_bed
+
+#include "elf32-target.h"
+
+#undef elf_backend_modify_program_headers
+
+/* VxWorks support. */
#undef TARGET_BIG_SYM
#define TARGET_BIG_SYM bfd_elf32_shvxworks_vec
#undef TARGET_BIG_NAME
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 7275dd9..b3f97f3 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -1511,6 +1511,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_SH_TLS_DTPMOD32",
"BFD_RELOC_SH_TLS_DTPOFF32",
"BFD_RELOC_SH_TLS_TPOFF32",
+ "BFD_RELOC_SH_GOT20",
+ "BFD_RELOC_SH_GOTOFF20",
+ "BFD_RELOC_SH_GOTFUNCDESC",
+ "BFD_RELOC_SH_GOTFUNCDESC20",
+ "BFD_RELOC_SH_GOTOFFFUNCDESC",
+ "BFD_RELOC_SH_GOTOFFFUNCDESC20",
+ "BFD_RELOC_SH_FUNCDESC",
"BFD_RELOC_ARC_B22_PCREL",
"BFD_RELOC_ARC_B26",
"BFD_RELOC_BFIN_16_IMM",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index a847629..7d16869 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -3255,6 +3255,20 @@ ENUMX
BFD_RELOC_SH_TLS_DTPOFF32
ENUMX
BFD_RELOC_SH_TLS_TPOFF32
+ENUMX
+ BFD_RELOC_SH_GOT20
+ENUMX
+ BFD_RELOC_SH_GOTOFF20
+ENUMX
+ BFD_RELOC_SH_GOTFUNCDESC
+ENUMX
+ BFD_RELOC_SH_GOTFUNCDESC20
+ENUMX
+ BFD_RELOC_SH_GOTOFFFUNCDESC
+ENUMX
+ BFD_RELOC_SH_GOTOFFFUNCDESC20
+ENUMX
+ BFD_RELOC_SH_FUNCDESC
ENUMDOC
Renesas / SuperH SH relocs. Not all of these appear in object files.
diff --git a/bfd/targets.c b/bfd/targets.c
index 2e330e6..69a5a94 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -663,7 +663,9 @@ extern const bfd_target bfd_elf32_sh64blin_vec;
extern const bfd_target bfd_elf32_sh64lnbsd_vec;
extern const bfd_target bfd_elf32_sh64nbsd_vec;
extern const bfd_target bfd_elf32_sh_vec;
+extern const bfd_target bfd_elf32_shbfd_vec;
extern const bfd_target bfd_elf32_shblin_vec;
+extern const bfd_target bfd_elf32_shfd_vec;
extern const bfd_target bfd_elf32_shl_vec;
extern const bfd_target bfd_elf32_shl_symbian_vec;
extern const bfd_target bfd_elf32_shlin_vec;
@@ -1003,7 +1005,9 @@ static const bfd_target * const _bfd_target_vector[] =
&bfd_elf32_littlescore_vec,
#endif
&bfd_elf32_sh_vec,
+ &bfd_elf32_shbfd_vec,
&bfd_elf32_shblin_vec,
+ &bfd_elf32_shfd_vec,
&bfd_elf32_shl_vec,
&bfd_elf32_shl_symbian_vec,
&bfd_elf32_shlin_vec,
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index c4abd96..8cfe737 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,9 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * readelf.c (get_machine_flags): Handle EF_SH_PIC and EF_SH_FDPIC.
+
2010-05-25 Jay Krell <jay.krell@cornell.edu>
PR ld/11621
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9c3e2dc..f64dcb9 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -2440,6 +2440,11 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
default: strcat (buf, _(", unknown ISA")); break;
}
+ if (e_flags & EF_SH_PIC)
+ strcat (buf, ", pic");
+
+ if (e_flags & EF_SH_FDPIC)
+ strcat (buf, ", fdpic");
break;
case EM_SH:
diff --git a/gas/ChangeLog b/gas/ChangeLog
index 028388d..9779979 100644
--- a/gas/ChangeLog
+++ b/gas/ChangeLog
@@ -1,3 +1,24 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * config/tc-sh.c (sh_fdpic): New.
+ (sh_check_fixup): Handle relocations on movi20.
+ (parse_exp): Do not reject PIC operators here.
+ (build_Mytes): Check for unhandled PIC operators here. Use
+ sh_check_fixup for movi20.
+ (enum options): Add OPTION_FDPIC.
+ (md_longopts, md_parse_option, md_show_usage): Add --fdpic.
+ (sh_fix_adjustable, md_apply_fix): Handle FDPIC and movi20 relocations.
+ (sh_elf_final_processing): Handle --fdpic.
+ (sh_uclinux_target_format): New.
+ (sh_parse_name): Handle FDPIC relocation operators.
+ * config/tc-sh.h (TARGET_FORMAT): Define specially for TE_UCLINUX.
+ (sh_uclinux_target_format): Declare for TE_UCLINUX.
+ * configure.tgt (sh-*-uclinux* | sh[12]-*-uclinux*): Set
+ em=uclinux.
+ * doc/c-sh.texi (SH Options): Document --fdpic.
+
2010-05-25 Jay Krell <jay.krell@cornell.edu>
PR ld/11621
diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c
index a7cdd0e..4e49e4e 100644
--- a/gas/config/tc-sh.c
+++ b/gas/config/tc-sh.c
@@ -145,6 +145,9 @@ static unsigned int preset_target_arch;
accommodate the insns seen so far. */
static unsigned int valid_arch;
+/* Whether --fdpic was given. */
+static int sh_fdpic;
+
const char EXP_CHARS[] = "eE";
/* Chars that mean this number is a floating point constant. */
@@ -612,7 +615,6 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
if (exp->X_op == O_PIC_reloc)
{
-#ifdef HAVE_SH64
switch (*r_type_p)
{
case BFD_RELOC_NONE:
@@ -620,6 +622,31 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
*r_type_p = exp->X_md;
break;
+ case BFD_RELOC_SH_DISP20:
+ switch (exp->X_md)
+ {
+ case BFD_RELOC_32_GOT_PCREL:
+ *r_type_p = BFD_RELOC_SH_GOT20;
+ break;
+
+ case BFD_RELOC_32_GOTOFF:
+ *r_type_p = BFD_RELOC_SH_GOTOFF20;
+ break;
+
+ case BFD_RELOC_SH_GOTFUNCDESC:
+ *r_type_p = BFD_RELOC_SH_GOTFUNCDESC20;
+ break;
+
+ case BFD_RELOC_SH_GOTOFFFUNCDESC:
+ *r_type_p = BFD_RELOC_SH_GOTOFFFUNCDESC20;
+ break;
+
+ default:
+ abort ();
+ }
+ break;
+
+#ifdef HAVE_SH64
case BFD_RELOC_SH_IMM_LOW16:
switch (exp->X_md)
{
@@ -715,13 +742,11 @@ sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p)
abort ();
}
break;
+#endif
default:
abort ();
}
-#else
- *r_type_p = exp->X_md;
-#endif
if (exp == main_exp)
exp->X_op = O_symbol;
else
@@ -1358,12 +1383,6 @@ parse_exp (char *s, sh_operand_info *op)
expression (&op->immediate);
if (op->immediate.X_op == O_absent)
as_bad (_("missing operand"));
-#ifdef OBJ_ELF
- else if (op->immediate.X_op == O_PIC_reloc
- || sh_PIC_related_p (op->immediate.X_add_symbol)
- || sh_PIC_related_p (op->immediate.X_op_symbol))
- as_bad (_("misplaced PIC operand"));
-#endif
new_pointer = input_line_pointer;
input_line_pointer = save;
return new_pointer;
@@ -2327,6 +2346,8 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
unsigned int size = 2;
int low_byte = target_big_endian ? 1 : 0;
int max_index = 4;
+ bfd_reloc_code_real_type r_type;
+ int unhandled_pic = 0;
nbuf[0] = 0;
nbuf[1] = 0;
@@ -2337,6 +2358,14 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
nbuf[6] = 0;
nbuf[7] = 0;
+ for (indx = 0; indx < 3; indx++)
+ if (opcode->arg[indx] == A_IMM
+ && operand[indx].type == A_IMM
+ && (operand[indx].immediate.X_op == O_PIC_reloc
+ || sh_PIC_related_p (operand[indx].immediate.X_add_symbol)
+ || sh_PIC_related_p (operand[indx].immediate.X_op_symbol)))
+ unhandled_pic = 1;
+
if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32))
{
output = frag_more (4);
@@ -2415,7 +2444,11 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
case IMM0_20_4:
break;
case IMM0_20:
- insert4 (output, BFD_RELOC_SH_DISP20, 0, operand);
+ r_type = BFD_RELOC_SH_DISP20;
+ if (sh_check_fixup (&operand->immediate, &r_type))
+ as_bad (_("Invalid PIC expression."));
+ unhandled_pic = 0;
+ insert4 (output, r_type, 0, operand);
break;
case IMM0_20BY8:
insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand);
@@ -2474,6 +2507,8 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand)
}
}
}
+ if (unhandled_pic)
+ as_bad (_("misplaced PIC operand"));
if (!target_big_endian)
{
output[1] = (nbuf[0] << 4) | (nbuf[1]);
@@ -3098,6 +3133,9 @@ enum options
OPTION_PT32,
#endif
OPTION_H_TICK_HEX,
+#ifdef OBJ_ELF
+ OPTION_FDPIC,
+#endif
OPTION_DUMMY /* Not used. This is just here to make it easy to add and subtract options from this enum. */
};
@@ -3126,6 +3164,10 @@ struct option md_longopts[] =
#endif /* HAVE_SH64 */
{ "h-tick-hex", no_argument, NULL, OPTION_H_TICK_HEX },
+#ifdef OBJ_ELF
+ {"fdpic", no_argument, NULL, OPTION_FDPIC},
+#endif
+
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
@@ -3259,6 +3301,12 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
enable_h_tick_hex = 1;
break;
+#ifdef OBJ_ELF
+ case OPTION_FDPIC:
+ sh_fdpic = TRUE;
+ break;
+#endif /* OBJ_ELF */
+
default:
return 0;
}
@@ -3311,6 +3359,10 @@ SH options:\n\
--expand-pt32 with -abi=64, expand PT, PTA and PTB instructions\n\
to 32 bits only\n"));
#endif /* HAVE_SH64 */
+#ifdef OBJ_ELF
+ fprintf (stream, _("\
+--fdpic generate an FDPIC object file\n"));
+#endif /* OBJ_ELF */
}
/* This struct is used to pass arguments to sh_count_relocs through
@@ -3804,7 +3856,13 @@ sh_fix_adjustable (fixS *fixP)
{
if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL
|| fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL
+ || fixP->fx_r_type == BFD_RELOC_SH_GOT20
|| fixP->fx_r_type == BFD_RELOC_SH_GOTPC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTFUNCDESC20
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC
+ || fixP->fx_r_type == BFD_RELOC_SH_GOTOFFFUNCDESC20
+ || fixP->fx_r_type == BFD_RELOC_SH_FUNCDESC
|| ((fixP->fx_r_type == BFD_RELOC_32) && dont_adjust_reloc_32)
|| fixP->fx_r_type == BFD_RELOC_RVA)
return 0;
@@ -3843,6 +3901,22 @@ sh_elf_final_processing (void)
elf_elfheader (stdoutput)->e_flags &= ~EF_SH_MACH_MASK;
elf_elfheader (stdoutput)->e_flags |= val;
+
+ if (sh_fdpic)
+ elf_elfheader (stdoutput)->e_flags |= EF_SH_FDPIC;
+}
+#endif
+
+#ifdef TE_UCLINUX
+/* Return the target format for uClinux. */
+
+const char *
+sh_uclinux_target_format (void)
+{
+ if (sh_fdpic)
+ return (!target_big_endian ? "elf32-sh-fdpic" : "elf32-shbig-fdpic");
+ else
+ return (!target_big_endian ? "elf32-shl" : "elf32-sh");
}
#endif
@@ -4151,7 +4225,13 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* Fallthrough */
case BFD_RELOC_32_GOT_PCREL:
+ case BFD_RELOC_SH_GOT20:
case BFD_RELOC_SH_GOTPLT32:
+ case BFD_RELOC_SH_GOTFUNCDESC:
+ case BFD_RELOC_SH_GOTFUNCDESC20:
+ case BFD_RELOC_SH_GOTOFFFUNCDESC:
+ case BFD_RELOC_SH_GOTOFFFUNCDESC20:
+ case BFD_RELOC_SH_FUNCDESC:
* valP = 0; /* Fully resolved at runtime. No addend. */
apply_full_field_fix (fixP, buf, 0, 4);
break;
@@ -4161,6 +4241,7 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
S_SET_THREAD_LOCAL (fixP->fx_addsy);
/* Fallthrough */
case BFD_RELOC_32_GOTOFF:
+ case BFD_RELOC_SH_GOTOFF20:
apply_full_field_fix (fixP, buf, val, 4);
break;
#endif
@@ -4468,6 +4549,14 @@ sh_parse_name (char const *name,
reloc_type = BFD_RELOC_SH_TLS_LE_32;
else if ((next_end = sh_end_of_match (next + 1, "DTPOFF")))
reloc_type = BFD_RELOC_SH_TLS_LDO_32;
+ else if ((next_end = sh_end_of_match (next + 1, "PCREL")))
+ reloc_type = BFD_RELOC_32_PCREL;
+ else if ((next_end = sh_end_of_match (next + 1, "GOTFUNCDESC")))
+ reloc_type = BFD_RELOC_SH_GOTFUNCDESC;
+ else if ((next_end = sh_end_of_match (next + 1, "GOTOFFFUNCDESC")))
+ reloc_type = BFD_RELOC_SH_GOTOFFFUNCDESC;
+ else if ((next_end = sh_end_of_match (next + 1, "FUNCDESC")))
+ reloc_type = BFD_RELOC_SH_FUNCDESC;
else
goto no_suffix;
diff --git a/gas/config/tc-sh.h b/gas/config/tc-sh.h
index 1b5ec26..2a69627 100644
--- a/gas/config/tc-sh.h
+++ b/gas/config/tc-sh.h
@@ -1,6 +1,6 @@
/* This file is tc-sh.h
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
This file is part of GAS, the GNU Assembler.
@@ -134,7 +134,7 @@ extern void sh_frob_file (void);
#define COFF_MAGIC (!target_big_endian ? SH_ARCH_MAGIC_LITTLE : SH_ARCH_MAGIC_BIG)
-#define tc_coff_symbol_emit_hook(a) ; /* not used */
+#define tc_coff_symbol_emit_hook(a) ; /* Not used. */
#define TC_KEEP_FX_OFFSET 1
@@ -155,7 +155,7 @@ extern void sh_frob_file (void);
#ifdef OBJ_ELF
/* ELF specific definitions. */
-/* Whether or not the target is big endian */
+/* Whether or not the target is big endian. */
extern int target_big_endian;
#ifdef TE_LINUX
#define TARGET_FORMAT (!target_big_endian ? "elf32-sh-linux" : "elf32-shbig-linux")
@@ -165,6 +165,9 @@ extern int target_big_endian;
#define TARGET_FORMAT (!target_big_endian ? "elf32-shl-symbian" : "elf32-sh-symbian")
#elif defined (TE_VXWORKS)
#define TARGET_FORMAT (!target_big_endian ? "elf32-shl-vxworks" : "elf32-sh-vxworks")
+#elif defined (TE_UCLINUX)
+#define TARGET_FORMAT sh_uclinux_target_format ()
+extern const char * sh_uclinux_target_format (void);
#else
#define TARGET_FORMAT (!target_big_endian ? "elf32-shl" : "elf32-sh")
#endif
@@ -172,7 +175,7 @@ extern int target_big_endian;
#define elf_tc_final_processing sh_elf_final_processing
extern void sh_elf_final_processing (void);
-#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */
+#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs. */
#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
@@ -227,8 +230,8 @@ extern bfd_boolean sh_fix_adjustable (struct fix *);
#define md_parse_name(name, exprP, mode, nextcharP) \
sh_parse_name ((name), (exprP), (mode), (nextcharP))
-int sh_parse_name (char const *name, expressionS *exprP,
- enum expr_mode mode, char *nextchar);
+int sh_parse_name (char const *, expressionS *,
+ enum expr_mode, char *);
#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
sh_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
@@ -244,7 +247,7 @@ void sh_cons_fix_new (fragS *, int, int, expressionS *);
extern void sh_cfi_frame_initial_instructions (void);
#define tc_regname_to_dw2regnum sh_regname_to_dw2regnum
-extern int sh_regname_to_dw2regnum (char *regname);
+extern int sh_regname_to_dw2regnum (char *);
/* All SH instructions are multiples of 16 bits. */
#define DWARF2_LINE_MIN_INSN_LENGTH 2
diff --git a/gas/configure.tgt b/gas/configure.tgt
index 23d8662..77cbac1 100644
--- a/gas/configure.tgt
+++ b/gas/configure.tgt
@@ -360,7 +360,8 @@ case ${generic_target} in
*) endian=big ;;
esac ;;
sh*-*-symbianelf*) fmt=elf endian=little ;;
- sh-*-elf* | sh-*-uclinux* | sh[12]-*-uclinux*) fmt=elf ;;
+ sh-*-elf*) fmt=elf ;;
+ sh-*-uclinux* | sh[12]-*-uclinux*) fmt=elf em=uclinux ;;
sh-*-coff*) fmt=coff ;;
sh-*-nto*) fmt=elf ;;
sh-*-pe*) fmt=coff em=pe bfd_gas=yes endian=little ;;
diff --git a/gas/doc/c-sh.texi b/gas/doc/c-sh.texi
index 00c95d7..619f022 100644
--- a/gas/doc/c-sh.texi
+++ b/gas/doc/c-sh.texi
@@ -1,5 +1,5 @@
-@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2003, 2004, 2005, 2008
-@c Free Software Foundation, Inc.
+@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2003, 2004,
+@c 2005, 2008, 2010 Free Software Foundation, Inc.
@c This is part of the GAS manual.
@c For copying conditions, see the file as.texinfo.
@page
@@ -54,6 +54,10 @@ Renesas assembler.
@item --allow-reg-prefix
Allow '$' as a register name prefix.
+@kindex --fdpic
+@item --fdpic
+Generate an FDPIC object file.
+
@item --isa=sh4 | sh4a
Specify the sh4 or sh4a instruction set.
@item --isa=dsp
diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog
index 59f9830..5d2a4f3 100644
--- a/gas/testsuite/ChangeLog
+++ b/gas/testsuite/ChangeLog
@@ -1,3 +1,15 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * gas/sh/basic.exp: Run new tests. Handle uClinux like Linux.
+ * gas/sh/fdpic.d: New file.
+ * gas/sh/fdpic.s: New file.
+ * gas/sh/reg-prefix.d: Force big-endian.
+ * gas/sh/sh2a-pic.d: New file.
+ * gas/sh/sh2a-pic.s: New file.
+ * lib/gas-defs.exp (is_elf_format): Include sh*-*-uclinux*.
+
2010-05-18 H.J. Lu <hongjiu.lu@intel.com>
PR gas/11600
diff --git a/gas/testsuite/gas/sh/basic.exp b/gas/testsuite/gas/sh/basic.exp
index 3bb7931..2daa038 100644
--- a/gas/testsuite/gas/sh/basic.exp
+++ b/gas/testsuite/gas/sh/basic.exp
@@ -142,7 +142,7 @@ if [istarget sh*-*-*] then {
run_dump_test "pcrel2"
}
- if {[istarget sh*-*elf] || [istarget sh*-linux*]} then {
+ if {[istarget sh*-*elf] || [istarget sh*-*linux*]} then {
if {![istarget "sh64*-*-*"] && ![istarget "sh5*-*-*"]} then {
run_dump_test "sh4a"
run_dump_test "sh4a-fp"
@@ -151,9 +151,11 @@ if [istarget sh*-*-*] then {
run_dump_test "sh4al-dsp"
run_dump_test "sh2a"
+ run_dump_test "sh2a-pic"
}
run_dump_test "pic"
+ run_dump_test "fdpic"
# Test TLS.
run_dump_test "tlsd"
diff --git a/gas/testsuite/gas/sh/fdpic.d b/gas/testsuite/gas/sh/fdpic.d
new file mode 100644
index 0000000..33dfc71
--- /dev/null
+++ b/gas/testsuite/gas/sh/fdpic.d
@@ -0,0 +1,13 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: FDPIC relocations
+
+dump.o: file format elf32-sh.*
+
+Disassembly of section .text:
+ \.\.\.
+ 0: R_SH_REL32 foo
+ 4: R_SH_FUNCDESC foo
+ 8: R_SH_GOT32 foo
+ c: R_SH_GOTOFF foo
+ 10: R_SH_GOTFUNCDESC foo
+ 14: R_SH_GOTOFFFUNCDESC foo
diff --git a/gas/testsuite/gas/sh/fdpic.s b/gas/testsuite/gas/sh/fdpic.s
new file mode 100644
index 0000000..7a7ad0f
--- /dev/null
+++ b/gas/testsuite/gas/sh/fdpic.s
@@ -0,0 +1,8 @@
+ .text
+
+ .long foo@PCREL
+ .long foo@FUNCDESC
+ .long foo@GOT
+ .long foo@GOTOFF
+ .long foo@GOTFUNCDESC
+ .long foo@GOTOFFFUNCDESC
diff --git a/gas/testsuite/gas/sh/reg-prefix.d b/gas/testsuite/gas/sh/reg-prefix.d
index 1821bbc..a42e8c4 100644
--- a/gas/testsuite/gas/sh/reg-prefix.d
+++ b/gas/testsuite/gas/sh/reg-prefix.d
@@ -1,10 +1,11 @@
#objdump: -dr --prefix-addresses --show-raw-insn
-#as: --allow-reg-prefix -little
+#as: --allow-reg-prefix -big
#name: SH --allow-reg-prefix option
+#skip: sh*-*-symbian*
# Test SH register names prefixed with $:
.*: file format elf.*sh.*
Disassembly of section .text:
-0x00000000 12 60 mov\.l @r1,r0
+0x00000000 60 12 mov\.l @r1,r0
diff --git a/gas/testsuite/gas/sh/sh2a-pic.d b/gas/testsuite/gas/sh/sh2a-pic.d
new file mode 100644
index 0000000..c7fe12b
--- /dev/null
+++ b/gas/testsuite/gas/sh/sh2a-pic.d
@@ -0,0 +1,16 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: SH2a PIC relocations
+#as: -isa=sh2a
+#skip: sh*-*-symbian*
+
+dump.o: file format elf32-sh.*
+
+Disassembly of section .text:
+0x00000000 01 00 00 00 movi20 #0,r1
+ 0: R_SH_GOT20 foo
+0x00000004 01 00 00 00 movi20 #0,r1
+ 4: R_SH_GOTOFF20 foo
+0x00000008 01 00 00 00 movi20 #0,r1
+ 8: R_SH_GOTFUNCDESC20 foo
+0x0000000c 01 00 00 00 movi20 #0,r1
+ c: R_SH_GOTOFFFUNCDESC20 foo
diff --git a/gas/testsuite/gas/sh/sh2a-pic.s b/gas/testsuite/gas/sh/sh2a-pic.s
new file mode 100644
index 0000000..888a7c9
--- /dev/null
+++ b/gas/testsuite/gas/sh/sh2a-pic.s
@@ -0,0 +1,6 @@
+ .text
+
+ movi20 #foo@GOT, r1
+ movi20 #foo@GOTOFF, r1
+ movi20 #foo@GOTFUNCDESC, r1
+ movi20 #foo@GOTOFFFUNCDESC, r1
diff --git a/gas/testsuite/lib/gas-defs.exp b/gas/testsuite/lib/gas-defs.exp
index 0506b94..fd2f179 100644
--- a/gas/testsuite/lib/gas-defs.exp
+++ b/gas/testsuite/lib/gas-defs.exp
@@ -289,6 +289,7 @@ proc is_elf_format {} {
&& ![istarget hppa*64*-*-hpux*] \
&& ![istarget *-*-linux*] \
&& ![istarget frv-*-uclinux*] \
+ && ![istarget sh*-*-uclinux*] \
&& ![istarget *-*-irix5*] \
&& ![istarget *-*-irix6*] \
&& ![istarget *-*-netbsd*] \
diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog
index 9008aaa..ddd927a 100644
--- a/include/elf/ChangeLog
+++ b/include/elf/ChangeLog
@@ -1,3 +1,14 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * sh.h (EF_SH_PIC, EF_SH_FDPIC): Define.
+ (R_SH_FIRST_INVALID_RELOC_6, R_SH_LAST_INVALID_RELOC_6): New. Adjust
+ other invalid ranges.
+ (R_SH_GOT20, R_SH_GOTOFF20, R_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC20)
+ (R_SH_GOTOFFFUNCDESC, R_SH_GOTOFFFUNCDESC20, R_SH_FUNCDESC)
+ (R_SH_FUNCDESC_VALUE): New.
+
2010-05-18 H.J. Lu <hongjiu.lu@intel.com>
PR gas/11600
diff --git a/include/elf/sh.h b/include/elf/sh.h
index fcb962a..c2bd50d 100644
--- a/include/elf/sh.h
+++ b/include/elf/sh.h
@@ -86,6 +86,12 @@ int sh_find_elf_flags (unsigned int arch_set);
/* Convert bfd_mach_* into EF_SH*. */
int sh_elf_get_flags_from_mach (unsigned long mach);
+/* Other e_flags bits. */
+
+#define EF_SH_PIC 0x100 /* Segments of an FDPIC binary may
+ be relocated independently. */
+#define EF_SH_FDPIC 0x8000 /* Uses the FDPIC ABI. */
+
/* Flags for the st_other symbol field.
Keep away from the STV_ visibility flags (bit 0..1). */
@@ -214,7 +220,17 @@ START_RELOC_NUMBERS (elf_sh_reloc_type)
RELOC_NUMBER (R_SH_JMP_SLOT64, 195)
RELOC_NUMBER (R_SH_RELATIVE64, 196)
FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_5, 197)
- FAKE_RELOC (R_SH_LAST_INVALID_RELOC_5, 241)
+ FAKE_RELOC (R_SH_LAST_INVALID_RELOC_5, 200)
+ RELOC_NUMBER (R_SH_GOT20, 201)
+ RELOC_NUMBER (R_SH_GOTOFF20, 202)
+ RELOC_NUMBER (R_SH_GOTFUNCDESC, 203)
+ RELOC_NUMBER (R_SH_GOTFUNCDESC20, 204)
+ RELOC_NUMBER (R_SH_GOTOFFFUNCDESC, 205)
+ RELOC_NUMBER (R_SH_GOTOFFFUNCDESC20, 206)
+ RELOC_NUMBER (R_SH_FUNCDESC, 207)
+ RELOC_NUMBER (R_SH_FUNCDESC_VALUE, 208)
+ FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_6, 209)
+ FAKE_RELOC (R_SH_LAST_INVALID_RELOC_6, 241)
RELOC_NUMBER (R_SH_SHMEDIA_CODE, 242)
RELOC_NUMBER (R_SH_PT_16, 243)
RELOC_NUMBER (R_SH_IMMS16, 244)
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 973e817..9cd324a 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,16 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * Makefile.am (ALL_EMULATIONS): Add eshelf_fd.o and eshlelf_fd.o.
+ (eshelf_fd.c, eshlelf_fd.c): New rules.
+ * Makefile.in: Regenerate.
+ * configure.tgt (sh-*-uclinux*): Add shelf_fd and shlelf_fd
+ emulations.
+ * emulparams/shelf_fd.sh: New file.
+ * emulparams/shlelf_fd.sh: New file.
+ * emulparams/shlelf_linux.sh: Update comment.
+
2010-05-25 Jay Krell <jay.krell@cornell.edu>
PR ld/11621
diff --git a/ld/configure.tgt b/ld/configure.tgt
index def0287..f75c96a 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -550,7 +550,7 @@ sh-*-elf* | sh[1234]*-*-elf | sh-*-rtems* | sh-*-kaos*)
targ_extra_emuls="shlelf sh shl" ;;
sh-*-uclinux* | sh[12]-*-uclinux*)
targ_emul=shelf_uclinux
- targ_extra_emuls="shelf shlelf sh shl" ;;
+ targ_extra_emuls="shelf shlelf sh shl shelf_fd shlelf_fd" ;;
sh-*-vxworks) targ_emul=shelf_vxworks
targ_extra_emuls=shlelf_vxworks ;;
sh-*-nto*) targ_emul=shelf_nto
diff --git a/ld/emulparams/shelf_fd.sh b/ld/emulparams/shelf_fd.sh
new file mode 100644
index 0000000..7ec25ab
--- /dev/null
+++ b/ld/emulparams/shelf_fd.sh
@@ -0,0 +1,2 @@
+. ${srcdir}/emulparams/shlelf_fd.sh
+OUTPUT_FORMAT="elf32-shbig-fdpic"
diff --git a/ld/emulparams/shlelf_fd.sh b/ld/emulparams/shlelf_fd.sh
new file mode 100644
index 0000000..f1f4107
--- /dev/null
+++ b/ld/emulparams/shlelf_fd.sh
@@ -0,0 +1,16 @@
+# If you change this file, please also look at files which source this one:
+# shelf_fd.sh
+
+. ${srcdir}/emulparams/shlelf_linux.sh
+OUTPUT_FORMAT="elf32-sh-fdpic"
+GOT=".got ${RELOCATING-0} : { *(.got.funcdesc) *(.got.plt) *(.got) }"
+OTHER_GOT_RELOC_SECTIONS="
+ .rela.got.funcdesc ${RELOCATING-0} : { *(.rela.got.funcdesc) }
+"
+OTHER_READONLY_SECTIONS="
+ .rofixup : {
+ ${RELOCATING+__ROFIXUP_LIST__ = .;}
+ *(.rofixup)
+ ${RELOCATING+__ROFIXUP_END__ = .;}
+ }
+"
diff --git a/ld/emulparams/shlelf_linux.sh b/ld/emulparams/shlelf_linux.sh
index 95b6acc..c14aae2 100644
--- a/ld/emulparams/shlelf_linux.sh
+++ b/ld/emulparams/shlelf_linux.sh
@@ -1,5 +1,5 @@
# If you change this file, please also look at files which source this one:
-# shelf_linux.sh
+# shelf_linux.sh shelf_fd.sh shlelf_fd.sh
SCRIPT_NAME=elf
OUTPUT_FORMAT="elf32-sh-linux"
diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog
index 61daf44..4a3989e 100644
--- a/ld/testsuite/ChangeLog
+++ b/ld/testsuite/ChangeLog
@@ -1,3 +1,46 @@
+2010-05-25 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Andrew Stubbs <ams@codesourcery.com>
+
+ * ld-sh/sh.exp: Handle uClinux like Linux.
+ * lib/ld-lib.exp (is_elf_format): Include sh*-*-uclinux*.
+ * ld-sh/fdpic-funcdesc-shared.d: New file.
+ * ld-sh/fdpic-funcdesc-shared.s: New file.
+ * ld-sh/fdpic-funcdesc-static.d: New file.
+ * ld-sh/fdpic-funcdesc-static.s: New file.
+ * ld-sh/fdpic-gotfuncdesc-shared.d: New file.
+ * ld-sh/fdpic-gotfuncdesc-shared.s: New file.
+ * ld-sh/fdpic-gotfuncdesc-static.d: New file.
+ * ld-sh/fdpic-gotfuncdesc-static.s: New file.
+ * ld-sh/fdpic-gotfuncdesci20-shared.d: New file.
+ * ld-sh/fdpic-gotfuncdesci20-shared.s: New file.
+ * ld-sh/fdpic-gotfuncdesci20-static.d: New file.
+ * ld-sh/fdpic-gotfuncdesci20-static.s: New file.
+ * ld-sh/fdpic-goti20-shared.d: New file.
+ * ld-sh/fdpic-goti20-shared.s: New file.
+ * ld-sh/fdpic-goti20-static.d: New file.
+ * ld-sh/fdpic-goti20-static.s: New file.
+ * ld-sh/fdpic-gotofffuncdesc-shared.d: New file.
+ * ld-sh/fdpic-gotofffuncdesc-shared.s: New file.
+ * ld-sh/fdpic-gotofffuncdesc-static.d: New file.
+ * ld-sh/fdpic-gotofffuncdesc-static.s: New file.
+ * ld-sh/fdpic-gotofffuncdesci20-shared.d: New file.
+ * ld-sh/fdpic-gotofffuncdesci20-shared.s: New file.
+ * ld-sh/fdpic-gotofffuncdesci20-static.d: New file.
+ * ld-sh/fdpic-gotofffuncdesci20-static.s: New file.
+ * ld-sh/fdpic-gotoffi20-shared.d: New file.
+ * ld-sh/fdpic-gotoffi20-shared.s: New file.
+ * ld-sh/fdpic-gotoffi20-static.d: New file.
+ * ld-sh/fdpic-gotoffi20-static.s: New file.
+ * ld-sh/fdpic-plt-be.d: New file.
+ * ld-sh/fdpic-plt-le.d: New file.
+ * ld-sh/fdpic-plt.s: New file.
+ * ld-sh/fdpic-plti20-be.d: New file.
+ * ld-sh/fdpic-plti20-le.d: New file.
+ * ld-sh/fdpic-stack-default.d: New file.
+ * ld-sh/fdpic-stack-size.d: New file.
+ * ld-sh/fdpic-stack.s: New file.
+
2010-05-18 H.J. Lu <hongjiu.lu@intel.com>
PR gas/11600
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-shared.d b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.d
new file mode 100644
index 0000000..899c5ae
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.d
@@ -0,0 +1,32 @@
+#source: fdpic-funcdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.data -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0009[ \t]+.*
+Contents of section \.data:
+ [0-9a-f]+ 00000000[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.data:
+
+[0-9a-f]+ <bar>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+\.\.\.\.
+[ \t]+[0-9a-f]+: R_SH_DIR32[ \t]+\.got
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-shared.s b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.s
new file mode 100644
index 0000000..87d600d
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.s
@@ -0,0 +1,10 @@
+ .data
+ .globl bar
+ .type bar,@object
+ .size bar,4
+bar:
+ .long foo@FUNCDESC
+ .text
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-static.d b/ld/testsuite/ld-sh/fdpic-funcdesc-static.d
new file mode 100644
index 0000000..cb09b90
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-funcdesc-static.d
@@ -0,0 +1,25 @@
+#source: fdpic-funcdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 400098 004100ac 004100b0 004100a8 004100b4[ \t]+.*
+Contents of section \.data:
+ 4100a8 004100ac[ \t]+.*
+Contents of section \.got:
+ 4100ac 00400094 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <foo>:
+[ \t]+400094:[ \t]+00 09[ \t]+nop[ \t]+
+
+00400096 <_start>:
+[ \t]+400096:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-static.s b/ld/testsuite/ld-sh/fdpic-funcdesc-static.s
new file mode 100644
index 0000000..f59e0d9
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-funcdesc-static.s
@@ -0,0 +1,14 @@
+ .data
+ .globl bar
+ .type bar,@object
+ .size bar,4
+bar:
+ .long foo@FUNCDESC
+ .text
+ .type foo,@function
+foo:
+ nop
+ .globl _start
+ .type _start,@function
+_start:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d
new file mode 100644
index 0000000..c86b424
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d
@@ -0,0 +1,25 @@
+#source: fdpic-gotfuncdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ d00001ce 0000000c[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! c
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s
new file mode 100644
index 0000000..d75a061
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s
@@ -0,0 +1,9 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ mov.l .L1, r0
+ mov.l @(r0,r12), r1
+ .align 2
+.L1:
+ .long foo@GOTFUNCDESC
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d
new file mode 100644
index 0000000..3da8c40
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d
@@ -0,0 +1,26 @@
+#source: fdpic-gotfuncdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 d00001ce 0000000c 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 4000a0 004100b0 004100b4 004100c4 004100b8[ \t]+.*
+Contents of section \.got:
+ 4100b0 0040009c 004100b8 00000000 00000000[ \t]+.*
+ 4100c0 00000000 004100b0[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+d0 00[ \t]+mov\.l[ \t]+400098 <_start\+0x4>,r0[ \t]+! c
+[ \t]+400096:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+[ \t]+400098:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+
+0040009c <foo>:
+[ \t]+40009c:[ \t]+00 09[ \t]+nop[ \t]+
+[ \t]+40009e:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s
new file mode 100644
index 0000000..fc403b7
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s
@@ -0,0 +1,12 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ mov.l .L1, r0
+ mov.l @(r0,r12), r1
+ .align 2
+.L1:
+ .long foo@GOTFUNCDESC
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d
new file mode 100644
index 0000000..39eb610
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d
@@ -0,0 +1,24 @@
+#source: fdpic-gotfuncdesci20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0000000c 01ce[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s
new file mode 100644
index 0000000..736d30d
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s
@@ -0,0 +1,6 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ movi20 #foo@GOTFUNCDESC, r0
+ mov.l @(r0,r12), r1
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d
new file mode 100644
index 0000000..246e8f3
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d
@@ -0,0 +1,24 @@
+#source: fdpic-gotfuncdesci20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 0000000c 01ce0009[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100ac 004100b0 004100c0 004100b4[ \t]+.*
+Contents of section \.got:
+ 4100ac 0040009a 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000 004100ac[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+0040009a <foo>:
+[ \t]+40009a:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s
new file mode 100644
index 0000000..76930f5
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s
@@ -0,0 +1,9 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ movi20 #foo@GOTFUNCDESC, r0
+ mov.l @(r0,r12), r1
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-shared.d b/ld/testsuite/ld-sh/fdpic-goti20-shared.d
new file mode 100644
index 0000000..0955770
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-goti20-shared.d
@@ -0,0 +1,24 @@
+#source: fdpic-goti20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0000000c 01ce[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_GLOB_DAT[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-shared.s b/ld/testsuite/ld-sh/fdpic-goti20-shared.s
new file mode 100644
index 0000000..08f5446
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-goti20-shared.s
@@ -0,0 +1,6 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ movi20 #foo@GOT, r0
+ mov.l @(r0,r12), r1
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-static.d b/ld/testsuite/ld-sh/fdpic-goti20-static.d
new file mode 100644
index 0000000..91f5299
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-goti20-static.d
@@ -0,0 +1,22 @@
+#source: fdpic-goti20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 0000000c 01ce[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100b4 004100a8[ \t]+.*
+Contents of section \.data:
+ 4100a4 00000001[ \t]+.*
+Contents of section \.got:
+ 4100a8 00000000 00000000 00000000 004100a4[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-static.s b/ld/testsuite/ld-sh/fdpic-goti20-static.s
new file mode 100644
index 0000000..172a680
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-goti20-static.s
@@ -0,0 +1,11 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ movi20 #foo@GOT, r0
+ mov.l @(r0,r12), r1
+ .data
+ .type foo,@object
+ .size foo,4
+foo:
+ .long 1
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d
new file mode 100644
index 0000000..c43721d
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d
@@ -0,0 +1,32 @@
+#source: fdpic-gotofffuncdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ d10031cc fffffff8 00090009[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000008 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d1 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r1[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 08[ \t]+movi20[ \t]+#8,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s
new file mode 100644
index 0000000..daf1c84
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s
@@ -0,0 +1,12 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ mov.l .L1, r1
+ add r12, r1
+ .align 2
+.L1:
+ .long foo@GOTOFFFUNCDESC
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d
new file mode 100644
index 0000000..5ff417f
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d
@@ -0,0 +1,27 @@
+#source: fdpic-gotofffuncdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 d10031cc fffffff8 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 4000a0 004100ac 004100b0 004100b4[ \t]+.*
+Contents of section \.got:
+ 4100ac 0040009c 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+d1 00[ \t]+mov\.l[ \t]+400098 <_start\+0x4>,r1[ \t]+! fffffff8
+[ \t]+400096:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+[ \t]+400098:[ \t]+ff ff[ \t]+\.word 0xffff
+[ \t]+40009a:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+
+0040009c <foo>:
+[ \t]+40009c:[ \t]+00 09[ \t]+nop[ \t]+
+[ \t]+40009e:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s
new file mode 100644
index 0000000..307ff1d0
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s
@@ -0,0 +1,12 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ mov.l .L1, r1
+ add r12, r1
+ .align 2
+.L1:
+ .long foo@GOTOFFFUNCDESC
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d
new file mode 100644
index 0000000..c19abe6
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d
@@ -0,0 +1,29 @@
+#source: fdpic-gotofffuncdesci20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 01f0fff8 31cc0009[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000006 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+01 f0 ff f8[ \t]+movi20[ \t]+#-8,r1
+ [0-9a-f]+:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 06[ \t]+movi20[ \t]+#6,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s
new file mode 100644
index 0000000..bf16011
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s
@@ -0,0 +1,9 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ movi20 #foo@GOTOFFFUNCDESC, r1
+ add r12, r1
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d
new file mode 100644
index 0000000..3b96f7e
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d
@@ -0,0 +1,24 @@
+#source: fdpic-gotofffuncdesci20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 01f0fff8 31cc0009[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100a8 004100ac 004100b0[ \t]+.*
+Contents of section \.got:
+ 4100a8 0040009a 004100b0 00000000 00000000[ \t]+.*
+ 4100b8 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+01 f0 ff f8[ \t]+movi20[ \t]+#-8,r1
+[ \t]+400098:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+
+0040009a <foo>:
+[ \t]+40009a:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s
new file mode 100644
index 0000000..7017e0a
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s
@@ -0,0 +1,9 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ movi20 #foo@GOTOFFFUNCDESC, r1
+ add r12, r1
+ .type foo,@function
+foo:
+ nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d
new file mode 100644
index 0000000..8b57e11
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d
@@ -0,0 +1,30 @@
+#source: fdpic-gotoffi20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.data -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 00f0fffc 01ce[ \t]+.*
+Contents of section \.data:
+ [0-9a-f]+ 00000001[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 f0 ff fc[ \t]+movi20[ \t]+#-4,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.data:
+
+[0-9a-f]+ <foo>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 01[ \t]+\.\.\.\.
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s
new file mode 100644
index 0000000..fc8213c
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s
@@ -0,0 +1,11 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ movi20 #foo@GOTOFF, r0
+ mov.l @(r0,r12), r1
+ .data
+ .type foo,@object
+ .size foo,4
+foo:
+ .long 1
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-static.d b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.d
new file mode 100644
index 0000000..9390720
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.d
@@ -0,0 +1,22 @@
+#source: fdpic-gotoffi20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 00f0fffc 01ce[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100a4[ \t]+.*
+Contents of section \.data:
+ 4100a0 00000001[ \t]+.*
+Contents of section \.got:
+ 4100a4 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 f0 ff fc[ \t]+movi20[ \t]+#-4,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-static.s b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.s
new file mode 100644
index 0000000..079255b
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.s
@@ -0,0 +1,11 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ movi20 #foo@GOTOFF, r0
+ mov.l @(r0,r12), r1
+ .data
+ .type foo,@object
+ .size foo,4
+foo:
+ .long 1
diff --git a/ld/testsuite/ld-sh/fdpic-plt-be.d b/ld/testsuite/ld-sh/fdpic-plt-be.d
new file mode 100644
index 0000000..375e088
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-plt-be.d
@@ -0,0 +1,75 @@
+#source: fdpic-plt.s
+#as: --isa=sh4a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ d00201ce 7004412b 0cce0009 fffffff0[ \t]+.*
+ [0-9a-f]+ 00000000 60c2402b 53c10009 d00201ce[ \t]+.*
+ [0-9a-f]+ 7004412b 0cce0009 fffffff8 0000000c[ \t]+.*
+ [0-9a-f]+ 60c2402b 53c10009[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ d000d101 ffffffc4 ffffffdc[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 0000023c 00000000 00000258 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+d0 02[ \t]+mov\.l[ \t]+[0-9a-f]+ <foo@plt\+0xc>,r0[ \t]+! fffffff0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f0[ \t]+fadd[ \t]+fr15,fr15
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+d0 02[ \t]+mov\.l[ \t]+[0-9a-f]+ <bar@plt\+0xc>,r0[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 0c[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffc4
+ [0-9a-f]+:[ \t]+d1 01[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffdc
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff c4[ \t]+fcmp/eq[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff dc[ \t]+fmov[ \t]+fr13,fr15
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+02 3c[ \t]+mov.b[ \t]+@\(r0,r3\),r2
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+[0-9a-f]+:[ \t]+02 58[ \t]+\.word 0x0258
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plt-le.d b/ld/testsuite/ld-sh/fdpic-plt-le.d
new file mode 100644
index 0000000..4a3e55b
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-plt-le.d
@@ -0,0 +1,74 @@
+#source: fdpic-plt.s
+#as: --isa=sh4a -little --fdpic
+#ld: -EL -mshlelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-sh-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ 02d0ce01 04702b41 ce0c0900 f0ffffff[ \t]+.*
+ [0-9a-f]+ 00000000 c2602b40 c1530900 02d0ce01[ \t]+.*
+ [0-9a-f]+ 04702b41 ce0c0900 f8ffffff 0c000000[ \t]+.*
+ [0-9a-f]+ c2602b40 c1530900[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ 00d001d1 c4ffffff dcffffff[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 3c020000 00000000 58020000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+02 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <foo@plt\+0xc>,r0[ \t]+! fffffff0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+f0 ff[ \t]+fadd[ \t]+fr15,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+02 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <bar@plt\+0xc>,r0[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+f8 ff[ \t]+fmov[ \t]+@r15,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+0c 00[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffc4
+ [0-9a-f]+:[ \t]+01 d1[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffdc
+ [0-9a-f]+:[ \t]+c4 ff[ \t]+fcmp/eq[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+dc ff[ \t]+fmov[ \t]+fr13,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+3c 02[ \t]+mov.b[ \t]+@\(r0,r3\),r2
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+58 02[ \t]+\.word 0x0258
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plt.s b/ld/testsuite/ld-sh/fdpic-plt.s
new file mode 100644
index 0000000..e873d3e
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-plt.s
@@ -0,0 +1,11 @@
+ .text
+ .globl f
+ .type f,@function
+f:
+ mov.l .L1, r0
+ mov.l .L2, r1
+ .align 2
+.L1:
+ .long foo@PLT
+.L2:
+ .long bar@PLT
diff --git a/ld/testsuite/ld-sh/fdpic-plti20-be.d b/ld/testsuite/ld-sh/fdpic-plti20-be.d
new file mode 100644
index 0000000..282b34b
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-plti20-be.d
@@ -0,0 +1,63 @@
+#source: fdpic-plt.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ 00f0fff0 01ce7004 412b0cce 00000000[ \t]+.*
+ [0-9a-f]+ 60c2402b 53c10009 00f0fff8 01ce7004[ \t]+.*
+ [0-9a-f]+ 412b0cce 0000000c 60c2402b 53c10009[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ d000d101 ffffffcc ffffffe0[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000238 00000000 00000250 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+00 f0 ff f0[ \t]+movi20[ \t]+#-16,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+00 f0 ff f8[ \t]+movi20[ \t]+#-8,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffcc
+ [0-9a-f]+:[ \t]+d1 01[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffe0
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff cc[ \t]+fmov[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff e0[ \t]+fadd[ \t]+fr14,fr15
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 02 38[ \t]+movi20[ \t]+#568,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+[ \t]+[0-9a-f]+:[ \t]+00 00 02 50[ \t]+movi20[ \t]+#592,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plti20-le.d b/ld/testsuite/ld-sh/fdpic-plti20-le.d
new file mode 100644
index 0000000..74e1e9b
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-plti20-le.d
@@ -0,0 +1,63 @@
+#source: fdpic-plt.s
+#as: --isa=sh2a -little --fdpic
+#ld: -EL -mshlelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-sh-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ f000f0ff ce010470 2b41ce0c 00000000[ \t]+.*
+ [0-9a-f]+ c2602b40 c1530900 f000f8ff ce010470[ \t]+.*
+ [0-9a-f]+ 2b41ce0c 0c000000 c2602b40 c1530900[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ 00d001d1 ccffffff e0ffffff[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 38020000 00000000 50020000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+f0 00 f0 ff[ \t]+movi20[ \t]+#-16,r0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+f0 00 f8 ff[ \t]+movi20[ \t]+#-8,r0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+0c 00[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+00 00 c2 60[ \t]+movi20[ \t]+#24770,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffcc
+ [0-9a-f]+:[ \t]+01 d1[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffe0
+ [0-9a-f]+:[ \t]+cc ff[ \t]+fmov[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+e0 ff[ \t]+fadd[ \t]+fr14,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+38 02[ \t]+\.word[ \t]+0x0238
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+[ \t]+[0-9a-f]+:[ \t]+00 00 50 02[ \t]+movi20[ \t]+#592,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-stack-default.d b/ld/testsuite/ld-sh/fdpic-stack-default.d
new file mode 100644
index 0000000..8f9fd92
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-stack-default.d
@@ -0,0 +1,19 @@
+#source: fdpic-stack.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#readelf: -l
+#target: sh*-*-uclinux*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x400074
+There are 2 program headers, starting at offset 52
+
+Program Headers:
+[ \t]+Type[ \t]+Offset[ \t]+VirtAddr[ \t]+PhysAddr[ \t]+FileSiz MemSiz[ \t]+Flg Align
+[ \t]+LOAD[ \t]+0x000000 0x00400000 0x00400000 0x00076 0x00076 R E 0x10000
+[ \t]+GNU_STACK[ \t]+0x000000 0x00000000 0x00000000 0x00000 0x20000 RWE 0x8
+
+ Section to Segment mapping:
+[ \t]+Segment Sections\.\.\.
+[ \t]+00[ \t]+\.text
+[ \t]+01[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-stack-size.d b/ld/testsuite/ld-sh/fdpic-stack-size.d
new file mode 100644
index 0000000..f993a2a
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-stack-size.d
@@ -0,0 +1,19 @@
+#source: fdpic-stack.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd --defsym __stacksize=0x40000
+#readelf: -l
+#target: sh*-*-uclinux*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x400074
+There are 2 program headers, starting at offset 52
+
+Program Headers:
+[ \t]+Type[ \t]+Offset[ \t]+VirtAddr[ \t]+PhysAddr[ \t]+FileSiz MemSiz[ \t]+Flg Align
+[ \t]+LOAD[ \t]+0x000000 0x00400000 0x00400000 0x00076 0x00076 R E 0x10000
+[ \t]+GNU_STACK[ \t]+0x000000 0x00000000 0x00000000 0x00000 0x40000 RWE 0x8
+
+ Section to Segment mapping:
+[ \t]+Segment Sections\.\.\.
+[ \t]+00[ \t]+\.text
+[ \t]+01[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-stack.s b/ld/testsuite/ld-sh/fdpic-stack.s
new file mode 100644
index 0000000..b0421ea
--- /dev/null
+++ b/ld/testsuite/ld-sh/fdpic-stack.s
@@ -0,0 +1,5 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ nop
diff --git a/ld/testsuite/ld-sh/sh.exp b/ld/testsuite/ld-sh/sh.exp
index 335946b..f42a79f 100644
--- a/ld/testsuite/ld-sh/sh.exp
+++ b/ld/testsuite/ld-sh/sh.exp
@@ -122,7 +122,7 @@ if { [which $CC] == 0 } {
return
}
-if [istarget sh*-linux-*] {
+if [istarget sh*-*linux*] {
exec sed -e s/_main/main/ -e s/_trap/trap/ -e s/_stack/stack/ \
< $srcdir/$subdir/start.s >tmpdir/start.s
} else {
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 5b2e62b..9e8b809 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -404,6 +404,7 @@ proc is_elf_format {} {
&& ![istarget *-*-linux*] \
&& ![istarget frv-*-uclinux*] \
&& ![istarget bfin-*-uclinux] \
+ && ![istarget sh*-*-uclinux*] \
&& ![istarget *-*-irix5*] \
&& ![istarget *-*-irix6*] \
&& ![istarget *-*-netbsd*] \