#include "elf/or1k.h"
#include "libiberty.h"
+#define N_ONES(X) (((bfd_vma)2 << (X)) - 1)
+
#define PLT_ENTRY_SIZE 20
#define PLT0_ENTRY_WORD0 0x19800000 /* l.movhi r12, 0 <- hi(.got+4) */
26, /* Bitsize. */
TRUE, /* PC_relative. */
0, /* Bitpos. */
- complain_overflow_dont, /* Complain on overflow. */
+ complain_overflow_signed, /* Complain on overflow. */
bfd_elf_generic_reloc,/* Special Function. */
"R_OR1K_PLT26", /* Name. */
FALSE, /* Partial Inplace. */
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
+ HOWTO (R_OR1K_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_TPOFF", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_TLS_DTPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_DTPOFF", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_TLS_DTPMOD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_DTPMOD", /* name */
+ FALSE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_AHI16, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_AHI16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_GOTOFF_AHI16, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_GOTOFF_AHI16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_TLS_IE_AHI16, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_IE_AHI16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_TLS_LE_AHI16, /* type */
+ 16, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_LE_AHI16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_SLO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_SLO16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_GOTOFF_SLO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_GOTOFF_SLO16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_OR1K_TLS_LE_SLO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_OR1K_TLS_LE_SLO16", /* name */
+ FALSE, /* partial_inplace */
+ 0x0, /* src_mask */
+ 0xffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* Map BFD reloc types to Or1k ELF reloc types. */
{ BFD_RELOC_8, R_OR1K_8 },
{ BFD_RELOC_LO16, R_OR1K_LO_16_IN_INSN },
{ BFD_RELOC_HI16, R_OR1K_HI_16_IN_INSN },
+ { BFD_RELOC_HI16_S, R_OR1K_AHI16 },
{ BFD_RELOC_OR1K_REL_26, R_OR1K_INSN_REL_26 },
{ BFD_RELOC_VTABLE_ENTRY, R_OR1K_GNU_VTENTRY },
{ BFD_RELOC_VTABLE_INHERIT, R_OR1K_GNU_VTINHERIT },
{ BFD_RELOC_32_PCREL, R_OR1K_32_PCREL },
{ BFD_RELOC_16_PCREL, R_OR1K_16_PCREL },
{ BFD_RELOC_8_PCREL, R_OR1K_8_PCREL },
+ { BFD_RELOC_LO16_GOTOFF, R_OR1K_GOTOFF_LO16 },
+ { BFD_RELOC_HI16_GOTOFF, R_OR1K_GOTOFF_HI16 },
+ { BFD_RELOC_HI16_S_GOTOFF, R_OR1K_GOTOFF_AHI16 },
{ BFD_RELOC_OR1K_GOTPC_HI16, R_OR1K_GOTPC_HI16 },
{ BFD_RELOC_OR1K_GOTPC_LO16, R_OR1K_GOTPC_LO16 },
{ BFD_RELOC_OR1K_GOT16, R_OR1K_GOT16 },
{ BFD_RELOC_OR1K_PLT26, R_OR1K_PLT26 },
- { BFD_RELOC_OR1K_GOTOFF_HI16, R_OR1K_GOTOFF_HI16 },
- { BFD_RELOC_OR1K_GOTOFF_LO16, R_OR1K_GOTOFF_LO16 },
{ BFD_RELOC_OR1K_GLOB_DAT, R_OR1K_GLOB_DAT },
{ BFD_RELOC_OR1K_COPY, R_OR1K_COPY },
{ BFD_RELOC_OR1K_JMP_SLOT, R_OR1K_JMP_SLOT },
{ BFD_RELOC_OR1K_TLS_LDO_LO16, R_OR1K_TLS_LDO_LO16 },
{ BFD_RELOC_OR1K_TLS_IE_HI16, R_OR1K_TLS_IE_HI16 },
{ BFD_RELOC_OR1K_TLS_IE_LO16, R_OR1K_TLS_IE_LO16 },
+ { BFD_RELOC_OR1K_TLS_IE_AHI16, R_OR1K_TLS_IE_AHI16 },
{ BFD_RELOC_OR1K_TLS_LE_HI16, R_OR1K_TLS_LE_HI16 },
{ BFD_RELOC_OR1K_TLS_LE_LO16, R_OR1K_TLS_LE_LO16 },
+ { BFD_RELOC_OR1K_TLS_LE_AHI16, R_OR1K_TLS_LE_AHI16 },
+ { BFD_RELOC_OR1K_SLO16, R_OR1K_SLO16 },
+ { BFD_RELOC_OR1K_GOTOFF_SLO16, R_OR1K_GOTOFF_SLO16 },
+ { BFD_RELOC_OR1K_TLS_LE_SLO16, R_OR1K_TLS_LE_SLO16 },
};
#define TLS_UNKNOWN 0
static reloc_howto_type *
or1k_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
- bfd_reloc_code_real_type code)
+ bfd_reloc_code_real_type bcode)
{
unsigned int i;
- for (i = ARRAY_SIZE (or1k_reloc_map); i--;)
- if (or1k_reloc_map[i].bfd_reloc_val == code)
- return & or1k_elf_howto_table[or1k_reloc_map[i].or1k_reloc_val];
+ for (i = 0; i < ARRAY_SIZE (or1k_reloc_map); i++)
+ if (or1k_reloc_map[i].bfd_reloc_val == bcode)
+ {
+ unsigned int ocode = or1k_reloc_map[i].or1k_reloc_val;
+ if (ocode < (unsigned int) R_OR1K_max)
+ return &or1k_elf_howto_table[ocode];
+ else
+ break;
+ }
return NULL;
}
{
unsigned int i;
- for (i = 0;
- i < (sizeof (or1k_elf_howto_table)
- / sizeof (or1k_elf_howto_table[0]));
- i++)
+ for (i = 0; i < R_OR1K_max; i++)
if (or1k_elf_howto_table[i].name != NULL
&& strcasecmp (or1k_elf_howto_table[i].name, r_name) == 0)
return &or1k_elf_howto_table[i];
return (address - elf_hash_table (info)->tls_sec->vma);
}
+/* Like _bfd_final_link_relocate, but handles non-contiguous fields. */
+
+static bfd_reloc_status_type
+or1k_final_link_relocate (reloc_howto_type *howto, bfd *input_bfd,
+ asection *input_section, bfd_byte *contents,
+ bfd_vma offset, bfd_vma value)
+{
+ bfd_reloc_status_type status = bfd_reloc_ok;
+ int size = bfd_get_reloc_size (howto);
+ bfd_vma x;
+
+ /* Sanity check the address. */
+ if (offset + size > bfd_get_section_limit_octets (input_bfd, input_section))
+ return bfd_reloc_outofrange;
+
+ if (howto->pc_relative)
+ {
+ value -= (input_section->output_section->vma
+ + input_section->output_offset);
+ if (howto->pcrel_offset)
+ value -= offset;
+ }
+
+ switch (howto->type)
+ {
+ case R_OR1K_AHI16:
+ case R_OR1K_GOTOFF_AHI16:
+ case R_OR1K_TLS_IE_AHI16:
+ case R_OR1K_TLS_LE_AHI16:
+ /* Adjust the operand to match with a signed LO16. */
+ value += 0x8000;
+ break;
+
+ case R_OR1K_INSN_REL_26:
+ /* Diagnose mis-aligned branch targets. */
+ if (value & 3)
+ status = bfd_reloc_dangerous;
+ break;
+ }
+
+ status = bfd_check_overflow (howto->complain_on_overflow,
+ howto->bitsize,
+ howto->rightshift,
+ bfd_arch_bits_per_address (input_bfd),
+ value);
+ value >>= howto->rightshift;
+
+ /* If we're overwriting the entire destination,
+ then no need to read the current contents. */
+ if (size == 0 || howto->dst_mask == N_ONES (size))
+ x = 0;
+ else
+ {
+ BFD_ASSERT (size == 4);
+ x = bfd_get_32 (input_bfd, contents + offset);
+ }
+
+ switch (howto->type)
+ {
+ case R_OR1K_SLO16:
+ case R_OR1K_GOTOFF_SLO16:
+ case R_OR1K_TLS_LE_SLO16:
+ /* The split imm16 field used for stores. */
+ x = (x & ~0x3e007ff) | ((value & 0xf800) << 10) | (value & 0x7ff);
+ break;
+
+ default:
+ {
+ bfd_vma fieldmask = howto->dst_mask;
+ value <<= howto->bitpos;
+ x = (x & ~fieldmask) | (value & fieldmask);
+ }
+ break;
+ }
+
+ /* Put the relocated value back in the object file. */
+ switch (size)
+ {
+ case 0:
+ break;
+ case 1:
+ bfd_put_8 (input_bfd, x, contents + offset);
+ break;
+ case 2:
+ bfd_put_16 (input_bfd, x, contents + offset);
+ break;
+ case 4:
+ bfd_put_32 (input_bfd, x, contents + offset);
+ break;
+#ifdef BFD64
+ case 8:
+ bfd_put_64 (input_bfd, x, contents + offset);
+ break;
+#endif
+ default:
+ _bfd_error_handler
+ (_("%pB: Cannot handle relocation value size of %d"),
+ input_bfd, size);
+ abort ();
+ }
+ return status;
+}
+
/* Relocate an Or1k ELF section.
The RELOCATE_SECTION function is called by the new ELF backend linker
case R_OR1K_GOTOFF_LO16:
case R_OR1K_GOTOFF_HI16:
+ case R_OR1K_GOTOFF_AHI16:
+ case R_OR1K_GOTOFF_SLO16:
/* Relocation is offset from GOT. */
BFD_ASSERT (sgot != NULL);
relocation
case R_OR1K_INSN_REL_26:
case R_OR1K_HI_16_IN_INSN:
case R_OR1K_LO_16_IN_INSN:
+ case R_OR1K_AHI16:
+ case R_OR1K_SLO16:
case R_OR1K_32:
/* R_OR1K_16? */
{
bfd_set_error (bfd_error_bad_value);
return FALSE;
-
case R_OR1K_TLS_GD_HI16:
case R_OR1K_TLS_GD_LO16:
case R_OR1K_TLS_IE_HI16:
case R_OR1K_TLS_IE_LO16:
+ case R_OR1K_TLS_IE_AHI16:
{
bfd_vma gotoff;
Elf_Internal_Rela rela;
relocation = sgot->output_offset + gotoff;
break;
}
+
case R_OR1K_TLS_LE_HI16:
case R_OR1K_TLS_LE_LO16:
-
+ case R_OR1K_TLS_LE_AHI16:
+ case R_OR1K_TLS_LE_SLO16:
/* Relocation is offset from TP. */
relocation = tpoff (info, relocation);
break;
default:
break;
}
- r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents,
- rel->r_offset, relocation, rel->r_addend);
+
+ r = or1k_final_link_relocate (howto, input_bfd, input_section, contents,
+ rel->r_offset, relocation + rel->r_addend);
if (r != bfd_reloc_ok)
{
struct elf_link_hash_entry *h;
unsigned long r_symndx;
unsigned char tls_type;
+ int r_type;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx < symtab_hdr->sh_info)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
- switch (ELF32_R_TYPE (rel->r_info))
+ r_type = ELF32_R_TYPE (rel->r_info);
+ switch (r_type)
{
case R_OR1K_TLS_GD_HI16:
case R_OR1K_TLS_GD_LO16:
break;
case R_OR1K_TLS_IE_HI16:
case R_OR1K_TLS_IE_LO16:
+ case R_OR1K_TLS_IE_AHI16:
tls_type = TLS_IE;
break;
case R_OR1K_TLS_LE_HI16:
case R_OR1K_TLS_LE_LO16:
+ case R_OR1K_TLS_LE_AHI16:
+ case R_OR1K_TLS_LE_SLO16:
tls_type = TLS_LE;
break;
default:
local_tls_type[r_symndx] = tls_type;
}
- switch (ELF32_R_TYPE (rel->r_info))
+ switch (r_type)
{
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
break;
case R_OR1K_GOT16:
- case R_OR1K_GOTOFF_HI16:
- case R_OR1K_GOTOFF_LO16:
case R_OR1K_TLS_GD_HI16:
case R_OR1K_TLS_GD_LO16:
case R_OR1K_TLS_IE_HI16:
case R_OR1K_TLS_IE_LO16:
- if (htab->root.sgot == NULL)
- {
- if (dynobj == NULL)
- htab->root.dynobj = dynobj = abfd;
- if (!_bfd_elf_create_got_section (dynobj, info))
- return FALSE;
- }
-
- if (ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_HI16 &&
- ELF32_R_TYPE (rel->r_info) != R_OR1K_GOTOFF_LO16)
- {
+ case R_OR1K_TLS_IE_AHI16:
if (h != NULL)
h->got.refcount += 1;
else
}
local_got_refcounts[r_symndx] += 1;
}
+ /* FALLTHRU */
+
+ case R_OR1K_GOTOFF_HI16:
+ case R_OR1K_GOTOFF_LO16:
+ case R_OR1K_GOTOFF_AHI16:
+ case R_OR1K_GOTOFF_SLO16:
+ if (htab->root.sgot == NULL)
+ {
+ if (dynobj == NULL)
+ htab->root.dynobj = dynobj = abfd;
+ if (!_bfd_elf_create_got_section (dynobj, info))
+ return FALSE;
}
break;
case R_OR1K_INSN_REL_26:
case R_OR1K_HI_16_IN_INSN:
case R_OR1K_LO_16_IN_INSN:
+ case R_OR1K_AHI16:
+ case R_OR1K_SLO16:
case R_OR1K_32:
- /* R_OR1K_16? */
{
if (h != NULL && !bfd_link_pic (info))
{
/* We may also need a .plt entry. */
h->plt.refcount += 1;
- if (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26)
+ if (r_type != R_OR1K_INSN_REL_26)
h->pointer_equality_needed = 1;
}
if ((bfd_link_pic (info)
&& (sec->flags & SEC_ALLOC) != 0
- && (ELF32_R_TYPE (rel->r_info) != R_OR1K_INSN_REL_26
+ && (r_type != R_OR1K_INSN_REL_26
|| (h != NULL
&& (!SYMBOLIC_BIND (info, h)
|| h->root.type == bfd_link_hash_defweak
}
p->count += 1;
- if (ELF32_R_TYPE (rel->r_info) == R_OR1K_INSN_REL_26)
+ if (r_type == R_OR1K_INSN_REL_26)
p->pc_count += 1;
}
}