/* Intel 80386/80486-specific support for 32-bit ELF
- Copyright (C) 1993-2018 Free Software Foundation, Inc.
+ Copyright (C) 1993-2020 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
#endif
static reloc_howto_type *
-elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
+elf_i386_reloc_type_lookup (bfd *abfd,
bfd_reloc_code_real_type code)
{
switch (code)
return &elf_howto_table[R_386_GNU_VTENTRY - R_386_vt_offset];
default:
- break;
+ TRACE ("Unknown");
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: unsupported relocation type: %#x"),
+ abfd, (int) code);
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
}
-
- TRACE ("Unknown");
- return 0;
}
static reloc_howto_type *
}
static reloc_howto_type *
-elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type)
+elf_i386_rtype_to_howto (unsigned r_type)
{
unsigned int indx;
>= R_386_ext2 - R_386_ext)
&& ((indx = r_type - R_386_vt_offset) - R_386_ext2
>= R_386_vt - R_386_ext2))
- {
- /* xgettext:c-format */
- _bfd_error_handler (_("%B: invalid relocation type %d"),
- abfd, (int) r_type);
- indx = R_386_NONE;
- }
+ return NULL;
/* PR 17512: file: 0f67f69d. */
if (elf_howto_table [indx].type != r_type)
return NULL;
return &elf_howto_table[indx];
}
-static void
-elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
+static bfd_boolean
+elf_i386_info_to_howto_rel (bfd *abfd,
arelent *cache_ptr,
Elf_Internal_Rela *dst)
{
unsigned int r_type = ELF32_R_TYPE (dst->r_info);
- cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type);
+
+ if ((cache_ptr->howto = elf_i386_rtype_to_howto (r_type)) == NULL)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
+ abfd, r_type);
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
+
+ return TRUE;
}
/* Return whether a symbol name implies a local label. The UnixWare
sizeof (elf_i386_lazy_plt0_entry), /* plt0_entry_size */
elf_i386_lazy_plt_entry, /* plt_entry */
LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */
+ NULL, /* plt_tlsdesc_entry */
+ 0, /* plt_tlsdesc_entry_size*/
+ 0, /* plt_tlsdesc_got1_offset */
+ 0, /* plt_tlsdesc_got2_offset */
+ 0, /* plt_tlsdesc_got1_insn_end */
+ 0, /* plt_tlsdesc_got2_insn_end */
2, /* plt0_got1_offset */
8, /* plt0_got2_offset */
0, /* plt0_got2_insn_end */
sizeof (elf_i386_lazy_ibt_plt0_entry), /* plt0_entry_size */
elf_i386_lazy_ibt_plt_entry, /* plt_entry */
LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */
+ NULL, /* plt_tlsdesc_entry */
+ 0, /* plt_tlsdesc_entry_size*/
+ 0, /* plt_tlsdesc_got1_offset */
+ 0, /* plt_tlsdesc_got2_offset */
+ 0, /* plt_tlsdesc_got1_insn_end */
+ 0, /* plt_tlsdesc_got2_insn_end */
2, /* plt0_got1_offset */
8, /* plt0_got2_offset */
0, /* plt0_got2_insn_end */
reloc_howto_type *from, *to;
const char *name;
- from = elf_i386_rtype_to_howto (abfd, from_type);
- to = elf_i386_rtype_to_howto (abfd, to_type);
+ from = elf_i386_rtype_to_howto (from_type);
+ to = elf_i386_rtype_to_howto (to_type);
if (h)
name = h->root.root.string;
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: TLS transition from %s to %s against `%s' at %#Lx "
- "in section `%A' failed"),
+ (_("%pB: TLS transition from %s to %s against `%s'"
+ " at %#" PRIx64 " in section `%pA' failed"),
abfd, from->name, to->name, name,
- rel->r_offset, sec);
+ (uint64_t) rel->r_offset, sec);
bfd_set_error (bfd_error_bad_value);
return FALSE;
}
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base"
+ (_("%pB: direct GOT relocation R_386_GOT32X against `%s' without base"
" register can not be used when making a shared object"),
abfd, name);
return FALSE;
&& local_ref)
{
/* The function is locally defined. */
-convert_branch:
+ convert_branch:
/* Convert R_386_GOT32X to R_386_PC32. */
if (modrm == 0x15 || (modrm & 0xf8) == 0x90)
{
}
else
{
- nop = link_info->call_nop_byte;
- if (link_info->call_nop_as_suffix)
+ nop = htab->params->call_nop_byte;
+ if (htab->params->call_nop_as_suffix)
{
nop_offset = roff + 3;
irel->r_offset -= 1;
|| h->root.type == bfd_link_hash_defweak)
&& local_ref))
{
-convert_load:
+ convert_load:
if (opcode == 0x8b)
{
if (to_reloc_32)
if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
{
/* xgettext:c-format */
- _bfd_error_handler (_("%B: bad symbol index: %d"),
+ _bfd_error_handler (_("%pB: bad symbol index: %d"),
abfd, r_symndx);
goto error_return;
}
/* It is referenced by a non-shared object. */
h->ref_regular = 1;
-
- if (h->type == STT_GNU_IFUNC)
- elf_tdata (info->output_bfd)->has_gnu_symbols
- |= elf_gnu_symbol_ifunc;
}
if (r_type == R_386_GOT32X
rel, rel_end, h, r_symndx, FALSE))
goto error_return;
+ /* Check if _GLOBAL_OFFSET_TABLE_ is referenced. */
+ if (h == htab->elf.hgot)
+ htab->got_referenced = TRUE;
+
switch (r_type)
{
case R_386_TLS_LDM:
NULL);
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: `%s' accessed both as normal and "
+ (_("%pB: `%s' accessed both as normal and "
"thread local symbol"),
abfd, name);
bfd_set_error (bfd_error_bad_value);
if (r_type != R_386_TLS_IE)
{
if (eh != NULL)
- eh->zero_undefweak &= 0x2;
+ {
+ eh->zero_undefweak &= 0x2;
+
+ /* Need GOT to resolve undefined weak symbol to 0. */
+ if (r_type == R_386_GOTOFF
+ && h->root.type == bfd_link_hash_undefweak
+ && bfd_link_executable (info))
+ htab->got_referenced = TRUE;
+ }
break;
}
/* Fall through */
case R_386_PC32:
if (eh != NULL && (sec->flags & SEC_CODE) != 0)
eh->zero_undefweak |= 0x2;
-do_relocation:
+ do_relocation:
/* We are called after all symbols have been resolved. Only
relocation against STT_GNU_IFUNC symbol must go through
PLT. */
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: unsupported non-PIC call to IFUNC `%s'"),
+ (_("%pB: unsupported non-PIC call to IFUNC `%s'"),
abfd, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
goto error_return;
}
size_reloc = FALSE;
-do_size:
- if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
+ do_size:
+ if (NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
R_386_32))
{
struct elf_dyn_relocs *p;
p = *head;
if (p == NULL || p->sec != sec)
{
- bfd_size_type amt = sizeof *p;
+ size_t amt = sizeof *p;
p = (struct elf_dyn_relocs *) bfd_alloc (htab->elf.dynobj,
amt);
if (p == NULL)
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_386_GNU_VTENTRY:
- BFD_ASSERT (h != NULL);
- if (h != NULL
- && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
goto error_return;
break;
return TRUE;
-error_return:
+ error_return:
if (elf_section_data (sec)->this_hdr.contents != contents)
free (contents);
sec->check_relocs_failed = 1;
{
const char *name;
- name = bfd_get_section_name (abfd, sec);
+ name = bfd_section_name (sec);
/* This is an ugly, but unfortunately necessary hack that is
needed when producing EFI binaries on x86. It tells
if (htab == NULL)
return FALSE;
- BFD_ASSERT (is_x86_elf (input_bfd, htab));
+ if (!is_x86_elf (input_bfd, htab))
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
symtab_hdr = &elf_symtab_hdr (input_bfd);
sym_hashes = elf_sym_hashes (input_bfd);
continue;
}
- if ((indx = r_type) >= R_386_standard
- && ((indx = r_type - R_386_ext_offset) - R_386_standard
- >= R_386_ext - R_386_standard)
- && ((indx = r_type - R_386_tls_offset) - R_386_ext
- >= R_386_ext2 - R_386_ext))
+ howto = elf_i386_rtype_to_howto (r_type);
+ if (howto == NULL)
return _bfd_unrecognized_reloc (input_bfd, input_section, r_type);
- howto = elf_howto_table + indx;
-
r_symndx = ELF32_R_SYM (rel->r_info);
h = NULL;
sym = NULL;
if (sec != NULL && discarded_section (sec))
{
_bfd_clear_contents (howto, input_bfd, input_section,
- contents + rel->r_offset);
+ contents, rel->r_offset);
wrel->r_offset = rel->r_offset;
wrel->r_info = 0;
wrel->r_addend = 0;
if ((input_section->flags & SEC_ALLOC) == 0)
{
+ /* If this is a SHT_NOTE section without SHF_ALLOC, treat
+ STT_GNU_IFUNC symbol as STT_FUNC. */
+ if (elf_section_type (input_section) == SHT_NOTE)
+ goto skip_ifunc;
/* Dynamic relocs are not propagated for SEC_DEBUGGING
sections because such sections are not SEC_ALLOC and
thus ld.so will not process them. */
switch (r_type)
{
default:
-bad_ifunc_reloc:
+ bad_ifunc_reloc:
if (h->root.root.string)
name = h->root.root.string;
else
NULL);
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: relocation %s against STT_GNU_IFUNC "
+ (_("%pB: relocation %s against STT_GNU_IFUNC "
"symbol `%s' isn't supported"), input_bfd,
howto->name, name);
bfd_set_error (bfd_error_bad_value);
asection *sreloc;
bfd_vma offset;
-do_ifunc_pointer:
+ do_ifunc_pointer:
/* Need a dynamic relocation to get the real function
adddress. */
offset = _bfd_elf_section_offset (output_bfd,
if (POINTER_LOCAL_IFUNC_P (info, h))
{
- info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+ info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
h->root.root.string,
h->root.u.def.section->owner);
}
}
+ skip_ifunc:
resolved_to_zero = (eh != NULL
&& UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh));
switch (r_type)
{
case R_386_GOT32X:
- /* Avoid optimizing _DYNAMIC since ld.so may use its
- link-time address. */
- if (h == htab->elf.hdynamic)
- goto r_386_got32;
-
- if (bfd_link_pic (info))
- {
- /* It is OK to convert mov to lea and convert indirect
- branch to direct branch. It is OK to convert adc,
- add, and, cmp, or, sbb, sub, test, xor only when PIC
- is false. */
- unsigned int opcode, addend;
- addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if (addend != 0)
- goto r_386_got32;
- opcode = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
- if (opcode != 0x8b && opcode != 0xff)
- goto r_386_got32;
- }
-
- /* Resolve "mov GOT[(%reg)], %reg",
- "call/jmp *GOT[(%reg)]", "test %reg, foo@GOT[(%reg)]"
- and "binop foo@GOT[(%reg)], %reg". */
- if (h == NULL
- || (h->plt.offset == (bfd_vma) -1
- && h->got.offset == (bfd_vma) -1)
- || htab->elf.sgotplt == NULL)
- abort ();
-
- offplt = (htab->elf.sgotplt->output_section->vma
- + htab->elf.sgotplt->output_offset);
-
- /* It is relative to .got.plt section. */
- if (h->got.offset != (bfd_vma) -1)
- /* Use GOT entry. Mask off the least significant bit in
- GOT offset which may be set by R_386_GOT32 processing
- below. */
- relocation = (htab->elf.sgot->output_section->vma
- + htab->elf.sgot->output_offset
- + (h->got.offset & ~1) - offplt);
- else
- /* Use GOTPLT entry. */
- relocation = (h->plt.offset / plt_entry_size
- - htab->plt.has_plt0 + 3) * 4;
-
- if (!bfd_link_pic (info))
- {
- /* If not PIC, add the .got.plt section address for
- baseless addressing. */
- unsigned int modrm;
- modrm = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
- if ((modrm & 0xc7) == 0x5)
- relocation += offplt;
- }
-
- unresolved_reloc = FALSE;
- break;
-
case R_386_GOT32:
-r_386_got32:
/* Relocation is to the entry for this symbol in the global
offset table. */
if (htab->elf.sgot == NULL)
we don't know what the GOT base is. */
const char *name;
-disallow_got32:
+ disallow_got32:
if (h == NULL || h->root.root.string == NULL)
name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym,
NULL);
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: direct GOT relocation %s against `%s'"
+ (_("%pB: direct GOT relocation %s against `%s'"
" without base register can not be used"
" when making a shared object"),
input_bfd, howto->name, name);
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: relocation R_386_GOTOFF against undefined %s"
+ (_("%pB: relocation R_386_GOTOFF against undefined %s"
" `%s' can not be used when making a shared object"),
input_bfd, v, h->root.root.string);
bfd_set_error (bfd_error_bad_value);
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B: relocation R_386_GOTOFF against protected %s"
+ (_("%pB: relocation R_386_GOTOFF against protected %s"
" `%s' can not be used when making a shared object"),
input_bfd,
h->type == STT_FUNC ? "function" : "data",
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"),
+ (_("%pB(%pA+%#" PRIx64 "): unresolvable %s relocation against symbol `%s'"),
input_bfd,
input_section,
- rel->r_offset,
+ (uint64_t) rel->r_offset,
howto->name,
h->root.root.string);
return FALSE;
}
-do_relocation:
+ do_relocation:
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
relocation, 0);
-check_relocation_error:
+ check_relocation_error:
if (r != bfd_reloc_ok)
{
const char *name;
if (name == NULL)
return FALSE;
if (*name == '\0')
- name = bfd_section_name (input_bfd, sec);
+ name = bfd_section_name (sec);
}
if (r == bfd_reloc_overflow)
{
_bfd_error_handler
/* xgettext:c-format */
- (_("%B(%A+%#Lx): reloc against `%s': error %d"),
+ (_("%pB(%pA+%#" PRIx64 "): reloc against `%s': error %d"),
input_bfd, input_section,
- rel->r_offset, name, (int) r);
+ (uint64_t) rel->r_offset, name, (int) r);
return FALSE;
}
}
+ got_offset);
if (PLT_LOCAL_IFUNC_P (info, h))
{
- info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+ info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
h->root.root.string,
h->root.u.def.section->owner);
sym->st_value = 0;
}
+ _bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
+
/* Don't generate dynamic GOT relocation against undefined weak
symbol in executable. */
if (h->got.offset != (bfd_vma) -1
}
if (SYMBOL_REFERENCES_LOCAL_P (info, h))
{
- info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"),
+ info->callbacks->minfo (_("Local IFUNC function `%s' in %pB\n"),
h->root.root.string,
h->root.u.def.section->owner);
else
{
BFD_ASSERT((h->got.offset & 1) == 0);
-do_glob_dat:
+ do_glob_dat:
bfd_put_32 (output_bfd, (bfd_vma) 0,
htab->elf.sgot->contents + h->got.offset);
rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT);
switch (get_elf_x86_backend_data (abfd)->target_os)
{
case is_normal:
+ case is_solaris:
non_lazy_plt = &elf_i386_non_lazy_plt;
lazy_ibt_plt = &elf_i386_lazy_ibt_plt;
non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt;
switch (get_elf_x86_backend_data (info->output_bfd)->target_os)
{
case is_normal:
+ case is_solaris:
init_table.plt0_pad_byte = 0x0;
init_table.lazy_plt = &elf_i386_lazy_plt;
init_table.non_lazy_plt = &elf_i386_non_lazy_plt;
#define elf_backend_linux_prpsinfo32_ugid16 TRUE
+#define elf32_bed elf32_i386_bed
+
#include "elf32-target.h"
/* FreeBSD support. */
"FreeBSD" label in the ELF header. So we put this label on all
executables and (for simplicity) also all other object files. */
-static void
-elf_i386_fbsd_post_process_headers (bfd *abfd, struct bfd_link_info *info)
+static bfd_boolean
+elf_i386_fbsd_init_file_header (bfd *abfd, struct bfd_link_info *info)
{
- _bfd_elf_post_process_headers (abfd, info);
+ if (!_bfd_elf_init_file_header (abfd, info))
+ return FALSE;
#ifdef OLD_FREEBSD_ABI_LABEL
{
memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
}
#endif
+ return TRUE;
}
-#undef elf_backend_post_process_headers
-#define elf_backend_post_process_headers elf_i386_fbsd_post_process_headers
+#undef elf_backend_init_file_header
+#define elf_backend_init_file_header elf_i386_fbsd_init_file_header
#undef elf32_bed
#define elf32_bed elf32_i386_fbsd_bed
#include "elf32-target.h"
+#undef elf_backend_init_file_header
+
/* Solaris 2. */
#undef TARGET_LITTLE_SYM
#undef TARGET_LITTLE_NAME
#define TARGET_LITTLE_NAME "elf32-i386-sol2"
-#undef elf_backend_post_process_headers
+static const struct elf_x86_backend_data elf_i386_solaris_arch_bed =
+ {
+ is_solaris /* os */
+ };
+
+#undef elf_backend_arch_data
+#define elf_backend_arch_data &elf_i386_solaris_arch_bed
/* Restore default: we cannot use ELFOSABI_SOLARIS, otherwise ELFOSABI_NONE
objects won't be recognized. */
#undef ELF_MACHINE_CODE
#define ELF_MACHINE_CODE EM_IAMCU
+#undef elf_backend_arch_data
+#define elf_backend_arch_data &elf_i386_arch_bed
+
#undef ELF_OSABI
#undef elf32_bed
#undef ELF_OSABI
#undef elf_backend_want_plt_sym
#define elf_backend_want_plt_sym 0
-#undef elf_backend_post_process_headers
#undef elf_backend_static_tls_alignment
/* NaCl uses substantially different PLT entries for the same effects. */
sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */
elf_i386_nacl_plt_entry, /* plt_entry */
NACL_PLT_ENTRY_SIZE, /* plt_entry_size */
+ NULL, /* plt_tlsdesc_entry */
+ 0, /* plt_tlsdesc_entry_size*/
+ 0, /* plt_tlsdesc_got1_offset */
+ 0, /* plt_tlsdesc_got2_offset */
+ 0, /* plt_tlsdesc_got1_insn_end */
+ 0, /* plt_tlsdesc_got2_insn_end */
2, /* plt0_got1_offset */
8, /* plt0_got2_offset */
0, /* plt0_got2_insn_end */
#define elf_backend_object_p elf32_i386_nacl_elf_object_p
#undef elf_backend_modify_segment_map
#define elf_backend_modify_segment_map nacl_modify_segment_map
-#undef elf_backend_modify_program_headers
-#define elf_backend_modify_program_headers nacl_modify_program_headers
+#undef elf_backend_modify_headers
+#define elf_backend_modify_headers nacl_modify_headers
#undef elf_backend_final_write_processing
#define elf_backend_final_write_processing nacl_final_write_processing
/* Restore defaults. */
#undef elf_backend_object_p
#undef elf_backend_modify_segment_map
-#undef elf_backend_modify_program_headers
+#undef elf_backend_modify_headers
#undef elf_backend_final_write_processing
/* VxWorks support. */