diff options
Diffstat (limited to 'binutils-2.25/ld/emultempl/pe.em')
-rw-r--r-- | binutils-2.25/ld/emultempl/pe.em | 284 |
1 files changed, 256 insertions, 28 deletions
diff --git a/binutils-2.25/ld/emultempl/pe.em b/binutils-2.25/ld/emultempl/pe.em index 4df7753c..979cc8b8 100644 --- a/binutils-2.25/ld/emultempl/pe.em +++ b/binutils-2.25/ld/emultempl/pe.em @@ -8,7 +8,7 @@ fi rm -f e${EMULATION_NAME}.c (echo;echo;echo;echo;echo)>e${EMULATION_NAME}.c # there, now line numbers match ;-) fragment <<EOF -/* Copyright 1995-2013 Free Software Foundation, Inc. +/* Copyright (C) 1995-2014 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -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" @@ -130,12 +132,15 @@ static int support_old_code = 0; 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 = TRUE; +static const char *emit_build_id; #ifdef DLL_SUPPORT static int pe_enable_stdcall_fixup = -1; /* 0=disable 1=enable. */ static char *pe_out_def_filename = NULL; static char *pe_implib_filename = NULL; static int pe_enable_auto_image_base = 0; +static unsigned long pe_auto_image_base = 0x61500000; static char *pe_dll_search_prefix = NULL; #endif @@ -239,8 +244,7 @@ fragment <<EOF (OPTION_EXCLUDE_LIBS + 1) #define OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC \ (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC + 1) -#define OPTION_LARGE_ADDRESS_AWARE \ - (OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC + 1) +#define OPTION_LARGE_ADDRESS_AWARE (OPTION_DLL_DISABLE_RUNTIME_PSEUDO_RELOC + 1) #define OPTION_DISABLE_LARGE_ADDRESS_AWARE \ (OPTION_LARGE_ADDRESS_AWARE + 1) #define OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V1 \ @@ -251,15 +255,13 @@ fragment <<EOF (OPTION_DLL_ENABLE_RUNTIME_PSEUDO_RELOC_V2 + 1) #define OPTION_USE_NUL_PREFIXED_IMPORT_TABLES \ (OPTION_EXCLUDE_MODULES_FOR_IMPLIB + 1) -#define OPTION_NO_LEADING_UNDERSCORE \ - (OPTION_USE_NUL_PREFIXED_IMPORT_TABLES + 1) -#define OPTION_LEADING_UNDERSCORE \ - (OPTION_NO_LEADING_UNDERSCORE + 1) +#define OPTION_NO_LEADING_UNDERSCORE (OPTION_USE_NUL_PREFIXED_IMPORT_TABLES + 1) +#define OPTION_LEADING_UNDERSCORE (OPTION_NO_LEADING_UNDERSCORE + 1) #define OPTION_ENABLE_LONG_SECTION_NAMES \ (OPTION_LEADING_UNDERSCORE + 1) #define OPTION_DISABLE_LONG_SECTION_NAMES \ (OPTION_ENABLE_LONG_SECTION_NAMES + 1) -/* DLLCharacteristics flags */ +/* DLLCharacteristics flags. */ #define OPTION_DYNAMIC_BASE (OPTION_DISABLE_LONG_SECTION_NAMES + 1) #define OPTION_FORCE_INTEGRITY (OPTION_DYNAMIC_BASE + 1) #define OPTION_NX_COMPAT (OPTION_FORCE_INTEGRITY + 1) @@ -268,6 +270,10 @@ fragment <<EOF #define OPTION_NO_BIND (OPTION_NO_SEH + 1) #define OPTION_WDM_DRIVER (OPTION_NO_BIND + 1) #define OPTION_TERMINAL_SERVER_AWARE (OPTION_WDM_DRIVER + 1) +/* Determinism. */ +#define OPTION_INSERT_TIMESTAMP (OPTION_TERMINAL_SERVER_AWARE + 1) +#define OPTION_NO_INSERT_TIMESTAMP (OPTION_INSERT_TIMESTAMP + 1) +#define OPTION_BUILD_ID (OPTION_NO_INSERT_TIMESTAMP + 1) static void gld${EMULATION_NAME}_add_options @@ -301,6 +307,8 @@ gld${EMULATION_NAME}_add_options OPTION_USE_NUL_PREFIXED_IMPORT_TABLES}, {"no-leading-underscore", no_argument, NULL, OPTION_NO_LEADING_UNDERSCORE}, {"leading-underscore", no_argument, NULL, OPTION_LEADING_UNDERSCORE}, + {"insert-timestamp", no_argument, NULL, OPTION_INSERT_TIMESTAMP}, + {"no-insert-timestamp", no_argument, NULL, OPTION_NO_INSERT_TIMESTAMP}, #ifdef DLL_SUPPORT /* getopt allows abbreviations, so we do this to stop it from treating -o as an abbreviation for this option. */ @@ -321,7 +329,7 @@ gld${EMULATION_NAME}_add_options treating -c as an abbreviation for these --compat-implib. */ {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, {"compat-implib", no_argument, NULL, OPTION_IMP_COMPAT}, - {"enable-auto-image-base", no_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, + {"enable-auto-image-base", optional_argument, NULL, OPTION_ENABLE_AUTO_IMAGE_BASE}, {"disable-auto-image-base", no_argument, NULL, OPTION_DISABLE_AUTO_IMAGE_BASE}, {"dll-search-prefix", required_argument, NULL, OPTION_DLL_SEARCH_PREFIX}, {"no-default-excludes", no_argument, NULL, OPTION_NO_DEFAULT_EXCLUDES}, @@ -345,6 +353,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} }; @@ -384,7 +393,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[] = { @@ -438,6 +447,8 @@ gld_${EMULATION_NAME}_list_options (FILE *file) fprintf (file, _(" --support-old-code Support interworking with old code\n")); fprintf (file, _(" --[no-]leading-underscore Set explicit symbol underscore prefix mode\n")); fprintf (file, _(" --thumb-entry=<symbol> Set the entry point to be Thumb <symbol>\n")); + fprintf (file, _(" --[no-]insert-timestamp Use a real timestamp rather than zero (default).\n")); + fprintf (file, _(" This makes binaries non-deterministic\n")); #ifdef DLL_SUPPORT fprintf (file, _(" --add-stdcall-alias Export symbols with and without @nn\n")); fprintf (file, _(" --disable-stdcall-fixup Don't link _sym to _sym@nn\n")); @@ -452,11 +463,12 @@ gld_${EMULATION_NAME}_list_options (FILE *file) fprintf (file, _(" --kill-at Remove @nn from exported symbols\n")); fprintf (file, _(" --out-implib <file> Generate import library\n")); fprintf (file, _(" --output-def <file> Generate a .DEF file for the built DLL\n")); - fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports.\n")); + fprintf (file, _(" --warn-duplicate-exports Warn about duplicate exports\n")); fprintf (file, _(" --compat-implib Create backward compatible import libs;\n\ create __imp_<SYMBOL> as well.\n")); - fprintf (file, _(" --enable-auto-image-base Automatically choose image base for DLLs\n\ - unless user specifies one\n")); + fprintf (file, _(" --enable-auto-image-base[=<address>] Automatically choose image base for DLLs\n\ + (optionally starting with address) unless\n\ + specifically set with --image-base\n")); fprintf (file, _(" --disable-auto-image-base Do not auto-choose image base. (default)\n")); fprintf (file, _(" --dll-search-prefix=<string> When linking dynamically to a dll without\n\ an importlib, use <string><basename>.dll\n\ @@ -490,6 +502,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")); } @@ -684,6 +697,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) @@ -754,6 +768,12 @@ gld${EMULATION_NAME}_handle_option (int optc) case OPTION_LEADING_UNDERSCORE: pe_leading_underscore = 1; break; + case OPTION_INSERT_TIMESTAMP: + insert_timestamp = TRUE; + break; + case OPTION_NO_INSERT_TIMESTAMP: + insert_timestamp = FALSE; + break; #ifdef DLL_SUPPORT case OPTION_OUT_DEF: pe_out_def_filename = xstrdup (optarg); @@ -796,6 +816,12 @@ gld${EMULATION_NAME}_handle_option (int optc) break; case OPTION_ENABLE_AUTO_IMAGE_BASE: pe_enable_auto_image_base = 1; + if (optarg && *optarg) + { + char *end; + pe_auto_image_base = strtoul (optarg, &end, 0); + /* XXX should check that we actually parsed something */ + } break; case OPTION_DISABLE_AUTO_IMAGE_BASE: pe_enable_auto_image_base = 0; @@ -866,6 +892,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 */ @@ -905,7 +942,7 @@ static unsigned long compute_dll_image_base (const char *ofile) { unsigned long hash = strhash (ofile); - return 0x61300000 + ((hash << 16) & 0x0FFC0000); + return pe_auto_image_base + ((hash << 16) & 0x0FFC0000); } #endif @@ -1221,6 +1258,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 .buildid 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: .buildid 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 .buildid 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, ".buildid", 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 .buildid section," + " --build-id ignored.\n"); + return FALSE; +} + static void gld_${EMULATION_NAME}_after_open (void) { @@ -1238,11 +1438,31 @@ gld_${EMULATION_NAME}_after_open (void) printf ("-%s\n", sym->root.string); bfd_hash_traverse (&link_info.hash->table, pr_sym, NULL); - for (a = link_info.input_bfds; a; a = a->link_next) + for (a = link_info.input_bfds; a; a = a->link.next) printf ("*%s\n",a->filename); } #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. */ @@ -1255,6 +1475,7 @@ gld_${EMULATION_NAME}_after_open (void) pe_data (link_info.output_bfd)->pe_opthdr = pe; pe_data (link_info.output_bfd)->dll = init[DLLOFF].value; pe_data (link_info.output_bfd)->real_flags |= real_flags; + pe_data (link_info.output_bfd)->insert_timestamp = insert_timestamp; /* At this point we must decide whether to use long section names in the output or not. If the user hasn't explicitly specified @@ -1264,17 +1485,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; + } + } } } @@ -2101,7 +2328,7 @@ gld_${EMULATION_NAME}_open_dynamic_archive unsigned int i; - if (! entry->flags.maybe_archive) + if (! entry->flags.maybe_archive || entry->flags.full_name_provided) return FALSE; filename = entry->filename; @@ -2227,6 +2454,7 @@ struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = gld_${EMULATION_NAME}_list_options, gld_${EMULATION_NAME}_recognized_file, gld_${EMULATION_NAME}_find_potential_libraries, - NULL /* new_vers_pattern. */ + NULL, /* new_vers_pattern. */ + NULL /* extra_map_file_text. */ }; EOF |