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:
parent
ae1d276159
commit
61e2488cd8
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
12
bfd/libpei.h
12
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
|
||||
|
216
bfd/peXXigen.c
216
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);
|
||||
|
||||
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
@ -152,17 +190,17 @@ 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;
|
||||
@ -172,38 +210,38 @@ struct internal_extra_pe_aouthdr
|
||||
bfd_vma BaseOfData;
|
||||
|
||||
/* PE stuff */
|
||||
bfd_vma ImageBase; /* address of specific location in memory that
|
||||
file is located, NT default 0x10000 */
|
||||
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 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];
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
18
ld/ChangeLog
18
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
|
||||
|
@ -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)
|
||||
|
@ -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@
|
||||
|
4
ld/NEWS
4
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:
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
158
ld/ldbuildid.c
Normal 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
39
ld/ldbuildid.h
Normal 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 */
|
@ -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)
|
||||
|
@ -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)
|
||||
#...
|
||||
|
@ -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)
|
||||
#...
|
||||
|
@ -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)
|
||||
#...
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
main:
|
||||
_main:
|
||||
nop
|
||||
|
@ -1,6 +1,8 @@
|
||||
.globl _mainCRTStartup
|
||||
.globl mainCRTStartup
|
||||
.globl start
|
||||
.text
|
||||
_mainCRTStartup:
|
||||
mainCRTStartup:
|
||||
start:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user