This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC PATCH, binutils] Add support for creating ELF import libraries


[resending without the ARM tag and other ARM specific bits from description because this applies to all ELF targets]

Hi,

TL;DR: is there interest for generic ELF import libraries (beside ARM)? If yes, RFC patch below.

One common development model for embedded devices is for ROM functions to be bundled in such devices and application developers calling these functions to interact with the device. In such cases, a way is needed for the application to know the addresses of the ROM functions. One convenient mechanism is to create a so called import library that application developers can link against. Such a library can already be created with objcopy --extract-symbol but this means it is done as a separate step than linking. This patch aims to add support in ld to create ELF import libraries at link time.

This patch extend the --out-implib switch from i386 PE backend to all ELF backends. This switch specifies a file where an import library should be created. The library is an object file containing no code or data section but just a symbol table with all symbols being absolute. By default, all global symbols in the output file are copied into the import library but target backend can apply different filters as they see fit, for instance when extra switches are supplied by the user.

ARM is interested in creating special kind of ELF import libraries [1] to support the security extensions of the ARMv8-M architecture [2]. Is there general interest in creating ELF import libraries outside ARM?

[1] https://sourceware.org/ml/binutils/2015-12/msg00358.html
[2] Software requirements for ARMv8-M security extensions are described in document ARM-ECM-0359818 [3]
[3] Available on http://infocenter.arm.com in Developer guides and articles > Software development > ARMÂv8-M Security Extensions: Requirements on Development Tools


ChangeLog entries are as follow:

*** bfd/ChangeLog ***

2015-07-20  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * elf-bfd.h (elf_backend_filter_implib_symbols): Declare backend hook.
        (_bfd_elf_filter_global_symbols): Declare default hook for the above.
        * elf.c (_bfd_elf_filter_global_symbols): New function.
        * elflink.c (elf_output_implib): Likewise.
        (bfd_elf_final_link): Call above function, failing if it does.
        * elfxx-target.h (elf_backend_filter_implib_symbols): Define macro and
        default it to _bfd_elf_filter_global_symbols.
        (elf_backend_copy_indirect_symbol): Fix spacing.
        (elf_backend_hide_symbol): Likewise.
        (elfNN_bed): Initialize elf_backend_filter_implib_symbols backend hook.


*** include/ChangeLog ***

2015-10-30  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * bfdlink.h (struct bfd_link_info): Declare new ldscript_def and
        out_implib_bfd fields.


*** ld/ChangeLog ***

2015-11-02  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * emultempl/elf32.em (gld${EMULATION_NAME}_after_open): Open import
        library file for writing and initialize implib_bfd field of link_info
        structure.
        * emultempl/pe.em (pe_implib_filename): Remove variable declaration.
        (OPTION_IMPLIB_FILENAME): Remove macro definition.
        (gld${EMULATION_NAME}_add_options): Remove --out-implib option.
        (gld_${EMULATION_NAME}_list_options): Likewise.
        (gld${EMULATION_NAME}_handle_option): Likewise.
        (gld_${EMULATION_NAME}_finish): Use command_line.out_implib_filename
        instead of pe_implib_filename.
        * emultempl/pep.em (pep_implib_filename): Remove variable declaration.
        (OPTION_IMPLIB_FILENAME): Remove enumerator.
        (gld${EMULATION_NAME}_add_options): Remove --out-implib option.
        (gld_${EMULATION_NAME}_list_options): Likewise.
        (gld${EMULATION_NAME}_handle_option): Likewise.
        (gld_${EMULATION_NAME}_finish): Use command_line.out_implib_filename
        instead of pep_implib_filename.
        * ld.h (args_type): Declare new out_implib_filename field.
        * ld.texinfo (--out-implib): Move documentation to arch-independent
        part and rephrase to apply to ELF targets.
        * ldexp.c (exp_fold_tree_1): Set ldscript_def field to 1 for symbols
        defined in linker scripts.
        * ldlex.h (enum option_values): Declare new OPTION_OUT_IMPLIB
        enumerator.
        * lexsup.c (ld_options): Add entry for new --out-implib switch.
        (parse_args): Handle OPTION_OUT_IMPLIB case.


*** ld/testsuite/ChangeLog ***

2015-10-30  Thomas Preud'homme  <thomas.preudhomme@arm.com>

        * ld-elf/elf.exp (Generate empty import library): New test.
        (Generate import library): Likewise.
        * ld-elf/implib.s: Likewise.
        * ld-elf/implib.rd: New file.
        * ld-elf/empty-implib.out: Likewise


diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h
index 70e33275054b5987777862b42c46e83d41ca7e6f..21566ac2fc9851f003d8f20737227e020a4e1434 100644
--- a/bfd/elf-bfd.h
+++ b/bfd/elf-bfd.h
@@ -57,7 +57,7 @@ extern "C" {
 #define elfNAME(X)	NAME(elf,X)
 
 /* Information held for an ELF symbol.  The first field is the
-   corresponding asymbol.  Every symbol is an ELF file is actually a
+   corresponding asymbol.  Every symbol in an ELF file is actually a
    pointer to this structure, although it is often handled as a
    pointer to an asymbol.  */
 
@@ -1125,6 +1125,11 @@ struct elf_backend_data
      bfd_boolean (*) (void *, const char *, Elf_Internal_Sym *, asection *,
 		      struct elf_link_hash_entry *));
 
+  /* Filter what symbols of the output file to include in the import
+     library if one is created.  */
+  unsigned int (*elf_backend_filter_implib_symbols)
+    (bfd *, struct bfd_link_info *, asymbol **, long);
+
   /* Copy any information related to dynamic linking from a pre-existing
      symbol to a newly created symbol.  Also called to copy flags and
      other back-end info to a weakdef, in which case the symbol is not
@@ -1932,6 +1937,8 @@ extern bfd_boolean _bfd_elf_section_already_linked
   (bfd *, asection *, struct bfd_link_info *);
 extern void bfd_elf_set_group_contents
   (bfd *, asection *, void *);
+extern unsigned int _bfd_elf_filter_global_symbols
+  (bfd *, struct bfd_link_info *, asymbol **, long);
 extern asection *_bfd_elf_check_kept_section
   (asection *, struct bfd_link_info *);
 #define _bfd_elf_link_just_syms _bfd_generic_link_just_syms
diff --git a/bfd/elf.c b/bfd/elf.c
index 9a2cff5fe511ad7abbc1a275829cf812abd1c22b..ac94dbf8ea156e2c341c766b0b492b6557a440f7 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -3697,6 +3697,45 @@ ignore_section_sym (bfd *abfd, asymbol *sym)
 	       || bfd_is_abs_section (sym->section)));
 }
 
+
+/* Filter global symbols of ABFD to include in the import library.  All
+   SYMCOUNT symbols of ABFD can be examined from their pointers in
+   SYMS.  Pointers of symbols to keep should be stored continuously at
+   the beginning of that array.
+
+   Returns the number of symbols to keep.  */
+
+unsigned int
+_bfd_elf_filter_global_symbols (bfd *abfd,
+				struct bfd_link_info *info,
+				asymbol **syms, long symcount)
+{
+  long src_count, dst_count = 0;
+
+  for (src_count = 0; src_count < symcount; src_count++)
+    {
+      asymbol *sym = syms[src_count];
+      char *name = (char *) bfd_asymbol_name (sym);
+      struct bfd_link_hash_entry *h;
+
+      if (!sym_is_global (abfd, sym))
+	continue;
+
+      h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, FALSE);
+      if (h->type != bfd_link_hash_defined && h->type != bfd_link_hash_defweak)
+	continue;
+
+      if (h->linker_def || h->ldscript_def)
+	continue;
+
+      syms[dst_count++] = sym;
+    }
+
+  syms[dst_count] = NULL;
+
+  return dst_count;
+}
+
 /* Map symbol from it's internal number to the external number, moving
    all local symbols to be at the head of the list.  */
 
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 1b41c793a978dd5d974c8e73927a5b8d85416b33..e2d5337c3fd91c43776dded28f45598fa78c4ebf 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -10829,6 +10829,104 @@ elf_fixup_link_order (bfd *abfd, asection *o)
   return TRUE;
 }
 
