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]

[PATCH 4/4] Add ld --build-id support for pe/coff


Add ld --build-id option for pe/coff, which adds a .build-id section containing
a CodeView record, pointed to by the debug directory.

Note that the pe/coff build-id is a fixed length of 16 bytes, not a variable
length like an ELF .note.gnu.build-id.

XXX: There is an unfortunate degree of code duplication between 32 and 64 bit
pe/coff variants, but this is hard to avoid given the way the code is
structured. :-(

Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>

bfd/ChangeLog:
2014-01-20  Jon TURNEY  <jon.turney@dronecode.org.uk>

	* libcoff-in.h (pe_tdata): Add build-id data.
	* libcoff.h: Regenerate.
	* coffcode.h (coff_write_object_contents): Run build_id
	after_write_object_contents hook.

ld/ChangeLog:

2014-01-20  Jon TURNEY  <jon.turney@dronecode.org.uk>

	* emultempl/pe.em (gld${EMULATION_NAME}_handle_option):
	(pecoff_checksum_contents, write_build_id, setup_build_id)
	(gld_${EMULATION_NAME}_after_open):  Handle and implement
	build-id option.
	* emultempl/pep.em: Ditto.

Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
---
 bfd/coffcode.h      |  10 ++-
 bfd/libcoff-in.h    |   8 +++
 bfd/libcoff.h       |   8 +++
 ld/NEWS             |   2 +
 ld/emultempl/pe.em  | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 ld/emultempl/pep.em | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 6 files changed, 420 insertions(+), 4 deletions(-)

diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index 542b5b7..786c114 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -4325,7 +4325,15 @@ coff_write_object_contents (bfd * abfd)
     }
 #endif
 
-  /* Now write them.  */
+#ifdef COFF_WITH_PE
+  /* After object contents are finalized so we can compute a reasonable hash,
+     but before header is written so we can update it to point to debug directory */
+  struct pe_tdata *pe = pe_data(abfd);
+  if (pe->build_id.after_write_object_contents != NULL)
+    (*pe->build_id.after_write_object_contents) (abfd);
+#endif
+
+  /* Now write header.  */
   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
     return FALSE;
 
diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h
index 49b5f10..69fc1e0 100644
--- a/bfd/libcoff-in.h
+++ b/bfd/libcoff-in.h
@@ -119,6 +119,14 @@ typedef struct pe_tdata
   bfd_boolean insert_timestamp;
   bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *);
   flagword real_flags;
+
+  /* build-id info. */
+  struct
+  {
+    bfd_boolean (*after_write_object_contents) (bfd *);
+    const char *style;
+    asection *sec;
+  } build_id;
 } pe_data_type;
 
 #define pe_data(bfd)		((bfd)->tdata.pe_obj_data)
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index 19b6d9c..3f91c93 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -123,6 +123,14 @@ typedef struct pe_tdata
   bfd_boolean insert_timestamp;
   bfd_boolean (*in_reloc_p) (bfd *, reloc_howto_type *);
   flagword real_flags;
+
+  /* build-id info. */
+  struct
+  {
+    bfd_boolean (*after_write_object_contents) (bfd *);
+    const char *style;
+    asection *sec;
+  } build_id;
 } pe_data_type;
 
 #define pe_data(bfd)		((bfd)->tdata.pe_obj_data)
diff --git a/ld/NEWS b/ld/NEWS
index c59040e..481ccd6 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,7 @@
 -*- text -*-
 
+* x86/x86_64 pe-coff now supports the --build-id option.
+
 * Add support for the Andes NDS32.
 
 Changes in 2.24:
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index 5d6da9e..f2e950f 100644
--- a/ld/emultempl/pe.em
+++ b/ld/emultempl/pe.em
@@ -66,6 +66,7 @@ fragment <<EOF
 #include "ldlex.h"
 #include "ldmisc.h"
 #include "ldctor.h"
+#include "ldbuildid.h"
 #include "coff/internal.h"
 
 /* FIXME: See bfd/peXXigen.c for why we include an architecture specific
@@ -73,9 +74,10 @@ fragment <<EOF
 #include "coff/i386.h"
 #include "coff/pe.h"
 
-/* FIXME: This is a BFD internal header file, and we should not be
+/* FIXME: These are BFD internal header files, and we should not be
    using it here.  */
 #include "../bfd/libcoff.h"
+#include "../bfd/libpei.h"
 
 #include "deffile.h"
 #include "pe-dll.h"
@@ -131,6 +133,7 @@ static char * thumb_entry_symbol = NULL;
 static lang_assignment_statement_type *image_base_statement = 0;
 static unsigned short pe_dll_characteristics = 0;
 static bfd_boolean insert_timestamp = FALSE;
+static const char *emit_build_id;
 
 #ifdef DLL_SUPPORT
 static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable.  */
@@ -268,6 +271,7 @@ fragment <<EOF
 #define OPTION_TERMINAL_SERVER_AWARE	(OPTION_WDM_DRIVER + 1)
 /* Determinism.  */
 #define OPTION_INSERT_TIMESTAMP		(OPTION_TERMINAL_SERVER_AWARE + 1)
+#define OPTION_BUILD_ID			(OPTION_INSERT_TIMESTAMP + 1)
 
 static void
 gld${EMULATION_NAME}_add_options
@@ -346,6 +350,7 @@ gld${EMULATION_NAME}_add_options
     {"no-bind", no_argument, NULL, OPTION_NO_BIND},
     {"wdmdriver", no_argument, NULL, OPTION_WDM_DRIVER},
     {"tsaware", no_argument, NULL, OPTION_TERMINAL_SERVER_AWARE},
+    {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
     {NULL, no_argument, NULL, 0}
   };
 
@@ -493,6 +498,7 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
   fprintf (file, _("  --no-bind			 Do not bind this image\n"));
   fprintf (file, _("  --wdmdriver		 Driver uses the WDM model\n"));
   fprintf (file, _("  --tsaware                  Image is Terminal Server aware\n"));
+  fprintf (file, _("  --build-id[=STYLE]         Generate build ID\n"));
 }
 
 
@@ -687,6 +693,7 @@ set_pe_stack_heap (char *resname, char *comname)
     einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg);
 }
 
+#define DEFAULT_BUILD_ID_STYLE	"md5"
 
 static bfd_boolean
 gld${EMULATION_NAME}_handle_option (int optc)
@@ -872,6 +879,17 @@ gld${EMULATION_NAME}_handle_option (int optc)
     case OPTION_TERMINAL_SERVER_AWARE:
       pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
       break;
+    case OPTION_BUILD_ID:
+      if (emit_build_id != NULL)
+	{
+	  free ((char *) emit_build_id);
+	  emit_build_id = NULL;
+	}
+      if (optarg == NULL)
+	optarg = DEFAULT_BUILD_ID_STYLE;
+      if (strcmp (optarg, "none"))
+	emit_build_id = xstrdup (optarg);
+      break;
     }
 
   /*  Set DLLCharacteristics bits  */
@@ -1227,6 +1245,163 @@ debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
     *found = 1;
 }
 
+static bfd_boolean
+pecoff_checksum_contents(bfd *abfd,
+                         void (*process) (const void *, size_t, void *),
+                         void *arg)
+{
+  file_ptr filepos = (file_ptr) 0;
+
+  while (1)
+    {
+      unsigned char b;
+      int status;
+
+      if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	return 0;
+
+      status = bfd_bread (&b, (bfd_size_type) 1, abfd);
+      if (status < 1)
+        {
+          break;
+        }
+
+      (*process) (&b, 1, arg);
+      filepos += 1;
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+write_build_id (bfd *abfd)
+{
+  struct pe_tdata *t = pe_data(abfd);
+  asection *asec;
+  struct bfd_link_order *link_order = NULL;
+  unsigned char *contents;
+  bfd_size_type size;
+
+  /* find the section the .build-id output section has been merged info */
+  for (asec = abfd->sections; asec != NULL; asec = asec->next)
+    {
+      struct bfd_link_order *l = NULL;
+      for (l = asec->map_head.link_order; l != NULL; l = l->next)
+        {
+          if ((l->type == bfd_indirect_link_order))
+            {
+              if (l->u.indirect.section == t->build_id.sec)
+                {
+                  link_order = l;
+                  break;
+                }
+            }
+        }
+
+      if (link_order)
+        break;
+    }
+
+  if (!link_order)
+    {
+      einfo (_("%P: warning: .build-id section discarded,"
+               " --build-id ignored.\n"));
+      return TRUE;
+    }
+
+  if (t->build_id.sec->contents == NULL)
+    t->build_id.sec->contents = (unsigned char *) xmalloc (t->build_id.sec->size);
+  contents = t->build_id.sec->contents;
+  size = t->build_id.sec->size;
+
+  bfd_size_type build_id_size = compute_build_id_size(t->build_id.style);
+  unsigned char *build_id = xmalloc(build_id_size);
+  generate_build_id(abfd, t->build_id.style, pecoff_checksum_contents, build_id);
+
+  bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase;
+
+  /* Construct a debug directory entry which points to an immediately following CodeView record */
+  struct internal_IMAGE_DEBUG_DIRECTORY idd;
+  idd.Characteristics = 0;
+  idd.TimeDateStamp = 0;
+  idd.MajorVersion = 0;
+  idd.MinorVersion = 0;
+  idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW;
+  idd.SizeOfData = sizeof(CV_INFO_PDB70) + 1;
+  idd.AddressOfRawData = asec->vma - ib + link_order->offset + sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+  idd.PointerToRawData = asec->filepos + link_order->offset + sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+
+  struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *)contents;
+  _bfd_XXi_swap_debugdir_out(abfd, &idd, ext);
+
+  /* Write the debug directory enttry */
+  if (bfd_seek (abfd, asec->filepos + link_order->offset, SEEK_SET) != 0)
+    return 0;
+
+  if ((bfd_bwrite (contents, size, abfd) != size))
+    return 0;
+
+  /* construct the CodeView record */
+  CODEVIEW_INFO cvinfo;
+  cvinfo.CVSignature = CVINFO_PDB70_CVSIGNATURE;
+  cvinfo.Age = 1;
+
+  /* zero pad or truncate the generated build_id to fit in the CodeView record */
+  memset(&(cvinfo.Signature), 0, CV_INFO_SIGNATURE_LENGTH);
+  memcpy(&(cvinfo.Signature), build_id, (build_id_size > CV_INFO_SIGNATURE_LENGTH) ? CV_INFO_SIGNATURE_LENGTH :  build_id_size);
+
+  free(build_id);
+
+  /* Write the codeview record */
+  if (_bfd_XXi_write_codeview_record(abfd, idd.PointerToRawData, &cvinfo) == 0)
+    return 0;
+
+  /* Record the location of the debug directory in the data directory */
+  pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress = asec->vma  - ib + link_order->offset;
+  pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size = sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+
+  return TRUE;
+}
+
+/* Make .build-id section, and set up coff_tdata->build_id. */
+static bfd_boolean
+setup_build_id (bfd *ibfd)
+{
+  asection *s;
+  flagword flags;
+
+  if (!validate_build_id_style (emit_build_id))
+    {
+      einfo ("%P: warning: unrecognized --build-id style ignored.\n");
+      return FALSE;
+    }
+
+  flags = (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+  s = bfd_make_section_anyway_with_flags (ibfd, ".build-id", flags);
+  if (s != NULL)
+    {
+      struct pe_tdata *t = pe_data(link_info.output_bfd);
+      t->build_id.after_write_object_contents = &write_build_id;
+      t->build_id.style = emit_build_id;
+      t->build_id.sec = s;
+
+      /*
+        section is a fixed size:
+        one IMAGE_DEBUG_DIRECTORY entry, of type IMAGE_DEBUG_TYPE_CODEVIEW,
+        pointing at a CV_INFO_PDB70 record containing the build-id, with a
+        null byte for PdbFileName
+      */
+      s->size = sizeof(struct external_IMAGE_DEBUG_DIRECTORY) + sizeof(CV_INFO_PDB70) + 1;
+
+      return TRUE;
+    }
+
+  einfo ("%P: warning: Cannot create .build-id section,"
+	 " --build-id ignored.\n");
+  return FALSE;
+}
+
 static void
 gld_${EMULATION_NAME}_after_open (void)
 {
@@ -1249,6 +1424,26 @@ gld_${EMULATION_NAME}_after_open (void)
     }
 #endif
 
+  if (emit_build_id != NULL)
+    {
+      bfd *abfd;
+
+      /* Find a COFF input.  */
+      for (abfd = link_info.input_bfds;
+	   abfd != (bfd *) NULL; abfd = abfd->link_next)
+	if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+	  break;
+
+      /* If there are no COFF input files do not try to
+	 add a build-id section.  */
+      if (abfd == NULL
+	  || !setup_build_id (abfd))
+	{
+	  free ((char *) emit_build_id);
+	  emit_build_id = NULL;
+	}
+    }
+
   /* Pass the wacky PE command line options into the output bfd.
      FIXME: This should be done via a function, rather than by
      including an internal BFD header.  */
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index b738800..750c127 100644
--- a/ld/emultempl/pep.em
+++ b/ld/emultempl/pep.em
@@ -64,6 +64,7 @@ fragment <<EOF
 #include "ldlex.h"
 #include "ldmisc.h"
 #include "ldctor.h"
+#include "ldbuildid.h"
 #include "coff/internal.h"
 
 /* FIXME: See bfd/peXXigen.c for why we include an architecture specific
@@ -71,9 +72,10 @@ fragment <<EOF
 #include "coff/x86_64.h"
 #include "coff/pe.h"
 
-/* FIXME: This is a BFD internal header file, and we should not be
+/* FIXME: These are BFD internal header files, and we should not be
    using it here.  */
 #include "../bfd/libcoff.h"
+#include "../bfd/libpei.h"
 
 #undef  AOUTSZ
 #define AOUTSZ		PEPAOUTSZ
@@ -146,6 +148,7 @@ static int support_old_code = 0;
 static lang_assignment_statement_type *image_base_statement = 0;
 static unsigned short pe_dll_characteristics = 0;
 static bfd_boolean insert_timestamp = FALSE;
+static const char *emit_build_id;
 
 #ifdef DLL_SUPPORT
 static int    pep_enable_stdcall_fixup = 1; /* 0=disable 1=enable (default).  */
@@ -242,7 +245,8 @@ enum options
   OPTION_NO_BIND,
   OPTION_WDM_DRIVER,
   OPTION_INSERT_TIMESTAMP,
-  OPTION_TERMINAL_SERVER_AWARE
+  OPTION_TERMINAL_SERVER_AWARE,
+  OPTION_BUILD_ID
 };
 
 static void
@@ -318,6 +322,7 @@ gld${EMULATION_NAME}_add_options
     {"wdmdriver", no_argument, NULL, OPTION_WDM_DRIVER},
     {"tsaware", no_argument, NULL, OPTION_TERMINAL_SERVER_AWARE},
     {"insert-timestamp", no_argument, NULL, OPTION_INSERT_TIMESTAMP},
+    {"build-id", optional_argument, NULL, OPTION_BUILD_ID},
     {NULL, no_argument, NULL, 0}
   };
 
