[v3,4/4] ld/testsuite: Add comprehensive PE COFF weak external tests
Commit Message
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
Comments
Oops I forgot to amend this commit with my testsuite changes exercising the issue with archives. Will have to submit a v4. But otherwise, the practical changes are good and I tested them thoroughly. Including the fix for gcc PR124263
Jun 23, 2026 5:38:29 PM Peter Damianov <peter0x44@disroot.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 <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;
> +}
> 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 <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;
> +}
> 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 <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;
> +}
> --
> 2.54.0
@@ -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}
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;
+}