From 1d4af308ae58f459a2bfc50de70832284f1d3d2a Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 6 Aug 2017 08:40:56 -0700 Subject: [PATCH] x86: Lookup __tls_get_addr or ___tls_get_addr once Instead of checking if a symbol is __tls_get_addr or ___tls_get_addr, we check if there is a reference to __tls_get_addr or ___tls_get_addr before starting relocation check. * elf32-i386.c (elf_i386_link_hash_entry): Change tls_get_addr to 1 bit. (elf_i386_link_hash_newfunc): Initialize tls_get_addr to 0. (elf_i386_check_tls_transition): Check tls_get_addr directly. (elf_i386_convert_load_reloc): Update tls_get_addr check. (elf_i386_link_check_relocs): New function. (bfd_elf32_bfd_link_check_relocs): New. * elf64-x86-64.c (elf_x86_64_link_hash_entry): Change tls_get_addr to 1 bit. (elf_x86_64_link_hash_newfunc): Initialize tls_get_addr to 0. (elf_x86_64_check_tls_transition): Check tls_get_addr directly. (elf_x86_64_convert_load_reloc): Update tls_get_addr check. (elf_x86_64_link_check_relocs): New function. (bfd_elf64_bfd_link_check_relocs): New. (bfd_elf32_bfd_link_check_relocs): Likewise. --- bfd/ChangeLog | 18 +++++++++++++++ bfd/elf32-i386.c | 54 +++++++++++++++++++++----------------------- bfd/elf64-x86-64.c | 56 ++++++++++++++++++++++------------------------ 3 files changed, 70 insertions(+), 58 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 7c58a866e54..49ef45f4290 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2017-08-06 H.J. Lu + + * elf32-i386.c (elf_i386_link_hash_entry): Change tls_get_addr + to 1 bit. + (elf_i386_link_hash_newfunc): Initialize tls_get_addr to 0. + (elf_i386_check_tls_transition): Check tls_get_addr directly. + (elf_i386_convert_load_reloc): Update tls_get_addr check. + (elf_i386_link_check_relocs): New function. + (bfd_elf32_bfd_link_check_relocs): New. + * elf64-x86-64.c (elf_x86_64_link_hash_entry): Change tls_get_addr + to 1 bit. + (elf_x86_64_link_hash_newfunc): Initialize tls_get_addr to 0. + (elf_x86_64_check_tls_transition): Check tls_get_addr directly. + (elf_x86_64_convert_load_reloc): Update tls_get_addr check. + (elf_x86_64_link_check_relocs): New function. + (bfd_elf64_bfd_link_check_relocs): New. + (bfd_elf32_bfd_link_check_relocs): Likewise. + 2017-08-06 H.J. Lu PR ld/21903: diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 37099b75574..14f018ea2cb 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -995,10 +995,8 @@ struct elf_i386_link_hash_entry /* Don't call finish_dynamic_symbol on this symbol. */ unsigned int no_finish_dynamic_symbol : 1; - /* 0: symbol isn't ___tls_get_addr. - 1: symbol is ___tls_get_addr. - 2: symbol is unknown. */ - unsigned int tls_get_addr : 2; + /* TRUE if symbol symbol is __tls_get_addr. */ + unsigned int tls_get_addr : 1; /* Reference count of C/C++ function pointer relocations in read-write section which can be resolved at run-time. */ @@ -1149,7 +1147,7 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, eh->has_got_reloc = 0; eh->has_non_got_reloc = 0; eh->no_finish_dynamic_symbol = 0; - eh->tls_get_addr = 2; + eh->tls_get_addr = 0; eh->func_pointer_refcount = 0; eh->plt_got.offset = (bfd_vma) -1; eh->tlsdesc_got = (bfd_vma) -1; @@ -1378,7 +1376,7 @@ elf_i386_check_tls_transition (asection *sec, struct elf_link_hash_entry *h; bfd_vma offset; bfd_byte *call; - bfd_boolean indirect_call, tls_get_addr; + bfd_boolean indirect_call; offset = rel->r_offset; switch (r_type) @@ -1483,29 +1481,9 @@ elf_i386_check_tls_transition (asection *sec, if (r_symndx < symtab_hdr->sh_info) return FALSE; - tls_get_addr = FALSE; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h != NULL && h->root.root.string != NULL) - { - struct elf_i386_link_hash_entry *eh - = (struct elf_i386_link_hash_entry *) h; - tls_get_addr = eh->tls_get_addr == 1; - if (eh->tls_get_addr > 1) - { - /* Use strncmp to check ___tls_get_addr since - ___tls_get_addr may be versioned. */ - if (strncmp (h->root.root.string, "___tls_get_addr", 15) - == 0) - { - eh->tls_get_addr = 1; - tls_get_addr = TRUE; - } - else - eh->tls_get_addr = 0; - } - } - - if (!tls_get_addr) + if (h == NULL + || !((struct elf_i386_link_hash_entry *) h)->tls_get_addr) return FALSE; else if (indirect_call) return (ELF32_R_TYPE (rel[1].r_info) == R_386_GOT32X); @@ -1863,7 +1841,7 @@ convert_branch: modrm = 0xe8; /* To support TLS optimization, always use addr32 prefix for "call *___tls_get_addr@GOT(%reg)". */ - if (eh && eh->tls_get_addr == 1) + if (eh && eh->tls_get_addr) { nop = 0x67; nop_offset = irel->r_offset - 2; @@ -7148,6 +7126,23 @@ error_alignment: return pbfd; } +static bfd_boolean +elf_i386_link_check_relocs (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_link_relocatable (info)) + { + /* Check for ___tls_get_addr reference. */ + struct elf_link_hash_entry *h; + h = elf_link_hash_lookup (elf_hash_table (info), "___tls_get_addr", + FALSE, FALSE, FALSE); + if (h != NULL) + ((struct elf_i386_link_hash_entry *) h)->tls_get_addr = 1; + } + + /* Invoke the regular ELF backend linker to do all the work. */ + return _bfd_elf_link_check_relocs (abfd, info); +} + #define TARGET_LITTLE_SYM i386_elf32_vec #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 @@ -7178,6 +7173,7 @@ error_alignment: #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup #define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab +#define bfd_elf32_bfd_link_check_relocs elf_i386_link_check_relocs #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 448599eb9b3..e5f4681354a 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1101,10 +1101,8 @@ struct elf_x86_64_link_hash_entry /* Don't call finish_dynamic_symbol on this symbol. */ unsigned int no_finish_dynamic_symbol : 1; - /* 0: symbol isn't __tls_get_addr. - 1: symbol is __tls_get_addr. - 2: symbol is unknown. */ - unsigned int tls_get_addr : 2; + /* TRUE if symbol symbol is __tls_get_addr. */ + unsigned int tls_get_addr : 1; /* Reference count of C/C++ function pointer relocations in read-write section which can be resolved at run-time. */ @@ -1264,7 +1262,7 @@ elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, eh->has_got_reloc = 0; eh->has_non_got_reloc = 0; eh->no_finish_dynamic_symbol = 0; - eh->tls_get_addr = 2; + eh->tls_get_addr = 0; eh->func_pointer_refcount = 0; eh->plt_second.offset = (bfd_vma) -1; eh->plt_got.offset = (bfd_vma) -1; @@ -1527,7 +1525,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, bfd_vma offset; struct elf_x86_64_link_hash_table *htab; bfd_byte *call; - bfd_boolean indirect_call, tls_get_addr; + bfd_boolean indirect_call; htab = elf_x86_64_hash_table (info); offset = rel->r_offset; @@ -1667,29 +1665,9 @@ elf_x86_64_check_tls_transition (bfd *abfd, if (r_symndx < symtab_hdr->sh_info) return FALSE; - tls_get_addr = FALSE; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h != NULL && h->root.root.string != NULL) - { - struct elf_x86_64_link_hash_entry *eh - = (struct elf_x86_64_link_hash_entry *) h; - tls_get_addr = eh->tls_get_addr == 1; - if (eh->tls_get_addr > 1) - { - /* Use strncmp to check __tls_get_addr since - __tls_get_addr may be versioned. */ - if (strncmp (h->root.root.string, "__tls_get_addr", 14) - == 0) - { - eh->tls_get_addr = 1; - tls_get_addr = TRUE; - } - else - eh->tls_get_addr = 0; - } - } - - if (!tls_get_addr) + if (h == NULL + || !((struct elf_x86_64_link_hash_entry *) h)->tls_get_addr) return FALSE; else if (largepic) return ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLTOFF64; @@ -2253,7 +2231,7 @@ convert: modrm = 0xe8; /* To support TLS optimization, always use addr32 prefix for "call *__tls_get_addr@GOTPCREL(%rip)". */ - if (eh && eh->tls_get_addr == 1) + if (eh && eh->tls_get_addr) { nop = 0x67; nop_offset = irel->r_offset - 2; @@ -7715,6 +7693,23 @@ error_alignment: return pbfd; } +static bfd_boolean +elf_x86_64_link_check_relocs (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_link_relocatable (info)) + { + /* Check for __tls_get_addr reference. */ + struct elf_link_hash_entry *h; + h = elf_link_hash_lookup (elf_hash_table (info), "__tls_get_addr", + FALSE, FALSE, FALSE); + if (h != NULL) + ((struct elf_x86_64_link_hash_entry *) h)->tls_get_addr = 1; + } + + /* Invoke the regular ELF backend linker to do all the work. */ + return _bfd_elf_link_check_relocs (abfd, info); +} + static const struct bfd_elf_special_section elf_x86_64_special_sections[]= { @@ -7779,6 +7774,7 @@ elf_x86_64_special_sections[]= #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject #define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab +#define bfd_elf64_bfd_link_check_relocs elf_x86_64_link_check_relocs #define elf_backend_section_from_shdr \ elf_x86_64_section_from_shdr @@ -8078,6 +8074,8 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) elf_x86_64_mkobject #define bfd_elf32_get_synthetic_symtab \ elf_x86_64_get_synthetic_symtab +#define bfd_elf32_bfd_link_check_relocs \ + elf_x86_64_link_check_relocs #undef elf_backend_object_p #define elf_backend_object_p \ -- 2.30.2