diff options
author | Nick Clifton <nickc@redhat.com> | 2024-04-02 15:08:07 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2024-04-02 15:09:16 +0100 |
commit | 121a3f4b4f4aac216abe239f6f3bd491b63e5e34 (patch) | |
tree | 56d118e289a4e2cce3c87e9358849541aa799193 /binutils/objcopy.c | |
parent | b35013e29f3bcf9028aa22291f378010420322fe (diff) | |
download | gdb-121a3f4b4f4aac216abe239f6f3bd491b63e5e34.zip gdb-121a3f4b4f4aac216abe239f6f3bd491b63e5e34.tar.gz gdb-121a3f4b4f4aac216abe239f6f3bd491b63e5e34.tar.bz2 |
Update objcopy's --section-alignment option so that it sets the alignment flag on PE sections. Add a check for aligned sections not matching their VMAs.
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r-- | binutils/objcopy.c | 110 |
1 files changed, 101 insertions, 9 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c index a8e0f15..77ab908 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -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: |