+/* Generate an import library in INFO->implib_bfd from symbols in ABFD.
+   Returns TRUE upon success, FALSE otherwise.  */
+
+static bfd_boolean
+elf_output_implib (bfd *abfd, struct bfd_link_info *info)
+{
+  bfd_boolean ret = FALSE;
+  bfd *implib_bfd;
+  const struct elf_backend_data *bed;
+  flagword flags;
+  enum bfd_architecture arch;
+  unsigned int mach;
+  asymbol **sympp = NULL;
+  long symsize;
+  long symcount;
+  long src_count;
+  elf_symbol_type *osymbuf;
+
+  implib_bfd = info->out_implib_bfd;
+  bed = get_elf_backend_data (abfd);
+
+  if (!bfd_set_format (implib_bfd, bfd_object))
+    return FALSE;
+
+  flags = bfd_get_file_flags (abfd);
+  flags &= ~HAS_RELOC;
+  if (!bfd_set_start_address (implib_bfd, 0)
+      || !bfd_set_file_flags (implib_bfd, flags))
+    return FALSE;
+
+  /* Copy architecture of output file to import library file.  */
+  arch = bfd_get_arch (abfd);
+  mach = bfd_get_mach (abfd);
+  if (!bfd_set_arch_mach (implib_bfd, arch, mach)
+      && (abfd->target_defaulted
+	  || bfd_get_arch (abfd) != bfd_get_arch (implib_bfd)))
+    return FALSE;
+
+  /* Get symbol table size.  */
+  symsize = bfd_get_symtab_upper_bound (abfd);
+  if (symsize < 0)
+    return FALSE;
+
+  /* Read in the symbol table.  */
+  sympp = (asymbol **) xmalloc (symsize);
+  symcount = bfd_canonicalize_symtab (abfd, sympp);
+  if (symcount < 0)
+    goto free_sym_buf;
+
+  /* Allow the BFD backend to copy any private header data it
+     understands from the output BFD to the import library BFD.  */
+  if (! bfd_copy_private_header_data (abfd, implib_bfd))
+    goto free_sym_buf;
+
+  /* Filter symbols to appear in the import library.  */
+  symcount = bed->elf_backend_filter_implib_symbols (abfd, info, sympp,
+						     symcount);
+  if (symcount == 0)
+    {
+      (*_bfd_error_handler) (_("%B: no symbol found for import library"),
+			     implib_bfd);
+      goto free_sym_buf;
+    }
+
+
+  /* Make symbols absolute.  */
+  osymbuf = (elf_symbol_type *) bfd_alloc2 (implib_bfd, symcount,
+					    sizeof (*osymbuf));
+  for (src_count = 0; src_count < symcount; src_count++)
+    {
+      memcpy (&osymbuf[src_count], (elf_symbol_type *) sympp[src_count],
+	      sizeof (*osymbuf));
+      osymbuf[src_count].symbol.section = bfd_abs_section_ptr;
+      osymbuf[src_count].internal_elf_sym.st_shndx = SHN_ABS;
+      osymbuf[src_count].symbol.value += sympp[src_count]->section->vma;
+      osymbuf[src_count].internal_elf_sym.st_value =
+	osymbuf[src_count].symbol.value;
+      sympp[src_count] = &osymbuf[src_count].symbol;
+    }
+
+  bfd_set_symtab (implib_bfd, sympp, symcount);
+
+  /* Allow the BFD backend to copy any private data it understands
+     from the output BFD to the import library BFD.  This is done last
+     to permit the routine to look at the filtered symbol table.  */
+  if (! bfd_copy_private_bfd_data (abfd, implib_bfd))
+    goto free_sym_buf;
+
+  if (!bfd_close (implib_bfd))
+    goto free_sym_buf;
+
+  ret = TRUE;
+
+free_sym_buf:
+  free (sympp);
+  return ret;
+}
+
 static void
 elf_final_link_free (bfd *obfd, struct elf_final_link_info *flinfo)
 {
@@ -11610,6 +11708,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info)
 	return FALSE;
     }
 
