From cef453db44856d6efc0941bc8a9df0fd318f6b8d Mon Sep 17 00:00:00 2001 From: Jeremy Drake Date: Fri, 13 Jun 2025 11:16:45 -0700 Subject: [PATCH] binutils: backport upstream commits This fixes #23577, https://sourceware.org/bugzilla/show_bug.cgi?id=14339, and https://sourceware.org/bugzilla/show_bug.cgi?id=32675 at least. Also backport support for filling in the load config directory with _load_config_used. This is not directly a bugfix, but avoided a conflict with the other patches. --- ...-bfd_get_symbol_leading_char-in-peXX.patch | 54 ++ ...5001-bfd-adjust-a-few-error-messages.patch | 76 +++ ...ll-in-PE-load-config-directory-entry.patch | 119 ++++ ...fig-size-workaround-for-i386-XP-and-.patch | 64 ++ ...mit-delay-load-import-data-into-its-.patch | 573 ++++++++++++++++++ ...-read-only-delayimp-data-into-.rdata.patch | 99 +++ ...use-nul-prefixed-import-tables-optio.patch | 54 ++ ...-delay-import-directory-in-PE-header.patch | 98 +++ mingw-w64-binutils/PKGBUILD | 34 +- 9 files changed, 1169 insertions(+), 2 deletions(-) create mode 100644 mingw-w64-binutils/5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch create mode 100644 mingw-w64-binutils/5001-bfd-adjust-a-few-error-messages.patch create mode 100644 mingw-w64-binutils/5002-bfd-fill-in-PE-load-config-directory-entry.patch create mode 100644 mingw-w64-binutils/5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch create mode 100644 mingw-w64-binutils/5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch create mode 100644 mingw-w64-binutils/5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch create mode 100644 mingw-w64-binutils/5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch create mode 100644 mingw-w64-binutils/5007-bfd-populate-delay-import-directory-in-PE-header.patch diff --git a/mingw-w64-binutils/5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch b/mingw-w64-binutils/5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch new file mode 100644 index 0000000000..430cfb333a --- /dev/null +++ b/mingw-w64-binutils/5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch @@ -0,0 +1,54 @@ +From 9d5eb91175c5ddb601ec24d3249ad23e81f92619 Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Mon, 7 Apr 2025 13:18:46 +0200 +Subject: [PATCH 5000/5007] bfd: properly use bfd_get_symbol_leading_char() in + peXXigen + +This function returns the leading char to use, so we cannot just assume +it will always be '_' or '\0'. + +Signed-off-by: Jeremy Drake +--- + bfd/peXXigen.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index 29012688adf..561f8585766 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -4403,6 +4403,7 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + struct coff_link_hash_entry *h1; + struct bfd_link_info *info = pfinfo->info; + bool result = true; ++ char name[20]; + + /* There are a few fields that need to be filled in now while we + have symbol table access. +@@ -4540,10 +4541,9 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + } + } + +- h1 = coff_link_hash_lookup (coff_hash_table (info), +- (bfd_get_symbol_leading_char (abfd) != 0 +- ? "__tls_used" : "_tls_used"), +- false, false, true); ++ name[0] = bfd_get_symbol_leading_char (abfd); ++ strcpy (name + !!name[0], "_tls_used"); ++ h1 = coff_link_hash_lookup (coff_hash_table (info), name, false, false, true); + if (h1 != NULL) + { + if ((h1->root.type == bfd_link_hash_defined +@@ -4558,8 +4558,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[9] because __tls_used is missing"), +- abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), ++ abfd, PE_TLS_TABLE, name); + result = false; + } + /* According to PECOFF sepcifications by Microsoft version 8.2 +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5001-bfd-adjust-a-few-error-messages.patch b/mingw-w64-binutils/5001-bfd-adjust-a-few-error-messages.patch new file mode 100644 index 0000000000..7429af18d7 --- /dev/null +++ b/mingw-w64-binutils/5001-bfd-adjust-a-few-error-messages.patch @@ -0,0 +1,76 @@ +From 75fde30d74a8d415cc8f642d3c560079245c1ca3 Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Mon, 7 Apr 2025 13:19:10 +0200 +Subject: [PATCH 5001/5007] bfd: adjust a few error messages + +Rationalize the error messages in _bfd_XXi_final_link_postscript(). +They now all correctly refer to DataDirectory instead of DataDictionary, +and use unified format strings, so fewer translations are needed. + +Signed-off-by: Jeremy Drake +--- + bfd/peXXigen.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index 561f8585766..7ca57831a94 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -4431,8 +4431,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[1] because .idata$2 is missing"), +- abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), ++ abfd, PE_IMPORT_TABLE, ".idata$2"); + result = false; + } + +@@ -4451,8 +4451,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[1] because .idata$4 is missing"), +- abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), ++ abfd, PE_IMPORT_TABLE, ".idata$4"); + result = false; + } + +@@ -4472,8 +4472,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[12] because .idata$5 is missing"), +- abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), ++ abfd, PE_IMPORT_ADDRESS_TABLE, ".idata$5"); + result = false; + } + +@@ -4492,8 +4492,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE (12)] because .idata$6 is missing"), +- abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s is missing"), ++ abfd, PE_IMPORT_ADDRESS_TABLE, ".idata$6"); + result = false; + } + } +@@ -4534,8 +4534,8 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + else + { + _bfd_error_handler +- (_("%pB: unable to fill in DataDictionary[PE_IMPORT_ADDRESS_TABLE(12)]" +- " because .idata$6 is missing"), abfd); ++ (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), ++ abfd, PE_IMPORT_ADDRESS_TABLE, "__IAT_end__"); + result = false; + } + } +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5002-bfd-fill-in-PE-load-config-directory-entry.patch b/mingw-w64-binutils/5002-bfd-fill-in-PE-load-config-directory-entry.patch new file mode 100644 index 0000000000..69be36b784 --- /dev/null +++ b/mingw-w64-binutils/5002-bfd-fill-in-PE-load-config-directory-entry.patch @@ -0,0 +1,119 @@ +From 8df2060980184a5762d774d95425c6fccaaba382 Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Mon, 7 Apr 2025 13:19:19 +0200 +Subject: [PATCH 5002/5007] bfd: fill in PE load config directory entry + +This is filled in with the rva of _load_config_used if defined (much +like _tls_used), and the size is the first 32-bit value at that symbol. + +Signed-off-by: Jeremy Drake +--- + bfd/peXXigen.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 70 insertions(+), 1 deletion(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index 7ca57831a94..f63a7b6f11a 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -593,7 +593,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out; + bfd_vma sa, fa, ib; +- IMAGE_DATA_DIRECTORY idata2, idata5, tls; ++ IMAGE_DATA_DIRECTORY idata2, idata5, tls, loadcfg; + + sa = extra->SectionAlignment; + fa = extra->FileAlignment; +@@ -602,6 +602,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE]; + idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE]; + tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE]; ++ loadcfg = pe->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE]; + + if (aouthdr_in->tsize) + { +@@ -651,6 +652,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + extra->DataDirectory[PE_IMPORT_TABLE] = idata2; + extra->DataDirectory[PE_IMPORT_ADDRESS_TABLE] = idata5; + extra->DataDirectory[PE_TLS_TABLE] = tls; ++ extra->DataDirectory[PE_LOAD_CONFIG_TABLE] = loadcfg; + + if (extra->DataDirectory[PE_IMPORT_TABLE].VirtualAddress == 0) + /* Until other .idata fixes are made (pending patch), the entry for +@@ -4573,6 +4575,73 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + #endif + } + ++ name[0] = bfd_get_symbol_leading_char (abfd); ++ strcpy (name + !!name[0], "_load_config_used"); ++ h1 = coff_link_hash_lookup (coff_hash_table (info), name, false, false, true); ++ if (h1 != NULL) ++ { ++ char data[4]; ++ if ((h1->root.type == bfd_link_hash_defined ++ || h1->root.type == bfd_link_hash_defweak) ++ && h1->root.u.def.section != NULL ++ && h1->root.u.def.section->output_section != NULL) ++ { ++ pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].VirtualAddress = ++ (h1->root.u.def.value ++ + h1->root.u.def.section->output_section->vma ++ + h1->root.u.def.section->output_offset ++ - pe_data (abfd)->pe_opthdr.ImageBase); ++ ++ if (pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].VirtualAddress ++ & (bfd_arch_bits_per_address (abfd) / bfd_arch_bits_per_byte (abfd) ++ - 1)) ++ { ++ _bfd_error_handler ++ (_("%pB: unable to fill in DataDirectory[%d]: %s not properly aligned"), ++ abfd, PE_LOAD_CONFIG_TABLE, name); ++ result = false; ++ } ++ ++ /* The size is stored as the first 4 bytes at _load_config_used. ++ The Microsoft PE format documentation says for compatibility with ++ Windows XP and earlier, the size must be 64 for x86 images. If ++ anyone cares about those versions, the size should be overridden ++ for i386. */ ++ if (bfd_get_section_contents (abfd, ++ h1->root.u.def.section->output_section, data, ++ h1->root.u.def.section->output_offset + h1->root.u.def.value, ++ 4)) ++ { ++ pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].Size ++ = bfd_get_32 (abfd, data); ++ ++ if ((bfd_vma) pe_data (abfd)->pe_opthdr ++ .DataDirectory[PE_LOAD_CONFIG_TABLE].Size ++ > h1->root.u.def.section->size - h1->root.u.def.value) ++ { ++ _bfd_error_handler ++ (_("%pB: unable to fill in DataDirectory[%d]: size too large for the containing section"), ++ abfd, PE_LOAD_CONFIG_TABLE); ++ result = false; ++ } ++ } ++ else ++ { ++ _bfd_error_handler ++ (_("%pB: unable to fill in DataDirectory[%d]: size can't be read from %s"), ++ abfd, PE_LOAD_CONFIG_TABLE, name); ++ result = false; ++ } ++ } ++ else ++ { ++ _bfd_error_handler ++ (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), ++ abfd, PE_LOAD_CONFIG_TABLE, name); ++ result = false; ++ } ++ } ++ + /* If there is a .pdata section and we have linked pdata finally, we + need to sort the entries ascending. */ + #if !defined(COFF_WITH_pep) && (defined(COFF_WITH_pex64) || defined(COFF_WITH_peAArch64) || defined(COFF_WITH_peLoongArch64) || defined (COFF_WITH_peRiscV64)) +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch b/mingw-w64-binutils/5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch new file mode 100644 index 0000000000..2725e3bd86 --- /dev/null +++ b/mingw-w64-binutils/5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch @@ -0,0 +1,64 @@ +From eb4f86f44322c7969e01fe41597a26fbbf033dab Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Mon, 7 Apr 2025 13:19:28 +0200 +Subject: [PATCH 5003/5007] bfd: add load config size workaround for i386 XP + and earlier + +Per the Microsoft PE documentation, XP and earlier on i686 require the +Size field to be 64, rather than the actual size as required on other +architectures. I have confirmed Windows 11 accepts either 64 or the +actual size for i386 images, but only the actual size for x86_64 images. + +Signed-off-by: Jeremy Drake +--- + bfd/peXXigen.c | 28 ++++++++++++++++++---------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index f63a7b6f11a..9938108ce6b 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -4602,22 +4602,30 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + result = false; + } + +- /* The size is stored as the first 4 bytes at _load_config_used. +- The Microsoft PE format documentation says for compatibility with +- Windows XP and earlier, the size must be 64 for x86 images. If +- anyone cares about those versions, the size should be overridden +- for i386. */ ++ /* The size is stored as the first 4 bytes at _load_config_used. */ + if (bfd_get_section_contents (abfd, + h1->root.u.def.section->output_section, data, + h1->root.u.def.section->output_offset + h1->root.u.def.value, + 4)) + { ++ uint32_t size = bfd_get_32 (abfd, data); ++ /* The Microsoft PE format documentation says for compatibility ++ with Windows XP and earlier, the size must be 64 for x86 ++ images. */ + pe_data (abfd)->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE].Size +- = bfd_get_32 (abfd, data); +- +- if ((bfd_vma) pe_data (abfd)->pe_opthdr +- .DataDirectory[PE_LOAD_CONFIG_TABLE].Size +- > h1->root.u.def.section->size - h1->root.u.def.value) ++ = (bfd_get_arch (abfd) == bfd_arch_i386 ++ && ((bfd_get_mach (abfd) & ~bfd_mach_i386_intel_syntax) ++ == bfd_mach_i386_i386) ++ && ((pe_data (abfd)->pe_opthdr.Subsystem ++ == IMAGE_SUBSYSTEM_WINDOWS_GUI) ++ || (pe_data (abfd)->pe_opthdr.Subsystem ++ == IMAGE_SUBSYSTEM_WINDOWS_CUI)) ++ && (pe_data (abfd)->pe_opthdr.MajorSubsystemVersion * 256 ++ + pe_data (abfd)->pe_opthdr.MinorSubsystemVersion ++ <= 0x0501)) ++ ? 64 : size; ++ ++ if (size > h1->root.u.def.section->size - h1->root.u.def.value) + { + _bfd_error_handler + (_("%pB: unable to fill in DataDirectory[%d]: size too large for the containing section"), +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch b/mingw-w64-binutils/5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch new file mode 100644 index 0000000000..81a1d36666 --- /dev/null +++ b/mingw-w64-binutils/5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch @@ -0,0 +1,573 @@ +From 31ed2c87d3ef91159f8262e93ea24cc75722b9ab Mon Sep 17 00:00:00 2001 +From: LIU Hao +Date: Fri, 13 Jun 2025 07:52:29 +0200 +Subject: [PATCH 5004/5007] bfd,ld,dlltool: Emit delay-load import data into + its own section + +A delay-import symbol (of a function) is resolved when a call to it is made. +The delay loader may overwrite the `__imp_` pointer to the actual function +after it has been resolved, which requires the pointer itself be in a +writeable section. + +Previously it was placed in the ordinary Import Address Table (IAT), which +is emitted into the `.idata` section, which had been changed to read-only +in db00f6c3aceabbf03acdb69e74b59b2d2b043cd7, which caused segmentation +faults when functions from delay-import library were called. This is +PR 32675. + +This commit makes DLLTOOL emit delay-import IAT into `.didat`, as specified +by Microsoft. Most of the code is copied from `.idata`, except that this +section is writeable. As a side-effect of this, PR 14339 is also fixed. + +Using this DEF: + + ``` + ; ws2_32.def + LIBRARY "WS2_32.DLL" + EXPORTS + WSAGetLastError + ``` + +and this C program: + + ``` + // delay.c + #define WIN32_LEAN_AND_MEAN 1 + #include + #include + + ///////////////////////////////////////////////////////// + // User code + ///////////////////////////////////////////////////////// + + DWORD WINAPI WSAGetLastError(void); + extern PVOID __imp_WSAGetLastError; + + int + main(void) + { + fprintf(stderr, "before delay load, __imp_WSAGetLastError = %p\n", __imp_WSAGetLastError); + SetLastError(123); + fprintf(stderr, "WSAGetLastError() = %d\n", WSAGetLastError()); + fprintf(stderr, "after delay load, __imp_WSAGetLastError = %p\n", __imp_WSAGetLastError); + __imp_WSAGetLastError = (PVOID) 1234567; + fprintf(stderr, "after plain write, __imp_WSAGetLastError = %p\n", __imp_WSAGetLastError); + } + + ///////////////////////////////////////////////////////// + // Overridden `__delayLoadHelper2` facility + ///////////////////////////////////////////////////////// + + extern char __ImageBase[]; + PVOID WINAPI ResolveDelayLoadedAPI(PVOID ParentModuleBase, LPCVOID DelayloadDescriptor, + PVOID FailureDllHook, PVOID FailureSystemHook, + FARPROC* ThunkAddress, ULONG Flags); + FARPROC WINAPI DelayLoadFailureHook(LPCSTR name, LPCSTR function); + + FARPROC WINAPI __delayLoadHelper2(LPCVOID pidd, FARPROC* ppfnIATEntry) + { + return ResolveDelayLoadedAPI(&__ImageBase, pidd, NULL, (PVOID) DelayLoadFailureHook, + ppfnIATEntry, 0); + } + ``` + +This program used to crash: + + ``` + $ dlltool -nn -d ws2_32.def -y delay_ws2_32.a + $ gcc -g delay.c delay_ws2_32.a -o delay.exe + $ ./delay.exe + before delay load, __imp_WSAGetLastError = 00007FF6937215C6 + Segmentation fault + ``` + +After this commit, it loads and calls `WSAGetLastError()` properly, and +`__imp_WSAGetLastError` is writeable: + + ``` + $ dlltool -nn -d ws2_32.def -y delay_ws2_32.a + $ gcc -g delay.c delay_ws2_32.a -o delay.exe + $ ./delay.exe + before delay load, __imp_WSAGetLastError = 00007FF76E2215C6 + WSAGetLastError() = 123 + after delay load, __imp_WSAGetLastError = 00007FFF191FA720 + after plain write, __imp_WSAGetLastError = 000000000012D687 + ``` + +Reference: https://learn.microsoft.com/en-us/windows/win32/secbp/pe-metadata#import-handling +Co-authored-by: Jeremy Drake +Signed-off-by: LIU Hao +Signed-off-by: Jeremy Drake +--- + bfd/coffgen.c | 15 +++++++++ + bfd/pe-aarch64.c | 2 ++ + bfd/pe-arm.c | 2 ++ + bfd/pe-i386.c | 2 ++ + bfd/pe-x86_64.c | 2 ++ + bfd/peXXigen.c | 1 + + bfd/pei-aarch64.c | 2 ++ + bfd/pei-arm.c | 2 ++ + bfd/pei-i386.c | 2 ++ + bfd/pei-loongarch64.c | 2 ++ + bfd/pei-riscv64.c | 2 ++ + bfd/pei-x86_64.c | 2 ++ + bfd/syms.c | 1 + + binutils/dlltool.c | 76 +++++++++++++++++++++++++++++++++++++++---- + ld/scripttempl/pe.sc | 26 ++++++++++++++- + ld/scripttempl/pep.sc | 27 ++++++++++++++- + 16 files changed, 158 insertions(+), 8 deletions(-) + +diff --git a/bfd/coffgen.c b/bfd/coffgen.c +index d8c60e26342..8a01b7fdef8 100644 +--- a/bfd/coffgen.c ++++ b/bfd/coffgen.c +@@ -43,6 +43,7 @@ + #include "coff/internal.h" + #include "libcoff.h" + #include "hashtab.h" ++#include "safe-ctype.h" + + /* Extract a long section name at STRINDEX and copy it to the bfd objstack. + Return NULL in case of error. */ +@@ -3099,6 +3100,19 @@ coff_gc_sweep_symbol (struct coff_link_hash_entry *h, + typedef bool (*gc_sweep_hook_fn) + (bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); + ++static inline bool ++is_subsection (const char *str, const char *prefix) ++{ ++ size_t n = strlen (prefix); ++ if (strncmp (str, prefix, n) != 0) ++ return false; ++ if (str[n] == 0) ++ return true; ++ else if (str[n] != '$') ++ return false; ++ return ISDIGIT (str[n + 1]) && str[n + 2] == 0; ++} ++ + static bool + coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) + { +@@ -3120,6 +3134,7 @@ coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) + else if (startswith (o->name, ".idata") + || startswith (o->name, ".pdata") + || startswith (o->name, ".xdata") ++ || is_subsection (o->name, ".didat") + || startswith (o->name, ".rsrc")) + o->gc_mark = 1; + +diff --git a/bfd/pe-aarch64.c b/bfd/pe-aarch64.c +index 64975d19f67..2204a51c509 100644 +--- a/bfd/pe-aarch64.c ++++ b/bfd/pe-aarch64.c +@@ -48,6 +48,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pe-arm.c b/bfd/pe-arm.c +index fe4e18e7e06..5efa559a353 100644 +--- a/bfd/pe-arm.c ++++ b/bfd/pe-arm.c +@@ -43,6 +43,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pe-i386.c b/bfd/pe-i386.c +index 07f674342cf..3742fd8feb4 100644 +--- a/bfd/pe-i386.c ++++ b/bfd/pe-i386.c +@@ -36,6 +36,8 @@ + #define COFF_SECTION_ALIGNMENT_ENTRIES \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pe-x86_64.c b/bfd/pe-x86_64.c +index d56d75dabd0..9151aac5792 100644 +--- a/bfd/pe-x86_64.c ++++ b/bfd/pe-x86_64.c +@@ -57,6 +57,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index 9938108ce6b..7dfa82ee43e 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -1001,6 +1001,7 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out) + { ".arch", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_8BYTES }, + { ".bss", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".data", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, ++ { ".didat", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".edata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { ".idata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { ".pdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, +diff --git a/bfd/pei-aarch64.c b/bfd/pei-aarch64.c +index 3d7f5b376a6..00f38e0f9bb 100644 +--- a/bfd/pei-aarch64.c ++++ b/bfd/pei-aarch64.c +@@ -49,6 +49,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pei-arm.c b/bfd/pei-arm.c +index 2abc14de025..07cebb510ef 100644 +--- a/bfd/pei-arm.c ++++ b/bfd/pei-arm.c +@@ -45,6 +45,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pei-i386.c b/bfd/pei-i386.c +index 676a824877b..a26f1702b3b 100644 +--- a/bfd/pei-i386.c ++++ b/bfd/pei-i386.c +@@ -35,6 +35,8 @@ + #define COFF_SECTION_ALIGNMENT_ENTRIES \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pei-loongarch64.c b/bfd/pei-loongarch64.c +index 4b3a30d4ddc..f22498cab21 100644 +--- a/bfd/pei-loongarch64.c ++++ b/bfd/pei-loongarch64.c +@@ -49,6 +49,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pei-riscv64.c b/bfd/pei-riscv64.c +index e87aa429350..c4ae7bfb89a 100644 +--- a/bfd/pei-riscv64.c ++++ b/bfd/pei-riscv64.c +@@ -49,6 +49,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c +index 3f8f255af33..a5c2fd85f06 100644 +--- a/bfd/pei-x86_64.c ++++ b/bfd/pei-x86_64.c +@@ -51,6 +51,8 @@ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".idata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ ++{ COFF_SECTION_NAME_PARTIAL_MATCH (".didat"), \ ++ COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_EXACT_MATCH (".pdata"), \ + COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 2 }, \ + { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \ +diff --git a/bfd/syms.c b/bfd/syms.c +index 95017ba4f11..df2229b3fa3 100644 +--- a/bfd/syms.c ++++ b/bfd/syms.c +@@ -594,6 +594,7 @@ struct section_to_type + adding entries. Since it is so short, a linear search is used. */ + static const struct section_to_type stt[] = + { ++ {".didat", 'i'}, /* MSVC's .didat (delay import) section */ + {".drectve", 'i'}, /* MSVC's .drective section */ + {".edata", 'e'}, /* MSVC's .edata (export) section */ + {".idata", 'i'}, /* MSVC's .idata (import) section */ +diff --git a/binutils/dlltool.c b/binutils/dlltool.c +index d32bf2062b4..371d61fc484 100644 +--- a/binutils/dlltool.c ++++ b/binutils/dlltool.c +@@ -2268,7 +2268,7 @@ typedef struct + #define DATA_SEC_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_DATA) + #define BSS_SEC_FLAGS SEC_ALLOC + +-static sinfo secdata[NSECS] = ++static sinfo secdata_plain[NSECS] = + { + INIT_SEC_DATA (TEXT, ".text", TEXT_SEC_FLAGS, 2), + INIT_SEC_DATA (DATA, ".data", DATA_SEC_FLAGS, 2), +@@ -2279,6 +2279,17 @@ static sinfo secdata[NSECS] = + INIT_SEC_DATA (IDATA6, ".idata$6", SEC_HAS_CONTENTS, 1) + }; + ++static sinfo secdata_delay[NSECS] = ++{ ++ INIT_SEC_DATA (TEXT, ".text", TEXT_SEC_FLAGS, 2), ++ INIT_SEC_DATA (DATA, ".data", DATA_SEC_FLAGS, 2), ++ INIT_SEC_DATA (BSS, ".bss", BSS_SEC_FLAGS, 2), ++ INIT_SEC_DATA (IDATA7, ".didat$7", SEC_HAS_CONTENTS, 2), ++ INIT_SEC_DATA (IDATA5, ".didat$5", SEC_HAS_CONTENTS, 2), ++ INIT_SEC_DATA (IDATA4, ".didat$4", SEC_HAS_CONTENTS, 2), ++ INIT_SEC_DATA (IDATA6, ".didat$6", SEC_HAS_CONTENTS, 1) ++}; ++ + /* This is what we're trying to make. We generate the imp symbols with + both single and double underscores, for compatibility. + +@@ -2341,6 +2352,7 @@ make_imp_label (const char *prefix, const char *name) + static bfd * + make_one_lib_file (export_type *exp, int i, int delay) + { ++ sinfo *const secdata = delay ? secdata_delay : secdata_plain; + char *outname = TMP_STUB; + size_t name_len = strlen (outname); + sprintf (outname + name_len - 7, "%05d.o", i); +@@ -2835,7 +2847,7 @@ make_delay_head (void) + + if (!no_idata5) + { +- fprintf (f, "\t.section\t.idata$5\n"); ++ fprintf (f, "\t.section\t.didat$5\n"); + /* NULL terminating list. */ + if (create_for_pep) + fprintf (f, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); +@@ -2846,15 +2858,15 @@ make_delay_head (void) + + if (!no_idata4) + { +- fprintf (f, "\t.section\t.idata$4\n"); ++ fprintf (f, "\t.section\t.didat$4\n"); + fprintf (f, "\t%s\t0\n", ASM_LONG); + if (create_for_pep) + fprintf (f, "\t%s\t0\n", ASM_LONG); +- fprintf (f, "\t.section\t.idata$4\n"); ++ fprintf (f, "\t.section\t.didat$4\n"); + fprintf (f, "__INT_%s:\n", imp_name_lab); + } + +- fprintf (f, "\t.section\t.idata$2\n"); ++ fprintf (f, "\t.section\t.didat$2\n"); + + fclose (f); + +@@ -2921,6 +2933,57 @@ make_tail (void) + return abfd; + } + ++static bfd * ++make_delay_tail (void) ++{ ++ FILE *f = fopen (TMP_TAIL_S, FOPEN_WT); ++ bfd *abfd; ++ ++ if (f == NULL) ++ { ++ fatal (_("failed to open temporary tail file: %s"), TMP_TAIL_S); ++ return NULL; ++ } ++ ++ temp_file_to_remove[TEMP_TAIL_FILE] = TMP_TAIL_S; ++ ++ if (!no_idata4) ++ { ++ fprintf (f, "\t.section\t.didat$4\n"); ++ if (create_for_pep) ++ fprintf (f, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); ++ else ++ fprintf (f, "\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ ++ } ++ ++ if (!no_idata5) ++ { ++ fprintf (f, "\t.section\t.didat$5\n"); ++ if (create_for_pep) ++ fprintf (f, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); ++ else ++ fprintf (f, "\t%s\t0\n", ASM_LONG); /* NULL terminating list. */ ++ } ++ ++ fprintf (f, "\t.section\t.didat$7\n"); ++ fprintf (f, "\t%s\t__%s_iname\n", ASM_GLOBAL, imp_name_lab); ++ fprintf (f, "__%s_iname:\t%s\t\"%s\"\n", ++ imp_name_lab, ASM_TEXT, dll_name); ++ ++ fclose (f); ++ ++ assemble_file (TMP_TAIL_S, TMP_TAIL_O); ++ ++ abfd = bfd_openr (TMP_TAIL_O, HOW_BFD_READ_TARGET); ++ if (abfd == NULL) ++ /* xgettext:c-format */ ++ fatal (_("failed to open temporary tail file: %s: %s"), ++ TMP_TAIL_O, bfd_get_errmsg ()); ++ ++ temp_file_to_remove[TEMP_TAIL_O_FILE] = TMP_TAIL_O; ++ return abfd; ++} ++ + static void + gen_lib_file (int delay) + { +@@ -2956,12 +3019,13 @@ gen_lib_file (int delay) + if (delay) + { + ar_head = make_delay_head (); ++ ar_tail = make_delay_tail(); + } + else + { + ar_head = make_head (); ++ ar_tail = make_tail(); + } +- ar_tail = make_tail(); + + if (ar_head == NULL || ar_tail == NULL) + return; +diff --git a/ld/scripttempl/pe.sc b/ld/scripttempl/pe.sc +index 96a47515444..108c6fb2cdf 100644 +--- a/ld/scripttempl/pe.sc ++++ b/ld/scripttempl/pe.sc +@@ -14,7 +14,7 @@ fi + # substitution, so we do this instead. + # Sorting of the .foo$* sections is required by the definition of + # grouped sections in PE. +-# Sorting of the file names in R_IDATA is required by the ++# Sorting of the file names in R_IDATA and R_DIDAT is required by the + # current implementation of dlltool (this could probably be changed to + # use grouped sections instead). + if test "${RELOCATING}"; then +@@ -39,6 +39,18 @@ if test "${RELOCATING}"; then + R_IDATA67=' + KEEP (SORT(*)(.idata$6)) + KEEP (SORT(*)(.idata$7))' ++ R_DIDAT234=' ++ __DELAY_IMPORT_DIRECTORY_start__ = .; ++ KEEP (SORT(*)(.didat$2)) ++ KEEP (SORT(*)(.didat$3)) ++ __DELAY_IMPORT_DIRECTORY_end__ = .; ++ /* These zeroes mark the end of the import list. */ ++ . += (__DELAY_IMPORT_DIRECTORY_end__ - __DELAY_IMPORT_DIRECTORY_start__) ? 8*4 : 0; ++ KEEP (SORT(*)(.didat$4))' ++ R_DIDAT5='KEEP (SORT(*)(.didat$5))' ++ R_DIDAT67=' ++ KEEP (SORT(*)(.didat$6)) ++ KEEP (SORT(*)(.didat$7))' + R_CRT_XC='KEEP (*(SORT(.CRT$XC*))) /* C initialization */' + R_CRT_XI='KEEP (*(SORT(.CRT$XI*))) /* C++ initialization */' + R_CRT_XL='KEEP (*(SORT(.CRT$XL*))) /* TLS callbacks */' +@@ -61,6 +73,9 @@ else + R_IDATA234= + R_IDATA5= + R_IDATA67= ++ R_DIDAT234= ++ R_DIDAT5= ++ R_DIDAT67= + R_CRT_XC= + R_CRT_XI= + R_CRT_XL= +@@ -244,6 +259,15 @@ SECTIONS + ${R_IDATA67} + } + ++ .didat ${RELOCATING+BLOCK(__section_alignment__)} : ++ { ++ /* This cannot currently be handled with grouped sections. ++ See pe.em:sort_sections. */ ++ ${R_DIDAT234} ++ ${R_DIDAT5} ++ ${R_DIDAT67} ++ } ++ + /* Windows TLS expects .tls\$AAA to be at the start and .tls\$ZZZ to be + at the end of section. This is important because _tls_start MUST + be at the beginning of the section to enable SECREL32 relocations with TLS +diff --git a/ld/scripttempl/pep.sc b/ld/scripttempl/pep.sc +index e2c6c2cedd2..f508ebe5585 100644 +--- a/ld/scripttempl/pep.sc ++++ b/ld/scripttempl/pep.sc +@@ -14,7 +14,7 @@ fi + # substitution, so we do this instead. + # Sorting of the .foo$* sections is required by the definition of + # grouped sections in PE. +-# Sorting of the file names in R_IDATA is required by the ++# Sorting of the file names in R_IDATA and R_DIDAT is required by the + # current implementation of dlltool (this could probably be changed to + # use grouped sections instead). + if test "${RELOCATING}"; then +@@ -40,6 +40,19 @@ if test "${RELOCATING}"; then + R_IDATA67=' + KEEP (SORT(*)(.idata$6)) + KEEP (SORT(*)(.idata$7))' ++ R_DIDAT234=' ++ __DELAY_IMPORT_DIRECTORY_start__ = .; ++ KEEP (SORT(*)(.didat$2)) ++ KEEP (SORT(*)(.didat$3)) ++ __DELAY_IMPORT_DIRECTORY_end__ = .; ++ /* These zeroes mark the end of the import list. */ ++ . += (__DELAY_IMPORT_DIRECTORY_end__ - __DELAY_IMPORT_DIRECTORY_start__) ? 8*4 : 0; ++ . = ALIGN(8); ++ KEEP (SORT(*)(.didat$4))' ++ R_DIDAT5='SORT(*)(.didat$5)' ++ R_DIDAT67=' ++ KEEP (SORT(*)(.didat$6)) ++ KEEP (SORT(*)(.didat$7))' + R_CRT_XC='KEEP (*(SORT(.CRT$XC*))) /* C initialization */' + R_CRT_XI='KEEP (*(SORT(.CRT$XI*))) /* C++ initialization */' + R_CRT_XL='KEEP (*(SORT(.CRT$XL*))) /* TLS callbacks */' +@@ -62,6 +75,9 @@ else + R_IDATA234= + R_IDATA5= + R_IDATA67= ++ R_DIDAT234= ++ R_DIDAT5= ++ R_DIDAT67= + R_CRT_XC= + R_CRT_XI= + R_CRT_XL= +@@ -251,6 +267,15 @@ SECTIONS + ${R_IDATA67} + } + ++ .didat ${RELOCATING+BLOCK(__section_alignment__)} : ++ { ++ /* This cannot currently be handled with grouped sections. ++ See pep.em:sort_sections. */ ++ ${R_DIDAT234} ++ ${R_DIDAT5} ++ ${R_DIDAT67} ++ } ++ + /* Windows TLS expects .tls\$AAA to be at the start and .tls\$ZZZ to be + at the end of the .tls section. This is important because _tls_start MUST + be at the beginning of the section to enable SECREL32 relocations with TLS +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch b/mingw-w64-binutils/5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch new file mode 100644 index 0000000000..2535dd7cdc --- /dev/null +++ b/mingw-w64-binutils/5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch @@ -0,0 +1,99 @@ +From 247eb6f63e697b30b42c9c3df6d6a2c99525f4e2 Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Fri, 13 Jun 2025 07:52:47 +0200 +Subject: [PATCH 5005/5007] ld,dlltool: move read-only delayimp data into + .rdata + +This allows the delay IAT to be in its own section with nothing else, as +required by IMAGE_GUARD_DELAYLOAD_IAT_IN_ITS_OWN_SECTION, documented at +https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#load-configuration-layout + +Signed-off-by: Jeremy Drake +--- + binutils/dlltool.c | 5 +---- + ld/scripttempl/pe.sc | 7 +++++-- + ld/scripttempl/pep.sc | 8 ++++++-- + 3 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/binutils/dlltool.c b/binutils/dlltool.c +index 371d61fc484..5b038dba8c5 100644 +--- a/binutils/dlltool.c ++++ b/binutils/dlltool.c +@@ -2819,7 +2819,7 @@ make_delay_head (void) + + /* Output the delay import descriptor */ + fprintf (f, "\n%s DELAY_IMPORT_DESCRIPTOR\n", ASM_C); +- fprintf (f, ".section\t.text$2\n"); ++ fprintf (f, ".section\t.didat$2\n"); + fprintf (f, "%s __DELAY_IMPORT_DESCRIPTOR_%s\n", ASM_GLOBAL,imp_name_lab); + fprintf (f, "__DELAY_IMPORT_DESCRIPTOR_%s:\n", imp_name_lab); + fprintf (f, "\t%s 1\t%s grAttrs\n", ASM_LONG, ASM_C); +@@ -2862,12 +2862,9 @@ make_delay_head (void) + fprintf (f, "\t%s\t0\n", ASM_LONG); + if (create_for_pep) + fprintf (f, "\t%s\t0\n", ASM_LONG); +- fprintf (f, "\t.section\t.didat$4\n"); + fprintf (f, "__INT_%s:\n", imp_name_lab); + } + +- fprintf (f, "\t.section\t.didat$2\n"); +- + fclose (f); + + assemble_file (TMP_HEAD_S, TMP_HEAD_O); +diff --git a/ld/scripttempl/pe.sc b/ld/scripttempl/pe.sc +index 108c6fb2cdf..8fb98b2c06e 100644 +--- a/ld/scripttempl/pe.sc ++++ b/ld/scripttempl/pe.sc +@@ -146,6 +146,11 @@ SECTIONS + ${RELOCATING+__rt_psrelocs_start = .;} + ${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))} + ${RELOCATING+__rt_psrelocs_end = .;} ++ /* read-only parts of .didat */ ++ /* This cannot currently be handled with grouped sections. ++ See pe.em:sort_sections. */ ++ ${R_DIDAT234} ++ ${R_DIDAT67} + + /* .ctors & .dtors */ + ${CONSTRUCTING+ +@@ -263,9 +268,7 @@ SECTIONS + { + /* This cannot currently be handled with grouped sections. + See pe.em:sort_sections. */ +- ${R_DIDAT234} + ${R_DIDAT5} +- ${R_DIDAT67} + } + + /* Windows TLS expects .tls\$AAA to be at the start and .tls\$ZZZ to be +diff --git a/ld/scripttempl/pep.sc b/ld/scripttempl/pep.sc +index f508ebe5585..841ee352f73 100644 +--- a/ld/scripttempl/pep.sc ++++ b/ld/scripttempl/pep.sc +@@ -148,6 +148,12 @@ SECTIONS + ${RELOCATING+__rt_psrelocs_start = .;} + ${RELOCATING+KEEP(*(.rdata_runtime_pseudo_reloc))} + ${RELOCATING+__rt_psrelocs_end = .;} ++ /* read-only parts of .didat */ ++ /* This cannot currently be handled with grouped sections. ++ See pe.em:sort_sections. */ ++ ${RELOCATING+. = ALIGN(8);} ++ ${R_DIDAT234} ++ ${R_DIDAT67} + + /* .ctors & .dtors */ + ${CONSTRUCTING+. = ALIGN(8);} +@@ -271,9 +277,7 @@ SECTIONS + { + /* This cannot currently be handled with grouped sections. + See pep.em:sort_sections. */ +- ${R_DIDAT234} + ${R_DIDAT5} +- ${R_DIDAT67} + } + + /* Windows TLS expects .tls\$AAA to be at the start and .tls\$ZZZ to be +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch b/mingw-w64-binutils/5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch new file mode 100644 index 0000000000..41c8a06610 --- /dev/null +++ b/mingw-w64-binutils/5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch @@ -0,0 +1,54 @@ +From 592388aa50a52fb6c82002cd89e98d607680ab7c Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Fri, 13 Jun 2025 07:53:07 +0200 +Subject: [PATCH 5006/5007] dlltool: respect use-nul-prefixed-import-tables + option for delaylib + +Noticed the extra zeros while inspecting the output. + +Signed-off-by: Jeremy Drake +--- + binutils/dlltool.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/binutils/dlltool.c b/binutils/dlltool.c +index 5b038dba8c5..d161140b1ba 100644 +--- a/binutils/dlltool.c ++++ b/binutils/dlltool.c +@@ -2848,20 +2848,25 @@ make_delay_head (void) + if (!no_idata5) + { + fprintf (f, "\t.section\t.didat$5\n"); +- /* NULL terminating list. */ +- if (create_for_pep) +- fprintf (f, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); +- else +- fprintf (f, "\t%s\t0\n", ASM_LONG); ++ if (use_nul_prefixed_import_tables) ++ { ++ if (create_for_pep) ++ fprintf (f, "\t%s\t0\n\t%s\t0\n", ASM_LONG, ASM_LONG); ++ else ++ fprintf (f, "\t%s\t0\n", ASM_LONG); ++ } + fprintf (f, "__IAT_%s:\n", imp_name_lab); + } + + if (!no_idata4) + { + fprintf (f, "\t.section\t.didat$4\n"); +- fprintf (f, "\t%s\t0\n", ASM_LONG); +- if (create_for_pep) +- fprintf (f, "\t%s\t0\n", ASM_LONG); ++ if (use_nul_prefixed_import_tables) ++ { ++ fprintf (f, "\t%s\t0\n", ASM_LONG); ++ if (create_for_pep) ++ fprintf (f, "\t%s\t0\n", ASM_LONG); ++ } + fprintf (f, "__INT_%s:\n", imp_name_lab); + } + +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/5007-bfd-populate-delay-import-directory-in-PE-header.patch b/mingw-w64-binutils/5007-bfd-populate-delay-import-directory-in-PE-header.patch new file mode 100644 index 0000000000..654efb8dc5 --- /dev/null +++ b/mingw-w64-binutils/5007-bfd-populate-delay-import-directory-in-PE-header.patch @@ -0,0 +1,98 @@ +From 175d5bf58d1c1f0fe6bdc75afd0cc98eb39f24ba Mon Sep 17 00:00:00 2001 +From: Jeremy Drake +Date: Fri, 13 Jun 2025 07:53:24 +0200 +Subject: [PATCH 5007/5007] bfd: populate delay import directory in PE header + +Previously, the delay import table was constructed but its rva and size +were never put into the PE optional header. + +Signed-off-by: Jeremy Drake +--- + bfd/peXXigen.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 49 insertions(+), 1 deletion(-) + +diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c +index 7dfa82ee43e..19f38a4ac1b 100644 +--- a/bfd/peXXigen.c ++++ b/bfd/peXXigen.c +@@ -593,7 +593,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; + PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out; + bfd_vma sa, fa, ib; +- IMAGE_DATA_DIRECTORY idata2, idata5, tls, loadcfg; ++ IMAGE_DATA_DIRECTORY idata2, idata5, didat2, tls, loadcfg; + + sa = extra->SectionAlignment; + fa = extra->FileAlignment; +@@ -601,6 +601,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + + idata2 = pe->pe_opthdr.DataDirectory[PE_IMPORT_TABLE]; + idata5 = pe->pe_opthdr.DataDirectory[PE_IMPORT_ADDRESS_TABLE]; ++ didat2 = pe->pe_opthdr.DataDirectory[PE_DELAY_IMPORT_DESCRIPTOR]; + tls = pe->pe_opthdr.DataDirectory[PE_TLS_TABLE]; + loadcfg = pe->pe_opthdr.DataDirectory[PE_LOAD_CONFIG_TABLE]; + +@@ -651,6 +652,7 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out) + a final link is going to be performed, it can overwrite them. */ + extra->DataDirectory[PE_IMPORT_TABLE] = idata2; + extra->DataDirectory[PE_IMPORT_ADDRESS_TABLE] = idata5; ++ extra->DataDirectory[PE_DELAY_IMPORT_DESCRIPTOR] = didat2; + extra->DataDirectory[PE_TLS_TABLE] = tls; + extra->DataDirectory[PE_LOAD_CONFIG_TABLE] = loadcfg; + +@@ -4544,6 +4546,52 @@ _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_link_info *pfinfo) + } + } + ++ /* The delay import directory. This is .didat$2 */ ++ h1 = coff_link_hash_lookup (coff_hash_table (info), ++ "__DELAY_IMPORT_DIRECTORY_start__", false, false, ++ true); ++ if (h1 != NULL ++ && (h1->root.type == bfd_link_hash_defined ++ || h1->root.type == bfd_link_hash_defweak) ++ && h1->root.u.def.section != NULL ++ && h1->root.u.def.section->output_section != NULL) ++ { ++ bfd_vma delay_va; ++ ++ delay_va = ++ (h1->root.u.def.value ++ + h1->root.u.def.section->output_section->vma ++ + h1->root.u.def.section->output_offset); ++ ++ h1 = coff_link_hash_lookup (coff_hash_table (info), ++ "__DELAY_IMPORT_DIRECTORY_end__", false, ++ false, true); ++ if (h1 != NULL ++ && (h1->root.type == bfd_link_hash_defined ++ || h1->root.type == bfd_link_hash_defweak) ++ && h1->root.u.def.section != NULL ++ && h1->root.u.def.section->output_section != NULL) ++ { ++ pe_data (abfd)->pe_opthdr.DataDirectory[PE_DELAY_IMPORT_DESCRIPTOR].Size = ++ ((h1->root.u.def.value ++ + h1->root.u.def.section->output_section->vma ++ + h1->root.u.def.section->output_offset) ++ - delay_va); ++ if (pe_data (abfd)->pe_opthdr.DataDirectory[PE_DELAY_IMPORT_DESCRIPTOR].Size ++ != 0) ++ pe_data (abfd)->pe_opthdr.DataDirectory[PE_DELAY_IMPORT_DESCRIPTOR].VirtualAddress = ++ delay_va - pe_data (abfd)->pe_opthdr.ImageBase; ++ } ++ else ++ { ++ _bfd_error_handler ++ (_("%pB: unable to fill in DataDirectory[%d]: %s not defined correctly"), ++ abfd, PE_DELAY_IMPORT_DESCRIPTOR, ++ "__DELAY_IMPORT_DIRECTORY_end__"); ++ result = false; ++ } ++ } ++ + name[0] = bfd_get_symbol_leading_char (abfd); + strcpy (name + !!name[0], "_tls_used"); + h1 = coff_link_hash_lookup (coff_hash_table (info), name, false, false, true); +-- +2.49.0.windows.1 + diff --git a/mingw-w64-binutils/PKGBUILD b/mingw-w64-binutils/PKGBUILD index 9f6aab1000..05b6dd4e59 100644 --- a/mingw-w64-binutils/PKGBUILD +++ b/mingw-w64-binutils/PKGBUILD @@ -6,7 +6,7 @@ _realname=binutils pkgbase=mingw-w64-${_realname} pkgname=("${MINGW_PACKAGE_PREFIX}-${_realname}") pkgver=2.44 -pkgrel=3 +pkgrel=4 pkgdesc="A set of programs to assemble and manipulate binary and object files (mingw-w64)" arch=('any') mingw_arch=('mingw32' 'mingw64' 'ucrt64') @@ -33,6 +33,14 @@ source=(https://ftp.gnu.org/gnu/binutils/${_realname}-${pkgver}.tar.bz2{,.sig} libiberty-unlink-handle-windows-nul.patch 3001-hack-libiberty-link-order.patch 4000-fix-DEBUG_S_INLINEELINES.patch + 5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch + 5001-bfd-adjust-a-few-error-messages.patch + 5002-bfd-fill-in-PE-load-config-directory-entry.patch + 5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch + 5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch + 5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch + 5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch + 5007-bfd-populate-delay-import-directory-in-PE-header.patch ) sha256sums=('f66390a661faa117d00fab2e79cf2dc9d097b42cc296bf3f8677d1e7b452dc3a' 'SKIP' @@ -44,7 +52,15 @@ sha256sums=('f66390a661faa117d00fab2e79cf2dc9d097b42cc296bf3f8677d1e7b452dc3a' 'a094660ec95996c00b598429843b7869037732146442af567ada9f539bd40480' '7ccbd418695733c50966068fa9755a6abb156f53af23701d2bc097c63e9e0030' '604628156c08f3e361de60329af250fab6839e23e61e289f8369a7e18a04e277' - '5ed35a728b956ad49a5e196ae59f681666f2754f0a4903b9280a430d7a312ea8') + '5ed35a728b956ad49a5e196ae59f681666f2754f0a4903b9280a430d7a312ea8' + '0e04d2c174fd8faaf7982e049e0baa551b4fbfe49dca1a950625af50a71326b9' + 'ea53673a3f4196f649d46e4adda54d3dfed77152204c51713790755d16b4f7e5' + 'e36ab10562cefb8cae77ed06a7c91132ced6c90bda1a2d05c852b630f7a33089' + 'f3a6f8d9ce48c165a3b9e32ab9cf61bccaa05ce3826f03cb04c7ebaaab3f726d' + '4214fdc959057c3c5ed576df2d61a649c8817f8323fc4d6d25606f0cd6445d7f' + 'cf7f79840c6aace55fc5ea4638aaeb1cf07a13d07f5f7c1e2d86da3f0641ceff' + '928d283d86c66930167e2ef71f73e5222e9e3f878c5f57b5272dd12577fb82e1' + '9c5e3f13029e980e2ba98fd1bc6d5c5f738bc3680436848f4ef8a889f82a1f2d') validpgpkeys=('EAF1C276A747E9ED86210CBAC3126D3B4AE55E93' # Tristan Gingold '3A24BC1E8FB409FA9F14371813FCEF89DD9E3C4F') # Nick Clifton @@ -95,6 +111,20 @@ prepare() { # https://github.com/msys2/MINGW-packages/issues/24148 # https://sourceware.org/bugzilla/show_bug.cgi?id=32942 patch -p1 -i "${srcdir}/4000-fix-DEBUG_S_INLINEELINES.patch" + + # https://github.com/msys2/MINGW-packages/issues/23577 + # https://sourceware.org/bugzilla/show_bug.cgi?id=32675 + # https://sourceware.org/bugzilla/show_bug.cgi?id=14339 + # plus backport support for load config directory, to avoid a conflict + apply_patch_with_msg \ + 5000-bfd-properly-use-bfd_get_symbol_leading_char-in-peXX.patch \ + 5001-bfd-adjust-a-few-error-messages.patch \ + 5002-bfd-fill-in-PE-load-config-directory-entry.patch \ + 5003-bfd-add-load-config-size-workaround-for-i386-XP-and-.patch \ + 5004-bfd-ld-dlltool-Emit-delay-load-import-data-into-its-.patch \ + 5005-ld-dlltool-move-read-only-delayimp-data-into-.rdata.patch \ + 5006-dlltool-respect-use-nul-prefixed-import-tables-optio.patch \ + 5007-bfd-populate-delay-import-directory-in-PE-header.patch } build() {