X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-sparc.c;h=30daedf73050e8bc8324c0cf8da780ff818d5e06;hb=f4e0d9f40b21fb42bbf7da07917683fb1cc16e8e;hp=8fa5305f805df128c3da89f3740e19237ac0c6cc;hpb=e459dc7b30e97b545ba146016bf15769b798b3d5;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-sparc.c b/bfd/elfxx-sparc.c index 8fa5305f80..30daedf730 100644 --- a/bfd/elfxx-sparc.c +++ b/bfd/elfxx-sparc.c @@ -1,11 +1,11 @@ /* SPARC-specific support for ELF - Copyright 2005 Free Software Foundation, Inc. + Copyright (C) 2005-2016 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -15,18 +15,24 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + /* This file handles functionality common to the different SPARC ABI's. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" +#include "libiberty.h" #include "elf-bfd.h" #include "elf/sparc.h" #include "opcode/sparc.h" #include "elfxx-sparc.h" +#include "elf-vxworks.h" +#include "objalloc.h" +#include "hashtab.h" /* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ #define MINUS_ONE (~ (bfd_vma) 0) @@ -46,7 +52,7 @@ static bfd_reloc_status_type init_insn_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - PTR data, asection *input_section, bfd *output_bfd, + void * data, asection *input_section, bfd *output_bfd, bfd_vma *prelocation, bfd_vma *pinsn) { bfd_vma relocation; @@ -90,7 +96,7 @@ static bfd_reloc_status_type sparc_elf_notsup_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry ATTRIBUTE_UNUSED, asymbol *symbol ATTRIBUTE_UNUSED, - PTR data ATTRIBUTE_UNUSED, + void * data ATTRIBUTE_UNUSED, asection *input_section ATTRIBUTE_UNUSED, bfd *output_bfd ATTRIBUTE_UNUSED, char **error_message ATTRIBUTE_UNUSED) @@ -102,7 +108,7 @@ sparc_elf_notsup_reloc (bfd *abfd ATTRIBUTE_UNUSED, static bfd_reloc_status_type sparc_elf_wdisp16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - PTR data, asection *input_section, bfd *output_bfd, + void * data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { bfd_vma relocation; @@ -125,11 +131,39 @@ sparc_elf_wdisp16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, return bfd_reloc_ok; } +/* Handle the WDISP10 reloc. */ + +static bfd_reloc_status_type +sparc_elf_wdisp10_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void * data, asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_vma relocation; + bfd_vma insn; + bfd_reloc_status_type status; + + status = init_insn_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, &relocation, &insn); + if (status != bfd_reloc_other) + return status; + + insn &= ~ (bfd_vma) 0x181fe0; + insn |= (((relocation >> 2) & 0x300) << 11) + | (((relocation >> 2) & 0xff) << 5); + bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); + + if ((bfd_signed_vma) relocation < - 0x1000 + || (bfd_signed_vma) relocation > 0xfff) + return bfd_reloc_overflow; + else + return bfd_reloc_ok; +} + /* Handle the HIX22 reloc. */ static bfd_reloc_status_type sparc_elf_hix22_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - PTR data, asection *input_section, bfd *output_bfd, + void * data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { bfd_vma relocation; @@ -155,7 +189,7 @@ sparc_elf_hix22_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, static bfd_reloc_status_type sparc_elf_lox10_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, - PTR data, asection *input_section, bfd *output_bfd, + void * data, asection *input_section, bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED) { bfd_vma relocation; @@ -175,7 +209,7 @@ sparc_elf_lox10_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, static reloc_howto_type _bfd_sparc_elf_howto_table[] = { - HOWTO(R_SPARC_NONE, 0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", FALSE,0,0x00000000,TRUE), + HOWTO(R_SPARC_NONE, 0,3, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_NONE", FALSE,0,0x00000000,TRUE), HOWTO(R_SPARC_8, 0,0, 8,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_8", FALSE,0,0x000000ff,TRUE), HOWTO(R_SPARC_16, 0,1,16,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_16", FALSE,0,0x0000ffff,TRUE), HOWTO(R_SPARC_32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_32", FALSE,0,0xffffffff,TRUE), @@ -254,8 +288,21 @@ static reloc_howto_type _bfd_sparc_elf_howto_table[] = HOWTO(R_SPARC_TLS_DTPOFF32,0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF32",FALSE,0,0xffffffff,TRUE), HOWTO(R_SPARC_TLS_DTPOFF64,0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_TLS_DTPOFF64",FALSE,0,MINUS_ONE,TRUE), HOWTO(R_SPARC_TLS_TPOFF32,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF32",FALSE,0,0x00000000,TRUE), - HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE) + HOWTO(R_SPARC_TLS_TPOFF64,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_TLS_TPOFF64",FALSE,0,0x00000000,TRUE), + HOWTO(R_SPARC_GOTDATA_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_HIX22",FALSE,0,0x003fffff, FALSE), + HOWTO(R_SPARC_GOTDATA_LOX10,0,2,0,FALSE,0,complain_overflow_dont, sparc_elf_lox10_reloc, "R_SPARC_GOTDATA_LOX10",FALSE,0,0x000003ff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP_HIX22,0,2,0,FALSE,0,complain_overflow_bitfield,sparc_elf_hix22_reloc,"R_SPARC_GOTDATA_OP_HIX22",FALSE,0,0x003fffff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP_LOX10,0,2,0,FALSE,0,complain_overflow_dont, sparc_elf_lox10_reloc, "R_SPARC_GOTDATA_OP_LOX10",FALSE,0,0x000003ff, FALSE), + HOWTO(R_SPARC_GOTDATA_OP,0,0, 0,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_GOTDATA_OP",FALSE,0,0x00000000,TRUE), + HOWTO(R_SPARC_H34,12,2,22,FALSE,0,complain_overflow_unsigned,bfd_elf_generic_reloc,"R_SPARC_H34",FALSE,0,0x003fffff,FALSE), + HOWTO(R_SPARC_SIZE32,0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_SIZE32",FALSE,0,0xffffffff,TRUE), + HOWTO(R_SPARC_SIZE64,0,4,64,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc,"R_SPARC_SIZE64",FALSE,0,MINUS_ONE, TRUE), + HOWTO(R_SPARC_WDISP10,2,2,10,TRUE, 0,complain_overflow_signed,sparc_elf_wdisp10_reloc,"R_SPARC_WDISP10",FALSE,0,0x00000000,TRUE), }; +static reloc_howto_type sparc_jmp_irel_howto = + HOWTO(R_SPARC_JMP_IREL, 0,0,00,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_JMP_IREL",FALSE,0,0x00000000,TRUE); +static reloc_howto_type sparc_irelative_howto = + HOWTO(R_SPARC_IRELATIVE, 0,0,00,FALSE,0,complain_overflow_dont, bfd_elf_generic_reloc, "R_SPARC_IRELATIVE",FALSE,0,0x00000000,TRUE); static reloc_howto_type sparc_vtinherit_howto = HOWTO (R_SPARC_GNU_VTINHERIT, 0,2,0,FALSE,0,complain_overflow_dont, NULL, "R_SPARC_GNU_VTINHERIT", FALSE,0, 0, FALSE); static reloc_howto_type sparc_vtentry_howto = @@ -263,102 +310,269 @@ static reloc_howto_type sparc_vtentry_howto = static reloc_howto_type sparc_rev32_howto = HOWTO(R_SPARC_REV32, 0,2,32,FALSE,0,complain_overflow_bitfield,bfd_elf_generic_reloc, "R_SPARC_REV32", FALSE,0,0xffffffff,TRUE); -struct elf_reloc_map { - bfd_reloc_code_real_type bfd_reloc_val; - unsigned char elf_reloc_val; -}; - -static const struct elf_reloc_map sparc_reloc_map[] = -{ - { BFD_RELOC_NONE, R_SPARC_NONE, }, - { BFD_RELOC_16, R_SPARC_16, }, - { BFD_RELOC_16_PCREL, R_SPARC_DISP16 }, - { BFD_RELOC_8, R_SPARC_8 }, - { BFD_RELOC_8_PCREL, R_SPARC_DISP8 }, - { BFD_RELOC_CTOR, R_SPARC_64 }, - { BFD_RELOC_32, R_SPARC_32 }, - { BFD_RELOC_32_PCREL, R_SPARC_DISP32 }, - { BFD_RELOC_HI22, R_SPARC_HI22 }, - { BFD_RELOC_LO10, R_SPARC_LO10, }, - { BFD_RELOC_32_PCREL_S2, R_SPARC_WDISP30 }, - { BFD_RELOC_64_PCREL, R_SPARC_DISP64 }, - { BFD_RELOC_SPARC22, R_SPARC_22 }, - { BFD_RELOC_SPARC13, R_SPARC_13 }, - { BFD_RELOC_SPARC_GOT10, R_SPARC_GOT10 }, - { BFD_RELOC_SPARC_GOT13, R_SPARC_GOT13 }, - { BFD_RELOC_SPARC_GOT22, R_SPARC_GOT22 }, - { BFD_RELOC_SPARC_PC10, R_SPARC_PC10 }, - { BFD_RELOC_SPARC_PC22, R_SPARC_PC22 }, - { BFD_RELOC_SPARC_WPLT30, R_SPARC_WPLT30 }, - { BFD_RELOC_SPARC_COPY, R_SPARC_COPY }, - { BFD_RELOC_SPARC_GLOB_DAT, R_SPARC_GLOB_DAT }, - { BFD_RELOC_SPARC_JMP_SLOT, R_SPARC_JMP_SLOT }, - { BFD_RELOC_SPARC_RELATIVE, R_SPARC_RELATIVE }, - { BFD_RELOC_SPARC_WDISP22, R_SPARC_WDISP22 }, - { BFD_RELOC_SPARC_UA16, R_SPARC_UA16 }, - { BFD_RELOC_SPARC_UA32, R_SPARC_UA32 }, - { BFD_RELOC_SPARC_UA64, R_SPARC_UA64 }, - { BFD_RELOC_SPARC_10, R_SPARC_10 }, - { BFD_RELOC_SPARC_11, R_SPARC_11 }, - { BFD_RELOC_SPARC_64, R_SPARC_64 }, - { BFD_RELOC_SPARC_OLO10, R_SPARC_OLO10 }, - { BFD_RELOC_SPARC_HH22, R_SPARC_HH22 }, - { BFD_RELOC_SPARC_HM10, R_SPARC_HM10 }, - { BFD_RELOC_SPARC_LM22, R_SPARC_LM22 }, - { BFD_RELOC_SPARC_PC_HH22, R_SPARC_PC_HH22 }, - { BFD_RELOC_SPARC_PC_HM10, R_SPARC_PC_HM10 }, - { BFD_RELOC_SPARC_PC_LM22, R_SPARC_PC_LM22 }, - { BFD_RELOC_SPARC_WDISP16, R_SPARC_WDISP16 }, - { BFD_RELOC_SPARC_WDISP19, R_SPARC_WDISP19 }, - { BFD_RELOC_SPARC_7, R_SPARC_7 }, - { BFD_RELOC_SPARC_5, R_SPARC_5 }, - { BFD_RELOC_SPARC_6, R_SPARC_6 }, - { BFD_RELOC_SPARC_DISP64, R_SPARC_DISP64 }, - { BFD_RELOC_SPARC_TLS_GD_HI22, R_SPARC_TLS_GD_HI22 }, - { BFD_RELOC_SPARC_TLS_GD_LO10, R_SPARC_TLS_GD_LO10 }, - { BFD_RELOC_SPARC_TLS_GD_ADD, R_SPARC_TLS_GD_ADD }, - { BFD_RELOC_SPARC_TLS_GD_CALL, R_SPARC_TLS_GD_CALL }, - { BFD_RELOC_SPARC_TLS_LDM_HI22, R_SPARC_TLS_LDM_HI22 }, - { BFD_RELOC_SPARC_TLS_LDM_LO10, R_SPARC_TLS_LDM_LO10 }, - { BFD_RELOC_SPARC_TLS_LDM_ADD, R_SPARC_TLS_LDM_ADD }, - { BFD_RELOC_SPARC_TLS_LDM_CALL, R_SPARC_TLS_LDM_CALL }, - { BFD_RELOC_SPARC_TLS_LDO_HIX22, R_SPARC_TLS_LDO_HIX22 }, - { BFD_RELOC_SPARC_TLS_LDO_LOX10, R_SPARC_TLS_LDO_LOX10 }, - { BFD_RELOC_SPARC_TLS_LDO_ADD, R_SPARC_TLS_LDO_ADD }, - { BFD_RELOC_SPARC_TLS_IE_HI22, R_SPARC_TLS_IE_HI22 }, - { BFD_RELOC_SPARC_TLS_IE_LO10, R_SPARC_TLS_IE_LO10 }, - { BFD_RELOC_SPARC_TLS_IE_LD, R_SPARC_TLS_IE_LD }, - { BFD_RELOC_SPARC_TLS_IE_LDX, R_SPARC_TLS_IE_LDX }, - { BFD_RELOC_SPARC_TLS_IE_ADD, R_SPARC_TLS_IE_ADD }, - { BFD_RELOC_SPARC_TLS_LE_HIX22, R_SPARC_TLS_LE_HIX22 }, - { BFD_RELOC_SPARC_TLS_LE_LOX10, R_SPARC_TLS_LE_LOX10 }, - { BFD_RELOC_SPARC_TLS_DTPMOD32, R_SPARC_TLS_DTPMOD32 }, - { BFD_RELOC_SPARC_TLS_DTPMOD64, R_SPARC_TLS_DTPMOD64 }, - { BFD_RELOC_SPARC_TLS_DTPOFF32, R_SPARC_TLS_DTPOFF32 }, - { BFD_RELOC_SPARC_TLS_DTPOFF64, R_SPARC_TLS_DTPOFF64 }, - { BFD_RELOC_SPARC_TLS_TPOFF32, R_SPARC_TLS_TPOFF32 }, - { BFD_RELOC_SPARC_TLS_TPOFF64, R_SPARC_TLS_TPOFF64 }, - { BFD_RELOC_SPARC_PLT32, R_SPARC_PLT32 }, - { BFD_RELOC_SPARC_PLT64, R_SPARC_PLT64 }, - { BFD_RELOC_SPARC_HIX22, R_SPARC_HIX22 }, - { BFD_RELOC_SPARC_LOX10, R_SPARC_LOX10 }, - { BFD_RELOC_SPARC_H44, R_SPARC_H44 }, - { BFD_RELOC_SPARC_M44, R_SPARC_M44 }, - { BFD_RELOC_SPARC_L44, R_SPARC_L44 }, - { BFD_RELOC_SPARC_REGISTER, R_SPARC_REGISTER }, - { BFD_RELOC_VTABLE_INHERIT, R_SPARC_GNU_VTINHERIT }, - { BFD_RELOC_VTABLE_ENTRY, R_SPARC_GNU_VTENTRY }, - { BFD_RELOC_SPARC_REV32, R_SPARC_REV32 }, -}; - reloc_howto_type * _bfd_sparc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, bfd_reloc_code_real_type code) { - unsigned int i; - + /* We explicitly handle each relocation type in the switch + instead of using a lookup table for efficiency. */ switch (code) { + case BFD_RELOC_NONE: + return &_bfd_sparc_elf_howto_table[R_SPARC_NONE]; + + case BFD_RELOC_8: + return &_bfd_sparc_elf_howto_table[R_SPARC_8]; + + case BFD_RELOC_16: + return &_bfd_sparc_elf_howto_table[R_SPARC_16]; + + case BFD_RELOC_32: + return &_bfd_sparc_elf_howto_table[R_SPARC_32]; + + case BFD_RELOC_8_PCREL: + return &_bfd_sparc_elf_howto_table[R_SPARC_DISP8]; + + case BFD_RELOC_16_PCREL: + return &_bfd_sparc_elf_howto_table[R_SPARC_DISP16]; + + case BFD_RELOC_32_PCREL: + return &_bfd_sparc_elf_howto_table[R_SPARC_DISP32]; + + case BFD_RELOC_32_PCREL_S2: + return &_bfd_sparc_elf_howto_table[R_SPARC_WDISP30]; + + case BFD_RELOC_SPARC_WDISP22: + return &_bfd_sparc_elf_howto_table[R_SPARC_WDISP22]; + + case BFD_RELOC_HI22: + return &_bfd_sparc_elf_howto_table[R_SPARC_HI22]; + + case BFD_RELOC_SPARC22: + return &_bfd_sparc_elf_howto_table[R_SPARC_22]; + + case BFD_RELOC_SPARC13: + return &_bfd_sparc_elf_howto_table[R_SPARC_13]; + + case BFD_RELOC_LO10: + return &_bfd_sparc_elf_howto_table[R_SPARC_LO10]; + + case BFD_RELOC_SPARC_GOT10: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOT10]; + + case BFD_RELOC_SPARC_GOT13: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOT13]; + + case BFD_RELOC_SPARC_GOT22: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOT22]; + + case BFD_RELOC_SPARC_PC10: + return &_bfd_sparc_elf_howto_table[R_SPARC_PC10]; + + case BFD_RELOC_SPARC_PC22: + return &_bfd_sparc_elf_howto_table[R_SPARC_PC22]; + + case BFD_RELOC_SPARC_WPLT30: + return &_bfd_sparc_elf_howto_table[R_SPARC_WPLT30]; + + case BFD_RELOC_SPARC_COPY: + return &_bfd_sparc_elf_howto_table[R_SPARC_COPY]; + + case BFD_RELOC_SPARC_GLOB_DAT: + return &_bfd_sparc_elf_howto_table[R_SPARC_GLOB_DAT]; + + case BFD_RELOC_SPARC_JMP_SLOT: + return &_bfd_sparc_elf_howto_table[R_SPARC_JMP_SLOT]; + + case BFD_RELOC_SPARC_RELATIVE: + return &_bfd_sparc_elf_howto_table[R_SPARC_RELATIVE]; + + case BFD_RELOC_SPARC_UA32: + return &_bfd_sparc_elf_howto_table[R_SPARC_UA32]; + + case BFD_RELOC_SPARC_PLT32: + return &_bfd_sparc_elf_howto_table[R_SPARC_PLT32]; + + case BFD_RELOC_SPARC_10: + return &_bfd_sparc_elf_howto_table[R_SPARC_10]; + + case BFD_RELOC_SPARC_11: + return &_bfd_sparc_elf_howto_table[R_SPARC_11]; + + case BFD_RELOC_SPARC_64: + return &_bfd_sparc_elf_howto_table[R_SPARC_64]; + + case BFD_RELOC_SPARC_OLO10: + return &_bfd_sparc_elf_howto_table[R_SPARC_OLO10]; + + case BFD_RELOC_SPARC_HH22: + return &_bfd_sparc_elf_howto_table[R_SPARC_HH22]; + + case BFD_RELOC_SPARC_HM10: + return &_bfd_sparc_elf_howto_table[R_SPARC_HM10]; + + case BFD_RELOC_SPARC_LM22: + return &_bfd_sparc_elf_howto_table[R_SPARC_LM22]; + + case BFD_RELOC_SPARC_PC_HH22: + return &_bfd_sparc_elf_howto_table[R_SPARC_PC_HH22]; + + case BFD_RELOC_SPARC_PC_HM10: + return &_bfd_sparc_elf_howto_table[R_SPARC_PC_HM10]; + + case BFD_RELOC_SPARC_PC_LM22: + return &_bfd_sparc_elf_howto_table[R_SPARC_PC_LM22]; + + case BFD_RELOC_SPARC_WDISP16: + return &_bfd_sparc_elf_howto_table[R_SPARC_WDISP16]; + + case BFD_RELOC_SPARC_WDISP19: + return &_bfd_sparc_elf_howto_table[R_SPARC_WDISP19]; + + case BFD_RELOC_SPARC_7: + return &_bfd_sparc_elf_howto_table[R_SPARC_7]; + + case BFD_RELOC_SPARC_5: + return &_bfd_sparc_elf_howto_table[R_SPARC_5]; + + case BFD_RELOC_SPARC_6: + return &_bfd_sparc_elf_howto_table[R_SPARC_6]; + + case BFD_RELOC_SPARC_DISP64: + return &_bfd_sparc_elf_howto_table[R_SPARC_DISP64]; + + case BFD_RELOC_SPARC_PLT64: + return &_bfd_sparc_elf_howto_table[R_SPARC_PLT64]; + + case BFD_RELOC_SPARC_HIX22: + return &_bfd_sparc_elf_howto_table[R_SPARC_HIX22]; + + case BFD_RELOC_SPARC_LOX10: + return &_bfd_sparc_elf_howto_table[R_SPARC_LOX10]; + + case BFD_RELOC_SPARC_H44: + return &_bfd_sparc_elf_howto_table[R_SPARC_H44]; + + case BFD_RELOC_SPARC_M44: + return &_bfd_sparc_elf_howto_table[R_SPARC_M44]; + + case BFD_RELOC_SPARC_L44: + return &_bfd_sparc_elf_howto_table[R_SPARC_L44]; + + case BFD_RELOC_SPARC_REGISTER: + return &_bfd_sparc_elf_howto_table[R_SPARC_REGISTER]; + + case BFD_RELOC_SPARC_UA64: + return &_bfd_sparc_elf_howto_table[R_SPARC_UA64]; + + case BFD_RELOC_SPARC_UA16: + return &_bfd_sparc_elf_howto_table[R_SPARC_UA16]; + + case BFD_RELOC_SPARC_TLS_GD_HI22: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_GD_HI22]; + + case BFD_RELOC_SPARC_TLS_GD_LO10: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_GD_LO10]; + + case BFD_RELOC_SPARC_TLS_GD_ADD: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_GD_ADD]; + + case BFD_RELOC_SPARC_TLS_GD_CALL: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_GD_CALL]; + + case BFD_RELOC_SPARC_TLS_LDM_HI22: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDM_HI22]; + + case BFD_RELOC_SPARC_TLS_LDM_LO10: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDM_LO10]; + + case BFD_RELOC_SPARC_TLS_LDM_ADD: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDM_ADD]; + + case BFD_RELOC_SPARC_TLS_LDM_CALL: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDM_CALL]; + + case BFD_RELOC_SPARC_TLS_LDO_HIX22: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDO_HIX22]; + + case BFD_RELOC_SPARC_TLS_LDO_LOX10: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDO_LOX10]; + + case BFD_RELOC_SPARC_TLS_LDO_ADD: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LDO_ADD]; + + case BFD_RELOC_SPARC_TLS_IE_HI22: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_IE_HI22]; + + case BFD_RELOC_SPARC_TLS_IE_LO10: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_IE_LO10]; + + case BFD_RELOC_SPARC_TLS_IE_LD: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_IE_LD]; + + case BFD_RELOC_SPARC_TLS_IE_LDX: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_IE_LDX]; + + case BFD_RELOC_SPARC_TLS_IE_ADD: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_IE_ADD]; + + case BFD_RELOC_SPARC_TLS_LE_HIX22: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LE_HIX22]; + + case BFD_RELOC_SPARC_TLS_LE_LOX10: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_LE_LOX10]; + + case BFD_RELOC_SPARC_TLS_DTPMOD32: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_DTPMOD32]; + + case BFD_RELOC_SPARC_TLS_DTPMOD64: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_DTPMOD64]; + + case BFD_RELOC_SPARC_TLS_DTPOFF32: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_DTPOFF32]; + + case BFD_RELOC_SPARC_TLS_DTPOFF64: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_DTPOFF64]; + + case BFD_RELOC_SPARC_TLS_TPOFF32: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_TPOFF32]; + + case BFD_RELOC_SPARC_TLS_TPOFF64: + return &_bfd_sparc_elf_howto_table[R_SPARC_TLS_TPOFF64]; + + case BFD_RELOC_SPARC_GOTDATA_HIX22: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOTDATA_HIX22]; + + case BFD_RELOC_SPARC_GOTDATA_LOX10: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOTDATA_LOX10]; + + case BFD_RELOC_SPARC_GOTDATA_OP_HIX22: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOTDATA_OP_HIX22]; + + case BFD_RELOC_SPARC_GOTDATA_OP_LOX10: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOTDATA_OP_LOX10]; + + case BFD_RELOC_SPARC_GOTDATA_OP: + return &_bfd_sparc_elf_howto_table[R_SPARC_GOTDATA_OP]; + + case BFD_RELOC_SPARC_H34: + return &_bfd_sparc_elf_howto_table[R_SPARC_H34]; + + case BFD_RELOC_SPARC_SIZE32: + return &_bfd_sparc_elf_howto_table[R_SPARC_SIZE32]; + + case BFD_RELOC_SPARC_SIZE64: + return &_bfd_sparc_elf_howto_table[R_SPARC_SIZE64]; + + case BFD_RELOC_SPARC_WDISP10: + return &_bfd_sparc_elf_howto_table[R_SPARC_WDISP10]; + + case BFD_RELOC_SPARC_JMP_IREL: + return &sparc_jmp_irel_howto; + + case BFD_RELOC_SPARC_IRELATIVE: + return &sparc_irelative_howto; + case BFD_RELOC_VTABLE_INHERIT: return &sparc_vtinherit_howto; @@ -369,24 +583,47 @@ _bfd_sparc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, return &sparc_rev32_howto; default: - for (i = 0; - i < sizeof (sparc_reloc_map) / sizeof (struct elf_reloc_map); - i++) - { - if (sparc_reloc_map[i].bfd_reloc_val == code) - return (_bfd_sparc_elf_howto_table - + (int) sparc_reloc_map[i].elf_reloc_val); - } + break; } bfd_set_error (bfd_error_bad_value); return NULL; } +reloc_howto_type * +_bfd_sparc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < (sizeof (_bfd_sparc_elf_howto_table) + / sizeof (_bfd_sparc_elf_howto_table[0])); + i++) + if (_bfd_sparc_elf_howto_table[i].name != NULL + && strcasecmp (_bfd_sparc_elf_howto_table[i].name, r_name) == 0) + return &_bfd_sparc_elf_howto_table[i]; + + if (strcasecmp (sparc_vtinherit_howto.name, r_name) == 0) + return &sparc_vtinherit_howto; + if (strcasecmp (sparc_vtentry_howto.name, r_name) == 0) + return &sparc_vtentry_howto; + if (strcasecmp (sparc_rev32_howto.name, r_name) == 0) + return &sparc_rev32_howto; + + return NULL; +} + reloc_howto_type * _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type) { switch (r_type) { + case R_SPARC_JMP_IREL: + return &sparc_jmp_irel_howto; + + case R_SPARC_IRELATIVE: + return &sparc_irelative_howto; + case R_SPARC_GNU_VTINHERIT: return &sparc_vtinherit_howto; @@ -397,7 +634,12 @@ _bfd_sparc_elf_info_to_howto_ptr (unsigned int r_type) return &sparc_rev32_howto; default: - BFD_ASSERT (r_type < (unsigned int) R_SPARC_max_std); + if (r_type >= (unsigned int) R_SPARC_max_std) + { + (*_bfd_error_handler) (_("invalid relocation type %d"), + (int) r_type); + r_type = R_SPARC_NONE; + } return &_bfd_sparc_elf_howto_table[r_type]; } } @@ -477,58 +719,47 @@ struct _bfd_sparc_elf_obj_tdata #define _bfd_sparc_elf_local_got_tls_type(abfd) \ (_bfd_sparc_elf_tdata (abfd)->local_got_tls_type) +#define is_sparc_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == SPARC_ELF_DATA) + bfd_boolean _bfd_sparc_elf_mkobject (bfd *abfd) { - bfd_size_type amt = sizeof (struct _bfd_sparc_elf_obj_tdata); - abfd->tdata.any = bfd_zalloc (abfd, amt); - if (abfd->tdata.any == NULL) - return FALSE; - return TRUE; + return bfd_elf_allocate_object (abfd, sizeof (struct _bfd_sparc_elf_obj_tdata), + SPARC_ELF_DATA); } static void -sparc_put_word_32 (bfd *bfd, bfd_vma val, void *ptr) +sparc_put_word_32 (bfd *abfd, bfd_vma val, void *ptr) { - bfd_put_32 (bfd, val, ptr); + bfd_put_32 (abfd, val, ptr); } static void -sparc_put_word_64 (bfd *bfd, bfd_vma val, void *ptr) +sparc_put_word_64 (bfd *abfd, bfd_vma val, void *ptr) { - bfd_put_64 (bfd, val, ptr); + bfd_put_64 (abfd, val, ptr); } static void -sparc_elf_append_rela_64 (bfd *abfd ATTRIBUTE_UNUSED, - asection *s ATTRIBUTE_UNUSED, - Elf_Internal_Rela *rel ATTRIBUTE_UNUSED) +sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel) { -#ifdef BFD64 - Elf64_External_Rela *loc64; + const struct elf_backend_data *bed; + bfd_byte *loc; - loc64 = (Elf64_External_Rela *) s->contents; - loc64 += s->reloc_count++; - bfd_elf64_swap_reloca_out (abfd, rel, (bfd_byte *) loc64); -#endif -} - -static void -sparc_elf_append_rela_32 (bfd *abfd, asection *s, Elf_Internal_Rela *rel) -{ - Elf32_External_Rela *loc32; - - loc32 = (Elf32_External_Rela *) s->contents; - loc32 += s->reloc_count++; - bfd_elf32_swap_reloca_out (abfd, rel, (bfd_byte *) loc32); + bed = get_elf_backend_data (abfd); + loc = s->contents + (s->reloc_count++ * bed->s->sizeof_rela); + bed->s->swap_reloca_out (abfd, rel, loc); } static bfd_vma sparc_elf_r_info_64 (Elf_Internal_Rela *in_rel ATTRIBUTE_UNUSED, - bfd_vma index ATTRIBUTE_UNUSED, + bfd_vma rel_index ATTRIBUTE_UNUSED, bfd_vma type ATTRIBUTE_UNUSED) { - return ELF64_R_INFO (index, + return ELF64_R_INFO (rel_index, (in_rel ? ELF64_R_TYPE_INFO (ELF64_R_TYPE_DATA (in_rel->r_info), type) : type)); @@ -536,9 +767,9 @@ sparc_elf_r_info_64 (Elf_Internal_Rela *in_rel ATTRIBUTE_UNUSED, static bfd_vma sparc_elf_r_info_32 (Elf_Internal_Rela *in_rel ATTRIBUTE_UNUSED, - bfd_vma index, bfd_vma type) + bfd_vma rel_index, bfd_vma type) { - return ELF32_R_INFO (index, type); + return ELF32_R_INFO (rel_index, type); } static bfd_vma @@ -602,7 +833,7 @@ sparc64_plt_entry_build (bfd *output_bfd, asection *splt, bfd_vma offset, { unsigned char *entry = splt->contents + offset; const unsigned int nop = SPARC_NOP; - int index; + int plt_index; if (offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE)) { @@ -610,9 +841,9 @@ sparc64_plt_entry_build (bfd *output_bfd, asection *splt, bfd_vma offset, *r_offset = offset; - index = (offset / PLT64_ENTRY_SIZE); + plt_index = (offset / PLT64_ENTRY_SIZE); - sethi = 0x03000000 | (index * PLT64_ENTRY_SIZE); + sethi = 0x03000000 | (plt_index * PLT64_ENTRY_SIZE); ba = 0x30680000 | (((splt->contents + PLT64_ENTRY_SIZE) - (entry + 4)) / 4 & 0x7ffff); @@ -659,7 +890,7 @@ sparc64_plt_entry_build (bfd *output_bfd, asection *splt, bfd_vma offset, ofs = offset % block_size; - index = (PLT64_LARGE_THRESHOLD + + plt_index = (PLT64_LARGE_THRESHOLD + (block * 160) + (ofs / insn_chunk_size)); @@ -689,15 +920,56 @@ sparc64_plt_entry_build (bfd *output_bfd, asection *splt, bfd_vma offset, bfd_put_64 (output_bfd, (bfd_vma) (splt->contents - (entry + 4)), ptr); } - return index - 4; + return plt_index - 4; } +/* The format of the first PLT entry in a VxWorks executable. */ +static const bfd_vma sparc_vxworks_exec_plt0_entry[] = + { + 0x05000000, /* sethi %hi(_GLOBAL_OFFSET_TABLE_+8), %g2 */ + 0x8410a000, /* or %g2, %lo(_GLOBAL_OFFSET_TABLE_+8), %g2 */ + 0xc4008000, /* ld [ %g2 ], %g2 */ + 0x81c08000, /* jmp %g2 */ + 0x01000000 /* nop */ + }; + +/* The format of subsequent PLT entries. */ +static const bfd_vma sparc_vxworks_exec_plt_entry[] = + { + 0x03000000, /* sethi %hi(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */ + 0x82106000, /* or %g1, %lo(_GLOBAL_OFFSET_TABLE_+f@got), %g1 */ + 0xc2004000, /* ld [ %g1 ], %g1 */ + 0x81c04000, /* jmp %g1 */ + 0x01000000, /* nop */ + 0x03000000, /* sethi %hi(f@pltindex), %g1 */ + 0x10800000, /* b _PLT_resolve */ + 0x82106000 /* or %g1, %lo(f@pltindex), %g1 */ + }; + +/* The format of the first PLT entry in a VxWorks shared object. */ +static const bfd_vma sparc_vxworks_shared_plt0_entry[] = + { + 0xc405e008, /* ld [ %l7 + 8 ], %g2 */ + 0x81c08000, /* jmp %g2 */ + 0x01000000 /* nop */ + }; + +/* The format of subsequent PLT entries. */ +static const bfd_vma sparc_vxworks_shared_plt_entry[] = + { + 0x03000000, /* sethi %hi(f@got), %g1 */ + 0x82106000, /* or %g1, %lo(f@got), %g1 */ + 0xc205c001, /* ld [ %l7 + %g1 ], %g1 */ + 0x81c04000, /* jmp %g1 */ + 0x01000000, /* nop */ + 0x03000000, /* sethi %hi(f@pltindex), %g1 */ + 0x10800000, /* b _PLT_resolve */ + 0x82106000 /* or %g1, %lo(f@pltindex), %g1 */ + }; + #define SPARC_ELF_PUT_WORD(htab, bfd, val, ptr) \ htab->put_word(bfd, val, ptr) -#define SPARC_ELF_APPEND_RELA(htab, bfd, sec, rela) \ - htab->append_rela(bfd, sec, rela) - #define SPARC_ELF_R_INFO(htab, in_rel, index, type) \ htab->r_info(in_rel, index, type) @@ -758,6 +1030,93 @@ link_hash_newfunc (struct bfd_hash_entry *entry, #define ELF32_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" #define ELF64_DYNAMIC_INTERPRETER "/usr/lib/sparcv9/ld.so.1" +/* Compute a hash of a local hash entry. We use elf_link_hash_entry + for local symbol so that we can handle local STT_GNU_IFUNC symbols + as global symbol. We reuse indx and dynstr_index for local symbol + hash since they aren't used by global symbols in this backend. */ + +static hashval_t +elf_sparc_local_htab_hash (const void *ptr) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) ptr; + return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); +} + +/* Compare local hash entries. */ + +static int +elf_sparc_local_htab_eq (const void *ptr1, const void *ptr2) +{ + struct elf_link_hash_entry *h1 + = (struct elf_link_hash_entry *) ptr1; + struct elf_link_hash_entry *h2 + = (struct elf_link_hash_entry *) ptr2; + + return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; +} + +/* Find and/or create a hash entry for local symbol. */ + +static struct elf_link_hash_entry * +elf_sparc_get_local_sym_hash (struct _bfd_sparc_elf_link_hash_table *htab, + bfd *abfd, const Elf_Internal_Rela *rel, + bfd_boolean create) +{ + struct _bfd_sparc_elf_link_hash_entry e, *ret; + asection *sec = abfd->sections; + unsigned long r_symndx; + hashval_t h; + void **slot; + + r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info); + h = ELF_LOCAL_SYMBOL_HASH (sec->id, r_symndx); + + e.elf.indx = sec->id; + e.elf.dynstr_index = r_symndx; + slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, + create ? INSERT : NO_INSERT); + + if (!slot) + return NULL; + + if (*slot) + { + ret = (struct _bfd_sparc_elf_link_hash_entry *) *slot; + return &ret->elf; + } + + ret = (struct _bfd_sparc_elf_link_hash_entry *) + objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, + sizeof (struct _bfd_sparc_elf_link_hash_entry)); + if (ret) + { + memset (ret, 0, sizeof (*ret)); + ret->elf.indx = sec->id; + ret->elf.dynstr_index = r_symndx; + ret->elf.dynindx = -1; + ret->elf.plt.offset = (bfd_vma) -1; + ret->elf.got.offset = (bfd_vma) -1; + *slot = ret; + } + return &ret->elf; +} + +/* Destroy a SPARC ELF linker hash table. */ + +static void +_bfd_sparc_elf_link_hash_table_free (bfd *obfd) +{ + struct _bfd_sparc_elf_link_hash_table *htab + = (struct _bfd_sparc_elf_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + /* Create a SPARC ELF linker hash table. */ struct bfd_link_hash_table * @@ -773,10 +1132,8 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd) if (ABI_64_P (abfd)) { ret->put_word = sparc_put_word_64; - ret->append_rela = sparc_elf_append_rela_64; ret->r_info = sparc_elf_r_info_64; ret->r_symndx = sparc_elf_r_symndx_64; - ret->build_plt_entry = sparc64_plt_entry_build; ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF64; ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD64; ret->tpoff_reloc = R_SPARC_TLS_TPOFF64; @@ -786,14 +1143,16 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd) ret->bytes_per_rela = sizeof (Elf64_External_Rela); ret->dynamic_interpreter = ELF64_DYNAMIC_INTERPRETER; ret->dynamic_interpreter_size = sizeof ELF64_DYNAMIC_INTERPRETER; + + ret->build_plt_entry = sparc64_plt_entry_build; + ret->plt_header_size = PLT64_HEADER_SIZE; + ret->plt_entry_size = PLT64_ENTRY_SIZE; } else { ret->put_word = sparc_put_word_32; - ret->append_rela = sparc_elf_append_rela_32; ret->r_info = sparc_elf_r_info_32; ret->r_symndx = sparc_elf_r_symndx_32; - ret->build_plt_entry = sparc32_plt_entry_build; ret->dtpoff_reloc = R_SPARC_TLS_DTPOFF32; ret->dtpmod_reloc = R_SPARC_TLS_DTPMOD32; ret->tpoff_reloc = R_SPARC_TLS_TPOFF32; @@ -803,44 +1162,33 @@ _bfd_sparc_elf_link_hash_table_create (bfd *abfd) ret->bytes_per_rela = sizeof (Elf32_External_Rela); ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER; ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER; + + ret->build_plt_entry = sparc32_plt_entry_build; + ret->plt_header_size = PLT32_HEADER_SIZE; + ret->plt_entry_size = PLT32_ENTRY_SIZE; } - if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc)) + if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, + sizeof (struct _bfd_sparc_elf_link_hash_entry), + SPARC_ELF_DATA)) { free (ret); return NULL; } - return &ret->elf.root; -} - -/* Create .got and .rela.got sections in DYNOBJ, and set up - shortcuts to them in our hash table. */ - -static bfd_boolean -create_got_section (bfd *dynobj, struct bfd_link_info *info) -{ - struct _bfd_sparc_elf_link_hash_table *htab; - - if (! _bfd_elf_create_got_section (dynobj, info)) - return FALSE; + ret->loc_hash_table = htab_try_create (1024, + elf_sparc_local_htab_hash, + elf_sparc_local_htab_eq, + NULL); + ret->loc_hash_memory = objalloc_create (); + if (!ret->loc_hash_table || !ret->loc_hash_memory) + { + _bfd_sparc_elf_link_hash_table_free (abfd); + return NULL; + } + ret->elf.root.hash_table_free = _bfd_sparc_elf_link_hash_table_free; - htab = _bfd_sparc_elf_hash_table (info); - htab->sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (htab->sgot != NULL); - - htab->srelgot = bfd_make_section (dynobj, ".rela.got"); - if (htab->srelgot == NULL - || ! bfd_set_section_flags (dynobj, htab->srelgot, SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY) - || ! bfd_set_section_alignment (dynobj, htab->srelgot, - htab->word_align_power)) - return FALSE; - return TRUE; + return &ret->elf.root; } /* Create .plt, .rela.plt, .got, .rela.got, .dynbss, and @@ -854,29 +1202,77 @@ _bfd_sparc_elf_create_dynamic_sections (bfd *dynobj, struct _bfd_sparc_elf_link_hash_table *htab; htab = _bfd_sparc_elf_hash_table (info); - if (!htab->sgot && !create_got_section (dynobj, info)) - return FALSE; + BFD_ASSERT (htab != NULL); if (!_bfd_elf_create_dynamic_sections (dynobj, info)) return FALSE; - htab->splt = bfd_get_section_by_name (dynobj, ".plt"); - htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); - htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); - if (!info->shared) - htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss"); + htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss"); + if (!bfd_link_pic (info)) + htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss"); - if (!htab->splt || !htab->srelplt || !htab->sdynbss - || (!info->shared && !htab->srelbss)) + if (htab->is_vxworks) + { + if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2)) + return FALSE; + if (bfd_link_pic (info)) + { + htab->plt_header_size + = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt0_entry); + htab->plt_entry_size + = 4 * ARRAY_SIZE (sparc_vxworks_shared_plt_entry); + } + else + { + htab->plt_header_size + = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt0_entry); + htab->plt_entry_size + = 4 * ARRAY_SIZE (sparc_vxworks_exec_plt_entry); + } + } + + if (!htab->elf.splt || !htab->elf.srelplt || !htab->sdynbss + || (!bfd_link_pic (info) && !htab->srelbss)) abort (); return TRUE; } +static bfd_boolean +create_ifunc_sections (bfd *abfd, struct bfd_link_info *info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_link_hash_table *htab = elf_hash_table (info); + flagword flags, pltflags; + asection *s; + + if (htab->irelifunc != NULL || htab->iplt != NULL) + return TRUE; + + flags = bed->dynamic_sec_flags; + pltflags = flags | SEC_ALLOC | SEC_CODE | SEC_LOAD; + + s = bfd_make_section_with_flags (abfd, ".iplt", pltflags); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, bed->plt_alignment)) + return FALSE; + htab->iplt = s; + + s = bfd_make_section_with_flags (abfd, ".rela.iplt", + flags | SEC_READONLY); + if (s == NULL + || ! bfd_set_section_alignment (abfd, s, + bed->s->log_file_align)) + return FALSE; + htab->irelplt = s; + + return TRUE; +} + /* Copy the extra info we tack onto an elf_link_hash_entry. */ void -_bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed, +_bfd_sparc_elf_copy_indirect_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *dir, struct elf_link_hash_entry *ind) { @@ -892,10 +1288,7 @@ _bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed, struct _bfd_sparc_elf_dyn_relocs **pp; struct _bfd_sparc_elf_dyn_relocs *p; - if (ind->root.type == bfd_link_hash_indirect) - abort (); - - /* Add reloc counts against the weak sym to the strong sym + /* Add reloc counts against the indirect sym to the direct sym list. Merge any entries against the same section. */ for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) { @@ -925,7 +1318,7 @@ _bfd_sparc_elf_copy_indirect_symbol (const struct elf_backend_data *bed, edir->tls_type = eind->tls_type; eind->tls_type = GOT_UNKNOWN; } - _bfd_elf_link_hash_copy_indirect (bed, dir, ind); + _bfd_elf_link_hash_copy_indirect (info, dir, ind); } static int @@ -937,7 +1330,7 @@ sparc_elf_tls_transition (struct bfd_link_info *info, bfd *abfd, && ! _bfd_sparc_elf_tdata (abfd)->has_tlsgd) r_type = R_SPARC_REV32; - if (info->shared) + if (bfd_link_pic (info)) return r_type; switch (r_type) @@ -978,33 +1371,41 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, struct _bfd_sparc_elf_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sreloc; int num_relocs; bfd_boolean checked_tlsgd = FALSE; - if (info->relocatable) + if (bfd_link_relocatable (info)) return TRUE; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + BFD_ASSERT (htab != NULL); + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); - local_got_offsets = elf_local_got_offsets (abfd); sreloc = NULL; if (ABI_64_P (abfd)) - num_relocs = NUM_SHDR_ENTRIES (& elf_section_data (sec)->rel_hdr); + num_relocs = NUM_SHDR_ENTRIES (_bfd_elf_single_rel_hdr (sec)); else num_relocs = sec->reloc_count; + + BFD_ASSERT (is_sparc_elf (abfd) || num_relocs == 0); + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + if (!create_ifunc_sections (htab->elf.dynobj, info)) + return FALSE; + rel_end = relocs + num_relocs; for (rel = relocs; rel < rel_end; rel++) { unsigned int r_type; unsigned long r_symndx; struct elf_link_hash_entry *h; + Elf_Internal_Sym *isym; r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info); r_type = SPARC_ELF_R_TYPE (rel->r_info); @@ -1016,10 +1417,53 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, return FALSE; } + isym = NULL; if (r_symndx < symtab_hdr->sh_info) - h = NULL; + { + /* A local symbol. */ + isym = bfd_sym_from_r_symndx (&htab->sym_cache, + abfd, r_symndx); + if (isym == NULL) + return FALSE; + + /* Check relocation against local STT_GNU_IFUNC symbol. */ + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + { + h = elf_sparc_get_local_sym_hash (htab, abfd, rel, + TRUE); + if (h == NULL) + return FALSE; + + /* Fake a STT_GNU_IFUNC symbol. */ + h->type = STT_GNU_IFUNC; + h->def_regular = 1; + h->ref_regular = 1; + h->forced_local = 1; + h->root.type = bfd_link_hash_defined; + } + else + h = NULL; + } else - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + 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; + + /* PR15323, ref flags aren't set for references in the same + object. */ + h->root.non_ir_ref = 1; + } + + if (h && h->type == STT_GNU_IFUNC) + { + if (h->def_regular) + { + h->ref_regular = 1; + h->plt.refcount += 1; + } + } /* Compatibility with old R_SPARC_REV32 reloc conflicting with R_SPARC_TLS_GD_HI22. */ @@ -1057,19 +1501,23 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_TLS_LE_HIX22: case R_SPARC_TLS_LE_LOX10: - if (info->shared) + if (bfd_link_pic (info)) goto r_sparc_plt32; break; case R_SPARC_TLS_IE_HI22: case R_SPARC_TLS_IE_LO10: - if (info->shared) + if (bfd_link_pic (info)) info->flags |= DF_STATIC_TLS; /* Fall through */ case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: case R_SPARC_TLS_GD_HI22: case R_SPARC_TLS_GD_LO10: /* This symbol requires a global offset table entry. */ @@ -1082,6 +1530,8 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: tls_type = GOT_NORMAL; break; case R_SPARC_TLS_GD_HI22: @@ -1119,7 +1569,16 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, _bfd_sparc_elf_local_got_tls_type (abfd) = (char *) (local_got_refcounts + symtab_hdr->sh_info); } - local_got_refcounts[r_symndx] += 1; + switch (r_type) + { + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: + break; + + default: + local_got_refcounts[r_symndx] += 1; + break; + } old_tls_type = _bfd_sparc_elf_local_got_tls_type (abfd) [r_symndx]; } @@ -1149,18 +1608,16 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, } } - if (htab->sgot == NULL) + if (htab->elf.sgot == NULL) { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!create_got_section (htab->elf.dynobj, info)) + if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) return FALSE; } break; case R_SPARC_TLS_GD_CALL: case R_SPARC_TLS_LDM_CALL: - if (info->shared) + if (bfd_link_pic (info)) { /* These are basically R_SPARC_TLS_WPLT30 relocs against __tls_get_addr. */ @@ -1203,6 +1660,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, goto r_sparc_plt32; break; } + /* PR 7027: We need similar behaviour for 64-bit binaries. */ + else if (r_type == R_SPARC_WPLT30) + break; /* It does not make sense to have a procedure linkage table entry for a local symbol. */ @@ -1244,6 +1704,7 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_WDISP22: case R_SPARC_WDISP19: case R_SPARC_WDISP16: + case R_SPARC_WDISP10: case R_SPARC_8: case R_SPARC_16: case R_SPARC_32: @@ -1268,12 +1729,13 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_SPARC_H44: case R_SPARC_M44: case R_SPARC_L44: + case R_SPARC_H34: case R_SPARC_UA64: if (h != NULL) h->non_got_ref = 1; r_sparc_plt32: - if (h != NULL && !info->shared) + if (h != NULL && !bfd_link_pic (info)) { /* We may need a .plt entry if the function this reloc refers to is in a shared lib. */ @@ -1301,18 +1763,21 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the symbol. */ - if ((info->shared + if ((bfd_link_pic (info) && (sec->flags & SEC_ALLOC) != 0 && (! _bfd_sparc_elf_howto_table[r_type].pc_relative || (h != NULL - && (! info->symbolic + && (! SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) - || (!info->shared + || (!bfd_link_pic (info) && (sec->flags & SEC_ALLOC) != 0 && h != NULL && (h->root.type == bfd_link_hash_defweak - || !h->def_regular))) + || !h->def_regular)) + || (!bfd_link_pic (info) + && h != NULL + && h->type == STT_GNU_IFUNC)) { struct _bfd_sparc_elf_dyn_relocs *p; struct _bfd_sparc_elf_dyn_relocs **head; @@ -1322,41 +1787,12 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, section in dynobj and make room for the reloc. */ if (sreloc == NULL) { - const char *name; - bfd *dynobj; - - name = (bfd_elf_string_from_elf_section - (abfd, - elf_elfheader (abfd)->e_shstrndx, - elf_section_data (sec)->rel_hdr.sh_name)); - if (name == NULL) - return FALSE; - - BFD_ASSERT (strncmp (name, ".rela", 5) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - name + 5) == 0); + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, htab->elf.dynobj, htab->word_align_power, + abfd, /*rela?*/ TRUE); - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - dynobj = htab->elf.dynobj; - - sreloc = bfd_get_section_by_name (dynobj, name); if (sreloc == NULL) - { - flagword flags; - - sreloc = bfd_make_section (dynobj, name); - flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - if (sreloc == NULL - || ! bfd_set_section_flags (dynobj, sreloc, flags) - || ! bfd_set_section_alignment (dynobj, sreloc, - htab->word_align_power)) - return FALSE; - } - elf_section_data (sec)->sreloc = sreloc; + return FALSE; } /* If this is a global symbol, we count the number of @@ -1368,15 +1804,16 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Track dynamic relocs needed for local syms too. We really need local syms available to do this easily. Oh well. */ - asection *s; - s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, - sec, r_symndx); + void *vpp; + + BFD_ASSERT (isym != NULL); + s = bfd_section_from_elf_index (abfd, isym->st_shndx); if (s == NULL) - return FALSE; + s = sec; - head = ((struct _bfd_sparc_elf_dyn_relocs **) - &elf_section_data (s)->local_dynrel); + vpp = &elf_section_data (s)->local_dynrel; + head = (struct _bfd_sparc_elf_dyn_relocs **) vpp; } p = *head; @@ -1407,7 +1844,9 @@ _bfd_sparc_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, break; case R_SPARC_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) return FALSE; break; @@ -1431,34 +1870,50 @@ _bfd_sparc_elf_gc_mark_hook (asection *sec, Elf_Internal_Sym *sym) { if (h != NULL) - { - struct _bfd_sparc_elf_link_hash_table *htab; - - htab = _bfd_sparc_elf_hash_table (info); - switch (SPARC_ELF_R_TYPE (rel->r_info)) + switch (SPARC_ELF_R_TYPE (rel->r_info)) { case R_SPARC_GNU_VTINHERIT: case R_SPARC_GNU_VTENTRY: - break; + return NULL; + } - default: - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; + /* FIXME: The test here, in check_relocs and in relocate_section + dealing with TLS optimization, ought to be !bfd_link_executable (info). */ + if (bfd_link_pic (info)) + { + switch (SPARC_ELF_R_TYPE (rel->r_info)) + { + case R_SPARC_TLS_GD_CALL: + case R_SPARC_TLS_LDM_CALL: + /* This reloc implicitly references __tls_get_addr. We know + another reloc will reference the same symbol as the one + on this reloc, so the real symbol and section will be + gc marked when processing the other reloc. That lets + us handle __tls_get_addr here. */ + h = elf_link_hash_lookup (elf_hash_table (info), "__tls_get_addr", + FALSE, FALSE, TRUE); + BFD_ASSERT (h != NULL); + h->mark = 1; + if (h->u.weakdef != NULL) + h->u.weakdef->mark = 1; + sym = NULL; + } + } - case bfd_link_hash_common: - return h->root.u.c.p->section; + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); +} - default: - break; - } - } +static Elf_Internal_Rela * +sparc_elf_find_reloc_at_ofs (Elf_Internal_Rela *rel, + Elf_Internal_Rela *relend, + bfd_vma offset) +{ + while (rel < relend) + { + if (rel->r_offset == offset) + return rel; + rel++; } - else - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); - return NULL; } @@ -1473,10 +1928,16 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel, *relend; + if (bfd_link_relocatable (info)) + return TRUE; + + BFD_ASSERT (is_sparc_elf (abfd) || sec->reloc_count == 0); + elf_section_data (sec)->local_dynrel = NULL; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + BFD_ASSERT (htab != NULL); + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); @@ -1509,7 +1970,7 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, } r_type = SPARC_ELF_R_TYPE (rel->r_info); - r_type = sparc_elf_tls_transition (info, abfd, r_type, h != NULL); + r_type = sparc_elf_tls_transition (info, abfd, r_type, h == NULL); switch (r_type) { case R_SPARC_TLS_LDM_HI22: @@ -1525,6 +1986,10 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: if (h != NULL) { if (h->got.refcount > 0) @@ -1532,8 +1997,17 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, } else { - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx]--; + switch (r_type) + { + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: + break; + + default: + if (local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx]--; + break; + } } break; @@ -1555,6 +2029,7 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_SPARC_WDISP22: case R_SPARC_WDISP19: case R_SPARC_WDISP16: + case R_SPARC_WDISP10: case R_SPARC_8: case R_SPARC_16: case R_SPARC_32: @@ -1580,8 +2055,9 @@ _bfd_sparc_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, case R_SPARC_H44: case R_SPARC_M44: case R_SPARC_L44: + case R_SPARC_H34: case R_SPARC_UA64: - if (info->shared) + if (bfd_link_pic (info)) break; /* Fall through. */ @@ -1615,13 +2091,14 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, struct _bfd_sparc_elf_link_hash_entry * eh; struct _bfd_sparc_elf_dyn_relocs *p; asection *s; - unsigned int power_of_two; htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); /* Make sure we know what is going on here. */ BFD_ASSERT (htab->elf.dynobj != NULL && (h->needs_plt + || h->type == STT_GNU_IFUNC || h->u.weakdef != NULL || (h->def_dynamic && h->ref_regular @@ -1635,6 +2112,7 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, some of their functions as STT_NOTYPE when they really should be STT_FUNC. */ if (h->type == STT_FUNC + || h->type == STT_GNU_IFUNC || h->needs_plt || (h->type == STT_NOTYPE && (h->root.type == bfd_link_hash_defined @@ -1642,11 +2120,10 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, && (h->root.u.def.section->flags & SEC_CODE) != 0)) { if (h->plt.refcount <= 0 - || (! info->shared - && !h->def_dynamic - && !h->ref_dynamic - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined)) + || (h->type != STT_GNU_IFUNC + && (SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)))) { /* This case can occur if we saw a WPLT30 reloc in an input file, but the symbol was never referred to by a dynamic @@ -1681,7 +2158,7 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, only references to the symbol are via the global offset table. For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ - if (info->shared) + if (bfd_link_pic (info)) return TRUE; /* If there are no references to this symbol that do not use the @@ -1689,6 +2166,13 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!h->non_got_ref) return TRUE; + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->non_got_ref = 0; + return TRUE; + } + eh = (struct _bfd_sparc_elf_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { @@ -1719,42 +2203,22 @@ _bfd_sparc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, to copy the initial value out of the dynamic object and into the runtime process image. We need to remember the offset into the .rel.bss section we are going to use. */ - if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0 && h->size != 0) { htab->srelbss->size += SPARC_ELF_RELA_BYTES (htab); h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > htab->align_power_max) - power_of_two = htab->align_power_max; - - /* Apply the required alignment. */ s = htab->sdynbss; - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (dynobj, s)) - { - if (! bfd_set_section_alignment (dynobj, s, power_of_two)) - return FALSE; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - return TRUE; + return _bfd_elf_adjust_dynamic_copy (info, h, s); } /* Allocate space in .plt, .got and associated reloc sections for dynamic relocs. */ static bfd_boolean -allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) +allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) { struct bfd_link_info *info; struct _bfd_sparc_elf_link_hash_table *htab; @@ -1764,17 +2228,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) if (h->root.type == bfd_link_hash_indirect) return TRUE; - if (h->root.type == bfd_link_hash_warning) - /* When warning symbols are created, they **replace** the "real" - entry in the hash table, thus we never get to see the real - symbol in a hash traversal. So look at it now. */ - h = (struct elf_link_hash_entry *) h->root.u.i.link; - info = (struct bfd_link_info *) inf; htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); - if (htab->elf.dynamic_sections_created - && h->plt.refcount > 0) + if ((htab->elf.dynamic_sections_created + && h->plt.refcount > 0) + || (h->type == STT_GNU_IFUNC + && h->def_regular + && h->ref_regular)) { /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -1785,14 +2247,24 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) return FALSE; } - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, bfd_link_pic (info), h) + || (h->type == STT_GNU_IFUNC + && h->def_regular)) { - asection *s = htab->splt; + asection *s = htab->elf.splt; - /* The first four entries in .plt is reserved. */ + if (s == NULL) + s = htab->elf.iplt; + + /* Allocate room for the header. */ if (s->size == 0) - s->size = (SPARC_ELF_WORD_BYTES(htab) == 8 ? - PLT64_HEADER_SIZE : PLT32_HEADER_SIZE); + { + s->size = htab->plt_header_size; + + /* Allocate space for the .rela.plt.unloaded relocations. */ + if (htab->is_vxworks && !bfd_link_pic (info)) + htab->srelplt2->size = sizeof (Elf32_External_Rela) * 2; + } /* The procedure linkage table size is bounded by the magnitude of the offset we can describe in the entry. */ @@ -1821,7 +2293,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) 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 + if (! bfd_link_pic (info) && !h->def_regular) { h->root.u.def.section = s; @@ -1829,11 +2301,23 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) } /* Make room for this entry. */ - s->size += (SPARC_ELF_WORD_BYTES(htab) == 8 ? - PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE); + s->size += htab->plt_entry_size; /* We also need to make an entry in the .rela.plt section. */ - htab->srelplt->size += SPARC_ELF_RELA_BYTES (htab); + if (s == htab->elf.splt) + htab->elf.srelplt->size += SPARC_ELF_RELA_BYTES (htab); + else + htab->elf.irelplt->size += SPARC_ELF_RELA_BYTES (htab); + + if (htab->is_vxworks) + { + /* Allocate space for the .got.plt entry. */ + htab->elf.sgotplt->size += 4; + + /* ...and for the .rela.plt.unloaded relocations. */ + if (!bfd_link_pic (info)) + htab->srelplt2->size += sizeof (Elf32_External_Rela) * 3; + } } else { @@ -1850,7 +2334,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) /* If R_SPARC_TLS_IE_{HI22,LO10} symbol is now local to the binary, make it a R_SPARC_TLS_LE_{HI22,LO10} requiring no TLS entry. */ if (h->got.refcount > 0 - && !info->shared + && !bfd_link_pic (info) && h->dynindx == -1 && _bfd_sparc_elf_hash_entry(h)->tls_type == GOT_TLS_IE) h->got.offset = (bfd_vma) -1; @@ -1869,7 +2353,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) return FALSE; } - s = htab->sgot; + s = htab->elf.sgot; h->got.offset = s->size; s->size += SPARC_ELF_WORD_BYTES (htab); /* R_SPARC_TLS_GD_HI{22,LO10} needs 2 consecutive GOT slots. */ @@ -1880,12 +2364,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) R_SPARC_TLS_GD_{HI22,LO10} needs one if local symbol and two if global. */ if ((tls_type == GOT_TLS_GD && h->dynindx == -1) - || tls_type == GOT_TLS_IE) - htab->srelgot->size += SPARC_ELF_RELA_BYTES (htab); + || tls_type == GOT_TLS_IE + || h->type == STT_GNU_IFUNC) + htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab); else if (tls_type == GOT_TLS_GD) - htab->srelgot->size += 2 * SPARC_ELF_RELA_BYTES (htab); - else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)) - htab->srelgot->size += SPARC_ELF_RELA_BYTES (htab); + htab->elf.srelgot->size += 2 * SPARC_ELF_RELA_BYTES (htab); + else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, + bfd_link_pic (info), + h)) + htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab); } else h->got.offset = (bfd_vma) -1; @@ -1900,11 +2387,9 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) space for pc-relative relocs that have become local due to symbol visibility changes. */ - if (info->shared) + if (bfd_link_pic (info)) { - if (h->def_regular - && (h->forced_local - || info->symbolic)) + if (SYMBOL_CALLS_LOCAL (info, h)) { struct _bfd_sparc_elf_dyn_relocs **pp; @@ -1918,6 +2403,37 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) pp = &p->next; } } + + if (htab->is_vxworks) + { + struct _bfd_sparc_elf_dyn_relocs **pp; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) + *pp = p->next; + else + pp = &p->next; + } + } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (eh->dyn_relocs != NULL + && h->root.type == bfd_link_hash_undefweak) + { + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + eh->dyn_relocs = NULL; + + /* Make sure undefined weak symbols are output as a dynamic + symbol in PIEs. */ + else if (h->dynindx == -1 + && !h->forced_local) + { + if (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + } } else { @@ -1962,17 +2478,33 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf) return TRUE; } +/* Allocate space in .plt, .got and associated reloc sections for + local dynamic relocs. */ + +static bfd_boolean +allocate_local_dynrelocs (void **slot, void *inf) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) *slot; + + if (h->type != STT_GNU_IFUNC + || !h->def_regular + || !h->ref_regular + || !h->forced_local + || h->root.type != bfd_link_hash_defined) + abort (); + + return allocate_dynrelocs (h, inf); +} + /* Find any dynamic relocs that apply to read-only sections. */ static bfd_boolean -readonly_dynrelocs (struct elf_link_hash_entry *h, PTR inf) +readonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) { struct _bfd_sparc_elf_link_hash_entry *eh; struct _bfd_sparc_elf_dyn_relocs *p; - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - eh = (struct _bfd_sparc_elf_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { @@ -2020,15 +2552,16 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, bfd *ibfd; htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); dynobj = htab->elf.dynobj; BFD_ASSERT (dynobj != NULL); if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (info->executable) + if (bfd_link_executable (info) && !info->nointerp) { - s = bfd_get_section_by_name (dynobj, ".interp"); + s = bfd_get_linker_section (dynobj, ".interp"); BFD_ASSERT (s != NULL); s->size = htab->dynamic_interpreter_size; s->contents = (unsigned char *) htab->dynamic_interpreter; @@ -2037,7 +2570,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, /* Set up .got offsets for local syms, and space for local dynamic relocs. */ - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) { bfd_signed_vma *local_got; bfd_signed_vma *end_local_got; @@ -2046,17 +2579,14 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, Elf_Internal_Shdr *symtab_hdr; asection *srel; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + if (! is_sparc_elf (ibfd)) continue; for (s = ibfd->sections; s != NULL; s = s->next) { struct _bfd_sparc_elf_dyn_relocs *p; - for (p = *((struct _bfd_sparc_elf_dyn_relocs **) - &elf_section_data (s)->local_dynrel); - p != NULL; - p = p->next) + for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) { if (!bfd_is_abs_section (p->sec) && bfd_is_abs_section (p->sec->output_section)) @@ -2066,9 +2596,18 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, linker script /DISCARD/, so we'll be discarding the relocs too. */ } + else if (htab->is_vxworks + && strcmp (p->sec->output_section->name, + ".tls_vars") == 0) + { + /* Relocations in vxworks .tls_vars sections are + handled specially by the loader. */ + } else if (p->count != 0) { srel = elf_section_data (p->sec)->sreloc; + if (!htab->elf.dynamic_sections_created) + srel = htab->elf.irelplt; srel->size += p->count * SPARC_ELF_RELA_BYTES (htab); if ((p->sec->output_section->flags & SEC_READONLY) != 0) info->flags |= DF_TEXTREL; @@ -2080,12 +2619,12 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, if (!local_got) continue; - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; local_tls_type = _bfd_sparc_elf_local_got_tls_type (ibfd); - s = htab->sgot; - srel = htab->srelgot; + s = htab->elf.sgot; + srel = htab->elf.srelgot; for (; local_got < end_local_got; ++local_got, ++local_tls_type) { if (*local_got > 0) @@ -2094,7 +2633,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, s->size += SPARC_ELF_WORD_BYTES (htab); if (*local_tls_type == GOT_TLS_GD) s->size += SPARC_ELF_WORD_BYTES (htab); - if (info->shared + if (bfd_link_pic (info) || *local_tls_type == GOT_TLS_GD || *local_tls_type == GOT_TLS_IE) srel->size += SPARC_ELF_RELA_BYTES (htab); @@ -2108,30 +2647,34 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, { /* Allocate 2 got entries and 1 dynamic reloc for R_SPARC_TLS_LDM_{HI22,LO10} relocs. */ - htab->tls_ldm_got.offset = htab->sgot->size; - htab->sgot->size += (2 * SPARC_ELF_WORD_BYTES (htab)); - htab->srelgot->size += SPARC_ELF_RELA_BYTES (htab); + htab->tls_ldm_got.offset = htab->elf.sgot->size; + htab->elf.sgot->size += (2 * SPARC_ELF_WORD_BYTES (htab)); + htab->elf.srelgot->size += SPARC_ELF_RELA_BYTES (htab); } else htab->tls_ldm_got.offset = -1; /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info); + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); + + /* Allocate .plt and .got entries, and space for local symbols. */ + htab_traverse (htab->loc_hash_table, allocate_local_dynrelocs, info); - if (! ABI_64_P (output_bfd) + if (!htab->is_vxworks && elf_hash_table (info)->dynamic_sections_created) { - /* Make space for the trailing nop in .plt. */ - if (htab->splt->size > 0) - htab->splt->size += 1 * SPARC_INSN_BYTES; + if (! ABI_64_P (output_bfd)) + { + /* Make space for the trailing nop in .plt. */ + if (htab->elf.splt->size > 0) + htab->elf.splt->size += 1 * SPARC_INSN_BYTES; + } /* If the .got section is more than 0x1000 bytes, we add 0x1000 to the value of _GLOBAL_OFFSET_TABLE_, so that 13 - bit relocations have a greater chance of working. - - FIXME: Make this optimization work for 64-bit too. */ - if (htab->sgot->size >= 0x1000 + bit relocations have a greater chance of working. */ + if (htab->elf.sgot->size >= 0x1000 && elf_hash_table (info)->hgot->root.u.def.value == 0) elf_hash_table (info)->hgot->root.u.def.value = 0x1000; } @@ -2141,55 +2684,56 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, memory for them. */ for (s = dynobj->sections; s != NULL; s = s->next) { - const char *name; - bfd_boolean strip = FALSE; - if ((s->flags & SEC_LINKER_CREATED) == 0) continue; - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - if (strncmp (name, ".rela", 5) == 0) + if (s == htab->elf.splt + || s == htab->elf.sgot + || s == htab->sdynbss + || s == htab->elf.iplt + || s == htab->elf.sgotplt) { - if (s->size == 0) - { - /* If we don't need this section, strip it from the - output file. This is to handle .rela.bss and - .rel.plt. We must create it in - create_dynamic_sections, because it must be created - before the linker maps input sections to output - sections. The linker does that before - adjust_dynamic_symbol is called, and it is that - function which decides whether anything needs to go - into these sections. */ - strip = TRUE; - } - else + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (CONST_STRNEQ (s->name, ".rela")) + { + if (s->size != 0) { /* We use the reloc_count field as a counter if we need to copy relocs into the output file. */ s->reloc_count = 0; } } - else if (s != htab->splt && s != htab->sgot) + else { - /* It's not one of our sections, so don't allocate space. */ + /* It's not one of our sections. */ continue; } - if (strip) + if (s->size == 0) { - _bfd_strip_section_from_output (info, s); + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rela.bss and + .rela.plt. We must create both sections in + create_dynamic_sections, because they must be created + before the linker maps input sections to output + sections. The linker does that before + adjust_dynamic_symbol is called, and it is that + function which decides whether anything needs to go + into these sections. */ + s->flags |= SEC_EXCLUDE; continue; } + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + /* Allocate memory for the section contents. Zero the memory for the benefit of .rela.plt, which has 4 unused entries at the beginning, and we don't want garbage. */ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) + if (s->contents == NULL) return FALSE; } @@ -2203,13 +2747,13 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, #define add_dynamic_entry(TAG, VAL) \ _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (info->executable) + if (bfd_link_executable (info)) { if (!add_dynamic_entry (DT_DEBUG, 0)) return FALSE; } - if (htab->srelplt->size != 0) + if (htab->elf.srelplt->size != 0) { if (!add_dynamic_entry (DT_PLTGOT, 0) || !add_dynamic_entry (DT_PLTRELSZ, 0) @@ -2227,8 +2771,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, - (PTR) info); + elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); if (info->flags & DF_TEXTREL) { @@ -2275,6 +2818,7 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, entry->isym.st_info = ELF_ST_INFO (app_regs [reg].bind, STT_REGISTER); entry->isym.st_shndx = app_regs [reg].shndx; + entry->isym.st_target_internal = 0; entry->next = NULL; entry->input_bfd = output_bfd; entry->input_indx = -1; @@ -2290,6 +2834,9 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, eht->dynsymcount++; } } + if (htab->is_vxworks + && !elf_vxworks_add_dynamic_entries (output_bfd, info)) + return FALSE; } #undef add_dynamic_entry @@ -2299,13 +2846,16 @@ _bfd_sparc_elf_size_dynamic_sections (bfd *output_bfd, bfd_boolean _bfd_sparc_elf_new_section_hook (bfd *abfd, asection *sec) { - struct _bfd_sparc_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); + if (!sec->used_by_bfd) + { + struct _bfd_sparc_elf_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); - sdata = (struct _bfd_sparc_elf_section_data *) bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = (PTR) sdata; + sdata = bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = sdata; + } return _bfd_elf_new_section_hook (abfd, sec); } @@ -2316,6 +2866,10 @@ _bfd_sparc_elf_relax_section (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *link_info ATTRIBUTE_UNUSED, bfd_boolean *again) { + if (bfd_link_relocatable (link_info)) + (*link_info->callbacks->einfo) + (_("%P%F: --relax and -r may not be used together\n")); + *again = FALSE; sec_do_relax (section) = 1; return TRUE; @@ -2341,20 +2895,44 @@ static bfd_vma tpoff (struct bfd_link_info *info, bfd_vma address) { struct elf_link_hash_table *htab = elf_hash_table (info); + const struct elf_backend_data *bed = get_elf_backend_data (info->output_bfd); + bfd_vma static_tls_size; /* If tls_sec is NULL, we should have signalled an error already. */ if (htab->tls_sec == NULL) return 0; - return address - htab->tls_size - htab->tls_sec->vma; + + /* Consider special static TLS alignment requirements. */ + static_tls_size = BFD_ALIGN (htab->tls_size, bed->static_tls_alignment); + return address - static_tls_size - htab->tls_sec->vma; +} + +/* Return the relocation value for a %gdop relocation. */ + +static bfd_vma +gdopoff (struct bfd_link_info *info, bfd_vma address) +{ + struct elf_link_hash_table *htab = elf_hash_table (info); + bfd_vma got_base; + + got_base = (htab->hgot->root.u.def.value + + htab->hgot->root.u.def.section->output_offset + + htab->hgot->root.u.def.section->output_section->vma); + + return address - got_base; } /* Relocate a SPARC ELF section. */ bfd_boolean -_bfd_sparc_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) +_bfd_sparc_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 _bfd_sparc_elf_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; @@ -2365,12 +2943,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; int num_relocs; - - if (info->relocatable) - return TRUE; + bfd_boolean is_vxworks_tls; htab = _bfd_sparc_elf_hash_table (info); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + BFD_ASSERT (htab != NULL); + symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); @@ -2380,10 +2957,15 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, got_base = elf_hash_table (info)->hgot->root.u.def.value; sreloc = elf_section_data (input_section)->sreloc; + /* We have to handle relocations in vxworks .tls_vars sections + specially, because the dynamic loader is 'weird'. */ + is_vxworks_tls = (htab->is_vxworks && bfd_link_pic (info) + && !strcmp (input_section->output_section->name, + ".tls_vars")); rel = relocs; if (ABI_64_P (output_bfd)) - num_relocs = NUM_SHDR_ENTRIES (& elf_section_data (input_section)->rel_hdr); + num_relocs = NUM_SHDR_ENTRIES (_bfd_elf_single_rel_hdr (input_section)); else num_relocs = input_section->reloc_count; relend = relocs + num_relocs; @@ -2412,7 +2994,6 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } howto = _bfd_sparc_elf_howto_table + r_type; - /* This is a final link. */ r_symndx = SPARC_ELF_R_SYMNDX (htab, rel->r_info); h = NULL; sym = NULL; @@ -2423,15 +3004,29 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, sym = local_syms + r_symndx; sec = local_sections[r_symndx]; relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); + + if (!bfd_link_relocatable (info) + && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) + { + /* Relocate against local STT_GNU_IFUNC symbol. */ + h = elf_sparc_get_local_sym_hash (htab, input_bfd, + rel, FALSE); + if (h == NULL) + abort (); + + /* Set STT_GNU_IFUNC symbol value. */ + h->root.u.def.value = sym->st_value; + h->root.u.def.section = sec; + } } else { - bfd_boolean warned; + bfd_boolean warned, ignored; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h, sec, relocation, - unresolved_reloc, warned); + unresolved_reloc, warned, ignored); if (warned) { /* To avoid generating warning messages about truncated @@ -2444,14 +3039,165 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } } + if (sec != NULL && discarded_section (sec)) + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + rel, 1, relend, howto, 0, contents); + + if (bfd_link_relocatable (info)) + continue; + + if (h != NULL + && h->type == STT_GNU_IFUNC + && h->def_regular) + { + asection *plt_sec; + const char *name; + + if ((input_section->flags & SEC_ALLOC) == 0 + || h->plt.offset == (bfd_vma) -1) + abort (); + + plt_sec = htab->elf.splt; + if (! plt_sec) + plt_sec =htab->elf.iplt; + + switch (r_type) + { + case R_SPARC_GOTDATA_OP: + continue; + + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: + r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22 + ? R_SPARC_GOT22 + : R_SPARC_GOT10); + howto = _bfd_sparc_elf_howto_table + r_type; + /* Fall through. */ + + case R_SPARC_GOT10: + case R_SPARC_GOT13: + case R_SPARC_GOT22: + if (htab->elf.sgot == NULL) + abort (); + off = h->got.offset; + if (off == (bfd_vma) -1) + abort(); + relocation = htab->elf.sgot->output_offset + off - got_base; + goto do_relocation; + + case R_SPARC_WPLT30: + case R_SPARC_WDISP30: + relocation = (plt_sec->output_section->vma + + plt_sec->output_offset + h->plt.offset); + goto do_relocation; + + case R_SPARC_32: + case R_SPARC_64: + if (bfd_link_pic (info) && h->non_got_ref) + { + Elf_Internal_Rela outrel; + bfd_vma offset; + + offset = _bfd_elf_section_offset (output_bfd, info, + input_section, + rel->r_offset); + if (offset == (bfd_vma) -1 + || offset == (bfd_vma) -2) + abort(); + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + offset); + + if (h->dynindx == -1 + || h->forced_local + || bfd_link_executable (info)) + { + outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, + 0, R_SPARC_IRELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + if (h->dynindx == -1) + abort(); + outrel.r_info = SPARC_ELF_R_INFO (htab, rel, h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + + sparc_elf_append_rela (output_bfd, sreloc, &outrel); + continue; + } + + relocation = (plt_sec->output_section->vma + + plt_sec->output_offset + h->plt.offset); + goto do_relocation; + + case R_SPARC_HI22: + case R_SPARC_LO10: + /* We should only see such relocs in static links. */ + if (bfd_link_pic (info)) + abort(); + relocation = (plt_sec->output_section->vma + + plt_sec->output_offset + h->plt.offset); + goto do_relocation; + + default: + if (h->root.root.string) + name = h->root.root.string; + else + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + NULL); + (*_bfd_error_handler) + (_("%B: relocation %s against STT_GNU_IFUNC " + "symbol `%s' isn't handled by %s"), input_bfd, + _bfd_sparc_elf_howto_table[r_type].name, + name, __FUNCTION__); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + switch (r_type) + { + case R_SPARC_GOTDATA_OP_HIX22: + case R_SPARC_GOTDATA_OP_LOX10: + if (SYMBOL_REFERENCES_LOCAL (info, h)) + r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22 + ? R_SPARC_GOTDATA_HIX22 + : R_SPARC_GOTDATA_LOX10); + else + r_type = (r_type == R_SPARC_GOTDATA_OP_HIX22 + ? R_SPARC_GOT22 + : R_SPARC_GOT10); + howto = _bfd_sparc_elf_howto_table + r_type; + break; + + case R_SPARC_GOTDATA_OP: + if (SYMBOL_REFERENCES_LOCAL (info, h)) + { + bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); + + /* {ld,ldx} [%rs1 + %rs2], %rd --> add %rs1, %rs2, %rd */ + relocation = 0x80000000 | (insn & 0x3e07c01f); + bfd_put_32 (output_bfd, relocation, contents + rel->r_offset); + } + continue; + } + switch (r_type) { + case R_SPARC_GOTDATA_HIX22: + case R_SPARC_GOTDATA_LOX10: + relocation = gdopoff (info, relocation); + break; + case R_SPARC_GOT10: case R_SPARC_GOT13: case R_SPARC_GOT22: /* Relocation is to the entry for this symbol in the global offset table. */ - if (htab->sgot == NULL) + if (htab->elf.sgot == NULL) abort (); if (h != NULL) @@ -2462,12 +3208,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, BFD_ASSERT (off != (bfd_vma) -1); dyn = elf_hash_table (info)->dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) - || (info->shared - && (info->symbolic - || h->dynindx == -1 - || h->forced_local) - && h->def_regular)) + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, + bfd_link_pic (info), + h) + || (bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h))) { /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -2486,7 +3231,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, else { SPARC_ELF_PUT_WORD (htab, output_bfd, relocation, - htab->sgot->contents + off); + htab->elf.sgot->contents + off); h->got.offset |= 1; } } @@ -2508,32 +3253,32 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, else { - if (info->shared) + if (bfd_link_pic (info)) { asection *s; Elf_Internal_Rela outrel; /* We need to generate a R_SPARC_RELATIVE reloc for the dynamic linker. */ - s = htab->srelgot; + s = htab->elf.srelgot; BFD_ASSERT (s != NULL); - outrel.r_offset = (htab->sgot->output_section->vma - + htab->sgot->output_offset + outrel.r_offset = (htab->elf.sgot->output_section->vma + + htab->elf.sgot->output_offset + off); outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE); outrel.r_addend = relocation; relocation = 0; - SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &outrel); + sparc_elf_append_rela (output_bfd, s, &outrel); } SPARC_ELF_PUT_WORD (htab, output_bfd, relocation, - htab->sgot->contents + off); + htab->elf.sgot->contents + off); local_got_offsets[r_symndx] |= 1; } } - relocation = htab->sgot->output_offset + off - got_base; + relocation = htab->elf.sgot->output_offset + off - got_base; break; case R_SPARC_PLT32: @@ -2564,12 +3309,15 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (h == NULL) break; } + /* PR 7027: We need similar behaviour for 64-bit binaries. */ + else if (r_type == R_SPARC_WPLT30 && h == NULL) + break; else { BFD_ASSERT (h != NULL); } - if (h->plt.offset == (bfd_vma) -1 || htab->splt == NULL) + if (h->plt.offset == (bfd_vma) -1 || htab->elf.splt == NULL) { /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when @@ -2577,8 +3325,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, break; } - relocation = (htab->splt->output_section->vma - + htab->splt->output_offset + relocation = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + h->plt.offset); unresolved_reloc = FALSE; if (r_type == R_SPARC_PLT32 || r_type == R_SPARC_PLT64) @@ -2606,6 +3354,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_WDISP22: case R_SPARC_WDISP19: case R_SPARC_WDISP16: + case R_SPARC_WDISP10: case R_SPARC_8: case R_SPARC_16: case R_SPARC_32: @@ -2630,25 +3379,20 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_H44: case R_SPARC_M44: case R_SPARC_L44: + case R_SPARC_H34: case R_SPARC_UA64: r_sparc_plt32: - /* r_symndx will be zero only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ - if (r_symndx == 0 - || (input_section->flags & SEC_ALLOC) == 0) + if ((input_section->flags & SEC_ALLOC) == 0 + || is_vxworks_tls) break; - if ((info->shared + if ((bfd_link_pic (info) && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) && (! howto->pc_relative - || (h != NULL - && h->dynindx != -1 - && (! info->symbolic - || !h->def_regular)))) - || (!info->shared + || !SYMBOL_CALLS_LOCAL (info, h))) + || (!bfd_link_pic (info) && h != NULL && h->dynindx != -1 && !h->non_got_ref @@ -2724,8 +3468,11 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, memset (&outrel, 0, sizeof outrel); /* h->dynindx may be -1 if the symbol was marked to become local. */ - else if (h != NULL && ! is_plt - && ((! info->symbolic && h->dynindx != -1) + else if (h != NULL + && h->dynindx != -1 + && (_bfd_sparc_elf_howto_table[r_type].pc_relative + || !bfd_link_pic (info) + || !SYMBOLIC_BIND (info, h) || !h->def_regular)) { BFD_ASSERT (h->dynindx != -1); @@ -2734,7 +3481,8 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } else { - if (r_type == R_SPARC_32 || r_type == R_SPARC_64) + if ( (!ABI_64_P (output_bfd) && r_type == R_SPARC_32) + || (ABI_64_P (output_bfd) && r_type == R_SPARC_64)) { outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE); @@ -2744,8 +3492,10 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { long indx; + outrel.r_addend = relocation + rel->r_addend; + if (is_plt) - sec = htab->splt; + sec = htab->elf.splt; if (bfd_is_abs_section (sec)) indx = 0; @@ -2758,9 +3508,20 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { asection *osec; + /* We are turning this relocation into one + against a section symbol. It would be + proper to subtract the symbol's value, + osec->vma, from the emitted reloc addend, + but ld.so expects buggy relocs. */ osec = sec->output_section; indx = elf_section_data (osec)->dynindx; + if (indx == 0) + { + osec = htab->elf.text_index_section; + indx = elf_section_data (osec)->dynindx; + } + /* FIXME: we really should be able to link non-pic shared libraries. */ if (indx == 0) @@ -2774,12 +3535,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } } - outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx, r_type); - outrel.r_addend = relocation + rel->r_addend; + outrel.r_info = SPARC_ELF_R_INFO (htab, rel, indx, + r_type); } } - SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel); + sparc_elf_append_rela (output_bfd, sreloc, &outrel); /* This reloc will be computed at runtime, so there's no need to do anything now. */ @@ -2809,7 +3570,9 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, else if (h != NULL) { tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type; - if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) + if (!bfd_link_pic (info) + && h->dynindx == -1 + && tls_type == GOT_TLS_IE) switch (SPARC_ELF_R_TYPE (rel->r_info)) { case R_SPARC_TLS_GD_HI22: @@ -2860,7 +3623,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } r_sparc_tlsldm: - if (htab->sgot == NULL) + if (htab->elf.sgot == NULL) abort (); if ((off & 1) != 0) @@ -2870,12 +3633,13 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, Elf_Internal_Rela outrel; int dr_type, indx; - if (htab->srelgot == NULL) + if (htab->elf.srelgot == NULL) abort (); - SPARC_ELF_PUT_WORD (htab, output_bfd, 0, htab->sgot->contents + off); - outrel.r_offset = (htab->sgot->output_section->vma - + htab->sgot->output_offset + off); + SPARC_ELF_PUT_WORD (htab, output_bfd, 0, + htab->elf.sgot->contents + off); + outrel.r_offset = (htab->elf.sgot->output_section->vma + + htab->elf.sgot->output_offset + off); indx = h && h->dynindx != -1 ? h->dynindx : 0; if (r_type == R_SPARC_TLS_IE_HI22 || r_type == R_SPARC_TLS_IE_LO10) @@ -2887,7 +3651,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, else outrel.r_addend = 0; outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx, dr_type); - SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel); + sparc_elf_append_rela (output_bfd, htab->elf.srelgot, &outrel); if (r_type == R_SPARC_TLS_GD_HI22 || r_type == R_SPARC_TLS_GD_LO10) @@ -2897,24 +3661,25 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, BFD_ASSERT (! unresolved_reloc); SPARC_ELF_PUT_WORD (htab, output_bfd, relocation - dtpoff_base (info), - (htab->sgot->contents + off + (htab->elf.sgot->contents + off + SPARC_ELF_WORD_BYTES (htab))); } else { SPARC_ELF_PUT_WORD (htab, output_bfd, 0, - (htab->sgot->contents + off + (htab->elf.sgot->contents + off + SPARC_ELF_WORD_BYTES (htab))); outrel.r_info = SPARC_ELF_R_INFO (htab, NULL, indx, SPARC_ELF_DTPOFF_RELOC (htab)); outrel.r_offset += SPARC_ELF_WORD_BYTES (htab); - SPARC_ELF_APPEND_RELA (htab, output_bfd, htab->srelgot, &outrel); + sparc_elf_append_rela (output_bfd, htab->elf.srelgot, + &outrel); } } else if (dr_type == SPARC_ELF_DTPMOD_RELOC (htab)) { SPARC_ELF_PUT_WORD (htab, output_bfd, 0, - (htab->sgot->contents + off + (htab->elf.sgot->contents + off + SPARC_ELF_WORD_BYTES (htab))); } } @@ -2922,14 +3687,14 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (off >= (bfd_vma) -2) abort (); - relocation = htab->sgot->output_offset + off - got_base; + relocation = htab->elf.sgot->output_offset + off - got_base; unresolved_reloc = FALSE; howto = _bfd_sparc_elf_howto_table + r_type; break; case R_SPARC_TLS_LDM_HI22: case R_SPARC_TLS_LDM_LO10: - if (! info->shared) + if (! bfd_link_pic (info)) { bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset); continue; @@ -2940,7 +3705,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_TLS_LDO_HIX22: case R_SPARC_TLS_LDO_LOX10: - if (info->shared) + if (bfd_link_pic (info)) { relocation -= dtpoff_base (info); break; @@ -2952,10 +3717,10 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_TLS_LE_HIX22: case R_SPARC_TLS_LE_LOX10: - if (info->shared) + if (bfd_link_pic (info)) { Elf_Internal_Rela outrel; - bfd_boolean skip, relocate = FALSE; + bfd_boolean skip; BFD_ASSERT (sreloc != NULL); skip = FALSE; @@ -2965,7 +3730,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (outrel.r_offset == (bfd_vma) -1) skip = TRUE; else if (outrel.r_offset == (bfd_vma) -2) - skip = TRUE, relocate = TRUE; + skip = TRUE; outrel.r_offset += (input_section->output_section->vma + input_section->output_offset); if (skip) @@ -2977,14 +3742,14 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + rel->r_addend; } - SPARC_ELF_APPEND_RELA (htab, output_bfd, sreloc, &outrel); + sparc_elf_append_rela (output_bfd, sreloc, &outrel); continue; } relocation = tpoff (info, relocation); break; case R_SPARC_TLS_LDM_CALL: - if (! info->shared) + if (! bfd_link_pic (info)) { /* mov %g0, %o0 */ bfd_put_32 (output_bfd, 0x90100000, contents + rel->r_offset); @@ -2998,12 +3763,13 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, tls_type = _bfd_sparc_elf_local_got_tls_type (input_bfd) [r_symndx]; else if (h != NULL) tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type; - if (! info->shared + if (! bfd_link_pic (info) || (r_type == R_SPARC_TLS_GD_CALL && tls_type == GOT_TLS_IE)) { + Elf_Internal_Rela *rel2; bfd_vma insn; - if (!info->shared && (h == NULL || h->dynindx == -1)) + if (!bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) { /* GD -> LE */ bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset); @@ -3036,7 +3802,26 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, continue; } - bfd_put_32 (output_bfd, 0x9001c008, contents + rel->r_offset); + /* We cannot just overwrite the delay slot instruction, + as it might be what puts the %o0 argument to + __tls_get_addr into place. So we have to transpose + the delay slot with the add we patch in. */ + insn = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); + bfd_put_32 (output_bfd, insn, + contents + rel->r_offset); + bfd_put_32 (output_bfd, 0x9001c008, + contents + rel->r_offset + 4); + + rel2 = rel; + while ((rel2 = sparc_elf_find_reloc_at_ofs (rel2 + 1, relend, + rel->r_offset + 4)) + != NULL) + { + /* If the instruction we moved has a relocation attached to + it, adjust the offset so that it will apply to the correct + instruction. */ + rel2->r_offset -= 4; + } continue; } @@ -3054,7 +3839,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, tls_type = _bfd_sparc_elf_local_got_tls_type (input_bfd) [r_symndx]; else if (h != NULL) tls_type = _bfd_sparc_elf_hash_entry(h)->tls_type; - if (! info->shared || tls_type == GOT_TLS_IE) + if (! bfd_link_pic (info) || tls_type == GOT_TLS_IE) { /* add %reg1, %reg2, %reg3, %tgd_add(foo) changed into IE: @@ -3062,7 +3847,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, or LE: add %g7, %reg2, %reg3. */ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); - if ((h != NULL && h->dynindx != -1) || info->shared) + if ((h != NULL && h->dynindx != -1) || bfd_link_pic (info)) relocation = insn | (ABI_64_P (output_bfd) ? 0xc0580000 : 0xc0000000); else relocation = (insn & ~0x7c000) | 0x1c000; @@ -3071,12 +3856,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, continue; case R_SPARC_TLS_LDM_ADD: - if (! info->shared) + if (! bfd_link_pic (info)) bfd_put_32 (output_bfd, SPARC_NOP, contents + rel->r_offset); continue; case R_SPARC_TLS_LDO_ADD: - if (! info->shared) + if (! bfd_link_pic (info)) { /* Change rs1 into %g7. */ bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); @@ -3087,7 +3872,7 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_SPARC_TLS_IE_LD: case R_SPARC_TLS_IE_LDX: - if (! info->shared && (h == NULL || h->dynindx == -1)) + if (! bfd_link_pic (info) && (h == NULL || h->dynindx == -1)) { bfd_vma insn = bfd_get_32 (input_bfd, contents + rel->r_offset); int rs2 = insn & 0x1f; @@ -3119,12 +3904,15 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, not process them. */ if (unresolved_reloc && !((input_section->flags & SEC_DEBUGGING) != 0 - && h->def_dynamic)) + && h->def_dynamic) + && _bfd_elf_section_offset (output_bfd, info, input_section, + rel->r_offset) != (bfd_vma) -1) (*_bfd_error_handler) - (_("%B(%A+0x%lx): unresolvable relocation against symbol `%s'"), + (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, (long) rel->r_offset, + howto->name, h->root.root.string); r = bfd_reloc_continue; @@ -3161,6 +3949,25 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, | ((relocation >> 2) & 0x3fff)); bfd_put_32 (input_bfd, x, contents + rel->r_offset); + r = bfd_check_overflow (howto->complain_on_overflow, + howto->bitsize, howto->rightshift, + bfd_arch_bits_per_address (input_bfd), + relocation); + } + else if (r_type == R_SPARC_WDISP10) + { + bfd_vma x; + + relocation += rel->r_addend; + relocation -= (input_section->output_section->vma + + input_section->output_offset); + relocation -= rel->r_offset; + + x = bfd_get_32 (input_bfd, contents + rel->r_offset); + x |= ((((relocation >> 2) & 0x300) << 11) + | (((relocation >> 2) & 0xff) << 5)); + bfd_put_32 (input_bfd, x, contents + rel->r_offset); + r = bfd_check_overflow (howto->complain_on_overflow, howto->bitsize, howto->rightshift, bfd_arch_bits_per_address (input_bfd), @@ -3207,12 +4014,15 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, r = bfd_reloc_ok; } - else if (r_type == R_SPARC_HIX22) + else if (r_type == R_SPARC_HIX22 + || r_type == R_SPARC_GOTDATA_HIX22) { bfd_vma x; relocation += rel->r_addend; - relocation = relocation ^ MINUS_ONE; + if (r_type == R_SPARC_HIX22 + || (bfd_signed_vma) relocation < 0) + relocation = relocation ^ MINUS_ONE; x = bfd_get_32 (input_bfd, contents + rel->r_offset); x = (x & ~(bfd_vma) 0x3fffff) | ((relocation >> 10) & 0x3fffff); @@ -3223,12 +4033,17 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd_arch_bits_per_address (input_bfd), relocation); } - else if (r_type == R_SPARC_LOX10) + else if (r_type == R_SPARC_LOX10 + || r_type == R_SPARC_GOTDATA_LOX10) { bfd_vma x; relocation += rel->r_addend; - relocation = (relocation & 0x3ff) | 0x1c00; + if (r_type == R_SPARC_LOX10 + || (bfd_signed_vma) relocation < 0) + relocation = (relocation & 0x3ff) | 0x1c00; + else + relocation = (relocation & 0x3ff); x = bfd_get_32 (input_bfd, contents + rel->r_offset); x = (x & ~(bfd_vma) 0x1fff) | relocation; @@ -3328,10 +4143,12 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } if (r == bfd_reloc_continue) - r = _bfd_final_link_relocate (howto, input_bfd, input_section, - contents, rel->r_offset, - relocation, rel->r_addend); - + { +do_relocation: + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, rel->r_addend); + } if (r != bfd_reloc_ok) { switch (r) @@ -3343,8 +4160,36 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, { const char *name; + /* The Solaris native linker silently disregards overflows. + We don't, but this breaks stabs debugging info, whose + relocations are only 32-bits wide. Ignore overflows in + this case and also for discarded entries. */ + if ((r_type == R_SPARC_32 + || r_type == R_SPARC_UA32 + || r_type == R_SPARC_DISP32) + && (((input_section->flags & SEC_DEBUGGING) != 0 + && strcmp (bfd_section_name (input_bfd, + input_section), + ".stab") == 0) + || _bfd_elf_section_offset (output_bfd, info, + input_section, + rel->r_offset) + == (bfd_vma)-1)) + break; + if (h != NULL) - name = NULL; + { + /* Assume this is a call protected by other code that + detect the symbol is undefined. If this is the case, + we can safely ignore the overflow. If not, the + program is hosed anyway, and a little warning isn't + going to help. */ + if (h->root.type == bfd_link_hash_undefweak + && howto->pc_relative) + break; + + name = NULL; + } else { name = bfd_elf_string_from_elf_section (input_bfd, @@ -3355,11 +4200,9 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, if (*name == '\0') name = bfd_section_name (input_bfd, sec); } - if (! ((*info->callbacks->reloc_overflow) - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_offset))) - return FALSE; + (*info->callbacks->reloc_overflow) + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); } break; } @@ -3369,6 +4212,99 @@ _bfd_sparc_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, return TRUE; } +/* Build a VxWorks PLT entry. PLT_INDEX is the index of the PLT entry + and PLT_OFFSET is the byte offset from the start of .plt. GOT_OFFSET + is the offset of the associated .got.plt entry from + _GLOBAL_OFFSET_TABLE_. */ + +static void +sparc_vxworks_build_plt_entry (bfd *output_bfd, struct bfd_link_info *info, + bfd_vma plt_offset, bfd_vma plt_index, + bfd_vma got_offset) +{ + bfd_vma got_base; + const bfd_vma *plt_entry; + struct _bfd_sparc_elf_link_hash_table *htab; + bfd_byte *loc; + Elf_Internal_Rela rela; + + htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + if (bfd_link_pic (info)) + { + plt_entry = sparc_vxworks_shared_plt_entry; + got_base = 0; + } + else + { + plt_entry = sparc_vxworks_exec_plt_entry; + got_base = (htab->elf.hgot->root.u.def.value + + htab->elf.hgot->root.u.def.section->output_offset + + htab->elf.hgot->root.u.def.section->output_section->vma); + } + + /* Fill in the entry in the procedure linkage table. */ + bfd_put_32 (output_bfd, plt_entry[0] + ((got_base + got_offset) >> 10), + htab->elf.splt->contents + plt_offset); + bfd_put_32 (output_bfd, plt_entry[1] + ((got_base + got_offset) & 0x3ff), + htab->elf.splt->contents + plt_offset + 4); + bfd_put_32 (output_bfd, plt_entry[2], + htab->elf.splt->contents + plt_offset + 8); + bfd_put_32 (output_bfd, plt_entry[3], + htab->elf.splt->contents + plt_offset + 12); + bfd_put_32 (output_bfd, plt_entry[4], + htab->elf.splt->contents + plt_offset + 16); + bfd_put_32 (output_bfd, plt_entry[5] + (plt_index >> 10), + htab->elf.splt->contents + plt_offset + 20); + /* PC-relative displacement for a branch to the start of + the PLT section. */ + bfd_put_32 (output_bfd, plt_entry[6] + (((-plt_offset - 24) >> 2) + & 0x003fffff), + htab->elf.splt->contents + plt_offset + 24); + bfd_put_32 (output_bfd, plt_entry[7] + (plt_index & 0x3ff), + htab->elf.splt->contents + plt_offset + 28); + + /* Fill in the .got.plt entry, pointing initially at the + second half of the PLT entry. */ + BFD_ASSERT (htab->elf.sgotplt != NULL); + bfd_put_32 (output_bfd, + htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + + plt_offset + 20, + htab->elf.sgotplt->contents + got_offset); + + /* Add relocations to .rela.plt.unloaded. */ + if (!bfd_link_pic (info)) + { + loc = (htab->srelplt2->contents + + (2 + 3 * plt_index) * sizeof (Elf32_External_Rela)); + + /* Relocate the initial sethi. */ + rela.r_offset = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset + + plt_offset); + rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22); + rela.r_addend = got_offset; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Likewise the following or. */ + rela.r_offset += 4; + rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Relocate the .got.plt entry. */ + rela.r_offset = (htab->elf.sgotplt->output_section->vma + + htab->elf.sgotplt->output_offset + + got_offset); + rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32); + rela.r_addend = plt_offset + 20; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + } +} + /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ @@ -3378,11 +4314,12 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - bfd *dynobj; struct _bfd_sparc_elf_link_hash_table *htab; + const struct elf_backend_data *bed; htab = _bfd_sparc_elf_hash_table (info); - dynobj = htab->elf.dynobj; + BFD_ASSERT (htab != NULL); + bed = get_elf_backend_data (output_bfd); if (h->plt.offset != (bfd_vma) -1) { @@ -3390,36 +4327,113 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, asection *srela; Elf_Internal_Rela rela; bfd_byte *loc; - bfd_vma r_offset; + bfd_vma r_offset, got_offset; int rela_index; - /* This symbol has an entry in the PLT. Set it up. */ - - BFD_ASSERT (h->dynindx != -1); - - splt = htab->splt; - srela = htab->srelplt; - BFD_ASSERT (splt != NULL && srela != NULL); + /* When building a static executable, use .iplt and + .rela.iplt sections for STT_GNU_IFUNC symbols. */ + if (htab->elf.splt != NULL) + { + splt = htab->elf.splt; + srela = htab->elf.srelplt; + } + else + { + splt = htab->elf.iplt; + srela = htab->elf.irelplt; + } - /* Fill in the entry in the procedure linkage table. */ - rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt, - h->plt.offset, splt->size, - &r_offset); + if (splt == NULL || srela == NULL) + abort (); /* Fill in the entry in the .rela.plt section. */ - rela.r_offset = r_offset - + (splt->output_section->vma + splt->output_offset); - if (! ABI_64_P (output_bfd) - || h->plt.offset < (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE)) + if (htab->is_vxworks) { + /* Work out the index of this PLT entry. */ + rela_index = ((h->plt.offset - htab->plt_header_size) + / htab->plt_entry_size); + + /* Calculate the offset of the associated .got.plt entry. + The first three entries are reserved. */ + got_offset = (rela_index + 3) * 4; + + sparc_vxworks_build_plt_entry (output_bfd, info, h->plt.offset, + rela_index, got_offset); + + + /* On VxWorks, the relocation points to the .got.plt entry, + not the .plt entry. */ + rela.r_offset = (htab->elf.sgotplt->output_section->vma + + htab->elf.sgotplt->output_offset + + got_offset); rela.r_addend = 0; + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, + R_SPARC_JMP_SLOT); } else { - rela.r_addend = -(h->plt.offset + 4) - -(splt->output_section->vma + splt->output_offset); + bfd_boolean ifunc = FALSE; + + /* Fill in the entry in the procedure linkage table. */ + rela_index = SPARC_ELF_BUILD_PLT_ENTRY (htab, output_bfd, splt, + h->plt.offset, splt->size, + &r_offset); + + if (h == NULL + || h->dynindx == -1 + || ((bfd_link_executable (info) + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + && h->def_regular + && h->type == STT_GNU_IFUNC)) + { + ifunc = TRUE; + BFD_ASSERT (h == NULL + || (h->type == STT_GNU_IFUNC + && h->def_regular + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak))); + } + + rela.r_offset = r_offset + + (splt->output_section->vma + splt->output_offset); + if (ABI_64_P (output_bfd) + && h->plt.offset >= (PLT64_LARGE_THRESHOLD * PLT64_ENTRY_SIZE)) + { + if (ifunc) + { + rela.r_addend = (h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset + + h->root.u.def.value); + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, + R_SPARC_IRELATIVE); + } + else + { + rela.r_addend = (-(h->plt.offset + 4) + - splt->output_section->vma + - splt->output_offset); + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, + R_SPARC_JMP_SLOT); + } + } + else + { + if (ifunc) + { + rela.r_addend = (h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset + + h->root.u.def.value); + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, + R_SPARC_JMP_IREL); + } + else + { + rela.r_addend = 0; + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, + R_SPARC_JMP_SLOT); + } + } } - rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_JMP_SLOT); /* Adjust for the first 4 reserved elements in the .plt section when setting the offset in the .rela.plt section. @@ -3427,18 +4441,8 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, thus .plt[4] has corresponding .rela.plt[0] and so on. */ loc = srela->contents; -#ifdef BFD64 - if (ABI_64_P (output_bfd)) - { - loc += rela_index * sizeof (Elf64_External_Rela); - bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); - } - else -#endif - { - loc += rela_index * sizeof (Elf32_External_Rela); - bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); - } + loc += rela_index * bed->s->sizeof_rela; + bed->s->swap_reloca_out (output_bfd, &rela, loc); if (!h->def_regular) { @@ -3464,8 +4468,8 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, /* This symbol has an entry in the GOT. Set it up. */ - sgot = htab->sgot; - srela = htab->srelgot; + sgot = htab->elf.sgot; + srela = htab->elf.srelgot; BFD_ASSERT (sgot != NULL && srela != NULL); rela.r_offset = (sgot->output_section->vma @@ -3477,12 +4481,29 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, the symbol was forced to be local because of a version file. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (info->shared - && (info->symbolic || h->dynindx == -1) + if (! bfd_link_pic (info) + && h->type == STT_GNU_IFUNC && h->def_regular) + { + asection *plt; + + /* We load the GOT entry with the PLT entry. */ + plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; + SPARC_ELF_PUT_WORD (htab, output_bfd, + (plt->output_section->vma + + plt->output_offset + h->plt.offset), + htab->elf.sgot->contents + + (h->got.offset & ~(bfd_vma) 1)); + return TRUE; + } + else if (bfd_link_pic (info) + && SYMBOL_REFERENCES_LOCAL (info, h)) { asection *sec = h->root.u.def.section; - rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE); + if (h->type == STT_GNU_IFUNC) + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_IRELATIVE); + else + rela.r_info = SPARC_ELF_R_INFO (htab, NULL, 0, R_SPARC_RELATIVE); rela.r_addend = (h->root.u.def.value + sec->output_section->vma + sec->output_offset); @@ -3495,7 +4516,7 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, SPARC_ELF_PUT_WORD (htab, output_bfd, 0, sgot->contents + (h->got.offset & ~(bfd_vma) 1)); - SPARC_ELF_APPEND_RELA (htab, output_bfd, srela, &rela); + sparc_elf_append_rela (output_bfd, srela, &rela); } if (h->needs_copy) @@ -3506,8 +4527,8 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, /* This symbols needs a copy reloc. Set it up. */ BFD_ASSERT (h->dynindx != -1); - s = bfd_get_section_by_name (h->root.u.def.section->owner, - ".rela.bss"); + s = bfd_get_linker_section (h->root.u.def.section->owner, + ".rela.bss"); BFD_ASSERT (s != NULL); rela.r_offset = (h->root.u.def.value @@ -3515,13 +4536,16 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, + h->root.u.def.section->output_offset); rela.r_info = SPARC_ELF_R_INFO (htab, NULL, h->dynindx, R_SPARC_COPY); rela.r_addend = 0; - SPARC_ELF_APPEND_RELA (htab, output_bfd, s, &rela); + sparc_elf_append_rela (output_bfd, s, &rela); } - /* Mark some specially defined symbols as absolute. */ - if (strcmp (h->root.root.string, "_DYNAMIC") == 0 - || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0 - || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0) + /* Mark some specially defined symbols as absolute. On VxWorks, + _GLOBAL_OFFSET_TABLE_ is not absolute: it is relative to the + ".got" section. Likewise _PROCEDURE_LINKAGE_TABLE_ and ".plt". */ + if (sym != NULL + && (h == htab->elf.hdynamic + || (!htab->is_vxworks + && (h == htab->elf.hgot || h == htab->elf.hplt)))) sym->st_shndx = SHN_ABS; return TRUE; @@ -3529,31 +4553,58 @@ _bfd_sparc_elf_finish_dynamic_symbol (bfd *output_bfd, /* Finish up the dynamic sections. */ -#ifdef BFD64 static bfd_boolean -sparc64_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, - bfd *dynobj, asection *sdyn, - asection *splt ATTRIBUTE_UNUSED) +sparc_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, + bfd *dynobj, asection *sdyn, + asection *splt ATTRIBUTE_UNUSED) { - Elf64_External_Dyn *dyncon, *dynconend; + struct _bfd_sparc_elf_link_hash_table *htab; + const struct elf_backend_data *bed; + bfd_byte *dyncon, *dynconend; + size_t dynsize; int stt_regidx = -1; + bfd_boolean abi_64_p; - dyncon = (Elf64_External_Dyn *) sdyn->contents; - dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) + htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + bed = get_elf_backend_data (output_bfd); + dynsize = bed->s->sizeof_dyn; + dynconend = sdyn->contents + sdyn->size; + abi_64_p = ABI_64_P (output_bfd); + for (dyncon = sdyn->contents; dyncon < dynconend; dyncon += dynsize) { Elf_Internal_Dyn dyn; const char *name; bfd_boolean size; - bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); + bed->s->swap_dyn_in (dynobj, dyncon, &dyn); - switch (dyn.d_tag) + if (htab->is_vxworks && dyn.d_tag == DT_RELASZ) + { + /* On VxWorks, DT_RELASZ should not include the relocations + in .rela.plt. */ + if (htab->elf.srelplt) + { + dyn.d_un.d_val -= htab->elf.srelplt->size; + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + else if (htab->is_vxworks && dyn.d_tag == DT_PLTGOT) + { + /* On VxWorks, DT_PLTGOT should point to the start of the GOT, + not to the start of the PLT. */ + if (htab->elf.sgotplt) + { + dyn.d_un.d_val = (htab->elf.sgotplt->output_section->vma + + htab->elf.sgotplt->output_offset); + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); + } + } + else if (htab->is_vxworks + && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); + else if (abi_64_p && dyn.d_tag == DT_SPARC_REGISTER) { - case DT_PLTGOT: name = ".plt"; size = FALSE; break; - case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break; - case DT_JMPREL: name = ".rela.plt"; size = FALSE; break; - case DT_SPARC_REGISTER: if (stt_regidx == -1) { stt_regidx = @@ -3562,76 +4613,147 @@ sparc64_finish_dyn (bfd *output_bfd, struct bfd_link_info *info, return FALSE; } dyn.d_un.d_val = stt_regidx++; - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); - /* fallthrough */ - default: name = NULL; size = FALSE; break; + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } - - if (name != NULL) + else { - asection *s; + switch (dyn.d_tag) + { + case DT_PLTGOT: name = ".plt"; size = FALSE; break; + case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break; + case DT_JMPREL: name = ".rela.plt"; size = FALSE; break; + default: name = NULL; size = FALSE; break; + } - s = bfd_get_section_by_name (output_bfd, name); - if (s == NULL) - dyn.d_un.d_val = 0; - else + if (name != NULL) { - if (! size) - dyn.d_un.d_ptr = s->vma; + asection *s; + + s = bfd_get_linker_section (dynobj, name); + if (s == NULL) + dyn.d_un.d_val = 0; else - dyn.d_un.d_val = s->size; + { + if (! size) + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + else + dyn.d_un.d_val = s->size; + } + bed->s->swap_dyn_out (output_bfd, &dyn, dyncon); } - bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); } } return TRUE; } -#endif -static bfd_boolean -sparc32_finish_dyn (bfd *output_bfd, - struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *dynobj, asection *sdyn, - asection *splt ATTRIBUTE_UNUSED) +/* Install the first PLT entry in a VxWorks executable and make sure that + .rela.plt.unloaded relocations have the correct symbol indexes. */ + +static void +sparc_vxworks_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info) { - Elf32_External_Dyn *dyncon, *dynconend; + struct _bfd_sparc_elf_link_hash_table *htab; + Elf_Internal_Rela rela; + bfd_vma got_base; + bfd_byte *loc; - dyncon = (Elf32_External_Dyn *) sdyn->contents; - dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); - for (; dyncon < dynconend; dyncon++) + htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); + + /* Calculate the absolute value of _GLOBAL_OFFSET_TABLE_. */ + got_base = (htab->elf.hgot->root.u.def.section->output_section->vma + + htab->elf.hgot->root.u.def.section->output_offset + + htab->elf.hgot->root.u.def.value); + + /* Install the initial PLT entry. */ + bfd_put_32 (output_bfd, + sparc_vxworks_exec_plt0_entry[0] + ((got_base + 8) >> 10), + htab->elf.splt->contents); + bfd_put_32 (output_bfd, + sparc_vxworks_exec_plt0_entry[1] + ((got_base + 8) & 0x3ff), + htab->elf.splt->contents + 4); + bfd_put_32 (output_bfd, + sparc_vxworks_exec_plt0_entry[2], + htab->elf.splt->contents + 8); + bfd_put_32 (output_bfd, + sparc_vxworks_exec_plt0_entry[3], + htab->elf.splt->contents + 12); + bfd_put_32 (output_bfd, + sparc_vxworks_exec_plt0_entry[4], + htab->elf.splt->contents + 16); + + loc = htab->srelplt2->contents; + + /* Add an unloaded relocation for the initial entry's "sethi". */ + rela.r_offset = (htab->elf.splt->output_section->vma + + htab->elf.splt->output_offset); + rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22); + rela.r_addend = 8; + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Likewise the following "or". */ + rela.r_offset += 4; + rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10); + bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); + loc += sizeof (Elf32_External_Rela); + + /* Fix up the remaining .rela.plt.unloaded relocations. They may have + the wrong symbol index for _G_O_T_ or _P_L_T_ depending on the order + in which symbols were output. */ + while (loc < htab->srelplt2->contents + htab->srelplt2->size) { - Elf_Internal_Dyn dyn; - const char *name; - bfd_boolean size; + Elf_Internal_Rela rel; + + /* The entry's initial "sethi" (against _G_O_T_). */ + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_HI22); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + + /* The following "or" (also against _G_O_T_). */ + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_SPARC_LO10); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + + /* The .got.plt entry (against _P_L_T_). */ + bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_SPARC_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + loc += sizeof (Elf32_External_Rela); + } +} - bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); +/* Install the first PLT entry in a VxWorks shared object. */ - switch (dyn.d_tag) - { - case DT_PLTGOT: name = ".plt"; size = FALSE; break; - case DT_PLTRELSZ: name = ".rela.plt"; size = TRUE; break; - case DT_JMPREL: name = ".rela.plt"; size = FALSE; break; - default: name = NULL; size = FALSE; break; - } +static void +sparc_vxworks_finish_shared_plt (bfd *output_bfd, struct bfd_link_info *info) +{ + struct _bfd_sparc_elf_link_hash_table *htab; + unsigned int i; - if (name != NULL) - { - asection *s; + htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); - s = bfd_get_section_by_name (output_bfd, name); - if (s == NULL) - dyn.d_un.d_val = 0; - else - { - if (! size) - dyn.d_un.d_ptr = s->vma; - else - dyn.d_un.d_val = s->size; - } - bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); - } - } - return TRUE; + for (i = 0; i < ARRAY_SIZE (sparc_vxworks_shared_plt0_entry); i++) + bfd_put_32 (output_bfd, sparc_vxworks_shared_plt0_entry[i], + htab->elf.splt->contents + i * 4); +} + +/* Finish up local dynamic symbol handling. We set the contents of + various dynamic sections here. */ + +static bfd_boolean +finish_local_dynamic_symbol (void **slot, void *inf) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) *slot; + struct bfd_link_info *info + = (struct bfd_link_info *) inf; + + return _bfd_sparc_elf_finish_dynamic_symbol (info->output_bfd, info, + h, NULL); } bfd_boolean @@ -3642,60 +4764,64 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i struct _bfd_sparc_elf_link_hash_table *htab; htab = _bfd_sparc_elf_hash_table (info); + BFD_ASSERT (htab != NULL); dynobj = htab->elf.dynobj; - sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + sdyn = bfd_get_linker_section (dynobj, ".dynamic"); if (elf_hash_table (info)->dynamic_sections_created) { asection *splt; - bfd_boolean ret; - splt = bfd_get_section_by_name (dynobj, ".plt"); + splt = htab->elf.splt; BFD_ASSERT (splt != NULL && sdyn != NULL); -#ifdef BFD64 - if (ABI_64_P (output_bfd)) - ret = sparc64_finish_dyn (output_bfd, info, dynobj, sdyn, splt); - else -#endif - ret = sparc32_finish_dyn (output_bfd, info, dynobj, sdyn, splt); - - if (ret != TRUE) - return ret; + if (!sparc_finish_dyn (output_bfd, info, dynobj, sdyn, splt)) + return FALSE; /* Initialize the contents of the .plt section. */ if (splt->size > 0) { - if (ABI_64_P (output_bfd)) - memset (splt->contents, 0, 4 * PLT64_ENTRY_SIZE); + if (htab->is_vxworks) + { + if (bfd_link_pic (info)) + sparc_vxworks_finish_shared_plt (output_bfd, info); + else + sparc_vxworks_finish_exec_plt (output_bfd, info); + } else { - memset (splt->contents, 0, 4 * PLT32_ENTRY_SIZE); - bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP, - splt->contents + splt->size - 4); + memset (splt->contents, 0, htab->plt_header_size); + if (!ABI_64_P (output_bfd)) + bfd_put_32 (output_bfd, (bfd_vma) SPARC_NOP, + splt->contents + splt->size - 4); } } - elf_section_data (splt->output_section)->this_hdr.sh_entsize = - (ABI_64_P (output_bfd) ? PLT64_ENTRY_SIZE : PLT32_ENTRY_SIZE); + if (elf_section_data (splt->output_section) != NULL) + elf_section_data (splt->output_section)->this_hdr.sh_entsize + = ((htab->is_vxworks || !ABI_64_P (output_bfd)) + ? 0 : htab->plt_entry_size); } /* Set the first entry in the global offset table to the address of the dynamic section. */ - if (htab->sgot && htab->sgot->size > 0) + if (htab->elf.sgot && htab->elf.sgot->size > 0) { bfd_vma val = (sdyn ? sdyn->output_section->vma + sdyn->output_offset : 0); - SPARC_ELF_PUT_WORD (htab, output_bfd, val, htab->sgot->contents); + SPARC_ELF_PUT_WORD (htab, output_bfd, val, htab->elf.sgot->contents); } - if (htab->sgot) - elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = + if (htab->elf.sgot) + elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = SPARC_ELF_WORD_BYTES (htab); + /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ + htab_traverse (htab->loc_hash_table, finish_local_dynamic_symbol, info); + return TRUE; } @@ -3705,11 +4831,49 @@ _bfd_sparc_elf_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *i bfd_boolean _bfd_sparc_elf_object_p (bfd *abfd) { + obj_attribute *attrs = elf_known_obj_attributes (abfd)[OBJ_ATTR_GNU]; + obj_attribute *hwcaps = &attrs[Tag_GNU_Sparc_HWCAPS]; + obj_attribute *hwcaps2 = &attrs[Tag_GNU_Sparc_HWCAPS2]; + + unsigned int v9c_hwcaps_mask = ELF_SPARC_HWCAP_ASI_BLK_INIT; + unsigned int v9d_hwcaps_mask = (ELF_SPARC_HWCAP_FMAF + | ELF_SPARC_HWCAP_VIS3 + | ELF_SPARC_HWCAP_HPC); + unsigned int v9e_hwcaps_mask = (ELF_SPARC_HWCAP_AES + | ELF_SPARC_HWCAP_DES + | ELF_SPARC_HWCAP_KASUMI + | ELF_SPARC_HWCAP_CAMELLIA + | ELF_SPARC_HWCAP_MD5 + | ELF_SPARC_HWCAP_SHA1 + | ELF_SPARC_HWCAP_SHA256 + | ELF_SPARC_HWCAP_SHA512 + | ELF_SPARC_HWCAP_MPMUL + | ELF_SPARC_HWCAP_MONT + | ELF_SPARC_HWCAP_CRC32C + | ELF_SPARC_HWCAP_CBCOND + | ELF_SPARC_HWCAP_PAUSE); + unsigned int v9v_hwcaps_mask = (ELF_SPARC_HWCAP_FJFMAU + | ELF_SPARC_HWCAP_IMA); + unsigned int v9m_hwcaps2_mask = (ELF_SPARC_HWCAP2_SPARC5 + | ELF_SPARC_HWCAP2_MWAIT + | ELF_SPARC_HWCAP2_XMPMUL + | ELF_SPARC_HWCAP2_XMONT); + if (ABI_64_P (abfd)) { unsigned long mach = bfd_mach_sparc_v9; - if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3) + if (hwcaps2->i & v9m_hwcaps2_mask) + mach = bfd_mach_sparc_v9m; + else if (hwcaps->i & v9v_hwcaps_mask) + mach = bfd_mach_sparc_v9v; + else if (hwcaps->i & v9e_hwcaps_mask) + mach = bfd_mach_sparc_v9e; + else if (hwcaps->i & v9d_hwcaps_mask) + mach = bfd_mach_sparc_v9d; + else if (hwcaps->i & v9c_hwcaps_mask) + mach = bfd_mach_sparc_v9c; + else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3) mach = bfd_mach_sparc_v9b; else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1) mach = bfd_mach_sparc_v9a; @@ -3719,7 +4883,22 @@ _bfd_sparc_elf_object_p (bfd *abfd) { if (elf_elfheader (abfd)->e_machine == EM_SPARC32PLUS) { - if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3) + if (hwcaps2->i & v9m_hwcaps2_mask) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusm); + else if (hwcaps->i & v9v_hwcaps_mask) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusv); + else if (hwcaps->i & v9e_hwcaps_mask) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8pluse); + else if (hwcaps->i & v9d_hwcaps_mask) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusd); + else if (hwcaps->i & v9c_hwcaps_mask) + return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, + bfd_mach_sparc_v8plusc); + else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US3) return bfd_default_set_arch_mach (abfd, bfd_arch_sparc, bfd_mach_sparc_v8plusb); else if (elf_elfheader (abfd)->e_flags & EF_SPARC_SUN_US1) @@ -3760,3 +4939,46 @@ _bfd_sparc_elf_plt_sym_val (bfd_vma i, const asection *plt, const arelent *rel) else return rel->address; } + +/* Merge backend specific data from an object file to the output + object file when linking. */ + +bfd_boolean +_bfd_sparc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) +{ + obj_attribute *in_attr, *in_attrs; + obj_attribute *out_attr, *out_attrs; + + if (!elf_known_obj_attributes_proc (obfd)[0].i) + { + /* This is the first object. Copy the attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); + + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + elf_known_obj_attributes_proc (obfd)[0].i = 1; + + return TRUE; + } + + in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; + + in_attr = &in_attrs[Tag_GNU_Sparc_HWCAPS]; + out_attr = &out_attrs[Tag_GNU_Sparc_HWCAPS]; + + out_attr->i |= in_attr->i; + out_attr->type = 1; + + in_attr = &in_attrs[Tag_GNU_Sparc_HWCAPS2]; + out_attr = &out_attrs[Tag_GNU_Sparc_HWCAPS2]; + + out_attr->i |= in_attr->i; + out_attr->type = 1; + + + /* Merge Tag_compatibility attributes and any common GNU ones. */ + _bfd_elf_merge_object_attributes (ibfd, obfd); + + return TRUE; +}