[v2] Fix several mix up between octets and bytes in ELF program headers

Message ID 20191209084645.20775-1-ceggers@gmx.de
State Superseded
Headers show
Series
  • [v2] Fix several mix up between octets and bytes in ELF program headers
Related show

Commit Message

Christian Eggers Dec. 9, 2019, 8:46 a.m.
Alan Moda wrote:
> I'm wondering if you would be better off leaving all the values as

> octets when written to file.  There are things in the ELF spec, like

> p_offset mod pagesize == p_vaddr mod pagesize, that assume p_offset

> and p_vaddr have the same units.


in v2 I've "kept" p_paddr, p_vaddr and sh_addr as octets. Compared to
v1, the result is also ok for me. I had to disable one unit test for SDMA as
'objcopy --set-section-address .text=0x80000000' will overflow when
converting 0x80000000 (LMA, bytes) to sh_addr (octets).

---

When converting between addresses in ELF headers [octets] and bfd
LMA/VMA [bytes], the number of octets per byte needs to be incorperated.

In ld, the SIZEOF_HEADERS linker script statement must be resolved to
bytes instead of octets.

Patch changelog:
v2: Keep ELF header entries as octets.


include/
	* elf/internal.h (struct elf_internal_phdr): Add unit (octets)
	to several member field comments.
	(Elf_Internal_Shdr): likewise.

bfd/
	* elf.c (_bfd_elf_make_section_from_shdr): Introduce new temp
	opb. Divide Elf_Internal_Shdr::sh_addr by opb when setting
	section LMA/VMA.
	(_bfd_elf_make_section_from_phdr): Similarly.
	(elf_fake_sections): Fix calculation of
	Elf_Internal_shdr::sh_addr from section VMA.
	(_bfd_elf_map_sections_to_segments): Fix mixup between octets
	and bytes.
	(assign_file_positions_for_load_sections): Fix calculations of
	Elf_Internal_shdr::p_vaddr and p_paddr from section LMA/VMA. Fix
	comparison between program header address and section LMA.
	(assign_file_positions_for_non_load_sections): Likewise.
	(rewrite_elf_program_header): Likewise. Introduce new temp opb.
	(IS_CONTAINED_BY_VMA): Add parameter opb.
	(IS_CONTAINED_BY_LMA,IS_SECTION_IN_INPUT_SEGMENT,
	INCLUDE_SECTION_IN_SEGMENT): Likewise.
	(copy_elf_program_header): Update call to
	ELF_SECTION_IN_SEGMENT(). Fix calculations of p_addr_valid and
	p_vaddr_offset.
	* elf32-rx.c (OCTETS_PER_BYTE): Define.
	(rx_elf_object_p): Use OCTETS_PER_BYTE for calculating
	section LMA from program header addresses.
	* elf64-ia64-vms.c (OCTETS_PER_BYTE): Define.
	(elf64_vms_link_add_object_symbols): Use OCTETS_PER_BYTE for
	calculating section LMA from program header addresses.
	* elflink.c (elf_link_add_object_symbols): Multiply section VMA
	with octets per byte when comparing against p_vaddr.

ld/
	* ldexp.c (fold_name): Return SIZEOF_HEADERS in bytes.

Signed-off-by: Christian Eggers <ceggers@gmx.de>

---
 bfd/elf.c              | 131 ++++++++++++++++++++++++++++---------------------
 bfd/elf32-rx.c         |   8 ++-
 bfd/elf64-ia64-vms.c   |   7 ++-
 bfd/elflink.c          |  14 ++++--
 include/elf/internal.h |  19 +++----
 ld/ldexp.c             |   3 +-
 6 files changed, 108 insertions(+), 74 deletions(-)

--
2.16.4

Comments

Christian Eggers Dec. 17, 2019, 8:45 p.m. | #1
Hi Alan,

ping.... Seems you currently have some fun with ubsan.

regards
Christian


Am Montag, 9. Dezember 2019, 09:46:45 CET schrieb Christian Eggers:
> Alan Moda wrote:

> > I'm wondering if you would be better off leaving all the values as

> > octets when written to file.  There are things in the ELF spec, like

> > p_offset mod pagesize == p_vaddr mod pagesize, that assume p_offset

> > and p_vaddr have the same units.

>

> in v2 I've "kept" p_paddr, p_vaddr and sh_addr as octets. Compared to

> v1, the result is also ok for me. I had to disable one unit test for SDMA as

> 'objcopy --set-section-address .text=0x80000000' will overflow when

> converting 0x80000000 (LMA, bytes) to sh_addr (octets).

>

> ---

>

> When converting between addresses in ELF headers [octets] and bfd

> LMA/VMA [bytes], the number of octets per byte needs to be incorperated.

>

> In ld, the SIZEOF_HEADERS linker script statement must be resolved to

> bytes instead of octets.

>

> Patch changelog:

> v2: Keep ELF header entries as octets.

>

>

> include/

> 	* elf/internal.h (struct elf_internal_phdr): Add unit (octets)

> 	to several member field comments.

> 	(Elf_Internal_Shdr): likewise.

>

> bfd/

> 	* elf.c (_bfd_elf_make_section_from_shdr): Introduce new temp

> 	opb. Divide Elf_Internal_Shdr::sh_addr by opb when setting

> 	section LMA/VMA.

> 	(_bfd_elf_make_section_from_phdr): Similarly.

> 	(elf_fake_sections): Fix calculation of

> 	Elf_Internal_shdr::sh_addr from section VMA.

> 	(_bfd_elf_map_sections_to_segments): Fix mixup between octets

> 	and bytes.

> 	(assign_file_positions_for_load_sections): Fix calculations of

> 	Elf_Internal_shdr::p_vaddr and p_paddr from section LMA/VMA. Fix

> 	comparison between program header address and section LMA.

> 	(assign_file_positions_for_non_load_sections): Likewise.

> 	(rewrite_elf_program_header): Likewise. Introduce new temp opb.

> 	(IS_CONTAINED_BY_VMA): Add parameter opb.

> 	(IS_CONTAINED_BY_LMA,IS_SECTION_IN_INPUT_SEGMENT,

> 	INCLUDE_SECTION_IN_SEGMENT): Likewise.

> 	(copy_elf_program_header): Update call to

> 	ELF_SECTION_IN_SEGMENT(). Fix calculations of p_addr_valid and

> 	p_vaddr_offset.

> 	* elf32-rx.c (OCTETS_PER_BYTE): Define.

> 	(rx_elf_object_p): Use OCTETS_PER_BYTE for calculating

> 	section LMA from program header addresses.

> 	* elf64-ia64-vms.c (OCTETS_PER_BYTE): Define.

> 	(elf64_vms_link_add_object_symbols): Use OCTETS_PER_BYTE for

> 	calculating section LMA from program header addresses.

> 	* elflink.c (elf_link_add_object_symbols): Multiply section VMA

> 	with octets per byte when comparing against p_vaddr.

>

> ld/

> 	* ldexp.c (fold_name): Return SIZEOF_HEADERS in bytes.

>

> Signed-off-by: Christian Eggers <ceggers@gmx.de>

> ---

>  bfd/elf.c              | 131

> ++++++++++++++++++++++++++++--------------------- bfd/elf32-rx.c         |

>  8 ++-

>  bfd/elf64-ia64-vms.c   |   7 ++-

>  bfd/elflink.c          |  14 ++++--

>  include/elf/internal.h |  19 +++----

>  ld/ldexp.c             |   3 +-

>  6 files changed, 108 insertions(+), 74 deletions(-)

>

> diff --git a/bfd/elf.c b/bfd/elf.c

> index 1aa2603ee8c..d98cf9b8a51 100644

> --- a/bfd/elf.c

> +++ b/bfd/elf.c

> @@ -1028,6 +1028,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,

>    asection *newsect;

>    flagword flags;

>    const struct elf_backend_data *bed;

> +  unsigned int opb = bfd_octets_per_byte (abfd, NULL);

>

>    if (hdr->bfd_section != NULL)

>      return TRUE;

> @@ -1046,11 +1047,6 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,

>

>    newsect->filepos = hdr->sh_offset;

>

> -  if (!bfd_set_section_vma (newsect, hdr->sh_addr)

> -      || !bfd_set_section_size (newsect, hdr->sh_size)

> -      || !bfd_set_section_alignment (newsect, bfd_log2

> (hdr->sh_addralign))) -    return FALSE;

> -

>    flags = SEC_NO_FLAGS;

>    if (hdr->sh_type != SHT_NOBITS)

>      flags |= SEC_HAS_CONTENTS;

> @@ -1108,7 +1104,10 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,

>  	    flags |= SEC_DEBUGGING | SEC_ELF_OCTETS;

>  	  else if (strncmp (name, GNU_BUILD_ATTRS_SECTION_NAME, 21) == 0

>

>  		   || strncmp (name, ".note.gnu", 9) == 0)

>

> -	    flags |= SEC_ELF_OCTETS;

> +	    {

> +	      flags |= SEC_ELF_OCTETS;

> +	      opb = 1;

> +	    }

>  	  else if (strncmp (name, ".line", 5) == 0

>

>  		   || strncmp (name, ".stab", 5) == 0

>  		   || strcmp (name, ".gdb_index") == 0)

>

> @@ -1116,6 +1115,11 @@ _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))) +    return FALSE;

> +

>    /* As a GNU extension, if the name begins with .gnu.linkonce, we

>       only link a single copy of the section.  This is used to support

>       g++.  g++ will emit each template expansion in its own section.

> @@ -1177,7 +1181,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,

>  	    {

>  	      if ((flags & SEC_LOAD) == 0)

>  		newsect->lma = (phdr->p_paddr

> -				+ hdr->sh_addr - phdr->p_vaddr);

> +				+ hdr->sh_addr - phdr->p_vaddr) / opb;

>  	      else

>  		/* We used to use the same adjustment for SEC_LOAD

>  		   sections, but that doesn't work if the segment

> @@ -1187,7 +1191,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

> @@ -2970,6 +2974,7 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,

>    char namebuf[64];

>    size_t len;

>    int split;

> +  unsigned int opb = bfd_octets_per_byte (abfd, NULL);

>

>    split = ((hdr->p_memsz > 0)

>  	    && (hdr->p_filesz > 0)

> @@ -2986,8 +2991,8 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,

>        newsect = bfd_make_section (abfd, name);

>        if (newsect == NULL)

>  	return FALSE;

> -      newsect->vma = hdr->p_vaddr;

> -      newsect->lma = hdr->p_paddr;

> +      newsect->vma = hdr->p_vaddr / opb;

> +      newsect->lma = hdr->p_paddr / opb;

>        newsect->size = hdr->p_filesz;

>        newsect->filepos = hdr->p_offset;

>        newsect->flags |= SEC_HAS_CONTENTS;

> @@ -3022,8 +3027,8 @@ _bfd_elf_make_section_from_phdr (bfd *abfd,

>        newsect = bfd_make_section (abfd, name);

>        if (newsect == NULL)

>  	return FALSE;

> -      newsect->vma = hdr->p_vaddr + hdr->p_filesz;

> -      newsect->lma = hdr->p_paddr + hdr->p_filesz;

> +      newsect->vma = (hdr->p_vaddr + hdr->p_filesz) / opb;

> +      newsect->lma = (hdr->p_paddr + hdr->p_filesz) / opb;

>        newsect->size = hdr->p_memsz - hdr->p_filesz;

>        newsect->filepos = hdr->p_offset + hdr->p_filesz;

>        align = newsect->vma & -newsect->vma;

> @@ -3299,7 +3304,7 @@ elf_fake_sections (bfd *abfd, asection *asect, void

> *fsarg)

>

>    if ((asect->flags & SEC_ALLOC) != 0

>

>        || asect->user_set_vma)

>

> -    this_hdr->sh_addr = asect->vma;

> +    this_hdr->sh_addr = asect->vma * bfd_octets_per_byte (abfd, asect);

>    else

>      this_hdr->sh_addr = 0;

>

> @@ -4685,6 +4690,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 +4730,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 +4956,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 +4982,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 +5436,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 +5549,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;  /* octets */

>        bfd_boolean no_contents;

>

>        /* An ELF segment (described by Elf_Internal_Phdr) may contain a

> @@ -5554,16 +5563,16 @@ assign_file_positions_for_load_sections (bfd *abfd,

>        p->p_flags = m->p_flags;

>

>        if (m->count == 0)

> -	p->p_vaddr = m->p_vaddr_offset;

> +	p->p_vaddr = m->p_vaddr_offset * opb;

>        else

> -	p->p_vaddr = m->sections[0]->vma + m->p_vaddr_offset;

> +	p->p_vaddr = (m->sections[0]->vma + m->p_vaddr_offset) * opb;

>

>        if (m->p_paddr_valid)

>  	p->p_paddr = m->p_paddr;

>        else if (m->count == 0)

>  	p->p_paddr = 0;

>        else

> -	p->p_paddr = m->sections[0]->lma + m->p_vaddr_offset;

> +	p->p_paddr = (m->sections[0]->lma + m->p_vaddr_offset) * opb;

>

>        if (p->p_type == PT_LOAD

>  	  && (abfd->flags & D_PAGED) != 0)

> @@ -5644,7 +5653,8 @@ assign_file_positions_for_load_sections (bfd *abfd,

>  	      && (abfd->flags & D_PAGED) != 0

>  	      && bed->no_page_alias

>  	      && (off & (maxpagesize - 1)) != 0

> -	      && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))

> +	      && ((off & -maxpagesize)

> +		  == ((off + off_adjust) & -maxpagesize)))

>  	    off_adjust += maxpagesize;

>  	  off += off_adjust;

>  	  if (no_contents)

> @@ -5735,7 +5745,7 @@ assign_file_positions_for_load_sections (bfd *abfd,

>  	      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;

> @@ -5755,7 +5765,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 +5796,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;                /* octets */

> +	      bfd_vma p_end = p_start + p->p_memsz;        /* octets */

> +	      bfd_vma s_start = sec->lma * opb;            /* octets */

> +	      bfd_vma adjust = s_start - p_end;            /* octets */

>

>  	      if (adjust != 0

>  		  && (s_start < p_end

> @@ -5798,9 +5808,10 @@ assign_file_positions_for_load_sections (bfd *abfd,

>  		  _bfd_error_handler

>  		    /* xgettext:c-format */

>  		    (_("%pB: section %pA lma %#" PRIx64 " adjusted to %#" PRIx64),

> -		     abfd, sec, (uint64_t) s_start, (uint64_t) p_end);

> +		     abfd, sec, (uint64_t) s_start / opb,

> +		     (uint64_t) p_end / opb);

>  		  adjust = 0;

> -		  sec->lma = p_end;

> +		  sec->lma = p_end / opb;

>  		}

>  	      p->p_memsz += adjust;

>

> @@ -6186,8 +6197,11 @@ assign_file_positions_for_non_load_sections (bfd

> *abfd,

>

>  		  if (i < lm->count)

>  		    {

> -		      p->p_vaddr = lm->sections[i]->vma;

> -		      p->p_paddr = lm->sections[i]->lma;

> +		      unsigned int opb = bfd_octets_per_byte (abfd,

> +							      lm->sections[i]);

> +

> +		      p->p_vaddr = lm->sections[i]->vma * opb;

> +		      p->p_paddr = lm->sections[i]->lma * opb;

>  		      p->p_offset = lm->sections[i]->filepos;

>  		      p->p_memsz = end - p->p_vaddr;

>  		      p->p_filesz = p->p_memsz;

> @@ -6786,6 +6800,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>    struct elf_segment_map *phdr_adjust_seg = NULL;

>    unsigned int phdr_adjust_num = 0;

>    const struct elf_backend_data *bed;

> +  unsigned int opb = bfd_octets_per_byte (ibfd, NULL);

>

>    bed = get_elf_backend_data (ibfd);

>    iehdr = elf_elfheader (ibfd);

> @@ -6808,17 +6823,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>

>    /* Returns TRUE if the given section is contained within

>       the given segment.  VMA addresses are compared.  */

> -#define IS_CONTAINED_BY_VMA(section, segment)				\

> -  (section->vma >= segment->p_vaddr					\

> -   && (section->vma + SECTION_SIZE (section, segment)			\

> +#define IS_CONTAINED_BY_VMA(section, segment, opb)			\

> +  (section->vma * (opb) >= segment->p_vaddr				\

> +   && (section->vma * (opb) + SECTION_SIZE (section, segment)		\

>         <= (SEGMENT_END (segment, segment->p_vaddr))))

>

>    /* Returns TRUE if the given section is contained within

>       the given segment.  LMA addresses are compared.  */

> -#define IS_CONTAINED_BY_LMA(section, segment, base)			\

> -  (section->lma >= base							\

> -   && (section->lma + SECTION_SIZE (section, segment) >= section->lma)	\

> -   && (section->lma + SECTION_SIZE (section, segment)			\

> +#define IS_CONTAINED_BY_LMA(section, segment, base, opb)		\

> +  (section->lma * (opb) >= base						\

> +   && (section->lma * (opb) + SECTION_SIZE (section, segment) >=

> section->lma) \ +   && (section->lma * (opb) + SECTION_SIZE (section,

> segment)		\

>         <= SEGMENT_END (segment, base)))

>

>    /* Handle PT_NOTE segment.  */

> @@ -6864,10 +6879,10 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>         7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.

>         8. PT_DYNAMIC should not contain empty sections at the beginning

>  	  (with the possible exception of .dynamic).  */

> -#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed)		\

> +#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb)		\

>    ((((segment->p_paddr							\

> -      ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)	\

> -      : IS_CONTAINED_BY_VMA (section, segment))				\

> +      ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb)	\

> +      : IS_CONTAINED_BY_VMA (section, segment, opb))			\

>       && (section->flags & SEC_ALLOC) != 0)				\

>

>      || IS_NOTE (segment, section))					\

>

>     && segment->p_type != PT_GNU_STACK					\

> @@ -6879,15 +6894,15 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>     && (segment->p_type != PT_DYNAMIC					\

>

>         || SECTION_SIZE (section, segment) > 0				\

>         || (segment->p_paddr						\

>

> -	   ? segment->p_paddr != section->lma				\

> -	   : segment->p_vaddr != section->vma)				\

> +	   ? segment->p_paddr != section->lma * (opb)			\

> +	   : segment->p_vaddr != section->vma * (opb))			\

>

>         || (strcmp (bfd_section_name (section), ".dynamic") == 0))	\

>

>     && (segment->p_type != PT_LOAD || !section->segment_mark))

>

>  /* If the output section of a section in the input segment is NULL,

>     it is removed from the corresponding output segment.   */

> -#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)		\

> -  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)		\

> +#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed, opb)		\

> +  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb)		\

>     && section->output_section != NULL)

>

>    /* Returns TRUE iff seg1 starts after the end of seg2.  */

> @@ -6941,7 +6956,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>  	    {

>  	      /* Mininal change so that the normal section to segment

>  		 assignment code will work.  */

> -	      segment->p_vaddr = section->vma;

> +	      segment->p_vaddr = section->vma * opb;

>  	      break;

>  	    }

>

> @@ -7027,7 +7042,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>  	{

>  	  /* Find the first section in the input segment, which may be

>  	     removed from the corresponding output segment.   */

> -	  if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed))

> +	  if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb))

>  	    {

>  	      if (first_section == NULL)

>  		first_section = section;

> @@ -7095,7 +7110,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>  		 " at vaddr=%#" PRIx64 ", is this intentional?"),

>  	       ibfd, (uint64_t) segment->p_vaddr);

>

> -	  map->p_vaddr_offset = segment->p_vaddr;

> +	  map->p_vaddr_offset = segment->p_vaddr / opb;

>  	  map->count = 0;

>  	  *pointer_to_map = map;

>  	  pointer_to_map = &map->next;

> @@ -7149,7 +7164,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>  	   section != NULL;

>  	   section = section->next)

>  	{

> -	  if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))

> +	  if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed, opb))

>  	    {

>  	      output_section = section->output_section;

>

> @@ -7176,10 +7191,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>

>  	      /* Match up the physical address of the segment with the

>  		 LMA address of the output section.  */

> -	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)

> +	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,

> +				       opb)

>

>  		  || IS_COREFILE_NOTE (segment, section)

>  		  || (bed->want_p_paddr_set_to_zero

>

> -		      && IS_CONTAINED_BY_VMA (output_section, segment)))

> +		      && IS_CONTAINED_BY_VMA (output_section, segment, opb)))

>  		{

>  		  if (matching_lma == NULL

>

>  		      || output_section->lma < matching_lma->lma)

>

> @@ -7223,7 +7239,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>

>  	      /* Account for padding before the first section in the

>  		 segment.  */

> -	      map->p_vaddr_offset = map->p_paddr + hdr_size - matching_lma->lma;

> +	      map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb

> +				     - matching_lma->lma);

>  	    }

>

>  	  free (sections);

> @@ -7294,7 +7311,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

>

>  	      BFD_ASSERT (output_section != NULL);

>

> -	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)

> +	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,

> +				       opb)

>

>  		  || IS_COREFILE_NOTE (segment, section))

>

>  		{

>  		  if (map->count == 0)

> @@ -7445,6 +7463,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);

>

> @@ -7570,7 +7589,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)

>  			seg_off = this_hdr->sh_offset - segment->p_offset;

>  		      else

>  			seg_off = this_hdr->sh_addr - segment->p_vaddr;

> -		      if (section->lma - segment->p_paddr != seg_off)

> +		      if (section->lma * opb - segment->p_paddr != seg_off)

>  			map->p_paddr_valid = FALSE;

>  		    }

>  		  if (isec == section_count)

> @@ -7580,7 +7599,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)

>  	}

>

>        if (section_count == 0)

> -	map->p_vaddr_offset = segment->p_vaddr;

> +	map->p_vaddr_offset = segment->p_vaddr / opb;

>        else if (map->p_paddr_valid)

>  	{

>  	  /* Account for padding before the first section in the segment.  */

> @@ -7590,7 +7609,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)

>  	  if (map->includes_phdrs)

>  	    hdr_size += iehdr->e_phnum * iehdr->e_phentsize;

>

> -	  map->p_vaddr_offset = (map->p_paddr + hdr_size

> +	  map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb

>  				 - (lowest_section ? lowest_section->lma : 0));

>  	}

>

> diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c

> index a1a5ce11be1..1524a05cc50 100644

> --- a/bfd/elf32-rx.c

> +++ b/bfd/elf32-rx.c

> @@ -26,6 +26,9 @@

>  #include "libiberty.h"

>  #include "elf32-rx.h"

>

> +/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */

> +#define OCTETS_PER_BYTE(ABFD, SEC) 1

> +

>  #define RX_OPCODE_BIG_ENDIAN 0

>

>  /* This is a meta-target that's used only with objcopy, to avoid the

> @@ -3306,7 +3309,10 @@ rx_elf_object_p (bfd * abfd)

>  	      && phdr[i].p_vaddr <= bsec->vma

>  	      && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1))

>  	    {

> -	      bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr);

> +	      bsec->lma = (phdr[i].p_paddr / OCTETS_PER_BYTE (abfd, bsec)

> +			   + (bsec->vma

> +			      - (phdr[i].p_vaddr

> +				 / OCTETS_PER_BYTE (abfd, bsec))));

>  	    }

>  	  bsec = bsec->next;

>  	}

> diff --git a/bfd/elf64-ia64-vms.c b/bfd/elf64-ia64-vms.c

> index d0cb7e08e10..6a3bd793a3d 100644

> --- a/bfd/elf64-ia64-vms.c

> +++ b/bfd/elf64-ia64-vms.c

> @@ -30,6 +30,9 @@

>  #include "vms.h"

>  #include "bfdver.h"

>

> +/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */

> +#define OCTETS_PER_BYTE(ABFD, SEC) 1

> +

