/* SPARC-specific support for ELF
- Copyright 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005-2015 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,
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)
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;
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)
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;
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;
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;
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 =
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;
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;
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];
}
}
#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);
-}
-
-static void
-sparc_elf_append_rela_64 (bfd *abfd ATTRIBUTE_UNUSED,
- asection *s ATTRIBUTE_UNUSED,
- Elf_Internal_Rela *rel ATTRIBUTE_UNUSED)
-{
-#ifdef BFD64
- Elf64_External_Rela *loc64;
-
- loc64 = (Elf64_External_Rela *) s->contents;
- loc64 += s->reloc_count++;
- bfd_elf64_swap_reloca_out (abfd, rel, (bfd_byte *) loc64);
-#endif
+ bfd_put_64 (abfd, val, ptr);
}
static void
-sparc_elf_append_rela_32 (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
+sparc_elf_append_rela (bfd *abfd, asection *s, Elf_Internal_Rela *rel)
{
- Elf32_External_Rela *loc32;
+ const struct elf_backend_data *bed;
+ bfd_byte *loc;
- 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));
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
{
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))
{
*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);
ofs = offset % block_size;
- index = (PLT64_LARGE_THRESHOLD +
+ plt_index = (PLT64_LARGE_THRESHOLD +
(block * 160) +
(ofs / insn_chunk_size));
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)
#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 *
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;
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;
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
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");
+ htab->sdynbss = bfd_get_linker_section (dynobj, ".dynbss");
if (!info->shared)
- htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss");
+ htab->srelbss = bfd_get_linker_section (dynobj, ".rela.bss");
- if (!htab->splt || !htab->srelplt || !htab->sdynbss
+ if (htab->is_vxworks)
+ {
+ if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
+ return FALSE;
+ if (info->shared)
+ {
+ 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
|| (!info->shared && !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)
{
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; )
{
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
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;
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);
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. */
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. */
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:
_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];
}
}
}
- 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;
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. */
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:
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;
&& (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
&& (sec->flags & SEC_ALLOC) != 0
&& h != NULL
&& (h->root.type == bfd_link_hash_defweak
- || !h->def_regular)))
+ || !h->def_regular))
+ || (!info->shared
+ && h != NULL
+ && h->type == STT_GNU_IFUNC))
{
struct _bfd_sparc_elf_dyn_relocs *p;
struct _bfd_sparc_elf_dyn_relocs **head;
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);
-
- if (htab->elf.dynobj == NULL)
- htab->elf.dynobj = abfd;
- dynobj = htab->elf.dynobj;
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->elf.dynobj, htab->word_align_power,
+ abfd, /*rela?*/ TRUE);
- 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
/* 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;
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;
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 !info->executable. */
+ if (info->shared)
+ {
+ 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;
}
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
+ if (info->relocatable)
+ 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);
}
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:
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)
}
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;
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:
case R_SPARC_H44:
case R_SPARC_M44:
case R_SPARC_L44:
+ case R_SPARC_H34:
case R_SPARC_UA64:
if (info->shared)
break;
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
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
&& (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
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)
{
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;
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. */
return FALSE;
}
- if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)
+ || (h->type == STT_GNU_IFUNC
+ && h->def_regular))
{
- asection *s = htab->splt;
+ asection *s = htab->elf.splt;
+
+ if (s == NULL)
+ s = htab->elf.iplt;
- /* The first four entries in .plt is reserved. */
+ /* 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 && !info->shared)
+ 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. */
}
/* 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 (!info->shared)
+ htab->srelplt2->size += sizeof (Elf32_External_Rela) * 3;
+ }
}
else
{
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. */
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);
+ htab->elf.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 += SPARC_ELF_RELA_BYTES (htab);
}
else
h->got.offset = (bfd_vma) -1;
if (info->shared)
{
- if (h->def_regular
- && (h->forced_local
- || info->symbolic))
+ if (SYMBOL_CALLS_LOCAL (info, h))
{
struct _bfd_sparc_elf_dyn_relocs **pp;
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
{
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)
{
bfd *ibfd;
htab = _bfd_sparc_elf_hash_table (info);
+ BFD_ASSERT (htab != NULL);
dynobj = htab->elf.dynobj;
BFD_ASSERT (dynobj != NULL);
/* Set the contents of the .interp section to the interpreter. */
if (info->executable)
{
- 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;
/* 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;
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))
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;
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)
{
/* 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)
+ && !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 (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
+ 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;
}
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;
}
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)
/* 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)
{
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;
eht->dynsymcount++;
}
}
+ if (htab->is_vxworks
+ && !elf_vxworks_add_dynamic_entries (output_bfd, info))
+ return FALSE;
}
#undef add_dynamic_entry
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);
}
struct bfd_link_info *link_info ATTRIBUTE_UNUSED,
bfd_boolean *again)
{
+ if (link_info->relocatable)
+ (*link_info->callbacks->einfo)
+ (_("%P%F: --relax and -r may not be used together\n"));
+
*again = FALSE;
sec_do_relax (section) = 1;
return TRUE;
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;
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);
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 && info->shared
+ && !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;
}
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;
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
+
+ if (!info->relocatable
+ && 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
}
}
+ if (sec != NULL && discarded_section (sec))
+ RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
+ rel, 1, relend, howto, 0, contents);
+
+ if (info->relocatable)
+ 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 (info->shared && 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
+ || info->executable)
+ {
+ 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 (info->shared)
+ 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)
if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
|| (info->shared
- && (info->symbolic
- || h->dynindx == -1
- || h->forced_local)
- && h->def_regular))
+ && SYMBOL_REFERENCES_LOCAL (info, h)))
{
/* This is actually a static link, or it is a
-Bsymbolic link and the symbol is defined
else
{
SPARC_ELF_PUT_WORD (htab, output_bfd, relocation,
- htab->sgot->contents + off);
+ htab->elf.sgot->contents + off);
h->got.offset |= 1;
}
}
/* 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:
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
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)
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:
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
|| 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))))
+ || !SYMBOL_CALLS_LOCAL (info, h)))
|| (!info->shared
&& h != NULL
&& h->dynindx != -1
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
+ && (! is_plt
+ || !info->shared
+ || !SYMBOLIC_BIND (info, h)
|| !h->def_regular))
{
BFD_ASSERT (h->dynindx != -1);
{
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;
{
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)
}
}
- 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. */
}
r_sparc_tlsldm:
- if (htab->sgot == NULL)
+ if (htab->elf.sgot == NULL)
abort ();
if ((off & 1) != 0)
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)
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)
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)));
}
}
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;
if (info->shared)
{
Elf_Internal_Rela outrel;
- bfd_boolean skip, relocate = FALSE;
+ bfd_boolean skip;
BFD_ASSERT (sreloc != NULL);
skip = FALSE;
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)
+ 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);
if (! info->shared
|| (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))
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;
}
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;
| ((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),
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);
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;
}
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)
{
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,
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 (info->shared)
+ {
+ 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 (!info->shared)
+ {
+ 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. */
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)
{
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
+ || ((info->executable
+ || 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.
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)
{
/* 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
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 (! info->shared
+ && 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 (info->shared
+ && 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);
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)
/* 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
+ 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;
/* 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 =
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_section_by_name (output_bfd, 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->vma;
+ 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
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 (info->shared)
+ 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;
}
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;
+}