@@ -453,6 +458,7 @@ gld_${EMULATION_NAME}_list_options (FILE *file)
   fprintf (file, _("  --no-bind			 Do not bind this image\n"));
   fprintf (file, _("  --wdmdriver		 Driver uses the WDM model\n"));
   fprintf (file, _("  --tsaware                  Image is Terminal Server aware\n"));
+  fprintf (file, _("  --build-id[=STYLE]         Generate build ID\n"));
 #endif
 }
 
@@ -643,6 +649,7 @@ set_pep_stack_heap (char *resname, char *comname)
     einfo (_("%P%F: strange hex info for PE parameter '%s'\n"), optarg);
 }
 
+#define DEFAULT_BUILD_ID_STYLE	"md5"
 
 static bfd_boolean
 gld${EMULATION_NAME}_handle_option (int optc)
@@ -816,6 +823,17 @@ gld${EMULATION_NAME}_handle_option (int optc)
     case OPTION_TERMINAL_SERVER_AWARE:
       pe_dll_characteristics |= IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE;
       break;
+    case OPTION_BUILD_ID:
+      if (emit_build_id != NULL)
+	{
+	  free ((char *) emit_build_id);
+	  emit_build_id = NULL;
+	}
+      if (optarg == NULL)
+	optarg = DEFAULT_BUILD_ID_STYLE;
+      if (strcmp (optarg, "none"))
+	emit_build_id = xstrdup (optarg);
+      break;
     }
 
   /*  Set DLLCharacteristics bits  */
