[v3,1/1] Fix IAT (Import Address Table) alignment on AArch64

Message ID 20260505083445.4558-2-evgeny.karpov@arm.com
State Accepted
Headers
Series Fix IAT (Import Address Table) alignment on AArch64 |

Commit Message

Evgeny Karpov May 5, 2026, 8:34 a.m. UTC
  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 by aligning IAT to 8 bytes for PE32+.

binutils/ChangeLog:

	* dlltool.c (make_head): Apply alignment to IAT.
	(make_delay_head): Apply alignment to Delay IAT.
	(main): Adjust 8 byte alignment for PE32+.
---
 binutils/dlltool.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)
  

Comments

Jan Beulich May 8, 2026, 8:28 a.m. UTC | #1
On 05.05.2026 10:34, Evgeny Karpov wrote:
> 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 by aligning IAT to 8 bytes for PE32+.
> 
> binutils/ChangeLog:
> 
> 	* dlltool.c (make_head): Apply alignment to IAT.
> 	(make_delay_head): Apply alignment to Delay IAT.
> 	(main): Adjust 8 byte alignment for PE32+.

Okay, with ...

> @@ -4013,6 +4017,14 @@ main (int ac, char **av)
>    /* Check if we generated PE+.  */
>    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+.

... the typo here (alignment) corrected. I'll do that while committing.

I guess I'll also replace AArch64 with PE32+ in the title.

Jan
  
Jan Beulich May 8, 2026, 8:31 a.m. UTC | #2
On 08.05.2026 10:28, Jan Beulich wrote:
> On 05.05.2026 10:34, Evgeny Karpov wrote:
>> 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 by aligning IAT to 8 bytes for PE32+.
>>
>> binutils/ChangeLog:
>>
>> 	* dlltool.c (make_head): Apply alignment to IAT.
>> 	(make_delay_head): Apply alignment to Delay IAT.
>> 	(main): Adjust 8 byte alignment for PE32+.
> 
> Okay, with ...
> 
>> @@ -4013,6 +4017,14 @@ main (int ac, char **av)
>>    /* Check if we generated PE+.  */
>>    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+.
> 
> ... the typo here (alignment) corrected. I'll do that while committing.

Except, wait: The patch is missing your S-o-b. Which we need unless you
meanwhile have a copyright assignment in place with the FSF.

Jan

> I guess I'll also replace AArch64 with PE32+ in the title.
> 
> Jan
  
Alice Carlotti May 8, 2026, 1:50 p.m. UTC | #3
On Fri, May 08, 2026 at 10:31:51AM +0200, Jan Beulich wrote:
> On 08.05.2026 10:28, Jan Beulich wrote:
> > On 05.05.2026 10:34, Evgeny Karpov wrote:
> >> 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 by aligning IAT to 8 bytes for PE32+.
> >>
> >> binutils/ChangeLog:
> >>
> >> 	* dlltool.c (make_head): Apply alignment to IAT.
> >> 	(make_delay_head): Apply alignment to Delay IAT.
> >> 	(main): Adjust 8 byte alignment for PE32+.
> > 
> > Okay, with ...
> > 
> >> @@ -4013,6 +4017,14 @@ main (int ac, char **av)
> >>    /* Check if we generated PE+.  */
> >>    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+.
> > 
> > ... the typo here (alignment) corrected. I'll do that while committing.
> 
> Except, wait: The patch is missing your S-o-b. Which we need unless you
> meanwhile have a copyright assignment in place with the FSF.

This should be already covered by Arm's copyright assignment.

Alice

> 
> Jan
> 
> > I guess I'll also replace AArch64 with PE32+ in the title.
> > 
> > Jan
>
  

Patch

diff --git a/binutils/dlltool.c b/binutils/dlltool.c
index 94805fcd334..e3c476bf1ee 100644
--- a/binutils/dlltool.c
+++ b/binutils/dlltool.c
@@ -2735,6 +2735,8 @@  make_head (void)
   if (!no_idata5)
     {
       fprintf (f, "\t.section\t.idata$5\n");
+      fprintf (f, "\t.p2align %d\n", secdata_plain[IDATA5].align);
+
       if (use_nul_prefixed_import_tables)
 	{
 	  if (create_for_pep)
@@ -2828,6 +2830,8 @@  make_delay_head (void)
   if (!no_idata5)
     {
       fprintf (f, "\t.section\t.didat$5\n");
+      fprintf (f, "\t.p2align %d\n", secdata_delay[IDATA5].align);
+
       if (use_nul_prefixed_import_tables)
 	{
 	  if (create_for_pep)
@@ -4013,6 +4017,14 @@  main (int ac, char **av)
   /* Check if we generated PE+.  */
   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_plain[IDATA5].align = 3;
+      secdata_delay[IDATA5].align = 3;
+    }
 
   /* Check the default underscore */
   if (leading_underscore == NULL)