From 276da9b31bd6e3eb8d1dd814c867266f59f29093 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 24 Nov 2017 14:49:36 -0800 Subject: [PATCH] Re-apply "elf: Properly compute offsets of note descriptor and next note" CORE PT_NOTE segments may have p_align values of 0 or 1. gABI specifies that PT_NOTE alignment should be aligned to 4 bytes for 32-bit objects and to 8 bytes for 64-bit objects. If segment alignment is less than 4, we use 4 byte alignment. --- bfd/ChangeLog | 15 +++++++++++++++ bfd/elf.c | 31 +++++++++++++++++++++---------- binutils/ChangeLog | 7 +++++++ binutils/readelf.c | 8 ++++++-- include/ChangeLog | 7 +++++++ include/elf/external.h | 16 ++++++++++++++++ 6 files changed, 72 insertions(+), 12 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 55fe3b4..0395dcf 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,18 @@ +2017-11-24 H.J. Lu + + PR binutils/22444 + * elf.c (elf_read_notes): Add an argument for note aligment. + (elf_parse_notes): Likewise. + (_bfd_elf_make_section_from_shdr): Pass section aligment to + elf_parse_notes. + (bfd_section_from_phdr): Pass segment aligment to elf_read_notes. + (elf_parse_notes): Add an argument for note aligment. Use + ELF_NOTE_DESC_OFFSET to get the offset of the note descriptor. + Use ELF_NOTE_NEXT_OFFSET to get the offset of the next note + entry. + (elf_read_notes): Add an argument for note aligment and pass it + to elf_parse_notes. + 2017-11-23 Alan Modra * elf32-hppa.c (pc_dynrelocs): Define. diff --git a/bfd/elf.c b/bfd/elf.c index 8cd67ad..8f6aa53 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -52,9 +52,10 @@ 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) ; +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); + file_ptr offset, size_t align); /* Swap version information in and out. The version information is currently size independent. If that ever changes, this code will @@ -1089,7 +1090,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, if (!bfd_malloc_and_get_section (abfd, newsect, &contents)) return FALSE; - elf_parse_notes (abfd, (char *) contents, hdr->sh_size, hdr->sh_offset); + elf_parse_notes (abfd, (char *) contents, hdr->sh_size, + hdr->sh_offset, hdr->sh_addralign); free (contents); } @@ -2990,7 +2992,8 @@ bfd_section_from_phdr (bfd *abfd, Elf_Internal_Phdr *hdr, int hdr_index) case PT_NOTE: if (! _bfd_elf_make_section_from_phdr (abfd, hdr, hdr_index, "note")) return FALSE; - if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz)) + if (! elf_read_notes (abfd, hdr->p_offset, hdr->p_filesz, + hdr->p_align)) return FALSE; return TRUE; @@ -10970,14 +10973,21 @@ elfcore_write_register_note (bfd *abfd, } static bfd_boolean -elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) +elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset, + size_t align) { char *p; + /* NB: CORE PT_NOTE segments may have p_align values of 0 or 1. + gABI specifies that PT_NOTE alignment should be aligned to 4 + bytes for 32-bit objects and to 8 bytes for 64-bit objects. If + align is less than 4, we use 4 byte alignment. */ + if (align < 4) + align = 4; + p = buf; while (p < buf + size) { - /* FIXME: bad alignment assumption. */ Elf_External_Note *xnp = (Elf_External_Note *) p; Elf_Internal_Note in; @@ -10992,7 +11002,7 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) return FALSE; in.descsz = H_GET_32 (abfd, xnp->descsz); - in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); + in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align); in.descpos = offset + (in.descdata - buf); if (in.descsz != 0 && (in.descdata >= buf + size @@ -11054,14 +11064,15 @@ elf_parse_notes (bfd *abfd, char *buf, size_t size, file_ptr offset) break; } - p = in.descdata + BFD_ALIGN (in.descsz, 4); + p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align); } return TRUE; } static bfd_boolean -elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) +elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size, + size_t align) { char *buf; @@ -11080,7 +11091,7 @@ elf_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) buf[size] = 0; if (bfd_bread (buf, size, abfd) != size - || !elf_parse_notes (abfd, buf, size, offset)) + || !elf_parse_notes (abfd, buf, size, offset, align)) { free (buf); return FALSE; diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 32df4b9..eab6830 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,10 @@ +2017-11-24 H.J. Lu + + PR binutils/22444 + * readelf.c (process_notes_at): Use ELF_NOTE_DESC_OFFSET to get + the offset of the note descriptor. Use ELF_NOTE_NEXT_OFFSET to + get the offset of the next note entry. + 2017-11-23 Pavel I. Kryukov PR 22485 diff --git a/binutils/readelf.c b/binutils/readelf.c index 5944ebe..739367d 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -17969,9 +17969,13 @@ process_notes_at (Filedata * filedata, inote.namesz = BYTE_GET (external->namesz); inote.namedata = external->name; inote.descsz = BYTE_GET (external->descsz); - inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descdata = ((char *) external + + ELF_NOTE_DESC_OFFSET (inote.namesz, + section->sh_addralign)); inote.descpos = offset + (inote.descdata - (char *) pnotes); - next = inote.descdata + align_power (inote.descsz, 2); + next = ((char *) external + + ELF_NOTE_NEXT_OFFSET (inote.namesz, inote.descsz, + section->sh_addralign)); } else { diff --git a/include/ChangeLog b/include/ChangeLog index 670456c..a766867 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,10 @@ +2017-11-24 H.J. Lu + + PR binutils/22444 + * elf/external.h (ELF_ALIGN_UP): New. + (ELF_NOTE_DESC_OFFSET): Likewise. + (ELF_NOTE_NEXT_OFFSET): Likewise. + 2017-11-16 Tamar Christina * opcode/aarch64.h: (AARCH64_FEATURE_F16_FML): New. diff --git a/include/elf/external.h b/include/elf/external.h index d65bae0..eb0a53a 100644 --- a/include/elf/external.h +++ b/include/elf/external.h @@ -183,6 +183,22 @@ typedef struct { char name[1]; /* Start of the name+desc data */ } Elf_External_Note; +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. */ +#define ELF_ALIGN_UP(addr, boundary) \ + (((bfd_vma) (addr) + ((boundary) - 1)) & ~ (bfd_vma) ((boundary) -1)) + +/* Compute the offset of the note descriptor from size of note entry's + owner string and note alignment. */ +#define ELF_NOTE_DESC_OFFSET(namesz, align) \ + ELF_ALIGN_UP (offsetof (Elf_External_Note, name) + (namesz), (align)) + +/* Compute the offset of the next note entry from size of note entry's + owner string, size of the note descriptor and note alignment. */ +#define ELF_NOTE_NEXT_OFFSET(namesz, descsz, align) \ + ELF_ALIGN_UP (ELF_NOTE_DESC_OFFSET ((namesz), (align)) + (descsz), \ + (align)) + /* Relocation Entries */ typedef struct { unsigned char r_offset[4]; /* Location at which to apply the action */ -- 2.7.4