RISC-V: Fix ld-elf/pr22269* testcases.
[deliverable/binutils-gdb.git] / bfd / elf.c
index 3e8d5103e4d3921a21701a789e7c414397b0d565..47d046fa8346d2b47d32c94a12f700cbb7a8a461 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -628,7 +628,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
              bfd_alloc2 (abfd, num_group, sizeof (Elf_Internal_Shdr *));
          if (elf_tdata (abfd)->group_sect_ptr == NULL)
            return FALSE;
-         memset (elf_tdata (abfd)->group_sect_ptr, 0, num_group * sizeof (Elf_Internal_Shdr *));
+         memset (elf_tdata (abfd)->group_sect_ptr, 0,
+                 num_group * sizeof (Elf_Internal_Shdr *));
          num_group = 0;
 
          for (i = 0; i < shnum; i++)
@@ -709,13 +710,16 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                              |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD;
                          break;
                        }
-                     if (idx >= shnum)
+                     if (idx < shnum)
+                       dest->shdr = elf_elfsections (abfd)[idx];
+                     if (idx >= shnum
+                         || dest->shdr->sh_type == SHT_GROUP)
                        {
                          _bfd_error_handler
-                           (_("%pB: invalid SHT_GROUP entry"), abfd);
-                         idx = 0;
+                           (_("%pB: invalid entry in SHT_GROUP section [%u]"),
+                              abfd, i);
+                         dest->shdr = NULL;
                        }
-                     dest->shdr = elf_elfsections (abfd)[idx];
                    }
                }
            }
@@ -781,7 +785,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect)
                idx = (Elf_Internal_Group *) shdr->contents;
                n_elt = shdr->sh_size / 4;
                while (--n_elt != 0)
-                 if ((s = (++idx)->shdr->bfd_section) != NULL
+                 if ((++idx)->shdr != NULL
+                     && (s = idx->shdr->bfd_section) != NULL
                      && elf_next_in_group (s) != NULL)
                    break;
                if (n_elt != 0)
@@ -6641,7 +6646,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
           : segment->p_vaddr != section->vma)                          \
        || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic")   \
           == 0))                                                       \
-   && !section->segment_mark)
+   && (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.   */
@@ -6769,13 +6774,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       asection **sections;
       asection *output_section;
       unsigned int isec;
-      bfd_vma matching_lma;
-      bfd_vma suggested_lma;
+      asection *matching_lma;
+      asection *suggested_lma;
       unsigned int j;
       bfd_size_type amt;
       asection *first_section;
-      bfd_boolean first_matching_lma;
-      bfd_boolean first_suggested_lma;
 
       if (segment->p_type == PT_NULL)
        continue;
@@ -6902,10 +6905,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
         we have completely filled the segment, and there is nothing
         more to do.  */
       isec = 0;
-      matching_lma = 0;
-      suggested_lma = 0;
-      first_matching_lma = TRUE;
-      first_suggested_lma = TRUE;
+      matching_lma = NULL;
+      suggested_lma = NULL;
 
       for (section = first_section, j = 0;
           section != NULL;
@@ -6926,14 +6927,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                  && !bed->want_p_paddr_set_to_zero
                  && isec == 0
                  && output_section->lma != 0
-                 && output_section->vma == (segment->p_vaddr
-                                            + (map->includes_filehdr
-                                               ? iehdr->e_ehsize
-                                               : 0)
-                                            + (map->includes_phdrs
-                                               ? (iehdr->e_phnum
-                                                  * iehdr->e_phentsize)
-                                               : 0)))
+                 && (align_power (segment->p_vaddr
+                                  + (map->includes_filehdr
+                                     ? iehdr->e_ehsize : 0)
+                                  + (map->includes_phdrs
+                                     ? iehdr->e_phnum * iehdr->e_phentsize
+                                     : 0),
+                                  output_section->alignment_power)
+                     == output_section->vma))
                map->p_paddr = segment->p_vaddr;
 
              /* Match up the physical address of the segment with the
@@ -6943,22 +6944,17 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                  || (bed->want_p_paddr_set_to_zero
                      && IS_CONTAINED_BY_VMA (output_section, segment)))
                {
-                 if (first_matching_lma || output_section->lma < matching_lma)
-                   {
-                     matching_lma = output_section->lma;
-                     first_matching_lma = FALSE;
-                   }
+                 if (matching_lma == NULL
+                     || output_section->lma < matching_lma->lma)
+                   matching_lma = output_section;
 
                  /* We assume that if the section fits within the segment
                     then it does not overlap any other section within that
                     segment.  */
                  map->sections[isec++] = output_section;
                }
-             else if (first_suggested_lma)
-               {
-                 suggested_lma = output_section->lma;
-                 first_suggested_lma = FALSE;
-               }
+             else if (suggested_lma == NULL)
+               suggested_lma = output_section;
 
              if (j == section_count)
                break;
@@ -6981,63 +6977,54 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
 
          if (p_paddr_valid
              && !bed->want_p_paddr_set_to_zero
-             && matching_lma != map->p_paddr
+             && matching_lma->lma != map->p_paddr
              && !map->includes_filehdr
              && !map->includes_phdrs)
            /* 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 - map->p_paddr;
+           map->p_vaddr_offset = matching_lma->lma - map->p_paddr;
 
          free (sections);
          continue;
        }
       else
        {
-         if (!first_matching_lma)
-           {
-             /* At least one section fits inside the current segment.
-                Keep it, but modify its physical address to match the
-                LMA of the first section that fitted.  */
-             map->p_paddr = matching_lma;
-           }
-         else
-           {
-             /* None of the sections fitted inside the current segment.
-                Change the current segment's physical address to match
-                the LMA of the first section.  */
-             map->p_paddr = suggested_lma;
-           }
+         /* Change the current segment's physical address to match
+            the LMA of the first section that fitted, or if no
+            section fitted, the first section.  */
+         if (matching_lma == NULL)
+           matching_lma = suggested_lma;
+
+         map->p_paddr = matching_lma->lma;
 
          /* Offset the segment physical address from the lma
             to allow for space taken up by elf headers.  */
-         if (map->includes_filehdr)
+         if (map->includes_phdrs)
            {
-             if (map->p_paddr >= iehdr->e_ehsize)
-               map->p_paddr -= iehdr->e_ehsize;
-             else
-               {
-                 map->includes_filehdr = FALSE;
-                 map->includes_phdrs = FALSE;
-               }
+             map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
+
+             /* iehdr->e_phnum is just an estimate of the number
+                of program headers that we will need.  Make a note
+                here of the number we used and the segment we chose
+                to hold these headers, so that we can adjust the
+                offset when we know the correct value.  */
+             phdr_adjust_num = iehdr->e_phnum;
+             phdr_adjust_seg = map;
            }
 
-         if (map->includes_phdrs)
+         if (map->includes_filehdr)
            {
-             if (map->p_paddr >= iehdr->e_phnum * iehdr->e_phentsize)
-               {
-                 map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize;
-
-                 /* iehdr->e_phnum is just an estimate of the number
-                    of program headers that we will need.  Make a note
-                    here of the number we used and the segment we chose
-                    to hold these headers, so that we can adjust the
-                    offset when we know the correct value.  */
-                 phdr_adjust_num = iehdr->e_phnum;
-                 phdr_adjust_seg = map;
-               }
-             else
-               map->includes_phdrs = FALSE;
+             bfd_vma align = (bfd_vma) 1 << matching_lma->alignment_power;
+             map->p_paddr -= iehdr->e_ehsize;
+             /* We've subtracted off the size of headers from the
+                first section lma, but there may have been some
+                alignment padding before that section too.  Try to
+                account for that by adjusting the segment lma down to
+                the same alignment.  */
+             if (segment->p_align != 0 && segment->p_align < align)
+               align = segment->p_align;
+             map->p_paddr &= -align;
            }
        }
 
@@ -7052,8 +7039,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       do
        {
          map->count = 0;
-         suggested_lma = 0;
-         first_suggested_lma = TRUE;
+         suggested_lma = NULL;
 
          /* Fill the current segment with sections that fit.  */
          for (j = 0; j < section_count; j++)
@@ -7075,12 +7061,14 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                      /* If the first section in a segment does not start at
                         the beginning of the segment, then something is
                         wrong.  */
-                     if (output_section->lma
-                         != (map->p_paddr
-                             + (map->includes_filehdr ? iehdr->e_ehsize : 0)
-                             + (map->includes_phdrs
-                                ? iehdr->e_phnum * iehdr->e_phentsize
-                                : 0)))
+                     if (align_power (map->p_paddr
+                                      + (map->includes_filehdr
+                                         ? iehdr->e_ehsize : 0)
+                                      + (map->includes_phdrs
+                                         ? iehdr->e_phnum * iehdr->e_phentsize
+                                         : 0),
+                                      output_section->alignment_power)
+                         != output_section->lma)
                        abort ();
                    }
                  else
@@ -7098,11 +7086,8 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                          || (prev_sec->lma + prev_sec->size
                              > output_section->lma))
                        {
-                         if (first_suggested_lma)
-                           {
-                             suggested_lma = output_section->lma;
-                             first_suggested_lma = FALSE;
-                           }
+                         if (suggested_lma == NULL)
+                           suggested_lma = output_section;
 
                          continue;
                        }
@@ -7111,13 +7096,11 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
                  map->sections[map->count++] = output_section;
                  ++isec;
                  sections[j] = NULL;
-                 section->segment_mark = TRUE;
-               }
-             else if (first_suggested_lma)
-               {
-                 suggested_lma = output_section->lma;
-                 first_suggested_lma = FALSE;
+                 if (segment->p_type == PT_LOAD)
+                   section->segment_mark = TRUE;
                }
+             else if (suggested_lma == NULL)
+               suggested_lma = output_section;
            }
 
          BFD_ASSERT (map->count > 0);
@@ -7147,7 +7130,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
              map->p_type = segment->p_type;
              map->p_flags = segment->p_flags;
              map->p_flags_valid = 1;
-             map->p_paddr = suggested_lma;
+             map->p_paddr = suggested_lma->lma;
              map->p_paddr_valid = p_paddr_valid;
              map->includes_filehdr = 0;
              map->includes_phdrs = 0;
@@ -7173,6 +7156,15 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd)
       if (count > phdr_adjust_num)
        phdr_adjust_seg->p_paddr
          -= (count - phdr_adjust_num) * iehdr->e_phentsize;
+
+      for (map = map_first; map != NULL; map = map->next)
+       if (map->p_type == PT_PHDR)
+         {
+           bfd_vma adjust
+             = phdr_adjust_seg->includes_filehdr ? iehdr->e_ehsize : 0;
+           map->p_paddr = phdr_adjust_seg->p_paddr + adjust;
+           break;
+         }
     }
 
 #undef SEGMENT_END
This page took 0.040859 seconds and 4 git commands to generate.