From: Alan Modra Date: Tue, 15 Feb 2022 09:41:03 +0000 (+1030) Subject: What to do when sh_addralign isn't a power of two X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1f9b1a84350d3755ce8620900a35c3d1997535e6;p=binutils-gdb.git What to do when sh_addralign isn't a power of two BFD generally doesn't handle anything but a power of two section alignment, and ELF sh_addralign is required to be an integral power of two (or zero) by the ELF spec. Of course this is ignored by fuzzers, and because bfd_log2 rounds up, we can end up with alignment_power being 32 on a 32-bit object or 64 on a 64-bit object. That then triggers ubsan warnings in places like bfd_update_compression_header where we want to convert from alignment_power back to an alignment. I suppose we could reject object files that have non-compliant sh_addralign, but I think it's also reasonable to use the greatest power of two divisor of sh_addralign, ie. the rightmost 1 bit. * elf.c (_bfd_elf_make_section_from_shdr): Use greatest power of two divisor of sh_addralign. (_bfd_elf_assign_file_position_for_section): Likewise. (assign_file_positions_for_non_load_sections): Likewise. --- diff --git a/bfd/elf.c b/bfd/elf.c index 79f71aa81e2..a67415e76e1 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1104,7 +1104,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, 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))) + || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign + & -hdr->sh_addralign))) return false; /* As a GNU extension, if the name begins with .gnu.linkonce, we @@ -4227,7 +4228,7 @@ _bfd_elf_assign_file_position_for_section (Elf_Internal_Shdr *i_shdrp, bool align) { if (align && i_shdrp->sh_addralign > 1) - offset = BFD_ALIGN (offset, i_shdrp->sh_addralign); + offset = BFD_ALIGN (offset, i_shdrp->sh_addralign & -i_shdrp->sh_addralign); i_shdrp->sh_offset = offset; if (i_shdrp->bfd_section != NULL) i_shdrp->bfd_section->filepos = offset; @@ -6149,6 +6150,7 @@ assign_file_positions_for_non_load_sections (bfd *abfd, for (hdrpp = i_shdrpp + 1; hdrpp < end_hdrpp; hdrpp++) { Elf_Internal_Shdr *hdr; + bfd_vma align; hdr = *hdrpp; if (hdr->bfd_section != NULL @@ -6174,11 +6176,10 @@ assign_file_positions_for_non_load_sections (bfd *abfd, : hdr->bfd_section->name)); /* We don't need to page align empty sections. */ if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0) - off += vma_page_aligned_bias (hdr->sh_addr, off, - maxpagesize); + align = maxpagesize; else - off += vma_page_aligned_bias (hdr->sh_addr, off, - hdr->sh_addralign); + align = hdr->sh_addralign & -hdr->sh_addralign; + off += vma_page_aligned_bias (hdr->sh_addr, off, align); off = _bfd_elf_assign_file_position_for_section (hdr, off, false); }