Use p_vaddr_offset to set p_vaddr on segments without sections
authorAlan Modra <amodra@gmail.com>
Sat, 6 Oct 2018 02:54:28 +0000 (12:24 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 8 Oct 2018 09:56:08 +0000 (20:26 +1030)
p_vaddr is currently set from the first section vma if a segment has
sections, and to zero if a segment has no sections.  This means we
lose p_vaddr when objcopy'ing executables if a segment without
sections has a non-zero p_vaddr.

This patch saves p_vaddr to p_vaddr_offset, and to make the use of
p_vaddr_offset consistent, inverts the sign.  (It's now added to
section vma to get segment vaddr, and added to zero when there are no
sections.)

* elf.c (assign_file_positions_for_load_sections): Set p_vaddr
from m->p_vaddr_offset for segments without sections.  Invert
sign of p_vaddr_offset.
(rewrite_elf_program_header, copy_elf_program_header): Save
old segment p_vaddr to p_vaddr_offset.  Invert sign of
p_vaddr_offset.

bfd/ChangeLog
bfd/elf.c

index 3d6796b09497578010af1aaf7d650197a7944b55..5276305d802376bac8e87fa035ab1cacf1d3499e 100644 (file)
@@ -1,3 +1,12 @@
+2018-10-08  Alan Modra  <amodra@gmail.com>
+
+       * elf.c (assign_file_positions_for_load_sections): Set p_vaddr
+       from m->p_vaddr_offset for segments without sections.  Invert
+       sign of p_vaddr_offset.
+       (rewrite_elf_program_header, copy_elf_program_header): Save
+       old segment p_vaddr to p_vaddr_offset.  Invert sign of
+       p_vaddr_offset.
+
 2018-10-08  Alan Modra  <amodra@gmail.com>
 
        * elf.c (get_program_header_size): Don't count PT_INTERP if
index fe43c9ffe726328b85ab9e87434260b8ecf2127d..742a52e7bf064867ef00c877f0e5edd9a1b36e4d 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -5358,16 +5358,16 @@ assign_file_positions_for_load_sections (bfd *abfd,
       p->p_flags = m->p_flags;
 
       if (m->count == 0)
-       p->p_vaddr = 0;
+       p->p_vaddr = m->p_vaddr_offset;
       else
-       p->p_vaddr = m->sections[0]->vma - m->p_vaddr_offset;
+       p->p_vaddr = m->sections[0]->vma + m->p_vaddr_offset;
 
       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;
 
       if (p->p_type == PT_LOAD
          && (abfd->flags & D_PAGED) != 0)
@@ -6881,6 +6881,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->count = 0;
          *pointer_to_map = map;
          pointer_to_map = &map->next;
@@ -7005,7 +7006,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
            /* There is some padding before the first section in the
               segment.  So, we must account for that in the output
               segment's vma.  */
-           map->p_vaddr_offset = matching_lma->lma - map->p_paddr;
+           map->p_vaddr_offset = map->p_paddr - matching_lma->lma;
 
          free (sections);
          continue;
@@ -7367,12 +7368,14 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd)
            map->header_size = lowest_section->filepos;
        }
 
-      if (!map->includes_phdrs
-         && !map->includes_filehdr
-         && map->p_paddr_valid)
-       /* There is some other padding before the first section.  */
-       map->p_vaddr_offset = ((lowest_section ? lowest_section->lma : 0)
-                              - segment->p_paddr);
+      if (section_count == 0)
+       map->p_vaddr_offset = segment->p_vaddr;
+      else if (!map->includes_phdrs
+              && !map->includes_filehdr
+              && map->p_paddr_valid)
+       /* Account for padding before the first section.  */
+       map->p_vaddr_offset = (segment->p_paddr
+                              - (lowest_section ? lowest_section->lma : 0));
 
       map->count = section_count;
       *pointer_to_map = map;