/* PowerPC-specific support for 32-bit ELF
- Copyright (C) 1994-2020 Free Software Foundation, Inc.
+ Copyright (C) 1994-2021 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
if (error_message != NULL)
{
- static char buf[60];
- sprintf (buf, _("generic linker can't handle %s"),
- reloc_entry->howto->name);
- *error_message = buf;
+ static char *message;
+ free (message);
+ if (asprintf (&message, _("generic linker can't handle %s"),
+ reloc_entry->howto->name) < 0)
+ message = NULL;
+ *error_message = message;
}
return bfd_reloc_dangerous;
}
};
/* This is what we want for new plt/got. */
-static struct bfd_elf_special_section ppc_alt_plt =
+static const struct bfd_elf_special_section ppc_alt_plt =
{ STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC };
static const struct bfd_elf_special_section *
/* Get the PPC ELF linker hash table from a link_info structure. */
#define ppc_elf_hash_table(p) \
- (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \
- == PPC32_ELF_DATA ? ((struct ppc_elf_link_hash_table *) ((p)->hash)) : NULL)
+ ((is_elf_hash_table ((p)->hash) \
+ && elf_hash_table_id (elf_hash_table (p)) == PPC32_ELF_DATA) \
+ ? (struct ppc_elf_link_hash_table *) (p)->hash : NULL)
/* Create an entry in a PPC ELF linker hash table. */
return FALSE;
break;
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ sec->has_tls_reloc = 1;
+ /* Fall through. */
/* We shouldn't really be seeing TPREL32. */
case R_PPC_TPREL32:
case R_PPC_TPREL16:
case R_PPC_TPREL16_LO:
- case R_PPC_TPREL16_HI:
- case R_PPC_TPREL16_HA:
if (bfd_link_dll (info))
info->flags |= DF_STATIC_TLS;
goto dodyn;
if (htab == NULL)
return FALSE;
+ htab->do_tls_opt = 1;
+
/* Make two passes through the relocs. First time check that tls
relocs involved in setting up a tls_get_addr call are indeed
followed by such a call. If they are not, don't do any tls
tls_clear = 0;
break;
+ case R_PPC_TPREL16_HA:
+ if (pass == 0)
+ {
+ unsigned char buf[4];
+ unsigned int insn;
+ bfd_vma off = rel->r_offset & ~3;
+ if (!bfd_get_section_contents (ibfd, sec, buf,
+ off, 4))
+ {
+ if (elf_section_data (sec)->relocs != relstart)
+ free (relstart);
+ return FALSE;
+ }
+ insn = bfd_get_32 (ibfd, buf);
+ /* addis rt,2,imm */
+ if ((insn & ((0x3fu << 26) | 0x1f << 16))
+ != ((15u << 26) | (2 << 16)))
+ {
+ /* xgettext:c-format */
+ info->callbacks->minfo
+ (_("%H: warning: %s unexpected insn %#x.\n"),
+ ibfd, sec, off, "R_PPC_TPREL16_HA", insn);
+ htab->do_tls_opt = 0;
+ }
+ }
+ continue;
+
+ case R_PPC_TPREL16_HI:
+ htab->do_tls_opt = 0;
+ continue;
+
default:
continue;
}
free (relstart);
}
}
- htab->do_tls_opt = 1;
return TRUE;
}
\f
if (r_type < R_PPC_max)
howto = ppc_elf_howto_table[r_type];
- switch (r_type)
- {
- default:
- break;
-
- case R_PPC_TPREL16_HA:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- if ((insn & ((0x3fu << 26) | 0x1f << 16))
- != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */)
- /* xgettext:c-format */
- info->callbacks->minfo
- (_("%H: warning: %s unexpected insn %#x.\n"),
- input_bfd, input_section, rel->r_offset, howto->name, insn);
- else
- bfd_put_32 (input_bfd, NOP, p);
- }
- break;
-
- case R_PPC_TPREL16_LO:
- if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
- {
- bfd_byte *p = contents + (rel->r_offset & ~3);
- unsigned int insn = bfd_get_32 (input_bfd, p);
- insn &= ~(0x1f << 16);
- insn |= 2 << 16;
- bfd_put_32 (input_bfd, insn, p);
- }
- break;
- }
-
tls_type = 0;
switch (r_type)
{
goto copy_reloc;
}
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC_TPREL16_HA:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ bfd_put_32 (input_bfd, NOP, p);
+ }
+ break;
+
+ case R_PPC_TPREL16_LO:
+ if (htab->do_tls_opt && relocation + addend + 0x8000 < 0x10000)
+ {
+ bfd_byte *p = contents + (rel->r_offset & ~3);
+ unsigned int insn = bfd_get_32 (input_bfd, p);
+ insn &= ~(0x1f << 16);
+ insn |= 2 << 16;
+ bfd_put_32 (input_bfd, insn, p);
+ }
+ break;
+ }
+
switch (r_type)
{
default: