X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf.c;h=9ca42e10d8e5b28090d6ce73cc65fbd456210123;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=5b3d27c67396c584aad88c352b9bf2270279c8c9;hpb=64029e93683a266c38d19789e780f3748bd6a188;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index 5b3d27c673..9ca42e10d8 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1,6 +1,6 @@ /* ELF executable support for BFD. - 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. @@ -35,6 +35,7 @@ SECTION /* For sparc64-cross-sparc32. */ #define _SYSCALL32 #include "sysdep.h" +#include #include "bfd.h" #include "bfdlink.h" #include "libbfd.h" @@ -50,10 +51,7 @@ SECTION static int elf_sort_sections (const void *, const void *); static bfd_boolean assign_file_positions_except_relocs (bfd *, struct bfd_link_info *); -static bfd_boolean prep_headers (bfd *); static bfd_boolean swap_out_syms (bfd *, struct elf_strtab_hash **, int) ; -static bfd_boolean elf_read_notes (bfd *, file_ptr, bfd_size_type, - size_t align) ; static bfd_boolean elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset, size_t align); @@ -274,7 +272,7 @@ bfd_elf_mkcorefile (bfd *abfd) return elf_tdata (abfd)->core != NULL; } -static char * +char * bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) { Elf_Internal_Shdr **i_shdrp; @@ -298,16 +296,10 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) /* Allocate and clear an extra byte at the end, to prevent crashes in case the string table is not terminated. */ if (shstrtabsize + 1 <= 1 - || shstrtabsize > bfd_get_file_size (abfd) || bfd_seek (abfd, offset, SEEK_SET) != 0 - || (shstrtab = (bfd_byte *) bfd_alloc (abfd, shstrtabsize + 1)) == NULL) - shstrtab = NULL; - else if (bfd_bread (shstrtab, shstrtabsize, abfd) != shstrtabsize) + || (shstrtab = _bfd_alloc_and_read (abfd, shstrtabsize + 1, + shstrtabsize)) == NULL) { - if (bfd_get_error () != bfd_error_system_call) - bfd_set_error (bfd_error_file_truncated); - bfd_release (abfd, shstrtab); - shstrtab = NULL; /* Once we've failed to read it, make sure we don't keep trying. Otherwise, we'll keep allocating space for the string table over and over. */ @@ -350,6 +342,16 @@ bfd_elf_string_from_elf_section (bfd *abfd, if (bfd_elf_get_str_section (abfd, shindex) == NULL) return NULL; } + else + { + /* PR 24273: The string section's contents may have already + been loaded elsewhere, eg because a corrupt file has the + string section index in the ELF header pointing at a group + section. So be paranoid, and test that the last byte of + the section is zero. */ + if (hdr->sh_size == 0 || hdr->contents[hdr->sh_size - 1] != 0) + return NULL; + } if (strindex >= hdr->sh_size) { @@ -394,7 +396,7 @@ bfd_elf_get_elf_syms (bfd *ibfd, Elf_Internal_Sym *isymend; const struct elf_backend_data *bed; size_t extsym_size; - bfd_size_type amt; + size_t amt; file_ptr pos; if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) @@ -440,11 +442,16 @@ bfd_elf_get_elf_syms (bfd *ibfd, alloc_intsym = NULL; bed = get_elf_backend_data (ibfd); extsym_size = bed->s->sizeof_sym; - amt = (bfd_size_type) symcount * extsym_size; + if (_bfd_mul_overflow (symcount, extsym_size, &amt)) + { + bfd_set_error (bfd_error_file_too_big); + intsym_buf = NULL; + goto out; + } pos = symtab_hdr->sh_offset + symoffset * extsym_size; if (extsym_buf == NULL) { - alloc_ext = bfd_malloc2 (symcount, extsym_size); + alloc_ext = bfd_malloc (amt); extsym_buf = alloc_ext; } if (extsym_buf == NULL @@ -459,12 +466,16 @@ bfd_elf_get_elf_syms (bfd *ibfd, extshndx_buf = NULL; else { - amt = (bfd_size_type) symcount * sizeof (Elf_External_Sym_Shndx); + if (_bfd_mul_overflow (symcount, sizeof (Elf_External_Sym_Shndx), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + intsym_buf = NULL; + goto out; + } pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx); if (extshndx_buf == NULL) { - alloc_extshndx = (Elf_External_Sym_Shndx *) - bfd_malloc2 (symcount, sizeof (Elf_External_Sym_Shndx)); + alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); extshndx_buf = alloc_extshndx; } if (extshndx_buf == NULL @@ -478,8 +489,12 @@ bfd_elf_get_elf_syms (bfd *ibfd, if (intsym_buf == NULL) { - alloc_intsym = (Elf_Internal_Sym *) - bfd_malloc2 (symcount, sizeof (Elf_Internal_Sym)); + if (_bfd_mul_overflow (symcount, sizeof (Elf_Internal_Sym), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto out; + } + alloc_intsym = (Elf_Internal_Sym *) bfd_malloc (amt); intsym_buf = alloc_intsym; if (intsym_buf == NULL) goto out; @@ -498,17 +513,14 @@ bfd_elf_get_elf_syms (bfd *ibfd, _bfd_error_handler (_("%pB symbol number %lu references" " nonexistent SHT_SYMTAB_SHNDX section"), ibfd, (unsigned long) symoffset); - if (alloc_intsym != NULL) - free (alloc_intsym); + free (alloc_intsym); intsym_buf = NULL; goto out; } out: - if (alloc_ext != NULL) - free (alloc_ext); - if (alloc_extshndx != NULL) - free (alloc_extshndx); + free (alloc_ext); + free (alloc_extshndx); return intsym_buf; } @@ -536,7 +548,7 @@ bfd_elf_sym_name (bfd *abfd, if (name == NULL) name = "(null)"; else if (sym_sec && *name == '\0') - name = bfd_section_name (abfd, sym_sec); + name = bfd_section_name (sym_sec); return name; } @@ -621,15 +633,14 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) { /* We keep a list of elf section headers for group sections, so we can find them quickly. */ - bfd_size_type amt; + size_t amt; elf_tdata (abfd)->num_group = num_group; - elf_tdata (abfd)->group_sect_ptr = (Elf_Internal_Shdr **) - bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *)); + amt = num_group * sizeof (Elf_Internal_Shdr *); + elf_tdata (abfd)->group_sect_ptr + = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt); if (elf_tdata (abfd)->group_sect_ptr == NULL) return FALSE; - memset (elf_tdata (abfd)->group_sect_ptr, 0, - num_group * sizeof (Elf_Internal_Shdr *)); num_group = 0; for (i = 0; i < shnum; i++) @@ -651,28 +662,13 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) num_group += 1; /* Read the raw contents. */ - BFD_ASSERT (sizeof (*dest) >= 4); - amt = shdr->sh_size * sizeof (*dest) / 4; - shdr->contents = (unsigned char *) - bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4); - /* PR binutils/4110: Handle corrupt group headers. */ - if (shdr->contents == NULL) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB: corrupt size field in group section" - " header: %#" PRIx64), - abfd, (uint64_t) shdr->sh_size); - bfd_set_error (bfd_error_bad_value); - -- num_group; - continue; - } - - memset (shdr->contents, 0, amt); - - if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 - || (bfd_bread (shdr->contents, shdr->sh_size, abfd) - != shdr->sh_size)) + BFD_ASSERT (sizeof (*dest) >= 4 && sizeof (*dest) % 4 == 0); + shdr->contents = NULL; + if (_bfd_mul_overflow (shdr->sh_size, + sizeof (*dest) / 4, &amt) + || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 + || !(shdr->contents + = _bfd_alloc_and_read (abfd, amt, shdr->sh_size))) { _bfd_error_handler /* xgettext:c-format */ @@ -681,10 +677,6 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) abfd, (uint64_t) shdr->sh_size); bfd_set_error (bfd_error_bad_value); -- num_group; - /* PR 17510: If the group contents are even - partially corrupt, do not allow any of the - contents to be used. */ - memset (shdr->contents, 0, amt); continue; } @@ -704,6 +696,7 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) idx = H_GET_32 (abfd, src); if (src == shdr->contents) { + dest->shdr = NULL; dest->flags = idx; if (shdr->bfd_section != NULL && (idx & GRP_COMDAT)) shdr->bfd_section->flags @@ -861,11 +854,10 @@ _bfd_elf_setup_sections (bfd *abfd) if (elfsec == 0) { const struct elf_backend_data *bed = get_elf_backend_data (abfd); - if (bed->link_order_error_handler) - bed->link_order_error_handler - /* xgettext:c-format */ - (_("%pB: warning: sh_link not set for section `%pA'"), - abfd, s); + bed->link_order_error_handler + /* xgettext:c-format */ + (_("%pB: warning: sh_link not set for section `%pA'"), + abfd, s); } else { @@ -963,6 +955,14 @@ bfd_elf_is_group_section (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) return elf_next_in_group (sec) != NULL; } +const char * +bfd_elf_group_name (bfd *abfd ATTRIBUTE_UNUSED, const asection *sec) +{ + if (elf_sec_group (sec) != NULL) + return elf_group_name (sec); + return NULL; +} + static char * convert_debug_to_zdebug (bfd *abfd, const char *name) { @@ -988,6 +988,18 @@ convert_zdebug_to_debug (bfd *abfd, const char *name) return new_name; } +/* This a copy of lto_section defined in GCC (lto-streamer.h). */ + +struct lto_section +{ + int16_t major_version; + int16_t minor_version; + unsigned char slim_object; + + /* Flags is a private field that is not defined publicly. */ + uint16_t flags; +}; + /* Make a BFD section from an ELF section. We store a pointer to the BFD section in the bfd_section field of the header. */ @@ -1000,6 +1012,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, asection *newsect; flagword flags; const struct elf_backend_data *bed; + unsigned int opb = bfd_octets_per_byte (abfd, NULL); if (hdr->bfd_section != NULL) return TRUE; @@ -1018,12 +1031,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, newsect->filepos = hdr->sh_offset; - if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) - || ! bfd_set_section_size (abfd, newsect, hdr->sh_size) - || ! bfd_set_section_alignment (abfd, newsect, - bfd_log2 (hdr->sh_addralign))) - return FALSE; - flags = SEC_NO_FLAGS; if (hdr->sh_type != SHT_NOBITS) flags |= SEC_HAS_CONTENTS; @@ -1056,33 +1063,47 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, if ((hdr->sh_flags & SHF_EXCLUDE) != 0) flags |= SEC_EXCLUDE; + switch (elf_elfheader (abfd)->e_ident[EI_OSABI]) + { + /* FIXME: We should not recognize SHF_GNU_MBIND for ELFOSABI_NONE, + but binutils as of 2019-07-23 did not set the EI_OSABI header + byte. */ + case ELFOSABI_NONE: + case ELFOSABI_GNU: + case ELFOSABI_FREEBSD: + if ((hdr->sh_flags & SHF_GNU_MBIND) != 0) + elf_tdata (abfd)->has_gnu_osabi |= elf_gnu_osabi_mbind; + break; + } + if ((flags & SEC_ALLOC) == 0) { /* The debugging sections appear to be recognized only by name, not any sort of flag. Their SEC_ALLOC bits are cleared. */ if (name [0] == '.') { - const char *p; - int n; - if (name[1] == 'd') - p = ".debug", n = 6; - else if (name[1] == 'g' && name[2] == 'n') - p = ".gnu.linkonce.wi.", n = 17; - else if (name[1] == 'g' && name[2] == 'd') - p = ".gdb_index", n = 11; /* yes we really do mean 11. */ - else if (name[1] == 'l') - p = ".line", n = 5; - else if (name[1] == 's') - p = ".stab", n = 5; - else if (name[1] == 'z') - p = ".zdebug", n = 7; - else - p = NULL, n = 0; - if (p != NULL && strncmp (name, p, n) == 0) + if (strncmp (name, ".debug", 6) == 0 + || strncmp (name, ".gnu.linkonce.wi.", 17) == 0 + || strncmp (name, ".zdebug", 7) == 0) + flags |= SEC_DEBUGGING | SEC_ELF_OCTETS; + else if (strncmp (name, GNU_BUILD_ATTRS_SECTION_NAME, 21) == 0 + || strncmp (name, ".note.gnu", 9) == 0) + { + flags |= SEC_ELF_OCTETS; + opb = 1; + } + else if (strncmp (name, ".line", 5) == 0 + || strncmp (name, ".stab", 5) == 0 + || strcmp (name, ".gdb_index") == 0) flags |= SEC_DEBUGGING; } } + if (!bfd_set_section_vma (newsect, hdr->sh_addr / opb) + || !bfd_set_section_size (newsect, hdr->sh_size) + || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign))) + return FALSE; + /* As a GNU extension, if the name begins with .gnu.linkonce, we only link a single copy of the section. This is used to support g++. g++ will emit each template expansion in its own section. @@ -1093,14 +1114,14 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, && elf_next_in_group (newsect) == NULL) flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + if (!bfd_set_section_flags (newsect, flags)) + return FALSE; + bed = get_elf_backend_data (abfd); if (bed->elf_backend_section_flags) - if (! bed->elf_backend_section_flags (&flags, hdr)) + if (!bed->elf_backend_section_flags (hdr)) return FALSE; - if (! bfd_set_section_flags (abfd, newsect, flags)) - return FALSE; - /* We do not parse the PT_NOTE segments as we are interested even in the separate debug info files which may have the segments offsets corrupted. PT_NOTEs from the core files are currently not parsed using BFD. */ @@ -1116,7 +1137,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, free (contents); } - if ((flags & SEC_ALLOC) != 0) + if ((newsect->flags & SEC_ALLOC) != 0) { Elf_Internal_Phdr *phdr; unsigned int i, nload; @@ -1142,9 +1163,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, || phdr->p_type == PT_TLS) && ELF_SECTION_IN_SEGMENT (hdr, phdr)) { - if ((flags & SEC_LOAD) == 0) + if ((newsect->flags & SEC_LOAD) == 0) newsect->lma = (phdr->p_paddr - + hdr->sh_addr - phdr->p_vaddr); + + hdr->sh_addr - phdr->p_vaddr) / opb; else /* We used to use the same adjustment for SEC_LOAD sections, but that doesn't work if the segment @@ -1154,7 +1175,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, segment will contain sections with contiguous LMAs, even if the VMAs are not. */ newsect->lma = (phdr->p_paddr - + hdr->sh_offset - phdr->p_offset); + + hdr->sh_offset - phdr->p_offset) / opb; /* With contiguous segments, we can't tell from file offsets whether a section with zero size should @@ -1170,18 +1191,19 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, /* Compress/decompress DWARF debug sections with names: .debug_* and .zdebug_*, after the section flags is set. */ - if ((flags & SEC_DEBUGGING) + if ((newsect->flags & SEC_DEBUGGING) && ((name[1] == 'd' && name[6] == '_') || (name[1] == 'z' && name[7] == '_'))) { enum { nothing, compress, decompress } action = nothing; int compression_header_size; bfd_size_type uncompressed_size; + unsigned int uncompressed_align_power; bfd_boolean compressed = bfd_is_section_compressed_with_header (abfd, newsect, &compression_header_size, - &uncompressed_size); - + &uncompressed_size, + &uncompressed_align_power); if (compressed) { /* Compressed section. Check if we should decompress. */ @@ -1241,7 +1263,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, char *new_name = convert_zdebug_to_debug (abfd, name); if (new_name == NULL) return FALSE; - bfd_rename_section (abfd, newsect, new_name); + bfd_rename_section (newsect, new_name); } } else @@ -1250,6 +1272,17 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, newsect->flags |= SEC_ELF_RENAME; } + /* GCC uses .gnu.lto_.lto. as a LTO bytecode information + section. */ + const char *lto_section_name = ".gnu.lto_.lto."; + if (strncmp (name, lto_section_name, strlen (lto_section_name)) == 0) + { + struct lto_section lsection; + if (bfd_get_section_contents (abfd, newsect, &lsection, 0, + sizeof (struct lto_section))) + abfd->lto_slim_object = lsection.slim_object; + } + return TRUE; } @@ -1299,15 +1332,15 @@ static bfd_boolean section_match (const Elf_Internal_Shdr * a, const Elf_Internal_Shdr * b) { - return - a->sh_type == b->sh_type - && (a->sh_flags & ~ SHF_INFO_LINK) - == (b->sh_flags & ~ SHF_INFO_LINK) - && a->sh_addralign == b->sh_addralign - && a->sh_size == b->sh_size - && a->sh_entsize == b->sh_entsize - /* FIXME: Check sh_addr ? */ - ; + if (a->sh_type != b->sh_type + || ((a->sh_flags ^ b->sh_flags) & ~SHF_INFO_LINK) != 0 + || a->sh_addralign != b->sh_addralign + || a->sh_entsize != b->sh_entsize) + return FALSE; + if (a->sh_type == SHT_SYMTAB + || a->sh_type == SHT_STRTAB) + return TRUE; + return a->sh_size == b->sh_size; } /* Find a section in OBFD that has the same characteristics @@ -1387,9 +1420,8 @@ copy_special_section_fields (const bfd *ibfd, } /* Allow the target a chance to decide how these fields should be set. */ - if (bed->elf_backend_copy_special_section_fields != NULL - && bed->elf_backend_copy_special_section_fields - (ibfd, obfd, iheader, oheader)) + if (bed->elf_backend_copy_special_section_fields (ibfd, obfd, + iheader, oheader)) return TRUE; /* We have an iheader which might match oheader, and which has non-zero @@ -1573,8 +1605,8 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) { /* Final attempt. Call the backend copy function with a NULL input section. */ - if (bed->elf_backend_copy_special_section_fields != NULL) - bed->elf_backend_copy_special_section_fields (ibfd, obfd, NULL, oheader); + (void) bed->elf_backend_copy_special_section_fields (ibfd, obfd, + NULL, oheader); } } @@ -1843,15 +1875,16 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) return TRUE; error_return: - if (dynbuf != NULL) - free (dynbuf); + free (dynbuf); return FALSE; } -/* Get version string. */ +/* Get version name. If BASE_P is TRUE, return "Base" for VER_FLG_BASE + and return symbol version for symbol version itself. */ const char * _bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol, + bfd_boolean base_p, bfd_boolean *hidden) { const char *version_string = NULL; @@ -1869,10 +1902,18 @@ _bfd_elf_get_symbol_version_string (bfd *abfd, asymbol *symbol, && (vernum > elf_tdata (abfd)->cverdefs || (elf_tdata (abfd)->verdef[0].vd_flags == VER_FLG_BASE))) - version_string = "Base"; + version_string = base_p ? "Base" : ""; else if (vernum <= elf_tdata (abfd)->cverdefs) - version_string = - elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + { + const char *nodename + = elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + version_string = ""; + if (base_p + || nodename == NULL + || symbol->name == NULL + || strcmp (symbol->name, nodename) != 0) + version_string = nodename; + } else { Elf_Internal_Verneed *t; @@ -1953,6 +1994,7 @@ bfd_elf_print_symbol (bfd *abfd, /* If we have version information, print it. */ version_string = _bfd_elf_get_symbol_version_string (abfd, symbol, + TRUE, &hidden); if (version_string) { @@ -2024,9 +2066,14 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) sections_being_created = NULL; if (sections_being_created == NULL) { - /* FIXME: It would be more efficient to attach this array to the bfd somehow. */ - sections_being_created = (bfd_boolean *) - bfd_zalloc (abfd, elf_numsections (abfd) * sizeof (bfd_boolean)); + size_t amt = elf_numsections (abfd) * sizeof (bfd_boolean); + + /* PR 26005: Do not use bfd_zalloc here as the memory might + be released before the bfd has been fully scanned. */ + sections_being_created = (bfd_boolean *) bfd_malloc (amt); + if (sections_being_created == NULL) + return FALSE; + memset (sections_being_created, FALSE, amt); sections_being_created_abfd = abfd; } if (sections_being_created [shindex]) @@ -2247,7 +2294,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (entry->ndx == shindex) goto success; - entry = bfd_alloc (abfd, sizeof * entry); + entry = bfd_alloc (abfd, sizeof (*entry)); if (entry == NULL) goto fail; entry->ndx = shindex; @@ -2384,15 +2431,18 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) && ! bfd_section_from_shdr (abfd, hdr->sh_link)) goto fail; - /* If this reloc section does not use the main symbol table we - don't treat it as a reloc section. BFD can't adequately - represent such a section, so at least for now, we don't - try. We just present it as a normal section. We also - can't use it as a reloc section if it points to the null - section, an invalid section, another reloc section, or its - sh_link points to the null section. */ - if (hdr->sh_link != elf_onesymtab (abfd) + /* If this is an alloc section in an executable or shared + library, or the reloc section does not use the main symbol + table we don't treat it as a reloc section. BFD can't + adequately represent such a section, so at least for now, + we don't try. We just present it as a normal section. We + also can't use it as a reloc section if it points to the + null section, an invalid section, another reloc section, or + its sh_link points to the null section. */ + if (((abfd->flags & (DYNAMIC | EXEC_P)) != 0 + && (hdr->sh_flags & SHF_ALLOC) != 0) || hdr->sh_link == SHN_UNDEF + || hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF || hdr->sh_info >= num_sec || elf_elfsections (abfd)[hdr->sh_info]->sh_type == SHT_REL @@ -2416,9 +2466,22 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) else p_hdr = &esdt->rel.hdr; - /* PR 17512: file: 0b4f81b7. */ + /* PR 17512: file: 0b4f81b7. + Also see PR 24456, for a file which deliberately has two reloc + sections. */ if (*p_hdr != NULL) - goto fail; + { + if (!bed->init_secondary_reloc_section (abfd, hdr, name, shindex)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: warning: secondary relocation section '%s' " + "for section %pA found - ignoring"), + abfd, name, target_sect); + } + goto success; + } + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, sizeof (*hdr2)); if (hdr2 == NULL) goto fail; @@ -2548,8 +2611,9 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) sections_being_created [shindex] = FALSE; if (-- nesting == 0) { + free (sections_being_created); sections_being_created = NULL; - sections_being_created_abfd = abfd; + sections_being_created_abfd = NULL; } return ret; } @@ -2605,6 +2669,7 @@ static const struct bfd_elf_special_section special_sections_b[] = static const struct bfd_elf_special_section special_sections_c[] = { { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".ctf"), 0, SHT_PROGBITS, 0 }, { NULL, 0, 0, 0, 0 } }; @@ -2853,28 +2918,13 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) bed = get_elf_backend_data (abfd); sec->use_rela_p = bed->default_use_rela_p; - /* When we read a file, we don't need to set ELF section type and - flags. They will be overridden in _bfd_elf_make_section_from_shdr - anyway. We will set ELF section type and flags for all linker - created sections. If user specifies BFD section flags, we will - set ELF section type and flags based on BFD section flags in - elf_fake_sections. Special handling for .init_array/.fini_array - output sections since they may contain .ctors/.dtors input - sections. We don't want _bfd_elf_init_private_section_data to - copy ELF section type from .ctors/.dtors input sections. */ - if (abfd->direction != read_direction - || (sec->flags & SEC_LINKER_CREATED) != 0) + /* Set up ELF section type and flags for newly created sections, if + there is an ABI mandated section. */ + ssect = (*bed->get_sec_type_attr) (abfd, sec); + if (ssect != NULL) { - ssect = (*bed->get_sec_type_attr) (abfd, sec); - if (ssect != NULL - && (!sec->flags - || (sec->flags & SEC_LINKER_CREATED) != 0 - || ssect->type == SHT_INIT_ARRAY - || ssect->type == SHT_FINI_ARRAY)) - { - elf_section_type (sec) = ssect->type; - elf_section_flags (sec) = ssect->attr; - } + elf_section_type (sec) = ssect->type; + elf_section_flags (sec) = ssect->attr; } return _bfd_generic_new_section_hook (abfd, sec); @@ -2913,6 +2963,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, char namebuf[64]; size_t len; int split; + unsigned int opb = bfd_octets_per_byte (abfd, NULL); split = ((hdr->p_memsz > 0) && (hdr->p_filesz > 0) @@ -2929,8 +2980,8 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, newsect = bfd_make_section (abfd, name); if (newsect == NULL) return FALSE; - newsect->vma = hdr->p_vaddr; - newsect->lma = hdr->p_paddr; + newsect->vma = hdr->p_vaddr / opb; + newsect->lma = hdr->p_paddr / opb; newsect->size = hdr->p_filesz; newsect->filepos = hdr->p_offset; newsect->flags |= SEC_HAS_CONTENTS; @@ -2965,8 +3016,8 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, newsect = bfd_make_section (abfd, name); if (newsect == NULL) return FALSE; - newsect->vma = hdr->p_vaddr + hdr->p_filesz; - newsect->lma = hdr->p_paddr + hdr->p_filesz; + newsect->vma = (hdr->p_vaddr + hdr->p_filesz) / opb; + newsect->lma = (hdr->p_paddr + hdr->p_filesz) / opb; newsect->size = hdr->p_memsz - hdr->p_filesz; newsect->filepos = hdr->p_offset + hdr->p_filesz; align = newsect->vma & -newsect->vma; @@ -2994,6 +3045,16 @@ _bfd_elf_make_section_from_phdr (bfd *abfd, return TRUE; } +static bfd_boolean +_bfd_elf_core_find_build_id (bfd *templ, bfd_vma offset) +{ + /* The return value is ignored. Build-ids are considered optional. */ + if (templ->xvec->flavour == bfd_target_elf_flavour) + return (*get_elf_backend_data (templ)->elf_backend_core_find_build_id) + (templ, offset); + return FALSE; +} + bfd_boolean bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) { @@ -3005,7 +3066,11 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "null"); case PT_LOAD: - return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load"); + if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "load")) + return FALSE; + if (bfd_get_format (abfd) == bfd_core && abfd->build_id == NULL) + _bfd_elf_core_find_build_id (abfd, hdr->p_offset); + return TRUE; case PT_DYNAMIC: return _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "dynamic"); @@ -3122,7 +3187,7 @@ _bfd_elf_init_reloc_shdr (bfd *abfd, int bfd_elf_get_default_section_type (flagword flags) { - if ((flags & SEC_ALLOC) != 0 + if ((flags & (SEC_ALLOC | SEC_IS_COMMON)) != 0 && (flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) return SHT_NOBITS; return SHT_PROGBITS; @@ -3146,6 +3211,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) unsigned int sh_type; const char *name = asect->name; bfd_boolean delay_st_name_p = FALSE; + bfd_vma mask; if (arg->failed) { @@ -3167,7 +3233,6 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) /* Set SEC_ELF_COMPRESS to indicate this section should be compressed. */ asect->flags |= SEC_ELF_COMPRESS; - /* If this section will be compressed, delay adding section name to section name section after it is compressed in _bfd_elf_assign_file_positions_for_non_load. */ @@ -3228,7 +3293,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) if ((asect->flags & SEC_ALLOC) != 0 || asect->user_set_vma) - this_hdr->sh_addr = asect->vma; + this_hdr->sh_addr = asect->vma * bfd_octets_per_byte (abfd, asect); else this_hdr->sh_addr = 0; @@ -3245,7 +3310,10 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) arg->failed = TRUE; return; } - this_hdr->sh_addralign = (bfd_vma) 1 << asect->alignment_power; + /* Set sh_addralign to the highest power of two given by alignment + consistent with the section VMA. Linker scripts can force VMA. */ + mask = ((bfd_vma) 1 << asect->alignment_power) | this_hdr->sh_addr; + this_hdr->sh_addralign = mask & -mask; /* The sh_entsize and sh_info fields may have been set already by copy_private_section_data. */ @@ -3458,7 +3526,8 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) /* Ignore linker created group section. See elfNN_ia64_object_p in elfxx-ia64.c. */ - if (((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_GROUP) + if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) != SEC_GROUP + || sec->size == 0 || *failedptr) return; @@ -3474,8 +3543,13 @@ bfd_elf_set_group_contents (bfd *abfd, asection *sec, void *failedptrarg) if (symindx == 0) { /* If called from the assembler, swap_out_syms will have set up - elf_section_syms. */ - BFD_ASSERT (elf_section_syms (abfd) != NULL); + elf_section_syms. + PR 25699: A corrupt input file could contain bogus group info. */ + if (elf_section_syms (abfd) == NULL) + { + *failedptr = TRUE; + return; + } symindx = elf_section_syms (abfd)[sec->index]->udata.i; } elf_section_data (sec)->this_hdr.sh_info = symindx; @@ -3649,6 +3723,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) Elf_Internal_Shdr **i_shdrp; struct bfd_elf_section_data *d; bfd_boolean need_symtab; + size_t amt; section_number = 1; @@ -3722,11 +3797,11 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); if (section_number > ((SHN_LORESERVE - 2) & 0xFFFF)) { - elf_section_list * entry; + elf_section_list *entry; BFD_ASSERT (elf_symtab_shndx_list (abfd) == NULL); - entry = bfd_zalloc (abfd, sizeof * entry); + entry = bfd_zalloc (abfd, sizeof (*entry)); entry->ndx = section_number++; elf_symtab_shndx_list (abfd) = entry; entry->hdr.sh_name @@ -3756,8 +3831,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* Set up the list of section header pointers, in agreement with the indices. */ - i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc2 (abfd, section_number, - sizeof (Elf_Internal_Shdr *)); + amt = section_number * sizeof (Elf_Internal_Shdr *); + i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt); if (i_shdrp == NULL) return FALSE; @@ -3875,11 +3950,10 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) where s is NULL. */ const struct elf_backend_data *bed = get_elf_backend_data (abfd); - if (bed->link_order_error_handler) - bed->link_order_error_handler - /* xgettext:c-format */ - (_("%pB: warning: sh_link not set for section `%pA'"), - abfd, sec); + bed->link_order_error_handler + /* xgettext:c-format */ + (_("%pB: warning: sh_link not set for section `%pA'"), + abfd, sec); } } @@ -3929,9 +4003,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) elf_section_data (s)->this_hdr.sh_link = d->this_idx; /* This is a .stab section. */ - if (elf_section_data (s)->this_hdr.sh_entsize == 0) - elf_section_data (s)->this_hdr.sh_entsize - = 4 + 2 * bfd_get_arch_size (abfd) / 8; + elf_section_data (s)->this_hdr.sh_entsize = 12; } } break; @@ -3989,8 +4061,8 @@ sym_is_global (bfd *abfd, asymbol *sym) return (*bed->elf_backend_sym_is_global) (abfd, sym); return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 - || bfd_is_und_section (bfd_get_section (sym)) - || bfd_is_com_section (bfd_get_section (sym))); + || bfd_is_und_section (bfd_asymbol_section (sym)) + || bfd_is_com_section (bfd_asymbol_section (sym))); } /* Filter global symbols of ABFD to include in the import library. All @@ -4076,6 +4148,7 @@ elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) unsigned int idx; asection *asect; asymbol **new_syms; + size_t amt; #ifdef DEBUG fprintf (stderr, "elf_map_symbols\n"); @@ -4089,7 +4162,8 @@ elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) } max_index++; - sect_syms = (asymbol **) bfd_zalloc2 (abfd, max_index, sizeof (asymbol *)); + amt = max_index * sizeof (asymbol *); + sect_syms = (asymbol **) bfd_zalloc (abfd, amt); if (sect_syms == NULL) return FALSE; elf_section_syms (abfd) = sect_syms; @@ -4140,9 +4214,8 @@ elf_map_symbols (bfd *abfd, unsigned int *pnum_locals) } /* Now sort the symbols so the local symbols are first. */ - new_syms = (asymbol **) bfd_alloc2 (abfd, num_locals + num_globals, - sizeof (asymbol *)); - + amt = (num_locals + num_globals) * sizeof (asymbol *); + new_syms = (asymbol **) bfd_alloc (abfd, amt); if (new_syms == NULL) return FALSE; @@ -4232,12 +4305,9 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, if (bed->elf_backend_begin_write_processing) (*bed->elf_backend_begin_write_processing) (abfd, link_info); - if (! prep_headers (abfd)) + if (!(*bed->elf_backend_init_file_header) (abfd, link_info)) return FALSE; - /* Post process the headers if necessary. */ - (*bed->elf_backend_post_process_headers) (abfd, link_info); - fsargs.failed = FALSE; fsargs.link_info = link_info; bfd_map_over_sections (abfd, elf_fake_sections, &fsargs); @@ -4270,7 +4340,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, } shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; - /* sh_name was set in prep_headers. */ + /* sh_name was set in init_file_header. */ shstrtab_hdr->sh_type = SHT_STRTAB; shstrtab_hdr->sh_flags = bed->elf_strtab_flags; shstrtab_hdr->sh_addr = 0; @@ -4368,6 +4438,14 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info) ++segs; } + s = bfd_get_section_by_name (abfd, + NOTE_GNU_PROPERTY_SECTION_NAME); + if (s != NULL && s->size != 0) + { + /* We need a PT_GNU_PROPERTY segment. */ + ++segs; + } + for (s = abfd->sections; s != NULL; s = s->next) { if ((s->flags & SEC_LOAD) != 0 @@ -4402,31 +4480,32 @@ get_program_header_size (bfd *abfd, struct bfd_link_info *info) bed = get_elf_backend_data (abfd); - if ((abfd->flags & D_PAGED) != 0) - { - /* Add a PT_GNU_MBIND segment for each mbind section. */ - unsigned int page_align_power = bfd_log2 (bed->commonpagesize); - for (s = abfd->sections; s != NULL; s = s->next) - if (elf_section_flags (s) & SHF_GNU_MBIND) - { - if (elf_section_data (s)->this_hdr.sh_info - > PT_GNU_MBIND_NUM) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%pB: GNU_MBIN section `%pA' has invalid sh_info field: %d"), - abfd, s, elf_section_data (s)->this_hdr.sh_info); - continue; - } - /* Align mbind section to page size. */ - if (s->alignment_power < page_align_power) - s->alignment_power = page_align_power; - segs ++; - } - } - - /* Let the backend count up any program headers it might need. */ - if (bed->elf_backend_additional_program_headers) + if ((abfd->flags & D_PAGED) != 0 + && (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0) + { + /* Add a PT_GNU_MBIND segment for each mbind section. */ + unsigned int page_align_power = bfd_log2 (bed->commonpagesize); + for (s = abfd->sections; s != NULL; s = s->next) + if (elf_section_flags (s) & SHF_GNU_MBIND) + { + if (elf_section_data (s)->this_hdr.sh_info > PT_GNU_MBIND_NUM) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB: GNU_MBIND section `%pA' has invalid " + "sh_info field: %d"), + abfd, s, elf_section_data (s)->this_hdr.sh_info); + continue; + } + /* Align mbind section to page size. */ + if (s->alignment_power < page_align_power) + s->alignment_power = page_align_power; + segs ++; + } + } + + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_additional_program_headers) { int a; @@ -4473,7 +4552,7 @@ make_mapping (bfd *abfd, struct elf_segment_map *m; unsigned int i; asection **hdrpp; - bfd_size_type amt; + size_t amt; amt = sizeof (struct elf_segment_map) - sizeof (asection *); amt += (to - from) * sizeof (asection *); @@ -4600,18 +4679,19 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) bfd_boolean phdr_in_segment; bfd_boolean writable; bfd_boolean executable; - int tls_count = 0; + unsigned int tls_count = 0; asection *first_tls = NULL; asection *first_mbind = NULL; asection *dynsec, *eh_frame_hdr; - bfd_size_type amt; - bfd_vma addr_mask, wrap_to = 0; - bfd_size_type phdr_size; + size_t amt; + bfd_vma addr_mask, wrap_to = 0; /* Bytes. */ + bfd_size_type phdr_size; /* Octets/bytes. */ + unsigned int opb = bfd_octets_per_byte (abfd, NULL); /* Select the allocated sections, and sort them. */ - sections = (asection **) bfd_malloc2 (bfd_count_sections (abfd), - sizeof (asection *)); + amt = bfd_count_sections (abfd) * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); if (sections == NULL) goto error_return; @@ -4626,11 +4706,15 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) { if ((s->flags & SEC_ALLOC) != 0) { + /* target_index is unused until bfd_elf_final_link + starts output of section symbols. Use it to make + qsort stable. */ + s->target_index = i; sections[i] = s; ++i; /* A wrapping section potentially clashes with header. */ - if (((s->lma + s->size) & addr_mask) < (s->lma & addr_mask)) - wrap_to = (s->lma + s->size) & addr_mask; + if (((s->lma + s->size / opb) & addr_mask) < (s->lma & addr_mask)) + wrap_to = (s->lma + s->size / opb) & addr_mask; } } BFD_ASSERT (i <= bfd_count_sections (abfd)); @@ -4642,6 +4726,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (phdr_size == (bfd_size_type) -1) phdr_size = get_program_header_size (abfd, info); phdr_size += bed->s->sizeof_ehdr; + /* phdr_size is compared to LMA values which are in bytes. */ + phdr_size /= opb; maxpagesize = bed->maxpagesize; if (maxpagesize == 0) maxpagesize = 1; @@ -4712,7 +4798,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) program headers we will need. */ if (phdr_in_segment && count > 0) { - bfd_vma phdr_lma; + bfd_vma phdr_lma; /* Bytes. */ bfd_boolean separate_phdr = FALSE; phdr_lma = (sections[0]->lma - phdr_size) & addr_mask & -maxpagesize; @@ -4752,7 +4838,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) m = make_mapping (abfd, sections, 0, 0, phdr_in_segment); if (m == NULL) goto error_return; - m->p_paddr = phdr_lma; + m->p_paddr = phdr_lma * opb; m->p_vaddr_offset = (sections[0]->vma - phdr_size) & addr_mask & -maxpagesize; m->p_paddr_valid = 1; @@ -4866,7 +4952,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) executable = TRUE; last_hdr = hdr; /* .tbss sections effectively have zero size. */ - last_size = !IS_TBSS (hdr) ? hdr->size : 0; + last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb; continue; } @@ -4892,7 +4978,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) last_hdr = hdr; /* .tbss sections effectively have zero size. */ - last_size = !IS_TBSS (hdr) ? hdr->size : 0; + last_size = (!IS_TBSS (hdr) ? hdr->size : 0) / opb; hdr_index = i; phdr_in_segment = FALSE; } @@ -4940,7 +5026,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) if (s2->next->alignment_power == alignment_power && (s2->next->flags & SEC_LOAD) != 0 && elf_section_type (s2->next) == SHT_NOTE - && align_power (s2->lma + s2->size, + && align_power (s2->lma + s2->size / opb, alignment_power) == s2->next->lma) count++; @@ -4992,7 +5078,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) m->p_flags = PF_R; m->p_flags_valid = 1; s = first_tls; - for (i = 0; i < (unsigned int) tls_count; ++i) + for (i = 0; i < tls_count; ++i) { if ((s->flags & SEC_THREAD_LOCAL) == 0) { @@ -5000,7 +5086,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) (_("%pB: TLS sections are not adjacent:"), abfd); s = first_tls; i = 0; - while (i < (unsigned int) tls_count) + while (i < tls_count) { if ((s->flags & SEC_THREAD_LOCAL) != 0) { @@ -5022,11 +5108,12 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) pm = &m->next; } - if (first_mbind && (abfd->flags & D_PAGED) != 0) + if (first_mbind + && (abfd->flags & D_PAGED) != 0 + && (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0) for (s = first_mbind; s != NULL; s = s->next) if ((elf_section_flags (s) & SHF_GNU_MBIND) != 0 - && (elf_section_data (s)->this_hdr.sh_info - <= PT_GNU_MBIND_NUM)) + && elf_section_data (s)->this_hdr.sh_info <= PT_GNU_MBIND_NUM) { /* Mandated PF_R. */ unsigned long p_flags = PF_R; @@ -5051,6 +5138,24 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) pm = &m->next; } + s = bfd_get_section_by_name (abfd, + NOTE_GNU_PROPERTY_SECTION_NAME); + if (s != NULL && s->size != 0) + { + amt = sizeof (struct elf_segment_map) + sizeof (asection *); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_PROPERTY; + m->count = 1; + m->p_flags_valid = 1; + m->sections[0] = s; + m->p_flags = PF_R; + *pm = m; + pm = &m->next; + } + /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME segment. */ eh_frame_hdr = elf_eh_frame_hdr (abfd); @@ -5103,9 +5208,12 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) { i = m->count; while (--i != (unsigned) -1) - if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) - == (SEC_LOAD | SEC_HAS_CONTENTS)) - break; + { + if (m->sections[i]->size > 0 + && (m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) + == (SEC_LOAD | SEC_HAS_CONTENTS)) + break; + } if (i != (unsigned) -1) break; @@ -5140,8 +5248,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) return TRUE; error_return: - if (sections != NULL) - free (sections); + free (sections); return FALSE; } @@ -5174,14 +5281,7 @@ elf_sort_sections (const void *arg1, const void *arg2) if (TOEND (sec1)) { - if (TOEND (sec2)) - { - /* If the indices are the same, do not return 0 - here, but continue to try the next comparison. */ - if (sec1->target_index - sec2->target_index != 0) - return sec1->target_index - sec2->target_index; - } - else + if (!TOEND (sec2)) return 1; } else if (TOEND (sec2)) @@ -5203,6 +5303,56 @@ elf_sort_sections (const void *arg1, const void *arg2) return sec1->target_index - sec2->target_index; } +/* This qsort comparison functions sorts PT_LOAD segments first and + by p_paddr, for assign_file_positions_for_load_sections. */ + +static int +elf_sort_segments (const void *arg1, const void *arg2) +{ + const struct elf_segment_map *m1 = *(const struct elf_segment_map **) arg1; + const struct elf_segment_map *m2 = *(const struct elf_segment_map **) arg2; + + if (m1->p_type != m2->p_type) + { + if (m1->p_type == PT_NULL) + return 1; + if (m2->p_type == PT_NULL) + return -1; + return m1->p_type < m2->p_type ? -1 : 1; + } + if (m1->includes_filehdr != m2->includes_filehdr) + return m1->includes_filehdr ? -1 : 1; + if (m1->no_sort_lma != m2->no_sort_lma) + return m1->no_sort_lma ? -1 : 1; + if (m1->p_type == PT_LOAD && !m1->no_sort_lma) + { + bfd_vma lma1, lma2; /* Octets. */ + lma1 = 0; + if (m1->p_paddr_valid) + lma1 = m1->p_paddr; + else if (m1->count != 0) + { + unsigned int opb = bfd_octets_per_byte (m1->sections[0]->owner, + m1->sections[0]); + lma1 = (m1->sections[0]->lma + m1->p_vaddr_offset) * opb; + } + lma2 = 0; + if (m2->p_paddr_valid) + lma2 = m2->p_paddr; + else if (m2->count != 0) + { + unsigned int opb = bfd_octets_per_byte (m2->sections[0]->owner, + m2->sections[0]); + lma2 = (m2->sections[0]->lma + m2->p_vaddr_offset) * opb; + } + if (lma1 != lma2) + return lma1 < lma2 ? -1 : 1; + } + if (m1->idx != m2->idx) + return m1->idx < m2->idx ? -1 : 1; + return 0; +} + /* Ian Lance Taylor writes: We shouldn't be using % with a negative signed number. That's just @@ -5289,14 +5439,15 @@ assign_file_positions_for_load_sections (bfd *abfd, { const struct elf_backend_data *bed = get_elf_backend_data (abfd); struct elf_segment_map *m; + struct elf_segment_map *phdr_load_seg; Elf_Internal_Phdr *phdrs; Elf_Internal_Phdr *p; - file_ptr off; + file_ptr off; /* Octets. */ bfd_size_type maxpagesize; - unsigned int pt_load_count = 0; - unsigned int alloc; + unsigned int alloc, actual; unsigned int i, j; - bfd_vma header_pad = 0; + struct elf_segment_map **sorted_seg_map; + unsigned int opb = bfd_octets_per_byte (abfd, NULL); if (link_info == NULL && !_bfd_elf_map_sections_to_segments (abfd, link_info)) @@ -5304,11 +5455,7 @@ assign_file_positions_for_load_sections (bfd *abfd, alloc = 0; for (m = elf_seg_map (abfd); m != NULL; m = m->next) - { - ++alloc; - if (m->header_size) - header_pad = m->header_size; - } + m->idx = alloc++; if (alloc) { @@ -5325,10 +5472,17 @@ assign_file_positions_for_load_sections (bfd *abfd, elf_elfheader (abfd)->e_phnum = alloc; if (elf_program_header_size (abfd) == (bfd_size_type) -1) - elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr; + { + actual = alloc; + elf_program_header_size (abfd) = alloc * bed->s->sizeof_phdr; + } else - BFD_ASSERT (elf_program_header_size (abfd) - >= alloc * bed->s->sizeof_phdr); + { + actual = elf_program_header_size (abfd) / bed->s->sizeof_phdr; + BFD_ASSERT (elf_program_header_size (abfd) + == actual * bed->s->sizeof_phdr); + BFD_ASSERT (actual >= alloc); + } if (alloc == 0) { @@ -5345,36 +5499,16 @@ assign_file_positions_for_load_sections (bfd *abfd, See ld/emultempl/elf-generic.em:gld${EMULATION_NAME}_map_segments where the layout is forced to according to a larger size in the last iterations for the testcase ld-elf/header. */ - BFD_ASSERT (elf_program_header_size (abfd) % bed->s->sizeof_phdr - == 0); - phdrs = (Elf_Internal_Phdr *) - bfd_zalloc2 (abfd, - (elf_program_header_size (abfd) / bed->s->sizeof_phdr), - sizeof (Elf_Internal_Phdr)); + phdrs = bfd_zalloc (abfd, (actual * sizeof (*phdrs) + + alloc * sizeof (*sorted_seg_map))); + sorted_seg_map = (struct elf_segment_map **) (phdrs + actual); elf_tdata (abfd)->phdr = phdrs; if (phdrs == NULL) return FALSE; - maxpagesize = 1; - if ((abfd->flags & D_PAGED) != 0) - maxpagesize = bed->maxpagesize; - - off = bed->s->sizeof_ehdr; - off += alloc * bed->s->sizeof_phdr; - if (header_pad < (bfd_vma) off) - header_pad = 0; - else - header_pad -= off; - off += header_pad; - - for (m = elf_seg_map (abfd), p = phdrs, j = 0; - m != NULL; - m = m->next, p++, j++) + for (m = elf_seg_map (abfd), j = 0; m != NULL; m = m->next, j++) { - asection **secpp; - bfd_vma off_adjust; - bfd_boolean no_contents; - + sorted_seg_map[j] = m; /* If elf_segment_map is not from map_sections_to_segments, the sections may not be correctly ordered. NOTE: sorting should not be done to the PT_NOTE section of a corefile, which may @@ -5383,28 +5517,68 @@ assign_file_positions_for_load_sections (bfd *abfd, if (m->count > 1 && !(elf_elfheader (abfd)->e_type == ET_CORE && m->p_type == PT_NOTE)) - qsort (m->sections, (size_t) m->count, sizeof (asection *), - elf_sort_sections); + { + for (i = 0; i < m->count; i++) + m->sections[i]->target_index = i; + qsort (m->sections, (size_t) m->count, sizeof (asection *), + elf_sort_sections); + } + } + if (alloc > 1) + qsort (sorted_seg_map, alloc, sizeof (*sorted_seg_map), + elf_sort_segments); + + maxpagesize = 1; + if ((abfd->flags & D_PAGED) != 0) + maxpagesize = bed->maxpagesize; + + /* Sections must map to file offsets past the ELF file header. */ + off = bed->s->sizeof_ehdr; + /* And if one of the PT_LOAD headers doesn't include the program + headers then we'll be mapping program headers in the usual + position after the ELF file header. */ + phdr_load_seg = NULL; + for (j = 0; j < alloc; j++) + { + m = sorted_seg_map[j]; + if (m->p_type != PT_LOAD) + break; + if (m->includes_phdrs) + { + phdr_load_seg = m; + break; + } + } + if (phdr_load_seg == NULL) + off += actual * bed->s->sizeof_phdr; + + for (j = 0; j < alloc; j++) + { + asection **secpp; + bfd_vma off_adjust; /* Octets. */ + bfd_boolean no_contents; /* An ELF segment (described by Elf_Internal_Phdr) may contain a number of sections with contents contributing to both p_filesz and p_memsz, followed by a number of sections with no contents that just contribute to p_memsz. In this loop, OFF tracks next available file offset for PT_LOAD and PT_NOTE segments. */ + m = sorted_seg_map[j]; + p = phdrs + m->idx; p->p_type = m->p_type; p->p_flags = m->p_flags; if (m->count == 0) - p->p_vaddr = m->p_vaddr_offset; + p->p_vaddr = m->p_vaddr_offset * opb; else - p->p_vaddr = m->sections[0]->vma + m->p_vaddr_offset; + p->p_vaddr = (m->sections[0]->vma + m->p_vaddr_offset) * opb; if (m->p_paddr_valid) p->p_paddr = m->p_paddr; else if (m->count == 0) p->p_paddr = 0; else - p->p_paddr = m->sections[0]->lma + m->p_vaddr_offset; + p->p_paddr = (m->sections[0]->lma + m->p_vaddr_offset) * opb; if (p->p_type == PT_LOAD && (abfd->flags & D_PAGED) != 0) @@ -5421,21 +5595,25 @@ assign_file_positions_for_load_sections (bfd *abfd, maxpagesize = m->p_align; p->p_align = maxpagesize; - pt_load_count += 1; } else if (m->p_align_valid) p->p_align = m->p_align; else if (m->count == 0) p->p_align = 1 << bed->s->log_file_align; - else - p->p_align = 0; + + if (m == phdr_load_seg) + { + if (!m->includes_filehdr) + p->p_offset = off; + off += actual * bed->s->sizeof_phdr; + } no_contents = FALSE; off_adjust = 0; if (p->p_type == PT_LOAD && m->count > 0) { - bfd_size_type align; + bfd_size_type align; /* Bytes. */ unsigned int align_power = 0; if (m->p_align_valid) @@ -5446,7 +5624,7 @@ assign_file_positions_for_load_sections (bfd *abfd, { unsigned int secalign; - secalign = bfd_get_section_alignment (abfd, *secpp); + secalign = bfd_section_alignment (*secpp); if (secalign > align_power) align_power = secalign; } @@ -5472,15 +5650,17 @@ assign_file_positions_for_load_sections (bfd *abfd, break; } - off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align); + off_adjust = vma_page_aligned_bias (p->p_vaddr, off, align * opb); /* Broken hardware and/or kernel require that files do not map the same page with different permissions on some hppa processors. */ - if (pt_load_count > 1 + if (j != 0 + && (abfd->flags & D_PAGED) != 0 && bed->no_page_alias && (off & (maxpagesize - 1)) != 0 - && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize)) + && ((off & -maxpagesize) + == ((off + off_adjust) & -maxpagesize))) off_adjust += maxpagesize; off += off_adjust; if (no_contents) @@ -5515,33 +5695,38 @@ assign_file_positions_for_load_sections (bfd *abfd, for (i = 0; i < m->count; i++) elf_section_type (m->sections[i]) = SHT_NOTE; - p->p_offset = 0; - p->p_filesz = 0; - p->p_memsz = 0; - if (m->includes_filehdr) { if (!m->p_flags_valid) p->p_flags |= PF_R; p->p_filesz = bed->s->sizeof_ehdr; p->p_memsz = bed->s->sizeof_ehdr; - if (m->count > 0) + if (p->p_type == PT_LOAD) { - if (p->p_vaddr < (bfd_vma) off - || (!m->p_paddr_valid - && p->p_paddr < (bfd_vma) off)) + if (m->count > 0) { - _bfd_error_handler - (_("%pB: not enough room for program headers," - " try linking with -N"), - abfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; + if (p->p_vaddr < (bfd_vma) off + || (!m->p_paddr_valid + && p->p_paddr < (bfd_vma) off)) + { + _bfd_error_handler + (_("%pB: not enough room for program headers," + " try linking with -N"), + abfd); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + p->p_vaddr -= off; + if (!m->p_paddr_valid) + p->p_paddr -= off; } - - p->p_vaddr -= off; + } + else if (sorted_seg_map[0]->includes_filehdr) + { + Elf_Internal_Phdr *filehdr = phdrs + sorted_seg_map[0]->idx; + p->p_vaddr = filehdr->p_vaddr; if (!m->p_paddr_valid) - p->p_paddr -= off; + p->p_paddr = filehdr->p_paddr; } } @@ -5549,25 +5734,33 @@ assign_file_positions_for_load_sections (bfd *abfd, { if (!m->p_flags_valid) p->p_flags |= PF_R; - + p->p_filesz += actual * bed->s->sizeof_phdr; + p->p_memsz += actual * bed->s->sizeof_phdr; if (!m->includes_filehdr) { - p->p_offset = bed->s->sizeof_ehdr; - - if (m->count > 0) + if (p->p_type == PT_LOAD) + { + elf_elfheader (abfd)->e_phoff = p->p_offset; + if (m->count > 0) + { + p->p_vaddr -= off - p->p_offset; + if (!m->p_paddr_valid) + p->p_paddr -= off - p->p_offset; + } + } + else if (phdr_load_seg != NULL) { - p->p_vaddr -= off - p->p_offset; + Elf_Internal_Phdr *phdr = phdrs + phdr_load_seg->idx; + bfd_vma phdr_off = 0; /* Octets. */ + if (phdr_load_seg->includes_filehdr) + phdr_off = bed->s->sizeof_ehdr; + p->p_vaddr = phdr->p_vaddr + phdr_off; if (!m->p_paddr_valid) - p->p_paddr -= off - p->p_offset; + p->p_paddr = phdr->p_paddr + phdr_off; + p->p_offset = phdr->p_offset + phdr_off; } - } - - p->p_filesz += alloc * bed->s->sizeof_phdr; - p->p_memsz += alloc * bed->s->sizeof_phdr; - if (m->count) - { - p->p_filesz += header_pad; - p->p_memsz += header_pad; + else + p->p_offset = bed->s->sizeof_ehdr; } } @@ -5575,10 +5768,24 @@ assign_file_positions_for_load_sections (bfd *abfd, || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) { if (!m->includes_filehdr && !m->includes_phdrs) - p->p_offset = off; + { + p->p_offset = off; + if (no_contents) + { + /* Put meaningless p_offset for PT_LOAD segments + without file contents somewhere within the first + page, in an attempt to not point past EOF. */ + bfd_size_type align = maxpagesize; + if (align < p->p_align) + align = p->p_align; + if (align < 1) + align = 1; + p->p_offset = off % align; + } + } else { - file_ptr adjust; + file_ptr adjust; /* Octets. */ adjust = off - (p->p_offset + p->p_filesz); if (!no_contents) @@ -5600,7 +5807,7 @@ assign_file_positions_for_load_sections (bfd *abfd, sec = *secpp; this_hdr = &elf_section_data (sec)->this_hdr; - align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec); + align = (bfd_size_type) 1 << bfd_section_alignment (sec); if ((p->p_type == PT_LOAD || p->p_type == PT_TLS) @@ -5609,10 +5816,10 @@ assign_file_positions_for_load_sections (bfd *abfd, && ((this_hdr->sh_flags & SHF_TLS) == 0 || p->p_type == PT_TLS)))) { - bfd_vma p_start = p->p_paddr; - bfd_vma p_end = p_start + p->p_memsz; - bfd_vma s_start = sec->lma; - bfd_vma adjust = s_start - p_end; + bfd_vma p_start = p->p_paddr; /* Octets. */ + bfd_vma p_end = p_start + p->p_memsz; /* Octets. */ + bfd_vma s_start = sec->lma * opb; /* Octets. */ + bfd_vma adjust = s_start - p_end; /* Octets. */ if (adjust != 0 && (s_start < p_end @@ -5621,26 +5828,46 @@ assign_file_positions_for_load_sections (bfd *abfd, _bfd_error_handler /* xgettext:c-format */ (_("%pB: section %pA lma %#" PRIx64 " adjusted to %#" PRIx64), - abfd, sec, (uint64_t) s_start, (uint64_t) p_end); + abfd, sec, (uint64_t) s_start / opb, + (uint64_t) p_end / opb); adjust = 0; - sec->lma = p_end; + sec->lma = p_end / opb; } p->p_memsz += adjust; - if (this_hdr->sh_type != SHT_NOBITS) + if (p->p_type == PT_LOAD) { - if (p->p_filesz + adjust < p->p_memsz) + if (this_hdr->sh_type != SHT_NOBITS) { - /* We have a PROGBITS section following NOBITS ones. - Allocate file space for the NOBITS section(s) and - zero it. */ - adjust = p->p_memsz - p->p_filesz; - if (!write_zeros (abfd, off, adjust)) - return FALSE; + off_adjust = 0; + if (p->p_filesz + adjust < p->p_memsz) + { + /* We have a PROGBITS section following NOBITS ones. + Allocate file space for the NOBITS section(s) and + zero it. */ + adjust = p->p_memsz - p->p_filesz; + if (!write_zeros (abfd, off, adjust)) + return FALSE; + } + } + /* We only adjust sh_offset in SHT_NOBITS sections + as would seem proper for their address when the + section is first in the segment. sh_offset + doesn't really have any significance for + SHT_NOBITS anyway, apart from a notional position + relative to other sections. Historically we + didn't bother with adjusting sh_offset and some + programs depend on it not being adjusted. See + pr12921 and pr25662. */ + if (this_hdr->sh_type != SHT_NOBITS || i == 0) + { + off += adjust; + if (this_hdr->sh_type == SHT_NOBITS) + off_adjust += adjust; } - off += adjust; - p->p_filesz += adjust; } + if (this_hdr->sh_type != SHT_NOBITS) + p->p_filesz += adjust; } if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) @@ -5727,6 +5954,26 @@ assign_file_positions_for_load_sections (bfd *abfd, off -= off_adjust; + /* PR ld/20815 - Check that the program header segment, if + present, will be loaded into memory. */ + if (p->p_type == PT_PHDR + && phdr_load_seg == NULL + && !(bed->elf_backend_allow_non_load_phdr != NULL + && bed->elf_backend_allow_non_load_phdr (abfd, phdrs, alloc))) + { + /* The fix for this error is usually to edit the linker script being + used and set up the program headers manually. Either that or + leave room for the headers at the start of the SECTIONS. */ + _bfd_error_handler (_("%pB: error: PHDR segment not covered" + " by LOAD segment"), + abfd); + if (link_info == NULL) + return FALSE; + /* Arrange for the linker to exit with an error, deleting + the output file unless --noinhibit-exec is given. */ + link_info->callbacks->info ("%X"); + } + /* Check that all sections are in a PT_LOAD segment. Don't check funky gdb generated core files. */ if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core) @@ -5766,31 +6013,109 @@ assign_file_positions_for_load_sections (bfd *abfd, } elf_next_file_pos (abfd) = off; - return TRUE; -} - -/* Assign file positions for the other sections. */ - -static bfd_boolean -assign_file_positions_for_non_load_sections (bfd *abfd, - struct bfd_link_info *link_info) -{ - const struct elf_backend_data *bed = get_elf_backend_data (abfd); - Elf_Internal_Shdr **i_shdrpp; - Elf_Internal_Shdr **hdrpp, **end_hdrpp; - Elf_Internal_Phdr *phdrs; - Elf_Internal_Phdr *p; - struct elf_segment_map *m; - struct elf_segment_map *hdrs_segment; - bfd_vma filehdr_vaddr, filehdr_paddr; - bfd_vma phdrs_vaddr, phdrs_paddr; - file_ptr off; - unsigned int count; - i_shdrpp = elf_elfsections (abfd); - end_hdrpp = i_shdrpp + elf_numsections (abfd); - off = elf_next_file_pos (abfd); - for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++) + if (link_info != NULL + && phdr_load_seg != NULL + && phdr_load_seg->includes_filehdr) + { + /* There is a segment that contains both the file headers and the + program headers, so provide a symbol __ehdr_start pointing there. + A program can use this to examine itself robustly. */ + + struct elf_link_hash_entry *hash + = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start", + FALSE, FALSE, TRUE); + /* If the symbol was referenced and not defined, define it. */ + if (hash != NULL + && (hash->root.type == bfd_link_hash_new + || hash->root.type == bfd_link_hash_undefined + || hash->root.type == bfd_link_hash_undefweak + || hash->root.type == bfd_link_hash_common)) + { + asection *s = NULL; + bfd_vma filehdr_vaddr = phdrs[phdr_load_seg->idx].p_vaddr / opb; + + if (phdr_load_seg->count != 0) + /* The segment contains sections, so use the first one. */ + s = phdr_load_seg->sections[0]; + else + /* Use the first (i.e. lowest-addressed) section in any segment. */ + for (m = elf_seg_map (abfd); m != NULL; m = m->next) + if (m->p_type == PT_LOAD && m->count != 0) + { + s = m->sections[0]; + break; + } + + if (s != NULL) + { + hash->root.u.def.value = filehdr_vaddr - s->vma; + hash->root.u.def.section = s; + } + else + { + hash->root.u.def.value = filehdr_vaddr; + hash->root.u.def.section = bfd_abs_section_ptr; + } + + hash->root.type = bfd_link_hash_defined; + hash->def_regular = 1; + hash->non_elf = 0; + } + } + + return TRUE; +} + +/* Determine if a bfd is a debuginfo file. Unfortunately there + is no defined method for detecting such files, so we have to + use heuristics instead. */ + +bfd_boolean +is_debuginfo_file (bfd *abfd) +{ + if (abfd == NULL || bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return FALSE; + + Elf_Internal_Shdr **start_headers = elf_elfsections (abfd); + Elf_Internal_Shdr **end_headers = start_headers + elf_numsections (abfd); + Elf_Internal_Shdr **headerp; + + for (headerp = start_headers; headerp < end_headers; headerp ++) + { + Elf_Internal_Shdr *header = * headerp; + + /* Debuginfo files do not have any allocated SHT_PROGBITS sections. + The only allocated sections are SHT_NOBITS or SHT_NOTES. */ + if ((header->sh_flags & SHF_ALLOC) == SHF_ALLOC + && header->sh_type != SHT_NOBITS + && header->sh_type != SHT_NOTE) + return FALSE; + } + + return TRUE; +} + +/* Assign file positions for the other sections, except for compressed debugging + and other sections assigned in _bfd_elf_assign_file_positions_for_non_load(). */ + +static bfd_boolean +assign_file_positions_for_non_load_sections (bfd *abfd, + struct bfd_link_info *link_info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Shdr **i_shdrpp; + Elf_Internal_Shdr **hdrpp, **end_hdrpp; + Elf_Internal_Phdr *phdrs; + Elf_Internal_Phdr *p; + struct elf_segment_map *m; + file_ptr off; + unsigned int opb = bfd_octets_per_byte (abfd, NULL); + + i_shdrpp = elf_elfsections (abfd); + end_hdrpp = i_shdrpp + elf_numsections (abfd); + off = elf_next_file_pos (abfd); + for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++) { Elf_Internal_Shdr *hdr; @@ -5802,7 +6127,13 @@ assign_file_positions_for_non_load_sections (bfd *abfd, BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos); else if ((hdr->sh_flags & SHF_ALLOC) != 0) { - if (hdr->sh_size != 0) + if (hdr->sh_size != 0 + /* PR 24717 - debuginfo files are known to be not strictly + compliant with the ELF standard. In particular they often + have .note.gnu.property sections that are outside of any + loadable segment. This is not a problem for such files, + so do not warn about them. */ + && ! is_debuginfo_file (abfd)) _bfd_error_handler /* xgettext:c-format */ (_("%pB: warning: allocated section `%s' not in segment"), @@ -5822,9 +6153,12 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) + /* We don't know the offset of these sections yet: their size has + not been decided. */ || (hdr->bfd_section != NULL - && (hdr->bfd_section->flags & SEC_ELF_COMPRESS)) - /* Compress DWARF debug sections. */ + && (hdr->bfd_section->flags & SEC_ELF_COMPRESS + || (bfd_section_is_ctf (hdr->bfd_section) + && abfd->is_linker_output))) || hdr == i_shdrpp[elf_onesymtab (abfd)] || (elf_symtab_shndx_list (abfd) != NULL && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx]) @@ -5834,91 +6168,16 @@ assign_file_positions_for_non_load_sections (bfd *abfd, else off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); } + elf_next_file_pos (abfd) = off; /* Now that we have set the section file positions, we can set up the file positions for the non PT_LOAD segments. */ - count = 0; - filehdr_vaddr = 0; - filehdr_paddr = 0; - phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; - phdrs_paddr = 0; - hdrs_segment = NULL; phdrs = elf_tdata (abfd)->phdr; - for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) - { - ++count; - if (p->p_type != PT_LOAD) - continue; - - if (m->includes_filehdr) - { - filehdr_vaddr = p->p_vaddr; - filehdr_paddr = p->p_paddr; - } - if (m->includes_phdrs) - { - phdrs_vaddr = p->p_vaddr; - phdrs_paddr = p->p_paddr; - if (m->includes_filehdr) - { - hdrs_segment = m; - phdrs_vaddr += bed->s->sizeof_ehdr; - phdrs_paddr += bed->s->sizeof_ehdr; - } - } - } - - if (hdrs_segment != NULL && link_info != NULL) - { - /* There is a segment that contains both the file headers and the - program headers, so provide a symbol __ehdr_start pointing there. - A program can use this to examine itself robustly. */ - - struct elf_link_hash_entry *hash - = elf_link_hash_lookup (elf_hash_table (link_info), "__ehdr_start", - FALSE, FALSE, TRUE); - /* If the symbol was referenced and not defined, define it. */ - if (hash != NULL - && (hash->root.type == bfd_link_hash_new - || hash->root.type == bfd_link_hash_undefined - || hash->root.type == bfd_link_hash_undefweak - || hash->root.type == bfd_link_hash_common)) - { - asection *s = NULL; - if (hdrs_segment->count != 0) - /* The segment contains sections, so use the first one. */ - s = hdrs_segment->sections[0]; - else - /* Use the first (i.e. lowest-addressed) section in any segment. */ - for (m = elf_seg_map (abfd); m != NULL; m = m->next) - if (m->count != 0) - { - s = m->sections[0]; - break; - } - - if (s != NULL) - { - hash->root.u.def.value = filehdr_vaddr - s->vma; - hash->root.u.def.section = s; - } - else - { - hash->root.u.def.value = filehdr_vaddr; - hash->root.u.def.section = bfd_abs_section_ptr; - } - - hash->root.type = bfd_link_hash_defined; - hash->def_regular = 1; - hash->non_elf = 0; - } - } - for (m = elf_seg_map (abfd), p = phdrs; m != NULL; m = m->next, p++) { if (p->p_type == PT_GNU_RELRO) { - bfd_vma start, end; + bfd_vma start, end; /* Bytes. */ bfd_boolean ok; if (link_info != NULL) @@ -5934,7 +6193,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, if (!m->p_size_valid) abort (); start = m->sections[0]->vma; - end = start + m->p_size; + end = start + m->p_size / opb; } else { @@ -5959,7 +6218,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, && lm->count != 0 && (lm->sections[lm->count - 1]->vma + (!IS_TBSS (lm->sections[lm->count - 1]) - ? lm->sections[lm->count - 1]->size + ? lm->sections[lm->count - 1]->size / opb : 0)) > start && lm->sections[0]->vma < end) break; @@ -5979,10 +6238,10 @@ assign_file_positions_for_non_load_sections (bfd *abfd, if (i < lm->count) { - p->p_vaddr = lm->sections[i]->vma; - p->p_paddr = lm->sections[i]->lma; + p->p_vaddr = lm->sections[i]->vma * opb; + p->p_paddr = lm->sections[i]->lma * opb; p->p_offset = lm->sections[i]->filepos; - p->p_memsz = end - p->p_vaddr; + p->p_memsz = end * opb - p->p_vaddr; p->p_filesz = p->p_memsz; /* The RELRO segment typically ends a few bytes @@ -6059,22 +6318,8 @@ assign_file_positions_for_non_load_sections (bfd *abfd, } } } - else if (m->includes_filehdr) - { - p->p_vaddr = filehdr_vaddr; - if (! m->p_paddr_valid) - p->p_paddr = filehdr_paddr; - } - else if (m->includes_phdrs) - { - p->p_vaddr = phdrs_vaddr; - if (! m->p_paddr_valid) - p->p_paddr = phdrs_paddr; - } } - elf_next_file_pos (abfd) = off; - return TRUE; } @@ -6092,11 +6337,12 @@ find_section_in_list (unsigned int i, elf_section_list * list) VMAs must be known before this is called. Reloc sections come in two flavours: Those processed specially as - "side-channel" data attached to a section to which they apply, and - those that bfd doesn't process as relocations. The latter sort are - stored in a normal bfd section by bfd_section_from_shdr. We don't - consider the former sort here, unless they form part of the loadable - image. Reloc sections not assigned here will be handled later by + "side-channel" data attached to a section to which they apply, and those that + bfd doesn't process as relocations. The latter sort are stored in a normal + bfd section by bfd_section_from_shdr. We don't consider the former sort + here, unless they form part of the loadable image. Reloc sections not + assigned here (and compressed debugging sections and CTF sections which + nothing else in the file can rely upon) will be handled later by assign_file_positions_for_relocs. We also don't set the positions of the .symtab and .strtab here. */ @@ -6108,6 +6354,7 @@ assign_file_positions_except_relocs (bfd *abfd, struct elf_obj_tdata *tdata = elf_tdata (abfd); Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int alloc; if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 && bfd_get_format (abfd) != bfd_core) @@ -6131,9 +6378,12 @@ assign_file_positions_except_relocs (bfd *abfd, hdr = *hdrpp; if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) && hdr->bfd_section == NULL) + /* Do not assign offsets for these sections yet: we don't know + their sizes. */ || (hdr->bfd_section != NULL - && (hdr->bfd_section->flags & SEC_ELF_COMPRESS)) - /* Compress DWARF debug sections. */ + && (hdr->bfd_section->flags & SEC_ELF_COMPRESS + || (bfd_section_is_ctf (hdr->bfd_section) + && abfd->is_linker_output))) || i == elf_onesymtab (abfd) || (elf_symtab_shndx_list (abfd) != NULL && hdr == i_shdrpp[elf_symtab_shndx_list (abfd)->ndx]) @@ -6147,11 +6397,10 @@ assign_file_positions_except_relocs (bfd *abfd, } elf_next_file_pos (abfd) = off; + elf_program_header_size (abfd) = 0; } else { - unsigned int alloc; - /* Assign file positions for the loaded sections based on the assignment of sections to segments. */ if (!assign_file_positions_for_load_sections (abfd, link_info)) @@ -6160,68 +6409,16 @@ assign_file_positions_except_relocs (bfd *abfd, /* And for non-load sections. */ if (!assign_file_positions_for_non_load_sections (abfd, link_info)) return FALSE; + } - if (bed->elf_backend_modify_program_headers != NULL) - { - if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info)) - return FALSE; - } - - /* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=. */ - if (link_info != NULL && bfd_link_pie (link_info)) - { - unsigned int num_segments = elf_elfheader (abfd)->e_phnum; - Elf_Internal_Phdr *segment = elf_tdata (abfd)->phdr; - Elf_Internal_Phdr *end_segment = &segment[num_segments]; - - /* Find the lowest p_vaddr in PT_LOAD segments. */ - bfd_vma p_vaddr = (bfd_vma) -1; - for (; segment < end_segment; segment++) - if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr) - p_vaddr = segment->p_vaddr; - - /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD - segments is non-zero. */ - if (p_vaddr) - i_ehdrp->e_type = ET_EXEC; - } - - /* Write out the program headers. */ - alloc = elf_elfheader (abfd)->e_phnum; - if (alloc == 0) - return TRUE; - - /* PR ld/20815 - Check that the program header segment, if present, will - be loaded into memory. FIXME: The check below is not sufficient as - really all PT_LOAD segments should be checked before issuing an error - message. Plus the PHDR segment does not have to be the first segment - in the program header table. But this version of the check should - catch all real world use cases. - - FIXME: We used to have code here to sort the PT_LOAD segments into - ascending order, as per the ELF spec. But this breaks some programs, - including the Linux kernel. But really either the spec should be - changed or the programs updated. */ - if (alloc > 1 - && tdata->phdr[0].p_type == PT_PHDR - && (bed->elf_backend_allow_non_load_phdr == NULL - || !bed->elf_backend_allow_non_load_phdr (abfd, tdata->phdr, - alloc)) - && tdata->phdr[1].p_type == PT_LOAD - && (tdata->phdr[1].p_vaddr > tdata->phdr[0].p_vaddr - || (tdata->phdr[1].p_vaddr + tdata->phdr[1].p_memsz - < tdata->phdr[0].p_vaddr + tdata->phdr[0].p_memsz))) - { - /* The fix for this error is usually to edit the linker script being - used and set up the program headers manually. Either that or - leave room for the headers at the start of the SECTIONS. */ - _bfd_error_handler (_("%pB: error: PHDR segment not covered" - " by LOAD segment"), - abfd); - return FALSE; - } + if (!(*bed->elf_backend_modify_headers) (abfd, link_info)) + return FALSE; - if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 + /* Write out the program headers. */ + alloc = i_ehdrp->e_phnum; + if (alloc != 0) + { + if (bfd_seek (abfd, i_ehdrp->e_phoff, SEEK_SET) != 0 || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) return FALSE; } @@ -6229,8 +6426,9 @@ assign_file_positions_except_relocs (bfd *abfd, return TRUE; } -static bfd_boolean -prep_headers (bfd *abfd) +bfd_boolean +_bfd_elf_init_file_header (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) { Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */ struct elf_strtab_hash *shstrtab; @@ -6293,16 +6491,6 @@ prep_headers (bfd *abfd) i_ehdrp->e_entry = bfd_get_start_address (abfd); i_ehdrp->e_shentsize = bed->s->sizeof_shdr; - /* If we're building an executable, we'll need a program header table. */ - if (abfd->flags & EXEC_P) - /* It all happens later. */ - ; - else - { - i_ehdrp->e_phentsize = 0; - i_ehdrp->e_phoff = 0; - } - elf_tdata (abfd)->symtab_hdr.sh_name = (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", FALSE); elf_tdata (abfd)->strtab_hdr.sh_name = @@ -6317,6 +6505,38 @@ prep_headers (bfd *abfd) return TRUE; } +/* Set e_type in ELF header to ET_EXEC for -pie -Ttext-segment=. + + FIXME: We used to have code here to sort the PT_LOAD segments into + ascending order, as per the ELF spec. But this breaks some programs, + including the Linux kernel. But really either the spec should be + changed or the programs updated. */ + +bfd_boolean +_bfd_elf_modify_headers (bfd *obfd, struct bfd_link_info *link_info) +{ + if (link_info != NULL && bfd_link_pie (link_info)) + { + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (obfd); + unsigned int num_segments = i_ehdrp->e_phnum; + struct elf_obj_tdata *tdata = elf_tdata (obfd); + Elf_Internal_Phdr *segment = tdata->phdr; + Elf_Internal_Phdr *end_segment = &segment[num_segments]; + + /* Find the lowest p_vaddr in PT_LOAD segments. */ + bfd_vma p_vaddr = (bfd_vma) -1; + for (; segment < end_segment; segment++) + if (segment->p_type == PT_LOAD && p_vaddr > segment->p_vaddr) + p_vaddr = segment->p_vaddr; + + /* Set e_type to ET_EXEC if the lowest p_vaddr in PT_LOAD + segments is non-zero. */ + if (p_vaddr) + i_ehdrp->e_type = ET_EXEC; + } + return TRUE; +} + /* Assign file positions for all the reloc sections which are not part of the loadable file image, and the file position of section headers. */ @@ -6341,10 +6561,12 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd) asection *sec = shdrp->bfd_section; bfd_boolean is_rel = (shdrp->sh_type == SHT_REL || shdrp->sh_type == SHT_RELA); + bfd_boolean is_ctf = sec && bfd_section_is_ctf (sec); if (is_rel + || is_ctf || (sec != NULL && (sec->flags & SEC_ELF_COMPRESS))) { - if (!is_rel) + if (!is_rel && !is_ctf) { const char *name = sec->name; struct bfd_elf_section_data *d; @@ -6390,6 +6612,13 @@ _bfd_elf_assign_file_positions_for_non_load (bfd *abfd) shdrp->contents = sec->contents; shdrp->bfd_section->contents = NULL; } + else if (is_ctf) + { + /* Update section size and contents. */ + shdrp->sh_size = sec->size; + shdrp->contents = sec->contents; + } + off = _bfd_elf_assign_file_position_for_section (shdrp, off, TRUE); @@ -6477,8 +6706,8 @@ _bfd_elf_write_object_contents (bfd *abfd) || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) return FALSE; - if (bed->elf_backend_final_write_processing) - (*bed->elf_backend_final_write_processing) (abfd, elf_linker (abfd)); + if (!(*bed->elf_backend_final_write_processing) (abfd)) + return FALSE; if (!bed->s->write_shdrs_and_ehdr (abfd)) return FALSE; @@ -6609,6 +6838,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) struct elf_segment_map *phdr_adjust_seg = NULL; unsigned int phdr_adjust_num = 0; const struct elf_backend_data *bed; + unsigned int opb = bfd_octets_per_byte (ibfd, NULL); bed = get_elf_backend_data (ibfd); iehdr = elf_elfheader (ibfd); @@ -6631,16 +6861,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) /* Returns TRUE if the given section is contained within the given segment. VMA addresses are compared. */ -#define IS_CONTAINED_BY_VMA(section, segment) \ - (section->vma >= segment->p_vaddr \ - && (section->vma + SECTION_SIZE (section, segment) \ +#define IS_CONTAINED_BY_VMA(section, segment, opb) \ + (section->vma * (opb) >= segment->p_vaddr \ + && (section->vma * (opb) + SECTION_SIZE (section, segment) \ <= (SEGMENT_END (segment, segment->p_vaddr)))) /* Returns TRUE if the given section is contained within the given segment. LMA addresses are compared. */ -#define IS_CONTAINED_BY_LMA(section, segment, base) \ - (section->lma >= base \ - && (section->lma + SECTION_SIZE (section, segment) \ +#define IS_CONTAINED_BY_LMA(section, segment, base, opb) \ + (section->lma * (opb) >= base \ + && (section->lma + SECTION_SIZE (section, segment) / (opb) >= section->lma) \ + && (section->lma * (opb) + SECTION_SIZE (section, segment) \ <= SEGMENT_END (segment, base))) /* Handle PT_NOTE segment. */ @@ -6686,10 +6917,10 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. 8. PT_DYNAMIC should not contain empty sections at the beginning (with the possible exception of .dynamic). */ -#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed) \ +#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb) \ ((((segment->p_paddr \ - ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \ - : IS_CONTAINED_BY_VMA (section, segment)) \ + ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb) \ + : IS_CONTAINED_BY_VMA (section, segment, opb)) \ && (section->flags & SEC_ALLOC) != 0) \ || IS_NOTE (segment, section)) \ && segment->p_type != PT_GNU_STACK \ @@ -6701,16 +6932,15 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) && (segment->p_type != PT_DYNAMIC \ || SECTION_SIZE (section, segment) > 0 \ || (segment->p_paddr \ - ? segment->p_paddr != section->lma \ - : segment->p_vaddr != section->vma) \ - || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \ - == 0)) \ + ? segment->p_paddr != section->lma * (opb) \ + : segment->p_vaddr != section->vma * (opb)) \ + || (strcmp (bfd_section_name (section), ".dynamic") == 0)) \ && (segment->p_type != PT_LOAD || !section->segment_mark)) /* If the output section of a section in the input segment is NULL, it is removed from the corresponding output segment. */ -#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ - (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed) \ +#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed, opb) \ + (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb) \ && section->output_section != NULL) /* Returns TRUE iff seg1 starts after the end of seg2. */ @@ -6764,7 +6994,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) { /* Mininal change so that the normal section to segment assignment code will work. */ - segment->p_vaddr = section->vma; + segment->p_vaddr = section->vma * opb; break; } @@ -6836,7 +7066,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) asection *matching_lma; asection *suggested_lma; unsigned int j; - bfd_size_type amt; + size_t amt; asection *first_section; if (segment->p_type == PT_NULL) @@ -6850,7 +7080,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) { /* Find the first section in the input segment, which may be removed from the corresponding output segment. */ - if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)) + if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb)) { if (first_section == NULL) first_section = section; @@ -6862,7 +7092,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) /* Allocate a segment map big enough to contain all of the sections we have selected. */ amt = sizeof (struct elf_segment_map) - sizeof (asection *); - amt += (bfd_size_type) section_count * sizeof (asection *); + amt += section_count * sizeof (asection *); map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -6918,7 +7148,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) " at vaddr=%#" PRIx64 ", is this intentional?"), ibfd, (uint64_t) segment->p_vaddr); - map->p_vaddr_offset = segment->p_vaddr; + map->p_vaddr_offset = segment->p_vaddr / opb; map->count = 0; *pointer_to_map = map; pointer_to_map = &map->next; @@ -6954,7 +7184,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) pointers that we are interested in. As these sections get assigned to a segment, they are removed from this array. */ - sections = (asection **) bfd_malloc2 (section_count, sizeof (asection *)); + amt = section_count * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); if (sections == NULL) return FALSE; @@ -6972,7 +7203,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) section != NULL; section = section->next) { - if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed)) + if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed, opb)) { output_section = section->output_section; @@ -6993,16 +7224,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) + (map->includes_phdrs ? iehdr->e_phnum * iehdr->e_phentsize : 0), - output_section->alignment_power) - == output_section->vma)) + output_section->alignment_power * opb) + == (output_section->vma * opb))) map->p_paddr = segment->p_vaddr; /* Match up the physical address of the segment with the LMA address of the output section. */ - if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr, + opb) || IS_COREFILE_NOTE (segment, section) || (bed->want_p_paddr_set_to_zero - && IS_CONTAINED_BY_VMA (output_section, segment))) + && IS_CONTAINED_BY_VMA (output_section, segment, opb))) { if (matching_lma == NULL || output_section->lma < matching_lma->lma) @@ -7036,14 +7268,19 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) pointer_to_map = &map->next; if (p_paddr_valid - && !bed->want_p_paddr_set_to_zero - && matching_lma->lma != map->p_paddr - && !map->includes_filehdr - && !map->includes_phdrs) - /* There is some padding before the first section in the - segment. So, we must account for that in the output - segment's vma. */ - map->p_vaddr_offset = map->p_paddr - matching_lma->lma; + && !bed->want_p_paddr_set_to_zero) + { + bfd_vma hdr_size = 0; + if (map->includes_filehdr) + hdr_size = iehdr->e_ehsize; + if (map->includes_phdrs) + hdr_size += iehdr->e_phnum * iehdr->e_phentsize; + + /* Account for padding before the first section in the + segment. */ + map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb + - matching_lma->lma); + } free (sections); continue; @@ -7056,7 +7293,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) if (matching_lma == NULL) matching_lma = suggested_lma; - map->p_paddr = matching_lma->lma; + map->p_paddr = matching_lma->lma * opb; /* Offset the segment physical address from the lma to allow for space taken up by elf headers. */ @@ -7084,7 +7321,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) the same alignment. */ if (segment->p_align != 0 && segment->p_align < align) align = segment->p_align; - map->p_paddr &= -align; + map->p_paddr &= -(align * opb); } } @@ -7113,7 +7350,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) BFD_ASSERT (output_section != NULL); - if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr, + opb) || IS_COREFILE_NOTE (segment, section)) { if (map->count == 0) @@ -7127,9 +7365,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) + (map->includes_phdrs ? iehdr->e_phnum * iehdr->e_phentsize : 0), - output_section->alignment_power) - != output_section->lma) - abort (); + output_section->alignment_power * opb) + != output_section->lma * opb) + goto sorry; } else { @@ -7163,7 +7401,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) suggested_lma = output_section; } - BFD_ASSERT (map->count > 0); + /* PR 23932. A corrupt input file may contain sections that cannot + be assigned to any segment - because for example they have a + negative size - or segments that do not contain any sections. + But there are also valid reasons why a segment can be empty. + So allow a count of zero. */ /* Add the current segment to the list of built segments. */ *pointer_to_map = map; @@ -7175,7 +7417,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) segments. Create a new segment here, initialise it and carry on looping. */ amt = sizeof (struct elf_segment_map) - sizeof (asection *); - amt += (bfd_size_type) section_count * sizeof (asection *); + amt += section_count * sizeof (asection *); map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) { @@ -7190,11 +7432,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) map->p_type = segment->p_type; map->p_flags = segment->p_flags; map->p_flags_valid = 1; - map->p_paddr = suggested_lma->lma; + map->p_paddr = suggested_lma->lma * opb; map->p_paddr_valid = p_paddr_valid; map->includes_filehdr = 0; map->includes_phdrs = 0; } + + continue; + sorry: + bfd_set_error (bfd_error_sorry); + free (sections); + return FALSE; } while (isec < section_count); @@ -7255,6 +7503,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) unsigned int num_segments; bfd_boolean phdr_included = FALSE; bfd_boolean p_paddr_valid; + unsigned int opb = bfd_octets_per_byte (ibfd, NULL); iehdr = elf_elfheader (ibfd); @@ -7280,11 +7529,10 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) { asection *section; unsigned int section_count; - bfd_size_type amt; + size_t amt; Elf_Internal_Shdr *this_hdr; asection *first_section = NULL; asection *lowest_section; - bfd_boolean no_contents = TRUE; /* Compute how many sections are in this segment. */ for (section = ibfd->sections, section_count = 0; @@ -7296,8 +7544,6 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) { if (first_section == NULL) first_section = section; - if (elf_section_type (section) != SHT_NOBITS) - no_contents = FALSE; section_count++; } } @@ -7305,7 +7551,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) /* Allocate a segment map big enough to contain all of the sections we have selected. */ amt = sizeof (struct elf_segment_map) - sizeof (asection *); - amt += (bfd_size_type) section_count * sizeof (asection *); + amt += section_count * sizeof (asection *); map = (struct elf_segment_map *) bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -7383,7 +7629,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) seg_off = this_hdr->sh_offset - segment->p_offset; else seg_off = this_hdr->sh_addr - segment->p_vaddr; - if (section->lma - segment->p_paddr != seg_off) + if (section->lma * opb - segment->p_paddr != seg_off) map->p_paddr_valid = FALSE; } if (isec == section_count) @@ -7392,27 +7638,20 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) } } - if (map->includes_filehdr && lowest_section != NULL) + if (section_count == 0) + map->p_vaddr_offset = segment->p_vaddr / opb; + else if (map->p_paddr_valid) { - /* Try to keep the space used by the headers plus any - padding fixed. If there are sections with file contents - in this segment then the lowest sh_offset is the best - guess. Otherwise the segment only has file contents for - the headers, and p_filesz is the best guess. */ - if (no_contents) - map->header_size = segment->p_filesz; - else - map->header_size = lowest_section->filepos; - } + /* Account for padding before the first section in the segment. */ + bfd_vma hdr_size = 0; + if (map->includes_filehdr) + hdr_size = iehdr->e_ehsize; + if (map->includes_phdrs) + hdr_size += iehdr->e_phnum * iehdr->e_phentsize; - if (section_count == 0) - map->p_vaddr_offset = segment->p_vaddr; - else if (!map->includes_phdrs - && !map->includes_filehdr - && map->p_paddr_valid) - /* Account for padding before the first section. */ - map->p_vaddr_offset = (segment->p_paddr - - (lowest_section ? lowest_section->lma : 0)); + map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb + - (lowest_section ? lowest_section->lma : 0)); + } map->count = section_count; *pointer_to_map = map; @@ -7512,7 +7751,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) return copy_elf_program_header (ibfd, obfd); } -rewrite: + rewrite: if (ibfd->xvec == obfd->xvec) { /* When rewriting program header, set the output maxpagesize to @@ -7565,10 +7804,19 @@ _bfd_elf_init_private_section_data (bfd *ibfd, BFD_ASSERT (elf_section_data (osec) != NULL); - /* For objcopy and relocatable link, don't copy the output ELF - section type from input if the output BFD section flags have been - set to something different. For a final link allow some flags - that the linker clears to differ. */ + /* If this is a known ABI section, ELF section type and flags may + have been set up when OSEC was created. For normal sections we + allow the user to override the type and flags other than + SHF_MASKOS and SHF_MASKPROC. */ + if (elf_section_type (osec) == SHT_PROGBITS + || elf_section_type (osec) == SHT_NOTE + || elf_section_type (osec) == SHT_NOBITS) + elf_section_type (osec) = SHT_NULL; + /* For objcopy and relocatable link, copy the ELF section type from + the input file if the BFD section flags are the same. (If they + are different the user may be doing something like + "objcopy --set-section-flags .text=alloc,data".) For a final + link allow some flags that the linker clears to differ. */ if (elf_section_type (osec) == SHT_NULL && (osec->flags == isec->flags || (final_link @@ -7577,11 +7825,12 @@ _bfd_elf_init_private_section_data (bfd *ibfd, elf_section_type (osec) = elf_section_type (isec); /* FIXME: Is this correct for all OS/PROC specific flags? */ - elf_section_flags (osec) |= (elf_section_flags (isec) - & (SHF_MASKOS | SHF_MASKPROC)); + elf_section_flags (osec) = (elf_section_flags (isec) + & (SHF_MASKOS | SHF_MASKPROC)); /* Copy sh_info from input for mbind section. */ - if (elf_section_flags (isec) & SHF_GNU_MBIND) + if ((elf_tdata (ibfd)->has_gnu_osabi & elf_gnu_osabi_mbind) != 0 + && elf_section_flags (isec) & SHF_GNU_MBIND) elf_section_data (osec)->this_hdr.sh_info = elf_section_data (isec)->this_hdr.sh_info; @@ -7682,19 +7931,34 @@ _bfd_elf_fixup_group_sections (bfd *ibfd, asection *discarded) elf_section_flags (s->output_section) &= ~SHF_GROUP; elf_group_name (s->output_section) = NULL; } - /* Conversely, if the member section is not being output - but the SHT_GROUP section is, then adjust its size. */ - else if (s->output_section == discarded - && isec->output_section != discarded) + else { struct bfd_elf_section_data *elf_sec = elf_section_data (s); - removed += 4; - if (elf_sec->rel.hdr != NULL - && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0) - removed += 4; - if (elf_sec->rela.hdr != NULL - && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0) - removed += 4; + if (s->output_section == discarded + && isec->output_section != discarded) + { + /* Conversely, if the member section is not being + output but the SHT_GROUP section is, then adjust + its size. */ + removed += 4; + if (elf_sec->rel.hdr != NULL + && (elf_sec->rel.hdr->sh_flags & SHF_GROUP) != 0) + removed += 4; + if (elf_sec->rela.hdr != NULL + && (elf_sec->rela.hdr->sh_flags & SHF_GROUP) != 0) + removed += 4; + } + else + { + /* Also adjust for zero-sized relocation member + section. */ + if (elf_sec->rel.hdr != NULL + && elf_sec->rel.hdr->sh_size == 0) + removed += 4; + if (elf_sec->rela.hdr != NULL + && elf_sec->rela.hdr->sh_size == 0) + removed += 4; + } } s = elf_next_in_group (s); if (s == first) @@ -7814,7 +8078,7 @@ swap_out_syms (bfd *abfd, int relocatable_p) { const struct elf_backend_data *bed; - int symcount; + unsigned int symcount; asymbol **syms; struct elf_strtab_hash *stt; Elf_Internal_Shdr *symtab_hdr; @@ -7825,9 +8089,9 @@ swap_out_syms (bfd *abfd, bfd_byte *outbound_shndx; unsigned long outbound_syms_index; unsigned long outbound_shndx_index; - int idx; + unsigned int idx; unsigned int num_locals; - bfd_size_type amt; + size_t amt; bfd_boolean name_local_sections; if (!elf_map_symbols (abfd, &num_locals)) @@ -7851,21 +8115,22 @@ swap_out_syms (bfd *abfd, symstrtab_hdr->sh_type = SHT_STRTAB; /* Allocate buffer to swap out the .strtab section. */ - symstrtab = (struct elf_sym_strtab *) bfd_malloc ((symcount + 1) - * sizeof (*symstrtab)); - if (symstrtab == NULL) + if (_bfd_mul_overflow (symcount + 1, sizeof (*symstrtab), &amt) + || (symstrtab = (struct elf_sym_strtab *) bfd_malloc (amt)) == NULL) { + bfd_set_error (bfd_error_no_memory); _bfd_elf_strtab_free (stt); return FALSE; } - outbound_syms = (bfd_byte *) bfd_alloc2 (abfd, 1 + symcount, - bed->s->sizeof_sym); - if (outbound_syms == NULL) + if (_bfd_mul_overflow (symcount + 1, bed->s->sizeof_sym, &amt) + || (outbound_syms = (bfd_byte *) bfd_alloc (abfd, amt)) == NULL) { -error_return: - _bfd_elf_strtab_free (stt); + error_no_mem: + bfd_set_error (bfd_error_no_memory); + error_return: free (symstrtab); + _bfd_elf_strtab_free (stt); return FALSE; } symtab_hdr->contents = outbound_syms; @@ -7879,9 +8144,10 @@ error_return: symtab_shndx_hdr = & elf_symtab_shndx_list (abfd)->hdr; if (symtab_shndx_hdr->sh_name != 0) { - amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx); - outbound_shndx = (bfd_byte *) - bfd_zalloc2 (abfd, 1 + symcount, sizeof (Elf_External_Sym_Shndx)); + if (_bfd_mul_overflow (symcount + 1, + sizeof (Elf_External_Sym_Shndx), &amt)) + goto error_no_mem; + outbound_shndx = (bfd_byte *) bfd_zalloc (abfd, amt); if (outbound_shndx == NULL) goto error_return; @@ -8003,9 +8269,26 @@ error_return: if (elf_symtab_shndx_list (abfd)) shndx = elf_symtab_shndx_list (abfd)->ndx; break; - default: + case SHN_COMMON: + case SHN_ABS: shndx = SHN_ABS; break; + default: + if (shndx >= SHN_LOPROC && shndx <= SHN_HIOS) + { + if (bed->symbol_section_index) + shndx = bed->symbol_section_index (abfd, type_ptr); + /* Otherwise just leave the index alone. */ + } + else + { + if (shndx > SHN_HIOS && shndx < SHN_HIRESERVE) + _bfd_error_handler (_("%pB: \ +Unable to handle section index %x in ELF symbol. Using ABS instead."), + abfd, shndx); + shndx = SHN_ABS; + } + break; } } else @@ -8176,11 +8459,16 @@ error_return: long _bfd_elf_get_symtab_upper_bound (bfd *abfd) { - long symcount; + bfd_size_type symcount; long symtab_size; Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr; symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + if (symcount >= LONG_MAX / sizeof (asymbol *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } symtab_size = (symcount + 1) * (sizeof (asymbol *)); if (symcount > 0) symtab_size -= sizeof (asymbol *); @@ -8191,7 +8479,7 @@ _bfd_elf_get_symtab_upper_bound (bfd *abfd) long _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) { - long symcount; + bfd_size_type symcount; long symtab_size; Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr; @@ -8202,6 +8490,11 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) } symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + if (symcount >= LONG_MAX / sizeof (asymbol *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } symtab_size = (symcount + 1) * (sizeof (asymbol *)); if (symcount > 0) symtab_size -= sizeof (asymbol *); @@ -8210,9 +8503,30 @@ _bfd_elf_get_dynamic_symtab_upper_bound (bfd *abfd) } long -_bfd_elf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, - sec_ptr asect) +_bfd_elf_get_reloc_upper_bound (bfd *abfd, sec_ptr asect) { + if (asect->reloc_count != 0) + { + /* Sanity check reloc section size. */ + struct bfd_elf_section_data *d = elf_section_data (asect); + Elf_Internal_Shdr *rel_hdr = &d->this_hdr; + bfd_size_type ext_rel_size = rel_hdr->sh_size; + ufile_ptr filesize = bfd_get_file_size (abfd); + + if (filesize != 0 && ext_rel_size > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + +#if SIZEOF_LONG == SIZEOF_INT + if (asect->reloc_count >= LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } +#endif return (asect->reloc_count + 1) * sizeof (arelent *); } @@ -8247,7 +8561,7 @@ _bfd_elf_canonicalize_symtab (bfd *abfd, asymbol **allocation) long symcount = bed->s->slurp_symbol_table (abfd, allocation, FALSE); if (symcount >= 0) - bfd_get_symcount (abfd) = symcount; + abfd->symcount = symcount; return symcount; } @@ -8259,7 +8573,7 @@ _bfd_elf_canonicalize_dynamic_symtab (bfd *abfd, long symcount = bed->s->slurp_symbol_table (abfd, allocation, TRUE); if (symcount >= 0) - bfd_get_dynamic_symcount (abfd) = symcount; + abfd->dynsymcount = symcount; return symcount; } @@ -8271,7 +8585,7 @@ _bfd_elf_canonicalize_dynamic_symtab (bfd *abfd, long _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) { - long ret; + bfd_size_type count, ext_rel_size; asection *s; if (elf_dynsymtab (abfd) == 0) @@ -8280,16 +8594,38 @@ _bfd_elf_get_dynamic_reloc_upper_bound (bfd *abfd) return -1; } - ret = sizeof (arelent *); + count = 1; + ext_rel_size = 0; for (s = abfd->sections; s != NULL; s = s->next) if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) && (elf_section_data (s)->this_hdr.sh_type == SHT_REL || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) - ret += ((s->size / elf_section_data (s)->this_hdr.sh_entsize) - * sizeof (arelent *)); - - return ret; -} + { + ext_rel_size += s->size; + if (ext_rel_size < s->size) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + count += s->size / elf_section_data (s)->this_hdr.sh_entsize; + if (count > LONG_MAX / sizeof (arelent *)) + { + bfd_set_error (bfd_error_file_too_big); + return -1; + } + } + if (count > 1) + { + /* Sanity check reloc section sizes. */ + ufile_ptr filesize = bfd_get_file_size (abfd); + if (filesize != 0 && ext_rel_size > filesize) + { + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + return count * sizeof (arelent *); +} /* Canonicalize the dynamic relocation entries. Note that we return the dynamic relocations as a single block, although they are actually @@ -8347,6 +8683,7 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) { bfd_byte *contents = NULL; unsigned int freeidx = 0; + size_t amt; if (elf_dynverref (abfd) != 0) { @@ -8361,27 +8698,28 @@ _bfd_elf_slurp_version_tables (bfd *abfd, bfd_boolean default_imported_symver) if (hdr->sh_info == 0 || hdr->sh_info > hdr->sh_size / sizeof (Elf_External_Verneed)) { -error_return_bad_verref: + error_return_bad_verref: _bfd_error_handler (_("%pB: .gnu.version_r invalid entry"), abfd); bfd_set_error (bfd_error_bad_value); -error_return_verref: + error_return_verref: elf_tdata (abfd)->verref = NULL; elf_tdata (abfd)->cverrefs = 0; goto error_return; } - contents = (bfd_byte *) bfd_malloc (hdr->sh_size); - if (contents == NULL) + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0) goto error_return_verref; - - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) + contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + if (contents == NULL) goto error_return_verref; - elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) - bfd_alloc2 (abfd, hdr->sh_info, sizeof (Elf_Internal_Verneed)); - + if (_bfd_mul_overflow (hdr->sh_info, sizeof (Elf_Internal_Verneed), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return_verref; + } + elf_tdata (abfd)->verref = (Elf_Internal_Verneed *) bfd_alloc (abfd, amt); if (elf_tdata (abfd)->verref == NULL) goto error_return_verref; @@ -8410,9 +8748,14 @@ error_return_verref: iverneed->vn_auxptr = NULL; else { + if (_bfd_mul_overflow (iverneed->vn_cnt, + sizeof (Elf_Internal_Vernaux), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return_verref; + } iverneed->vn_auxptr = (struct elf_internal_vernaux *) - bfd_alloc2 (abfd, iverneed->vn_cnt, - sizeof (Elf_Internal_Vernaux)); + bfd_alloc (abfd, amt); if (iverneed->vn_auxptr == NULL) goto error_return_verref; } @@ -8498,11 +8841,10 @@ error_return_verref: goto error_return; } - contents = (bfd_byte *) bfd_malloc (hdr->sh_size); - if (contents == NULL) + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0) goto error_return_verdef; - if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 - || bfd_bread (contents, hdr->sh_size, abfd) != hdr->sh_size) + contents = _bfd_malloc_and_read (abfd, hdr->sh_size, hdr->sh_size); + if (contents == NULL) goto error_return_verdef; BFD_ASSERT (sizeof (Elf_External_Verdef) @@ -8544,9 +8886,12 @@ error_return_verref: else freeidx = ++maxidx; } - - elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) - bfd_zalloc2 (abfd, maxidx, sizeof (Elf_Internal_Verdef)); + if (_bfd_mul_overflow (maxidx, sizeof (Elf_Internal_Verdef), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return_verdef; + } + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt); if (elf_tdata (abfd)->verdef == NULL) goto error_return_verdef; @@ -8574,9 +8919,14 @@ error_return_verref: iverdef->vd_auxptr = NULL; else { + if (_bfd_mul_overflow (iverdef->vd_cnt, + sizeof (Elf_Internal_Verdaux), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return_verdef; + } iverdef->vd_auxptr = (struct elf_internal_verdaux *) - bfd_alloc2 (abfd, iverdef->vd_cnt, - sizeof (Elf_Internal_Verdaux)); + bfd_alloc (abfd, amt); if (iverdef->vd_auxptr == NULL) goto error_return_verdef; } @@ -8639,8 +8989,12 @@ error_return_verref: else freeidx++; - elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) - bfd_zalloc2 (abfd, freeidx, sizeof (Elf_Internal_Verdef)); + if (_bfd_mul_overflow (freeidx, sizeof (Elf_Internal_Verdef), &amt)) + { + bfd_set_error (bfd_error_file_too_big); + goto error_return; + } + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt); if (elf_tdata (abfd)->verdef == NULL) goto error_return; @@ -8678,8 +9032,7 @@ error_return_verref: return TRUE; error_return: - if (contents != NULL) - free (contents); + free (contents); return FALSE; } @@ -8688,7 +9041,7 @@ _bfd_elf_make_empty_symbol (bfd *abfd) { elf_symbol_type *newsym; - newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof * newsym); + newsym = (elf_symbol_type *) bfd_zalloc (abfd, sizeof (*newsym)); if (!newsym) return NULL; newsym->symbol.the_bfd = abfd; @@ -8814,11 +9167,12 @@ _bfd_elf_find_nearest_line (bfd *abfd, if (_bfd_dwarf2_find_nearest_line (abfd, symbols, NULL, section, offset, filename_ptr, functionname_ptr, line_ptr, discriminator_ptr, - dwarf_debug_sections, 0, - &elf_tdata (abfd)->dwarf2_find_line_info) - || _bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset, - filename_ptr, functionname_ptr, - line_ptr)) + dwarf_debug_sections, + &elf_tdata (abfd)->dwarf2_find_line_info)) + return TRUE; + + if (_bfd_dwarf1_find_nearest_line (abfd, symbols, section, offset, + filename_ptr, functionname_ptr, line_ptr)) { if (!*functionname_ptr) _bfd_elf_find_function (abfd, symbols, section, offset, @@ -8854,7 +9208,7 @@ _bfd_elf_find_line (bfd *abfd, asymbol **symbols, asymbol *symbol, { return _bfd_dwarf2_find_nearest_line (abfd, symbols, symbol, NULL, 0, filename_ptr, NULL, line_ptr, NULL, - dwarf_debug_sections, 0, + dwarf_debug_sections, &elf_tdata (abfd)->dwarf2_find_line_info); } @@ -8926,15 +9280,47 @@ _bfd_elf_set_section_contents (bfd *abfd, hdr = &elf_section_data (section)->this_hdr; if (hdr->sh_offset == (file_ptr) -1) { - /* We must compress this section. Write output to the buffer. */ - unsigned char *contents = hdr->contents; - if ((offset + count) > hdr->sh_size - || (section->flags & SEC_ELF_COMPRESS) == 0 - || contents == NULL) - abort (); + unsigned char *contents; + + if (bfd_section_is_ctf (section)) + /* Nothing to do with this section: the contents are generated + later. */ + return TRUE; + + if ((section->flags & SEC_ELF_COMPRESS) == 0) + { + _bfd_error_handler + (_("%pB:%pA: error: attempting to write into an unallocated compressed section"), + abfd, section); + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + if ((offset + count) > hdr->sh_size) + { + _bfd_error_handler + (_("%pB:%pA: error: attempting to write over the end of the section"), + abfd, section); + + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + contents = hdr->contents; + if (contents == NULL) + { + _bfd_error_handler + (_("%pB:%pA: error: attempting to write section into an empty buffer"), + abfd, section); + + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + memcpy (contents + offset, location, count); return TRUE; } + pos = hdr->sh_offset + offset; if (bfd_seek (abfd, pos, SEEK_SET) != 0 || bfd_bwrite (location, count, abfd) != count) @@ -8995,7 +9381,7 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc) howto = bfd_reloc_type_lookup (abfd, code); - if (areloc->howto->pcrel_offset != howto->pcrel_offset) + if (howto && areloc->howto->pcrel_offset != howto->pcrel_offset) { if (howto->pcrel_offset) areloc->addend += areloc->address; @@ -9044,7 +9430,7 @@ _bfd_elf_validate_reloc (bfd *abfd, arelent *areloc) /* xgettext:c-format */ _bfd_error_handler (_("%pB: %s unsupported"), abfd, areloc->howto->name); - bfd_set_error (bfd_error_bad_value); + bfd_set_error (bfd_error_sorry); return FALSE; } @@ -9052,7 +9438,9 @@ bfd_boolean _bfd_elf_close_and_cleanup (bfd *abfd) { struct elf_obj_tdata *tdata = elf_tdata (abfd); - if (bfd_get_format (abfd) == bfd_object && tdata != NULL) + if (tdata != NULL + && (bfd_get_format (abfd) == bfd_object + || bfd_get_format (abfd) == bfd_core)) { if (elf_tdata (abfd)->o != NULL && elf_shstrtab (abfd) != NULL) _bfd_elf_strtab_free (elf_shstrtab (abfd)); @@ -9164,6 +9552,23 @@ _bfd_elfcore_make_pseudosection (bfd *abfd, return elfcore_maybe_make_sect (abfd, name, sect); } +static bfd_boolean +elfcore_make_auxv_note_section (bfd *abfd, Elf_Internal_Note *note, + size_t offs) +{ + asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", + SEC_HAS_CONTENTS); + + if (sect == NULL) + return FALSE; + + sect->size = note->descsz - offs; + sect->filepos = note->descpos + offs; + sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; + + return TRUE; +} + /* prstatus_t exists on: solaris 2.5+ linux 2.[01] + glibc @@ -9486,6 +9891,18 @@ elfcore_grok_aarch_sve (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-aarch-sve", note); } +static bfd_boolean +elfcore_grok_aarch_pauth (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-aarch-pauth", note); +} + +static bfd_boolean +elfcore_grok_arc_v2 (bfd *abfd, Elf_Internal_Note *note) +{ + return elfcore_make_note_pseudosection (abfd, ".reg-arc-v2", note); +} + #if defined (HAVE_PRPSINFO_T) typedef prpsinfo_t elfcore_psinfo_t; #if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ @@ -9865,94 +10282,94 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) case NT_PPC_TAR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tar (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tar (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_PPR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_ppr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_ppr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_DSCR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_dscr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_dscr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_EBB: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_ebb (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_ebb (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_PMU: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_pmu (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_pmu (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CGPR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cgpr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cgpr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CFPR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cfpr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cfpr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CVMX: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cvmx (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cvmx (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CVSX: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cvsx (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cvsx (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_SPR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_spr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_spr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CTAR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_ctar (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_ctar (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CPPR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cppr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cppr (abfd, note); else - return TRUE; + return TRUE; case NT_PPC_TM_CDSCR: if (note->namesz == 6 - && strcmp (note->namedata, "LINUX") == 0) - return elfcore_grok_ppc_tm_cdscr (abfd, note); + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_ppc_tm_cdscr (abfd, note); else - return TRUE; + return TRUE; case NT_S390_HIGH_GPRS: if (note->namesz == 6 @@ -10045,6 +10462,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_ARC_V2: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_arc_v2 (abfd, note); + else + return TRUE; + case NT_ARM_VFP: if (note->namesz == 6 && strcmp (note->namedata, "LINUX") == 0) @@ -10080,6 +10504,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) else return TRUE; + case NT_ARM_PAC_MASK: + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_aarch_pauth (abfd, note); + else + return TRUE; + case NT_PRPSINFO: case NT_PSINFO: if (bed->elf_backend_grok_psinfo) @@ -10092,18 +10523,7 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) #endif case NT_AUXV: - { - asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", - SEC_HAS_CONTENTS); - - if (sect == NULL) - return FALSE; - sect->size = note->descsz; - sect->filepos = note->descpos; - sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; - - return TRUE; - } + return elfcore_make_auxv_note_section (abfd, note, 0); case NT_FILE: return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.file", @@ -10155,8 +10575,8 @@ static bfd_boolean elfobj_grok_stapsdt_note_1 (bfd *abfd, Elf_Internal_Note *note) { struct sdt_note *cur = - (struct sdt_note *) bfd_alloc (abfd, sizeof (struct sdt_note) - + note->descsz); + (struct sdt_note *) bfd_alloc (abfd, + sizeof (struct sdt_note) + note->descsz); cur->next = (struct sdt_note *) (elf_tdata (abfd))->sdt_note_head; cur->size = (bfd_size_type) note->descsz; @@ -10349,18 +10769,7 @@ elfcore_grok_freebsd_note (bfd *abfd, Elf_Internal_Note *note) note); case NT_FREEBSD_PROCSTAT_AUXV: - { - asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", - SEC_HAS_CONTENTS); - - if (sect == NULL) - return FALSE; - sect->size = note->descsz - 4; - sect->filepos = note->descpos + 4; - sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; - - return TRUE; - } + return elfcore_make_auxv_note_section (abfd, note, 4); case NT_X86_XSTATE: if (note->namesz == 8) @@ -10424,17 +10833,30 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) if (elfcore_netbsd_get_lwpid (note, &lwp)) elf_tdata (abfd)->core->lwpid = lwp; - if (note->type == NT_NETBSDCORE_PROCINFO) + switch (note->type) { + case NT_NETBSDCORE_PROCINFO: /* NetBSD-specific core "procinfo". Note that we expect to find this note before any of the others, which is fine, since the kernel writes this note out first when it creates a core file. */ - return elfcore_grok_netbsd_procinfo (abfd, note); +#ifdef NT_NETBSDCORE_AUXV + case NT_NETBSDCORE_AUXV: + /* NetBSD-specific Elf Auxiliary Vector data. */ + return elfcore_make_auxv_note_section (abfd, note, 4); +#endif +#ifdef NT_NETBSDCORE_LWPSTATUS + case NT_NETBSDCORE_LWPSTATUS: + return elfcore_make_note_pseudosection (abfd, + ".note.netbsdcore.lwpstatus", + note); +#endif + default: + break; } - /* As of Jan 2002 there are no other machine-independent notes + /* As of March 2020 there are no other machine-independent notes defined for NetBSD core files. If the note type is less than the start of the machine-dependent note types, we don't understand it. */ @@ -10448,6 +10870,7 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and PT_GETFPREGS == mach+2. */ + case bfd_arch_aarch64: case bfd_arch_alpha: case bfd_arch_sparc: switch (note->type) @@ -10462,6 +10885,23 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) return TRUE; } + /* On SuperH, PT_GETREGS == mach+3 and PT_GETFPREGS == mach+5. + There's also old PT___GETREGS40 == mach + 1 for old reg + structure which lacks GBR. */ + + case bfd_arch_sh: + switch (note->type) + { + case NT_NETBSDCORE_FIRSTMACH+3: + return elfcore_make_note_pseudosection (abfd, ".reg", note); + + case NT_NETBSDCORE_FIRSTMACH+5: + return elfcore_make_note_pseudosection (abfd, ".reg2", note); + + default: + return TRUE; + } + /* On all other arch's, PT_GETREGS == mach+1 and PT_GETFPREGS == mach+3. */ @@ -10518,18 +10958,7 @@ elfcore_grok_openbsd_note (bfd *abfd, Elf_Internal_Note *note) return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); if (note->type == NT_OPENBSD_AUXV) - { - asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", - SEC_HAS_CONTENTS); - - if (sect == NULL) - return FALSE; - sect->size = note->descsz; - sect->filepos = note->descpos; - sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; - - return TRUE; - } + return elfcore_make_auxv_note_section (abfd, note, 0); if (note->type == NT_OPENBSD_WCOOKIE) { @@ -11063,158 +11492,158 @@ elfcore_write_ppc_vsx (bfd *abfd, char * elfcore_write_ppc_tar (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tar, - int size) + char *buf, + int *bufsiz, + const void *ppc_tar, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TAR, ppc_tar, size); + note_name, NT_PPC_TAR, ppc_tar, size); } char * elfcore_write_ppc_ppr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_ppr, - int size) + char *buf, + int *bufsiz, + const void *ppc_ppr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_PPR, ppc_ppr, size); + note_name, NT_PPC_PPR, ppc_ppr, size); } char * elfcore_write_ppc_dscr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_dscr, - int size) + char *buf, + int *bufsiz, + const void *ppc_dscr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_DSCR, ppc_dscr, size); + note_name, NT_PPC_DSCR, ppc_dscr, size); } char * elfcore_write_ppc_ebb (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_ebb, - int size) + char *buf, + int *bufsiz, + const void *ppc_ebb, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_EBB, ppc_ebb, size); + note_name, NT_PPC_EBB, ppc_ebb, size); } char * elfcore_write_ppc_pmu (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_pmu, - int size) + char *buf, + int *bufsiz, + const void *ppc_pmu, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_PMU, ppc_pmu, size); + note_name, NT_PPC_PMU, ppc_pmu, size); } char * elfcore_write_ppc_tm_cgpr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cgpr, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cgpr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CGPR, ppc_tm_cgpr, size); + note_name, NT_PPC_TM_CGPR, ppc_tm_cgpr, size); } char * elfcore_write_ppc_tm_cfpr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cfpr, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cfpr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CFPR, ppc_tm_cfpr, size); + note_name, NT_PPC_TM_CFPR, ppc_tm_cfpr, size); } char * elfcore_write_ppc_tm_cvmx (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cvmx, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cvmx, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CVMX, ppc_tm_cvmx, size); + note_name, NT_PPC_TM_CVMX, ppc_tm_cvmx, size); } char * elfcore_write_ppc_tm_cvsx (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cvsx, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cvsx, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CVSX, ppc_tm_cvsx, size); + note_name, NT_PPC_TM_CVSX, ppc_tm_cvsx, size); } char * elfcore_write_ppc_tm_spr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_spr, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_spr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_SPR, ppc_tm_spr, size); + note_name, NT_PPC_TM_SPR, ppc_tm_spr, size); } char * elfcore_write_ppc_tm_ctar (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_ctar, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_ctar, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CTAR, ppc_tm_ctar, size); + note_name, NT_PPC_TM_CTAR, ppc_tm_ctar, size); } char * elfcore_write_ppc_tm_cppr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cppr, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cppr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CPPR, ppc_tm_cppr, size); + note_name, NT_PPC_TM_CPPR, ppc_tm_cppr, size); } char * elfcore_write_ppc_tm_cdscr (bfd *abfd, - char *buf, - int *bufsiz, - const void *ppc_tm_cdscr, - int size) + char *buf, + int *bufsiz, + const void *ppc_tm_cdscr, + int size) { char *note_name = "LINUX"; return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PPC_TM_CDSCR, ppc_tm_cdscr, size); + note_name, NT_PPC_TM_CDSCR, ppc_tm_cdscr, size); } static char * @@ -11439,6 +11868,30 @@ elfcore_write_aarch_sve (bfd *abfd, note_name, NT_ARM_SVE, aarch_sve, size); } +char * +elfcore_write_aarch_pauth (bfd *abfd, + char *buf, + int *bufsiz, + const void *aarch_pauth, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_ARM_PAC_MASK, aarch_pauth, size); +} + +char * +elfcore_write_arc_v2 (bfd *abfd, + char *buf, + int *bufsiz, + const void *arc_v2, + int size) +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_ARC_V2, arc_v2, size); +} + char * elfcore_write_register_note (bfd *abfd, char *buf, @@ -11519,6 +11972,10 @@ elfcore_write_register_note (bfd *abfd, return elfcore_write_aarch_hw_watch (abfd, buf, bufsiz, data, size); if (strcmp (section, ".reg-aarch-sve") == 0) return elfcore_write_aarch_sve (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-aarch-pauth") == 0) + return elfcore_write_aarch_pauth (abfd, buf, bufsiz, data, size); + if (strcmp (section, ".reg-arc-v2") == 0) + return elfcore_write_arc_v2 (abfd, buf, bufsiz, data, size); return NULL; } @@ -11582,7 +12039,8 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset, GROKER_ELEMENT ("NetBSD-CORE", elfcore_grok_netbsd_note), GROKER_ELEMENT ( "OpenBSD", elfcore_grok_openbsd_note), GROKER_ELEMENT ("QNX", elfcore_grok_nto_note), - GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note) + GROKER_ELEMENT ("SPU/", elfcore_grok_spu_note), + GROKER_ELEMENT ("GNU", elfobj_grok_gnu_note) }; #undef GROKER_ELEMENT int i; @@ -11622,7 +12080,7 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset, return TRUE; } -static bfd_boolean +bfd_boolean elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size, size_t align) { @@ -11634,7 +12092,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size, if (bfd_seek (abfd, offset, SEEK_SET) != 0) return FALSE; - buf = (char *) bfd_malloc (size + 1); + buf = (char *) _bfd_malloc_and_read (abfd, size + 1, size); if (buf == NULL) return FALSE; @@ -11642,8 +12100,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size, 0-termintate the buffer so that string searches will not overflow. */ buf[size] = 0; - if (bfd_bread (buf, size, abfd) != size - || !elf_parse_notes (abfd, buf, size, offset, align)) + if (!elf_parse_notes (abfd, buf, size, offset, align)) { free (buf); return FALSE; @@ -11791,7 +12248,8 @@ _bfd_elf_section_offset (bfd *abfd, /* address_size and sec->size are in octets. Convert to bytes before subtracting the original offset. */ - offset = (sec->size - address_size) / bfd_octets_per_byte (abfd) - offset; + offset = ((sec->size - address_size) + / bfd_octets_per_byte (abfd, sec) - offset); } return offset; } @@ -11948,22 +12406,37 @@ asection _bfd_elf_large_com_section = BFD_FAKE_SECTION (_bfd_elf_large_com_section, &lcomm_sym, "LARGE_COMMON", 0, SEC_IS_COMMON); -void -_bfd_elf_post_process_headers (bfd * abfd, - struct bfd_link_info * link_info ATTRIBUTE_UNUSED) +bfd_boolean +_bfd_elf_final_write_processing (bfd *abfd) { - Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ + Elf_Internal_Ehdr *i_ehdrp; /* ELF file header, internal form. */ i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; - - /* To make things simpler for the loader on Linux systems we set the - osabi field to ELFOSABI_GNU if the binary contains symbols of - the STT_GNU_IFUNC type or STB_GNU_UNIQUE binding. */ - if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE - && elf_tdata (abfd)->has_gnu_symbols) - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_GNU; + if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE) + i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; + + /* Set the osabi field to ELFOSABI_GNU if the binary contains + SHF_GNU_MBIND sections or symbols of STT_GNU_IFUNC type or + STB_GNU_UNIQUE binding. */ + if (elf_tdata (abfd)->has_gnu_osabi != 0) + { + if (i_ehdrp->e_ident[EI_OSABI] == ELFOSABI_NONE) + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_GNU; + else if (i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_GNU + && i_ehdrp->e_ident[EI_OSABI] != ELFOSABI_FREEBSD) + { + if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_mbind) + _bfd_error_handler (_("GNU_MBIND section is unsupported")); + if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_ifunc) + _bfd_error_handler (_("symbol type STT_GNU_IFUNC is unsupported")); + if (elf_tdata (abfd)->has_gnu_osabi & elf_gnu_osabi_unique) + _bfd_error_handler (_("symbol binding STB_GNU_UNIQUE is unsupported")); + bfd_set_error (bfd_error_sorry); + return FALSE; + } + } + return TRUE; } @@ -12001,3 +12474,435 @@ _bfd_elf_maybe_function_sym (const asymbol *sym, asection *sec, size = 1; return size; } + +/* Set to non-zero to enable some debug messages. */ +#define DEBUG_SECONDARY_RELOCS 0 + +/* An internal-to-the-bfd-library only section type + used to indicate a cached secondary reloc section. */ +#define SHT_SECONDARY_RELOC (SHT_LOOS + SHT_RELA) + +/* Create a BFD section to hold a secondary reloc section. */ + +bfd_boolean +_bfd_elf_init_secondary_reloc_section (bfd * abfd, + Elf_Internal_Shdr *hdr, + const char * name, + unsigned int shindex) +{ + /* We only support RELA secondary relocs. */ + if (hdr->sh_type != SHT_RELA) + return FALSE; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "secondary reloc section %s encountered\n", name); +#endif + hdr->sh_type = SHT_SECONDARY_RELOC; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); +} + +/* Read in any secondary relocs associated with SEC. */ + +bfd_boolean +_bfd_elf_slurp_secondary_reloc_section (bfd * abfd, + asection * sec, + asymbol ** symbols) +{ + const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + asection * relsec; + bfd_boolean result = TRUE; + bfd_vma (*r_sym) (bfd_vma); + +#if BFD_DEFAULT_TARGET_SIZE > 32 + if (bfd_arch_bits_per_address (abfd) != 32) + r_sym = elf64_r_sym; + else +#endif + r_sym = elf32_r_sym; + + /* Discover if there are any secondary reloc sections + associated with SEC. */ + for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next) + { + Elf_Internal_Shdr * hdr = & elf_section_data (relsec)->this_hdr; + + if (hdr->sh_type == SHT_SECONDARY_RELOC + && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx) + { + bfd_byte * native_relocs; + bfd_byte * native_reloc; + arelent * internal_relocs; + arelent * internal_reloc; + unsigned int i; + unsigned int entsize; + unsigned int symcount; + unsigned int reloc_count; + size_t amt; + + if (ebd->elf_info_to_howto == NULL) + return FALSE; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "read secondary relocs for %s from %s\n", + sec->name, relsec->name); +#endif + entsize = hdr->sh_entsize; + + native_relocs = bfd_malloc (hdr->sh_size); + if (native_relocs == NULL) + { + result = FALSE; + continue; + } + + reloc_count = NUM_SHDR_ENTRIES (hdr); + if (_bfd_mul_overflow (reloc_count, sizeof (arelent), & amt)) + { + free (native_relocs); + bfd_set_error (bfd_error_file_too_big); + result = FALSE; + continue; + } + + internal_relocs = (arelent *) bfd_alloc (abfd, amt); + if (internal_relocs == NULL) + { + free (native_relocs); + result = FALSE; + continue; + } + + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (native_relocs, hdr->sh_size, abfd) + != hdr->sh_size)) + { + free (native_relocs); + /* The internal_relocs will be freed when + the memory for the bfd is released. */ + result = FALSE; + continue; + } + + symcount = bfd_get_symcount (abfd); + + for (i = 0, internal_reloc = internal_relocs, + native_reloc = native_relocs; + i < reloc_count; + i++, internal_reloc++, native_reloc += entsize) + { + bfd_boolean res; + Elf_Internal_Rela rela; + + ebd->s->swap_reloca_in (abfd, native_reloc, & rela); + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a normal BFD reloc is always section relative, + and the address of a dynamic reloc is absolute.. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) + internal_reloc->address = rela.r_offset; + else + internal_reloc->address = rela.r_offset - sec->vma; + + if (r_sym (rela.r_info) == STN_UNDEF) + { + /* FIXME: This and the error case below mean that we + have a symbol on relocs that is not elf_symbol_type. */ + internal_reloc->sym_ptr_ptr = + bfd_abs_section_ptr->symbol_ptr_ptr; + } + else if (r_sym (rela.r_info) > symcount) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): relocation %d has invalid symbol index %ld"), + abfd, sec, i, (long) r_sym (rela.r_info)); + bfd_set_error (bfd_error_bad_value); + internal_reloc->sym_ptr_ptr = + bfd_abs_section_ptr->symbol_ptr_ptr; + result = FALSE; + } + else + { + asymbol **ps; + + ps = symbols + r_sym (rela.r_info) - 1; + + internal_reloc->sym_ptr_ptr = ps; + /* Make sure that this symbol is not removed by strip. */ + (*ps)->flags |= BSF_KEEP; + } + + internal_reloc->addend = rela.r_addend; + + res = ebd->elf_info_to_howto (abfd, internal_reloc, & rela); + if (! res || internal_reloc->howto == NULL) + { +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "there is no howto associated with reloc %lx\n", + rela.r_info); +#endif + result = FALSE; + } + } + + free (native_relocs); + /* Store the internal relocs. */ + elf_section_data (relsec)->sec_info = internal_relocs; + } + } + + return result; +} + +/* Set the ELF section header fields of an output secondary reloc section. */ + +bfd_boolean +_bfd_elf_copy_special_section_fields (const bfd * ibfd ATTRIBUTE_UNUSED, + bfd * obfd ATTRIBUTE_UNUSED, + const Elf_Internal_Shdr * isection, + Elf_Internal_Shdr * osection) +{ + asection * isec; + asection * osec; + + if (isection == NULL) + return FALSE; + + if (isection->sh_type != SHT_SECONDARY_RELOC) + return TRUE; + + isec = isection->bfd_section; + if (isec == NULL) + return FALSE; + + osec = osection->bfd_section; + if (osec == NULL) + return FALSE; + + BFD_ASSERT (elf_section_data (osec)->sec_info == NULL); + elf_section_data (osec)->sec_info = elf_section_data (isec)->sec_info; + osection->sh_type = SHT_RELA; + osection->sh_link = elf_onesymtab (obfd); + if (osection->sh_link == 0) + { + /* There is no symbol table - we are hosed... */ + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): link section cannot be set because the output file does not have a symbol table"), + obfd, osec); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Find the output section that corresponds to the isection's sh_info link. */ + if (isection->sh_info == 0 + || isection->sh_info >= elf_numsections (ibfd)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): info section index is invalid"), + obfd, osec); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + isection = elf_elfsections (ibfd)[isection->sh_info]; + + if (isection == NULL + || isection->bfd_section == NULL + || isection->bfd_section->output_section == NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): info section index cannot be set because the section is not in the output"), + obfd, osec); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + osection->sh_info = + elf_section_data (isection->bfd_section->output_section)->this_idx; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "update header of %s, sh_link = %u, sh_info = %u\n", + osec->name, osection->sh_link, osection->sh_info); +#endif + + return TRUE; +} + +/* Write out a secondary reloc section. */ + +bfd_boolean +_bfd_elf_write_secondary_reloc_section (bfd *abfd, asection *sec) +{ + const struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + bfd_vma addr_offset; + asection * relsec; + bfd_vma (*r_info) (bfd_vma, bfd_vma); + bfd_boolean result = TRUE; + + if (sec == NULL) + return FALSE; + +#if BFD_DEFAULT_TARGET_SIZE > 32 + if (bfd_arch_bits_per_address (abfd) != 32) + r_info = elf64_r_info; + else +#endif + r_info = elf32_r_info; + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + addr_offset = 0; + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + addr_offset = sec->vma; + + /* Discover if there are any secondary reloc sections + associated with SEC. */ + for (relsec = abfd->sections; relsec != NULL; relsec = relsec->next) + { + const struct bfd_elf_section_data * const esd = elf_section_data (relsec); + Elf_Internal_Shdr * const hdr = (Elf_Internal_Shdr *) & esd->this_hdr; + + if (hdr->sh_type == SHT_RELA + && hdr->sh_info == (unsigned) elf_section_data (sec)->this_idx) + { + asymbol * last_sym; + int last_sym_idx; + unsigned int reloc_count; + unsigned int idx; + arelent * src_irel; + bfd_byte * dst_rela; + + if (hdr->contents != NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: secondary reloc section processed twice"), + abfd, relsec); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + continue; + } + + reloc_count = hdr->sh_size / hdr->sh_entsize; + if (reloc_count <= 0) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: secondary reloc section is empty!"), + abfd, relsec); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + continue; + } + + hdr->contents = bfd_alloc (abfd, hdr->sh_size); + if (hdr->contents == NULL) + continue; + +#if DEBUG_SECONDARY_RELOCS + fprintf (stderr, "write %u secondary relocs for %s from %s\n", + reloc_count, sec->name, relsec->name); +#endif + last_sym = NULL; + last_sym_idx = 0; + dst_rela = hdr->contents; + src_irel = (arelent *) esd->sec_info; + if (src_irel == NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: internal relocs missing for secondary reloc section"), + abfd, relsec); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + continue; + } + + for (idx = 0; idx < reloc_count; idx++, dst_rela += hdr->sh_entsize) + { + Elf_Internal_Rela src_rela; + arelent *ptr; + asymbol *sym; + int n; + + ptr = src_irel + idx; + if (ptr == NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: reloc table entry %u is empty"), + abfd, relsec, idx); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + break; + } + + if (ptr->sym_ptr_ptr == NULL) + { + /* FIXME: Is this an error ? */ + n = 0; + } + else + { + sym = *ptr->sym_ptr_ptr; + + if (sym == last_sym) + n = last_sym_idx; + else + { + n = _bfd_elf_symbol_from_bfd_symbol (abfd, & sym); + if (n < 0) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: secondary reloc %u references a missing symbol"), + abfd, relsec, idx); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + n = 0; + } + + last_sym = sym; + last_sym_idx = n; + } + + if (sym->the_bfd != NULL + && sym->the_bfd->xvec != abfd->xvec + && ! _bfd_elf_validate_reloc (abfd, ptr)) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: secondary reloc %u references a deleted symbol"), + abfd, relsec, idx); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + n = 0; + } + } + + src_rela.r_offset = ptr->address + addr_offset; + if (ptr->howto == NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("%pB(%pA): error: secondary reloc %u is of an unknown type"), + abfd, relsec, idx); + bfd_set_error (bfd_error_bad_value); + result = FALSE; + src_rela.r_info = r_info (0, 0); + } + else + src_rela.r_info = r_info (n, ptr->howto->type); + src_rela.r_addend = ptr->addend; + ebd->s->swap_reloca_out (abfd, &src_rela, dst_rela); + } + } + } + + return result; +}