Re: [PATCH v3 4/4] ld/testsuite: Add comprehensive PE COFF weak external tests

Peter0x44 via Binutils <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
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 <[email protected]>:

> 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.