From 89f09cae6217346cd1adbc61ad4a5f1214b727cd Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 16 Jan 2013 21:34:44 +0000 Subject: Add x86 size relocation support to bfd * bfd-in2.h: Regenerated. * libbfd.h: Likewise. * elf32-i386.c (elf_howto_table): Fill R_386_SIZE32 entry. (elf_i386_reloc_type_lookup): Support BFD_RELOC_SIZE32. (elf_i386_check_relocs): Handle R_386_SIZE32. (elf_i386_gc_sweep_hook): Likewise. (elf_i386_relocate_section): Likewise. * elf64-x86-64.c (x86_64_elf_howto_table): Fill R_X86_64_SIZE32 and R_X86_64_SIZE64 entries. (x86_64_reloc_map): Add BFD_RELOC_SIZE32 and BFD_RELOC_SIZE64, (elf_x86_64_rtype_to_howto): Handle R_X86_64_SIZE32 for x32. (elf_x86_64_reloc_name_lookup): Likewise. (elf_x86_64_check_relocs): Handle R_X86_64_SIZE32 and R_X86_64_SIZE64. (elf_x86_64_gc_sweep_hook): Likewise. (elf_x86_64_relocate_section): Likewise. * reloc.c (bfd_reloc_code_type): Add BFD_RELOC_SIZE32 and BFD_RELOC_SIZE64. --- bfd/ChangeLog | 24 ++++++++++++++++++++ bfd/bfd-in2.h | 4 ++++ bfd/elf32-i386.c | 34 +++++++++++++++++++++++++++-- bfd/elf64-x86-64.c | 64 +++++++++++++++++++++++++++++++++++++++++++++--------- bfd/libbfd.h | 2 ++ bfd/reloc.c | 7 ++++++ 6 files changed, 123 insertions(+), 12 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index ccb03bc4c7..2dec362dae 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,27 @@ +2013-01-16 H.J. Lu + + * bfd-in2.h: Regenerated. + * libbfd.h: Likewise. + + * elf32-i386.c (elf_howto_table): Fill R_386_SIZE32 entry. + (elf_i386_reloc_type_lookup): Support BFD_RELOC_SIZE32. + (elf_i386_check_relocs): Handle R_386_SIZE32. + (elf_i386_gc_sweep_hook): Likewise. + (elf_i386_relocate_section): Likewise. + + * elf64-x86-64.c (x86_64_elf_howto_table): Fill R_X86_64_SIZE32 + and R_X86_64_SIZE64 entries. + (x86_64_reloc_map): Add BFD_RELOC_SIZE32 and BFD_RELOC_SIZE64, + (elf_x86_64_rtype_to_howto): Handle R_X86_64_SIZE32 for x32. + (elf_x86_64_reloc_name_lookup): Likewise. + (elf_x86_64_check_relocs): Handle R_X86_64_SIZE32 and + R_X86_64_SIZE64. + (elf_x86_64_gc_sweep_hook): Likewise. + (elf_x86_64_relocate_section): Likewise. + + * reloc.c (bfd_reloc_code_type): Add BFD_RELOC_SIZE32 and + BFD_RELOC_SIZE64. + 2013-01-15 H.J. Lu * elf64-x86-64.c (R_X86_64_standard): Replace R_X86_64_IRELATIVE diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 0cb9bb0f8e..3561e192f8 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -2523,6 +2523,10 @@ The 24-bit relocation is used in some Intel 960 configurations. */ BFD_RELOC_HI16_S_PLTOFF, BFD_RELOC_8_PLTOFF, +/* Size relocations. */ + BFD_RELOC_SIZE32, + BFD_RELOC_SIZE64, + /* Relocations used by 68K ELF. */ BFD_RELOC_68K_GLOB_DAT, BFD_RELOC_68K_JMP_SLOT, diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 99e8f45c86..368c8d5866 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -133,7 +133,9 @@ static reloc_howto_type elf_howto_table[]= HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", TRUE, 0xffffffff, 0xffffffff, FALSE), - EMPTY_HOWTO (38), + HOWTO(R_386_SIZE32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, + bfd_elf_generic_reloc, "R_386_SIZE32", + TRUE, 0xffffffff, 0xffffffff, FALSE), HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_GOTDESC", TRUE, 0xffffffff, 0xffffffff, FALSE), @@ -312,6 +314,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, TRACE ("BFD_RELOC_386_TLS_TPOFF32"); return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset]; + case BFD_RELOC_SIZE32: + TRACE ("BFD_RELOC_SIZE32"); + return &elf_howto_table[R_386_SIZE32 - R_386_tls_offset]; + case BFD_RELOC_386_TLS_GOTDESC: TRACE ("BFD_RELOC_386_TLS_GOTDESC"); return &elf_howto_table[R_386_TLS_GOTDESC - R_386_tls_offset]; @@ -1680,6 +1686,7 @@ elf_i386_check_relocs (bfd *abfd, case R_386_32: case R_386_PC32: + case R_386_SIZE32: if (h != NULL && info->executable) { /* If this reloc is in a read-only section, we might @@ -1959,6 +1966,7 @@ elf_i386_gc_sweep_hook (bfd *abfd, case R_386_32: case R_386_PC32: + case R_386_SIZE32: if (info->shared && (h == NULL || h->type != STT_GNU_IFUNC)) break; @@ -3185,6 +3193,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_reloc_status_type r; unsigned int indx; int tls_type; + bfd_vma st_size; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == R_386_GNU_VTINHERIT @@ -3217,6 +3226,7 @@ elf_i386_relocate_section (bfd *output_bfd, relocation = (sec->output_section->vma + sec->output_offset + sym->st_value); + st_size = sym->st_size; if (ELF_ST_TYPE (sym->st_info) == STT_SECTION && ((sec->flags & SEC_MERGE) != 0 @@ -3309,6 +3319,7 @@ elf_i386_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)) @@ -3670,6 +3681,25 @@ elf_i386_relocate_section (bfd *output_bfd, unresolved_reloc = FALSE; break; + case R_386_SIZE32: + 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; + /* Fall through. */ + case R_386_32: case R_386_PC32: if ((input_section->flags & SEC_ALLOC) == 0 @@ -3680,7 +3710,7 @@ elf_i386_relocate_section (bfd *output_bfd, && (h == NULL || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT || h->root.type != bfd_link_hash_undefweak) - && (r_type != R_386_PC32 + && ((r_type != R_386_PC32 && r_type != R_386_SIZE32) || !SYMBOL_CALLS_LOCAL (info, h))) || (ELIMINATE_COPY_RELOCS && !info->shared 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 diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 7c78d9b05e..20d614751d 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -940,6 +940,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_HI16_PLTOFF", "BFD_RELOC_HI16_S_PLTOFF", "BFD_RELOC_8_PLTOFF", + "BFD_RELOC_SIZE32", + "BFD_RELOC_SIZE64", "BFD_RELOC_68K_GLOB_DAT", "BFD_RELOC_68K_JMP_SLOT", "BFD_RELOC_68K_RELATIVE", diff --git a/bfd/reloc.c b/bfd/reloc.c index 51ebc1c172..7a14be9d58 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -1736,6 +1736,13 @@ ENUMX ENUMDOC For ELF. +ENUM + BFD_RELOC_SIZE32 +ENUMX + BFD_RELOC_SIZE64 +ENUMDOC + Size relocations. + ENUM BFD_RELOC_68K_GLOB_DAT ENUMX -- cgit v1.2.1