[v2] Add support for IMPORT_NAME_EXPORTAS in ILF (MSVC style) import libraries

Message ID 20241001065639.3937812-1-martin@martin.st
State New
Headers
Series [v2] Add support for IMPORT_NAME_EXPORTAS in ILF (MSVC style) import libraries |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Test passed

Commit Message

Martin Storsjö Oct. 1, 2024, 6:56 a.m. UTC
  This import name type is formally yet undocumented, but MSVC
produces/supports it, primarily for ARM64EC import libraries.

LLVM/LLD also supports this import name type. Since recently,
llvm-dlltool also uses this type for certain kinds of renamed imports
(that are easy to do in the long style import libraries produced by
GNU dlltool, but require this name type in short import libraries).

This name type contains a third string, in addition to the symbol
name and the DLL name, indicating the actual imported name to
reference in the import tables - which now can be distinct different
from the symbol name on the object file level.

https://github.com/llvm/llvm-project/commit/8f23464a5d957242c89ca6f33d4379c42519cd81
and
https://github.com/llvm/llvm-project/commit/7b275aa2438c22604505d618dd37ee60052f2800
show how this import name type was added in LLVM.

Signed-off-by: Martin Storsjö <martin@martin.st>
---
v2: Added references in the commit message, fixed whitespace type
in the pe.h header.
---
 bfd/peicode.h     | 43 ++++++++++++++++++++++++++++++++++++-------
 include/coff/pe.h |  1 +
 2 files changed, 37 insertions(+), 7 deletions(-)
  

Patch

diff --git a/bfd/peicode.h b/bfd/peicode.h
index 11807efa62e..d6d752dfd42 100644
--- a/bfd/peicode.h
+++ b/bfd/peicode.h
@@ -409,7 +409,7 @@  pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
       There will be two symbols for the imported value, one the symbol name
       and one with _imp__ prefixed.  Allowing for the terminating nul's this
-      is strlen (symbol_name) * 2 + 8 + 21 + strlen (source_dll).
+      is strlen (import_name) * 2 + 8 + 21 + strlen (source_dll).
 
       The strings in the string table must start STRING__SIZE_SIZE bytes into
       the table in order to for the string lookup code in coffgen/coffcode to
@@ -425,7 +425,7 @@  pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 #define SIZEOF_ILF_EXT_SYMS	 (NUM_ILF_SYMS * sizeof (* vars.esym_table))
 #define SIZEOF_ILF_RELOCS	 (NUM_ILF_RELOCS * sizeof (* vars.reltab))
 #define SIZEOF_ILF_INT_RELOCS	 (NUM_ILF_RELOCS * sizeof (* vars.int_reltab))
-#define SIZEOF_ILF_STRINGS	 (strlen (symbol_name) * 2 + 8 \
+#define SIZEOF_ILF_STRINGS	 (strlen (import_name) * 2 + 8 \
 					+ 21 + strlen (source_dll) \
 					+ NUM_ILF_SECTIONS * 9 \
 					+ STRING_SIZE_SIZE)
@@ -440,7 +440,7 @@  pe_bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 #define SIZEOF_IDATA5		(1 * 4)
 #endif
 
-#define SIZEOF_IDATA6		(2 + strlen (symbol_name) + 1 + 1)
+#define SIZEOF_IDATA6		(2 + strlen (import_name) + 1 + 1)
 #define SIZEOF_IDATA7		(strlen (source_dll) + 1 + 1)
 #define SIZEOF_ILF_SECTIONS	(NUM_ILF_SECTIONS * sizeof (struct coff_section_tdata))
 
@@ -792,7 +792,8 @@  pe_ILF_build_a_bfd (bfd *	    abfd,
 		    char *	    symbol_name,
 		    char *	    source_dll,
 		    unsigned int    ordinal,
-		    unsigned int    types)
+		    unsigned int    types,
+		    char *          import_name)
 {
   bfd_byte *		   ptr;
   pe_ILF_vars		   vars;
@@ -834,6 +835,17 @@  pe_ILF_build_a_bfd (bfd *	    abfd,
     case IMPORT_NAME:
     case IMPORT_NAME_NOPREFIX:
     case IMPORT_NAME_UNDECORATE:
+      import_name = symbol_name;
+      break;
+
+    case IMPORT_NAME_EXPORTAS:
+      if (!import_name || !import_name[0])
+	{
+	  _bfd_error_handler (_("%pB: missing import name for "
+				"IMPORT_NAME_EXPORTAS for %s"),
+			      abfd, symbol_name);
+	  return false;
+	}
       break;
 
     default:
@@ -955,7 +967,7 @@  pe_ILF_build_a_bfd (bfd *	    abfd,
 	goto error_return;
 
       /* If necessary, trim the import symbol name.  */
-      symbol = symbol_name;
+      symbol = import_name;
 
       /* As used by MS compiler, '_', '@', and '?' are alternative
 	 forms of USER_LABEL_PREFIX, with '?' for c++ mangled names,
@@ -964,7 +976,8 @@  pe_ILF_build_a_bfd (bfd *	    abfd,
 	 IMPORT_NAME_NOPREFIX and IMPORT_NAME_UNDECORATE as per the
 	 PE COFF 6.0 spec (section 8.3, Import Name Type).  */
 
-      if (import_name_type != IMPORT_NAME)
+      if (import_name_type != IMPORT_NAME &&
+	  import_name_type != IMPORT_NAME_EXPORTAS)
 	{
 	  char c = symbol[0];
 
@@ -1179,6 +1192,7 @@  pe_ILF_object_p (bfd * abfd)
   bfd_byte *	  ptr;
   char *	  symbol_name;
   char *	  source_dll;
+  char *	  import_name;
   unsigned int	  machine;
   bfd_size_type	  size;
   unsigned int	  ordinal;
@@ -1340,9 +1354,24 @@  pe_ILF_object_p (bfd * abfd)
       return NULL;
     }
 
+  /* An ILF file may contain a third string, after source_dll; this is used
+   * for IMPORT_NAME_EXPORTAS. We know from above that the whole block of
+   * data is null terminated, ptr[size-1]==0, but we don't know how many
+   * individual null terminated strings we have in there.
+   *
+   * First find the end of source_dll. */
+  import_name = source_dll + strlen (source_dll) + 1;
+  if ((bfd_byte *) import_name >= ptr + size)
+    {
+      /* If this points at the end of the ptr+size block, we only had two
+       * strings. */
+      import_name = NULL;
+    }
+
   /* Now construct the bfd.  */
   if (! pe_ILF_build_a_bfd (abfd, magic, symbol_name,
-			    source_dll, ordinal, types))
+			    source_dll, ordinal, types,
+			    import_name))
     {
       bfd_release (abfd, ptr);
       return NULL;
diff --git a/include/coff/pe.h b/include/coff/pe.h
index 37446e4579d..9d7909013c7 100644
--- a/include/coff/pe.h
+++ b/include/coff/pe.h
@@ -338,6 +338,7 @@  typedef struct
 #define IMPORT_NAME		1
 #define IMPORT_NAME_NOPREFIX	2
 #define IMPORT_NAME_UNDECORATE	3
+#define IMPORT_NAME_EXPORTAS	4
 
 /* Weak external characteristics.  */
 #define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY	1