[PATCH] Fix IAT (Import Address Table) alignment on AArch64
Evgeny Karpov
evgeny.karpov@arm.com
Thu Apr 9 14:40:38 GMT 2026
On Thu, Apr 09, 2026, Jan Beulich wrote:
> On 09.04.2026 13:21, Evgeny Karpov wrote:
> > On Thu, Apr 09, 2026, Jan Beulich wrote:
> >> On 09.04.2026 10:10, Evgeny Karpov wrote:
> >>> On Wed, Apr 08, 2026, Jan Beulich wrote:
> >>>> On 08.04.2026 12:30, Evgeny Karpov wrote:
> >>>>> On Wed, Apr 08, 2026, Jan Beulich wrote:
> >>>>>> On 08.04.2026 11:27, Evgeny Karpov wrote:
> >>>>>>> On Wed, Apr 08, 2026, Jan Beulich wrote:
> >>>>>>>> On 08.04.2026 11:05, Evgeny Karpov wrote:
> >>>>>>>>> On Wed, Apr 08, 2026, Jan Beulich wrote:
> >>>>>>>>>> On 07.04.2026 19:12, Evgeny Karpov wrote:
> >>>>>>>>>>> On Tue, Apr 07, 2026, Jan Beulich wrote:
> >>>>>>>>>>>> On 07.04.2026 16:47, Evgeny Karpov wrote:
> >>>>>>>>>>>>> On Tue, Apr 07, 2026, Jan Beulich wrote:
> >>>>>>>>>>>>>> On 07.04.2026 11:48, Evgeny Karpov wrote:
> >>>>>>>>>>>>>>> The IAT should be aligned to 8 bytes in aarch64-w64-mingw32, otherwise, it might
> >>>>>>>>>>>>>>> result in relocation issues.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> What is it that makes this different on aarch64? IOW I wonder if this is
> >>>>>>>>>>>>>> going too far or not far enough.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> binutils/ChangeLog:
> >>>>>>>>>>>>>>>
> >>>>>>>>>>>>>>> * dlltool.c (make_head): Update.
> >>>>>>>>>>>>>>
> >>>>>>>>>>>>>> Please either omit the ChangeLog entry, or have it say something meaningful.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> The updated decription:
> >>>>>>>>>>>>> ---
> >>>>>>>>>>>>> The IAT should be aligned to 8 bytes in aarch64-w64-mingw32, otherwise, it might
> >>>>>>>>>>>>> result in relocation issues.
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> When a function is imported from DLL, it generates the following code:
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> adrp x19, __imp_fn
> >>>>>>>>>>>>> ldr x19, [x19, #:lo12:__imp_fn]
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> 8 byte alignment is required for ldr relocation. Addresses are placed in IAT.
> >>>>>>>>>>>>> The size of the chunk on AArch64 is 8 bytes.
> >>>>>>>>>>>>> If IAT is not aligned to 8 bytes, the relocation issue appears.
> >>>>>>>>>>>>> This patch fixes this issue.
> >>>>>>>>>>>>
> >>>>>>>>>>>> Much better, thanks. This addresses part of my earlier remark then as well,
> >>>>>>>>>>>> clarifying it's not "too much" that you do. The "too little" aspect remains,
> >>>>>>>>>>>> though: Looking at a random ia64 archive, I see .idata$5 to have 8-byte
> >>>>>>>>>>>> alignment there as well. Shouldn't .idata$5 always have machine-word
> >>>>>>>>>>>> alignment?
> >>>>>>>>>>>
> >>>>>>>>>>> Based on PE Format documentation
> >>>>>>>>>>> https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-address-table
> >>>>>>>>>>>
> >>>>>>>>>>> 4 byte addresses are used for PE32 and 8 byte addresses are used for PE32+.
> >>>>>>>>>>> There is no definition about the alignment, however it might be optional.
> >>>>>>>>>>> 8 byte alignment appears as a requirement for an architecture.
> >>>>>>>>>>> For example, it requires 8 byte alignment for ldr relocation on AArch64.
> >>>>>>>>>>>
> >>>>>>>>>>> Potentially, 8 byte alignment might be applied to all architectures,
> >>>>>>>>>>> however this might not be necessary for other relocations and could
> >>>>>>>>>>> slightly unnecessarily increase the size.
> >>>>>>>>>>
> >>>>>>>>>> Applying 8-byte alignment uniformly might add padding between .idata$4 and
> >>>>>>>>>> .idata$5 for PE32, which likely is unwanted (and possibly is wrong).
> >>>>>>>>>
> >>>>>>>>> Most likely, it does not break the PE format as it has an RVA to IAT, however it is
> >>>>>>>>> definitely might bring unwanted padding to PE32.
> >>>>>>>>>
> >>>>>>>>>>>>> binutils/ChangeLog:
> >>>>>>>>>>>>>
> >>>>>>>>>>>>> * dlltool.c (make_head): Add 8 byte alignment.
> >>>>>>>>>>>>
> >>>>>>>>>>>> This sadly still gives the impression of wider a change (all targets) than
> >>>>>>>>>>>> there is.
> >>>>>>>>>>>
> >>>>>>>>>>> It will be changed to "Add 8 byte alignment on AArch64.".
> >>>>>>>>>>
> >>>>>>>>>> If you insist on enforcing the alignment only for Arm64, then the code
> >>>>>>>>>> comment itself also wants extending to clarify why that target is special.
> >>>>>>>>>> As said, I think we should follow what MS tools do and arrange for 4- / 8-
> >>>>>>>>>> byte alignment for all targets.
> >>>>>>>>>
> >>>>>>>>> Based on this suggestion, the patch can be changed to:
> >>>>>>>>>
> >>>>>>>>> + /* Align IAT (Import Address Table) to 8 bytes for PE32+.
> >>>>>>>>> + https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-address-table. */
> >>>>>>>>> + if (create_for_pep)
> >>>>>>>>> + fprintf (f, "\t.align 3\n");
> >>>>>>>>
> >>>>>>>> Any reason to then not also go the final small step and use
> >>>>>>>>
> >>>>>>>> fprintf (f, "\t.p2align %d\n", create_for_pep ? 3 : 2);
> >>>>>>>
> >>>>>>> It looks like the alignment to 4 is not necessary because it is already aligned to
> >>>>>>> 4 by INIT_SEC_DATA (IDATA5, ".idata$5", SEC_HAS_CONTENTS, 2).
> >>>>>>
> >>>>>> Hmm, good point, yet then wouldn't we better correct things there? And then
> >>>>>> also for .didat? secdata_{plain,delay}[] aren't even const, so a "rude"
> >>>>>> approach could be to edit those tables at runtime. (Preferably we'd solve
> >>>>>> this differently though, e.g. by setting .align to -1 to indicate 2 or 3
> >>>>>> want using depending on the target.)
> >>>>>
> >>>>> It might be better to keep default 4 byte alignment for readability.
> >>>>> It turns the change into following:
> >>>>>
> >>>>> create_for_pep = (strcmp (mname, "i386:x86-64") == 0
> >>>>> || strcmp (mname, "arm64") == 0);
> >>>>>
> >>>>> + if (create_for_pep)
> >>>>> + {
> >>>>> + /* Update default 4 byte IAT (Import Address Table) alignemnt to 8 bytes
> >>>>> + for PE32+.
> >>>>> + https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#import-address-table. */
> >>>>> + secdata[IDATA5].align = 3;
> >>>>
> >>>> I guess you mean secdata_plain[] here? Other than that I think all that is
> >>>> now needed is a clean v2 submission.
> >>>
> >>> Actually, applying alignment in secdata_plain is already too late, and it
> >>> should be done in the header for .idata$5 before the first chunk symbol,
> >>> as it was done initially.
> >>
> >> I fear I don't understand: When modifying secdata_{plain,delay}[] right
> >> after setting create_for_pep, how can that be too late? gen_lib_file()
> >> (and hence make_one_lib_file()) is only called later.
> >
> > There is a sequence of .idata$5 sections that starts with a section created
> > by using make_head.
>
> Which means what exactly wrt me pointing out that gen_lib_file() (and hence
> make_head()) run much later than the editing of the two tables (in main())?
It looks like make_one_lib_file uses the alignment from secdata_plain to create
.idata$5 section, which will be placed after .idata$5 head section created by
make_head. make_head does not have an alignment without the patch introduced earlier.
however it has a reference to the first chunk, that should be aligned.
And the order is defined later in gen_lib_file.
Regards,
Evgeny
More information about the Binutils
mailing list