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