From patchwork Sat May 30 19:15:22 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter0x44 X-Patchwork-Id: 136126 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 584FA4BA799D for ; Sat, 30 May 2026 19:17:59 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 584FA4BA799D DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1780168679; bh=14DL6AAjPX6HtN+lXYNgxuywdCEWNnCkoZt+INjryYU=; 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=S84H8B3uHXg5tLI99TGL6SWTgNwFok//NsV0x8EO38Erdlmvwsk8wTdSV6ZQ4c/Mn Kqa9siOhtZ7mzI2Xmu2M0ARVDikLgf2QTKxC20xa0BUuxAHtLJXyH8zifvwDd821Dg B3Bwn2YUKarhCkdYyDRm73BVJULxBJ2GCUNz3Sus= 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 78CF24BA79A3 for ; Sat, 30 May 2026 19:16:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 78CF24BA79A3 ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 78CF24BA79A3 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780168569; cv=none; b=NiISTTtPZHO9YyHrgDaLVw6guMQnTJZfr0u/YUHzMr+8hIsduOtPERJDYwb0zdI3hEJy0JCYbfHUvLVoaNayJc7NuXWW9SikSm38f86CFPr4EhWlmbac3DeVH3FUZUYyIYJTz9l12PE8ZbalxrNj2xM2Aosmw8d6YszsAI04gQU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780168569; c=relaxed/simple; bh=5a9rBhyxdZB5jgrNcjy1MdWEEngMnECyHQPdkE/BhWo=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=DDejL7x6PrHX2IVNCX6pyyCaUVaRYUxF3rBxX7Fd5xcvoLYFuNfoHhAeiMHWpiKwcAvuHTSVBulc4MdFPK0Cgp+ZW/08B+Gr0scHQjqX7fuWOmBZ43TEHYldXH29JQoLGYqET2OYbSlyjSQjzA3F3xotmiukkALlMW8chVMl5Bg= 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=EdUHSQpC DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 78CF24BA79A3 Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 5EF6E26AF7; Sat, 30 May 2026 21:16:08 +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 GhBmo4BLza2x; Sat, 30 May 2026 21:16:07 +0200 (CEST) To: binutils@sourceware.org Cc: martin@martin.st, pali@kernel.org, lh_mouse@126.com, oleg.tolmatcev@gmail.com, amodra@gmail.com, jbeulich@suse.com, Peter Damianov Subject: [PATCH 3/3] ld/testsuite: Add comprehensive PE COFF weak external tests Date: Sat, 30 May 2026 15:15:22 -0400 Message-ID: <20260530191522.57144-4-peter0x44@disroot.org> In-Reply-To: <20260530191522.57144-1-peter0x44@disroot.org> References: <20260530191522.57144-1-peter0x44@disroot.org> 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, URIBL_BLOCKED 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. ld/testsuite/ * ld-pe/pe-compile.exp (weak_ext_test): New proc. Compiles source files, links via gcc, and runs natively if possible. Add tests: normal, weak-undef, weak-defined, weak-decl-weak-def, 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 | 88 +++++++++++++++++++ .../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, 195 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..189b95ea315 100644 --- a/ld/testsuite/ld-pe/pe-compile.exp +++ b/ld/testsuite/ld-pe/pe-compile.exp @@ -138,3 +138,91 @@ 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)" + } +} + +# 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} + +# 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; +}