2010-05-21 Daniel Jacobowitz <dan@codesourcery.com>
authorNick Clifton <nickc@redhat.com>
Tue, 25 May 2010 14:12:43 +0000 (14:12 +0000)
committerNick Clifton <nickc@redhat.com>
Tue, 25 May 2010 14:12:43 +0000 (14:12 +0000)
            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*.
        * ld-sh/fdpic-funcdesc-shared.d: New file.
        * ld-sh/fdpic-funcdesc-shared.s: New file.
        * ld-sh/fdpic-funcdesc-static.d: New file.
        * ld-sh/fdpic-funcdesc-static.s: New file.
        * ld-sh/fdpic-gotfuncdesc-shared.d: New file.
        * ld-sh/fdpic-gotfuncdesc-shared.s: New file.
        * ld-sh/fdpic-gotfuncdesc-static.d: New file.
        * ld-sh/fdpic-gotfuncdesc-static.s: New file.
        * ld-sh/fdpic-gotfuncdesci20-shared.d: New file.
        * ld-sh/fdpic-gotfuncdesci20-shared.s: New file.
        * ld-sh/fdpic-gotfuncdesci20-static.d: New file.
        * ld-sh/fdpic-gotfuncdesci20-static.s: New file.
        * ld-sh/fdpic-goti20-shared.d: New file.
        * ld-sh/fdpic-goti20-shared.s: New file.
        * ld-sh/fdpic-goti20-static.d: New file.
        * ld-sh/fdpic-goti20-static.s: New file.
        * ld-sh/fdpic-gotofffuncdesc-shared.d: New file.
        * ld-sh/fdpic-gotofffuncdesc-shared.s: New file.
        * ld-sh/fdpic-gotofffuncdesc-static.d: New file.
        * ld-sh/fdpic-gotofffuncdesc-static.s: New file.
        * ld-sh/fdpic-gotofffuncdesci20-shared.d: New file.
        * ld-sh/fdpic-gotofffuncdesci20-shared.s: New file.
        * ld-sh/fdpic-gotofffuncdesci20-static.d: New file.
        * ld-sh/fdpic-gotofffuncdesci20-static.s: New file.
        * ld-sh/fdpic-gotoffi20-shared.d: New file.
        * ld-sh/fdpic-gotoffi20-shared.s: New file.
        * ld-sh/fdpic-gotoffi20-static.d: New file.
        * ld-sh/fdpic-gotoffi20-static.s: New file.
        * ld-sh/fdpic-plt-be.d: New file.
        * ld-sh/fdpic-plt-le.d: New file.
        * ld-sh/fdpic-plt.s: New file.
        * ld-sh/fdpic-plti20-be.d: New file.
        * ld-sh/fdpic-plti20-le.d: New file.
        * ld-sh/fdpic-stack-default.d: New file.
        * ld-sh/fdpic-stack-size.d: New file.
        * ld-sh/fdpic-stack.s: New file.

71 files changed:
bfd/ChangeLog
bfd/bfd-in2.h
bfd/config.bfd
bfd/configure
bfd/configure.in
bfd/elf32-sh-relocs.h
bfd/elf32-sh.c
bfd/libbfd.h
bfd/reloc.c
bfd/targets.c
binutils/ChangeLog
binutils/readelf.c
gas/ChangeLog
gas/config/tc-sh.c
gas/config/tc-sh.h
gas/configure.tgt
gas/doc/c-sh.texi
gas/testsuite/ChangeLog
gas/testsuite/gas/sh/basic.exp
gas/testsuite/gas/sh/fdpic.d [new file with mode: 0644]
gas/testsuite/gas/sh/fdpic.s [new file with mode: 0644]
gas/testsuite/gas/sh/reg-prefix.d
gas/testsuite/gas/sh/sh2a-pic.d [new file with mode: 0644]
gas/testsuite/gas/sh/sh2a-pic.s [new file with mode: 0644]
gas/testsuite/lib/gas-defs.exp
include/elf/ChangeLog
include/elf/sh.h
ld/ChangeLog
ld/configure.tgt
ld/emulparams/shelf_fd.sh [new file with mode: 0644]
ld/emulparams/shlelf_fd.sh [new file with mode: 0644]
ld/emulparams/shlelf_linux.sh
ld/testsuite/ChangeLog
ld/testsuite/ld-sh/fdpic-funcdesc-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-funcdesc-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-funcdesc-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-funcdesc-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-goti20-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-goti20-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-goti20-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-goti20-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotoffi20-static.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-gotoffi20-static.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-plt-be.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-plt-le.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-plt.s [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-plti20-be.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-plti20-le.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-stack-default.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-stack-size.d [new file with mode: 0644]
ld/testsuite/ld-sh/fdpic-stack.s [new file with mode: 0644]
ld/testsuite/ld-sh/sh.exp
ld/testsuite/lib/ld-lib.exp

index 4c7593c..76924de 100644 (file)
@@ -1,3 +1,98 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * config.bfd (sh-*-uclinux* | sh[12]-*-uclinux*): Add
+       bfd_elf32_shl_vec, and FDPIC vectors to targ_selvecs.
+       * configure.in: Handle FDPIC vectors.
+       * elf32-sh-relocs.h: Add FDPIC and movi20 relocations.
+       * elf32-sh.c (DEFAULT_STACK_SIZE): Define.
+       (SYMBOL_FUNCDESC_LOCAL): Define.  Use it instead of
+       SYMBOL_REFERENCES_LOCAL for function descriptors.
+       (fdpic_object_p): New.
+       (sh_reloc_map): Add FDPIC and movi20 relocations.
+       (sh_elf_info_to_howto, sh_elf_relocate_section): Handle new invalid
+       range.
+       (struct elf_sh_plt_info): Add got20 and short_plt.  Update all
+       definitions.
+       (FDPIC_PLT_ENTRY_SIZE, FDPIC_PLT_LAZY_OFFSET): Define.
+       (fdpic_sh_plt_entry_be, fdpic_sh_plt_entry_le, fdpic_sh_plts): New.
+       (FDPIC_SH2A_PLT_ENTRY_SIZE, FDPIC_SH2A_PLT_LAZY_OFFSET): Define.
+       (fdpic_sh2a_plt_entry_be, fdpic_sh2a_plt_entry_le)
+       (fdpic_sh2a_short_plt_be, fdpic_sh2a_short_plt_le, fdpic_sh2a_plts):
+       New.
+       (get_plt_info): Handle FDPIC.
+       (MAX_SHORT_PLT): Define.
+       (get_plt_index, get_plt_offset): Handle short_plt.
+       (union gotref): New.
+       (struct elf_sh_link_hash_entry): Add funcdesc, rename tls_type to
+       got_type and adjust all uses.  Add GOT_FUNCDESC.
+       (struct sh_elf_obj_tdata): Add local_funcdesc.  Rename
+       local_got_tls_type to local_got_type.
+       (sh_elf_local_got_type): Renamed from sh_elf_local_got_tls_type.  All
+       users changed.
+       (sh_elf_local_funcdesc): Define.
+       (struct elf_sh_link_hash_table): Add sfuncdesc, srelfuncdesc, fdpic_p,
+       and srofixup.
+       (sh_elf_link_hash_newfunc): Initialize new fields.
+       (sh_elf_link_hash_table_create): Set fdpic_p.
+       (sh_elf_omit_section_dynsym): New.
+       (create_got_section): Create .got.funcdesc, .rela.got.funcdesc
+       and .rofixup.
+       (allocate_dynrelocs): Allocate local function descriptors and space
+       for R_SH_FUNCDESC-related relocations, and for rofixups.
+       Handle GOT_FUNCDESC.  Create fixups.  Handle GOT entries which
+       require function descriptors.
+       (sh_elf_always_size_sections): Handle PT_GNU_STACK and __stacksize.
+       (sh_elf_modify_program_headers): New.
+       (sh_elf_size_dynamic_sections): Allocate function descriptors for
+       local symbols.  Allocate .got.funcdesc contents.  Allocate rofixups.
+       Handle local GOT entries of type GOT_FUNCDESC.  Create fixups for
+       local GOT entries.  Ensure that FDPIC libraries always have a PLTGOT
+       entry in the .dynamic section.
+       (sh_elf_add_dyn_reloc, sh_elf_got_offset, sh_elf_initialize_funcdesc)
+       (sh_elf_add_rofixup, sh_elf_osec_to_segment)
+       (sh_elf_osec_readonly_p, install_movi20_field): New functions.
+       (sh_elf_relocate_section): Handle new relocations, R_SH_FUNCDESC,
+       R_SH_GOTFUNCDESC and R_SH_GOTOFFFUNCDESC.  Use sh_elf_got_offset
+       and .got.plt throughout to find _GLOBAL_OFFSET_TABLE_.  Add rofixup
+       read-only section warnings.  Handle undefined weak symbols.  Generate
+       fixups for R_SH_DIR32 and GOT entries.  Check for cross-segment
+       relocations and clear EF_SH_PIC.  Handle 20-bit relocations.
+       Always generate R_SH_DIR32 for FDPIC instead of R_SH_RELATIVE.
+       (sh_elf_gc_sweep_hook): Handle R_SH_FUNCDESC, R_SH_GOTOFF20,
+       R_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC20, and R_SH_GOTOFFFUNCDESC.
+       Handle 20-bit relocations.
+       (sh_elf_copy_indirect_symbol): Copy function descriptor reference
+       counts.
+       (sh_elf_check_relocs): Handle new relocations.  Make symbols
+       dynamic for FDPIC relocs.  Account for rofixups.  Error for FDPIC
+       symbol mismatches.  Allocate a GOT for R_SH_DIR32. Allocate fixups
+       for R_SH_DIR32.
+       (sh_elf_copy_private_data): Copy PT_GNU_STACK size.
+       (sh_elf_merge_private_data): Copy initial flags.  Do not clobber
+       non-mach flags.  Set EF_SH_PIC for FDPIC.  Reject FDPIC mismatches.
+       (sh_elf_finish_dynamic_symbol): Do not handle got_funcdesc entries
+       here.  Rename sgot to sgotplt and srel to srelplt.  Handle short_plt,
+       FDPIC descriptors, and got20.  Create R_SH_FUNCDESC_VALUE for FDPIC.
+       Use install_movi20_field.  Rename srel to srelgot.  Always generate
+       R_SH_DIR32 for FDPIC instead of R_SH_RELATIVE.
+       (sh_elf_finish_dynamic_sections): Fill in the GOT pointer in rofixup.
+       Do not fill in reserved GOT entries for FDPIC.  Correct DT_PLTGOT.
+       Rename sgot to sgotplt.  Assert that the right number of rofixups
+       and dynamic relocations were allocated.
+       (sh_elf_use_relative_eh_frame, sh_elf_encode_eh_address): New.
+       (elf_backend_omit_section_dynsym): Use sh_elf_omit_section_dynsym.
+       (elf_backend_can_make_relative_eh_frame)
+       (elf_backend_can_make_lsda_relative_eh_frame)
+       (elf_backend_encode_eh_address): Define.
+       (TARGET_BIG_SYM, TARGET_BIG_NAME, TARGET_LITTLE_SYM)
+       (TARGET_LITTLE_NAME, elf_backend_modify_program_headers, elf32_bed):
+       Redefine for FDPIC vector.
+       * reloc.c: Add SH FDPIC and movi20 relocations.
+       * targets.c (_bfd_target_vector): Add FDPIC vectors.
+       * configure, bfd-in2.h, libbfd.h: Regenerated.
+
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11624
index e9dcb2c..5c42128 100644 (file)
@@ -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
index d39ef18..abe1b5e 100644 (file)
@@ -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
index d498ff2..310bb6a 100755 (executable)
@@ -15135,7 +15135,9 @@ do
     bfd_elf32_sh64lnbsd_vec)   tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
     bfd_elf32_sh64nbsd_vec)    tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
     bfd_elf32_sh_vec)          tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
+    bfd_elf32_shbfd_vec)       tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
     bfd_elf32_shblin_vec)      tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
+    bfd_elf32_shfd_vec)                tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
     bfd_elf32_shl_vec)         tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
     bfd_elf32_shl_symbian_vec) tb="$tb elf32-sh-symbian.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
     bfd_elf32_shlin_vec)       tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
index 3ca7fc7..65ae8d3 100644 (file)
@@ -772,7 +772,9 @@ do
     bfd_elf32_sh64lnbsd_vec)   tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
     bfd_elf32_sh64nbsd_vec)    tb="$tb elf32-sh64.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf cofflink.lo" ;;
     bfd_elf32_sh_vec)          tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
+    bfd_elf32_shbfd_vec)       tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
     bfd_elf32_shblin_vec)      tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
+    bfd_elf32_shfd_vec)                tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
     bfd_elf32_shl_vec)         tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
     bfd_elf32_shl_symbian_vec) tb="$tb elf32-sh-symbian.lo elf32-sh64-com.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo" ;;
     bfd_elf32_shlin_vec)       tb="$tb elf32-sh.lo elf-vxworks.lo elf32.lo $elf coff-sh.lo cofflink.lo" ;;
index 70f3a7b..05f0875 100644 (file)
@@ -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.
 
         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),
index 23ee06a..1b0daf9 100644 (file)
@@ -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)
 \f
 #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,67 +3747,251 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 \f
-/* Relocate an SH ELF section.  */
+/* Add a dynamic relocation to the SRELOC section.  */
 
-static bfd_boolean
-sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
-                        bfd *input_bfd, asection *input_section,
-                        bfd_byte *contents, Elf_Internal_Rela *relocs,
-                        Elf_Internal_Sym *local_syms,
-                        asection **local_sections)
+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)
 {
-  struct elf_sh_link_hash_table *htab;
-  Elf_Internal_Shdr *symtab_hdr;
-  struct elf_link_hash_entry **sym_hashes;
-  Elf_Internal_Rela *rel, *relend;
-  bfd *dynobj;
-  bfd_vma *local_got_offsets;
-  asection *sgot;
-  asection *sgotplt;
-  asection *splt;
-  asection *sreloc;
-  asection *srelgot;
-  bfd_boolean is_vxworks_tls;
+  Elf_Internal_Rela outrel;
+  bfd_vma reloc_offset;
 
-  BFD_ASSERT (is_sh_elf (input_bfd));
+  outrel.r_offset = offset;
+  outrel.r_info = ELF32_R_INFO (dynindx, reloc_type);
+  outrel.r_addend = addend;
 
-  htab = sh_elf_hash_table (info);
-  if (htab == NULL)
-    return FALSE;
-  symtab_hdr = &elf_symtab_hdr (input_bfd);
-  sym_hashes = elf_sym_hashes (input_bfd);
-  dynobj = htab->root.dynobj;
-  local_got_offsets = elf_local_got_offsets (input_bfd);
+  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++;
 
-  sgot = htab->sgot;
-  sgotplt = htab->sgotplt;
-  splt = htab->splt;
-  sreloc = NULL;
-  srelgot = NULL;
-  /* We have to handle relocations in vxworks .tls_vars sections
-     specially, because the dynamic loader is 'weird'.  */
-  is_vxworks_tls = (htab->vxworks_p && info->shared
-                   && !strcmp (input_section->output_section->name,
-                               ".tls_vars"));
+  return reloc_offset;
+}
 
-  rel = relocs;
-  relend = relocs + input_section->reloc_count;
-  for (; rel < relend; rel++)
-    {
-      int r_type;
-      reloc_howto_type *howto;
-      unsigned long r_symndx;
-      Elf_Internal_Sym *sym;
-      asection *sec;
-      struct elf_link_hash_entry *h;
-      bfd_vma relocation;
-      bfd_vma addend = (bfd_vma) 0;
-      bfd_reloc_status_type r;
-      int seen_stt_datalabel = 0;
-      bfd_vma off;
-      int tls_type;
+/* Add an FDPIC read-only fixup.  */
 
-      r_symndx = ELF32_R_SYM (rel->r_info);
+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
+sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
+                        bfd *input_bfd, asection *input_section,
+                        bfd_byte *contents, Elf_Internal_Rela *relocs,
+                        Elf_Internal_Sym *local_syms,
+                        asection **local_sections)
+{
+  struct elf_sh_link_hash_table *htab;
+  Elf_Internal_Shdr *symtab_hdr;
+  struct elf_link_hash_entry **sym_hashes;
+  Elf_Internal_Rela *rel, *relend;
+  bfd *dynobj;
+  bfd_vma *local_got_offsets;
+  asection *sgot;
+  asection *sgotplt;
+  asection *splt;
+  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));
+
+  htab = sh_elf_hash_table (info);
+  if (htab == NULL)
+    return FALSE;
+  symtab_hdr = &elf_symtab_hdr (input_bfd);
+  sym_hashes = elf_sym_hashes (input_bfd);
+  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;
+  sreloc = NULL;
+  srelgot = NULL;
+  /* We have to handle relocations in vxworks .tls_vars sections
+     specially, because the dynamic loader is 'weird'.  */
+  is_vxworks_tls = (htab->vxworks_p && info->shared
+                   && !strcmp (input_section->output_section->name,
+                               ".tls_vars"));
+
+  rel = relocs;
+  relend = relocs + input_section->reloc_count;
+  for (; rel < relend; rel++)
+    {
+      int r_type;
+      reloc_howto_type *howto;
+      unsigned long r_symndx;
+      Elf_Internal_Sym *sym;
+      asection *sec;
+      struct elf_link_hash_entry *h;
+      bfd_vma relocation;
+      bfd_vma addend = (bfd_vma) 0;
+      bfd_reloc_status_type r;
+      int seen_stt_datalabel = 0;
+      bfd_vma off;
+      int got_type;
+      const char *symname = NULL;
+
+      r_symndx = ELF32_R_SYM (rel->r_info);
 
       r_type = ELF32_R_TYPE (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);
+    }
 
-      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+  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);
+
+      /* 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
index 7275dd9..b3f97f3 100644 (file)
@@ -1511,6 +1511,13 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_SH_TLS_DTPMOD32",
   "BFD_RELOC_SH_TLS_DTPOFF32",
   "BFD_RELOC_SH_TLS_TPOFF32",
+  "BFD_RELOC_SH_GOT20",
+  "BFD_RELOC_SH_GOTOFF20",
+  "BFD_RELOC_SH_GOTFUNCDESC",
+  "BFD_RELOC_SH_GOTFUNCDESC20",
+  "BFD_RELOC_SH_GOTOFFFUNCDESC",
+  "BFD_RELOC_SH_GOTOFFFUNCDESC20",
+  "BFD_RELOC_SH_FUNCDESC",
   "BFD_RELOC_ARC_B22_PCREL",
   "BFD_RELOC_ARC_B26",
   "BFD_RELOC_BFIN_16_IMM",
index a847629..7d16869 100644 (file)
@@ -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.
 
index 2e330e6..69a5a94 100644 (file)
@@ -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,
index c4abd96..8cfe737 100644 (file)
@@ -1,3 +1,9 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * readelf.c (get_machine_flags): Handle EF_SH_PIC and EF_SH_FDPIC.
+
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index 9c3e2dc..f64dcb9 100644 (file)
@@ -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:
index 028388d..9779979 100644 (file)
@@ -1,3 +1,24 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * config/tc-sh.c (sh_fdpic): New.
+       (sh_check_fixup): Handle relocations on movi20.
+       (parse_exp): Do not reject PIC operators here.
+       (build_Mytes): Check for unhandled PIC operators here.  Use
+       sh_check_fixup for movi20.
+       (enum options): Add OPTION_FDPIC.
+       (md_longopts, md_parse_option, md_show_usage): Add --fdpic.
+       (sh_fix_adjustable, md_apply_fix): Handle FDPIC and movi20 relocations.
+       (sh_elf_final_processing): Handle --fdpic.
+       (sh_uclinux_target_format): New.
+       (sh_parse_name): Handle FDPIC relocation operators.
+       * config/tc-sh.h (TARGET_FORMAT): Define specially for TE_UCLINUX.
+       (sh_uclinux_target_format): Declare for TE_UCLINUX.
+       * configure.tgt (sh-*-uclinux* | sh[12]-*-uclinux*): Set
+       em=uclinux.
+       * doc/c-sh.texi (SH Options): Document --fdpic.
+
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index a7cdd0e..4e49e4e 100644 (file)
@@ -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 */
 }
 \f
 /* 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;
 
index 1b5ec26..2a69627 100644 (file)
@@ -1,6 +1,6 @@
 /* This file is tc-sh.h
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
-   2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
 
    This file is part of GAS, the GNU Assembler.
 
@@ -134,7 +134,7 @@ extern void sh_frob_file (void);
 
 #define COFF_MAGIC (!target_big_endian ? SH_ARCH_MAGIC_LITTLE : SH_ARCH_MAGIC_BIG)
 
-#define tc_coff_symbol_emit_hook(a) ; /* not used */
+#define tc_coff_symbol_emit_hook(a) ; /* Not used.  */
 
 #define TC_KEEP_FX_OFFSET 1
 
@@ -155,7 +155,7 @@ extern void sh_frob_file (void);
 #ifdef OBJ_ELF
 /* ELF specific definitions.  */
 
-/* Whether or not the target is big endian */
+/* Whether or not the target is big endian */
 extern int target_big_endian;
 #ifdef TE_LINUX
 #define TARGET_FORMAT (!target_big_endian ? "elf32-sh-linux" : "elf32-shbig-linux")
@@ -165,6 +165,9 @@ extern int target_big_endian;
 #define TARGET_FORMAT (!target_big_endian ? "elf32-shl-symbian" : "elf32-sh-symbian")
 #elif defined (TE_VXWORKS)
 #define TARGET_FORMAT (!target_big_endian ? "elf32-shl-vxworks" : "elf32-sh-vxworks")
+#elif defined (TE_UCLINUX)
+#define TARGET_FORMAT sh_uclinux_target_format ()
+extern const char * sh_uclinux_target_format (void);
 #else
 #define TARGET_FORMAT (!target_big_endian ? "elf32-shl" : "elf32-sh")
 #endif
@@ -172,7 +175,7 @@ extern int target_big_endian;
 #define elf_tc_final_processing sh_elf_final_processing
 extern void sh_elf_final_processing (void);
 
-#define DIFF_EXPR_OK           /* foo-. gets turned into PC relative relocs */
+#define DIFF_EXPR_OK           /* foo-. gets turned into PC relative relocs */
 
 #define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_"
 
@@ -227,8 +230,8 @@ extern bfd_boolean sh_fix_adjustable (struct fix *);
 
 #define md_parse_name(name, exprP, mode, nextcharP) \
   sh_parse_name ((name), (exprP), (mode), (nextcharP))
-int sh_parse_name (char const *name, expressionS *exprP,
-                  enum expr_mode mode, char *nextchar);
+int sh_parse_name (char const *, expressionS *,
+                  enum expr_mode, char *);
 
 #define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \
   sh_cons_fix_new ((FRAG), (OFF), (LEN), (EXP))
@@ -244,7 +247,7 @@ void sh_cons_fix_new (fragS *, int, int, expressionS *);
 extern void sh_cfi_frame_initial_instructions (void);
 
 #define tc_regname_to_dw2regnum sh_regname_to_dw2regnum
-extern int sh_regname_to_dw2regnum (char *regname);
+extern int sh_regname_to_dw2regnum (char *);
 
 /* All SH instructions are multiples of 16 bits.  */
 #define DWARF2_LINE_MIN_INSN_LENGTH 2
index 23d8662..77cbac1 100644 (file)
@@ -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 ;;
index 00c95d7..619f022 100644 (file)
@@ -1,5 +1,5 @@
-@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2003, 2004, 2005, 2008
-@c Free Software Foundation, Inc.
+@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2001, 2003, 2004,
+@c 2005, 2008, 2010  Free Software Foundation, Inc.
 @c This is part of the GAS manual.
 @c For copying conditions, see the file as.texinfo.
 @page
@@ -54,6 +54,10 @@ Renesas assembler.
 @item --allow-reg-prefix
 Allow '$' as a register name prefix.
 
+@kindex --fdpic
+@item --fdpic
+Generate an FDPIC object file.
+
 @item --isa=sh4 | sh4a
 Specify the sh4 or sh4a instruction set.
 @item --isa=dsp
index 59f9830..5d2a4f3 100644 (file)
@@ -1,3 +1,15 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * gas/sh/basic.exp: Run new tests.  Handle uClinux like Linux.
+       * gas/sh/fdpic.d: New file.
+       * gas/sh/fdpic.s: New file.
+       * gas/sh/reg-prefix.d: Force big-endian.
+       * gas/sh/sh2a-pic.d: New file.
+       * gas/sh/sh2a-pic.s: New file.
+       * lib/gas-defs.exp (is_elf_format): Include sh*-*-uclinux*.
+
 2010-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/11600
index 3bb7931..2daa038 100644 (file)
@@ -142,7 +142,7 @@ if [istarget sh*-*-*] then {
        run_dump_test "pcrel2"
     }
 
-    if {[istarget sh*-*elf] || [istarget sh*-linux*]} then {
+    if {[istarget sh*-*elf] || [istarget sh*-*linux*]} then {
        if {![istarget "sh64*-*-*"] && ![istarget "sh5*-*-*"]} then {
            run_dump_test "sh4a"
            run_dump_test "sh4a-fp"
@@ -151,9 +151,11 @@ if [istarget sh*-*-*] then {
            run_dump_test "sh4al-dsp"
 
            run_dump_test "sh2a"
+           run_dump_test "sh2a-pic"
        }
 
        run_dump_test "pic"
+       run_dump_test "fdpic"
 
        # Test TLS.
        run_dump_test "tlsd"
diff --git a/gas/testsuite/gas/sh/fdpic.d b/gas/testsuite/gas/sh/fdpic.d
new file mode 100644 (file)
index 0000000..33dfc71
--- /dev/null
@@ -0,0 +1,13 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: FDPIC relocations
+
+dump.o:     file format elf32-sh.*
+
+Disassembly of section .text:
+       \.\.\.
+                       0: R_SH_REL32   foo
+                       4: R_SH_FUNCDESC        foo
+                       8: R_SH_GOT32   foo
+                       c: R_SH_GOTOFF  foo
+                       10: R_SH_GOTFUNCDESC    foo
+                       14: R_SH_GOTOFFFUNCDESC foo
diff --git a/gas/testsuite/gas/sh/fdpic.s b/gas/testsuite/gas/sh/fdpic.s
new file mode 100644 (file)
index 0000000..7a7ad0f
--- /dev/null
@@ -0,0 +1,8 @@
+       .text
+
+       .long   foo@PCREL
+       .long   foo@FUNCDESC
+       .long   foo@GOT
+       .long   foo@GOTOFF
+       .long   foo@GOTFUNCDESC
+       .long   foo@GOTOFFFUNCDESC
index 1821bbc..a42e8c4 100644 (file)
@@ -1,10 +1,11 @@
 #objdump: -dr --prefix-addresses --show-raw-insn
-#as: --allow-reg-prefix -little
+#as: --allow-reg-prefix -big
 #name: SH --allow-reg-prefix option
+#skip: sh*-*-symbian*
 # Test SH register names prefixed with $:
 
 .*:     file format elf.*sh.*
 
 Disassembly of section .text:
-0x00000000 12 60               mov\.l  @r1,r0
+0x00000000 60 12               mov\.l  @r1,r0
 
diff --git a/gas/testsuite/gas/sh/sh2a-pic.d b/gas/testsuite/gas/sh/sh2a-pic.d
new file mode 100644 (file)
index 0000000..c7fe12b
--- /dev/null
@@ -0,0 +1,16 @@
+#objdump: -dr --prefix-addresses --show-raw-insn
+#name: SH2a PIC relocations
+#as: -isa=sh2a
+#skip: sh*-*-symbian*
+
+dump.o:     file format elf32-sh.*
+
+Disassembly of section .text:
+0x00000000 01 00 00 00         movi20  #0,r1
+                       0: R_SH_GOT20   foo
+0x00000004 01 00 00 00         movi20  #0,r1
+                       4: R_SH_GOTOFF20        foo
+0x00000008 01 00 00 00         movi20  #0,r1
+                       8: R_SH_GOTFUNCDESC20   foo
+0x0000000c 01 00 00 00         movi20  #0,r1
+                       c: R_SH_GOTOFFFUNCDESC20        foo
diff --git a/gas/testsuite/gas/sh/sh2a-pic.s b/gas/testsuite/gas/sh/sh2a-pic.s
new file mode 100644 (file)
index 0000000..888a7c9
--- /dev/null
@@ -0,0 +1,6 @@
+       .text
+
+       movi20  #foo@GOT, r1
+       movi20  #foo@GOTOFF, r1
+       movi20  #foo@GOTFUNCDESC, r1
+       movi20  #foo@GOTOFFFUNCDESC, r1
index 0506b94..fd2f179 100644 (file)
@@ -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*] \
index 9008aaa..ddd927a 100644 (file)
@@ -1,3 +1,14 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * sh.h (EF_SH_PIC, EF_SH_FDPIC): Define.
+       (R_SH_FIRST_INVALID_RELOC_6, R_SH_LAST_INVALID_RELOC_6): New.  Adjust
+       other invalid ranges.
+       (R_SH_GOT20, R_SH_GOTOFF20, R_SH_GOTFUNCDESC, R_SH_GOTFUNCDESC20)
+       (R_SH_GOTOFFFUNCDESC, R_SH_GOTOFFFUNCDESC20, R_SH_FUNCDESC)
+       (R_SH_FUNCDESC_VALUE): New.
+
 2010-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/11600
index fcb962a..c2bd50d 100644 (file)
@@ -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)
index 973e817..9cd324a 100644 (file)
@@ -1,3 +1,16 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * Makefile.am (ALL_EMULATIONS): Add eshelf_fd.o and eshlelf_fd.o.
+       (eshelf_fd.c, eshlelf_fd.c): New rules.
+       * Makefile.in: Regenerate.
+       * configure.tgt (sh-*-uclinux*): Add shelf_fd and shlelf_fd
+       emulations.
+       * emulparams/shelf_fd.sh: New file.
+       * emulparams/shlelf_fd.sh: New file.
+       * emulparams/shlelf_linux.sh: Update comment.
+
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index def0287..f75c96a 100644 (file)
@@ -550,7 +550,7 @@ sh-*-elf* | sh[1234]*-*-elf | sh-*-rtems* | sh-*-kaos*)
                        targ_extra_emuls="shlelf sh shl" ;;
 sh-*-uclinux* | sh[12]-*-uclinux*)
                        targ_emul=shelf_uclinux
-                       targ_extra_emuls="shelf shlelf sh shl" ;;
+                       targ_extra_emuls="shelf shlelf sh shl shelf_fd shlelf_fd" ;;
 sh-*-vxworks)          targ_emul=shelf_vxworks
                        targ_extra_emuls=shlelf_vxworks ;;
 sh-*-nto*)             targ_emul=shelf_nto
diff --git a/ld/emulparams/shelf_fd.sh b/ld/emulparams/shelf_fd.sh
new file mode 100644 (file)
index 0000000..7ec25ab
--- /dev/null
@@ -0,0 +1,2 @@
+. ${srcdir}/emulparams/shlelf_fd.sh
+OUTPUT_FORMAT="elf32-shbig-fdpic"
diff --git a/ld/emulparams/shlelf_fd.sh b/ld/emulparams/shlelf_fd.sh
new file mode 100644 (file)
index 0000000..f1f4107
--- /dev/null
@@ -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__ = .;}
+  }
+"
index 95b6acc..c14aae2 100644 (file)
@@ -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"
index 61daf44..4a3989e 100644 (file)
@@ -1,3 +1,46 @@
+2010-05-25  Daniel Jacobowitz  <dan@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Andrew Stubbs  <ams@codesourcery.com>
+
+       * ld-sh/sh.exp: Handle uClinux like Linux.
+       * lib/ld-lib.exp (is_elf_format): Include sh*-*-uclinux*.
+       * ld-sh/fdpic-funcdesc-shared.d: New file.
+       * ld-sh/fdpic-funcdesc-shared.s: New file.
+       * ld-sh/fdpic-funcdesc-static.d: New file.
+       * ld-sh/fdpic-funcdesc-static.s: New file.
+       * ld-sh/fdpic-gotfuncdesc-shared.d: New file.
+       * ld-sh/fdpic-gotfuncdesc-shared.s: New file.
+       * ld-sh/fdpic-gotfuncdesc-static.d: New file.
+       * ld-sh/fdpic-gotfuncdesc-static.s: New file.
+       * ld-sh/fdpic-gotfuncdesci20-shared.d: New file.
+       * ld-sh/fdpic-gotfuncdesci20-shared.s: New file.
+       * ld-sh/fdpic-gotfuncdesci20-static.d: New file.
+       * ld-sh/fdpic-gotfuncdesci20-static.s: New file.
+       * ld-sh/fdpic-goti20-shared.d: New file.
+       * ld-sh/fdpic-goti20-shared.s: New file.
+       * ld-sh/fdpic-goti20-static.d: New file.
+       * ld-sh/fdpic-goti20-static.s: New file.
+       * ld-sh/fdpic-gotofffuncdesc-shared.d: New file.
+       * ld-sh/fdpic-gotofffuncdesc-shared.s: New file.
+       * ld-sh/fdpic-gotofffuncdesc-static.d: New file.
+       * ld-sh/fdpic-gotofffuncdesc-static.s: New file.
+       * ld-sh/fdpic-gotofffuncdesci20-shared.d: New file.
+       * ld-sh/fdpic-gotofffuncdesci20-shared.s: New file.
+       * ld-sh/fdpic-gotofffuncdesci20-static.d: New file.
+       * ld-sh/fdpic-gotofffuncdesci20-static.s: New file.
+       * ld-sh/fdpic-gotoffi20-shared.d: New file.
+       * ld-sh/fdpic-gotoffi20-shared.s: New file.
+       * ld-sh/fdpic-gotoffi20-static.d: New file.
+       * ld-sh/fdpic-gotoffi20-static.s: New file.
+       * ld-sh/fdpic-plt-be.d: New file.
+       * ld-sh/fdpic-plt-le.d: New file.
+       * ld-sh/fdpic-plt.s: New file.
+       * ld-sh/fdpic-plti20-be.d: New file.
+       * ld-sh/fdpic-plti20-le.d: New file.
+       * ld-sh/fdpic-stack-default.d: New file.
+       * ld-sh/fdpic-stack-size.d: New file.
+       * ld-sh/fdpic-stack.s: New file.
+
 2010-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/11600
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-shared.d b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.d
new file mode 100644 (file)
index 0000000..899c5ae
--- /dev/null
@@ -0,0 +1,32 @@
+#source: fdpic-funcdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.data -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0009[ \t]+.*
+Contents of section \.data:
+ [0-9a-f]+ 00000000[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.data:
+
+[0-9a-f]+ <bar>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+\.\.\.\.
+[ \t]+[0-9a-f]+: R_SH_DIR32[ \t]+\.got
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-shared.s b/ld/testsuite/ld-sh/fdpic-funcdesc-shared.s
new file mode 100644 (file)
index 0000000..87d600d
--- /dev/null
@@ -0,0 +1,10 @@
+       .data
+       .globl  bar
+       .type   bar,@object
+       .size   bar,4
+bar:
+       .long   foo@FUNCDESC
+       .text
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-static.d b/ld/testsuite/ld-sh/fdpic-funcdesc-static.d
new file mode 100644 (file)
index 0000000..cb09b90
--- /dev/null
@@ -0,0 +1,25 @@
+#source: fdpic-funcdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 400098 004100ac 004100b0 004100a8 004100b4[ \t]+.*
+Contents of section \.data:
+ 4100a8 004100ac[ \t]+.*
+Contents of section \.got:
+ 4100ac 00400094 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <foo>:
+[ \t]+400094:[ \t]+00 09[ \t]+nop[ \t]+
+
+00400096 <_start>:
+[ \t]+400096:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-funcdesc-static.s b/ld/testsuite/ld-sh/fdpic-funcdesc-static.s
new file mode 100644 (file)
index 0000000..f59e0d9
--- /dev/null
@@ -0,0 +1,14 @@
+       .data
+       .globl  bar
+       .type   bar,@object
+       .size   bar,4
+bar:
+       .long   foo@FUNCDESC
+       .text
+       .type   foo,@function
+foo:
+       nop
+       .globl  _start
+       .type   _start,@function
+_start:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.d
new file mode 100644 (file)
index 0000000..c86b424
--- /dev/null
@@ -0,0 +1,25 @@
+#source: fdpic-gotfuncdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ d00001ce 0000000c[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! c
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-shared.s
new file mode 100644 (file)
index 0000000..d75a061
--- /dev/null
@@ -0,0 +1,9 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       mov.l .L1, r0
+       mov.l @(r0,r12), r1
+       .align 2
+.L1:
+       .long   foo@GOTFUNCDESC
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.d
new file mode 100644 (file)
index 0000000..3da8c40
--- /dev/null
@@ -0,0 +1,26 @@
+#source: fdpic-gotfuncdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 d00001ce 0000000c 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 4000a0 004100b0 004100b4 004100c4 004100b8[ \t]+.*
+Contents of section \.got:
+ 4100b0 0040009c 004100b8 00000000 00000000[ \t]+.*
+ 4100c0 00000000 004100b0[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+d0 00[ \t]+mov\.l[ \t]+400098 <_start\+0x4>,r0[ \t]+! c
+[ \t]+400096:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+[ \t]+400098:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+
+0040009c <foo>:
+[ \t]+40009c:[ \t]+00 09[ \t]+nop[ \t]+
+[ \t]+40009e:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesc-static.s
new file mode 100644 (file)
index 0000000..fc403b7
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       mov.l .L1, r0
+       mov.l @(r0,r12), r1
+       .align 2
+.L1:
+       .long   foo@GOTFUNCDESC
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.d
new file mode 100644 (file)
index 0000000..39eb610
--- /dev/null
@@ -0,0 +1,24 @@
+#source: fdpic-gotfuncdesci20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0000000c 01ce[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-shared.s
new file mode 100644 (file)
index 0000000..736d30d
--- /dev/null
@@ -0,0 +1,6 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       movi20 #foo@GOTFUNCDESC, r0
+       mov.l @(r0,r12), r1
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.d
new file mode 100644 (file)
index 0000000..246e8f3
--- /dev/null
@@ -0,0 +1,24 @@
+#source: fdpic-gotfuncdesci20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 0000000c 01ce0009[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100ac 004100b0 004100c0 004100b4[ \t]+.*
+Contents of section \.got:
+ 4100ac 0040009a 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000 004100ac[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+0040009a <foo>:
+[ \t]+40009a:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s b/ld/testsuite/ld-sh/fdpic-gotfuncdesci20-static.s
new file mode 100644 (file)
index 0000000..76930f5
--- /dev/null
@@ -0,0 +1,9 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       movi20 #foo@GOTFUNCDESC, r0
+       mov.l @(r0,r12), r1
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-shared.d b/ld/testsuite/ld-sh/fdpic-goti20-shared.d
new file mode 100644 (file)
index 0000000..0955770
--- /dev/null
@@ -0,0 +1,24 @@
+#source: fdpic-goti20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 0000000c 01ce[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
+[ \t]+[0-9a-f]+: R_SH_GLOB_DAT[ \t]+foo
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-shared.s b/ld/testsuite/ld-sh/fdpic-goti20-shared.s
new file mode 100644 (file)
index 0000000..08f5446
--- /dev/null
@@ -0,0 +1,6 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       movi20 #foo@GOT, r0
+       mov.l @(r0,r12), r1
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-static.d b/ld/testsuite/ld-sh/fdpic-goti20-static.d
new file mode 100644 (file)
index 0000000..91f5299
--- /dev/null
@@ -0,0 +1,22 @@
+#source: fdpic-goti20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 0000000c 01ce[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100b4 004100a8[ \t]+.*
+Contents of section \.data:
+ 4100a4 00000001[ \t]+.*
+Contents of section \.got:
+ 4100a8 00000000 00000000 00000000 004100a4[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
diff --git a/ld/testsuite/ld-sh/fdpic-goti20-static.s b/ld/testsuite/ld-sh/fdpic-goti20-static.s
new file mode 100644 (file)
index 0000000..172a680
--- /dev/null
@@ -0,0 +1,11 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       movi20 #foo@GOT, r0
+       mov.l @(r0,r12), r1
+       .data
+       .type   foo,@object
+       .size   foo,4
+foo:
+       .long 1
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.d
new file mode 100644 (file)
index 0000000..c43721d
--- /dev/null
@@ -0,0 +1,32 @@
+#source: fdpic-gotofffuncdesc-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ d10031cc fffffff8 00090009[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000008 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d1 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r1[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 08[ \t]+movi20[ \t]+#8,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-shared.s
new file mode 100644 (file)
index 0000000..daf1c84
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       mov.l .L1, r1
+       add r12, r1
+       .align 2
+.L1:
+       .long   foo@GOTOFFFUNCDESC
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.d
new file mode 100644 (file)
index 0000000..5ff417f
--- /dev/null
@@ -0,0 +1,27 @@
+#source: fdpic-gotofffuncdesc-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 d10031cc fffffff8 00090009[ \t]+.*
+Contents of section \.rofixup:
+ 4000a0 004100ac 004100b0 004100b4[ \t]+.*
+Contents of section \.got:
+ 4100ac 0040009c 004100b4 00000000 00000000[ \t]+.*
+ 4100bc 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+d1 00[ \t]+mov\.l[ \t]+400098 <_start\+0x4>,r1[ \t]+! fffffff8
+[ \t]+400096:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+[ \t]+400098:[ \t]+ff ff[ \t]+\.word 0xffff
+[ \t]+40009a:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+
+0040009c <foo>:
+[ \t]+40009c:[ \t]+00 09[ \t]+nop[ \t]+
+[ \t]+40009e:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesc-static.s
new file mode 100644 (file)
index 0000000..307ff1d
--- /dev/null
@@ -0,0 +1,12 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       mov.l .L1, r1
+       add r12, r1
+       .align 2
+.L1:
+       .long   foo@GOTOFFFUNCDESC
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.d
new file mode 100644 (file)
index 0000000..c19abe6
--- /dev/null
@@ -0,0 +1,29 @@
+#source: fdpic-gotofffuncdesci20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 01f0fff8 31cc0009[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000006 00000000 00000000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+01 f0 ff f8[ \t]+movi20[ \t]+#-8,r1
+ [0-9a-f]+:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+
+[0-9a-f]+ <foo>:
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 06[ \t]+movi20[ \t]+#6,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+\.text
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-shared.s
new file mode 100644 (file)
index 0000000..bf16011
--- /dev/null
@@ -0,0 +1,9 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       movi20 #foo@GOTOFFFUNCDESC, r1
+       add r12, r1
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.d
new file mode 100644 (file)
index 0000000..3b96f7e
--- /dev/null
@@ -0,0 +1,24 @@
+#source: fdpic-gotofffuncdesci20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 01f0fff8 31cc0009[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100a8 004100ac 004100b0[ \t]+.*
+Contents of section \.got:
+ 4100a8 0040009a 004100b0 00000000 00000000[ \t]+.*
+ 4100b8 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+01 f0 ff f8[ \t]+movi20[ \t]+#-8,r1
+[ \t]+400098:[ \t]+31 cc[ \t]+add[ \t]+r12,r1
+
+0040009a <foo>:
+[ \t]+40009a:[ \t]+00 09[ \t]+nop[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s b/ld/testsuite/ld-sh/fdpic-gotofffuncdesci20-static.s
new file mode 100644 (file)
index 0000000..7017e0a
--- /dev/null
@@ -0,0 +1,9 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       movi20 #foo@GOTOFFFUNCDESC, r1
+       add r12, r1
+       .type   foo,@function
+foo:
+       nop
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.d
new file mode 100644 (file)
index 0000000..8b57e11
--- /dev/null
@@ -0,0 +1,30 @@
+#source: fdpic-gotoffi20-shared.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.text -j.data -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ [0-9a-f]+ 00f0fffc 01ce[ \t]+.*
+Contents of section \.data:
+ [0-9a-f]+ 00000001[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 f0 ff fc[ \t]+movi20[ \t]+#-4,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+
+Disassembly of section \.data:
+
+[0-9a-f]+ <foo>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 01[ \t]+\.\.\.\.
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s b/ld/testsuite/ld-sh/fdpic-gotoffi20-shared.s
new file mode 100644 (file)
index 0000000..fc8213c
--- /dev/null
@@ -0,0 +1,11 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       movi20 #foo@GOTOFF, r0
+       mov.l @(r0,r12), r1
+       .data
+       .type   foo,@object
+       .size   foo,4
+foo:
+       .long   1
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-static.d b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.d
new file mode 100644 (file)
index 0000000..9390720
--- /dev/null
@@ -0,0 +1,22 @@
+#source: fdpic-gotoffi20-static.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#objdump: -ds
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.text:
+ 400094 00f0fffc 01ce[ \t]+.*
+Contents of section \.rofixup:
+ 40009c 004100a4[ \t]+.*
+Contents of section \.data:
+ 4100a0 00000001[ \t]+.*
+Contents of section \.got:
+ 4100a4 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.text:
+
+00400094 <_start>:
+[ \t]+400094:[ \t]+00 f0 ff fc[ \t]+movi20[ \t]+#-4,r0
+[ \t]+400098:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
diff --git a/ld/testsuite/ld-sh/fdpic-gotoffi20-static.s b/ld/testsuite/ld-sh/fdpic-gotoffi20-static.s
new file mode 100644 (file)
index 0000000..079255b
--- /dev/null
@@ -0,0 +1,11 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       movi20 #foo@GOTOFF, r0
+       mov.l @(r0,r12), r1
+       .data
+       .type   foo,@object
+       .size   foo,4
+foo:
+       .long   1
diff --git a/ld/testsuite/ld-sh/fdpic-plt-be.d b/ld/testsuite/ld-sh/fdpic-plt-be.d
new file mode 100644 (file)
index 0000000..375e088
--- /dev/null
@@ -0,0 +1,75 @@
+#source: fdpic-plt.s
+#as: --isa=sh4a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ d00201ce 7004412b 0cce0009 fffffff0[ \t]+.*
+ [0-9a-f]+ 00000000 60c2402b 53c10009 d00201ce[ \t]+.*
+ [0-9a-f]+ 7004412b 0cce0009 fffffff8 0000000c[ \t]+.*
+ [0-9a-f]+ 60c2402b 53c10009[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ d000d101 ffffffc4 ffffffdc[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 0000023c 00000000 00000258 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+d0 02[ \t]+mov\.l[ \t]+[0-9a-f]+ <foo@plt\+0xc>,r0[ \t]+! fffffff0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f0[ \t]+fadd[ \t]+fr15,fr15
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+d0 02[ \t]+mov\.l[ \t]+[0-9a-f]+ <bar@plt\+0xc>,r0[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff f8[ \t]+fmov[ \t]+@r15,fr15
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 0c[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffc4
+ [0-9a-f]+:[ \t]+d1 01[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffdc
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff c4[ \t]+fcmp/eq[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff dc[ \t]+fmov[ \t]+fr13,fr15
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+02 3c[ \t]+mov.b[ \t]+@\(r0,r3\),r2
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+[0-9a-f]+:[ \t]+02 58[ \t]+\.word 0x0258
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plt-le.d b/ld/testsuite/ld-sh/fdpic-plt-le.d
new file mode 100644 (file)
index 0000000..4a3e55b
--- /dev/null
@@ -0,0 +1,74 @@
+#source: fdpic-plt.s
+#as: --isa=sh4a -little --fdpic
+#ld: -EL -mshlelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-sh-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ 02d0ce01 04702b41 ce0c0900 f0ffffff[ \t]+.*
+ [0-9a-f]+ 00000000 c2602b40 c1530900 02d0ce01[ \t]+.*
+ [0-9a-f]+ 04702b41 ce0c0900 f8ffffff 0c000000[ \t]+.*
+ [0-9a-f]+ c2602b40 c1530900[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ 00d001d1 c4ffffff dcffffff[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 3c020000 00000000 58020000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+02 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <foo@plt\+0xc>,r0[ \t]+! fffffff0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+f0 ff[ \t]+fadd[ \t]+fr15,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+02 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <bar@plt\+0xc>,r0[ \t]+! fffffff8
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+ [0-9a-f]+:[ \t]+f8 ff[ \t]+fmov[ \t]+@r15,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+0c 00[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffc4
+ [0-9a-f]+:[ \t]+01 d1[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffdc
+ [0-9a-f]+:[ \t]+c4 ff[ \t]+fcmp/eq[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+dc ff[ \t]+fmov[ \t]+fr13,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+3c 02[ \t]+mov.b[ \t]+@\(r0,r3\),r2
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+00 00[ \t]+\.word 0x0000
+[ \t]+[0-9a-f]+:[ \t]+58 02[ \t]+\.word 0x0258
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plt.s b/ld/testsuite/ld-sh/fdpic-plt.s
new file mode 100644 (file)
index 0000000..e873d3e
--- /dev/null
@@ -0,0 +1,11 @@
+       .text
+       .globl  f
+       .type   f,@function
+f:
+       mov.l .L1, r0
+       mov.l .L2, r1
+       .align 2
+.L1:
+       .long   foo@PLT
+.L2:
+       .long   bar@PLT
diff --git a/ld/testsuite/ld-sh/fdpic-plti20-be.d b/ld/testsuite/ld-sh/fdpic-plti20-be.d
new file mode 100644 (file)
index 0000000..282b34b
--- /dev/null
@@ -0,0 +1,63 @@
+#source: fdpic-plt.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-shbig-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ 00f0fff0 01ce7004 412b0cce 00000000[ \t]+.*
+ [0-9a-f]+ 60c2402b 53c10009 00f0fff8 01ce7004[ \t]+.*
+ [0-9a-f]+ 412b0cce 0000000c 60c2402b 53c10009[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ d000d101 ffffffcc ffffffe0[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 00000238 00000000 00000250 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+00 f0 ff f0[ \t]+movi20[ \t]+#-16,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+00 f0 ff f8[ \t]+movi20[ \t]+#-8,r0
+ [0-9a-f]+:[ \t]+01 ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+70 04[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+41 2b[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+0c ce[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 0c[ \t]+movi20[ \t]+#12,r0
+ [0-9a-f]+:[ \t]+60 c2[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+40 2b[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+53 c1[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+00 09[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+d0 00[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffcc
+ [0-9a-f]+:[ \t]+d1 01[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffe0
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff cc[ \t]+fmov[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+ff e0[ \t]+fadd[ \t]+fr14,fr15
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+00 00 02 38[ \t]+movi20[ \t]+#568,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+[ \t]+[0-9a-f]+:[ \t]+00 00 02 50[ \t]+movi20[ \t]+#592,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-plti20-le.d b/ld/testsuite/ld-sh/fdpic-plti20-le.d
new file mode 100644 (file)
index 0000000..74e1e9b
--- /dev/null
@@ -0,0 +1,63 @@
+#source: fdpic-plt.s
+#as: --isa=sh2a -little --fdpic
+#ld: -EL -mshlelf_fd -shared
+#objdump: -dsR -j.plt -j.text -j.got
+#target: sh*-*-uclinux*
+
+.*:[ \t]+file format elf32-sh-fdpic
+
+Contents of section \.plt:
+ [0-9a-f]+ f000f0ff ce010470 2b41ce0c 00000000[ \t]+.*
+ [0-9a-f]+ c2602b40 c1530900 f000f8ff ce010470[ \t]+.*
+ [0-9a-f]+ 2b41ce0c 0c000000 c2602b40 c1530900[ \t]+.*
+Contents of section \.text:
+ [0-9a-f]+ 00d001d1 ccffffff e0ffffff[ \t]+.*
+Contents of section \.got:
+ [0-9a-f]+ 38020000 00000000 50020000 00000000[ \t]+.*
+ [0-9a-f]+ 00000000 00000000 00000000[ \t]+.*
+
+Disassembly of section \.plt:
+
+[0-9a-f]+ <foo@plt>:
+ [0-9a-f]+:[ \t]+f0 00 f0 ff[ \t]+movi20[ \t]+#-16,r0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+ [0-9a-f]+:[ \t]+c2 60[ \t]+mov\.l[ \t]+@r12,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+[0-9a-f]+ <bar@plt>:
+ [0-9a-f]+:[ \t]+f0 00 f8 ff[ \t]+movi20[ \t]+#-8,r0
+ [0-9a-f]+:[ \t]+ce 01[ \t]+mov\.l[ \t]+@\(r0,r12\),r1
+ [0-9a-f]+:[ \t]+04 70[ \t]+add[ \t]+#4,r0
+ [0-9a-f]+:[ \t]+2b 41[ \t]+jmp[ \t]+@r1
+ [0-9a-f]+:[ \t]+ce 0c[ \t]+mov\.l[ \t]+@\(r0,r12\),r12
+ [0-9a-f]+:[ \t]+0c 00[ \t]+mov\.b[ \t]+@\(r0,r0\),r0
+ [0-9a-f]+:[ \t]+00 00 c2 60[ \t]+movi20[ \t]+#24770,r0
+ [0-9a-f]+:[ \t]+2b 40[ \t]+jmp[ \t]+@r0
+ [0-9a-f]+:[ \t]+c1 53[ \t]+mov\.l[ \t]+@\(4,r12\),r3
+ [0-9a-f]+:[ \t]+09 00[ \t]+nop[ \t]+
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <f>:
+ [0-9a-f]+:[ \t]+00 d0[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x4>,r0[ \t]+! ffffffcc
+ [0-9a-f]+:[ \t]+01 d1[ \t]+mov\.l[ \t]+[0-9a-f]+ <f\+0x8>,r1[ \t]+! ffffffe0
+ [0-9a-f]+:[ \t]+cc ff[ \t]+fmov[ \t]+fr12,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+ [0-9a-f]+:[ \t]+e0 ff[ \t]+fadd[ \t]+fr14,fr15
+ [0-9a-f]+:[ \t]+ff ff[ \t]+\.word 0xffff
+
+Disassembly of section \.got:
+
+[0-9a-f]+ <\.got>:
+[ \t]+[0-9a-f]+:[ \t]+38 02[ \t]+\.word[ \t]+0x0238
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+foo
+[ \t]+[0-9a-f]+:[ \t]+00 00 00 00[ \t]+movi20[ \t]+#0,r0
+[ \t]+[0-9a-f]+:[ \t]+00 00 50 02[ \t]+movi20[ \t]+#592,r0
+[ \t]+[0-9a-f]+: R_SH_FUNCDESC_VALUE[ \t]+bar
+[ \t]+\.\.\.
diff --git a/ld/testsuite/ld-sh/fdpic-stack-default.d b/ld/testsuite/ld-sh/fdpic-stack-default.d
new file mode 100644 (file)
index 0000000..8f9fd92
--- /dev/null
@@ -0,0 +1,19 @@
+#source: fdpic-stack.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd
+#readelf: -l
+#target: sh*-*-uclinux*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x400074
+There are 2 program headers, starting at offset 52
+
+Program Headers:
+[ \t]+Type[ \t]+Offset[ \t]+VirtAddr[ \t]+PhysAddr[ \t]+FileSiz MemSiz[ \t]+Flg Align
+[ \t]+LOAD[ \t]+0x000000 0x00400000 0x00400000 0x00076 0x00076 R E 0x10000
+[ \t]+GNU_STACK[ \t]+0x000000 0x00000000 0x00000000 0x00000 0x20000 RWE 0x8
+
+ Section to Segment mapping:
+[ \t]+Segment Sections\.\.\.
+[ \t]+00[ \t]+\.text 
+[ \t]+01[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-stack-size.d b/ld/testsuite/ld-sh/fdpic-stack-size.d
new file mode 100644 (file)
index 0000000..f993a2a
--- /dev/null
@@ -0,0 +1,19 @@
+#source: fdpic-stack.s
+#as: --isa=sh2a -big --fdpic
+#ld: -EB -mshelf_fd --defsym __stacksize=0x40000
+#readelf: -l
+#target: sh*-*-uclinux*
+
+Elf file type is EXEC \(Executable file\)
+Entry point 0x400074
+There are 2 program headers, starting at offset 52
+
+Program Headers:
+[ \t]+Type[ \t]+Offset[ \t]+VirtAddr[ \t]+PhysAddr[ \t]+FileSiz MemSiz[ \t]+Flg Align
+[ \t]+LOAD[ \t]+0x000000 0x00400000 0x00400000 0x00076 0x00076 R E 0x10000
+[ \t]+GNU_STACK[ \t]+0x000000 0x00000000 0x00000000 0x00000 0x40000 RWE 0x8
+
+ Section to Segment mapping:
+[ \t]+Segment Sections\.\.\.
+[ \t]+00[ \t]+\.text 
+[ \t]+01[ \t]+
diff --git a/ld/testsuite/ld-sh/fdpic-stack.s b/ld/testsuite/ld-sh/fdpic-stack.s
new file mode 100644 (file)
index 0000000..b0421ea
--- /dev/null
@@ -0,0 +1,5 @@
+       .text
+       .globl  _start
+       .type   _start,@function
+_start:
+       nop
index 335946b..f42a79f 100644 (file)
@@ -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 {
index 5b2e62b..9e8b809 100644 (file)
@@ -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*] \