X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=fb5ed161f50c4cde39e8d7b24fe843fe18aaad09;hb=680e019e5aeec49734760653145fee89f0ddc00b;hp=377e76d0f3dc1327295c3f1339cffdaa8e79ae81;hpb=0a1b45a20eaa98d4d9026dc1fd17e79e741183af;p=binutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 377e76d0f3d..fb5ed161f50 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1,5 +1,5 @@ /* Intel 80386/80486-specific support for 32-bit ELF - Copyright (C) 1993-2021 Free Software Foundation, Inc. + Copyright (C) 1993-2022 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -26,41 +26,39 @@ /* 386 uses REL relocations instead of RELA. */ #define USE_REL 1 -#include "elf/i386.h" - static reloc_howto_type elf_howto_table[]= { HOWTO(R_386_NONE, 0, 3, 0, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_NONE", true, 0x00000000, 0x00000000, false), - HOWTO(R_386_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_PC32, 0, 2, 32, true, 0, complain_overflow_bitfield, + HOWTO(R_386_PC32, 0, 2, 32, true, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_PC32", true, 0xffffffff, 0xffffffff, true), - HOWTO(R_386_GOT32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_GOT32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_GOT32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_PLT32, 0, 2, 32, true, 0, complain_overflow_bitfield, + HOWTO(R_386_PLT32, 0, 2, 32, true, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_PLT32", true, 0xffffffff, 0xffffffff, true), - HOWTO(R_386_COPY, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_COPY, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_COPY", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_GLOB_DAT, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_GLOB_DAT, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_GLOB_DAT", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_JUMP_SLOT, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_JUMP_SLOT, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_JUMP_SLOT", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_RELATIVE, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_RELATIVE, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_RELATIVE", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_GOTOFF, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_GOTOFF, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_GOTOFF", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_GOTPC, 0, 2, 32, true, 0, complain_overflow_bitfield, + HOWTO(R_386_GOTPC, 0, 2, 32, true, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_GOTPC", true, 0xffffffff, 0xffffffff, true), @@ -72,22 +70,22 @@ static reloc_howto_type elf_howto_table[]= #define R_386_ext_offset (R_386_TLS_TPOFF - R_386_standard) /* These relocs are a GNU extension. */ - HOWTO(R_386_TLS_TPOFF, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_TPOFF, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_TPOFF", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_IE, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_IE, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_IE", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_GOTIE, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_GOTIE, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_GOTIE", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_LE, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_LE, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_LE", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_GD, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_GD, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_GD", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_LDM, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_LDM, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_LDM", true, 0xffffffff, 0xffffffff, false), HOWTO(R_386_16, 0, 1, 16, false, 0, complain_overflow_bitfield, @@ -106,40 +104,40 @@ static reloc_howto_type elf_howto_table[]= #define R_386_ext (R_386_PC8 + 1 - R_386_ext_offset) #define R_386_tls_offset (R_386_TLS_LDO_32 - R_386_ext) /* These are common with Solaris TLS implementation. */ - HOWTO(R_386_TLS_LDO_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_LDO_32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_LDO_32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_IE_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_IE_32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_IE_32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_LE_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_LE_32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_LE_32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_DTPMOD32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_DTPOFF32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_SIZE32, 0, 2, 32, false, 0, complain_overflow_unsigned, + HOWTO(R_386_SIZE32, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_SIZE32", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_GOTDESC, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_GOTDESC", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_DESC_CALL, 0, 0, 0, false, 0, complain_overflow_dont, + HOWTO(R_386_TLS_DESC_CALL, 0, 3, 0, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_DESC_CALL", false, 0, 0, false), - HOWTO(R_386_TLS_DESC, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_DESC, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_TLS_DESC", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_IRELATIVE, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_IRELATIVE, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_IRELATIVE", true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_GOT32X, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_GOT32X, 0, 2, 32, false, 0, complain_overflow_dont, bfd_elf_generic_reloc, "R_386_GOT32X", true, 0xffffffff, 0xffffffff, false), @@ -181,10 +179,6 @@ static reloc_howto_type elf_howto_table[]= }; -#define X86_PCREL_TYPE_P(TYPE) ((TYPE) == R_386_PC32) - -#define X86_SIZE_TYPE_P(TYPE) ((TYPE) == R_386_SIZE32) - #ifdef DEBUG_GEN_RELOC #define TRACE(str) \ fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) @@ -528,7 +522,7 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) Functions named elf_i386_* are called by external routines, other functions are only called locally. elf_i386_* functions appear in this file more or less in the order in which they are called - from external routines. eg. elf_i386_check_relocs is called + from external routines. eg. elf_i386_scan_relocs is called early in the link process, elf_i386_finish_dynamic_sections is one of the last functions. */ @@ -1112,7 +1106,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, } /* We checked the transition before when we were called from - elf_i386_check_relocs. We only want to check the new + elf_i386_scan_relocs. We only want to check the new transition which hasn't been checked before. */ check = new_to_type != to_type && from_type == to_type; to_type = new_to_type; @@ -1452,26 +1446,21 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, return true; } -/* Rename some of the generic section flags to better document how they - are used here. */ -#define check_relocs_failed sec_flg0 - /* Look through the relocs for a section during the first phase, and - calculate needed space in the global offset table, procedure linkage - table, and dynamic reloc sections. */ + calculate needed space in the global offset table, and procedure + linkage table. */ static bool -elf_i386_check_relocs (bfd *abfd, - struct bfd_link_info *info, - asection *sec, - const Elf_Internal_Rela *relocs) +elf_i386_scan_relocs (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) { struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; - asection *sreloc; bfd_byte *contents; bool converted; @@ -1501,8 +1490,6 @@ elf_i386_check_relocs (bfd *abfd, converted = false; - sreloc = NULL; - rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { @@ -1673,25 +1660,12 @@ elf_i386_check_relocs (bfd *abfd, { bfd_signed_vma *local_got_refcounts; + if (!elf_x86_allocate_local_got_info (abfd, + symtab_hdr->sh_info)) + goto error_return; + /* 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 (bfd_vma) + sizeof(char)); - local_got_refcounts = (bfd_signed_vma *) - bfd_zalloc (abfd, size); - if (local_got_refcounts == NULL) - goto error_return; - elf_local_got_refcounts (abfd) = local_got_refcounts; - elf_x86_local_tlsdesc_gotent (abfd) - = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); - elf_x86_local_got_tls_type (abfd) - = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); - } local_got_refcounts[r_symndx] = 1; old_tls_type = elf_x86_local_got_tls_type (abfd) [r_symndx]; } @@ -1805,6 +1779,23 @@ elf_i386_check_relocs (bfd *abfd, func_pointer_ref = true; } + if (h->pointer_equality_needed + && h->type == STT_FUNC + && eh->def_protected + && elf_has_indirect_extern_access (h->root.u.def.section->owner)) + { + /* Disallow non-canonical reference to canonical + protected function. */ + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: non-canonical reference to canonical " + "protected function `%s' in %pB"), + abfd, h->root.root.string, + h->root.u.def.section->owner); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + if (!func_pointer_ref) { /* If this reloc is in a read-only section, we might @@ -1815,6 +1806,9 @@ elf_i386_check_relocs (bfd *abfd, adjust_dynamic_symbol. */ h->non_got_ref = 1; + if (!elf_has_indirect_extern_access (sec->owner)) + eh->non_got_ref_without_indirect_extern_access = 1; + /* We may need a .plt entry if the symbol is a function defined in a shared lib or is a function referenced from the code or read-only section. */ @@ -1827,24 +1821,12 @@ elf_i386_check_relocs (bfd *abfd, size_reloc = false; do_size: if (!no_dynreloc - && NEED_DYNAMIC_RELOCATION_P (info, false, h, sec, r_type, - R_386_32)) + && NEED_DYNAMIC_RELOCATION_P (false, info, false, h, sec, + r_type, R_386_32)) { struct elf_dyn_relocs *p; struct elf_dyn_relocs **head; - /* We must copy these reloc types into the output file. - Create a reloc section in dynobj and make room for - this reloc. */ - if (sreloc == NULL) - { - sreloc = _bfd_elf_make_dynamic_reloc_section - (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ false); - - if (sreloc == NULL) - goto error_return; - } - /* If this is a global symbol, we count the number of relocations we need for this symbol. */ if (h != NULL) @@ -1915,13 +1897,14 @@ elf_i386_check_relocs (bfd *abfd, if (elf_section_data (sec)->this_hdr.contents != contents) { - if (!converted && !info->keep_memory) + if (!converted && !_bfd_link_keep_memory (info)) free (contents); else { /* Cache the section contents for elf_link_input_bfd if any load is converted or --no-keep-memory isn't used. */ elf_section_data (sec)->this_hdr.contents = contents; + info->cache_size += sec->size; } } @@ -1938,6 +1921,24 @@ elf_i386_check_relocs (bfd *abfd, return false; } +static bool +elf_i386_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + bfd *abfd; + + /* Scan relocations after rel_from_abs has been set on __ehdr_start. */ + for (abfd = info->input_bfds; + abfd != (bfd *) NULL; + abfd = abfd->link.next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && !_bfd_elf_link_iterate_on_relocs (abfd, info, + elf_i386_scan_relocs)) + return false; + + return _bfd_x86_elf_always_size_sections (output_bfd, info); +} + /* Set the correct type for an x86 ELF section. We do this by the section name, which is a hack, but ought to work. */ @@ -2014,7 +2015,7 @@ elf_i386_relocate_section (bfd *output_bfd, bool is_vxworks_tls; unsigned plt_entry_size; - /* Skip if check_relocs failed. */ + /* Skip if check_relocs or scan_relocs failed. */ if (input_section->check_relocs_failed) return false; @@ -2302,7 +2303,7 @@ elf_i386_relocate_section (bfd *output_bfd, { /* This references the local defitionion. We must initialize this entry in the global offset table. - Since the offset must always be a multiple of 8, + Since the offset must always be a multiple of 4, we use the least significant bit to record whether we have initialized it already. @@ -2489,8 +2490,10 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_put_32 (output_bfd, relocation, htab->elf.sgot->contents + off); h->got.offset |= 1; - - if (GENERATE_RELATIVE_RELOC_P (info, h)) + /* NB: Don't generate relative relocation here if + it has been generated by DT_RELR. */ + if (!info->enable_dt_relr + && GENERATE_RELATIVE_RELOC_P (info, h)) { /* PR ld/21402: If this symbol isn't dynamic in PIC, generate R_386_RELATIVE here. */ @@ -2520,7 +2523,9 @@ elf_i386_relocate_section (bfd *output_bfd, htab->elf.sgot->contents + off); local_got_offsets[r_symndx] |= 1; - if (bfd_link_pic (info)) + /* NB: Don't generate relative relocation here if it + has been generated by DT_RELR. */ + if (!info->enable_dt_relr && bfd_link_pic (info)) relative_reloc = true; } } @@ -2716,12 +2721,14 @@ elf_i386_relocate_section (bfd *output_bfd, || is_vxworks_tls) break; - if (GENERATE_DYNAMIC_RELOCATION_P (info, eh, r_type, sec, - false, resolved_to_zero, + if (GENERATE_DYNAMIC_RELOCATION_P (false, info, eh, r_type, + sec, false, + resolved_to_zero, (r_type == R_386_PC32))) { Elf_Internal_Rela outrel; bool skip, relocate; + bool generate_dynamic_reloc = true; asection *sreloc; /* When generating a shared object, these relocations @@ -2743,29 +2750,39 @@ elf_i386_relocate_section (bfd *output_bfd, if (skip) memset (&outrel, 0, sizeof outrel); - else if (COPY_INPUT_RELOC_P (info, h, r_type)) + else if (COPY_INPUT_RELOC_P (false, info, h, r_type)) outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); else { /* This symbol is local, or marked to become local. */ relocate = true; - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + /* NB: Don't generate relative relocation here if it + has been generated by DT_RELR. */ + if (info->enable_dt_relr) + generate_dynamic_reloc = false; + else + { + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - if (htab->params->report_relative_reloc) - _bfd_x86_elf_link_report_relative_reloc - (info, input_section, h, sym, "R_386_RELATIVE", - &outrel); + if (htab->params->report_relative_reloc) + _bfd_x86_elf_link_report_relative_reloc + (info, input_section, h, sym, "R_386_RELATIVE", + &outrel); + } } - sreloc = elf_section_data (input_section)->sreloc; - - if (sreloc == NULL || sreloc->contents == NULL) + if (generate_dynamic_reloc) { - r = bfd_reloc_notsupported; - goto check_relocation_error; - } + sreloc = elf_section_data (input_section)->sreloc; - elf_append_rel (output_bfd, sreloc, &outrel); + if (sreloc == NULL || sreloc->contents == NULL) + { + r = bfd_reloc_notsupported; + goto check_relocation_error; + } + + elf_append_rel (output_bfd, sreloc, &outrel); + } /* If this reloc is against an external symbol, we do not want to fiddle with the addend. Otherwise, we @@ -3791,6 +3808,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, Elf_Internal_Rela rel; asection *relgot = htab->elf.srelgot; const char *relative_reloc_name = NULL; + bool generate_dynamic_reloc = true; /* This symbol has an entry in the global offset table. Set it up. */ @@ -3873,8 +3891,13 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, && SYMBOL_REFERENCES_LOCAL_P (info, h)) { BFD_ASSERT((h->got.offset & 1) != 0); - rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - relative_reloc_name = "R_386_RELATIVE"; + if (info->enable_dt_relr) + generate_dynamic_reloc = false; + else + { + rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + relative_reloc_name = "R_386_RELATIVE"; + } } else { @@ -3885,12 +3908,15 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } - if (relative_reloc_name != NULL - && htab->params->report_relative_reloc) - _bfd_x86_elf_link_report_relative_reloc - (info, relgot, h, sym, relative_reloc_name, &rel); + if (generate_dynamic_reloc) + { + if (relative_reloc_name != NULL + && htab->params->report_relative_reloc) + _bfd_x86_elf_link_report_relative_reloc + (info, relgot, h, sym, relative_reloc_name, &rel); - elf_append_rel (output_bfd, relgot, &rel); + elf_append_rel (output_bfd, relgot, &rel); + } } if (h->needs_copy) @@ -4013,6 +4039,14 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, if (htab->elf.splt && htab->elf.splt->size > 0) { + if (bfd_is_abs_section (htab->elf.splt->output_section)) + { + info->callbacks->einfo + (_("%F%P: discarded output section: `%pA'\n"), + htab->elf.splt); + return false; + } + /* UnixWare sets the entsize of .plt to 4, although that doesn't really seem like the right value. */ elf_section_data (htab->elf.splt->output_section) @@ -4395,7 +4429,7 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info) #define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible -#define elf_backend_check_relocs elf_i386_check_relocs +#define elf_backend_always_size_sections elf_i386_always_size_sections #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections #define elf_backend_fake_sections elf_i386_fake_sections #define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections