On Tue, 26 Feb 2019, Richard Biener wrote: > On Tue, 26 Feb 2019, Mark Wielaard wrote: > > > On Tue, 2019-02-26 at 09:33 +0100, Richard Biener wrote: > > > On Mon, 25 Feb 2019, Mark Wielaard wrote: > > > > Since the introduction of GNU Property notes this is (sadly) no > > > > longer > > > > the correct way to iterate through ELF notes. The padding of names > > > > and > > > > desc might now depend on the alignment of the PT_NOTE segment. > > > > https://sourceware.org/ml/binutils/2018-09/msg00359.html > > > > > > Ick, that's of course worse ;) So it's not entirely clear what > > > the correct thing to do is - from how I read the mail at the above > > > link only iff sh_align of the note section is exactly 8 the above > > > ALIGN would use 8 byte alignment and else 4 is correct (independent > > > on sh_align). Or can I assume sh_align of the note section is > > > "correct" for all existing binaries? Note also the eventual > > > difference > > > between note sections and note program headers which have another, > > > possibly different(?) alignment? It's of course "easy" to replace > > > 4 above by info->dlpi_phdr[i].p_align (but the align field differs > > > in width between elfclass 32 and 64 ... :/). > > > > > > So - is merely changing the re-alignment from 4 to > > > info->dlpi_phdr[i].p_align "correct"? > > > > Yes, you will have multiple note segments one that combines the 4 > > padded notes and one that combines the 8 padded notes. > > Some tools put 0 or 1 in the align field, so you might want to use > > (completely untested): > > align = (p_align <= 4) ? 4 : 8; > > offset += ALIGN ((ALIGN (sizeof (uint32_t) * 3 + namesz, align) > > + descsz), align); > > That would mean when p_align == 8 the note name isn't 8-aligned > but just 4-aligned? That is, sizeof (Elf*_Nhdr) == 12, and the > name starts right after that instead of being aligned according > to p_align? That sounds odd... So p_align only applies to > the descriptor?
So rather like the following (simplified for _GNU_SOURCE since link.h includes elf.h there). I've not yet come along binaries with different p_align so I can't really test it. #if _GNU_SOURCE #include <link.h> #define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1)) static int get_build_id_1 (struct dl_phdr_info *info, size_t, void *data) { for (unsigned i = 0; i < info->dlpi_phnum; ++i) { if (info->dlpi_phdr[i].p_type != PT_NOTE) continue; ElfW(Nhdr) *nhdr = (ElfW(Nhdr) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr); ptrdiff_t size = info->dlpi_phdr[i].p_filesz; ptrdiff_t align = info->dlpi_phdr[i].p_align; if (align < 4) align = 4; while (size >= (ptrdiff_t)sizeof (ElfW(Nhdr))) { if (nhdr->n_type == NT_GNU_BUILD_ID && nhdr->n_namesz == 4 && strncmp ((char *)nhdr + ALIGN (sizeof (ElfW(Nhdr)), align), "GNU", 4) == 0 && nhdr->n_descsz >= 16) { memcpy (data, (char *)nhdr + ALIGN (sizeof (ElfW(Nhdr)), align) + ALIGN (nhdr->n_namesz, align), 16); return 1; } size_t offset = (ALIGN (sizeof (ElfW(Nhdr)), align) + ALIGN(nhdr->n_namesz, align) + ALIGN(nhdr->n_descsz, align)); nhdr = (ElfW(Nhdr) *)((char *)nhdr + offset); size -= offset; } } return 0; }