]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Update objcopy's --section-alignment option so that it sets the alignment flag on...
authorNick Clifton <nickc@redhat.com>
Tue, 2 Apr 2024 14:08:07 +0000 (15:08 +0100)
committerNick Clifton <nickc@redhat.com>
Tue, 2 Apr 2024 14:09:16 +0000 (15:09 +0100)
binutils/doc/binutils.texi
binutils/objcopy.c
binutils/od-pe.c
binutils/testsuite/binutils-all/objcopy.exp
binutils/testsuite/binutils-all/section-alignment.d [new file with mode: 0644]

index 50cc4707e143b31445cfa4a527a12bf5698a5460..79461559a568a260c66a39a354634d5c2ba4fa4a 100644 (file)
@@ -1737,6 +1737,10 @@ above.  If @var{sectionpattern} does not match any sections in the
 input file, a warning will be issued, unless
 @option{--no-change-warnings} is used.
 
+Note - changing the VMA of sections in a fully linked binary can be
+dangerous since there may be code that expects the sections to be
+located at their old address.
+
 @item --change-warnings
 @itemx --adjust-warnings
 If @option{--change-section-address} or @option{--change-section-lma} or
@@ -1766,7 +1770,14 @@ SHF_X86_64_LARGE.
 @item --set-section-alignment @var{sectionpattern}=@var{align}
 Set the alignment for any sections matching @var{sectionpattern}.
 @var{align} specifies the alignment in bytes and must be a power of
-two, i.e. 1, 2, 4, 8@dots{}. 
+two, i.e. 1, 2, 4, 8@dots{}.
+
+Note - setting a section's alignment will not automatically align its
+LMA or VMA addresses.  If those need to be changed as well then the
+@option{--change-section-lma} and/or @option{--change-section-vma}
+options should be used.  Also note that changing VMAs can cause
+problems in fully linked binaries where there may be code that expects
+the contents of the sections to be located at their old address.
 
 @item --add-section @var{sectionname}=@var{filename}
 Add a new section named @var{sectionname} while copying the file.  The
@@ -2129,11 +2140,21 @@ for dlls.
 [This option is specific to PE targets.]
 
 @item --section-alignment @var{num}
-Sets the section alignment field in the PE header.  Sections in memory
-will always begin at addresses which are a multiple of this number.
-Defaults to 0x1000.
 [This option is specific to PE targets.]
 
+Sets the section alignment field in the PE header - if one is present
+in the binary.  Sections in memory will always begin at addresses
+which are a multiple of this number.  Defaults to 0x1000.
+
+Note - this option will also set the alignment field in each section's
+flags.
+
+Note - if a section's LMA or VMA addresses are no longer aligned, and
+those addresses have not been set via the @option{--set-section-lma} or
+@option{--set-section-vma} options, and the file has been fully
+relocated then a warning message will be issued.  It will then be up
+to the user to decide if the LMA and VMA need updating.
+
 @item --stack @var{reserve}
 @itemx --stack @var{reserve},@var{commit}
 Specify the number of bytes of memory to reserve (and optionally commit)
index a8e0f156f3e28969bc9c92b85ed0a0efa8130078..77ab908094652eda3ebbca77ee767eacb94e7011 100644 (file)
@@ -4100,6 +4100,50 @@ setup_bfd_headers (bfd *ibfd, bfd *obfd)
   return;
 }
 
+static inline signed int
+power_of_two (bfd_vma val)
+{
+  signed int result = 0;
+
+  if (val == 0)
+    return 0;
+
+  while ((val & 1) == 0)
+    {
+      val >>= 1;
+      ++result;
+    }
+
+  if (val != 1)
+    /* Number has more than one 1, i.e. wasn't a power of 2.  */
+    return -1;
+
+  return result;
+}
+
+static unsigned int
+image_scn_align (unsigned int alignment)
+{
+  switch (alignment)
+    {
+    case 8192: return IMAGE_SCN_ALIGN_8192BYTES;
+    case 4096: return IMAGE_SCN_ALIGN_4096BYTES;
+    case 2048: return IMAGE_SCN_ALIGN_2048BYTES;
+    case 1024: return IMAGE_SCN_ALIGN_1024BYTES;
+    case  512: return IMAGE_SCN_ALIGN_512BYTES;
+    case  256: return IMAGE_SCN_ALIGN_256BYTES;
+    case  128: return IMAGE_SCN_ALIGN_128BYTES;
+    case   64: return IMAGE_SCN_ALIGN_64BYTES;
+    case   32: return IMAGE_SCN_ALIGN_32BYTES;
+    case   16: return IMAGE_SCN_ALIGN_16BYTES;
+    case    8: return IMAGE_SCN_ALIGN_8BYTES;
+    case    4: return IMAGE_SCN_ALIGN_4BYTES;
+    case    2: return IMAGE_SCN_ALIGN_2BYTES;
+    case    1: return IMAGE_SCN_ALIGN_1BYTES;
+    default: return 0;
+    }
+}
+
 /* Create a section in OBFD with the same
    name and attributes as ISECTION in IBFD.  */
 
@@ -4224,6 +4268,8 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   if (!bfd_set_section_size (osection, size))
     err = _("failed to set size");
 
+  bool vma_set_by_user = false;
+
   vma = bfd_section_vma (isection);
   p = find_section_list (bfd_section_name (isection), false,
                         SECTION_CONTEXT_ALTER_VMA | SECTION_CONTEXT_SET_VMA);
@@ -4233,6 +4279,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        vma = p->vma_val;
       else
        vma += p->vma_val;
+      vma_set_by_user = true;
     }
   else
     vma += change_section_address;
@@ -4240,6 +4287,8 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   if (!bfd_set_section_vma (osection, vma))
     err = _("failed to set vma");
 
+  bool lma_set_by_user = false;
+
   lma = isection->lma;
   p = find_section_list (bfd_section_name (isection), false,
                         SECTION_CONTEXT_ALTER_LMA | SECTION_CONTEXT_SET_LMA);
@@ -4249,6 +4298,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
        lma += p->lma_val;
       else
        lma = p->lma_val;
+      lma_set_by_user = true;
     }
   else
     lma += change_section_address;
@@ -4259,6 +4309,24 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
                         SECTION_CONTEXT_SET_ALIGNMENT);
   if (p != NULL)
     alignment = p->alignment;
+  else if (pe_section_alignment != (bfd_vma) -1
+          && bfd_get_flavour (obfd) == bfd_target_coff_flavour)
+    {
+      alignment = power_of_two (pe_section_alignment);
+
+      if (coff_section_data (ibfd, isection))
+       {
+         struct pei_section_tdata * pei_data = pei_section_data (ibfd, isection);
+
+         if (pei_data != NULL)
+           {
+             /* Set the alignment flag of the input section, which will
+                be copied to the output section later on.  */
+             pei_data->pe_flags &= ~IMAGE_SCN_ALIGN_POWER_BIT_MASK;
+             pei_data->pe_flags |= image_scn_align (pe_section_alignment);
+           }
+       }
+    }
   else
     alignment = bfd_section_alignment (isection);
 
@@ -4267,6 +4335,32 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   if (!bfd_set_section_alignment (osection, alignment))
     err = _("failed to set alignment");
 
+  /* If the output section's VMA is not aligned
+     and the alignment has changed
+     and the VMA was not set by the user
+     and the section does not have relocations associated with it
+     then warn the user.  */
+  if (osection->vma & ((1 << alignment) - 1)
+      && alignment != bfd_section_alignment (isection)
+      && change_section_address == 0
+      && ! vma_set_by_user
+      && bfd_get_reloc_upper_bound (ibfd, isection) < 1)
+    {
+      non_fatal (_("output section %s's alignment does not match its VMA"), name);
+    }
+
+  /* Similar check for a non-aligned LMA.
+     FIXME: Since this is only an LMA, maybe it does not matter if
+     it is not aligned ?  */
+  if (osection->lma & ((1 << alignment) - 1)
+      && alignment != bfd_section_alignment (isection)
+      && change_section_address == 0
+      && ! lma_set_by_user
+      && bfd_get_reloc_upper_bound (ibfd, isection) < 1)
+    {
+      non_fatal (_("output section %s's alignment does not match its LMA"), name);
+    }
+
   /* Copy merge entity size.  */
   osection->entsize = isection->entsize;
 
@@ -5713,15 +5807,8 @@ copy_main (int argc, char *argv[])
              fatal (_("bad format for --set-section-alignment: numeric argument needed"));
 
            /* Convert integer alignment into a power-of-two alignment.  */
-           palign = 0;
-           while ((align & 1) == 0)
-             {
-               align >>= 1;
-               ++palign;
-             }
-
-           if (align != 1)
-             /* Number has more than on 1, i.e. wasn't a power of 2.  */
+           palign = power_of_two (align);
+           if (palign == -1)
              fatal (_("bad format for --set-section-alignment: alignment is not a power of two"));
 
            /* Add the alignment setting to the section list.  */
@@ -5938,6 +6025,11 @@ copy_main (int argc, char *argv[])
        case OPTION_PE_SECTION_ALIGNMENT:
          pe_section_alignment = parse_vma (optarg,
                                            "--section-alignment");
+         if (power_of_two (pe_section_alignment) == -1)
+           {
+             non_fatal (_("--section-alignment argument is not a power of two: %s - ignoring"), optarg);
+             pe_section_alignment = (bfd_vma) -1;
+           }
          break;
 
        case OPTION_SUBSYSTEM:
index 5d2b77674779f1b0f3200ccf0c8ffbee61ddb3a3..28bce3bfd7fb24f7dc78eec97612396202ad1435 100644 (file)
@@ -138,7 +138,7 @@ static const struct xlat_table section_flag_xlat[] =
   { IMAGE_SCN_LNK_NRELOC_OVFL, "NRELOC OVFL" },
   { IMAGE_SCN_MEM_NOT_CACHED,  "NOT CACHED" },
   { IMAGE_SCN_MEM_NOT_PAGED,   "NOT PAGED" },
-  { IMAGE_SCN_MEM_SHARED,      "SHARED" },    
+  { IMAGE_SCN_MEM_SHARED,      "SHARED" },
   { 0, NULL }
 };
 
@@ -591,7 +591,44 @@ dump_pe_file_header (bfd *                            abfd,
     printf (_("\n  Optional header not present\n"));
 }
 
-/* Dump the sections header.  */
+static void
+dump_alignment (unsigned int flags)
+{
+  flags &= IMAGE_SCN_ALIGN_POWER_BIT_MASK;
+
+  if (flags == IMAGE_SCN_ALIGN_8192BYTES)
+    printf (_("Align: 8192 "));
+  else if (flags == IMAGE_SCN_ALIGN_4096BYTES)
+    printf (_("Align: 4096 "));
+  else if (flags == IMAGE_SCN_ALIGN_2048BYTES)
+    printf (_("Align: 2048 "));
+  else if (flags == IMAGE_SCN_ALIGN_1024BYTES)
+    printf (_("Align: 1024 "));
+  else if (flags == IMAGE_SCN_ALIGN_512BYTES)
+    printf (_("Align: 512 "));
+  else if (flags == IMAGE_SCN_ALIGN_256BYTES)
+    printf (_("Align: 256 "));
+  else if (flags == IMAGE_SCN_ALIGN_128BYTES)
+    printf (_("Align: 128 "));
+  else if (flags == IMAGE_SCN_ALIGN_64BYTES)
+    printf (_("Align: 64 "));
+  else if (flags == IMAGE_SCN_ALIGN_32BYTES)
+    printf (_("Align: 32 "));
+  else if (flags == IMAGE_SCN_ALIGN_16BYTES)
+    printf (_("Align: 16 "));
+  else if (flags == IMAGE_SCN_ALIGN_8BYTES)
+    printf (_("Align: 8 "));
+  else if (flags == IMAGE_SCN_ALIGN_4BYTES)
+    printf (_("Align: 4 "));
+  else if (flags == IMAGE_SCN_ALIGN_2BYTES)
+    printf (_("Align: 2 "));
+  else if (flags == IMAGE_SCN_ALIGN_1BYTES)
+    printf (_("Align: 1 "));
+  else
+    printf (_("Align: *unknown* "));
+}
+
+/* Dump the section's header.  */
 
 static void
 dump_pe_sections_header (bfd *                            abfd,
@@ -656,12 +693,14 @@ dump_pe_sections_header (bfd *                            abfd,
       else
        printf (_("\n            Flags: %08x: "), flags);
 
-      if (flags != 0)
-        {
-         /* Skip the alignment bits.  */
+      if (flags & IMAGE_SCN_ALIGN_POWER_BIT_MASK)
+       {
+         dump_alignment (flags);
          flags &= ~ IMAGE_SCN_ALIGN_POWER_BIT_MASK;
-          dump_flags (section_flag_xlat, flags);
-        }
+       }
+
+      if (flags != 0)
+       dump_flags (section_flag_xlat, flags);
 
       putchar ('\n');
     }
index d8848228b53120e5b711724e2b3d7144e4f42d37..8b432f3b48c45a50dc3075e08be2f3c8b4fc3035 100644 (file)
@@ -1463,6 +1463,7 @@ if [is_elf_format] {
 run_dump_test "pr23633"
 
 run_dump_test "set-section-alignment"
+run_dump_test "section-alignment"
 
 setup_xfail "hppa*-*-*"
 setup_xfail "spu-*-*"
diff --git a/binutils/testsuite/binutils-all/section-alignment.d b/binutils/testsuite/binutils-all/section-alignment.d
new file mode 100644 (file)
index 0000000..d62528c
--- /dev/null
@@ -0,0 +1,9 @@
+#source: pr23633.s
+#PROG: objcopy
+#objcopy: --section-alignment=512
+#objdump: -P sections
+#target: [is_pecoff_format]
+
+#...
+.* Align: 512.*
+#pass