From patchwork Mon Dec 5 01:53:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Harmstone X-Patchwork-Id: 29490 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:f944:0:0:0:0:0 with SMTP id q4csp2021515wrr; Sun, 4 Dec 2022 17:54:09 -0800 (PST) X-Google-Smtp-Source: AA0mqf4cX9Oe7LELmq2C2J94WEF3NmDvohGa8es3kbsJt7oYXO8oVdT+qToGAGBkt+E27cirSX73 X-Received: by 2002:a17:906:694a:b0:7c0:9d50:5144 with SMTP id c10-20020a170906694a00b007c09d505144mr18499319ejs.590.1670205249174; Sun, 04 Dec 2022 17:54:09 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1670205249; cv=none; d=google.com; s=arc-20160816; b=bk94M+745sZRg9cv97y0g5o45eiwgezfEotU69HKG1Taoxf/2Niq/bWYocij0RX4pZ hWI+72OwRP4lOUI6UPYYljzuSVkMiY90jeseV+GPAUzE3ffDN8QUvNha4tnxHyBr/0I8 6vI8K5YmciT+DL25xoERw8ZsgfhR6W/UKANANEEVVEDkt8DaKIn4bc1EDp/F4ebmZq1K XYZIRywGD4jiKuNQlQ8QfUMARv/E1Gm9MPwCStOXM/Z/wjbXNPr++bjdHuiL3vqDpn8O zVSPkIMVtYisFPEWQowrTDA+i1FyUIchBWVSb9kzXJ/DprTFDtFCaw3R27EzJ2gONor9 7p/A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:content-transfer-encoding :mime-version:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature:dmarc-filter:delivered-to; bh=60EZZ/HdFfN+JF082T7I2M+MBIgL1nfFGJB8O3BxHL0=; b=KAgho1gHEp+kUyAALtw6O15A4GFOeN5jDnVpEcme+nKgsTNyuGa5a5ZzQiZHh8D1zG uCpFCVtL+scRwnGzJsPJmGs04lMmfs0zUi5LJUCNMrL5kU8NkcLD/uxJBs8dDs8Kb1ko 3IpY5hCzfM6qbYd3DvR+fsCHyus1i5SQ8O9kn6mjJcnYt9g9gJxtf0tOG+gDj2sETCdR 9kqLQUATW0m93QuKPeU7ZIJiLFC4BCZfNW5abmOR/SIrC/5/aZsN/1d++TuN1YI9E1bm Z1F8QvbaC4j13FaL7j54GrKE4/+wUpkN1u+8TiPpyA2xWPaAiXpVTAYdm9I62GMdNGKQ 8Tzg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=eX+RSCiK; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from sourceware.org (ip-8-43-85-97.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id e19-20020a17090658d300b0079b8cce1170si10194096ejs.950.2022.12.04.17.54.08 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 04 Dec 2022 17:54:09 -0800 (PST) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=fail header.i=@gmail.com header.s=20210112 header.b=eX+RSCiK; spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5E308382EF0D for ; Mon, 5 Dec 2022 01:54:03 +0000 (GMT) X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org 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-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) 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 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 X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1751337139586290863?= X-GMAIL-MSGID: =?utf-8?q?1751337139586290863?= 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