@@ -1191,6 +1209,163 @@ debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
     *found = 1;
 }
 
+static bfd_boolean
+pecoff_checksum_contents(bfd *abfd,
+                         void (*process) (const void *, size_t, void *),
+                         void *arg)
+{
+  file_ptr filepos = (file_ptr) 0;
+
+  while (1)
+    {
+      unsigned char b;
+      int status;
+
+      if (bfd_seek (abfd, filepos, SEEK_SET) != 0)
+	return 0;
+
+      status = bfd_bread (&b, (bfd_size_type) 1, abfd);
+      if (status < 1)
+        {
+          break;
+        }
+
+      (*process) (&b, 1, arg);
+      filepos += 1;
+    }
+
+  return TRUE;
+}
+
+static bfd_boolean
+write_build_id (bfd *abfd)
+{
+  struct pe_tdata *t = pe_data(abfd);
+  asection *asec;
+  struct bfd_link_order *link_order = NULL;
+  unsigned char *contents;
+  bfd_size_type size;
+
+  /* find the section the .build-id output section has been merged info */
+  for (asec = abfd->sections; asec != NULL; asec = asec->next)
+    {
+      struct bfd_link_order *l = NULL;
+      for (l = asec->map_head.link_order; l != NULL; l = l->next)
+        {
+          if ((l->type == bfd_indirect_link_order))
+            {
+              if (l->u.indirect.section == t->build_id.sec)
+                {
+                  link_order = l;
+                  break;
+                }
+            }
+        }
+
+      if (link_order)
+        break;
+    }
+
+  if (!link_order)
+    {
+      einfo (_("%P: warning: .build-id section discarded,"
+               " --build-id ignored.\n"));
+      return TRUE;
+    }
+
+  if (t->build_id.sec->contents == NULL)
+    t->build_id.sec->contents = (unsigned char *) xmalloc (t->build_id.sec->size);
+  contents = t->build_id.sec->contents;
+  size = t->build_id.sec->size;
+
+  bfd_size_type build_id_size = compute_build_id_size(t->build_id.style);
+  unsigned char *build_id = xmalloc(build_id_size);
+  generate_build_id(abfd, t->build_id.style, pecoff_checksum_contents, build_id);
+
+  bfd_vma ib = pe_data (link_info.output_bfd)->pe_opthdr.ImageBase;
+
+  /* Construct a debug directory entry which points to an immediately following CodeView record */
+  struct internal_IMAGE_DEBUG_DIRECTORY idd;
+  idd.Characteristics = 0;
+  idd.TimeDateStamp = 0;
+  idd.MajorVersion = 0;
+  idd.MinorVersion = 0;
+  idd.Type = PE_IMAGE_DEBUG_TYPE_CODEVIEW;
+  idd.SizeOfData = sizeof(CV_INFO_PDB70) + 1;
+  idd.AddressOfRawData = asec->vma - ib + link_order->offset + sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+  idd.PointerToRawData = asec->filepos + link_order->offset + sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+
+  struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *)contents;
+  _bfd_XXi_swap_debugdir_out(abfd, &idd, ext);
+
+  /* Write the debug directory enttry */
+  if (bfd_seek (abfd, asec->filepos + link_order->offset, SEEK_SET) != 0)
+    return 0;
+
+  if ((bfd_bwrite (contents, size, abfd) != size))
+    return 0;
+
+  /* construct the CodeView record */
+  CODEVIEW_INFO cvinfo;
+  cvinfo.CVSignature = CVINFO_PDB70_CVSIGNATURE;
+  cvinfo.Age = 1;
+
+  /* zero pad or truncate the generated build_id to fit in the CodeView record */
+  memset(&(cvinfo.Signature), 0, CV_INFO_SIGNATURE_LENGTH);
+  memcpy(&(cvinfo.Signature), build_id, (build_id_size > CV_INFO_SIGNATURE_LENGTH) ? CV_INFO_SIGNATURE_LENGTH :  build_id_size);
+
+  free(build_id);
+
+  /* Write the codeview record */
+  if (_bfd_XXi_write_codeview_record(abfd, idd.PointerToRawData, &cvinfo) == 0)
+    return 0;
+
+  /* Record the location of the debug directory in the data directory */
+  pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].VirtualAddress = asec->vma  - ib + link_order->offset;
+  pe_data (link_info.output_bfd)->pe_opthdr.DataDirectory[PE_DEBUG_DATA].Size = sizeof(struct external_IMAGE_DEBUG_DIRECTORY);
+
+  return TRUE;
+}
+
+/* Make .build-id section, and set up coff_tdata->build_id. */
+static bfd_boolean
+setup_build_id (bfd *ibfd)
+{
+  asection *s;
+  flagword flags;
+
+  if (!validate_build_id_style (emit_build_id))
+    {
+      einfo ("%P: warning: unrecognized --build-id style ignored.\n");
+      return FALSE;
+    }
+
+  flags = (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_IN_MEMORY
+	   | SEC_LINKER_CREATED | SEC_READONLY | SEC_DATA);
+  s = bfd_make_section_anyway_with_flags (ibfd, ".build-id", flags);
+  if (s != NULL)
+    {
+      struct pe_tdata *t = pe_data(link_info.output_bfd);
+      t->build_id.after_write_object_contents = &write_build_id;
+      t->build_id.style = emit_build_id;
+      t->build_id.sec = s;
+
+      /*
+        section is a fixed size:
+        one IMAGE_DEBUG_DIRECTORY entry, of type IMAGE_DEBUG_TYPE_CODEVIEW,
+        pointing at a CV_INFO_PDB70 record containing the build-id, with a
+        null byte for PdbFileName
+      */
+      s->size = sizeof(struct external_IMAGE_DEBUG_DIRECTORY) + sizeof(CV_INFO_PDB70) + 1;
+
+      return TRUE;
+    }
+
+  einfo ("%P: warning: Cannot create .build-id section,"
+	 " --build-id ignored.\n");
+  return FALSE;
+}
+
 static void
 gld_${EMULATION_NAME}_after_open (void)
 {
@@ -1214,6 +1389,26 @@ gld_${EMULATION_NAME}_after_open (void)
     }
 #endif
 
+  if (emit_build_id != NULL)
+    {
+      bfd *abfd;
+
+      /* Find a COFF input.  */
+      for (abfd = link_info.input_bfds;
+	   abfd != (bfd *) NULL; abfd = abfd->link_next)
+	if (bfd_get_flavour (abfd) == bfd_target_coff_flavour)
+	  break;
+
+      /* If there are no COFF input files do not try to
+	 add a build-id section.  */
+      if (abfd == NULL
+	  || !setup_build_id (abfd))
+	{
+	  free ((char *) emit_build_id);
+	  emit_build_id = NULL;
+	}
+    }
+
   /* Pass the wacky PE command line options into the output bfd.
      FIXME: This should be done via a function, rather than by
      including an internal BFD header.  */
-- 
1.8.3.4


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