[3/3] ld/testsuite: Add comprehensive PE COFF weak external tests
Checks
| Context |
Check |
Description |
| linaro-tcwg-bot/tcwg_binutils_build--master-arm |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 |
success
|
Build passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 |
success
|
Test passed
|
| linaro-tcwg-bot/tcwg_binutils_check--master-arm |
success
|
Test passed
|
Commit Message
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
Comments
On Sat, May 30, 2026 at 03:15:22PM -0400, Peter Damianov wrote:
> Add tests covering the full matrix of weak/strong symbol interactions
> for PE COFF weak externals, based on testcases by Martin Storsjo.
On a cross build of x86_64-w64-mingw32 from x86_64-linux with gcc
13.2.0-6ubuntu1+26.1 installed, I see
x86_64-w64-mingw32 +FAIL: weak external: strong undef + weak def (link)
x86_64-w64-mingw32 +FAIL: weak external: duplicate weak defs (link)
On 2026-06-01 12:39, Alan Modra wrote:
> On Sat, May 30, 2026 at 03:15:22PM -0400, Peter Damianov wrote:
>> Add tests covering the full matrix of weak/strong symbol interactions
>> for PE COFF weak externals, based on testcases by Martin Storsjo.
>
> On a cross build of x86_64-w64-mingw32 from x86_64-linux with gcc
> 13.2.0-6ubuntu1+26.1 installed, I see
> x86_64-w64-mingw32 +FAIL: weak external: strong undef + weak def
> (link)
> x86_64-w64-mingw32 +FAIL: weak external: duplicate weak defs (link)
I tried this myself, and while I don't know for sure what is wrong for
you, I saw these logs:
ERROR:
************************************************************************
ERROR: Your compiler apparently ignores -B when choosing ld.
ERROR: Hint: don't configure gcc using --with-ld (or --with-as)
ERROR: You will not be testing the new ld in many of the following
tests.
ERROR: It seems you will be testing /usr/bin/x86_64-w64-mingw32-ld
instead.
ERROR:
************************************************************************
So I suspect it's testing the wrong LD.
FAIL: weak external: strong undef + weak def (link)
FAIL: weak external: duplicate weak defs (link)
I did manage to reproduce your same failures, but my local gcc which is
probably configured differently is fine.
@@ -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}
+
new file mode 100644
@@ -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 ();
+}
new file mode 100644
@@ -0,0 +1,8 @@
+/* Strong definition of func (adds 2). */
+extern int value;
+
+void
+func (void)
+{
+ value += 2;
+}
new file mode 100644
@@ -0,0 +1,5 @@
+/* Empty dummy function. */
+void
+dummy (void)
+{
+}
new file mode 100644
@@ -0,0 +1 @@
+int expected = 1;
new file mode 100644
@@ -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;
new file mode 100644
@@ -0,0 +1 @@
+int expected = 3;
new file mode 100644
@@ -0,0 +1 @@
+int expected = 5;
new file mode 100644
@@ -0,0 +1,26 @@
+/* Weak definition of func in main (adds 4). */
+#include <stdio.h>
+
+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;
+}
new file mode 100644
@@ -0,0 +1,22 @@
+/* Weak declaration of func (no definition). */
+#include <stdio.h>
+
+__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;
+}
new file mode 100644
@@ -0,0 +1,21 @@
+/* Strong undefined reference to func. */
+#include <stdio.h>
+
+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;
+}