+  if (info->out_implib_bfd && !elf_output_implib (abfd, info))
+    {
+      (*_bfd_error_handler) (_("%B: failed to generate import library"),
+			     info->out_implib_bfd);
+      return FALSE;
+    }
+
   /* Adjust the relocs to have the correct symbol indices.  */
   for (o = abfd->sections; o != NULL; o = o->next)
     {
diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h
index 0acecafcb29217e9ab178672a4a69703a5eea646..289327a433113e60c4e83c999b2056646b5bff41 100644
--- a/bfd/elfxx-target.h
+++ b/bfd/elfxx-target.h
@@ -514,11 +514,14 @@
 #ifndef elf_backend_output_arch_syms
 #define elf_backend_output_arch_syms		NULL
 #endif
+#ifndef elf_backend_filter_implib_symbols
+#define elf_backend_filter_implib_symbols	_bfd_elf_filter_global_symbols
+#endif
 #ifndef elf_backend_copy_indirect_symbol
-#define elf_backend_copy_indirect_symbol  _bfd_elf_link_hash_copy_indirect
+#define elf_backend_copy_indirect_symbol	_bfd_elf_link_hash_copy_indirect
 #endif
 #ifndef elf_backend_hide_symbol
-#define elf_backend_hide_symbol		_bfd_elf_link_hash_hide_symbol
+#define elf_backend_hide_symbol			_bfd_elf_link_hash_hide_symbol
 #endif
 #ifndef elf_backend_fixup_symbol
 #define elf_backend_fixup_symbol		NULL
@@ -747,6 +750,7 @@ static struct elf_backend_data elfNN_bed =
   elf_backend_print_symbol_all,
   elf_backend_output_arch_local_syms,
   elf_backend_output_arch_syms,
+  elf_backend_filter_implib_symbols,
   elf_backend_copy_indirect_symbol,
   elf_backend_hide_symbol,
   elf_backend_fixup_symbol,
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 93abab1c04e48af4a258e25adb00b618b6d03808..df0f08c19cc3f772e439b1c6706a834f27e626e8 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -99,6 +99,9 @@ struct bfd_link_hash_entry
      in a linker script.  */
   unsigned int linker_def : 1;
 
+  /* Symbol defined in a linker script.  */
+  unsigned int ldscript_def : 1;
+
   /* A union of information depending upon the type.  */
   union
     {
@@ -499,6 +502,9 @@ struct bfd_link_info
   /* The output BFD.  */
   bfd *output_bfd;
 
+  /* The import library generated.  */
+  bfd *out_implib_bfd;
+
   /* The list of input BFD's involved in the link.  These are chained
      together via the link.next field.  */
   bfd *input_bfds;
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 0405d4fa71554a672e6b3070f3f310fec2244760..8354f9a4e79b82e106dcd8062123e261fe13e789 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -1025,6 +1025,20 @@ gld${EMULATION_NAME}_after_open (void)
   if (!is_elf_hash_table (htab))
     return;
 
+  if (command_line.out_implib_filename)
+    {
+      unlink_if_ordinary (command_line.out_implib_filename);
+      link_info.out_implib_bfd
+	= bfd_openw (command_line.out_implib_filename,
+		     bfd_get_target (link_info.output_bfd));
+
+      if (link_info.out_implib_bfd == NULL)
+	{
+	  einfo ("%F%s: Can't open for writing: %E\n",
+		 command_line.out_implib_filename);
+	}
+    }
+
   if (emit_note_gnu_build_id != NULL)
     {
       bfd *abfd;
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 0370c5a52637c4043e80963f4065ab13ee7f9a14..f51dea4fffd95c2c3c72e15cf8329f8769c45cb4 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -138,7 +138,6 @@ static const char *emit_build_id;
 #ifdef DLL_SUPPORT
 static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable.  */
 static char *pe_out_def_filename = NULL;
-static char *pe_implib_filename = NULL;
 static int pe_enable_auto_image_base = 0;
 static unsigned long pe_auto_image_base = 0x61500000;
 static char *pe_dll_search_prefix = NULL;
@@ -228,8 +227,7 @@ fragment <<EOF
 #define OPTION_STDCALL_ALIASES		(OPTION_KILL_ATS + 1)
 #define OPTION_ENABLE_STDCALL_FIXUP	(OPTION_STDCALL_ALIASES + 1)
 #define OPTION_DISABLE_STDCALL_FIXUP	(OPTION_ENABLE_STDCALL_FIXUP + 1)
-#define OPTION_IMPLIB_FILENAME		(OPTION_DISABLE_STDCALL_FIXUP + 1)
-#define OPTION_THUMB_ENTRY		(OPTION_IMPLIB_FILENAME + 1)
+#define OPTION_THUMB_ENTRY		(OPTION_DISABLE_STDCALL_FIXUP + 1)
 #define OPTION_WARN_DUPLICATE_EXPORTS	(OPTION_THUMB_ENTRY + 1)
 #define OPTION_IMP_COMPAT		(OPTION_WARN_DUPLICATE_EXPORTS + 1)
 #define OPTION_ENABLE_AUTO_IMAGE_BASE	(OPTION_IMP_COMPAT + 1)
@@ -323,7 +321,6 @@ gld${EMULATION_NAME}_add_options
     {"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES},
     {"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP},
     {"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP},
-    {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME},
     {"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS},
     /* getopt() allows abbreviations, so we do this to stop it from
        treating -c as an abbreviation for these --compat-implib.  */
@@ -461,7 +458,6 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
   fprintf (file, _("                                     export, place into import library instead.\n"));
   fprintf (file, _("  --export-all-symbols               Automatically export all globals to DLL\n"));
   fprintf (file, _("  --kill-at                          Remove @nn from exported symbols\n"));
-  fprintf (file, _("  --out-implib <file>                Generate import library\n"));
   fprintf (file, _("  --output-def <file>                Generate a .DEF file for the built DLL\n"));
   fprintf (file, _("  --warn-duplicate-exports           Warn about duplicate exports\n"));
   fprintf (file, _("  --compat-implib                    Create backward compatible import libs;\n\
@@ -805,9 +801,6 @@ gld${EMULATION_NAME}_handle_option (int optc)
     case OPTION_DISABLE_STDCALL_FIXUP:
       pe_enable_stdcall_fixup = 0;
       break;
-    case OPTION_IMPLIB_FILENAME:
-      pe_implib_filename = xstrdup (optarg);
-      break;
     case OPTION_WARN_DUPLICATE_EXPORTS:
       pe_dll_warn_dup_exports = 1;
       break;
@@ -2073,8 +2066,9 @@ gld_${EMULATION_NAME}_finish (void)
     )
     {
       pe_dll_fill_sections (link_info.output_bfd, &link_info);
-      if (pe_implib_filename)
-	pe_dll_generate_implib (pe_def_file, pe_implib_filename, &link_info);
+      if (command_line.out_implib_filename)
+	pe_dll_generate_implib (pe_def_file, command_line.out_implib_filename,
+				&link_info);
     }
 #if defined(TARGET_IS_shpe)
   /* ARM doesn't need relocs.  */
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index 91de50165d71765ee61179dbd4e1f6b3f6ebe486..081890206a5dbacb53a9f3202fee6daff3542c9c 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -153,7 +153,6 @@ static const char *emit_build_id;
 #ifdef DLL_SUPPORT
 static int    pep_enable_stdcall_fixup = 1; /* 0=disable 1=enable (default).  */
 static char * pep_out_def_filename = NULL;
-static char * pep_implib_filename = NULL;
 static int    pep_enable_auto_image_base = 0;
 static char * pep_dll_search_prefix = NULL;
 #endif
@@ -217,7 +216,6 @@ enum options
   OPTION_STDCALL_ALIASES,
   OPTION_ENABLE_STDCALL_FIXUP,
   OPTION_DISABLE_STDCALL_FIXUP,
-  OPTION_IMPLIB_FILENAME,
   OPTION_WARN_DUPLICATE_EXPORTS,
   OPTION_IMP_COMPAT,
   OPTION_ENABLE_AUTO_IMAGE_BASE,
@@ -296,7 +294,6 @@ gld${EMULATION_NAME}_add_options
     {"add-stdcall-alias", no_argument, NULL, OPTION_STDCALL_ALIASES},
     {"enable-stdcall-fixup", no_argument, NULL, OPTION_ENABLE_STDCALL_FIXUP},
     {"disable-stdcall-fixup", no_argument, NULL, OPTION_DISABLE_STDCALL_FIXUP},
-    {"out-implib", required_argument, NULL, OPTION_IMPLIB_FILENAME},
     {"warn-duplicate-exports", no_argument, NULL, OPTION_WARN_DUPLICATE_EXPORTS},
     /* getopt() allows abbreviations, so we do this to stop it from
        treating -c as an abbreviation for these --compat-implib.  */
@@ -427,7 +424,6 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
   fprintf (file, _("                                     export, place into import library instead.\n"));
   fprintf (file, _("  --export-all-symbols               Automatically export all globals to DLL\n"));
   fprintf (file, _("  --kill-at                          Remove @nn from exported symbols\n"));
-  fprintf (file, _("  --out-implib <file>                Generate import library\n"));
   fprintf (file, _("  --output-def <file>                Generate a .DEF file for the built DLL\n"));
   fprintf (file, _("  --warn-duplicate-exports           Warn about duplicate exports.\n"));
   fprintf (file, _("  --compat-implib                    Create backward compatible import libs;\n\
@@ -761,9 +757,6 @@ gld${EMULATION_NAME}_handle_option (int optc)
     case OPTION_DISABLE_STDCALL_FIXUP:
       pep_enable_stdcall_fixup = 0;
       break;
-    case OPTION_IMPLIB_FILENAME:
-      pep_implib_filename = xstrdup (optarg);
-      break;
     case OPTION_WARN_DUPLICATE_EXPORTS:
       pep_dll_warn_dup_exports = 1;
       break;
@@ -1851,8 +1844,9 @@ gld_${EMULATION_NAME}_finish (void)
 	  && pep_def_file->num_exports != 0))
     {
       pep_dll_fill_sections (link_info.output_bfd, &link_info);
-      if (pep_implib_filename)
-	pep_dll_generate_implib (pep_def_file, pep_implib_filename, &link_info);
+      if (command_line.out_implib_filename)
+	pep_dll_generate_implib (pep_def_file,
+				 command_line.out_implib_filename, &link_info);
     }
 
   if (pep_out_def_filename)
diff --git a/ld/ld.h b/ld/ld.h
index d84ec4e634eab5c0443767c3acded05073fa0484..807cd30e9e35eee8c23052dc9bcccf233be005f0 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -158,6 +158,9 @@ typedef struct {
      input files.  */
   bfd_boolean accept_unknown_input_arch;
 
+  /* Name of the import library to generate.  */
+  char *out_implib_filename;
+
   /* If TRUE we'll just print the default output on stdout.  */
   bfd_boolean print_output_format;
 
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 1dd749249acbf8c97ce7ec4fad66d56efb9367cd..b9e7f7ce652319f4d9833076aaa0c1bd7a36c923 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -1696,6 +1696,16 @@ command @code{OUTPUT_FORMAT} can also specify the output format, but
 this option overrides it.  @xref{BFD}.
 @end ifclear
 
+@kindex --out-implib
+@item --out-implib @var{file}
+Create an import library in @var{file} corresponding to the executable
+the linker is generating (eg. a DLL or ELF program).  This import
+library (which should be called @code{*.dll.a} or @code{*.a} for DLLs)
+may be used to link clients against the generated executable; this
+behaviour makes it possible to skip a separate import library creation
+step (eg. @code{dlltool} for DLLs).  This option is only available for
+the i386 PE and ELF targetted ports of the linker.
+
 @kindex -pie
 @kindex --pic-executable
 @item -pie
@@ -2555,16 +2565,6 @@ automatically or implicitly exported symbols.
 [This option is specific to the i386 PE targeted port of the linker]
 
 @cindex DLLs, creating
-@kindex --out-implib
-@item --out-implib @var{file}
-The linker will create the file @var{file} which will contain an
-import lib corresponding to the DLL the linker is generating. This
-import lib (which should be called @code{*.dll.a} or @code{*.a}
-may be used to link clients against the generated DLL; this behaviour
-makes it possible to skip a separate @code{dlltool} import library
-creation step.
-[This option is specific to the i386 PE targeted port of the linker]
-
 @kindex --enable-auto-image-base
 @item --enable-auto-image-base
 @itemx --enable-auto-image-base=@var{value}
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 2ec8eb6d19892b5751afcacf9839181acd20cfd5..d80698fb05e4f5392068acf2d4e7d819dee2aabd 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -1182,6 +1182,7 @@ exp_fold_tree_1 (etree_type *tree)
 	      h->u.def.value = expld.result.value;
 	      h->u.def.section = expld.result.section;
 	      h->linker_def = 0;
+	      h->ldscript_def = 1;
 	      if (tree->type.node_class == etree_provide)
 		tree->type.node_class = etree_provided;
 
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 6f11e7bd21782367ad8347d5f3754aa09192b5ed..61f3f80dc98f352791b1155984b16930ce1e8177 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -35,6 +35,7 @@ enum option_values
   OPTION_DYNAMIC_LINKER,
   OPTION_NO_DYNAMIC_LINKER,
   OPTION_SYSROOT,
+  OPTION_OUT_IMPLIB,
   OPTION_EB,
   OPTION_EL,
   OPTION_EMBEDDED_RELOCS,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 4cad2097a1fb232bb576e2dc5d46bbadc42e1a9d..a3d040eb32e6559fdcb0c449fda98f09ff1ae45c 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -164,6 +164,8 @@ static const struct ld_option ld_options[] =
     'o', N_("FILE"), N_("Set output file name"), EXACTLY_TWO_DASHES },
   { {NULL, required_argument, NULL, '\0'},
     'O', NULL, N_("Optimize output file"), ONE_DASH },
+  { {"out-implib", required_argument, NULL, OPTION_OUT_IMPLIB},
+    '\0', N_("FILE"), N_("Generate import library"), TWO_DASHES },
 #ifdef ENABLE_PLUGINS
   { {"plugin", required_argument, NULL, OPTION_PLUGIN},
     '\0', N_("PLUGIN"), N_("Load named plugin"), ONE_DASH },
@@ -1004,6 +1006,9 @@ parse_args (unsigned argc, char **argv)
 	case OPTION_OFORMAT:
 	  lang_add_output_format (optarg, NULL, NULL, 0);
 	  break;
+	case OPTION_OUT_IMPLIB:
+	  command_line.out_implib_filename = xstrdup (optarg);
+	  break;
 	case OPTION_PRINT_SYSROOT:
 	  if (*ld_sysroot)
 	    puts (ld_sysroot);
diff --git a/ld/testsuite/ld-elf/elf.exp b/ld/testsuite/ld-elf/elf.exp
index e56c2054a69326c398b8f1298c010a3591a487a8..8b5799da8fb956f1bb5e4bf48448997f4ae6739f 100644
--- a/ld/testsuite/ld-elf/elf.exp
+++ b/ld/testsuite/ld-elf/elf.exp
@@ -124,6 +124,22 @@ foreach t $test_list {
     run_dump_test [file rootname $t]
 }
 
+# Check that the --out-implib option work correctly.
+run_ld_link_tests {
+    {"Generate empty import library"
+     "--out-implib=tmpdir/implib.lib" ""
+     "--defsym NO_GLOBAL=1"
+     {implib.s}
+     {{ld empty-implib.out}}
+     "implib"}
+    {"Generate import library"
+     "-Tdata=0x1000 --out-implib=tmpdir/implib.lib" ""
+     ""
+     {implib.s}
+     {{readelf {-s tmpdir/implib.lib} implib.rd}}
+     "implib"}
+}
+
 if { [istarget *-*-linux*]
      || [istarget *-*-nacl*]
      || [istarget *-*-gnu*] } {
diff --git a/ld/testsuite/ld-elf/empty-implib.out b/ld/testsuite/ld-elf/empty-implib.out
new file mode 100644
index 0000000000000000000000000000000000000000..b123064df3f6f429c59fe204d57e57ed76a8d5be
--- /dev/null
+++ b/ld/testsuite/ld-elf/empty-implib.out
@@ -0,0 +1,2 @@
+.*: .*: no symbol found for import library
+.*: .*: failed to generate import library
diff --git a/ld/testsuite/ld-elf/implib.rd b/ld/testsuite/ld-elf/implib.rd
new file mode 100644
index 0000000000000000000000000000000000000000..9f854a59bd26054a8fdb49f6dbaac4120b2c7ef1
--- /dev/null
+++ b/ld/testsuite/ld-elf/implib.rd
@@ -0,0 +1,11 @@
+File: tmpdir/implib.lib
+
+Symbol table '.symtab' contains 3 entries:
+   Num:    Value +Size Type    Bind   Vis      Ndx Name
+     0: [0-9a-f]+     0 NOTYPE  LOCAL  DEFAULT  UND 
+     1: 0+100[0-3]     1 OBJECT  GLOBAL DEFAULT  ABS exported1
+     2: 0+100[0-3]     1 OBJECT  GLOBAL DEFAULT  ABS exported2
+
+File: tmpdir/implib
+
+#...
diff --git a/ld/testsuite/ld-elf/implib.s b/ld/testsuite/ld-elf/implib.s
new file mode 100644
index 0000000000000000000000000000000000000000..a86a940c138d7dd65e42c609adbe594c579061ac
--- /dev/null
+++ b/ld/testsuite/ld-elf/implib.s
@@ -0,0 +1,22 @@
+.ifndef NO_GLOBAL
+	.bss
+	.comm	exported1,1
+
+	.data
+	.global	exported2
+	.type	exported2, %object
+	.size	exported2, 1
+exported2:
+	.byte	21
+.endif
+
+	.bss
+not_exported1:
+	.space	1
+	.size	not_exported1, 1
+
+	.data
+	.type	not_exported2, %object
+	.size	not_exported2, 1
+not_exported2:
+	.byte	42


The patch doesn't show any regression when running the binutils-gdb testsuite for arm-none-eabi, i386-unknown-pe and x86_64-unknown-mingw32 targets.

Any comments?

Best regards,

Thomas


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]