summaryrefslogtreecommitdiff
path: root/bfd/elf64-x86-64.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elf64-x86-64.c')
-rw-r--r--bfd/elf64-x86-64.c64
1 files changed, 54 insertions, 10 deletions
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 3f45776d18..8fae5fcb78 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -148,8 +148,12 @@ static reloc_howto_type x86_64_elf_howto_table[] =
HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed,
bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE,
MINUS_ONE, FALSE),
- EMPTY_HOWTO (32),
- EMPTY_HOWTO (33),
+ HOWTO(R_X86_64_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned,
+ bfd_elf_generic_reloc, "R_X86_64_SIZE32", FALSE, 0xffffffff, 0xffffffff,
+ FALSE),
+ HOWTO(R_X86_64_SIZE64, 0, 4, 64, FALSE, 0, complain_overflow_unsigned,
+ bfd_elf_generic_reloc, "R_X86_64_SIZE64", FALSE, MINUS_ONE, MINUS_ONE,
+ FALSE),
HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0,
complain_overflow_bitfield, bfd_elf_generic_reloc,
"R_X86_64_GOTPC32_TLSDESC",
@@ -238,6 +242,8 @@ static const struct elf_reloc_map x86_64_reloc_map[] =
{ BFD_RELOC_X86_64_GOTPC64, R_X86_64_GOTPC64, },
{ BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, },
{ BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, },
+ { BFD_RELOC_SIZE32, R_X86_64_SIZE32, },
+ { BFD_RELOC_SIZE64, R_X86_64_SIZE64, },
{ BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
{ BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
{ BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, },
@@ -1731,6 +1737,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_X86_64_PC32:
case R_X86_64_PC64:
case R_X86_64_64:
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
pointer:
if (h != NULL && info->executable)
{
@@ -2027,6 +2035,8 @@ elf_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
case R_X86_64_PC16:
case R_X86_64_PC32:
case R_X86_64_PC64:
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
if (info->shared
&& (h == NULL || h->type != STT_GNU_IFUNC))
break;
@@ -3202,6 +3212,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
bfd_reloc_status_type r;
int tls_type;
asection *base_got;
+ bfd_vma st_size;
r_type = ELF32_R_TYPE (rel->r_info);
if (r_type == (int) R_X86_64_GNU_VTINHERIT
@@ -3235,6 +3246,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
relocation = _bfd_elf_rela_local_sym (output_bfd, sym,
&sec, rel);
+ st_size = sym->st_size;
/* Relocate against local STT_GNU_IFUNC symbol. */
if (!info->relocatable
@@ -3258,6 +3270,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
r_symndx, symtab_hdr, sym_hashes,
h, sec, relocation,
unresolved_reloc, warned);
+ st_size = h->size;
}
if (sec != NULL && discarded_section (sec))
@@ -3267,14 +3280,22 @@ elf_x86_64_relocate_section (bfd *output_bfd,
if (info->relocatable)
continue;
- if (rel->r_addend == 0
- && r_type == R_X86_64_64
- && !ABI_64_P (output_bfd))
+ if (rel->r_addend == 0 && !ABI_64_P (output_bfd))
{
- /* For x32, treat R_X86_64_64 like R_X86_64_32 and zero-extend
- it to 64bit if addend is zero. */
- r_type = R_X86_64_32;
- memset (contents + rel->r_offset + 4, 0, 4);
+ if (r_type == R_X86_64_64)
+ {
+ /* For x32, treat R_X86_64_64 like R_X86_64_32 and
+ zero-extend it to 64bit if addend is zero. */
+ r_type = R_X86_64_32;
+ memset (contents + rel->r_offset + 4, 0, 4);
+ }
+ else if (r_type == R_X86_64_SIZE64)
+ {
+ /* For x32, treat R_X86_64_SIZE64 like R_X86_64_SIZE32 and
+ zero-extend it to 64bit if addend is zero. */
+ r_type = R_X86_64_SIZE32;
+ memset (contents + rel->r_offset + 4, 0, 4);
+ }
}
/* Since STT_GNU_IFUNC symbol must go through PLT, we handle
@@ -3655,6 +3676,26 @@ elf_x86_64_relocate_section (bfd *output_bfd,
unresolved_reloc = FALSE;
break;
+ case R_X86_64_SIZE32:
+ case R_X86_64_SIZE64:
+ if (h
+ && h->type == STT_TLS
+ && (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section != NULL
+ && htab->elf.tls_sec == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%B: `%s' accessed both as normal and thread local symbol"),
+ input_bfd, h->root.root.string);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ /* Set to symbol size. */
+ relocation = st_size;
+ goto direct;
+
case R_X86_64_PC8:
case R_X86_64_PC16:
case R_X86_64_PC32:
@@ -3727,6 +3768,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
/* FIXME: The ABI says the linker should make sure the value is
the same when it's zeroextended to 64 bit. */
+direct:
if ((input_section->flags & SEC_ALLOC) == 0)
break;
@@ -3734,7 +3776,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
&& (h == NULL
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
- && (! IS_X86_64_PCREL_TYPE (r_type)
+ && ((! IS_X86_64_PCREL_TYPE (r_type)
+ && r_type != R_X86_64_SIZE32
+ && r_type != R_X86_64_SIZE64)
|| ! SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared