aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon TURNEY <jon.turney@dronecode.org.uk>2014-04-08 10:59:43 +0100
committerNick Clifton <nickc@redhat.com>2014-04-08 10:59:43 +0100
commit61e2488cd8497d158303a78563ad40f51f5c3f8e (patch)
tree096a515807bb59268398b4dd879929e93f78fec3
parentae1d276159c3cfb29caacdf567aea01f433f78b0 (diff)
downloadfsf-binutils-gdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.zip
fsf-binutils-gdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.tar.gz
fsf-binutils-gdb-61e2488cd8497d158303a78563ad40f51f5c3f8e.tar.bz2
Add support for generating and inserting build IDs into COFF binaries.
* peXXigen.c (pe_print_debugdata): New function: Displays the contents of the debug directory and decodes codeview entries. (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out) (_bfd_XXi_slurp_codeview_record, _bfd_XXi_write_codeview_record): Add functions for reading and writing debugdir and codeview records. * libpei.h (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out) (_bfd_XXi_write_codeview_record): Add prototypes and macros. * 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. * pe.h (external_IMAGE_DEBUG_DIRECTORY, _CV_INFO_PDB70) (_CV_INFO_PDB20): Add structures and constants for debug directory and codeview records. * internal.h (internal_IMAGE_DEBUG_DIRECTORY, CODEVIEW_INFO): Add structures and constants for internal representation of debug directory and codeview records. * emultempl/elf32.em (id_note_section_size, read_hex, write_build_id): Move code for parsing build-id option and calculating the build-id to... * ldbuildid.c: New file. * ldbuildid.h: New file. * Makefile.am (CFILES, HFILES, OFILES, ld_new_SOURCES): Add new files. * Makefile.in: Regenerate. * ld.texinfo: Update --build-id description to mention COFF support. * NEWS: Mention support for COFF build ids. * 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: Likewise.
-rw-r--r--bfd/ChangeLog15
-rw-r--r--bfd/coffcode.h13
-rw-r--r--bfd/libcoff-in.h8
-rw-r--r--bfd/libcoff.h8
-rw-r--r--bfd/libpei.h12
-rw-r--r--bfd/peXXigen.c218
-rw-r--r--include/coff/ChangeLog9
-rw-r--r--include/coff/internal.h116
-rw-r--r--include/coff/pe.h49
-rw-r--r--ld/ChangeLog18
-rw-r--r--ld/Makefile.am10
-rw-r--r--ld/Makefile.in13
-rw-r--r--ld/NEWS4
-rw-r--r--ld/emultempl/elf32.em96
-rw-r--r--ld/emultempl/pe.em233
-rw-r--r--ld/emultempl/pep.em234
-rw-r--r--ld/ld.texinfo20
-rw-r--r--ld/ldbuildid.c158
-rw-r--r--ld/ldbuildid.h39
-rw-r--r--ld/ldmain.c7
-rw-r--r--ld/testsuite/ld-pe/longsecn-3.d3
-rw-r--r--ld/testsuite/ld-pe/longsecn-4.d3
-rw-r--r--ld/testsuite/ld-pe/longsecn-5.d3
-rw-r--r--ld/testsuite/ld-pe/non-c-lang-syms.s1
-rw-r--r--ld/testsuite/ld-pe/orphana_nu.s2
25 files changed, 1101 insertions, 191 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 6ad175f..70d23c5 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,18 @@
+2014-04-08 Jon TURNEY <jon.turney@dronecode.org.uk>
+
+ * peXXigen.c (pe_print_debugdata): New function: Displays the
+ contents of the debug directory and decodes codeview entries.
+ (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out)
+ (_bfd_XXi_slurp_codeview_record, _bfd_XXi_write_codeview_record):
+ Add functions for reading and writing debugdir and codeview
+ records.
+ * libpei.h (_bfd_XXi_swap_debugdir_in, _bfd_XXi_swap_debugdir_out)
+ (_bfd_XXi_write_codeview_record): Add prototypes and macros.
+ * 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.
+
2014-04-05 Alan Modra <amodra@gmail.com>
* elflink.c (_bfd_elf_add_default_symbol): Pass poldbfd when
diff --git a/bfd/coffcode.h b/bfd/coffcode.h
index d6fe39f..4994fb3 100644
--- a/bfd/coffcode.h
+++ b/bfd/coffcode.h
@@ -4329,7 +4329,18 @@ 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 a556edc..cc1e52b 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 36c9829..6cb387c 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/bfd/libpei.h b/bfd/libpei.h
index 0fdafb0..ffcafde 100644
--- a/bfd/libpei.h
+++ b/bfd/libpei.h
@@ -235,6 +235,9 @@
#define _bfd_XXi_swap_scnhdr_out _bfd_pex64i_swap_scnhdr_out
#define _bfd_XXi_swap_sym_in _bfd_pex64i_swap_sym_in
#define _bfd_XXi_swap_sym_out _bfd_pex64i_swap_sym_out
+#define _bfd_XXi_swap_debugdir_in _bfd_pex64i_swap_debugdir_in
+#define _bfd_XXi_swap_debugdir_out _bfd_pex64i_swap_debugdir_out
+#define _bfd_XXi_write_codeview_record _bfd_pex64i_write_codeview_record
#elif defined COFF_WITH_pep
@@ -266,6 +269,9 @@
#define _bfd_XXi_swap_scnhdr_out _bfd_pepi_swap_scnhdr_out
#define _bfd_XXi_swap_sym_in _bfd_pepi_swap_sym_in
#define _bfd_XXi_swap_sym_out _bfd_pepi_swap_sym_out
+#define _bfd_XXi_swap_debugdir_in _bfd_pepi_swap_debugdir_in
+#define _bfd_XXi_swap_debugdir_out _bfd_pepi_swap_debugdir_out
+#define _bfd_XXi_write_codeview_record _bfd_pepi_write_codeview_record
#else /* !COFF_WITH_pep */
@@ -297,6 +303,9 @@
#define _bfd_XXi_swap_scnhdr_out _bfd_pei_swap_scnhdr_out
#define _bfd_XXi_swap_sym_in _bfd_pei_swap_sym_in
#define _bfd_XXi_swap_sym_out _bfd_pei_swap_sym_out
+#define _bfd_XXi_swap_debugdir_in _bfd_pei_swap_debugdir_in
+#define _bfd_XXi_swap_debugdir_out _bfd_pei_swap_debugdir_out
+#define _bfd_XXi_write_codeview_record _bfd_pei_write_codeview_record
#endif /* !COFF_WITH_pep */
@@ -339,6 +348,9 @@ bfd_boolean _bfd_XX_print_private_bfd_data_common (bfd *, void *);
bfd_boolean _bfd_XX_bfd_copy_private_bfd_data_common (bfd *, bfd *);
void _bfd_XX_get_symbol_info (bfd *, asymbol *, symbol_info *);
bfd_boolean _bfd_XXi_final_link_postscript (bfd *, struct coff_final_link_info *);
+void _bfd_XXi_swap_debugdir_in (bfd *, void *, void *);
+unsigned _bfd_XXi_swap_debugdir_out (bfd *, void *, void *);
+unsigned _bfd_XXi_write_codeview_record (bfd *, file_ptr, CODEVIEW_INFO *);
/* The following are needed only for ONE of pe or pei, but don't
otherwise vary; peicode.h fixes up ifdefs but we provide the
diff --git a/bfd/peXXigen.c b/bfd/peXXigen.c
index e78edaa..ea7846f 100644
--- a/bfd/peXXigen.c
+++ b/bfd/peXXigen.c
@@ -802,7 +802,7 @@ _bfd_XXi_only_swap_filehdr_out (bfd * abfd, void * in, void * out)
/* Only use a real timestamp if the option was chosen. */
if ((pe_data (abfd)->insert_timestamp))
- H_PUT_32 (abfd, time(0), filehdr_out->f_timdat);
+ H_PUT_32 (abfd, time (0), filehdr_out->f_timdat);
PUT_FILEHDR_SYMPTR (abfd, filehdr_in->f_symptr,
filehdr_out->f_symptr);
@@ -1031,6 +1031,106 @@ _bfd_XXi_swap_scnhdr_out (bfd * abfd, void * in, void * out)
return ret;
}
+void
+_bfd_XXi_swap_debugdir_in (bfd * abfd, void * ext1, void * in1)
+{
+ struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) ext1;
+ struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) in1;
+
+ in->Characteristics = H_GET_32(abfd, ext->Characteristics);
+ in->TimeDateStamp = H_GET_32(abfd, ext->TimeDateStamp);
+ in->MajorVersion = H_GET_16(abfd, ext->MajorVersion);
+ in->MinorVersion = H_GET_16(abfd, ext->MinorVersion);
+ in->Type = H_GET_32(abfd, ext->Type);
+ in->SizeOfData = H_GET_32(abfd, ext->SizeOfData);
+ in->AddressOfRawData = H_GET_32(abfd, ext->AddressOfRawData);
+ in->PointerToRawData = H_GET_32(abfd, ext->PointerToRawData);
+}
+
+unsigned int
+_bfd_XXi_swap_debugdir_out (bfd * abfd, void * inp, void * extp)
+{
+ struct external_IMAGE_DEBUG_DIRECTORY *ext = (struct external_IMAGE_DEBUG_DIRECTORY *) extp;
+ struct internal_IMAGE_DEBUG_DIRECTORY *in = (struct internal_IMAGE_DEBUG_DIRECTORY *) inp;
+
+ H_PUT_32(abfd, in->Characteristics, ext->Characteristics);
+ H_PUT_32(abfd, in->TimeDateStamp, ext->TimeDateStamp);
+ H_PUT_16(abfd, in->MajorVersion, ext->MajorVersion);
+ H_PUT_16(abfd, in->MinorVersion, ext->MinorVersion);
+ H_PUT_32(abfd, in->Type, ext->Type);
+ H_PUT_32(abfd, in->SizeOfData, ext->SizeOfData);
+ H_PUT_32(abfd, in->AddressOfRawData, ext->AddressOfRawData);
+ H_PUT_32(abfd, in->PointerToRawData, ext->PointerToRawData);
+
+ return sizeof (struct external_IMAGE_DEBUG_DIRECTORY);
+}
+
+static CODEVIEW_INFO *
+_bfd_XXi_slurp_codeview_record (bfd * abfd, file_ptr where, unsigned long length, CODEVIEW_INFO *cvinfo)
+{
+ char buffer[256+1];
+
+ if (bfd_seek (abfd, where, SEEK_SET) != 0)
+ return NULL;
+
+ if (bfd_bread (buffer, 256, abfd) < 4)
+ return NULL;
+
+ /* ensure null termination of filename */
+ buffer[256] = '\0';
+
+ cvinfo->CVSignature = H_GET_32(abfd, buffer);
+ cvinfo->Age = 0;
+
+ if ((cvinfo->CVSignature == CVINFO_PDB70_CVSIGNATURE)
+ && (length > sizeof (CV_INFO_PDB70)))
+ {
+ CV_INFO_PDB70 *cvinfo70 = (CV_INFO_PDB70 *)(buffer);
+
+ cvinfo->Age = H_GET_32(abfd, cvinfo70->Age);
+ memcpy (cvinfo->Signature, cvinfo70->Signature, CV_INFO_SIGNATURE_LENGTH);
+ cvinfo->SignatureLength = CV_INFO_SIGNATURE_LENGTH;
+ // cvinfo->PdbFileName = cvinfo70->PdbFileName;
+
+ return cvinfo;
+ }
+ else if ((cvinfo->CVSignature == CVINFO_PDB20_CVSIGNATURE)
+ && (length > sizeof (CV_INFO_PDB20)))
+ {
+ CV_INFO_PDB20 *cvinfo20 = (CV_INFO_PDB20 *)(buffer);
+ cvinfo->Age = H_GET_32(abfd, cvinfo20->Age);
+ memcpy (cvinfo->Signature, cvinfo20->Signature, 4);
+ cvinfo->SignatureLength = 4;
+ // cvinfo->PdbFileName = cvinfo20->PdbFileName;
+
+ return cvinfo;
+ }
+
+ return NULL;
+}
+
+unsigned int
+_bfd_XXi_write_codeview_record (bfd * abfd, file_ptr where, CODEVIEW_INFO *cvinfo)
+{
+ unsigned int size = sizeof (CV_INFO_PDB70) + 1;
+ CV_INFO_PDB70 *cvinfo70;
+ char buffer[size];
+
+ if (bfd_seek (abfd, where, SEEK_SET) != 0)
+ return 0;
+
+ cvinfo70 = (CV_INFO_PDB70 *) buffer;
+ H_PUT_32 (abfd, CVINFO_PDB70_CVSIGNATURE, cvinfo70->CvSignature);
+ memcpy (&(cvinfo70->Signature), cvinfo->Signature, CV_INFO_SIGNATURE_LENGTH);
+ H_PUT_32 (abfd, cvinfo->Age, cvinfo70->Age);
+ cvinfo70->PdbFileName[0] = '\0';
+
+ if (bfd_bwrite (buffer, size, abfd) != size)
+ return 0;
+
+ return size;
+}
+
static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] =
{
N_("Export Directory [.edata (or where ever we found it)]"),
@@ -2240,6 +2340,117 @@ rsrc_print_section (bfd * abfd, void * vfile)
return TRUE;
}
+#define IMAGE_NUMBEROF_DEBUG_TYPES 12
+
+static char * debug_type_names[IMAGE_NUMBEROF_DEBUG_TYPES] =
+{
+ "Unknown",
+ "COFF",
+ "CodeView",
+ "FPO",
+ "Misc",
+ "Exception",
+ "Fixup",
+ "OMAP-to-SRC",
+ "OMAP-from-SRC",
+ "Borland",
+ "Reserved",
+ "CLSID",
+};
+
+static bfd_boolean
+pe_print_debugdata (bfd * abfd, void * vfile)
+{
+ FILE *file = (FILE *) vfile;
+ pe_data_type *pe = pe_data (abfd);
+ struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr;
+ asection *section;
+ bfd_byte *data = 0;
+ bfd_size_type dataoff;
+ unsigned int i;
+
+ bfd_vma addr = extra->DataDirectory[PE_DEBUG_DATA].VirtualAddress;
+ bfd_size_type size = extra->DataDirectory[PE_DEBUG_DATA].Size;
+
+ if (size == 0)
+ return TRUE;
+
+ addr += extra->ImageBase;
+ for (section = abfd->sections; section != NULL; section = section->next)
+ {
+ if ((addr >= section->vma) && (addr < (section->vma + section->size)))
+ break;
+ }
+
+ if (section == NULL)
+ {
+ fprintf (file,
+ _("\nThere is a debug directory, but the section containing it could not be found\n"));
+ return TRUE;
+ }
+
+ fprintf (file, _("\nThere is a debug directory in %s at 0x%lx\n\n"),
+ section->name, (unsigned long) addr);
+
+ dataoff = addr - section->vma;
+
+ fprintf (file,
+ _("Type Size Rva Offset\n"));
+
+ /* Read the whole section. */
+ if (!bfd_malloc_and_get_section (abfd, section, &data))
+ {
+ if (data != NULL)
+ free (data);
+ return FALSE;
+ }
+
+ for (i = 0; i < size / sizeof (struct external_IMAGE_DEBUG_DIRECTORY); i++)
+ {
+ const char *type_name;
+ struct external_IMAGE_DEBUG_DIRECTORY *ext
+ = &((struct external_IMAGE_DEBUG_DIRECTORY *)(data + dataoff))[i];
+ struct internal_IMAGE_DEBUG_DIRECTORY idd;
+
+ _bfd_XXi_swap_debugdir_in (abfd, ext, &idd);
+
+ if ((idd.Type) > IMAGE_NUMBEROF_DEBUG_TYPES)
+ type_name = debug_type_names[0];
+ else
+ type_name = debug_type_names[idd.Type];
+
+ fprintf (file, " %2ld %14s %08lx %08lx %08lx\n",
+ idd.Type, type_name, idd.SizeOfData,
+ idd.AddressOfRawData, idd.PointerToRawData);
+
+ if (idd.Type == PE_IMAGE_DEBUG_TYPE_CODEVIEW)
+ {
+ char signature[CV_INFO_SIGNATURE_LENGTH * 2 + 1];
+ char buffer[256 + 1];
+ CODEVIEW_INFO *cvinfo = (CODEVIEW_INFO *) buffer;
+
+ /* The debug entry doesn't have to have to be in a section,
+ in which case AddressOfRawData is 0, so always use PointerToRawData. */
+ if (!_bfd_XXi_slurp_codeview_record (abfd, (file_ptr) idd.PointerToRawData,
+ idd.SizeOfData, cvinfo))
+ continue;
+
+ for (i = 0; i < cvinfo->SignatureLength; i++)
+ sprintf (&signature[i*2], "%02x", cvinfo->Signature[i] & 0xff);
+
+ fprintf (file, "(format %c%c%c%c signature %s age %ld)\n",
+ buffer[0], buffer[1], buffer[2], buffer[3],
+ signature, cvinfo->Age);
+ }
+ }
+
+ if (size % sizeof (struct external_IMAGE_DEBUG_DIRECTORY) != 0)
+ fprintf (file,
+ _("The debug directory size is not a multiple of the debug directory entry size\n"));
+
+ return TRUE;
+}
+
/* Print out the program headers. */
bfd_boolean
@@ -2413,6 +2624,7 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
else
pe_print_pdata (abfd, vfile);
pe_print_reloc (abfd, vfile);
+ pe_print_debugdata (abfd, file);
rsrc_print_section (abfd, vfile);
@@ -3576,7 +3788,7 @@ rsrc_process_section (bfd * abfd,
if (num_input_rsrc < 2)
goto end;
-
+
/* Step one: Walk the section, computing the size of the tables,
leaves and data and decide if we need to do anything. */
dataend = data + size;
@@ -3841,7 +4053,7 @@ _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
+ (bfd_get_symbol_leading_char (abfd) != 0
? "__tls_used" : "_tls_used"),
FALSE, FALSE, TRUE);
if (h1 != NULL)
diff --git a/include/coff/ChangeLog b/include/coff/ChangeLog
index 2ee6361..769e9ea 100644
--- a/include/coff/ChangeLog
+++ b/include/coff/ChangeLog
@@ -1,3 +1,12 @@
+2014-04-08 Jon TURNEY <jon.turney@dronecode.org.uk>
+
+ * pe.h (external_IMAGE_DEBUG_DIRECTORY, _CV_INFO_PDB70)
+ (_CV_INFO_PDB20): Add structures and constants for debug directory
+ and codeview records.
+ * internal.h (internal_IMAGE_DEBUG_DIRECTORY, CODEVIEW_INFO):
+ Add structures and constants for internal representation of debug
+ directory and codeview records.
+
2014-03-13 Tristan Gingold <gingold@adacore.com>
* pe.h (struct external_ANON_OBJECT_HEADER_BIGOBJ): Declare.
diff --git a/include/coff/internal.h b/include/coff/internal.h
index b34e5c6..47e85d9 100644
--- a/include/coff/internal.h
+++ b/include/coff/internal.h
@@ -1,18 +1,18 @@
/* Internal format of COFF object file data structures, for GNU BFD.
This file is part of BFD, the Binary File Descriptor library.
-
+
Copyright (C) 1999-2014 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
@@ -55,7 +55,7 @@ struct internal_extra_pe_filehdr
unsigned short e_res2[10]; /* Reserved words, all 0x0 */
bfd_vma e_lfanew; /* File address of new exe header, 0x80 */
unsigned long dos_message[16]; /* text which always follows dos header */
- bfd_vma nt_signature; /* required NT signature, 0x4550 */
+ bfd_vma nt_signature; /* required NT signature, 0x4550 */
};
#define GO32_STUBSIZE 2048
@@ -66,7 +66,7 @@ struct internal_filehdr
/* coff-stgo32 EXE stub header before BFD tdata has been allocated.
Its data is kept in INTERNAL_FILEHDR.GO32STUB afterwards.
-
+
F_GO32STUB is set iff go32stub contains a valid data. Artifical headers
created in BFD have no pre-set go32stub. */
char go32stub[GO32_STUBSIZE];
@@ -109,7 +109,7 @@ struct internal_filehdr
#define F_GO32STUB (0x4000)
/* Extra structure which is used in the optional header. */
-typedef struct _IMAGE_DATA_DIRECTORY
+typedef struct _IMAGE_DATA_DIRECTORY
{
bfd_vma VirtualAddress;
long Size;
@@ -132,6 +132,44 @@ typedef struct _IMAGE_DATA_DIRECTORY
/* DataDirectory[15] is currently reserved, so no define. */
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+/* Extra structure used in debug directory. */
+struct internal_IMAGE_DEBUG_DIRECTORY
+{
+ unsigned long Characteristics;
+ unsigned long TimeDateStamp;
+ unsigned short MajorVersion;
+ unsigned short MinorVersion;
+ unsigned long Type;
+ unsigned long SizeOfData;
+ unsigned long AddressOfRawData;
+ unsigned long PointerToRawData;
+};
+
+#define PE_IMAGE_DEBUG_TYPE_UNKNOWN 0
+#define PE_IMAGE_DEBUG_TYPE_COFF 1
+#define PE_IMAGE_DEBUG_TYPE_CODEVIEW 2
+#define PE_IMAGE_DEBUG_TYPE_FPO 3
+#define PE_IMAGE_DEBUG_TYPE_MISC 4
+#define PE_IMAGE_DEBUG_TYPE_EXCEPTION 5
+#define PE_IMAGE_DEBUG_TYPE_FIXUP 6
+#define PE_IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
+#define PE_IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
+#define PE_IMAGE_DEBUG_TYPE_BORLAND 9
+#define PE_IMAGE_DEBUG_TYPE_RESERVED10 10
+#define PE_IMAGE_DEBUG_TYPE_CLSID 11
+
+/* Extra structure for a codeview debug record */
+#define CV_INFO_SIGNATURE_LENGTH 16
+
+typedef struct _CODEVIEW_INFO
+{
+ unsigned long CVSignature;
+ char Signature[CV_INFO_SIGNATURE_LENGTH];
+ unsigned int SignatureLength;
+ unsigned long Age;
+ // char PdbFileName[];
+} CODEVIEW_INFO;
+
/* Default image base for NT. */
#define NT_EXE_IMAGE_BASE 0x400000
#define NT_DLL_IMAGE_BASE 0x10000000
@@ -147,22 +185,22 @@ typedef struct _IMAGE_DATA_DIRECTORY
# define PE_DEF_FILE_ALIGNMENT 0x200
#endif
-struct internal_extra_pe_aouthdr
+struct internal_extra_pe_aouthdr
{
/* FIXME: The following entries are in AOUTHDR. But they aren't
available internally in bfd. We add them here so that objdump
can dump them. */
- /* The state of the image file */
+ /* The state of the image file. */
short Magic;
- /* Linker major version number */
+ /* Linker major version number. */
char MajorLinkerVersion;
- /* Linker minor version number */
+ /* Linker minor version number. */
char MinorLinkerVersion;
- /* Total size of all code sections */
+ /* Total size of all code sections. */
long SizeOfCode;
- /* Total size of all initialized data sections */
+ /* Total size of all initialized data sections. */
long SizeOfInitializedData;
- /* Total size of all uninitialized data sections */
+ /* Total size of all uninitialized data sections. */
long SizeOfUninitializedData;
/* Address of entry point relative to image base. */
bfd_vma AddressOfEntryPoint;
@@ -170,40 +208,40 @@ struct internal_extra_pe_aouthdr
bfd_vma BaseOfCode;
/* Address of the first data section relative to image base. */
bfd_vma BaseOfData;
-
+
/* PE stuff */
- bfd_vma ImageBase; /* address of specific location in memory that
- file is located, NT default 0x10000 */
-
- bfd_vma SectionAlignment; /* section alignment default 0x1000 */
- bfd_vma FileAlignment; /* file alignment default 0x200 */
- short MajorOperatingSystemVersion; /* minimum version of the operating */
- short MinorOperatingSystemVersion; /* system req'd for exe, default to 1*/
- short MajorImageVersion; /* user defineable field to store version of */
- short MinorImageVersion; /* exe or dll being created, default to 0 */
- short MajorSubsystemVersion; /* minimum subsystem version required to */
- short MinorSubsystemVersion; /* run exe; default to 3.1 */
- long Reserved1; /* seems to be 0 */
- long SizeOfImage; /* size of memory to allocate for prog */
- long SizeOfHeaders; /* size of PE header and section table */
- long CheckSum; /* set to 0 */
+ bfd_vma ImageBase; /* Address of specific location in memory that
+ file is located, NT default 0x10000. */
+
+ bfd_vma SectionAlignment; /* Section alignment default 0x1000. */
+ bfd_vma FileAlignment; /* File alignment default 0x200. */
+ short MajorOperatingSystemVersion; /* Minimum version of the operating. */
+ short MinorOperatingSystemVersion; /* System req'd for exe, default to 1. */
+ short MajorImageVersion; /* User defineable field to store version of */
+ short MinorImageVersion; /* exe or dll being created, default to 0. */
+ short MajorSubsystemVersion; /* Minimum subsystem version required to */
+ short MinorSubsystemVersion; /* run exe; default to 3.1. */
+ long Reserved1; /* Seems to be 0. */
+ long SizeOfImage; /* Size of memory to allocate for prog. */
+ long SizeOfHeaders; /* Size of PE header and section table. */
+ long CheckSum; /* Set to 0. */
short Subsystem;
- /* type of subsystem exe uses for user interface,
+ /* Type of subsystem exe uses for user interface,
possible values:
1 - NATIVE Doesn't require a subsystem
2 - WINDOWS_GUI runs in Windows GUI subsystem
3 - WINDOWS_CUI runs in Windows char sub. (console app)
5 - OS2_CUI runs in OS/2 character subsystem
- 7 - POSIX_CUI runs in Posix character subsystem */
- unsigned short DllCharacteristics; /* flags for DLL init */
- bfd_vma SizeOfStackReserve; /* amount of memory to reserve */
- bfd_vma SizeOfStackCommit; /* amount of memory initially committed for
- initial thread's stack, default is 0x1000 */
- bfd_vma SizeOfHeapReserve; /* amount of virtual memory to reserve and */
- bfd_vma SizeOfHeapCommit; /* commit, don't know what to defaut it to */
- long LoaderFlags; /* can probably set to 0 */
- long NumberOfRvaAndSizes; /* number of entries in next entry, 16 */
+ 7 - POSIX_CUI runs in Posix character subsystem. */
+ unsigned short DllCharacteristics; /* flags for DLL init. */
+ bfd_vma SizeOfStackReserve; /* Amount of memory to reserve. */
+ bfd_vma SizeOfStackCommit; /* Amount of memory initially committed for
+ initial thread's stack, default is 0x1000. */
+ bfd_vma SizeOfHeapReserve; /* Amount of virtual memory to reserve and */
+ bfd_vma SizeOfHeapCommit; /* commit, don't know what to defaut it to. */
+ long LoaderFlags; /* Can probably set to 0. */
+ long NumberOfRvaAndSizes; /* Number of entries in next entry, 16. */
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
};
diff --git a/include/coff/pe.h b/include/coff/pe.h
index 3166531..0ed9dde 100644
--- a/include/coff/pe.h
+++ b/include/coff/pe.h
@@ -1,4 +1,4 @@
-/* pe.h - PE COFF header information
+/* pe.h - PE COFF header information
Copyright (C) 1999-2014 Free Software Foundation, Inc.
@@ -163,9 +163,9 @@
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
#define IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER 13
#define IMAGE_SUBSYSTEM_XBOX 14
-
+
/* Magic values that are true for all dos/nt implementations. */
-#define DOSMAGIC 0x5a4d
+#define DOSMAGIC 0x5a4d
#define NT_SIGNATURE 0x00004550
/* NT allows long filenames, we want to accommodate this.
@@ -264,7 +264,7 @@ struct external_PEI_filehdr
/* 32-bit PE a.out header: */
-typedef struct
+typedef struct
{
AOUTHDR standard;
@@ -300,7 +300,7 @@ typedef struct
/* Like PEAOUTHDR, except that the "standard" member has no BaseOfData
(aka data_start) member and that some of the members are 8 instead
of just 4 bytes long. */
-typedef struct
+typedef struct
{
#ifdef AOUTHDRSZ64
AOUTHDR64 standard;
@@ -338,7 +338,7 @@ typedef struct
#else
#define PEPAOUTSZ 240
#endif
-
+
#undef E_FILNMLEN
#define E_FILNMLEN 18 /* # characters in a file name. */
@@ -584,4 +584,41 @@ struct external_pex64_scope_entry
(PEX64_OFFSET_TO_SCOPE_COUNT(COUNTOFUNWINDCODES) + \
PEX64_SCOPE_ENTRY_SIZE * (IDX))
+/* Extra structure used in debug directory */
+struct external_IMAGE_DEBUG_DIRECTORY {
+ char Characteristics[4];
+ char TimeDateStamp[4];
+ char MajorVersion[2];
+ char MinorVersion[2];
+ char Type[4];
+ char SizeOfData[4];
+ char AddressOfRawData[4];
+ char PointerToRawData[4];
+};
+
+/* Extra structures used in codeview debug record */
+/* This is not part of the PE specification */
+
+#define CVINFO_PDB70_CVSIGNATURE 0x53445352 // "RSDS"
+#define CVINFO_PDB20_CVSIGNATURE 0x3031424e // "NB10"
+#define CVINFO_CV50_CVSIGNATURE 0x3131424e // "NB11"
+#define CVINFO_CV41_CVSIGNATURE 0x3930424e // âNB09"
+
+typedef struct _CV_INFO_PDB70
+{
+ char CvSignature[4];
+ char Signature[16];
+ char Age[4];
+ char PdbFileName[];
+} CV_INFO_PDB70;
+
+typedef struct _CV_INFO_PDB20
+{
+ char CvHeader[4];
+ char Offset[4];
+ char Signature[4];
+ char Age[4];
+ char PdbFileName[];
+} CV_INFO_PDB20;
+
#endif /* _PE_H */
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 0a02f90..cdba250 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,21 @@
+2014-04-08 Jon TURNEY <jon.turney@dronecode.org.uk>
+
+ * emultempl/elf32.em (id_note_section_size, read_hex, write_build_id):
+ Move code for parsing build-id option and calculating the build-id to...
+ * ldbuildid.c: New file.
+ * ldbuildid.h: New file.
+ * Makefile.am (CFILES, HFILES, OFILES, ld_new_SOURCES): Add new
+ files.
+ * Makefile.in: Regenerate.
+ * ld.texinfo: Update --build-id description to mention COFF
+ support.
+ * NEWS: Mention support for COFF build ids.
+ * 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: Likewise.
+
2014-04-04 Cary Coutant <ccoutant@google.com>
PR gold/16804
diff --git a/ld/Makefile.am b/ld/Makefile.am
index 795663f..3e2dc1a 100644
--- a/ld/Makefile.am
+++ b/ld/Makefile.am
@@ -496,12 +496,12 @@ ALL_EMUL_EXTRA_BINARIES =
CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \
mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \
- $(PLUGIN_C)
+ $(PLUGIN_C) ldbuildid.c
HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \
ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \
ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \
- elf-hints-local.h $(PLUGIN_H)
+ elf-hints-local.h $(PLUGIN_H) ldbuildid.h
GENERATED_CFILES = ldgram.c ldlex.c deffilep.c
GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h
@@ -513,7 +513,8 @@ BUILT_SOURCES = $(GENERATED_HFILES)
OFILES = ldgram.@OBJEXT@ ldlex-wrapper.@OBJEXT@ lexsup.@OBJEXT@ ldlang.@OBJEXT@ \
mri.@OBJEXT@ ldctor.@OBJEXT@ ldmain.@OBJEXT@ $(PLUGIN_OBJECT) \
ldwrite.@OBJEXT@ ldexp.@OBJEXT@ ldemul.@OBJEXT@ ldver.@OBJEXT@ ldmisc.@OBJEXT@ \
- ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES}
+ ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES} \
+ ldbuildid.@OBJEXT@
STAGESTUFF = *.@OBJEXT@ ldscripts/* e*.c
@@ -1935,7 +1936,8 @@ EXTRA_ld_new_SOURCES = deffilep.y ldlex.l
EXTRA_ld_new_SOURCES += pep-dll.c pe-dll.c
ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \
- ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C)
+ ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \
+ ldbuildid.c
ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(EMUL_EXTRA_BINARIES) \
$(BFDLIB) $(LIBIBERTY) $(LIBINTL_DEP)
ld_new_LDADD = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(BFDLIB) $(LIBIBERTY) $(LIBINTL)
diff --git a/ld/Makefile.in b/ld/Makefile.in
index 3c9f8f4..4f54c26 100644
--- a/ld/Makefile.in
+++ b/ld/Makefile.in
@@ -109,7 +109,7 @@ am_ld_new_OBJECTS = ldgram.$(OBJEXT) ldlex-wrapper.$(OBJEXT) \
ldctor.$(OBJEXT) ldmain.$(OBJEXT) ldwrite.$(OBJEXT) \
ldexp.$(OBJEXT) ldemul.$(OBJEXT) ldver.$(OBJEXT) \
ldmisc.$(OBJEXT) ldfile.$(OBJEXT) ldcref.$(OBJEXT) \
- $(am__objects_1)
+ $(am__objects_1) ldbuildid.$(OBJEXT)
ld_new_OBJECTS = $(am_ld_new_OBJECTS)
am__DEPENDENCIES_1 =
DEFAULT_INCLUDES = -I.@am__isrc@
@@ -800,12 +800,12 @@ ALL_EMUL_EXTRA_BINARIES =
CFILES = ldctor.c ldemul.c ldexp.c ldfile.c ldlang.c \
ldmain.c ldmisc.c ldver.c ldwrite.c lexsup.c \
mri.c ldcref.c pe-dll.c pep-dll.c ldlex-wrapper.c \
- $(PLUGIN_C)
+ $(PLUGIN_C) ldbuildid.c
HFILES = ld.h ldctor.h ldemul.h ldexp.h ldfile.h \
ldlang.h ldlex.h ldmain.h ldmisc.h ldver.h \
ldwrite.h mri.h deffile.h pe-dll.h pep-dll.h \
- elf-hints-local.h $(PLUGIN_H)
+ elf-hints-local.h $(PLUGIN_H) ldbuildid.h
GENERATED_CFILES = ldgram.c ldlex.c deffilep.c
GENERATED_HFILES = ldgram.h ldemul-list.h deffilep.h
@@ -816,7 +816,8 @@ BUILT_SOURCES = $(GENERATED_HFILES)
OFILES = ldgram.@OBJEXT@ ldlex-wrapper.@OBJEXT@ lexsup.@OBJEXT@ ldlang.@OBJEXT@ \
mri.@OBJEXT@ ldctor.@OBJEXT@ ldmain.@OBJEXT@ $(PLUGIN_OBJECT) \
ldwrite.@OBJEXT@ ldexp.@OBJEXT@ ldemul.@OBJEXT@ ldver.@OBJEXT@ ldmisc.@OBJEXT@ \
- ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES}
+ ldfile.@OBJEXT@ ldcref.@OBJEXT@ ${EMULATION_OFILES} ${EMUL_EXTRA_OFILES} \
+ ldbuildid.@OBJEXT@
STAGESTUFF = *.@OBJEXT@ ldscripts/* e*.c
@@ -838,7 +839,8 @@ ELF_GEN_DEPS = $(srcdir)/emultempl/generic.em $(srcdir)/emultempl/elf-generic.em
EXTRA_ld_new_SOURCES = deffilep.y ldlex.l pep-dll.c pe-dll.c \
$(ALL_EMULATION_SOURCES) $(ALL_64_EMULATION_SOURCES)
ld_new_SOURCES = ldgram.y ldlex-wrapper.c lexsup.c ldlang.c mri.c ldctor.c ldmain.c \
- ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C)
+ ldwrite.c ldexp.c ldemul.c ldver.c ldmisc.c ldfile.c ldcref.c $(PLUGIN_C) \
+ ldbuildid.c
ld_new_DEPENDENCIES = $(EMULATION_OFILES) $(EMUL_EXTRA_OFILES) $(EMUL_EXTRA_BINARIES) \
$(BFDLIB) $(LIBIBERTY) $(LIBINTL_DEP)
@@ -1365,6 +1367,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez80.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez8001.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ez8002.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldbuildid.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldcref.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldctor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldemul.Po@am__quote@
diff --git a/ld/NEWS b/ld/NEWS
index 94d086e..a9124b6 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,9 @@
-*- text -*-
+* Add support for the --build-id command line option to COFF based targets.
+
+* 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/elf32.em b/ld/emultempl/elf32.em
index de460a2..0173b66 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -39,10 +39,7 @@ fragment <<EOF
#include "bfd.h"
#include "libiberty.h"
#include "filenames.h"
-#include "safe-ctype.h"
#include "getopt.h"
-#include "md5.h"
-#include "sha1.h"
#include <fcntl.h>
#include "bfdlink.h"
@@ -54,6 +51,7 @@ fragment <<EOF
#include "ldlang.h"
#include "ldfile.h"
#include "ldemul.h"
+#include "ldbuildid.h"
#include <ldgram.h>
#include "elf/common.h"
#include "elf-bfd.h"
@@ -895,53 +893,20 @@ id_note_section_size (bfd *abfd ATTRIBUTE_UNUSED)
{
const char *style = emit_note_gnu_build_id;
bfd_size_type size;
+ bfd_size_type build_id_size;
size = offsetof (Elf_External_Note, name[sizeof "GNU"]);
size = (size + 3) & -(bfd_size_type) 4;
- if (!strcmp (style, "md5") || !strcmp (style, "uuid"))
- size += 128 / 8;
- else if (!strcmp (style, "sha1"))
- size += 160 / 8;
- else if (!strncmp (style, "0x", 2))
- {
- /* ID is in string form (hex). Convert to bits. */
- const char *id = style + 2;
- do
- {
- if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
- {
- ++size;
- id += 2;
- }
- else if (*id == '-' || *id == ':')
- ++id;
- else
- {
- size = 0;
- break;
- }
- } while (*id != '\0');
- }
+ build_id_size = compute_build_id_size (style);
+ if (build_id_size)
+ size += build_id_size;
else
size = 0;
return size;
}
-static unsigned char
-read_hex (const char xdigit)
-{
- if (ISDIGIT (xdigit))
- return xdigit - '0';
- if (ISUPPER (xdigit))
- return xdigit - 'A' + 0xa;
- if (ISLOWER (xdigit))
- return xdigit - 'a' + 0xa;
- abort ();
- return 0;
-}
-
static bfd_boolean
write_build_id (bfd *abfd)
{
@@ -954,7 +919,6 @@ write_build_id (bfd *abfd)
bfd_size_type size;
file_ptr position;
Elf_External_Note *e_note;
- typedef void (*sum_fn) (const void *, size_t, void *);
style = t->o->build_id.style;
asec = t->o->build_id.sec;
@@ -986,55 +950,7 @@ write_build_id (bfd *abfd)
bfd_h_put_32 (abfd, NT_GNU_BUILD_ID, &e_note->type);
memcpy (e_note->name, "GNU", sizeof "GNU");
- if (strcmp (style, "md5") == 0)
- {
- struct md5_ctx ctx;
-
- md5_init_ctx (&ctx);
- if (!bed->s->checksum_contents (abfd, (sum_fn) &md5_process_bytes, &ctx))
- return FALSE;
- md5_finish_ctx (&ctx, id_bits);
- }
- else if (strcmp (style, "sha1") == 0)
- {
- struct sha1_ctx ctx;
-
- sha1_init_ctx (&ctx);
- if (!bed->s->checksum_contents (abfd, (sum_fn) &sha1_process_bytes, &ctx))
- return FALSE;
- sha1_finish_ctx (&ctx, id_bits);
- }
- else if (strcmp (style, "uuid") == 0)
- {
- int n;
- int fd = open ("/dev/urandom", O_RDONLY);
- if (fd < 0)
- return FALSE;
- n = read (fd, id_bits, size);
- close (fd);
- if (n < (int) size)
- return FALSE;
- }
- else if (strncmp (style, "0x", 2) == 0)
- {
- /* ID is in string form (hex). Convert to bits. */
- const char *id = style + 2;
- size_t n = 0;
- do
- {
- if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
- {
- id_bits[n] = read_hex (*id++) << 4;
- id_bits[n++] |= read_hex (*id++);
- }
- else if (*id == '-' || *id == ':')
- ++id;
- else
- abort (); /* Should have been validated earlier. */
- } while (*id != '\0');
- }
- else
- abort (); /* Should have been validated earlier. */
+ generate_build_id (abfd, style, bed->s->checksum_contents, id_bits, size);
position = i_shdr->sh_offset + asec->output_offset;
size = asec->size;
diff --git a/ld/emultempl/pe.em b/ld/emultempl/pe.em
index c18cb26..ba51cc0 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. */
@@ -269,6 +272,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
@@ -347,6 +351,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}
};
@@ -386,7 +391,7 @@ typedef struct
#define U_SIZE(CSTR) \
(sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-#define D(field,symbol,def,usc) {&pe.field,sizeof(pe.field), def, symbol, 0, usc}
+#define D(field,symbol,def,usc) {&pe.field, sizeof (pe.field), def, symbol, 0, usc}
static definfo init[] =
{
@@ -495,6 +500,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"));
}
@@ -689,6 +695,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)
@@ -807,7 +814,7 @@ gld${EMULATION_NAME}_handle_option (int optc)
if (optarg && *optarg)
{
char *end;
- pe_auto_image_base = strtoul(optarg, &end, 0);
+ pe_auto_image_base = strtoul (optarg, &end, 0);
/* XXX should check that we actually parsed something */
}
break;
@@ -880,6 +887,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 */
@@ -1235,6 +1253,169 @@ 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;
+ bfd_size_type build_id_size;
+ unsigned char *build_id;
+
+ /* 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;
+
+ build_id_size = compute_build_id_size (t->build_id.style);
+ build_id = xmalloc (build_id_size);
+ generate_build_id (abfd, t->build_id.style, pecoff_checksum_contents, build_id, build_id_size);
+
+ 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 entry. */
+ 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)
{
@@ -1257,6 +1438,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. */
@@ -1279,17 +1480,23 @@ gld_${EMULATION_NAME}_after_open (void)
find it, so enable it in that case. */
if (pe_use_coff_long_section_names < 0 && link_info.strip == strip_none)
{
- /* Iterate over all sections of all input BFDs, checking
- for any that begin 'debug_' and are long names. */
- LANG_FOR_EACH_INPUT_STATEMENT (is)
+ if (link_info.relocatable)
+ pe_use_coff_long_section_names = 1;
+ else
{
- int found_debug = 0;
- bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
- if (found_debug)
- {
- pe_use_coff_long_section_names = 1;
- break;
- }
+ /* Iterate over all sections of all input BFDs, checking
+ for any that begin 'debug_' and are long names. */
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ int found_debug = 0;
+
+ bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
+ if (found_debug)
+ {
+ pe_use_coff_long_section_names = 1;
+ break;
+ }
+ }
}
}
diff --git a/ld/emultempl/pep.em b/ld/emultempl/pep.em
index dca36cc..d1575e2 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}
};
@@ -355,7 +360,7 @@ typedef struct
#define U_SIZE(CSTR) \
(sizeof (CSTR) + (is_underscoring () == 0 ? 0 : 1))
-#define D(field,symbol,def,usc) {&pep.field,sizeof(pep.field), def, symbol,0, usc}
+#define D(field,symbol,def,usc) {&pep.field, sizeof (pep.field), def, symbol, 0, usc}
static definfo init[] =
{
@@ -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 */
@@ -1187,10 +1205,174 @@ static void
debug_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *sect, void *obj)
{
int *found = (int *) obj;
+
if (strncmp (".debug_", sect->name, sizeof (".debug_") - 1) == 0)
*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;
+ bfd_size_type build_id_size;
+ unsigned char *build_id;
+
+ /* 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;
+
+ build_id_size = compute_build_id_size (t->build_id.style);
+ build_id = xmalloc (build_id_size);
+ generate_build_id (abfd, t->build_id.style, pecoff_checksum_contents, build_id, build_id_size);
+
+ 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 +1396,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. */
@@ -1236,17 +1438,23 @@ gld_${EMULATION_NAME}_after_open (void)
find it, so enable it in that case. */
if (pep_use_coff_long_section_names < 0 && link_info.strip == strip_none)
{
- /* Iterate over all sections of all input BFDs, checking
- for any that begin 'debug_' and are long names. */
- LANG_FOR_EACH_INPUT_STATEMENT (is)
+ if (link_info.relocatable)
+ pep_use_coff_long_section_names = 1;
+ else
{
- int found_debug = 0;
- bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
- if (found_debug)
- {
- pep_use_coff_long_section_names = 1;
- break;
- }
+ /* Iterate over all sections of all input BFDs, checking
+ for any that begin 'debug_' and are long names. */
+ LANG_FOR_EACH_INPUT_STATEMENT (is)
+ {
+ int found_debug = 0;
+
+ bfd_map_over_sections (is->the_bfd, debug_section_p, &found_debug);
+ if (found_debug)
+ {
+ pep_use_coff_long_section_names = 1;
+ break;
+ }
+ }
}
}
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 62d8aa7..7d2de3b 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -2160,16 +2160,16 @@ enable other tradeoffs in future versions of the linker.
@kindex --build-id=@var{style}
@item --build-id
@itemx --build-id=@var{style}
-Request creation of @code{.note.gnu.build-id} ELF note section.
-The contents of the note are unique bits identifying this linked
-file. @var{style} can be @code{uuid} to use 128 random bits,
-@code{sha1} to use a 160-bit @sc{SHA1} hash on the normative
-parts of the output contents, @code{md5} to use a 128-bit
-@sc{MD5} hash on the normative parts of the output contents, or
-@code{0x@var{hexstring}} to use a chosen bit string specified as
-an even number of hexadecimal digits (@code{-} and @code{:}
-characters between digit pairs are ignored). If @var{style} is
-omitted, @code{sha1} is used.
+Request the creation of a @code{.note.gnu.build-id} ELF note section
+or a @code{.build-id} COFF section. The contents of the note are
+unique bits identifying this linked file. @var{style} can be
+@code{uuid} to use 128 random bits, @code{sha1} to use a 160-bit
+@sc{SHA1} hash on the normative parts of the output contents,
+@code{md5} to use a 128-bit @sc{MD5} hash on the normative parts of
+the output contents, or @code{0x@var{hexstring}} to use a chosen bit
+string specified as an even number of hexadecimal digits (@code{-} and
+@code{:} characters between digit pairs are ignored). If @var{style}
+is omitted, @code{sha1} is used.
The @code{md5} and @code{sha1} styles produces an identifier
that is always the same in an identical output file, but will be
diff --git a/ld/ldbuildid.c b/ld/ldbuildid.c
new file mode 100644
index 0000000..1214789
--- /dev/null
+++ b/ld/ldbuildid.c
@@ -0,0 +1,158 @@
+/* ldbuildid.c - Build Id support routines
+ Copyright 2013, 2014 Free Software Foundation, Inc.
+
+ This file is part of the GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "safe-ctype.h"
+#include "md5.h"
+#include "sha1.h"
+#include "ldbuildid.h"
+
+#define streq(a,b) strcmp ((a), (b)) == 0
+#define strneq(a,b,n) strncmp ((a), (b), (n)) == 0
+
+bfd_boolean
+validate_build_id_style (const char *style)
+{
+ if ((streq (style, "md5")) || (streq (style, "sha1"))
+#ifndef __MINGW32__
+ || (streq (style, "uuid"))
+#endif
+ || (strneq (style, "0x", 2)))
+ return TRUE;
+
+ return FALSE;
+}
+
+bfd_size_type
+compute_build_id_size (const char *style)
+{
+ if (streq (style, "md5") || streq (style, "uuid"))
+ return 128 / 8;
+
+ if (streq (style, "sha1"))
+ return 160 / 8;
+
+ if (strneq (style, "0x", 2))
+ {
+ bfd_size_type size = 0;
+ /* ID is in string form (hex). Count the bytes. */
+ const char *id = style + 2;
+
+ do
+ {
+ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
+ {
+ ++size;
+ id += 2;
+ }
+ else if (*id == '-' || *id == ':')
+ ++id;
+ else
+ {
+ size = 0;
+ break;
+ }
+ } while (*id != '\0');
+ return size;
+ }
+
+ return 0;
+}
+
+static unsigned char
+read_hex (const char xdigit)
+{
+ if (ISDIGIT (xdigit))
+ return xdigit - '0';
+
+ if (ISUPPER (xdigit))
+ return xdigit - 'A' + 0xa;
+
+ if (ISLOWER (xdigit))
+ return xdigit - 'a' + 0xa;
+
+ abort ();
+ return 0;
+}
+
+bfd_boolean
+generate_build_id (bfd *abfd,
+ const char *style,
+ checksum_fn checksum_contents,
+ unsigned char *id_bits,
+ int size)
+{
+ if (streq (style, "md5"))
+ {
+ struct md5_ctx ctx;
+
+ md5_init_ctx (&ctx);
+ if (!(*checksum_contents) (abfd, (sum_fn) &md5_process_bytes, &ctx))
+ return FALSE;
+ md5_finish_ctx (&ctx, id_bits);
+ }
+ else if (streq (style, "sha1"))
+ {
+ struct sha1_ctx ctx;
+
+ sha1_init_ctx (&ctx);
+ if (!(*checksum_contents) (abfd, (sum_fn) &sha1_process_bytes, &ctx))
+ return FALSE;
+ sha1_finish_ctx (&ctx, id_bits);
+ }
+#ifndef __MINGW32__
+ else if (streq (style, "uuid"))
+ {
+ int n;
+ int fd = open ("/dev/urandom", O_RDONLY);
+
+ if (fd < 0)
+ return FALSE;
+ n = read (fd, id_bits, size);
+ close (fd);
+ if (n < size)
+ return FALSE;
+ }
+#endif
+ else if (strneq (style, "0x", 2))
+ {
+ /* ID is in string form (hex). Convert to bits. */
+ const char *id = style + 2;
+ size_t n = 0;
+
+ do
+ {
+ if (ISXDIGIT (id[0]) && ISXDIGIT (id[1]))
+ {
+ id_bits[n] = read_hex (*id++) << 4;
+ id_bits[n++] |= read_hex (*id++);
+ }
+ else if (*id == '-' || *id == ':')
+ ++id;
+ else
+ abort (); /* Should have been validated earlier. */
+ } while (*id != '\0');
+ }
+ else
+ abort (); /* Should have been validated earlier. */
+
+ return TRUE;
+}
diff --git a/ld/ldbuildid.h b/ld/ldbuildid.h
new file mode 100644
index 0000000..a91ac1a
--- /dev/null
+++ b/ld/ldbuildid.h
@@ -0,0 +1,39 @@
+/* ldbuildid.h -
+ Copyright 2013, 2014 Free Software Foundation, Inc.
+
+ This file is part of the GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef LDBUILDID_H
+#define LDBUILDID_H
+
+extern bfd_boolean
+validate_build_id_style (const char *);
+
+extern bfd_size_type
+compute_build_id_size (const char *);
+
+typedef void (*sum_fn) (const void *, size_t, void *);
+
+typedef bfd_boolean (*checksum_fn) (bfd *,
+ void (*) (const void *, size_t, void *),
+ void *);
+
+extern bfd_boolean
+generate_build_id (bfd *, const char *, checksum_fn, unsigned char *, int);
+
+#endif /* LDBUILDID_H */
diff --git a/ld/ldmain.c b/ld/ldmain.c
index 14253a6..b132dae 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -378,6 +378,13 @@ main (int argc, char **argv)
lang_final ();
+ /* If the only command line argument has been -v or --version or --verbose
+ then ignore any input files provided by linker scripts and exit now.
+ We do not want to create an output file when the linker is just invoked
+ to provide version information. */
+ if (argc == 2 && version_printed)
+ xexit (0);
+
if (!lang_has_input_file)
{
if (version_printed || command_line.print_output_format)
diff --git a/ld/testsuite/ld-pe/longsecn-3.d b/ld/testsuite/ld-pe/longsecn-3.d
index 0317be3..c86a828 100644
--- a/ld/testsuite/ld-pe/longsecn-3.d
+++ b/ld/testsuite/ld-pe/longsecn-3.d
@@ -37,5 +37,4 @@ Idx Name Size VMA +LMA +File off Algn
CONTENTS, ALLOC, LOAD, DATA
14 \.rodata\.very\.long\.section\$1234 [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text) [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
- (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
diff --git a/ld/testsuite/ld-pe/longsecn-4.d b/ld/testsuite/ld-pe/longsecn-4.d
index 565ef38..e326d98 100644
--- a/ld/testsuite/ld-pe/longsecn-4.d
+++ b/ld/testsuite/ld-pe/longsecn-4.d
@@ -37,5 +37,4 @@ Idx Name Size VMA +LMA +File off Algn
CONTENTS, ALLOC, LOAD, DATA
14 \.rodata\. [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text) [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
- (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
diff --git a/ld/testsuite/ld-pe/longsecn-5.d b/ld/testsuite/ld-pe/longsecn-5.d
index 82d94b8..f3ef22b 100644
--- a/ld/testsuite/ld-pe/longsecn-5.d
+++ b/ld/testsuite/ld-pe/longsecn-5.d
@@ -37,5 +37,4 @@ Idx Name Size VMA +LMA +File off Algn
CONTENTS, ALLOC, LOAD, DATA
14 \.rodata\.very\.long\.section\$1234 [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
CONTENTS, ALLOC, LOAD, DATA
- 15 \.(bss |text) [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ 2\*\*[0-9]
- (ALLOC|CONTENTS, ALLOC, LOAD, (READONLY, )?CODE)
+#...
diff --git a/ld/testsuite/ld-pe/non-c-lang-syms.s b/ld/testsuite/ld-pe/non-c-lang-syms.s
index e849d9e..28006a1 100644
--- a/ld/testsuite/ld-pe/non-c-lang-syms.s
+++ b/ld/testsuite/ld-pe/non-c-lang-syms.s
@@ -1,4 +1,3 @@
-
main:
_main:
nop
diff --git a/ld/testsuite/ld-pe/orphana_nu.s b/ld/testsuite/ld-pe/orphana_nu.s
index d3c564f..618789c 100644
--- a/ld/testsuite/ld-pe/orphana_nu.s
+++ b/ld/testsuite/ld-pe/orphana_nu.s
@@ -1,6 +1,8 @@
+ .globl _mainCRTStartup
.globl mainCRTStartup
.globl start
.text
+_mainCRTStartup:
mainCRTStartup:
start: