aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2022-02-15 20:11:03 +1030
committerAlan Modra <amodra@gmail.com>2022-02-16 22:05:10 +1030
commit1f9b1a84350d3755ce8620900a35c3d1997535e6 (patch)
treefaf43bbd8090ba94d17758ac78e56dee925253a5 /bfd/elf.c
parent6e731729881ae4c1a9542843c29a3981166c9e45 (diff)
downloadgdb-1f9b1a84350d3755ce8620900a35c3d1997535e6.zip
gdb-1f9b1a84350d3755ce8620900a35c3d1997535e6.tar.gz
gdb-1f9b1a84350d3755ce8620900a35c3d1997535e6.tar.bz2
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.
Diffstat (limited to 'bfd/elf.c')
-rw-r--r--bfd/elf.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/bfd/elf.c b/bfd/elf.c
index 79f71aa..a67415e 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);
}