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.
This commit is contained in:
Jon TURNEY 2014-04-08 10:59:43 +01:00 committed by Nick Clifton
parent ae1d276159
commit 61e2488cd8
25 changed files with 1101 additions and 191 deletions

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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 */
/* 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. */
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];
};

View file

@ -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 */

View file

@ -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

View file

@ -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)

View file

@ -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@

View file

@ -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:

View file

@ -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;

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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

158
ld/ldbuildid.c Normal file
View file

@ -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;
}

39
ld/ldbuildid.h Normal file
View file

@ -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 */

View file

@ -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)

View file

@ -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)
#...

View file

@ -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)
#...

View file

@ -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)
#...

View file

@ -1,4 +1,3 @@
main:
_main:
nop

View file

@ -1,6 +1,8 @@
.globl _mainCRTStartup
.globl mainCRTStartup
.globl start
.text
_mainCRTStartup:
mainCRTStartup:
start: