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 4c7593c82886363d9da5e61c66c114cb2c7b8b42..76924dec3541185ccc6e3adfde33c6cd97f52b1e 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
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11624
index e9dcb2c89ed62f2630fddb04562b509bd669ae0c..5c42128ba26d98e2fd5c2ac51314275be9c1ef4d 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_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
 
 /* ARC Cores relocs.
 ARC 22 bit pc-relative branch.  The lowest two bits must be zero and are
index d39ef180642e14ccaa2f5f62336e33c2ff56a191..abe1b5eb4404121e1e8d2874361b56a662661c88 100644 (file)
@@ -1257,7 +1257,7 @@ case "${targ}" in
 
   sh-*-uclinux* | sh[12]-*-uclinux*)
     targ_defvec=bfd_elf32_sh_vec
 
   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
 #ifdef BFD64
     targ_selvecs="${targ_selvecs} bfd_elf32_sh64lin_vec bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec"
 #endif
index d498ff2ee3ba33cb8ba9f5757f73e61fb02063d4..310bb6af652c0df0097d108fe4a286fb0ca467f9 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_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_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" ;;
     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 3ca7fc7cc512b83e23855c437e7ceced85a3b4ef..65ae8d303a9233bd041b2ea918463da7d72ea0bd 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_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_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" ;;
     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 70f3a7b8ae11fa54e25a64731900865089a61dc5..05f087562c2fb196d8cca037c9ea2e64c0e6c402 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.
 
 
    This file is part of BFD, the Binary File Descriptor library.
 
         0,                     /* src_mask */
         ((bfd_vma) 0) - 1,     /* dst_mask */
         FALSE),                /* pcrel_offset */
         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 (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),
   EMPTY_HOWTO (209),
   EMPTY_HOWTO (210),
   EMPTY_HOWTO (211),
index 23ee06a1d02ebaca0548e1ff20a497019626149c..1b0daf96bba226ab25f0779c8d7588697a90bc4b 100644 (file)
@@ -27,6 +27,7 @@
 #include "elf-bfd.h"
 #include "elf-vxworks.h"
 #include "elf/sh.h"
 #include "elf-bfd.h"
 #include "elf-vxworks.h"
 #include "elf/sh.h"
+#include "dwarf2.h"
 #include "libiberty.h"
 #include "../opcodes/sh-opc.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"
 
 
 #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)
 #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
 \f
 #define SH_PARTIAL32 TRUE
 #define SH_SRC_MASK32 0xffffffff
@@ -88,6 +99,22 @@ vxworks_object_p (bfd *abfd ATTRIBUTE_UNUSED)
 #endif
 }
 
 #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 *
 /* 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_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 },
 #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_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;
 }
 
   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_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;
   } 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
 };
 
 #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, 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.  */
     },
     {
       /* 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, 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,
       { 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.  */
     },
     {
       /* 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,
       { 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,
       { 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.  */
     },
     {
       /* 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,
       { 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,
       { 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.  */
     },
     {
       /* 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,
       { 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,
       { 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.  */
     },
     {
       /* 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,
       { 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,
       { 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.  */
     },
     {
       /* 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,
       { 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 *
 /* 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)];
   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
 
 }
 #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 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.  */
 }
 
 /* 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)
 {
 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
 }
 
 /* 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;
 };
 
   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
 /* 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;
 
 
   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 {
   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))
 };
 
 #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;
 
 {
   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_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 \
 
 #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 *srelplt;
   asection *sdynbss;
   asection *srelbss;
+  asection *sfuncdesc;
+  asection *srelfuncdesc;
+  asection *srofixup;
 
   /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
   asection *srelplt2;
 
   /* 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 is VxWorks.  */
   bfd_boolean vxworks_p;
+
+  /* True if the target system uses FDPIC.  */
+  bfd_boolean fdpic_p;
 };
 
 /* Traverse an sh ELF linker hash table.  */
 };
 
 /* 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
 #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;
     }
 
   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->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;
 }
 
 
   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.  */
 
 /* 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->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;
 }
 
   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;
          || 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.  */
 
          /* 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
             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.  */
            {
              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.  */
 
          /* 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);
 
          /* 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;
     {
       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.  */
 
       /* 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.  */
       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;
        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.  */
       /* 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);
        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);
        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 ((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;
     }
   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
 
     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;
 
   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);
     {
       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;
     }
 
   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);
 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;
 }
 
   return TRUE;
 }
 
+#endif
+
 /* Set the sizes of the dynamic sections.  */
 
 static bfd_boolean
 /* 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;
     {
       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;
       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;
                  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
       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;
       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)
     }
 
   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;
 
   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);
 
   /* 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;
   /* 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
       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
          || 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;
        }
              || ! 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)
        {
 
       if (relocs)
        {
@@ -3172,67 +3747,251 @@ sh_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   return TRUE;
 }
 \f
   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);
 
 
       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 >= 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_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;
        {
          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;
       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];
       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);
          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];
 
          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)
            {
          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_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
                       || 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
                      && ((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
                ;
              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;
 
       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:
       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
                  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
              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);
 
              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
              /* 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;
            }
              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:
          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:
 
        force_got:
        case R_SH_GOT32:
+       case R_SH_GOT20:
 #ifdef INCLUDE_SHMEDIA
        case R_SH_GOT_LOW16:
        case R_SH_GOT_MEDLOW16:
 #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);
             offset table.  */
 
          BFD_ASSERT (sgot != NULL);
+         check_segment[0] = check_segment[1] = -1;
 
          if (h != NULL)
            {
 
          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;
                      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
            {
            }
          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_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);
                    }
                      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)
 
 #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;
                }
 
                    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
 
            }
 
 #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_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
 #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;
 
 #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;
 
 
          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
 
        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.  */
 
 #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;
 
 #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;
 
          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;
 
          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);
            }
 
          BFD_ASSERT (splt != NULL);
+         check_segment[1] = plt_segment;
          relocation = (splt->output_section->vma
                        + splt->output_offset
                        + h->plt.offset);
          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;
 
 
          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;
        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:
 
        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);
          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)
          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)
            {
          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 (! 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)
            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;
            }
 
              continue;
            }
 
-         sgot = htab->sgot;
-         if (sgot == NULL)
+         if (sgot == NULL || sgotplt == NULL)
            abort ();
 
          if (h != 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);
              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;
            }
                          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))
            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;
          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_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;
                          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:
          goto final_link_relocate;
 
        case R_SH_TLS_LD_32:
+         check_segment[0] = check_segment[1] = -1;
          if (! info->shared)
            {
              bfd_vma offset;
          if (! info->shared)
            {
              bfd_vma offset;
@@ -4293,8 +5473,7 @@ sh_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
              continue;
            }
 
              continue;
            }
 
-         sgot = htab->sgot;
-         if (sgot == NULL)
+         if (sgot == NULL || sgotplt == NULL)
            abort ();
 
          off = htab->tls_ldm_got.offset;
            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;
            }
 
              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:
          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
          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;
 
            Elf_Internal_Rela outrel;
            bfd_byte *loc;
 
+           check_segment[0] = check_segment[1] = -1;
+
            if (! info->shared)
              {
                relocation = tpoff (info, relocation);
            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:
        }
 
     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)
       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;
   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)
   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);
   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++)
 
   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:
          break;
 
        case R_SH_GOT32:
+       case R_SH_GOT20:
        case R_SH_GOTOFF:
        case R_SH_GOTOFF:
+       case R_SH_GOTOFF20:
        case R_SH_GOTPC:
 #ifdef INCLUDE_SHMEDIA
        case R_SH_GOT_LOW16:
        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:
 #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
          if (h != NULL)
            {
 #ifdef INCLUDE_SHMEDIA
@@ -4680,7 +5890,28 @@ sh_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
            }
          break;
 
            }
          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:
        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;
        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->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)
     {
 
   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
     }
 
   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;
   asection *srelgot;
   asection *sreloc;
   unsigned int r_type;
-  int tls_type, old_tls_type;
+  int got_type, old_got_type;
 
   sgot = NULL;
   srelgot = NULL;
 
   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;
 
              || 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)
            {
       /* 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_GOTPLT32:
            case R_SH_GOT32:
+           case R_SH_GOT20:
            case R_SH_GOTOFF:
            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:
            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:
            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:
              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:
        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:
 #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_GOT10BY4:
        case R_SH_GOT10BY8:
 #endif
+       case R_SH_GOTFUNCDESC:
+       case R_SH_GOTFUNCDESC20:
          switch (r_type)
            {
            default:
          switch (r_type)
            {
            default:
-             tls_type = GOT_NORMAL;
+             got_type = GOT_NORMAL;
              break;
            case R_SH_TLS_GD_32:
              break;
            case R_SH_TLS_GD_32:
-             tls_type = GOT_TLS_GD;
+             got_type = GOT_TLS_GD;
              break;
            case R_SH_TLS_IE_32:
              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;
            }
 
              break;
            }
 
@@ -5027,7 +6301,7 @@ sh_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec,
              else
 #endif
                h->got.refcount += 1;
              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
            {
            }
          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.  */
 #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
                    = (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
                }
                    = (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;
              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 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
                {
              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;
                }
            }
 
                    (_("%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)
            {
              if (h != NULL)
-               sh_elf_hash_entry (h)->tls_type = tls_type;
+               sh_elf_hash_entry (h)->got_type = got_type;
              else
              else
-               sh_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
+               sh_elf_local_got_type (abfd) [r_symndx] = got_type;
            }
 
          break;
            }
 
          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;
 
          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:
        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;
            }
 
                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:
          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;
 
   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 */
   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;
     {
       /* 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);
       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))
     }
 
   if (! sh_merge_bfd_arch (ibfd, obfd))
@@ -5406,9 +6796,18 @@ sh_elf_merge_private_data (bfd *ibfd, bfd *obfd)
       return FALSE;
     }
 
       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));
     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 */
   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)
 {
 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
 }
 
 /* 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;
   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;
 
       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.  */
 
       /* 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;
       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
 
       /* 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);
 
         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
       /* 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)
 
 #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,
 
       /* 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
        {
       else
        {
+         BFD_ASSERT (!plt_info->symbol_fields.got20);
+
          install_plt_field (output_bfd, FALSE,
          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
                              + 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;
          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
              /* ??? 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
              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)
              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
 
              /* 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
            }
          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
 #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
 
       /* 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.  */
 
       /* 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);
                      + 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
       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)
       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
          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);
          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.  */
 
          /* 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;
                          + 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
     }
 
   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 *sgot;
-      asection *srel;
+      asection *srelgot;
       Elf_Internal_Rela rel;
       bfd_byte *loc;
 
       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;
         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
 
       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))
        {
       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
        {
        }
       else
        {
@@ -5639,8 +7094,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
          rel.r_addend = 0;
        }
 
          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);
     }
 
       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;
     if (eh->datalabel_got.offset != (bfd_vma) -1)
       {
        asection *sgot;
-       asection *srel;
+       asection *srelgot;
        Elf_Internal_Rela rel;
        bfd_byte *loc;
 
        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;
           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
 
        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))
          {
        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
          {
          }
        else
          {
@@ -5688,8 +7156,8 @@ sh_elf_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
            rel.r_addend = 0;
          }
 
            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);
       }
   }
        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;
 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;
 
   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)
   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;
 
       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);
 
       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:
 #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;
 
            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);
              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,
          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]));
                                  + (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.  */
     }
 
   /* 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)
     {
       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,
       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;
 }
 
   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);
 }
 
   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"
 #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
                                        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_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
 
 #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"
 
 
 #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
 #undef TARGET_BIG_SYM
 #define        TARGET_BIG_SYM                  bfd_elf32_shvxworks_vec
 #undef TARGET_BIG_NAME
index 7275dd9f1a242fca990ab5294747806c08dbc06b..b3f97f3e719d7691d78a445b5d287a6cbeb71630 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_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",
   "BFD_RELOC_ARC_B22_PCREL",
   "BFD_RELOC_ARC_B26",
   "BFD_RELOC_BFIN_16_IMM",
index a8476295d23eec5876e58187a33e028774573a2e..7d16869263d8a84943dc5277dae6e9b074f1729f 100644 (file)
@@ -3255,6 +3255,20 @@ ENUMX
   BFD_RELOC_SH_TLS_DTPOFF32
 ENUMX
   BFD_RELOC_SH_TLS_TPOFF32
   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.
 
 ENUMDOC
   Renesas / SuperH SH relocs.  Not all of these appear in object files.
 
index 2e330e6dbed37909b61a4b49589682002ea12ef0..69a5a94b8e1a9ebb0f7ec2709320d774d24aa757 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_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_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;
 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_littlescore_vec,
 #endif
         &bfd_elf32_sh_vec,
+        &bfd_elf32_shbfd_vec,
         &bfd_elf32_shblin_vec,
         &bfd_elf32_shblin_vec,
+        &bfd_elf32_shfd_vec,
         &bfd_elf32_shl_vec,
         &bfd_elf32_shl_symbian_vec,
         &bfd_elf32_shlin_vec,
         &bfd_elf32_shl_vec,
         &bfd_elf32_shl_symbian_vec,
         &bfd_elf32_shlin_vec,
index c4abd963c8faeabc919af249aa9d77ae3fec9281..8cfe737a8b8ab0a26e6ec8ee34329f8680c877db 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
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index 9c3e2dc5b79db79a1247ee597b96b112cfda0d70..f64dcb904fd79854b138aed777971089c292de21 100644 (file)
@@ -2440,6 +2440,11 @@ get_machine_flags (unsigned e_flags, unsigned e_machine)
            default: strcat (buf, _(", unknown ISA")); break;
            }
 
            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:
          break;
 
        case EM_SH:
index 028388d15eaf148161fb240c953aa6eeb3739a7d..97799791e7edd920a2d397676df437dae48f638e 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
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index a7cdd0ecceee3114257ad431c366275433a83243..4e49e4e8ccd185e5d5398ba0626831239abc3d7f 100644 (file)
@@ -145,6 +145,9 @@ static unsigned int preset_target_arch;
    accommodate the insns seen so far.  */
 static unsigned int valid_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.  */
 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)
     {
 
   if (exp->X_op == O_PIC_reloc)
     {
-#ifdef HAVE_SH64
       switch (*r_type_p)
        {
        case BFD_RELOC_NONE:
       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;
 
          *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)
            {
        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;
              abort ();
            }
          break;
+#endif
 
        default:
          abort ();
        }
 
        default:
          abort ();
        }
