diff options
author | Alan Modra <amodra@gmail.com> | 2023-08-04 15:09:53 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2023-08-04 17:59:01 +0930 |
commit | ae33771224660dac25e64c3f70943a17bfab7681 (patch) | |
tree | d48602b894890c97fb00c756b3962aaf8f480ab0 /bfd | |
parent | 49459ed32b71aefd0443d82c939f05933505080e (diff) | |
download | gdb-ae33771224660dac25e64c3f70943a17bfab7681.zip gdb-ae33771224660dac25e64c3f70943a17bfab7681.tar.gz gdb-ae33771224660dac25e64c3f70943a17bfab7681.tar.bz2 |
PR30697, ppc32 mix of local-dynamic and global-dynamic TLS
This fixes miscounting of dynamic relocations on GOT entries when
a) there are both local-dynamic and global-dynamic tls accesss for a
given symbol, and
b) the symbol is global with non-default visibility, and
c) the __tls_get_addr calls aren't optimised away.
PR 30697
bfd/
* elf32-ppc.c (allocate_dynrelocs): Correct local-dynamic
reloc count.
ld/
* testsuite/ld-powerpc/tls32ldgd.d,
* testsuite/ld-powerpc/tls32ldgd.s: New test.
* testsuite/ld-powerpc/powerpc.exp: Run it.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/elf32-ppc.c | 16 |
1 files changed, 7 insertions, 9 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 2c544b1..37bfbcf 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -5126,13 +5126,12 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) && eh->has_addr16_lo && htab->params->pic_fixup > 0)) { - unsigned int need; - /* Make sure this symbol is output as a dynamic symbol. */ if (!ensure_undef_dynamic (info, &eh->elf)) return false; - need = 0; + unsigned int need = got_entries_needed (eh->tls_mask); + unsigned int rel_need = need * sizeof (Elf32_External_Rela) / 4; if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)) { if (SYMBOL_REFERENCES_LOCAL (info, &eh->elf)) @@ -5141,9 +5140,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) a local dynamic reloc against a non-local symbol. */ htab->tlsld_got.refcount += 1; else - need += 8; + { + need += 8; + rel_need += sizeof (Elf32_External_Rela); + } } - need += got_entries_needed (eh->tls_mask); if (need == 0) eh->elf.got.offset = (bfd_vma) -1; else @@ -5161,13 +5162,10 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { asection *rsec; - need *= sizeof (Elf32_External_Rela) / 4; - if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)) - need -= sizeof (Elf32_External_Rela); rsec = htab->elf.srelgot; if (eh->elf.type == STT_GNU_IFUNC) rsec = htab->elf.irelplt; - rsec->size += need; + rsec->size += rel_need; } } } |