This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] SH-2A FDPIC Support
- From: Andrew Stubbs <ams at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Thu, 20 May 2010 17:27:56 +0100
- Subject: [PATCH] SH-2A FDPIC Support
Hi All,
The attached patch implements FDPIC support for SH-2A uClinux.
The ABI has been published here:
http://www.codesourcery.com/public/docs/sh-fdpic/sh-fdpic-abi.txt
The implementation is not perfect (there are still a number of FIXMEs
and such), but it is functional. I have successfully built a working
uClinux system (incorporating busybox and dynamically linked uClibc),
and the Binutils and GCC testsuites run tolerably well.
GCC and uClibc patches will follow soon.
OK to apply?
Andrew
2010-05-20 Daniel Jacobowitz <dan@codesourcery.com>
Joseph Myers <joseph@codesourcery.com>
Andrew Stubbs <ams@codesourcery.com>
bfd/
* 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.
binutils/
* readelf.c (get_machine_flags): Handle EF_SH_PIC and EF_SH_FDPIC.
gas/
* 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.
gas/testsuite/
* 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*.
include/elf/
* 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.
ld/
* 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.
ld/testsuite/
* ld-sh/sh.exp: Handle uClinux like Linux.
* lib/ld-lib.exp (is_elf_format): Include sh*-*-uclinux*.
---
src/binutils-mainline/bfd/bfd-in2.h | 7
src/binutils-mainline/bfd/config.bfd | 2
src/binutils-mainline/bfd/configure | 2
src/binutils-mainline/bfd/configure.in | 2
src/binutils-mainline/bfd/elf32-sh-relocs.h | 163 ++
src/binutils-mainline/bfd/elf32-sh.c | 1980 ++++++++++++++++++--
src/binutils-mainline/bfd/libbfd.h | 7
src/binutils-mainline/bfd/reloc.c | 14
src/binutils-mainline/bfd/targets.c | 4
src/binutils-mainline/binutils/readelf.c | 5
src/binutils-mainline/gas/config/tc-sh.c | 111 +
src/binutils-mainline/gas/config/tc-sh.h | 3
src/binutils-mainline/gas/configure.tgt | 3
src/binutils-mainline/gas/doc/c-sh.texi | 4
.../gas/testsuite/gas/sh/basic.exp | 4
src/binutils-mainline/gas/testsuite/gas/sh/fdpic.d | 13
src/binutils-mainline/gas/testsuite/gas/sh/fdpic.s | 8
.../gas/testsuite/gas/sh/reg-prefix.d | 4
.../gas/testsuite/gas/sh/sh2a-pic.d | 15
.../gas/testsuite/gas/sh/sh2a-pic.s | 6
.../gas/testsuite/lib/gas-defs.exp | 1
src/binutils-mainline/include/elf/sh.h | 18
src/binutils-mainline/ld/Makefile.am | 8
src/binutils-mainline/ld/Makefile.in | 8
src/binutils-mainline/ld/configure.tgt | 2
src/binutils-mainline/ld/emulparams/shelf_fd.sh | 2
src/binutils-mainline/ld/emulparams/shlelf_fd.sh | 16
.../ld/emulparams/shlelf_linux.sh | 2
src/binutils-mainline/ld/testsuite/ld-sh/sh.exp | 2
src/binutils-mainline/ld/testsuite/lib/ld-lib.exp | 1
30 files changed, 2185 insertions(+), 232 deletions(-)
create mode 100644 src/binutils-mainline/gas/testsuite/gas/sh/fdpic.d
create mode 100644 src/binutils-mainline/gas/testsuite/gas/sh/fdpic.s
create mode 100644 src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.d
create mode 100644 src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.s
create mode 100644 src/binutils-mainline/ld/emulparams/shelf_fd.sh
create mode 100644 src/binutils-mainline/ld/emulparams/shlelf_fd.sh
diff --git a/src/binutils-mainline/bfd/bfd-in2.h b/src/binutils-mainline/bfd/bfd-in2.h
index a3f8ccc..b11328d 100644
--- a/src/binutils-mainline/bfd/bfd-in2.h
+++ b/src/binutils-mainline/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/src/binutils-mainline/bfd/config.bfd b/src/binutils-mainline/bfd/config.bfd
index d39ef18..abe1b5e 100644
--- a/src/binutils-mainline/bfd/config.bfd
+++ b/src/binutils-mainline/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/src/binutils-mainline/bfd/configure b/src/binutils-mainline/bfd/configure
index 6ace16c..d177c67 100755
--- a/src/binutils-mainline/bfd/configure
+++ b/src/binutils-mainline/bfd/configure
@@ -15132,7 +15132,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/src/binutils-mainline/bfd/configure.in b/src/binutils-mainline/bfd/configure.in
index 6f05505..a928a0c 100644
--- a/src/binutils-mainline/bfd/configure.in
+++ b/src/binutils-mainline/bfd/configure.in
@@ -770,7 +770,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/src/binutils-mainline/bfd/elf32-sh-relocs.h b/src/binutils-mainline/bfd/elf32-sh-relocs.h
index 70f3a7b..05f0875 100644
--- a/src/binutils-mainline/bfd/elf32-sh-relocs.h
+++ b/src/binutils-mainline/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/src/binutils-mainline/bfd/elf32-sh.c b/src/binutils-mainline/bfd/elf32-sh.c
index 23ee06a..1b0daf9 100644
--- a/src/binutils-mainline/bfd/elf32-sh.c
+++ b/src/binutils-mainline/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/src/binutils-mainline/bfd/libbfd.h b/src/binutils-mainline/bfd/libbfd.h
index c02063a..c6e25ab 100644
--- a/src/binutils-mainline/bfd/libbfd.h
+++ b/src/binutils-mainline/bfd/libbfd.h
@@ -1510,6 +1510,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/src/binutils-mainline/bfd/reloc.c b/src/binutils-mainline/bfd/reloc.c
index a847629..7d16869 100644
--- a/src/binutils-mainline/bfd/reloc.c
+++ b/src/binutils-mainline/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/src/binutils-mainline/bfd/targets.c b/src/binutils-mainline/bfd/targets.c
index 2e330e6..69a5a94 100644
--- a/src/binutils-mainline/bfd/targets.c
+++ b/src/binutils-mainline/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/src/binutils-mainline/binutils/readelf.c b/src/binutils-mainline/binutils/readelf.c
index 53699b2..e43c798 100644
--- a/src/binutils-mainline/binutils/readelf.c
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/config/tc-sh.c b/src/binutils-mainline/gas/config/tc-sh.c
index a7cdd0e..4e49e4e 100644
--- a/src/binutils-mainline/gas/config/tc-sh.c
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/config/tc-sh.h b/src/binutils-mainline/gas/config/tc-sh.h
index 1b5ec26..85e5a51 100644
--- a/src/binutils-mainline/gas/config/tc-sh.h
+++ b/src/binutils-mainline/gas/config/tc-sh.h
@@ -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
diff --git a/src/binutils-mainline/gas/configure.tgt b/src/binutils-mainline/gas/configure.tgt
index 23d8662..77cbac1 100644
--- a/src/binutils-mainline/gas/configure.tgt
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/doc/c-sh.texi b/src/binutils-mainline/gas/doc/c-sh.texi
index 00c95d7..adb21df 100644
--- a/src/binutils-mainline/gas/doc/c-sh.texi
+++ b/src/binutils-mainline/gas/doc/c-sh.texi
@@ -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/src/binutils-mainline/gas/testsuite/gas/sh/basic.exp b/src/binutils-mainline/gas/testsuite/gas/sh/basic.exp
index 3bb7931..2daa038 100644
--- a/src/binutils-mainline/gas/testsuite/gas/sh/basic.exp
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/testsuite/gas/sh/fdpic.d b/src/binutils-mainline/gas/testsuite/gas/sh/fdpic.d
new file mode 100644
index 0000000..33dfc71
--- /dev/null
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/testsuite/gas/sh/fdpic.s b/src/binutils-mainline/gas/testsuite/gas/sh/fdpic.s
new file mode 100644
index 0000000..7a7ad0f
--- /dev/null
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/testsuite/gas/sh/reg-prefix.d b/src/binutils-mainline/gas/testsuite/gas/sh/reg-prefix.d
index 1821bbc..13c708c 100644
--- a/src/binutils-mainline/gas/testsuite/gas/sh/reg-prefix.d
+++ b/src/binutils-mainline/gas/testsuite/gas/sh/reg-prefix.d
@@ -1,10 +1,10 @@
#objdump: -dr --prefix-addresses --show-raw-insn
-#as: --allow-reg-prefix -little
+#as: --allow-reg-prefix -big
#name: SH --allow-reg-prefix option
# 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/src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.d b/src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.d
new file mode 100644
index 0000000..504d411
--- /dev/null
+++ b/src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.d
@@ -0,0 +1,15 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: SH2a PIC relocations
+#as: -isa=sh2a
+
+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/src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.s b/src/binutils-mainline/gas/testsuite/gas/sh/sh2a-pic.s
new file mode 100644
index 0000000..888a7c9
--- /dev/null
+++ b/src/binutils-mainline/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/src/binutils-mainline/gas/testsuite/lib/gas-defs.exp b/src/binutils-mainline/gas/testsuite/lib/gas-defs.exp
index 0506b94..fd2f179 100644
--- a/src/binutils-mainline/gas/testsuite/lib/gas-defs.exp
+++ b/src/binutils-mainline/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/src/binutils-mainline/include/elf/sh.h b/src/binutils-mainline/include/elf/sh.h
index fcb962a..c2bd50d 100644
--- a/src/binutils-mainline/include/elf/sh.h
+++ b/src/binutils-mainline/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/src/binutils-mainline/ld/Makefile.am b/src/binutils-mainline/ld/Makefile.am
index 3896fda..e9a8bb5 100644
--- a/src/binutils-mainline/ld/Makefile.am
+++ b/src/binutils-mainline/ld/Makefile.am
@@ -381,6 +381,8 @@ ALL_EMULATIONS = \
eshelf32_nbsd.o \
eshlelf32_nbsd.o \
eshelf.o \
+ eshelf_fd.o \
+ eshlelf_fd.o \
eshelf_linux.o \
eshlelf_linux.o \
eshelf_nbsd.o \
@@ -1729,6 +1731,12 @@ eshelf64_nbsd.c: $(srcdir)/emulparams/shelf64_nbsd.sh \
$(srcdir)/emulparams/shelf32_nbsd.sh $(srcdir)/emulparams/shelf32.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} shelf64_nbsd "$(tdir_shelf64_nbsd)"
+eshelf_fd.c: $(srcdir)/emulparams/shelf_fd.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} shelf_fd "$(tdir_shelf_fd)"
+eshlelf_fd.c: $(srcdir)/emulparams/shlelf_fd.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} shelf_fd "$(tdir_shelf_fd)"
eshelf_linux.c: $(srcdir)/emulparams/shelf_linux.sh \
$(srcdir)/emulparams/shlelf_linux.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
diff --git a/src/binutils-mainline/ld/Makefile.in b/src/binutils-mainline/ld/Makefile.in
index 7b0bf33..84aed74 100644
--- a/src/binutils-mainline/ld/Makefile.in
+++ b/src/binutils-mainline/ld/Makefile.in
@@ -671,6 +671,8 @@ ALL_EMULATIONS = \
eshelf32_nbsd.o \
eshlelf32_nbsd.o \
eshelf.o \
+ eshelf_fd.o \
+ eshlelf_fd.o \
eshelf_linux.o \
eshlelf_linux.o \
eshelf_nbsd.o \
@@ -3083,6 +3085,12 @@ eshelf64_nbsd.c: $(srcdir)/emulparams/shelf64_nbsd.sh \
$(srcdir)/emulparams/shelf32_nbsd.sh $(srcdir)/emulparams/shelf32.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} shelf64_nbsd "$(tdir_shelf64_nbsd)"
+eshelf_fd.c: $(srcdir)/emulparams/shelf_fd.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} shelf_fd "$(tdir_shelf_fd)"
+eshlelf_fd.c: $(srcdir)/emulparams/shlelf_fd.sh \
+ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ ${GENSCRIPTS} shlelf_fd "$(tdir_shlelf_fd)"
eshelf_linux.c: $(srcdir)/emulparams/shelf_linux.sh \
$(srcdir)/emulparams/shlelf_linux.sh \
$(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
diff --git a/src/binutils-mainline/ld/configure.tgt b/src/binutils-mainline/ld/configure.tgt
index def0287..f75c96a 100644
--- a/src/binutils-mainline/ld/configure.tgt
+++ b/src/binutils-mainline/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/src/binutils-mainline/ld/emulparams/shelf_fd.sh b/src/binutils-mainline/ld/emulparams/shelf_fd.sh
new file mode 100644
index 0000000..7ec25ab
--- /dev/null
+++ b/src/binutils-mainline/ld/emulparams/shelf_fd.sh
@@ -0,0 +1,2 @@
+. ${srcdir}/emulparams/shlelf_fd.sh
+OUTPUT_FORMAT="elf32-shbig-fdpic"
diff --git a/src/binutils-mainline/ld/emulparams/shlelf_fd.sh b/src/binutils-mainline/ld/emulparams/shlelf_fd.sh
new file mode 100644
index 0000000..f1f4107
--- /dev/null
+++ b/src/binutils-mainline/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/src/binutils-mainline/ld/emulparams/shlelf_linux.sh b/src/binutils-mainline/ld/emulparams/shlelf_linux.sh
index 95b6acc..c14aae2 100644
--- a/src/binutils-mainline/ld/emulparams/shlelf_linux.sh
+++ b/src/binutils-mainline/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/src/binutils-mainline/ld/testsuite/ld-sh/sh.exp b/src/binutils-mainline/ld/testsuite/ld-sh/sh.exp
index 335946b..f42a79f 100644
--- a/src/binutils-mainline/ld/testsuite/ld-sh/sh.exp
+++ b/src/binutils-mainline/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/src/binutils-mainline/ld/testsuite/lib/ld-lib.exp b/src/binutils-mainline/ld/testsuite/lib/ld-lib.exp
index 5b2e62b..4897b2c 100644
--- a/src/binutils-mainline/ld/testsuite/lib/ld-lib.exp
+++ b/src/binutils-mainline/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*] \