-#else
-      *r_type_p = exp->X_md;
-#endif
       if (exp == main_exp)
        exp->X_op = O_symbol;
       else
       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"));
   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;
   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;
   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;
 
   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;
 
   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);
   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:
            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);
              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]);
   if (!target_big_endian)
     {
       output[1] = (nbuf[0] << 4) | (nbuf[1]);
@@ -3098,6 +3133,9 @@ enum options
   OPTION_PT32,
 #endif
   OPTION_H_TICK_HEX,
   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.  */
 };
 
   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  },
 
 #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);
   {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;
 
       enable_h_tick_hex = 1;
       break;
 
+#ifdef OBJ_ELF
+    case OPTION_FDPIC:
+      sh_fdpic = TRUE;
+      break;
+#endif /* OBJ_ELF */
+
     default:
       return 0;
     }
     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 */
 --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
 }
 \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
 {
   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_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;
       || ((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;
 
   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
 
 }
 #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:
       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_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;
       * 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:
       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
       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;
     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;
 
   else
     goto no_suffix;
 
index 1b5ec268965c11cecb163f676bd2979a2640f97c..2a6962720aeef9ebb46eb82b6f4cc690fd6e262c 100644 (file)
@@ -1,6 +1,6 @@
 /* This file is tc-sh.h
    Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 /* 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.
 
 
    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 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
 
 
 #define TC_KEEP_FX_OFFSET 1
 
@@ -155,7 +155,7 @@ extern void sh_frob_file (void);
 #ifdef OBJ_ELF
 /* ELF specific definitions.  */
 
 #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")
 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")
 #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
 #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 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_"
 
 
 #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))
 
 #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))
 
 #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 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
 
 /* All SH instructions are multiples of 16 bits.  */
 #define DWARF2_LINE_MIN_INSN_LENGTH 2
index 23d86623050e20967a64c1b34a448920b1fef0c0..77cbac1d81524ade2dece725732a8f4737d5f687 100644 (file)
@@ -360,7 +360,8 @@ case ${generic_target} in
       *)       endian=big ;;
     esac ;;
   sh*-*-symbianelf*)                   fmt=elf endian=little ;;
       *)       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 ;;
   sh-*-coff*)                          fmt=coff ;;
   sh-*-nto*)                           fmt=elf ;;
   sh-*-pe*)                            fmt=coff em=pe bfd_gas=yes endian=little ;;
index 00c95d7857364c4306cf7f1505fcfc2007df1590..619f02294b9210b8cd31230caa969805011f2eec 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
 @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.
 
 @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
 @item --isa=sh4 | sh4a
 Specify the sh4 or sh4a instruction set.
 @item --isa=dsp
index 59f98302d74da3836294a9bdb1c3edfedcfbacdf..5d2a4f33024a91b5f49e52eca8cea67a805851fd 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
 2010-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/11600
index 3bb7931d1f2c438d50ec8ddf745e81bf1c2ec327..2daa03821041b237d4f6882d8594ff332601a4f0 100644 (file)
@@ -142,7 +142,7 @@ if [istarget sh*-*-*] then {
        run_dump_test "pcrel2"
     }
 
        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"
        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 "sh4al-dsp"
 
            run_dump_test "sh2a"
+           run_dump_test "sh2a-pic"
        }
 
        run_dump_test "pic"
        }
 
        run_dump_test "pic"
