From patchwork Tue Jun 23 21:38:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter0x44 X-Patchwork-Id: 137666 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 622164BA2E3B for ; Tue, 23 Jun 2026 21:38:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 622164BA2E3B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1782250736; bh=vVCEzMNNpMDFfovbFVg7i/MCsO8ExRXlZxqKy+U1qjM=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=a4dQOR0mnNtmmaw/qAczp4B0/zRkueHecyu0y0ZLDcflLpv3ciiLDZzXMAd1jJGX1 Ot4Ffrt+y24l1iGHQRx76F1FQFPsa+7MxLVcSrnq8pgyMnMl/StVJdlsYD3HVMVvcr qpjY+UKmaF9IcUttX5qx6y5UdLTehq5+l6LkkGZU= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) by sourceware.org (Postfix) with ESMTPS id 809A64BA5435 for ; Tue, 23 Jun 2026 21:38:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 809A64BA5435 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 809A64BA5435 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250700; cv=none; b=NZuSiIJKjJiGpjBzONmLNDY6fZ+Z56sNPz30I0THIWCDEQj5tbpVdum01sI8ijfxnJV5lM4QYfE9mtnCswbTnmJDTJnct83zxnOb1ajXle0SfFRY8ea42gs42jmLQZRmmo0rqHT+gy/LWqykdAzBmbcW229n8xS3hfkM4c6K3uY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250700; c=relaxed/simple; bh=tmR8E+Rm36DcA4r7o9on7SJqAJnSZwkcTCC1LBMHrFI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=DhExsYSC2u4AtL6yrNinSk+87etQVDaI4FygnxOYsZLFnKLlruW1bjRmB3NBqaS2IiT5eDnqQQCrQykPGIY0xVPbrGP8dUs5NdlccbDiHQvBZWlCLeSTg5/LAJ49rGLaWS7zjFGzm2z3EgEZCfhLpFQuJnoR/s+B1qJnzMrjs2E= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, secure) header.d=disroot.org header.i=@disroot.org header.a=rsa-sha256 header.s=mail header.b=KL4GJfi5 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 809A64BA5435 Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 59450267E6; Tue, 23 Jun 2026 23:38:19 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ugHAv0no1Pai; Tue, 23 Jun 2026 23:38:18 +0200 (CEST) To: binutils@sourceware.org Cc: amodra@gmail.com, jbeulich@suse.com, martin@martin.st, Peter Damianov Subject: [PATCH v3 1/4] PE-COFF: Fix weak external symbol resolution when strong undef is seen first Date: Tue, 23 Jun 2026 17:38:04 -0400 Message-ID: <4eed3fce357c58ef817e3cf3003735233ff85268.1782245474.git.peter0x44@disroot.org> In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Peter Damianov via Binutils From: Peter0x44 Reply-To: Peter Damianov Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org When linking PE-COFF objects, a weak external symbol (C_NT_WEAK with an aux record specifying a fallback alias) may fail to resolve if a strong undefined reference to the same symbol is encountered before the weak definition. This causes "undefined reference" errors for symbols like operator new or personality routines that GCC emits as weak externals with a fallback to a default implementation. There are two problems: 1. In coff_link_add_symbols, when the generic linker resolves a weak undefined against an existing strong undefined (NOACT in the action table), the COFF-specific symbol_class and aux record were not stored because the existing hash entry already had non-null class/type from the first (strong) object file. 2. In _bfd_coff_generic_relocate_section, the weak alias fallback only triggered for bfd_link_hash_undefweak symbols. When a strong undef is seen first, the hash type stays bfd_link_hash_undefined (the generic linker does not downgrade it), so the fallback was skipped. Fix by extending the condition in coff_link_add_symbols to also update symbol_class and aux when the incoming symbol is a PE weak external with aux and the existing hash is still undefined. Also extend the relocation handler to resolve the weak alias fallback for bfd_link_hash_undefined symbols that carry C_NT_WEAK class and have an aux record. bfd/ * cofflink.c (coff_link_add_symbols): Also store symbol_class and aux record when a PE weak external with aux meets an existing undefined hash entry. (_bfd_coff_generic_relocate_section): Also resolve weak alias fallback for undefined symbols with C_NT_WEAK class and aux. --- bfd/cofflink.c | 55 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/bfd/cofflink.c b/bfd/cofflink.c index e5c8a987d69..eba0fad4c3f 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -477,13 +477,20 @@ coff_link_add_symbols (bfd *abfd, /* If we don't have any symbol information currently in the hash table, or if we are looking at a symbol definition, then update the symbol class and type in - the hash table. */ + the hash table. Also update if the incoming symbol is + a weak external with an aux record (PE COFF weak alias) + and the existing symbol is still undefined, so the + fallback alias information is preserved for the linker's + relocation resolution. */ if (((*sym_hash)->symbol_class == C_NULL && (*sym_hash)->type == T_NULL) || sym.n_scnum != 0 || (sym.n_value != 0 && (*sym_hash)->root.type != bfd_link_hash_defined - && (*sym_hash)->root.type != bfd_link_hash_defweak)) + && (*sym_hash)->root.type != bfd_link_hash_defweak) + || (IS_WEAK_EXTERNAL (abfd, sym) + && sym.n_numaux > 0 + && (*sym_hash)->root.type == bfd_link_hash_undefined)) { (*sym_hash)->symbol_class = sym.n_sclass; if (sym.n_type != T_NULL) @@ -521,10 +528,9 @@ coff_link_add_symbols (bfd *abfd, union internal_auxent *iaux; (*sym_hash)->numaux = sym.n_numaux; - alloc = ((union internal_auxent *) - bfd_hash_allocate (&info->hash->table, - (sym.n_numaux - * sizeof (*alloc)))); + alloc = bfd_hash_allocate (&info->hash->table, + (sym.n_numaux + * sizeof (*alloc))); if (alloc == NULL) goto error_return; for (i = 0, eaux = esym + symesz, iaux = alloc; @@ -3065,14 +3071,24 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd, + sec->output_offset); } - else if (h->root.type == bfd_link_hash_undefweak) + else if (h->root.type == bfd_link_hash_undefweak + || (h->root.type == bfd_link_hash_undefined + && h->symbol_class == C_NT_WEAK && h->numaux == 1)) { - if (h->symbol_class == C_NT_WEAK && h->numaux == 1) + /* Weak undefined symbol: either GNU weak (no aux record) or + PE COFF weak external (C_NT_WEAK with aux record). + Also handles strong undefined symbols that carry PE weak + external metadata (when strong undef is seen before weak def, + the hash type stays bfd_link_hash_undefined but we preserve + the weak external class and aux for later resolution). */ + + bool is_pe_weak = (h->symbol_class == C_NT_WEAK && h->numaux == 1); + + if (is_pe_weak) { - /* See _Microsoft Portable Executable and Common Object + /* PE COFF weak external: resolve via fallback alias. + See _Microsoft Portable Executable and Common Object File Format Specification_, section 5.5.3. - Note that weak symbols without aux records are a GNU - extension. FIXME: All weak externals are treated as having characteristic IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY (1). These behave as per SVR4 ABI: A library member @@ -3081,24 +3097,37 @@ _bfd_coff_generic_relocate_section (bfd *output_bfd, See also linker.c: generic_link_check_archive_element. */ struct coff_link_hash_entry *h2 = NULL; unsigned long symndx2 = h->aux->x_sym.x_tagndx.u32; + if (symndx2 < obj_raw_syment_count (h->auxbfd)) h2 = obj_coff_sym_hashes (h->auxbfd)[symndx2]; if (!h2 || h2->root.type == bfd_link_hash_undefined) { + /* Fallback alias not found or still undefined. + Resolve to NULL. */ sec = bfd_abs_section_ptr; val = 0; } else { + /* Use fallback alias target. */ sec = h2->root.u.def.section; val = h2->root.u.def.value + sec->output_section->vma + sec->output_offset; } } else - /* This is a GNU extension. */ - val = 0; + { + /* GNU extension: ELF-style weak symbol in COFF without + PE weak external aux record. COFF has no native support + for weak symbols (unlike ELF where they're part of the + format). PE COFF adds them via C_NT_WEAK storage class + with an aux record pointing to a fallback symbol. GNU ld + extends this by allowing __attribute__((weak)) in COFF + objects even without the PE aux structure, treating them + like ELF weak symbols: resolve to NULL if not defined. */ + val = 0; + } } else if (! bfd_link_relocatable (info)) From patchwork Tue Jun 23 21:38:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter0x44 X-Patchwork-Id: 137667 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 475214BA2E3B for ; Tue, 23 Jun 2026 21:39:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 475214BA2E3B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1782250740; bh=T20kHcNQGaSZp6CyLWPG7iQv5II/QwRo+Yii9CfZY3c=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=kK1vmZUg8iMVNgBOJT/vCWigAOsYWE6+fLNM4kQU+BWlSx65djWJlwgUjTF0VaQVQ sRhIrx4wfy7mEp5rBk7Ighazo/fiNQbBoVoffuKFarqvpY+AYJ+bxSQ2MxLqVzxRDI aSc9NTj9YooZhtMgQqk9fO2cWgTV7XTkl5A17ysw= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) by sourceware.org (Postfix) with ESMTPS id 2987F4BA2E17 for ; Tue, 23 Jun 2026 21:38:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2987F4BA2E17 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2987F4BA2E17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250704; cv=none; b=pvpp2s4lM9KrRueL8gAPNg6U22NAib/Rj2noXkG3Xa6wBVBFPgR7TLTN9zBUe1bcKI+dXXcQ9eVdvov1HTNaEragq1FRszfgMPbAehXiL+xZLed96UgDmc7i0yBaZwliLozPajdnw/4BVokVAj+L1Z6/s7JisnlxshXUFTQvShM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250704; c=relaxed/simple; bh=zTo+lD5/6Xd6LPTR2EqtS3R7kT7JEgTQ8YwQWHFBq0Y=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=arWii7JmqMkeE78kj+YVq09kOwJX012RhpH1JE4jGSqIE3Kkzh+UqFJLaUfMY2EjQj5b8yZcM9zIulDR45/ypv1LuoUf2HqOCb/d3f/8IE0t5FJAVDYbTapxd5gEOdY1KjWU7iF+5LPmYKiHPFQNoZ+eXkJkABGcJa5c/VfLbk0= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, secure) header.d=disroot.org header.i=@disroot.org header.a=rsa-sha256 header.s=mail header.b=LCg1x8NS DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2987F4BA2E17 Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 0C4DC26726; Tue, 23 Jun 2026 23:38:23 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id ApFw9Qg7nLCR; Tue, 23 Jun 2026 23:38:22 +0200 (CEST) To: binutils@sourceware.org Cc: amodra@gmail.com, jbeulich@suse.com, martin@martin.st, Peter Damianov Subject: [PATCH v3 2/4] PE-COFF: Prefer weak external with defined fallback over null fallback Date: Tue, 23 Jun 2026 17:38:05 -0400 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Peter Damianov via Binutils From: Peter0x44 Reply-To: Peter Damianov Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org When two PE COFF weak externals for the same symbol are linked (both C_NT_WEAK with aux records), the generic linker takes no action on the second one (NOACT: weak undef meets existing weak undef). This means the first file's fallback alias always wins regardless of whether it points to a real definition or to NULL. This causes a problem when a weak declaration (fallback = NULL, i.e. "resolve to NULL if nothing provides it") is linked before a weak definition (fallback = actual function body). The symbol resolves to address 0 at runtime, causing a crash when called. Fix this by comparing the fallback targets when two weak externals meet: if the incoming weak external's fallback resolves to a defined symbol and the existing one does not (or points to NULL), update the aux record to use the better fallback. This matches the behavior of lld after: https://github.com/llvm/llvm-project/commit/7ca5698b4c3698d06065e0941df7f23d72913d23 bfd/ * cofflink.c (coff_link_add_symbols): When two PE COFF weak externals meet, prefer the one whose fallback alias resolves to a defined symbol. --- bfd/cofflink.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/bfd/cofflink.c b/bfd/cofflink.c index eba0fad4c3f..75b4c47eacf 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -542,6 +542,88 @@ coff_link_add_symbols (bfd *abfd, (*sym_hash)->aux = alloc; } } + + /* When two PE COFF weak externals meet (both with aux + records specifying fallback aliases), prefer the one + whose fallback resolves to a defined symbol over one + whose fallback is undefined or NULL. This + handles the case where a weak declaration (with a + fallback of NULL) is seen before a weak + definition (with a fallback of the actual function + body). */ + else if (IS_WEAK_EXTERNAL (abfd, sym) + && sym.n_numaux > 0 + && (*sym_hash)->root.type == bfd_link_hash_undefweak + && (*sym_hash)->symbol_class == C_NT_WEAK + && (*sym_hash)->numaux == 1) + { + /* Parse the incoming aux to get the fallback tagndx. */ + union internal_auxent new_aux; + unsigned long new_tagndx; + unsigned long old_tagndx; + struct coff_link_hash_entry *h2_new = NULL; + struct coff_link_hash_entry *h2_old = NULL; + bool new_is_real_fallback; + bool old_is_unresolved_fallback; + + bfd_coff_swap_aux_in (abfd, esym + symesz, sym.n_type, + sym.n_sclass, 0, sym.n_numaux, + &new_aux); + new_tagndx = new_aux.x_sym.x_tagndx.u32; + + if (new_tagndx < obj_raw_syment_count (abfd)) + h2_new = obj_coff_sym_hashes (abfd)[new_tagndx]; + + old_tagndx = (*sym_hash)->aux->x_sym.x_tagndx.u32; + if (old_tagndx + < obj_raw_syment_count ((*sym_hash)->auxbfd)) + h2_old = obj_coff_sym_hashes + ((*sym_hash)->auxbfd)[old_tagndx]; + + /* Update if the new fallback is a real definition but + the old one is not. A weak declaration with no + definition uses the COFF null symbol as its fallback. + In the hash table that fallback looks like a defined + absolute symbol with value zero, so treat that case as + unresolved here. */ + new_is_real_fallback + = (h2_new != NULL + && (h2_new->root.type == bfd_link_hash_defined + || h2_new->root.type == bfd_link_hash_defweak) + && !(bfd_is_abs_section (h2_new->root.u.def.section) + && h2_new->root.u.def.value == 0)); + old_is_unresolved_fallback + = (h2_old == NULL + || h2_old->root.type == bfd_link_hash_undefined + || h2_old->root.type == bfd_link_hash_undefweak + || (h2_old->root.type == bfd_link_hash_defined + && bfd_is_abs_section (h2_old->root.u.def.section) + && h2_old->root.u.def.value == 0)); + + if (new_is_real_fallback && old_is_unresolved_fallback) + { + union internal_auxent *alloc; + unsigned int i; + bfd_byte *eaux; + union internal_auxent *iaux; + + (*sym_hash)->symbol_class = sym.n_sclass; + (*sym_hash)->auxbfd = abfd; + (*sym_hash)->numaux = sym.n_numaux; + alloc = bfd_hash_allocate (&info->hash->table, + (sym.n_numaux + * sizeof (*alloc))); + if (alloc == NULL) + goto error_return; + for (i = 0, eaux = esym + symesz, iaux = alloc; + i < sym.n_numaux; + i++, eaux += symesz, iaux++) + bfd_coff_swap_aux_in (abfd, eaux, sym.n_type, + sym.n_sclass, (int) i, + sym.n_numaux, iaux); + (*sym_hash)->aux = alloc; + } + } } if (classification == COFF_SYMBOL_PE_SECTION From patchwork Tue Jun 23 21:38:06 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter0x44 X-Patchwork-Id: 137669 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4151A4BA2E19 for ; Tue, 23 Jun 2026 21:40:29 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4151A4BA2E19 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1782250829; bh=sZS0v2ipOn1IaSfOcd0Wgz/rMz3JqhqaglnfTGQVaZ8=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=e0c/EFjdLMKFWv2VPi2mu95sGBj5hWcoGFlhK7/YnNAEgpYblWfCczKT9e67ld/Rr M/WmhNWBJUp0YEPVR+qdal4/loAEviEv90rX5Q1OSfPUQnzQ4C15BrhrhehavGA9XF lczqpMkydh/14FAOyz4nms72HEHiWAAn8wJeSOxw= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) by sourceware.org (Postfix) with ESMTPS id 6338E4BA2E17 for ; Tue, 23 Jun 2026 21:38:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6338E4BA2E17 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6338E4BA2E17 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250707; cv=none; b=sezC2vff1y9jwFKow43tPu9gb2jtZpZ0+h+YYJ6TylojgJbm5kDxKhmLr+lCozqxTImHQ0+C+lEKGqHl45s0QKXgf5X3Lr4xfe0in5x89sfWG9phlI9GZW1D4Sj2TSwTIyFLlo20gn8OtAGIyEEpHpOEkdFPAtUwOE0kq/xhqi4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250707; c=relaxed/simple; bh=ATtdQFnlZDE5geAHuDpcMPBsVAe9KA73VBVTuNKIy6w=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=EoVKAQVvhzYgn6fr2/hNmAlaaj5LhaoRpV/5mTwNSp6Hga3G6mkKZcSg6bUQySWQ7ln6JpWoO5QK4LYCBJCsnA3i5/eOGOI/x++lJfXqTlzLTYUnYUzODThqGPEAG6BbTiJu8OmmnzWrImgKYYMkaIB1P+2ayRkK7UBfdpCjjiw= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, secure) header.d=disroot.org header.i=@disroot.org header.a=rsa-sha256 header.s=mail header.b=fMcnCj6Z DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6338E4BA2E17 Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 8043426F06; Tue, 23 Jun 2026 23:38:26 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id 9QlnHiNSWypL; Tue, 23 Jun 2026 23:38:25 +0200 (CEST) To: binutils@sourceware.org Cc: amodra@gmail.com, jbeulich@suse.com, martin@martin.st, Peter Damianov Subject: [PATCH v3 3/4] bfd: Handle PE weak externals with real fallbacks in archives Date: Tue, 23 Jun 2026 17:38:06 -0400 Message-ID: <8292b88c6b7216d8eedba27e1d1bd6a8c7da34d5.1782245474.git.peter0x44@disroot.org> In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Peter Damianov via Binutils From: Peter0x44 Reply-To: Peter Damianov Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org PE weak externals are canonicalized as undefined BFD symbols, even when their auxiliary entry names a real fallback definition in the same object. Archive map generation therefore skipped the public weak name, so a strong undefined reference to that name could not extract the archive member. Include such PE weak externals in the archive map, but only when the fallback is a real definition rather than the absolute-zero null symbol used for weak declarations with no fallback. Also avoid extracting an archive member again during repeated archive searches once the weak external resolves through a defined fallback. Fixes: https://gcc.gnu.org/PR124263 bfd/ * archive.c: Include coff-bfd.h. (_bfd_compute_and_push_armap): Include PE weak externals in the archive map when their fallback is a real definition. * coff-bfd.c (bfd_coff_pe_weak_external_has_real_fallback): New function. * coff-bfd.h (bfd_coff_pe_weak_external_has_real_fallback): Declare. * cofflink.c (coff_link_hash_pe_weak_external_has_real_fallback): New function. (coff_link_check_archive_element): Avoid extracting an archive member again for a PE weak external whose real fallback is already defined. --- bfd/archive.c | 22 ++++++++++++++++------ bfd/coff-bfd.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ bfd/coff-bfd.h | 3 +++ bfd/cofflink.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 6 deletions(-) diff --git a/bfd/archive.c b/bfd/archive.c index 44030eb3d63..1bff31b6d09 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -142,6 +142,7 @@ SUBSECTION #include "filenames.h" #include "bfdlink.h" #include "plugin.h" +#include "coff-bfd.h" #ifndef errno extern int errno; @@ -2535,12 +2536,21 @@ _bfd_compute_and_push_armap flagword flags = (syms[src_count])->flags; asection *sec = syms[src_count]->section; - if (((flags & (BSF_GLOBAL - | BSF_WEAK - | BSF_INDIRECT - | BSF_GNU_UNIQUE)) != 0 - || bfd_is_com_section (sec)) - && ! bfd_is_und_section (sec)) + /* Include symbols that normally define archive-map entries, plus + PE weak externals whose fallback is a real definition. Those + weak externals are canonicalized as undefined symbols, but their + public names can still be needed to pull the archive member. */ + bool include_in_armap + = ((((flags & (BSF_GLOBAL + | BSF_WEAK + | BSF_INDIRECT + | BSF_GNU_UNIQUE)) != 0 + || bfd_is_com_section (sec)) + && ! bfd_is_und_section (sec)) + || bfd_coff_pe_weak_external_has_real_fallback + (bfd_asymbol_bfd (syms[src_count]), syms[src_count])); + + if (include_in_armap) { bfd_size_type namelen; struct orl *new_map; diff --git a/bfd/coff-bfd.c b/bfd/coff-bfd.c index d836355aa64..e57135ddd18 100644 --- a/bfd/coff-bfd.c +++ b/bfd/coff-bfd.c @@ -110,3 +110,50 @@ bfd_coff_get_auxent (bfd *abfd, return true; } + +/* Return TRUE if SYMBOL is a PE weak external whose fallback symbol is + a real definition. A weak declaration with no fallback uses the COFF + null symbol as its fallback; do not treat that as an archive provider. */ + +bool +bfd_coff_pe_weak_external_has_real_fallback (bfd *abfd, + asymbol *symbol) +{ + coff_symbol_type *csym; + combined_entry_type *aux; + combined_entry_type *fallback; + + if (bfd_get_flavour (abfd) != bfd_target_coff_flavour + || coff_data (abfd) == NULL + || ! obj_pe (abfd)) + return false; + + csym = coff_symbol_from (symbol); + if (csym == NULL + || csym->native == NULL + || ! csym->native->is_sym + || csym->native->u.syment.n_sclass != C_NT_WEAK + || csym->native->u.syment.n_numaux != 1) + return false; + + aux = csym->native + 1; + if (aux->is_sym) + return false; + + if (aux->fix_tag) + fallback = (combined_entry_type *) aux->u.auxent.x_sym.x_tagndx.p; + else + { + uint32_t tagndx = aux->u.auxent.x_sym.x_tagndx.u32; + + if (tagndx >= obj_raw_syment_count (abfd)) + return false; + fallback = obj_raw_syments (abfd) + tagndx; + } + + return (fallback != NULL + && fallback->is_sym + && fallback->u.syment.n_scnum != N_UNDEF + && !(fallback->u.syment.n_scnum == N_ABS + && fallback->u.syment.n_value == 0)); +} diff --git a/bfd/coff-bfd.h b/bfd/coff-bfd.h index 70cc0c36902..6626c491ebb 100644 --- a/bfd/coff-bfd.h +++ b/bfd/coff-bfd.h @@ -81,5 +81,8 @@ extern bool bfd_coff_get_syment extern bool bfd_coff_get_auxent (bfd *, struct bfd_symbol *, int, union internal_auxent *); +extern bool bfd_coff_pe_weak_external_has_real_fallback + (bfd *, struct bfd_symbol *); + extern bool bfd_coff_set_symbol_class (bfd *, struct bfd_symbol *, unsigned int); diff --git a/bfd/cofflink.c b/bfd/cofflink.c index 75b4c47eacf..d029bec1678 100644 --- a/bfd/cofflink.c +++ b/bfd/cofflink.c @@ -36,6 +36,45 @@ static bool coff_link_check_archive_element bool *); static bool coff_link_add_symbols (bfd *, struct bfd_link_info *); +static bool +coff_link_hash_pe_weak_external_has_real_fallback + (struct coff_link_hash_entry *h) +{ + struct coff_link_hash_entry *h2; + unsigned long symndx; + + if (h->symbol_class != C_NT_WEAK + || h->numaux != 1 + || h->aux == NULL + || h->auxbfd == NULL + || ! obj_pe (h->auxbfd) + || obj_coff_sym_hashes (h->auxbfd) == NULL) + return false; + + /* The PE weak-external aux entry names the fallback symbol by raw + symbol index. Look up the corresponding link hash entry so we can + test the fallback's resolved state, not just its object-file entry. */ + symndx = h->aux->x_sym.x_tagndx.u32; + if (symndx >= obj_raw_syment_count (h->auxbfd)) + return false; + + h2 = obj_coff_sym_hashes (h->auxbfd)[symndx]; + if (h2 == NULL) + return false; + + while (h2->root.type == bfd_link_hash_indirect + || h2->root.type == bfd_link_hash_warning) + h2 = (struct coff_link_hash_entry *) h2->root.u.i.link; + + /* A weak declaration with no fallback uses the absolute-zero null + symbol. Only a defined real fallback means this archive member has + already satisfied the weak external. */ + return ((h2->root.type == bfd_link_hash_defined + || h2->root.type == bfd_link_hash_defweak) + && !(bfd_is_abs_section (h2->root.u.def.section) + && h2->root.u.def.value == 0)); +} + /* Return TRUE if SYM is a weak, external symbol. */ #define IS_WEAK_EXTERNAL(abfd, sym) \ ((sym).n_sclass == C_WEAKEXT \ @@ -255,6 +294,13 @@ coff_link_check_archive_element (bfd *abfd, if (((struct coff_link_hash_entry *) h)->indx == -3) return true; + /* A PE weak external can stay undefined even after its fallback has + been defined by this archive member. Avoid extracting the member + again if the same archive is searched more than once. */ + if (coff_link_hash_pe_weak_external_has_real_fallback + ((struct coff_link_hash_entry *) h)) + return true; + /* Include this element? */ if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd)) return true; From patchwork Tue Jun 23 21:38:07 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter0x44 X-Patchwork-Id: 137670 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 385E84BA2E0A for ; Tue, 23 Jun 2026 21:41:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 385E84BA2E0A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1782250909; bh=itvIzR+0j/+AswH9Y2nL9hpffpS7DdkpPqYE0buVN4o=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=Ogv4SaBsL7R54Ku+S6Jz5gELmnqqOzJjpuCxc5XdVsX2GcyYXG6GC/r6sMuhnOVvd aoWqo52bG1atb1aFR3rf03SJe8RcNO/dGpah9cTfSCguN90H2i9pdm4pJmQllbuU1R mcHrkP8WPMAlM82YpthBFoXsmEw4HlNa44mTW9P8= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) by sourceware.org (Postfix) with ESMTPS id BFD054BA23CA for ; Tue, 23 Jun 2026 21:38:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org BFD054BA23CA ARC-Filter: OpenARC Filter v1.0.0 sourceware.org BFD054BA23CA ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250711; cv=none; b=D4WZMelpBqJhZWY11GOjTQxjkTP0DICGdcGnVXjp96nxKjTQ4dAyb2zxVTbOWTHQWYbpxw1EgoluxAkCq1QrxSgAYcy0JJjmTsGgeYTFmld9NoGCWkcjm5Cc9nD7XMN5GVvLmlLSS27LmW7jNP66ICy4UnoShtUsV+HFDcRGUk8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1782250711; c=relaxed/simple; bh=j92d4AqFuLVak72vCqXueeF6XHN3UqXmcNyCCXRAFec=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=vAI6zss6hjVKKtWqTb+vqQthwNpbYRgsabDFFuMV/Q4dVZ0QkS9nrwI+cGFpamSfOPLGB+GVeTkkRQevXOviKzYE49IWrmOABg1oMrUtWJLv0cSyfE4BTpx8W+gyEmK021yl6lRwFxVQf3qR+OnsG4c85PU91d6Z+XqkIXKNVIs= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, secure) header.d=disroot.org header.i=@disroot.org header.a=rsa-sha256 header.s=mail header.b=mREOg//V DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BFD054BA23CA Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id A8B0526716; Tue, 23 Jun 2026 23:38:29 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id JaPfVaCgYUxX; Tue, 23 Jun 2026 23:38:29 +0200 (CEST) To: binutils@sourceware.org Cc: amodra@gmail.com, jbeulich@suse.com, martin@martin.st, Peter Damianov Subject: [PATCH v3 4/4] ld/testsuite: Add comprehensive PE COFF weak external tests Date: Tue, 23 Jun 2026 17:38:07 -0400 Message-ID: In-Reply-To: References: MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, PROLO_LEO1, SPF_HELO_NONE, SPF_PASS, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Peter Damianov via Binutils From: Peter0x44 Reply-To: Peter Damianov Errors-To: binutils-bounces~patchwork=sourceware.org@sourceware.org Add tests covering the full matrix of weak/strong symbol interactions for PE COFF weak externals, based on testcases by Martin Storsjo. The archive test covers PE weak externals whose public name is backed by a real fallback definition, and ensures weak declarations with the null fallback are not advertised as archive providers. ld/testsuite/ * ld-pe/pe-compile.exp (weak_ext_test): New proc. Compiles source files, links via gcc, and runs natively if possible. (weak_ext_archive_test): New proc. Add tests: normal, weak-undef, weak-defined, weak-decl-weak-def, strong-undef-weak-def-archive, weak-use, weak-override, weak-duplicate, weak-def-override, weak-def-use. * ld-pe/weak-ext-main.c: New file. * ld-pe/weak-ext-main-weak.c: New file. * ld-pe/weak-ext-main-weak-def.c: New file. * ld-pe/weak-ext-add2.c: New file. * ld-pe/weak-ext-add1-weak-chained.c: New file. * ld-pe/weak-ext-dummy.c: New file. * ld-pe/weak-ext-expected1.c: New file. * ld-pe/weak-ext-expected3.c: New file. * ld-pe/weak-ext-expected5.c: New file. * ld-pe/weak-ext-expected3-add1-weak.c: New file. --- ld/testsuite/ld-pe/pe-compile.exp | 167 ++++++++++++++++++ .../ld-pe/weak-ext-add1-weak-chained.c | 13 ++ ld/testsuite/ld-pe/weak-ext-add2.c | 8 + ld/testsuite/ld-pe/weak-ext-dummy.c | 5 + ld/testsuite/ld-pe/weak-ext-expected1.c | 1 + .../ld-pe/weak-ext-expected3-add1-weak.c | 9 + ld/testsuite/ld-pe/weak-ext-expected3.c | 1 + ld/testsuite/ld-pe/weak-ext-expected5.c | 1 + ld/testsuite/ld-pe/weak-ext-main-weak-def.c | 26 +++ ld/testsuite/ld-pe/weak-ext-main-weak.c | 22 +++ ld/testsuite/ld-pe/weak-ext-main.c | 21 +++ 11 files changed, 274 insertions(+) create mode 100644 ld/testsuite/ld-pe/weak-ext-add1-weak-chained.c create mode 100644 ld/testsuite/ld-pe/weak-ext-add2.c create mode 100644 ld/testsuite/ld-pe/weak-ext-dummy.c create mode 100644 ld/testsuite/ld-pe/weak-ext-expected1.c create mode 100644 ld/testsuite/ld-pe/weak-ext-expected3-add1-weak.c create mode 100644 ld/testsuite/ld-pe/weak-ext-expected3.c create mode 100644 ld/testsuite/ld-pe/weak-ext-expected5.c create mode 100644 ld/testsuite/ld-pe/weak-ext-main-weak-def.c create mode 100644 ld/testsuite/ld-pe/weak-ext-main-weak.c create mode 100644 ld/testsuite/ld-pe/weak-ext-main.c diff --git a/ld/testsuite/ld-pe/pe-compile.exp b/ld/testsuite/ld-pe/pe-compile.exp index 041a1cb9344..aac8711dff2 100644 --- a/ld/testsuite/ld-pe/pe-compile.exp +++ b/ld/testsuite/ld-pe/pe-compile.exp @@ -138,3 +138,170 @@ set align_tests { } run_ld_link_tests $align_tests + +# Test PE COFF weak external symbol resolution. +# These tests cover the full matrix of weak/strong interactions to verify +# that the linker correctly resolves weak externals in PE COFF objects. +# Based on testcases by Martin Storsjo. + +proc weak_ext_test { testname sources } { + global CC_FOR_TARGET + global srcdir + global subdir + + set objfiles {} + foreach src $sources { + set fileroot [file rootname [file tail $src]] + set obj "tmpdir/$fileroot.o" + if ![ld_compile $CC_FOR_TARGET $srcdir/$subdir/$src $obj] { + fail "$testname (compile $src)" + return + } + lappend objfiles $obj + } + + set output "tmpdir/weak-ext-test.exe" + if ![ld_link $CC_FOR_TARGET $output $objfiles] { + fail "$testname (link)" + return + } + + if ![isnative] { + pass "$testname (link only)" + return + } + + catch "exec $output" prog_output + if { $prog_output eq "" } { + pass $testname + } else { + verbose $prog_output + fail "$testname ($prog_output)" + } +} + +proc weak_ext_archive_test { } { + global CC_FOR_TARGET + global ar + global nm + global srcdir + global subdir + + set testname "weak external: archive strong undef + weak def" + set main_obj "tmpdir/weak-ext-main.o" + set weak_decl_obj "tmpdir/weak-ext-main-weak.o" + set weak_obj "tmpdir/weak-ext-add1-weak-chained.o" + set expected_obj "tmpdir/weak-ext-expected3.o" + set weak_decl_archive "tmpdir/weak-ext-decl-archive.a" + set archive "tmpdir/weak-ext-archive.a" + set output "tmpdir/weak-ext-archive-test.exe" + + set sources {weak-ext-main.c weak-ext-main-weak.c \ + weak-ext-add1-weak-chained.c weak-ext-expected3.c} + set objects [list $main_obj $weak_decl_obj $weak_obj $expected_obj] + foreach src $sources obj $objects { + if ![ld_compile $CC_FOR_TARGET $srcdir/$subdir/$src $obj] { + fail "$testname (compile $src)" + return + } + } + + set got [run_host_cmd "$ar" "rcs $weak_decl_archive $weak_decl_obj"] + if ![string match "" $got] { + fail "$testname (weak decl archive)" + return + } + + # A weak declaration with the null fallback must not advertise its + # public name as an archive-map provider. + set got [run_host_cmd "$nm" "--print-armap $weak_decl_archive"] + if [regexp "(^|\n)_?func in weak-ext-main-weak\\.o" $got] { + verbose -log $got + fail "$testname (weak decl armap)" + return + } + + set got [run_host_cmd "$ar" "rcs $archive $weak_obj"] + if ![string match "" $got] { + fail "$testname (archive)" + return + } + + # A weak external with a real fallback should advertise the public + # alias, so a strong undefined reference can extract the member. + set got [run_host_cmd "$nm" "--print-armap $archive"] + if ![regexp "(^|\n)_?func in weak-ext-add1-weak-chained\\.o" $got] { + verbose -log $got + fail "$testname (armap)" + return + } + + # Search the archive twice to cover command lines where the driver + # adds a library implicitly and the user also names it explicitly. + if ![ld_link $CC_FOR_TARGET $output \ + [list $main_obj $expected_obj $archive $archive]] { + fail "$testname (link)" + return + } + + if ![isnative] { + pass "$testname (link only)" + return + } + + catch "exec $output" prog_output + if { $prog_output eq "" } { + pass $testname + } else { + verbose $prog_output + fail "$testname ($prog_output)" + } +} + +# Strong undefined reference + strong definition: basic sanity check. +weak_ext_test "weak external: normal (strong undef + strong def)" \ + {weak-ext-main.c weak-ext-add2.c weak-ext-expected3.c weak-ext-dummy.c} + +# Weak declaration with no definition available: func remains NULL, +# never called. +weak_ext_test "weak external: weak undef (no def)" \ + {weak-ext-main-weak.c weak-ext-expected1.c weak-ext-dummy.c} + +# Weak declaration resolved by a strong definition in another object. +weak_ext_test "weak external: weak decl + strong def" \ + {weak-ext-main-weak.c weak-ext-add2.c weak-ext-expected3.c weak-ext-dummy.c} + +# Two weak externals for the same symbol meet: the one whose fallback +# alias points to an actual function body should win over the one whose +# fallback is NULL. +weak_ext_test "weak external: weak decl + weak def" \ + {weak-ext-main-weak.c weak-ext-add1-weak-chained.c weak-ext-expected3.c} + +# Strong undefined reference is seen before the weak definition: the +# linker must still store the weak external's aux record so the fallback +# alias can be resolved later. +weak_ext_test "weak external: strong undef + weak def" \ + {weak-ext-main.c weak-ext-add1-weak-chained.c weak-ext-expected3.c} + +weak_ext_archive_test + +# Strong definition overrides a weak definition: both call sites (in +# main and in dummy) should resolve to the strong def. +weak_ext_test "weak external: strong override of weak" \ + {weak-ext-main.c weak-ext-add1-weak-chained.c weak-ext-add2.c \ + weak-ext-expected5.c} + +# Two identical weak definitions for the same symbol: no conflict, +# the linker picks one (first wins) and discards the duplicate. +weak_ext_test "weak external: duplicate weak defs" \ + {weak-ext-main.c weak-ext-add1-weak-chained.c \ + weak-ext-expected3-add1-weak.c} + +# Weak definition in main overridden by a strong definition elsewhere. +weak_ext_test "weak external: weak def overridden by strong" \ + {weak-ext-main-weak-def.c weak-ext-add2.c weak-ext-expected3.c \ + weak-ext-dummy.c} + +# Weak definition in main used directly when no strong definition exists. +weak_ext_test "weak external: weak def used (no strong)" \ + {weak-ext-main-weak-def.c weak-ext-expected5.c weak-ext-dummy.c} diff --git a/ld/testsuite/ld-pe/weak-ext-add1-weak-chained.c b/ld/testsuite/ld-pe/weak-ext-add1-weak-chained.c new file mode 100644 index 00000000000..5b68b8435e2 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-add1-weak-chained.c @@ -0,0 +1,13 @@ +/* Weak definition of func (adds 1), plus dummy that calls func. */ +extern int value; + +__attribute__((weak)) void func (void) +{ + value += 1; +} + +void +dummy (void) +{ + func (); +} diff --git a/ld/testsuite/ld-pe/weak-ext-add2.c b/ld/testsuite/ld-pe/weak-ext-add2.c new file mode 100644 index 00000000000..691554d17e3 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-add2.c @@ -0,0 +1,8 @@ +/* Strong definition of func (adds 2). */ +extern int value; + +void +func (void) +{ + value += 2; +} diff --git a/ld/testsuite/ld-pe/weak-ext-dummy.c b/ld/testsuite/ld-pe/weak-ext-dummy.c new file mode 100644 index 00000000000..1c97c3cf97f --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-dummy.c @@ -0,0 +1,5 @@ +/* Empty dummy function. */ +void +dummy (void) +{ +} diff --git a/ld/testsuite/ld-pe/weak-ext-expected1.c b/ld/testsuite/ld-pe/weak-ext-expected1.c new file mode 100644 index 00000000000..5b4138b0bb1 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-expected1.c @@ -0,0 +1 @@ +int expected = 1; diff --git a/ld/testsuite/ld-pe/weak-ext-expected3-add1-weak.c b/ld/testsuite/ld-pe/weak-ext-expected3-add1-weak.c new file mode 100644 index 00000000000..585830bd304 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-expected3-add1-weak.c @@ -0,0 +1,9 @@ +/* Second weak definition of func (adds 1) plus expected value. */ +extern int value; + +__attribute__((weak)) void func (void) +{ + value += 1; +} + +int expected = 3; diff --git a/ld/testsuite/ld-pe/weak-ext-expected3.c b/ld/testsuite/ld-pe/weak-ext-expected3.c new file mode 100644 index 00000000000..3d67d70bcb0 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-expected3.c @@ -0,0 +1 @@ +int expected = 3; diff --git a/ld/testsuite/ld-pe/weak-ext-expected5.c b/ld/testsuite/ld-pe/weak-ext-expected5.c new file mode 100644 index 00000000000..fef6b322c03 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-expected5.c @@ -0,0 +1 @@ +int expected = 5; diff --git a/ld/testsuite/ld-pe/weak-ext-main-weak-def.c b/ld/testsuite/ld-pe/weak-ext-main-weak-def.c new file mode 100644 index 00000000000..05f81d189b4 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-main-weak-def.c @@ -0,0 +1,26 @@ +/* Weak definition of func in main (adds 4). */ +#include + +int value = 1; + +__attribute__((weak)) void func (void) +{ + value += 4; +} + +void dummy (void); +extern int expected; + +int +main (void) +{ + if (func) + func (); + dummy (); + if (value != expected) + { + printf ("expected %d, got %d\n", expected, value); + return 1; + } + return 0; +} diff --git a/ld/testsuite/ld-pe/weak-ext-main-weak.c b/ld/testsuite/ld-pe/weak-ext-main-weak.c new file mode 100644 index 00000000000..bc1501f62c0 --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-main-weak.c @@ -0,0 +1,22 @@ +/* Weak declaration of func (no definition). */ +#include + +__attribute__((weak)) void func (void); +void dummy (void); + +int value = 1; +extern int expected; + +int +main (void) +{ + if (func) + func (); + dummy (); + if (value != expected) + { + printf ("expected %d, got %d\n", expected, value); + return 1; + } + return 0; +} diff --git a/ld/testsuite/ld-pe/weak-ext-main.c b/ld/testsuite/ld-pe/weak-ext-main.c new file mode 100644 index 00000000000..916bb246e5f --- /dev/null +++ b/ld/testsuite/ld-pe/weak-ext-main.c @@ -0,0 +1,21 @@ +/* Strong undefined reference to func. */ +#include + +void func (void); +void dummy (void); + +int value = 1; +extern int expected; + +int +main (void) +{ + func (); + dummy (); + if (value != expected) + { + printf ("expected %d, got %d\n", expected, value); + return 1; + } + return 0; +}