>  /* THE RULES for all the stuff the linker creates --

>

>    GOT		Entries created in response to LTOFF or LTOFF_FPTR

> @@ -4833,8 +4836,8 @@ elf64_vms_link_add_object_symbols (bfd *abfd, struct

> bfd_link_info *info) s = bfd_make_section (abfd, ".dynamic");

>  		if (s == NULL)

>  		  goto error_return;

> -		s->vma = phdr->p_vaddr;

> -		s->lma = phdr->p_paddr;

> +		s->vma = phdr->p_vaddr / OCTETS_PER_BYTE (abfd, s);

> +		s->lma = phdr->p_paddr / OCTETS_PER_BYTE (abfd, s);

>  		s->size = phdr->p_filesz;

>  		s->filepos = phdr->p_offset;

>  		s->flags |= SEC_HAS_CONTENTS;

> diff --git a/bfd/elflink.c b/bfd/elflink.c

> index 7078a2fb6f4..e09ab908b60 100644

> --- a/bfd/elflink.c

> +++ b/bfd/elflink.c

> @@ -4227,11 +4227,15 @@ error_free_dyn:

>  	if (phdr->p_type == PT_GNU_RELRO)

>  	  {

>  	    for (s = abfd->sections; s != NULL; s = s->next)

> -	      if ((s->flags & SEC_ALLOC) != 0

> -		  && s->vma >= phdr->p_vaddr

> -		  && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz)

> -		s->flags |= SEC_READONLY;

> -	    break;

> +	      {

> +		unsigned int opb = bfd_octets_per_byte (abfd, s);

> +

> +		if ((s->flags & SEC_ALLOC) != 0

> +		    && s->vma * opb >= phdr->p_vaddr

> +		    && s->vma * opb + s->size <= phdr->p_vaddr + phdr->p_memsz)

> +		  s->flags |= SEC_READONLY;

> +		break;

> +	      }

>  	  }

>

>        /* We do not want to include any of the sections in a dynamic

> diff --git a/include/elf/internal.h b/include/elf/internal.h

> index 794c16812ee..4ede98aa54d 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 octets */

> +  bfd_vma	p_paddr;		/* Segment physical address in octets */

> +  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

> +					   octets */

> +  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 */

> @@ -267,7 +268,7 @@ struct elf_segment_map

>    unsigned long p_flags;

>    /* Program segment physical address.  */

>    bfd_vma p_paddr;

> -  /* Program segment virtual address offset from section vma.  */

> +  /* Program segment virtual address offset from section vma in bytes.  */

>    bfd_vma p_vaddr_offset;

>    /* Program segment alignment.  */

>    bfd_vma p_align;

> 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
Alan Modra Dec. 18, 2019, 2:12 a.m. | #2
On Tue, Dec 17, 2019 at 09:45:32PM +0100, Christian Eggers wrote:
Overall this is looking good, and I think your decision to make the
internal units for p_vaddr, p_paddr and sh_addr octets has worked out
well.

But it looks like you have missed a few places that need an octet per
byte factor.  eg. elf.c search for filehdr_vaddr.  Symbol values for
an address are in bytes, at least internally.  There's another one at
around line 7190 of elf.c where we have a comparison of an expression
involving p_vaddr and a section vma.  That one raises the question of
what to do with alignment.  Presumably, section->alignment_power stays
in bytes since it is most often used with section->vma.  So that's
another thing that needs converting if used to align p_vaddr/p_paddr.

Also elfcode.h bfd_from_remote_memory uses p_vaddr without converting
to bytes.

Also search for phdr_lma in elf.c.  IS_CONTAINED_BY_LMA needs a fix
too, and this in elf.c "map->p_paddr = matching_lma->lma" and the
alignment a little later.

You also need to correct code in bfd_elf_final_link using sh_addr when
setting up DT_REL/DT_RELA.  There's a comparison between sh_addr and
vma.

The following in elf32-rx.c where octets per byte is always one (and
thus the file needs no change) is bogus, please remove, and the change
to elf64-ia64-vms.c too:

> > --- a/bfd/elf32-rx.c

> > +++ b/bfd/elf32-rx.c

> > @@ -26,6 +26,9 @@

> >  #include "libiberty.h"

> >  #include "elf32-rx.h"

> >

> > +/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */

> > +#define OCTETS_PER_BYTE(ABFD, SEC) 1

> > +

> >  #define RX_OPCODE_BIG_ENDIAN 0

> >

> >  /* This is a meta-target that's used only with objcopy, to avoid the

> > @@ -3306,7 +3309,10 @@ rx_elf_object_p (bfd * abfd)

> >  	      && phdr[i].p_vaddr <= bsec->vma

> >  	      && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1))


If you're worrying about about the units of p_vaddr and p_paddr in
this file by introducing OCTETS_PER_BYTE, then the above two lines
need a conversion too, and other places in the file.

> >  	    {

> > -	      bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr);

> > +	      bsec->lma = (phdr[i].p_paddr / OCTETS_PER_BYTE (abfd, bsec)

> > +			   + (bsec->vma

> > +			      - (phdr[i].p_vaddr

> > +				 / OCTETS_PER_BYTE (abfd, bsec))));

> >  	    }

> >  	  bsec = bsec->next;

> >  	}


I'm also wondering about relocations, symbols and dynamic tags with
address values.  Does r_offset specify bytes or octets in the ELF
file?  If octets, then do we convert in elf_swap_reloca_in/out making
internal r_offset in bytes which should be most convenient since it is
often used with section vma?  How about r_addend and st_value?
Anyway, those can be left for a later patch if necessary.

-- 
Alan Modra
Australia Development Lab, IBM

Patch

diff --git a/bfd/elf.c b/bfd/elf.c
index 1aa2603ee8c..d98cf9b8a51 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1028,6 +1028,7 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,
   asection *newsect;
   flagword flags;
   const struct elf_backend_data *bed;
+  unsigned int opb = bfd_octets_per_byte (abfd, NULL);

   if (hdr->bfd_section != NULL)
     return TRUE;
@@ -1046,11 +1047,6 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,

   newsect->filepos = hdr->sh_offset;

-  if (!bfd_set_section_vma (newsect, hdr->sh_addr)
-      || !bfd_set_section_size (newsect, hdr->sh_size)
-      || !bfd_set_section_alignment (newsect, bfd_log2 (hdr->sh_addralign)))
-    return FALSE;
-
   flags = SEC_NO_FLAGS;
   if (hdr->sh_type != SHT_NOBITS)
     flags |= SEC_HAS_CONTENTS;
@@ -1108,7 +1104,10 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,
 	    flags |= SEC_DEBUGGING | SEC_ELF_OCTETS;
 	  else if (strncmp (name, GNU_BUILD_ATTRS_SECTION_NAME, 21) == 0
 		   || strncmp (name, ".note.gnu", 9) == 0)
-	    flags |= SEC_ELF_OCTETS;
+	    {
+	      flags |= SEC_ELF_OCTETS;
+	      opb = 1;
+	    }
 	  else if (strncmp (name, ".line", 5) == 0
 		   || strncmp (name, ".stab", 5) == 0
 		   || strcmp (name, ".gdb_index") == 0)
@@ -1116,6 +1115,11 @@  _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)))
+    return FALSE;
+
   /* As a GNU extension, if the name begins with .gnu.linkonce, we
      only link a single copy of the section.  This is used to support
      g++.  g++ will emit each template expansion in its own section.
@@ -1177,7 +1181,7 @@  _bfd_elf_make_section_from_shdr (bfd *abfd,
 	    {
 	      if ((flags & SEC_LOAD) == 0)
 		newsect->lma = (phdr->p_paddr
-				+ hdr->sh_addr - phdr->p_vaddr);
+				+ hdr->sh_addr - phdr->p_vaddr) / opb;
 	      else
 		/* We used to use the same adjustment for SEC_LOAD
 		   sections, but that doesn't work if the segment
@@ -1187,7 +1191,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
@@ -2970,6 +2974,7 @@  _bfd_elf_make_section_from_phdr (bfd *abfd,
   char namebuf[64];
   size_t len;
   int split;
+  unsigned int opb = bfd_octets_per_byte (abfd, NULL);

   split = ((hdr->p_memsz > 0)
 	    && (hdr->p_filesz > 0)
@@ -2986,8 +2991,8 @@  _bfd_elf_make_section_from_phdr (bfd *abfd,
       newsect = bfd_make_section (abfd, name);
       if (newsect == NULL)
 	return FALSE;
-      newsect->vma = hdr->p_vaddr;
-      newsect->lma = hdr->p_paddr;
+      newsect->vma = hdr->p_vaddr / opb;
+      newsect->lma = hdr->p_paddr / opb;
       newsect->size = hdr->p_filesz;
       newsect->filepos = hdr->p_offset;
       newsect->flags |= SEC_HAS_CONTENTS;
@@ -3022,8 +3027,8 @@  _bfd_elf_make_section_from_phdr (bfd *abfd,
       newsect = bfd_make_section (abfd, name);
       if (newsect == NULL)
 	return FALSE;
-      newsect->vma = hdr->p_vaddr + hdr->p_filesz;
-      newsect->lma = hdr->p_paddr + hdr->p_filesz;
+      newsect->vma = (hdr->p_vaddr + hdr->p_filesz) / opb;
+      newsect->lma = (hdr->p_paddr + hdr->p_filesz) / opb;
       newsect->size = hdr->p_memsz - hdr->p_filesz;
       newsect->filepos = hdr->p_offset + hdr->p_filesz;
       align = newsect->vma & -newsect->vma;
@@ -3299,7 +3304,7 @@  elf_fake_sections (bfd *abfd, asection *asect, void *fsarg)

   if ((asect->flags & SEC_ALLOC) != 0
       || asect->user_set_vma)
-    this_hdr->sh_addr = asect->vma;
+    this_hdr->sh_addr = asect->vma * bfd_octets_per_byte (abfd, asect);
   else
     this_hdr->sh_addr = 0;

@@ -4685,6 +4690,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 +4730,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 +4956,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 +4982,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 +5436,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 +5549,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;  /* octets */
       bfd_boolean no_contents;

       /* An ELF segment (described by Elf_Internal_Phdr) may contain a
@@ -5554,16 +5563,16 @@  assign_file_positions_for_load_sections (bfd *abfd,
       p->p_flags = m->p_flags;

       if (m->count == 0)
-	p->p_vaddr = m->p_vaddr_offset;
+	p->p_vaddr = m->p_vaddr_offset * opb;
       else
-	p->p_vaddr = m->sections[0]->vma + m->p_vaddr_offset;
+	p->p_vaddr = (m->sections[0]->vma + m->p_vaddr_offset) * opb;

       if (m->p_paddr_valid)
 	p->p_paddr = m->p_paddr;
       else if (m->count == 0)
 	p->p_paddr = 0;
       else
-	p->p_paddr = m->sections[0]->lma + m->p_vaddr_offset;
+	p->p_paddr = (m->sections[0]->lma + m->p_vaddr_offset) * opb;

       if (p->p_type == PT_LOAD
 	  && (abfd->flags & D_PAGED) != 0)
@@ -5644,7 +5653,8 @@  assign_file_positions_for_load_sections (bfd *abfd,
 	      && (abfd->flags & D_PAGED) != 0
 	      && bed->no_page_alias
 	      && (off & (maxpagesize - 1)) != 0
-	      && (off & -maxpagesize) == ((off + off_adjust) & -maxpagesize))
+	      && ((off & -maxpagesize)
+		  == ((off + off_adjust) & -maxpagesize)))
 	    off_adjust += maxpagesize;
 	  off += off_adjust;
 	  if (no_contents)
@@ -5735,7 +5745,7 @@  assign_file_positions_for_load_sections (bfd *abfd,
 	      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;
@@ -5755,7 +5765,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 +5796,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;                /* octets */
+	      bfd_vma p_end = p_start + p->p_memsz;        /* octets */
+	      bfd_vma s_start = sec->lma * opb;            /* octets */
+	      bfd_vma adjust = s_start - p_end;            /* octets */

 	      if (adjust != 0
 		  && (s_start < p_end
@@ -5798,9 +5808,10 @@  assign_file_positions_for_load_sections (bfd *abfd,
 		  _bfd_error_handler
 		    /* xgettext:c-format */
 		    (_("%pB: section %pA lma %#" PRIx64 " adjusted to %#" PRIx64),
-		     abfd, sec, (uint64_t) s_start, (uint64_t) p_end);
+		     abfd, sec, (uint64_t) s_start / opb,
+		     (uint64_t) p_end / opb);
 		  adjust = 0;
-		  sec->lma = p_end;
+		  sec->lma = p_end / opb;
 		}
 	      p->p_memsz += adjust;

@@ -6186,8 +6197,11 @@  assign_file_positions_for_non_load_sections (bfd *abfd,

 		  if (i < lm->count)
 		    {
-		      p->p_vaddr = lm->sections[i]->vma;
-		      p->p_paddr = lm->sections[i]->lma;
+		      unsigned int opb = bfd_octets_per_byte (abfd,
+							      lm->sections[i]);
+
+		      p->p_vaddr = lm->sections[i]->vma * opb;
+		      p->p_paddr = lm->sections[i]->lma * opb;
 		      p->p_offset = lm->sections[i]->filepos;
 		      p->p_memsz = end - p->p_vaddr;
 		      p->p_filesz = p->p_memsz;
@@ -6786,6 +6800,7 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
   struct elf_segment_map *phdr_adjust_seg = NULL;
   unsigned int phdr_adjust_num = 0;
   const struct elf_backend_data *bed;
+  unsigned int opb = bfd_octets_per_byte (ibfd, NULL);

   bed = get_elf_backend_data (ibfd);
   iehdr = elf_elfheader (ibfd);
@@ -6808,17 +6823,17 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

   /* Returns TRUE if the given section is contained within
      the given segment.  VMA addresses are compared.  */
-#define IS_CONTAINED_BY_VMA(section, segment)				\
-  (section->vma >= segment->p_vaddr					\
-   && (section->vma + SECTION_SIZE (section, segment)			\
+#define IS_CONTAINED_BY_VMA(section, segment, opb)			\
+  (section->vma * (opb) >= segment->p_vaddr				\
+   && (section->vma * (opb) + SECTION_SIZE (section, segment)		\
        <= (SEGMENT_END (segment, segment->p_vaddr))))

   /* Returns TRUE if the given section is contained within
      the given segment.  LMA addresses are compared.  */
-#define IS_CONTAINED_BY_LMA(section, segment, base)			\
-  (section->lma >= base							\
-   && (section->lma + SECTION_SIZE (section, segment) >= section->lma)	\
-   && (section->lma + SECTION_SIZE (section, segment)			\
+#define IS_CONTAINED_BY_LMA(section, segment, base, opb)		\
+  (section->lma * (opb) >= base						\
+   && (section->lma * (opb) + SECTION_SIZE (section, segment) >= section->lma) \
+   && (section->lma * (opb) + SECTION_SIZE (section, segment)		\
        <= SEGMENT_END (segment, base)))

   /* Handle PT_NOTE segment.  */
@@ -6864,10 +6879,10 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
        7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments.
        8. PT_DYNAMIC should not contain empty sections at the beginning
 	  (with the possible exception of .dynamic).  */
-#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed)		\
+#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed, opb)		\
   ((((segment->p_paddr							\
-      ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr)	\
-      : IS_CONTAINED_BY_VMA (section, segment))				\
+      ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr, opb)	\
+      : IS_CONTAINED_BY_VMA (section, segment, opb))			\
      && (section->flags & SEC_ALLOC) != 0)				\
     || IS_NOTE (segment, section))					\
    && segment->p_type != PT_GNU_STACK					\
@@ -6879,15 +6894,15 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
    && (segment->p_type != PT_DYNAMIC					\
        || SECTION_SIZE (section, segment) > 0				\
        || (segment->p_paddr						\
-	   ? segment->p_paddr != section->lma				\
-	   : segment->p_vaddr != section->vma)				\
+	   ? segment->p_paddr != section->lma * (opb)			\
+	   : segment->p_vaddr != section->vma * (opb))			\
        || (strcmp (bfd_section_name (section), ".dynamic") == 0))	\
    && (segment->p_type != PT_LOAD || !section->segment_mark))

 /* If the output section of a section in the input segment is NULL,
    it is removed from the corresponding output segment.   */
-#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed)		\
-  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)		\
+#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed, opb)		\
+  (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb)		\
    && section->output_section != NULL)

   /* Returns TRUE iff seg1 starts after the end of seg2.  */
@@ -6941,7 +6956,7 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 	    {
 	      /* Mininal change so that the normal section to segment
 		 assignment code will work.  */
-	      segment->p_vaddr = section->vma;
+	      segment->p_vaddr = section->vma * opb;
 	      break;
 	    }

@@ -7027,7 +7042,7 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 	{
 	  /* Find the first section in the input segment, which may be
 	     removed from the corresponding output segment.   */
-	  if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed))
+	  if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed, opb))
 	    {
 	      if (first_section == NULL)
 		first_section = section;
@@ -7095,7 +7110,7 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 		 " at vaddr=%#" PRIx64 ", is this intentional?"),
 	       ibfd, (uint64_t) segment->p_vaddr);

-	  map->p_vaddr_offset = segment->p_vaddr;
+	  map->p_vaddr_offset = segment->p_vaddr / opb;
 	  map->count = 0;
 	  *pointer_to_map = map;
 	  pointer_to_map = &map->next;
@@ -7149,7 +7164,7 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 	   section != NULL;
 	   section = section->next)
 	{
-	  if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed))
+	  if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed, opb))
 	    {
 	      output_section = section->output_section;

@@ -7176,10 +7191,11 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

 	      /* Match up the physical address of the segment with the
 		 LMA address of the output section.  */
-	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
+	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
+				       opb)
 		  || IS_COREFILE_NOTE (segment, section)
 		  || (bed->want_p_paddr_set_to_zero
-		      && IS_CONTAINED_BY_VMA (output_section, segment)))
+		      && IS_CONTAINED_BY_VMA (output_section, segment, opb)))
 		{
 		  if (matching_lma == NULL
 		      || output_section->lma < matching_lma->lma)
@@ -7223,7 +7239,8 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

 	      /* Account for padding before the first section in the
 		 segment.  */
-	      map->p_vaddr_offset = map->p_paddr + hdr_size - matching_lma->lma;
+	      map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
+				     - matching_lma->lma);
 	    }

 	  free (sections);
@@ -7294,7 +7311,8 @@  rewrite_elf_program_header (bfd *ibfd, bfd *obfd)

 	      BFD_ASSERT (output_section != NULL);