+       run_dump_test "fdpic"
 
        # Test TLS.
        run_dump_test "tlsd"
 
        # 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 1821bbce3b2b6ff6df7216744876879880af6725..a42e8c4e858409c33cf4f0e44c26af960cdfb3e0 100644 (file)
@@ -1,10 +1,11 @@
 #objdump: -dr --prefix-addresses --show-raw-insn
 #objdump: -dr --prefix-addresses --show-raw-insn
-#as: --allow-reg-prefix -little
+#as: --allow-reg-prefix -big
 #name: SH --allow-reg-prefix option
 #name: SH --allow-reg-prefix option
+#skip: sh*-*-symbian*
 # Test SH register names prefixed with $:
 
 .*:     file format elf.*sh.*
 
 Disassembly of section .text:
 # 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 0506b9443954d1bb61958e78b16b35f9805b2a20..fd2f1791200861c9f298101dec171f1288fc9439 100644 (file)
@@ -289,6 +289,7 @@ proc is_elf_format {} {
         && ![istarget hppa*64*-*-hpux*] \
         && ![istarget *-*-linux*] \
         && ![istarget frv-*-uclinux*] \
         && ![istarget hppa*64*-*-hpux*] \
         && ![istarget *-*-linux*] \
         && ![istarget frv-*-uclinux*] \
+        && ![istarget sh*-*-uclinux*] \
         && ![istarget *-*-irix5*] \
         && ![istarget *-*-irix6*] \
         && ![istarget *-*-netbsd*] \
         && ![istarget *-*-irix5*] \
         && ![istarget *-*-irix6*] \
         && ![istarget *-*-netbsd*] \
index 9008aaabe313494067a5aba05bf54b9d92d2fca9..ddd927ae805f26ee15d9e52d1809505594e3d34a 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
 2010-05-18  H.J. Lu  <hongjiu.lu@intel.com>
 
        PR gas/11600
index fcb962ad504d30b962ab8e4d28209317580c1af9..c2bd50d2a87be17c9fde49840831e14a6b52d489 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);
 
 /* 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).  */
 
 /* 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)
   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)
   RELOC_NUMBER (R_SH_SHMEDIA_CODE, 242)
   RELOC_NUMBER (R_SH_PT_16, 243)
   RELOC_NUMBER (R_SH_IMMS16, 244)
index 973e817beba2678d953cf67dd6809c7f5dbdeaa6..9cd324a0d46f6515d00bdf513bbd684382486a6a 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
 2010-05-25  Jay Krell  <jay.krell@cornell.edu>
 
        PR ld/11621
index def02871975d2eb519f481a52efb08bf5db1db08..f75c96aa2efd66c2db8731f4ecb8f163ef34ac69 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="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
 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 95b6acc5d07f2396ecc7d8e70bb30a4b23616852..c14aae228d173337e120c37b7946978e449c6f67 100644 (file)
@@ -1,5 +1,5 @@
 # If you change this file, please also look at files which source this one:
 # 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"
 
 SCRIPT_NAME=elf
 OUTPUT_FORMAT="elf32-sh-linux"
index 61daf448410c193d57b68e02184e66c193880f72..4a3989e08d083fea6e2f759bf6ea7fc36d0bcf05 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
 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 335946babd2701c9473012f5c41d4192a2f98fff..f42a79fe6d0f9520284a809fce5232fe767d14dd 100644 (file)
@@ -122,7 +122,7 @@ if { [which $CC] == 0 } {
     return
 }
 
     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 {
     exec sed -e s/_main/main/ -e s/_trap/trap/ -e s/_stack/stack/ \
            < $srcdir/$subdir/start.s >tmpdir/start.s
 } else {
index 5b2e62b35c5c9e86afc584d3f5bfd839c0413f14..9e8b809f83359d03d48a047cd2895643b93b9186 100644 (file)
@@ -404,6 +404,7 @@ proc is_elf_format {} {
         && ![istarget *-*-linux*] \
         && ![istarget frv-*-uclinux*] \
         && ![istarget bfin-*-uclinux] \
         && ![istarget *-*-linux*] \
         && ![istarget frv-*-uclinux*] \
         && ![istarget bfin-*-uclinux] \
+        && ![istarget sh*-*-uclinux*] \
         && ![istarget *-*-irix5*] \
         && ![istarget *-*-irix6*] \
         && ![istarget *-*-netbsd*] \
         && ![istarget *-*-irix5*] \
         && ![istarget *-*-irix6*] \
         && ![istarget *-*-netbsd*] \
This page took 0.102669 seconds and 4 git commands to generate.