From c4276840c8e41dc39c4e0b24807d882e68d89f32 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 22 Oct 2014 12:55:41 -0700 Subject: [PATCH] binutils: refactor check_relocs --- binutils/bfd/elfxx-riscv.c | 132 ++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 62 deletions(-) diff --git a/binutils/bfd/elfxx-riscv.c b/binutils/bfd/elfxx-riscv.c index 02b799be..59b78bd1 100644 --- a/binutils/bfd/elfxx-riscv.c +++ b/binutils/bfd/elfxx-riscv.c @@ -815,7 +815,7 @@ struct riscv_elf_link_hash_entry #define GOT_NORMAL 1 #define GOT_TLS_GD 2 #define GOT_TLS_IE 4 - unsigned char tls_type; + char tls_type; }; #define riscv_elf_hash_entry(ent) \ @@ -835,6 +835,10 @@ struct _bfd_riscv_elf_obj_tdata #define _bfd_riscv_elf_local_got_tls_type(abfd) \ (_bfd_riscv_elf_tdata (abfd)->local_got_tls_type) +#define _bfd_riscv_elf_tls_type(abfd, h, symndx) \ + (*((h) != NULL ? &riscv_elf_hash_entry(h)->tls_type \ + : &_bfd_riscv_elf_local_got_tls_type (abfd) [symndx])) + #define is_riscv_elf(bfd) \ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ && elf_tdata (bfd) != NULL \ @@ -1197,6 +1201,55 @@ riscv_elf_copy_indirect_symbol (struct bfd_link_info *info, _bfd_elf_link_hash_copy_indirect (info, dir, ind); } +static bfd_boolean +riscv_elf_record_tls_type (bfd *abfd, struct elf_link_hash_entry *h, + unsigned long symndx, char tls_type) +{ + char *new_tls_type = &_bfd_riscv_elf_tls_type (abfd, h, symndx); + *new_tls_type |= tls_type; + if ((*new_tls_type & GOT_NORMAL) && (*new_tls_type & ~GOT_NORMAL)) + { + (*_bfd_error_handler) + (_("%B: `%s' accessed both as normal and thread local symbol"), + abfd, h ? h->root.root.string : ""); + return FALSE; + } + return TRUE; +} + +static bfd_boolean +riscv_elf_record_got_reference (bfd *abfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, long symndx) +{ + struct riscv_elf_link_hash_table *htab = riscv_elf_hash_table (info); + Elf_Internal_Shdr *symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + + if (htab->elf.sgot == NULL) + { + if (!riscv_elf_create_got_section (htab->elf.dynobj, info)) + return FALSE; + } + + if (h != NULL) + { + h->got.refcount += 1; + return TRUE; + } + + /* This is a global offset table entry for a local symbol. */ + if (elf_local_got_refcounts (abfd) == NULL) + { + bfd_size_type size = symtab_hdr->sh_info * (sizeof (bfd_vma) + 1); + if (!(elf_local_got_refcounts (abfd) = bfd_zalloc (abfd, size))) + return FALSE; + _bfd_riscv_elf_local_got_tls_type (abfd) + = (char *) (elf_local_got_refcounts (abfd) + symtab_hdr->sh_info); + } + elf_local_got_refcounts (abfd) [symndx] += 1; + + return TRUE; +} + /* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */ @@ -1226,7 +1279,6 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, unsigned int r_type; unsigned long r_symndx; struct elf_link_hash_entry *h; - int tls_type, old_tls_type; r_symndx = ELF_R_SYM (abfd, rel->r_info); r_type = ELF_R_TYPE (rel->r_info); @@ -1255,72 +1307,31 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, switch (r_type) { case R_RISCV_TLS_GD_HI20: - tls_type = GOT_TLS_GD; - goto have_got_reference; + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_GD)) + return FALSE; + break; case R_RISCV_TLS_IE_HI20: if (info->shared) goto illegal_static_reloc; - tls_type = GOT_TLS_IE; - goto have_got_reference; + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_IE)) + return FALSE; + break; case R_RISCV_TLS_GOT_HI20: if (info->shared) info->flags |= DF_STATIC_TLS; - tls_type = GOT_TLS_IE; - goto have_got_reference; + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_TLS_IE)) + return FALSE; + break; case R_RISCV_GOT_HI20: - tls_type = GOT_NORMAL; - /* Fall through. */ - - have_got_reference: - /* This symbol requires a global offset table entry. */ - if (h != NULL) - { - h->got.refcount += 1; - old_tls_type = riscv_elf_hash_entry(h)->tls_type; - riscv_elf_hash_entry(h)->tls_type |= tls_type; - } - else - { - bfd_signed_vma *local_got_refcounts; - - /* This is a global offset table entry for a local symbol. */ - local_got_refcounts = elf_local_got_refcounts (abfd); - if (local_got_refcounts == NULL) - { - bfd_size_type size; - - size = symtab_hdr->sh_info; - size *= (sizeof (bfd_signed_vma) + sizeof(char)); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); - if (local_got_refcounts == NULL) - return FALSE; - elf_local_got_refcounts (abfd) = local_got_refcounts; - _bfd_riscv_elf_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + symtab_hdr->sh_info); - } - local_got_refcounts[r_symndx] += 1; - old_tls_type = _bfd_riscv_elf_local_got_tls_type (abfd) [r_symndx]; - _bfd_riscv_elf_local_got_tls_type (abfd) [r_symndx] |= tls_type; - } - - if (((old_tls_type | tls_type) & GOT_NORMAL) - && ((old_tls_type | tls_type) & (GOT_TLS_IE | GOT_TLS_GD))) - { - (*_bfd_error_handler) - (_("%B: `%s' accessed both as normal and thread local symbol"), - abfd, h ? h->root.root.string : ""); - return FALSE; - } - - if (htab->elf.sgot == NULL) - { - if (!riscv_elf_create_got_section (htab->elf.dynobj, info)) - return FALSE; - } + if (!riscv_elf_record_got_reference (abfd, info, h, r_symndx) + || !riscv_elf_record_tls_type (abfd, h, r_symndx, GOT_NORMAL)) + return FALSE; break; case R_RISCV_CALL_PLT: @@ -2773,19 +2784,16 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, case R_RISCV_TLS_GD_HI20: if (h != NULL) { - tls_type = riscv_elf_hash_entry(h)->tls_type; off = h->got.offset; h->got.offset |= 1; } else { - BFD_ASSERT (local_got_offsets != NULL); - tls_type = - _bfd_riscv_elf_local_got_tls_type (input_bfd) [r_symndx]; off = local_got_offsets[r_symndx]; local_got_offsets[r_symndx] |= 1; } + tls_type = _bfd_riscv_elf_tls_type (input_bfd, h, r_symndx); BFD_ASSERT (tls_type & (GOT_TLS_IE | GOT_TLS_GD)); /* If this symbol is referenced by both GD and IE TLS, the IE reference's GOT slot follows the GD reference's slots. */