[PATCH v2 0/4] PE delay import fixes

Jeremy Drake sourceware-bugzilla@jdrake.com
Tue May 6 06:05:45 GMT 2025


Jeremy Drake (3):
  ld,dlltool: move read-only delayimp data into .rdata
  dlltool: respect use-nul-prefixed-import-tables option for delaylib
  bfd: populate delay import directory in PE header.

LIU Hao (1):
  bfd,ld,dlltool: Emit delay-load import data into its own section

 bfd/coffgen.c         | 14 +++++++
 bfd/pe-aarch64.c      |  2 +
 bfd/pe-arm.c          |  2 +
 bfd/pe-i386.c         |  2 +
 bfd/pe-x86_64.c       |  2 +
 bfd/peXXigen.c        | 51 +++++++++++++++++++++-
 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    | 98 ++++++++++++++++++++++++++++++++++++-------
 ld/scripttempl/pe.sc  | 29 ++++++++++++-
 ld/scripttempl/pep.sc | 31 +++++++++++++-
 16 files changed, 225 insertions(+), 19 deletions(-)

Range-diff against v1:
1:  5d7d252aacd ! 1:  8ac56d5a735 bfd,ld,dlltool: Emit delay-load import data into its own section
    @@ Commit message
         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.
    +    faults when functions from delay-import library were called.  This is
    +    PR 32675.

    -    This commit makes DLLTOOL emit delay-import IAT into `.didata`, as specified
    +    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.
    +    section is writeable.  As a side-effect of this, PR 14339 is also fixed.

         Using this DEF:

    @@ Commit message
            ```

         Reference: https://learn.microsoft.com/en-us/windows/win32/secbp/pe-metadata#import-handling
    +    Co-authored-by: Jeremy Drake <sourceware-bugzilla@jdrake.com>
         Signed-off-by: LIU Hao <lh_mouse@126.com>
    +    Signed-off-by: Jeremy Drake <sourceware-bugzilla@jdrake.com>

      ## bfd/coffgen.c ##
    +@@ bfd/coffgen.c: 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)
    + {
     @@ bfd/coffgen.c: 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")
    -+		   || startswith (o->name, ".didat")
    ++		   || is_subsection (o->name, ".didat")
      		   || startswith (o->name, ".rsrc"))
      	    o->gc_mark = 1;

2:  bd2cee94dfc ! 2:  c39f04640ac move read-only delayimp data into .rdata
    @@ Metadata
     Author: Jeremy Drake <sourceware-bugzilla@jdrake.com>

      ## Commit message ##
    -    move read-only delayimp data into .rdata
    +    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
    @@ binutils/dlltool.c: make_delay_head (void)
        fprintf (f, "__DELAY_IMPORT_DESCRIPTOR_%s:\n", imp_name_lab);
        fprintf (f, "\t%s 1\t%s grAttrs\n", ASM_LONG, ASM_C);
     @@ binutils/dlltool.c: 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);
    +       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");
    -+      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);
          }

-:  ----------- > 3:  5bc5c6f71fa dlltool: respect use-nul-prefixed-import-tables option for delaylib
3:  685e88d6db4 ! 4:  12302e5cc33 bfd: populate delay import directory in PE header.
    @@ bfd/peXXigen.c: _bfd_XXi_final_link_postscript (bfd * abfd, struct coff_final_li
     +  h1 = coff_link_hash_lookup (coff_hash_table (info),
     +			      "__DELAY_IMPORT_DIRECTORY_start__", false, false,
     +			      true);
    -+  if (h1 != NULL)
    ++  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)
     +    {
    -+      if ((h1->root.type == bfd_link_hash_defined
    ++      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)
     +	{
    -+	  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;
    -+	    }
    ++	  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;
     +	}
     +    }
     +
-- 
2.49.0.windows.1



More information about the Binutils mailing list