This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: [PATCH] Fix several mix up between octets and bytes in ELF program headers
- From: Christian Eggers <ceggers at gmx dot de>
- To: binutils at sourceware dot org
- Date: Mon, 02 Dec 2019 21:15:50 +0100
- Subject: Re: [PATCH] Fix several mix up between octets and bytes in ELF program headers
- References: <20191125084333.30248-1-ceggers@gmx.de>
Ping?
Is there anyone available to review these patches?
regards
Christian
Am Montag, 25. November 2019, 09:43:33 CET schrieb Christian Eggers:
> ELF_SECTION_IN_SEGMENT_1() curently compares Elf_Internal_Shdr::sh_addr
> [bytes] and elf_internal_phdr::p_vaddr [bytes] with
> Elf_Internal_Shdr::sh_size [octets] and elf_internal_phdr::p_memsz
> [octets]. Convert the former ones into octets prior comparison.
>
> In ld, the SIZEOF_HEADERS linker script statement must be resolved to
> bytes instead of octets.
>
> Currently I assume that all sections which are related to program
> headers have the same value for octets_per_byte.
>
> BTW: I regognized that there are two similar macros:
> - include/elf/internal.h:308 ELF_TBSS_SPECIAL()
> - bfd/elf.c:4665: IS_TBSS()
> Is this by intention?
>
> include/
> * elf/internal.h (struct elf_internal_phdr): Add unit (octets/
> bytes) to several member field comments.
> (Elf_Internal_Shdr): likewise.
> (ELF_SECTION_IN_SEGMENT_1): Add new parameter opb. Convert
> bytes into octets prior comparison.
> (ELF_SECTION_IN_SEGMENT): Add new parameter opb.
> (ELF_SECTION_IN_SEGMENT_STRICT): likewise.
>
> bfd/
> * elf.c (_bfd_elf_make_section_from_shdr): Supply new parameter
> opb to ELF_SECTION_IN_SEGMENT(). Fix calculation of section LMA
> from segment LMA.
> (_bfd_elf_map_sections_to_segments): Don't mix up octets and
> bytes.
> (assign_file_positions_for_load_sections): Don't mix up octets
> and bytes. Supply new parameter opb to
> ELF_SECTION_IN_SEGMENT_1().
> (rewrite_elf_program_header): Don't mix up octets and bytes.
> (copy_elf_program_header): Supply new parameter opb to
> ELF_SECTION_IN_SEGMENT().
> (copy_private_bfd_data): likewise.
> * elf32-spu.c (spu_elf_object_p): likewise.
>
> binutils/
> * readelf.c (process_program_headers): Add new parameter opb to
> call of ELF_SECTION_IN_SEGMENT_STRICT() macro.
>
> ld/
> * ldexp.c (fold_name): Return SIZEOF_HEADERS in bytes.
>
> gdb/
> * elfread.c (elf_symfile_segments): Add new parameter opb to
> call of ELF_SECTION_IN_SEGMENT() macro.
>
> Signed-off-by: Christian Eggers <ceggers@gmx.de>
> ---
> bfd/elf.c | 70
> +++++++++++++++++++++++++++++--------------------- bfd/elf32-spu.c |
> 3 ++-
> binutils/readelf.c | 5 +++-
> gdb/elfread.c | 3 ++-
> include/elf/internal.h | 33 ++++++++++++------------
> ld/ldexp.c | 3 ++-
> 6 files changed, 68 insertions(+), 49 deletions(-)
>
> diff --git a/bfd/elf.c b/bfd/elf.c
> index a4f26dac71d..10369483de3 100644
> --- a/bfd/elf.c
> +++ b/bfd/elf.c
> @@ -1153,6 +1153,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
> {
> Elf_Internal_Phdr *phdr;
> unsigned int i, nload;
> + unsigned int opb = bfd_octets_per_byte (abfd, newsect);
>
> /* Some ELF linkers produce binaries with all the program header
> p_paddr fields zero. If we have such a binary with more than
> @@ -1173,7 +1174,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
> if (((phdr->p_type == PT_LOAD
> && (hdr->sh_flags & SHF_TLS) == 0)
>
> || phdr->p_type == PT_TLS)
>
> - && ELF_SECTION_IN_SEGMENT (hdr, phdr))
> + && ELF_SECTION_IN_SEGMENT (hdr, phdr, opb))
> {
> if ((flags & SEC_LOAD) == 0)
> newsect->lma = (phdr->p_paddr
> @@ -1187,7 +1188,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
> @@ -4685,6 +4686,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct
> bfd_link_info *info) bfd_size_type amt;
> bfd_vma addr_mask, wrap_to = 0;
> bfd_size_type phdr_size;
> + unsigned int opb = bfd_octets_per_byte (abfd, NULL);
>
> /* Select the allocated sections, and sort them. */
>
> @@ -4724,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;
> @@ -4948,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;
> }
>
> @@ -4974,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;
> }
> @@ -5428,11 +5432,12 @@ assign_file_positions_for_load_sections (bfd *abfd,
> 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 alloc, actual;
> unsigned int i, j;
> 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))
> @@ -5540,7 +5545,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
> for (j = 0; j < alloc; j++)
> {
> asection **secpp;
> - bfd_vma off_adjust;
> + bfd_vma off_adjust; /* bytes */
> bfd_boolean no_contents;
>
> /* An ELF segment (described by Elf_Internal_Phdr) may contain a
> @@ -5600,6 +5605,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
> {
> bfd_size_type align;
> unsigned int align_power = 0;
> + file_ptr off_bytes = off / opb; /* bytes */
>
> if (m->p_align_valid)
> align = p->p_align;
> @@ -5635,7 +5641,7 @@ 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_bytes, align);
>
> /* Broken hardware and/or kernel require that files do not
> map the same page with different permissions on some hppa
> @@ -5643,10 +5649,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
> if (j != 0
> && (abfd->flags & D_PAGED) != 0
> && bed->no_page_alias
> - && (off & (maxpagesize - 1)) != 0
> - && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))
> + && (off_bytes & (maxpagesize - 1)) != 0
> + && ((off_bytes & -maxpagesize)
> + == ((off_bytes + off_adjust) & -maxpagesize)))
> off_adjust += maxpagesize;
> - off += off_adjust;
> + off += off_adjust * opb;
> if (no_contents)
> {
> /* We shouldn't need to align the segment on disk since
> @@ -5689,9 +5696,11 @@ assign_file_positions_for_load_sections (bfd *abfd,
> {
> if (m->count > 0)
> {
> - if (p->p_vaddr < (bfd_vma) off
> + file_ptr off_bytes = off / opb;
> +
> + if (p->p_vaddr < (bfd_vma) off_bytes
>
> || (!m->p_paddr_valid
>
> - && p->p_paddr < (bfd_vma) off))
> + && p->p_paddr < (bfd_vma) off_bytes))
> {
> _bfd_error_handler
> (_("%pB: not enough room for program headers,"
> @@ -5700,9 +5709,9 @@ assign_file_positions_for_load_sections (bfd *abfd,
> bfd_set_error (bfd_error_bad_value);
> return FALSE;
> }
> - p->p_vaddr -= off;
> + p->p_vaddr -= off_bytes;
> if (!m->p_paddr_valid)
> - p->p_paddr -= off;
> + p->p_paddr -= off_bytes;
> }
> }
> else if (sorted_seg_map[0]->includes_filehdr)
> @@ -5727,20 +5736,20 @@ assign_file_positions_for_load_sections (bfd *abfd,
> elf_elfheader (abfd)->e_phoff = p->p_offset;
> if (m->count > 0)
> {
> - p->p_vaddr -= off - p->p_offset;
> + p->p_vaddr -= (off - p->p_offset) / opb;
> if (!m->p_paddr_valid)
> - p->p_paddr -= off - p->p_offset;
> + p->p_paddr -= (off - p->p_offset) / opb;
> }
> }
> else if (phdr_load_seg != NULL)
> {
> Elf_Internal_Phdr *phdr = phdrs + phdr_load_seg->idx;
> - bfd_vma phdr_off = 0;
> + 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;
> + p->p_vaddr = phdr->p_vaddr + phdr_off / opb;
> if (!m->p_paddr_valid)
> - p->p_paddr = phdr->p_paddr + phdr_off;
> + p->p_paddr = phdr->p_paddr + phdr_off / opb;
> p->p_offset = phdr->p_offset + phdr_off;
> }
> else
> @@ -5755,7 +5764,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
> p->p_offset = off;
> else
> {
> - file_ptr adjust;
> + file_ptr adjust; /* octets */
>
> adjust = off - (p->p_offset + p->p_filesz);
> if (!no_contents)
> @@ -5786,10 +5795,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; /* bytes */
> + bfd_vma p_end = p_start + p->p_memsz / opb; /* bytes */
> + bfd_vma s_start = sec->lma; /* bytes */
> + bfd_vma adjust = (s_start - p_end) * opb; /* octets */
>
> if (adjust != 0
> && (s_start < p_end
> @@ -5905,7 +5914,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
> }
> }
>
> - off -= off_adjust;
> + off -= off_adjust * opb;
>
> /* PR ld/20815 - Check that the program header segment, if
> present, will be loaded into memory. */
> @@ -5948,7 +5957,7 @@ assign_file_positions_for_load_sections (bfd *abfd,
>
> sec = m->sections[i];
> this_hdr = &(elf_section_data(sec)->this_hdr);
> - if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, check_vma, 0)
> + if (!ELF_SECTION_IN_SEGMENT_1 (this_hdr, p, opb, check_vma, 0)
> && !ELF_TBSS_SPECIAL (this_hdr, p))
> {
> _bfd_error_handler
> @@ -7223,6 +7232,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
>
> /* Account for padding before the first section in the
> segment. */
> + hdr_size /= bfd_octets_per_byte (ibfd, NULL);
> map->p_vaddr_offset = map->p_paddr + hdr_size - matching_lma->lma;
> }
>
> @@ -7445,6 +7455,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);
>
> @@ -7481,7 +7492,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
> section = section->next)
> {
> this_hdr = &(elf_section_data(section)->this_hdr);
> - if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
> + if (ELF_SECTION_IN_SEGMENT (this_hdr, segment, opb))
> {
> if (first_section == NULL)
> first_section = section;
> @@ -7550,7 +7561,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
> section = section->next)
> {
> this_hdr = &(elf_section_data(section)->this_hdr);
> - if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
> + if (ELF_SECTION_IN_SEGMENT (this_hdr, segment, opb))
> {
> map->sections[isec++] = section->output_section;
> if ((section->flags & SEC_ALLOC) != 0)
> @@ -7625,6 +7636,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
> unsigned int i, num_segments;
> Elf_Internal_Shdr *this_hdr;
> const struct elf_backend_data *bed;
> + unsigned int opb = bfd_octets_per_byte (ibfd, NULL);
>
> bed = get_elf_backend_data (ibfd);
>
> @@ -7662,7 +7674,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd)
>
> /* Check if this section is covered by the segment. */
> this_hdr = &(elf_section_data(section)->this_hdr);
> - if (ELF_SECTION_IN_SEGMENT (this_hdr, segment))
> + if (ELF_SECTION_IN_SEGMENT (this_hdr, segment, opb))
> {
> /* FIXME: Check if its output section is changed or
> removed. What else do we need to check? */
> diff --git a/bfd/elf32-spu.c b/bfd/elf32-spu.c
> index 823628898f7..8429863dcc6 100644
> --- a/bfd/elf32-spu.c
> +++ b/bfd/elf32-spu.c
> @@ -287,7 +287,8 @@ spu_elf_object_p (bfd *abfd)
> Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[j];
>
> if (ELF_SECTION_SIZE (shdr, phdr) != 0
> - && ELF_SECTION_IN_SEGMENT (shdr, phdr))
> + && ELF_SECTION_IN_SEGMENT (shdr, phdr,
> + OCTETS_PER_BYTE (abfd, NULL)))
> {
> asection *sec = shdr->bfd_section;
> spu_elf_section_data (sec)->u.o.ovl_index = num_ovl;
> diff --git a/binutils/readelf.c b/binutils/readelf.c
> index 52bd71f2177..e84713f1771 100644
> --- a/binutils/readelf.c
> +++ b/binutils/readelf.c
> @@ -5367,6 +5367,9 @@ process_program_headers (Filedata * filedata)
> && filedata->section_headers != NULL
> && filedata->string_table != NULL)
> {
> + /* up to now, all ELF targets have one octet per byte */
> + unsigned int opb = 1;
> +
> printf (_("\n Section to Segment mapping:\n"));
> printf (_(" Segment Sections...\n"));
>
> @@ -5383,7 +5386,7 @@ process_program_headers (Filedata * filedata)
> for (j = 1; j < filedata->file_header.e_shnum; j++, section++)
> {
> if (!ELF_TBSS_SPECIAL (section, segment)
> - && ELF_SECTION_IN_SEGMENT_STRICT (section, segment))
> + && ELF_SECTION_IN_SEGMENT_STRICT (section, segment, opb))
> printf ("%s ", printable_section_name (filedata, section));
> }
>
> diff --git a/gdb/elfread.c b/gdb/elfread.c
> index 44b793d8f14..d17fb792520 100644
> --- a/gdb/elfread.c
> +++ b/gdb/elfread.c
> @@ -134,7 +134,8 @@ elf_symfile_segments (bfd *abfd)
> Elf_Internal_Shdr *this_hdr = &elf_section_data (sect)->this_hdr;
>
> for (j = 0; j < num_segments; j++)
> - if (ELF_SECTION_IN_SEGMENT (this_hdr, segments[j]))
> + if (ELF_SECTION_IN_SEGMENT (this_hdr, segments[j],
> + bfd_octets_per_byte (abfd, sect)))
> {
> data->segment_info[i] = j + 1;
> break;
> diff --git a/include/elf/internal.h b/include/elf/internal.h
> index 794c16812ee..d78014a0426 100644
> --- a/include/elf/internal.h
> +++ b/include/elf/internal.h
> @@ -86,11 +86,11 @@ typedef struct elf_internal_ehdr {
> struct elf_internal_phdr {
> unsigned long p_type; /* Identifies program segment type */
> unsigned long p_flags; /* Segment flags */
> - bfd_vma p_offset; /* Segment file offset */
> - bfd_vma p_vaddr; /* Segment virtual address */
> - bfd_vma p_paddr; /* Segment physical address */
> - bfd_vma p_filesz; /* Segment size in file */
> - bfd_vma p_memsz; /* Segment size in memory */
> + bfd_vma p_offset; /* Segment file offset in octets */
> + bfd_vma p_vaddr; /* Segment virtual address in bytes */
> + bfd_vma p_paddr; /* Segment physical address in bytes */
> + bfd_vma p_filesz; /* Segment size in file in octets */
> + bfd_vma p_memsz; /* Segment size in memory in octets */
> bfd_vma p_align; /* Segment alignment, file & memory */
> };
>
> @@ -102,9 +102,10 @@ typedef struct elf_internal_shdr {
> unsigned int sh_name; /* Section name, index in string tbl */
> unsigned int sh_type; /* Type of section */
> bfd_vma sh_flags; /* Miscellaneous section attributes */
> - bfd_vma sh_addr; /* Section virtual addr at execution */
> - file_ptr sh_offset; /* Section file offset */
> - bfd_size_type sh_size; /* Size of section in bytes */
> + bfd_vma sh_addr; /* Section virtual addr at execution in
> + bytes */
> + file_ptr sh_offset; /* Section file offset in octets */
> + bfd_size_type sh_size; /* Size of section in octets */
> unsigned int sh_link; /* Index of another section */
> unsigned int sh_info; /* Additional section information */
> bfd_vma sh_addralign; /* Section alignment */
> @@ -318,7 +319,7 @@ struct elf_segment_map
> is also zero size. Regardless of STRICT and CHECK_VMA, zero size
> sections won't match at the start or end of PT_DYNAMIC nor PT_NOTE,
> unless PT_DYNAMIC and PT_NOTE are themselves zero sized. */
> -#define ELF_SECTION_IN_SEGMENT_1(sec_hdr, segment, check_vma, strict) \
> +#define ELF_SECTION_IN_SEGMENT_1(sec_hdr, segment, opb, check_vma, strict)
> \ ((/* Only PT_LOAD, PT_GNU_RELRO and PT_TLS segments can contain \
SHF_TLS
> sections. */ \
> ((((sec_hdr)->sh_flags & SHF_TLS) != 0) \
> @@ -354,9 +355,9 @@ struct elf_segment_map
>
> || ((sec_hdr)->sh_flags & SHF_ALLOC) == 0 \
> || ((sec_hdr)->sh_addr >= (segment)->p_vaddr \
>
> && (!(strict) \
> - || ((sec_hdr)->sh_addr - (segment)->p_vaddr \
> + || (((sec_hdr)->sh_addr - (segment)->p_vaddr) * (opb) \
> <= (segment)->p_memsz - 1)) \
> - && (((sec_hdr)->sh_addr - (segment)->p_vaddr \
> + && ((((sec_hdr)->sh_addr - (segment)->p_vaddr) * (opb) \
> + ELF_SECTION_SIZE(sec_hdr, segment)) \
> <= (segment)->p_memsz))) \
> /* No zero size sections at start or end of PT_DYNAMIC nor \
> @@ -371,13 +372,13 @@ struct elf_segment_map
> < (segment)->p_filesz))) \
> && (((sec_hdr)->sh_flags & SHF_ALLOC) == 0 \
>
> || ((sec_hdr)->sh_addr > (segment)->p_vaddr \
>
> - && ((sec_hdr)->sh_addr - (segment)->p_vaddr \
> + && (((sec_hdr)->sh_addr - (segment)->p_vaddr) * (opb)\
> < (segment)->p_memsz))))))
>
> -#define ELF_SECTION_IN_SEGMENT(sec_hdr, segment) \
> - (ELF_SECTION_IN_SEGMENT_1 (sec_hdr, segment, 1, 0))
> +#define ELF_SECTION_IN_SEGMENT(sec_hdr, segment, opb) \
> + (ELF_SECTION_IN_SEGMENT_1 (sec_hdr, segment, opb, 1, 0))
>
> -#define ELF_SECTION_IN_SEGMENT_STRICT(sec_hdr, segment) \
> - (ELF_SECTION_IN_SEGMENT_1 (sec_hdr, segment, 1, 1))
> +#define ELF_SECTION_IN_SEGMENT_STRICT(sec_hdr, segment, opb) \
> + (ELF_SECTION_IN_SEGMENT_1 (sec_hdr, segment, opb, 1, 1))
>
> #endif /* _ELF_INTERNAL_H */
> diff --git a/ld/ldexp.c b/ld/ldexp.c
> index b287022f5a1..9c599c2d470 100644
> --- a/ld/ldexp.c
> +++ b/ld/ldexp.c
> @@ -700,7 +700,8 @@ fold_name (etree_type *tree)
> /* Don't find the real header size if only marking sections;
> The bfd function may cache incorrect data. */
> if (expld.phase != lang_mark_phase_enum)
> - hdr_size = bfd_sizeof_headers (link_info.output_bfd, &link_info);
> + hdr_size = (bfd_sizeof_headers (link_info.output_bfd, &link_info)
> + / bfd_octets_per_byte (link_info.output_bfd, NULL));
> new_number (hdr_size);
> }
> break;
> --
> 2.16.4