-	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr)
+	      if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr,
+				       opb)
 		  || IS_COREFILE_NOTE (segment, section))
 		{
 		  if (map->count == 0)
@@ -7445,6 +7463,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);

@@ -7570,7 +7589,7 @@  copy_elf_program_header (bfd *ibfd, bfd *obfd)
 			seg_off = this_hdr->sh_offset - segment->p_offset;
 		      else
 			seg_off = this_hdr->sh_addr - segment->p_vaddr;
-		      if (section->lma - segment->p_paddr != seg_off)
+		      if (section->lma * opb - segment->p_paddr != seg_off)
 			map->p_paddr_valid = FALSE;
 		    }
 		  if (isec == section_count)
@@ -7580,7 +7599,7 @@  copy_elf_program_header (bfd *ibfd, bfd *obfd)
 	}

       if (section_count == 0)
-	map->p_vaddr_offset = segment->p_vaddr;
+	map->p_vaddr_offset = segment->p_vaddr / opb;
       else if (map->p_paddr_valid)
 	{
 	  /* Account for padding before the first section in the segment.  */
@@ -7590,7 +7609,7 @@  copy_elf_program_header (bfd *ibfd, bfd *obfd)
 	  if (map->includes_phdrs)
 	    hdr_size += iehdr->e_phnum * iehdr->e_phentsize;

-	  map->p_vaddr_offset = (map->p_paddr + hdr_size
+	  map->p_vaddr_offset = ((map->p_paddr + hdr_size) / opb
 				 - (lowest_section ? lowest_section->lma : 0));
 	}

diff --git a/bfd/elf32-rx.c b/bfd/elf32-rx.c
index a1a5ce11be1..1524a05cc50 100644
--- a/bfd/elf32-rx.c
+++ b/bfd/elf32-rx.c
@@ -26,6 +26,9 @@ 
 #include "libiberty.h"
 #include "elf32-rx.h"

+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
 #define RX_OPCODE_BIG_ENDIAN 0

 /* This is a meta-target that's used only with objcopy, to avoid the
@@ -3306,7 +3309,10 @@  rx_elf_object_p (bfd * abfd)
 	      && phdr[i].p_vaddr <= bsec->vma
 	      && bsec->vma <= phdr[i].p_vaddr + (phdr[i].p_filesz - 1))
 	    {
-	      bsec->lma = phdr[i].p_paddr + (bsec->vma - phdr[i].p_vaddr);
+	      bsec->lma = (phdr[i].p_paddr / OCTETS_PER_BYTE (abfd, bsec)
+			   + (bsec->vma
+			      - (phdr[i].p_vaddr
+				 / OCTETS_PER_BYTE (abfd, bsec))));
 	    }
 	  bsec = bsec->next;
 	}
diff --git a/bfd/elf64-ia64-vms.c b/bfd/elf64-ia64-vms.c
index d0cb7e08e10..6a3bd793a3d 100644
--- a/bfd/elf64-ia64-vms.c
+++ b/bfd/elf64-ia64-vms.c
@@ -30,6 +30,9 @@ 
 #include "vms.h"
 #include "bfdver.h"

+/* All users of this file have bfd_octets_per_byte (abfd, sec) == 1.  */
+#define OCTETS_PER_BYTE(ABFD, SEC) 1
+
 /* THE RULES for all the stuff the linker creates --

   GOT		Entries created in response to LTOFF or LTOFF_FPTR
@@ -4833,8 +4836,8 @@  elf64_vms_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 		s = bfd_make_section (abfd, ".dynamic");
 		if (s == NULL)
 		  goto error_return;
-		s->vma = phdr->p_vaddr;
-		s->lma = phdr->p_paddr;
+		s->vma = phdr->p_vaddr / OCTETS_PER_BYTE (abfd, s);
+		s->lma = phdr->p_paddr / OCTETS_PER_BYTE (abfd, s);
 		s->size = phdr->p_filesz;
 		s->filepos = phdr->p_offset;
 		s->flags |= SEC_HAS_CONTENTS;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 7078a2fb6f4..e09ab908b60 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -4227,11 +4227,15 @@  error_free_dyn:
 	if (phdr->p_type == PT_GNU_RELRO)
 	  {
 	    for (s = abfd->sections; s != NULL; s = s->next)
-	      if ((s->flags & SEC_ALLOC) != 0
-		  && s->vma >= phdr->p_vaddr
-		  && s->vma + s->size <= phdr->p_vaddr + phdr->p_memsz)
-		s->flags |= SEC_READONLY;
-	    break;
+	      {
+		unsigned int opb = bfd_octets_per_byte (abfd, s);
+
+		if ((s->flags & SEC_ALLOC) != 0
+		    && s->vma * opb >= phdr->p_vaddr
+		    && s->vma * opb + s->size <= phdr->p_vaddr + phdr->p_memsz)
+		  s->flags |= SEC_READONLY;
+		break;
+	      }
 	  }

       /* We do not want to include any of the sections in a dynamic
diff --git a/include/elf/internal.h b/include/elf/internal.h
index 794c16812ee..4ede98aa54d 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 octets */
+  bfd_vma	p_paddr;		/* Segment physical address in octets */
+  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
+					   octets */
+  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 */
@@ -267,7 +268,7 @@  struct elf_segment_map
   unsigned long p_flags;
   /* Program segment physical address.  */
   bfd_vma p_paddr;
-  /* Program segment virtual address offset from section vma.  */
+  /* Program segment virtual address offset from section vma in bytes.  */
   bfd_vma p_vaddr_offset;
   /* Program segment alignment.  */
   bfd_vma p_align;
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;