From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) by sourceware.org (Postfix) with ESMTPS id EA59A382FADA for ; Mon, 5 Dec 2022 01:53:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EA59A382FADA Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=harmstone.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-wm1-x332.google.com with SMTP id n9-20020a05600c3b8900b003d0944dba41so4223917wms.4 for ; Sun, 04 Dec 2022 17:53:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:from:to:cc:subject:date :message-id:reply-to; bh=60EZZ/HdFfN+JF082T7I2M+MBIgL1nfFGJB8O3BxHL0=; b=eX+RSCiKWsndA4+NVmiLG4dXErGlhSZTugjxP3D46O6GyegOtKvRO87GA7pMKexona TAoEstovYmQuwcxvaI2XSLnffDJE6UDpO8Ei6rwtku3g9/KoYf0lmGiNTvLs7XoKHWLe 0yB2f7pfLQOe32dyhHHUtua8VWiyGTHeIoXShnwAuPcfWwR3QzVufBKTBM8TdzSB9g8Q WWNxdvTc5tXl1K7W0u2uwe3CkpCg1NnWVEFIIXb4TMzkLeArDgADQdCu83E8UrsvXMHU 5ZTBs8ct2YeQVEVlY9ouPesq6XGi2Q3xoMsdHAaGU+oQp7KuFgt88gpRyml7kCbju999 6eaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=60EZZ/HdFfN+JF082T7I2M+MBIgL1nfFGJB8O3BxHL0=; b=Q01fxNcNn7w07lkC81lsoDb0W65TpGG8DoZCkGkbvgLSiY/zK1YdpvRiaOlF2j3dML tW+86nXo1KMpdXtdiH5z0MHrIk/gNPHnYOLPGaS3JuKF2Wrh9yqNB6Tf4Uzt/T+cxlcL TfxkEEyT1e9x6IzghCEySPFL6MmpZFPbSyNs7nxPTJLBPNBRcPs179wRG74pslhqAb9s ka/Hp+w1kfjF4xtH8KxGz2P4/RDkpYkJieHAMck0jSwownS0kNLpTPgz9NoA4sl1Wrdk zWrLfw5H4XCKtvZHhKK5EWWhx5q+ozRIyZf73i+nc0PB+67InOXlXUQmzVLJ0ubz7cgI mq2w== X-Gm-Message-State: ANoB5pk3hSZ8Xvx5Xwq6NioccFlakC+Bg1DhTmO3qE81Cz5HC2oTPobD taS836O8PxBy+SKyGd/6FEFUI5mdXRY= X-Google-Smtp-Source: AA0mqf6CMw5XpJlDmSNORUUwPxGNyDs6U9ZD1Ti8kxyR9YJTfxqOIUP7MnDRRF/b+MP0F7ntckOgKQ== X-Received: by 2002:a7b:ca55:0:b0:3cf:84e9:e705 with SMTP id m21-20020a7bca55000000b003cf84e9e705mr52361340wml.28.1670205234408; Sun, 04 Dec 2022 17:53:54 -0800 (PST) Received: from beren.harmstone.com ([2a02:8010:64ea:0:8eb8:7eff:fe53:9d5f]) by smtp.gmail.com with ESMTPSA id l28-20020a05600c1d1c00b003c6b7f5567csm26288362wms.0.2022.12.04.17.53.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 04 Dec 2022 17:53:53 -0800 (PST) Sender: Mark Harmstone From: Mark Harmstone To: binutils@sourceware.org Cc: Mark Harmstone Subject: [PATCH] ld: Write linker symbols in PDB Date: Mon, 5 Dec 2022 01:53:47 +0000 Message-Id: <20221205015347.25781-3-mark@harmstone.com> X-Mailer: git-send-email 2.37.4 In-Reply-To: <20221205015347.25781-1-mark@harmstone.com> References: <20221129001015.21775-3-mark@harmstone.com> <20221205015347.25781-1-mark@harmstone.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,GIT_PATCH_0,HEADER_FROM_DIFFERENT_DOMAINS,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Adds a few symbols that Microsoft's LINK generates itself, with the version number etc. --- ld/pdb.c | 246 ++++++++++++++++++++++++++++++++----- ld/pdb.h | 42 +++++++ ld/testsuite/ld-pe/pdb.exp | 77 ++++++++++++ 3 files changed, 331 insertions(+), 34 deletions(-) diff --git a/ld/pdb.c b/ld/pdb.c index e16e45c23b1..86c71cfdfbb 100644 --- a/ld/pdb.c +++ b/ld/pdb.c @@ -21,6 +21,7 @@ #include "pdb.h" #include "bfdlink.h" #include "ld.h" +#include "ldmain.h" #include "ldmisc.h" #include "libbfd.h" #include "libiberty.h" @@ -3422,6 +3423,171 @@ handle_debugt_section (asection *s, bfd *mod, struct types *types, return true; } +/* Return the CodeView constant for the selected architecture. */ +static uint16_t +target_processor (bfd *abfd) +{ + if (abfd->arch_info->arch != bfd_arch_i386) + return 0; + + if (abfd->arch_info->mach & bfd_mach_x86_64) + return CV_CFL_X64; + else + return CV_CFL_80386; +} + +/* Create the symbols that go in "* Linker *", the dummy module created + for the linker itself. */ +static bool +create_linker_symbols (bfd *abfd, uint8_t **syms, uint32_t *sym_byte_size, + const char *pdb_name) +{ + uint8_t *ptr; + struct objname *name; + struct compile3 *comp; + struct envblock *env; + size_t padding1, padding2, env_size; + char *cwdval, *exeval, *pdbval; + + /* extra NUL for padding */ + static const char linker_fn[] = "* Linker *\0"; + static const char linker_name[] = "GNU LD " VERSION; + + static const char cwd[] = "cwd"; + static const char exe[] = "exe"; + static const char pdb[] = "pdb"; + + cwdval = getcwd (NULL, 0); + if (!cwdval) + { + einfo (_("%P: warning: unable to get working directory\n")); + return false; + } + + exeval = lrealpath (program_name); + + if (!exeval) + { + einfo (_("%P: warning: unable to get program name\n")); + free (cwdval); + return false; + } + + pdbval = lrealpath (pdb_name); + + if (!pdbval) + { + einfo (_("%P: warning: unable to get full path to PDB\n")); + free (exeval); + free (cwdval); + return false; + } + + *sym_byte_size += offsetof (struct objname, name) + sizeof (linker_fn); + *sym_byte_size += offsetof (struct compile3, compiler) + sizeof (linker_name); + + if (*sym_byte_size % 4) + padding1 = 4 - (*sym_byte_size % 4); + else + padding1 = 0; + + *sym_byte_size += padding1; + + env_size = offsetof (struct envblock, strings); + env_size += sizeof (cwd); + env_size += strlen (cwdval) + 1; + env_size += sizeof (exe); + env_size += strlen (exeval) + 1; + env_size += sizeof (pdb); + env_size += strlen (pdbval) + 1; + + if (env_size % 4) + padding2 = 4 - (env_size % 4); + else + padding2 = 0; + + env_size += padding2; + + *sym_byte_size += env_size; + + *syms = xmalloc (*sym_byte_size); + ptr = *syms; + + /* Write S_OBJNAME */ + + name = (struct objname *) ptr; + bfd_putl16 (offsetof (struct objname, name) + + sizeof (linker_fn) - sizeof (uint16_t), + &name->size); + bfd_putl16 (S_OBJNAME, &name->kind); + bfd_putl32 (0, &name->signature); + memcpy (name->name, linker_fn, sizeof (linker_fn)); + + ptr += offsetof (struct objname, name) + sizeof (linker_fn); + + /* Write S_COMPILE3 */ + + comp = (struct compile3 *) ptr; + + bfd_putl16 (offsetof (struct compile3, compiler) + sizeof (linker_name) + + padding1 - sizeof (uint16_t), + &comp->size); + bfd_putl16 (S_COMPILE3, &comp->kind); + bfd_putl32 (CV_CFL_LINK, &comp->flags); + bfd_putl16 (target_processor (abfd), &comp->machine); + bfd_putl16 (0, &comp->frontend_major); + bfd_putl16 (0, &comp->frontend_minor); + bfd_putl16 (0, &comp->frontend_build); + bfd_putl16 (0, &comp->frontend_qfe); + bfd_putl16 (0, &comp->backend_major); + bfd_putl16 (0, &comp->backend_minor); + bfd_putl16 (0, &comp->backend_build); + bfd_putl16 (0, &comp->backend_qfe); + memcpy (comp->compiler, linker_name, sizeof (linker_name)); + + memset (comp->compiler + sizeof (linker_name), 0, padding1); + + ptr += offsetof (struct compile3, compiler) + + sizeof (linker_name) + padding1; + + /* Write S_ENVBLOCK */ + + env = (struct envblock *) ptr; + + bfd_putl16 (env_size - sizeof (uint16_t), &env->size); + bfd_putl16 (S_ENVBLOCK, &env->kind); + env->flags = 0; + + ptr += offsetof (struct envblock, strings); + + memcpy (ptr, cwd, sizeof (cwd)); + ptr += sizeof (cwd); + memcpy (ptr, cwdval, strlen (cwdval) + 1); + ptr += strlen (cwdval) + 1; + + memcpy (ptr, exe, sizeof (exe)); + ptr += sizeof (exe); + memcpy (ptr, exeval, strlen (exeval) + 1); + ptr += strlen (exeval) + 1; + + memcpy (ptr, pdb, sizeof (pdb)); + ptr += sizeof (pdb); + memcpy (ptr, pdbval, strlen (pdbval) + 1); + ptr += strlen (pdbval) + 1; + + /* Microsoft's LINK also includes "cmd", the command-line options passed + to the linker, but unfortunately we don't have access to argc and argv + at this stage. */ + + memset (ptr, 0, padding2); + + free (pdbval); + free (exeval); + free (cwdval); + + return true; +} + /* Populate the module stream, which consists of the transformed .debug$S data for each object file. */ static bool @@ -3431,55 +3597,65 @@ populate_module_stream (bfd *stream, bfd *mod, uint32_t *sym_byte_size, struct mod_source_files *mod_source, bfd *abfd, struct types *types, struct types *ids, uint16_t mod_num, - bfd *sym_rec_stream, struct globals *glob) + bfd *sym_rec_stream, struct globals *glob, + const char *pdb_name) { uint8_t int_buf[sizeof (uint32_t)]; uint8_t *c13_info = NULL; uint8_t *syms = NULL; - struct type_entry **map = NULL; - uint32_t num_types = 0; *sym_byte_size = 0; *c13_info_size = 0; - /* Process .debug$T section. */ - - for (asection *s = mod->sections; s; s = s->next) + if (!strcmp (bfd_get_filename (mod), "dll stuff")) { - if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) + if (!create_linker_symbols (mod, &syms, sym_byte_size, pdb_name)) + return false; + } + else + { + struct type_entry **map = NULL; + uint32_t num_types = 0; + + /* Process .debug$T section. */ + + for (asection *s = mod->sections; s; s = s->next) { - if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, - &map, &num_types)) + if (!strcmp (s->name, ".debug$T") && s->size >= sizeof (uint32_t)) { - free (mod_source->files); - return false; - } + if (!handle_debugt_section (s, mod, types, ids, mod_num, strings, + &map, &num_types)) + { + free (mod_source->files); + return false; + } - break; + break; + } } - } - /* Process .debug$S section(s). */ + /* Process .debug$S section(s). */ - for (asection *s = mod->sections; s; s = s->next) - { - if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) + for (asection *s = mod->sections; s; s = s->next) { - if (!handle_debugs_section (s, mod, strings, &c13_info, - c13_info_size, mod_source, abfd, - &syms, sym_byte_size, map, num_types, - sym_rec_stream, glob, mod_num)) + if (!strcmp (s->name, ".debug$S") && s->size >= sizeof (uint32_t)) { - free (c13_info); - free (syms); - free (mod_source->files); - free (map); - return false; + if (!handle_debugs_section (s, mod, strings, &c13_info, + c13_info_size, mod_source, abfd, + &syms, sym_byte_size, map, num_types, + sym_rec_stream, glob, mod_num)) + { + free (c13_info); + free (syms); + free (mod_source->files); + free (map); + return false; + } } } - } - free (map); + free (map); + } /* Write the signature. */ @@ -3533,7 +3709,8 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, uint32_t *size, struct string_table *strings, struct source_files_info *source, struct types *types, struct types *ids, - bfd *sym_rec_stream, struct globals *glob) + bfd *sym_rec_stream, struct globals *glob, + const char *pdb_name) { uint8_t *ptr; unsigned int mod_num; @@ -3623,7 +3800,7 @@ create_module_info_substream (bfd *abfd, bfd *pdb, void **data, strings, &c13_info_size, &source->mods[mod_num], abfd, types, ids, mod_num, - sym_rec_stream, glob)) + sym_rec_stream, glob, pdb_name)) { for (unsigned int i = 0; i < source->mod_count; i++) { @@ -4112,7 +4289,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, struct string_table *strings, struct types *types, struct types *ids, - bfd *sym_rec_stream) + bfd *sym_rec_stream, const char *pdb_name) { struct pdb_dbi_stream_header h; struct optional_dbg_header opt; @@ -4135,7 +4312,7 @@ populate_dbi_stream (bfd *stream, bfd *abfd, bfd *pdb, if (!create_module_info_substream (abfd, pdb, &mod_info, &mod_info_size, strings, &source, types, ids, - sym_rec_stream, &glob)) + sym_rec_stream, &glob, pdb_name)) { htab_delete (glob.hashmap); return false; @@ -4829,7 +5006,8 @@ create_pdb_file (bfd *abfd, const char *pdb_name, const unsigned char *guid) if (!populate_dbi_stream (dbi_stream, abfd, pdb, section_header_stream_num, sym_rec_stream_num, publics_stream_num, - &strings, &types, &ids, sym_rec_stream)) + &strings, &types, &ids, sym_rec_stream, + pdb_name)) { einfo (_("%P: warning: cannot populate DBI stream " "in PDB file: %E\n")); diff --git a/ld/pdb.h b/ld/pdb.h index 2ac4701645e..43daf7ca748 100644 --- a/ld/pdb.h +++ b/ld/pdb.h @@ -93,6 +93,7 @@ #define S_LPROCREF 0x1127 #define S_FRAMECOOKIE 0x113a #define S_COMPILE3 0x113c +#define S_ENVBLOCK 0x113d #define S_LOCAL 0x113e #define S_DEFRANGE_REGISTER 0x1141 #define S_DEFRANGE_FRAMEPOINTER_REL 0x1142 @@ -796,6 +797,47 @@ struct heap_alloc_site uint32_t type; } ATTRIBUTE_PACKED; +/* OBJNAMESYM in cvinfo.h */ +struct objname +{ + uint16_t size; + uint16_t kind; + uint32_t signature; + char name[]; +} ATTRIBUTE_PACKED; + +#define CV_CFL_80386 0x03 +#define CV_CFL_X64 0xD0 + +#define CV_CFL_LINK 0x07 + +/* COMPILESYM3 in cvinfo.h */ +struct compile3 +{ + uint16_t size; + uint16_t kind; + uint32_t flags; + uint16_t machine; + uint16_t frontend_major; + uint16_t frontend_minor; + uint16_t frontend_build; + uint16_t frontend_qfe; + uint16_t backend_major; + uint16_t backend_minor; + uint16_t backend_build; + uint16_t backend_qfe; + char compiler[]; +} ATTRIBUTE_PACKED; + +/* ENVBLOCKSYM in cvinfo.h */ +struct envblock +{ + uint16_t size; + uint16_t kind; + uint8_t flags; + char strings[]; +} ATTRIBUTE_PACKED; + extern bool create_pdb_file (bfd *, const char *, const unsigned char *); #endif diff --git a/ld/testsuite/ld-pe/pdb.exp b/ld/testsuite/ld-pe/pdb.exp index 5df1583c247..bd50b2fb076 100644 --- a/ld/testsuite/ld-pe/pdb.exp +++ b/ld/testsuite/ld-pe/pdb.exp @@ -1678,6 +1678,83 @@ proc test9 { } { } else { fail "Incorrect symbols in module stream" } + + # check linker symbols + + set off 64 + + set obj1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $obj1] + 1] + + set ar1 [string range $mod_info $off [expr [string first \000 $mod_info $off] - 1]] + incr off [expr [string length $ar1] + 1] + + if { [expr $off % 4] != 0 } { + set off [expr $off + 4 - ($off % 4)] + } + + incr off 34 + + binary scan [string range $mod_info $off [expr $off + 1]] s linker_syms_index + + set index_str [format "%04x" $linker_syms_index] + + set exec_output [run_host_cmd "$ar" "x --output tmpdir tmpdir/pdb-syms2.pdb $index_str"] + + if ![string match "" $exec_output] { + fail "Could not extract linker symbols" + return + } else { + pass "Extracted linker symbols" + } + + set syms [file_contents "tmpdir/$index_str"] + + # check S_OBJNAME + + set off 4 + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x1101 } { + fail "First linker symbol was not S_OBJNAME" + } else { + pass "First linker symbol was S_OBJNAME" + + set linker_fn [string range $syms [expr $off + 8] [expr [string first \000 $syms [expr $off + 8]] - 1]] + + if ![string equal $linker_fn "* Linker *"] { + fail "Incorrect linker object name" + } else { + pass "Correct linker object name" + } + } + + incr off [expr $sym_len + 2] + + # check S_COMPILE3 + + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x113c } { + fail "Second linker symbol was not S_COMPILE3" + } else { + pass "Second linker symbol was S_COMPILE3" + } + + incr off [expr $sym_len + 2] + + # check S_ENVBLOCK + + binary scan [string range $syms $off [expr $off + 1]] s sym_len + binary scan [string range $syms [expr $off + 2] [expr $off + 3]] s sym_type + + if { $sym_type != 0x113d } { + fail "Third linker symbol was not S_ENVBLOCK" + } else { + pass "Third linker symbol was S_ENVBLOCK" + } } test1 -- 2.37.4