[2/2] ld: testsuite: Add sframe test for PR 33401

Message ID 20251203092050.6795-3-claudiu.zissulescu-ianculescu@oracle.com
State New
Headers
Series sframe: Fix for PR 33401 |

Commit Message

claudiu.zissulescu-ianculescu--- via Binutils Dec. 3, 2025, 9:20 a.m. UTC
  From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>

When linking for a relocable output file (-r), one or more R_*_NONE
relocations may be generated for .sframe section. Two new tcl
procedures are added to sframe.exp file. 'check-dump' is checking if
an input bin file has the same relocation as specified in the second
input argument. 'check_pr33401' is the main checking function for
PR33401 which calls twice the ld tool to produce an relocable output
file.

ld:

	PR ld/33401
	* testsuite/ld-sframe/StateClient.cpp:  New file.
	* testsuite/ld-sframe/StatePlaying.cpp: Likewise.
	* testsuite/ld-sframe/pr33401.rd: Likewise.
	* testsuite/ld-sframe/sframe.exp (check_dump): New procedure.
	(check_pr33401): Likewise.
---
 ld/testsuite/ld-sframe/StateClient.cpp  |  26 ++++++
 ld/testsuite/ld-sframe/StatePlaying.cpp |  41 +++++++++
 ld/testsuite/ld-sframe/pr33401.rd       |   3 +
 ld/testsuite/ld-sframe/sframe.exp       | 114 ++++++++++++++++++++++++
 4 files changed, 184 insertions(+)
 create mode 100644 ld/testsuite/ld-sframe/StateClient.cpp
 create mode 100644 ld/testsuite/ld-sframe/StatePlaying.cpp
 create mode 100644 ld/testsuite/ld-sframe/pr33401.rd
  

Comments

Indu Bhagat Dec. 9, 2025, 9:12 p.m. UTC | #1
On 12/3/25 1:20 AM, claudiu.zissulescu-ianculescu@oracle.com wrote:
> From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
> 
> When linking for a relocable output file (-r), one or more R_*_NONE
> relocations may be generated for .sframe section. Two new tcl
> procedures are added to sframe.exp file. 'check-dump' is checking if
> an input bin file has the same relocation as specified in the second
> input argument. 'check_pr33401' is the main checking function for
> PR33401 which calls twice the ld tool to produce an relocable output
> file.
> 
> ld:
> 
> 	PR ld/33401
> 	* testsuite/ld-sframe/StateClient.cpp:  New file.
> 	* testsuite/ld-sframe/StatePlaying.cpp: Likewise.
> 	* testsuite/ld-sframe/pr33401.rd: Likewise.
> 	* testsuite/ld-sframe/sframe.exp (check_dump): New procedure.
> 	(check_pr33401): Likewise.
> ---

Thanks Claudiu for reducing the test files to create this testcase.

Some comments inline.

>   ld/testsuite/ld-sframe/StateClient.cpp  |  26 ++++++
>   ld/testsuite/ld-sframe/StatePlaying.cpp |  41 +++++++++
>   ld/testsuite/ld-sframe/pr33401.rd       |   3 +
>   ld/testsuite/ld-sframe/sframe.exp       | 114 ++++++++++++++++++++++++
>   4 files changed, 184 insertions(+)
>   create mode 100644 ld/testsuite/ld-sframe/StateClient.cpp
>   create mode 100644 ld/testsuite/ld-sframe/StatePlaying.cpp
>   create mode 100644 ld/testsuite/ld-sframe/pr33401.rd
> 
> diff --git a/ld/testsuite/ld-sframe/StateClient.cpp b/ld/testsuite/ld-sframe/StateClient.cpp
> new file mode 100644
> index 00000000000..0154469ce6c
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/StateClient.cpp
> @@ -0,0 +1,26 @@
> +void a(void *);
> +class b {
> +  long ag;
> +  bool c();
> +  void m_fn2() {
> +    if (c())
> +      d(ag);
> +  }
> +  void d(long);
> +
> +public:
> +  ~b() { m_fn2(); }
> +};
> +class Player {
> +  int *an;
> +  b ao;
> +  char be;
> +
> +public:
> +  virtual ~Player() {
> +    a(&be);
> +    a(&be);
> +    a(&be);
> +    delete an;
> +  }
> +} e;
> diff --git a/ld/testsuite/ld-sframe/StatePlaying.cpp b/ld/testsuite/ld-sframe/StatePlaying.cpp
> new file mode 100644
> index 00000000000..f61c32d54c1
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/StatePlaying.cpp
> @@ -0,0 +1,41 @@
> +void b(void *);
> +class c {
> +public:
> +  long am;
> +  bool d();
> +  void e() {
> +    if (d())
> +      f(am);
> +  }
> +  void f(long);
> +  ~c() { e(); }
> +};
> +class g {
> +public:
> +  virtual ~g();
> +};
> +class Player {
> +  int *bh;
> +  c bi;
> +  char bj;
> +
> +public:
> +  virtual ~Player() {
> +    b(&bj);
> +    b(&bj);
> +    b(&bj);
> +    delete bh;
> +  }
> +};
> +class h {
> +public:
> +  ~h() {
> +    Player *a[0];
> +    delete a[0];
> +  }
> +};
> +class i : g {
> +  h bo;
> +  virtual int j();
> +};
> +int i::j() {}
> diff --git a/ld/testsuite/ld-sframe/pr33401.rd b/ld/testsuite/ld-sframe/pr33401.rd
> new file mode 100644
> index 00000000000..00142818b34
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/pr33401.rd
> @@ -0,0 +1,3 @@
> +#...
> +[0-9a-f]+ +0+ +R_.*_NONE +.*
> +#pass
> \ No newline at end of file
> diff --git a/ld/testsuite/ld-sframe/sframe.exp b/ld/testsuite/ld-sframe/sframe.exp
> index 61dc4dafa2e..42faeafca5f 100644
> --- a/ld/testsuite/ld-sframe/sframe.exp
> +++ b/ld/testsuite/ld-sframe/sframe.exp
> @@ -18,6 +18,118 @@
>   # MA 02110-1301, USA.
>   #
>   
> +proc check_dump { binfile dumpfile } {
> +    global srcdir
> +    global READELF
> +    global subdir
> +    global env
> +    global runtests
> +
> +    set binary $READELF
> +    set progopts "-j .rela.sframe"
> +    set failed 0
> +
> +    # Ensure consistent sorting of symbols
> +    if {[info exists env(LC_ALL)]} {
> +	set old_lc_all $env(LC_ALL)
> +    }
> +    set env(LC_ALL) "C"
> +    set cmd "$binary $progopts $binfile > dump.out"
> +    send_log "$cmd\n"
> +    catch "exec $cmd" comp_output
> +    if {[info exists old_lc_all]} {
> +	set env(LC_ALL) $old_lc_all
> +    } else {
> +	unset env(LC_ALL)
> +    }
> +    set comp_output [prune_warnings $comp_output]
> +    if ![string match "" $comp_output] then {
> +	send_log "$comp_output\n"
> +	return 1
> +    }
> +
> +    if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
> +	verbose -log "output is [file_contents "dump.out"]" 2
> +	return 1
> +    }
> +    return 0
> +}
> +
> +# Test infrastructure for bug 33401
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=33401
> +# Sframe section contains R_*_NONE relocations intermingled with other
> +# relas in the output relocatable object.
> +#
> +# src_files filenames of assembler files
> +proc check_pr33401 { src_files } {
> +    global ld
> +    global CXX_FOR_TARGET
> +    global as
> +    global LDFLAGS
> +    global srcdir
> +    global subdir
> +    global env
> +    global runtests
> +
> +    set objfiles {}
> +    set testname "PR33401"
> +    set failed 0
> +    set linkfile "tmpdir/automa_module.o"
> +
> +    if ![runtest_file_p $runtests $testname] then {
> +	return 0
> +    }
> +

I think there needs to be a check for presence of CXX_FOR_TARGET 
somewhere.  Perhaps like so?

# Check to see if the C++ compilers is available
if { [which $CXX_FOR_TARGET] == 0 } {
     return
}

Without such a check, this test will fail for cross-builds when the 
corresponding CXX_FOR_TARGET is not installed.

E.g., for --target=aarch64-linux, I see not-graceful exit when running 
make check:

ERROR: aarch64-linux-g++ does not exist
Error during assembling one if the input files.
Error/Warning threshold exceeded:  1 0 (max. 1 3)


> +    # Assemble each file in the test.
> +    foreach src_file $src_files {
> +	set fileroot "[file rootname [file tail $src_file]]"
> +	set objfile "tmpdir/$fileroot.o"
> +
> +	if { [file extension $src_file] == ".cpp" } {
> +	    set as_file "tmpdir/$fileroot.s"
> +	    if ![ld_compile "$CXX_FOR_TARGET -S -O2 -w" $srcdir/$subdir/$src_file $as_file] {
> +		set failed 1
> +		break
> +	    }
> +	} else {
> +	    set as_file "$srcdir/$subdir/$src_file"
> +	}
> +	if { ![ld_assemble $as "--gsframe $as_file" $objfile] } {
> +	    set failed 1
> +	    break
> +	}
> +	lappend objfiles $objfile
> +    }
> +
> +    # Catch assembler errors.
> +    if { $failed } {
> +	verbose -log "Error during assembling one if the input files."
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Do the first linking. If this fails, we cannot resolve the test.
> +    if { ![ld_link $ld $linkfile "-L$srcdir/$subdir -r $objfiles"] } {
> +	verbose -log "Error during linking assembled objects."
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Check the output of the first ld invocation
> +    if { [check_dump $linkfile pr33401.rd] } {
> +	verbose -log "No R_*_NONE in .rela.sframe"
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Check if the second ld -r invocation is ok
> +    if { ![ld_link $ld /dev/null "-L$srcdir/$subdir -r $linkfile"] } {
> +	fail $testname
> +    } else {
> +	pass $testname
> +    }
> +}
> +
>   if [skip_sframe_tests] {
>       unsupported "no SFrame format support in the assembler, or SFrame disabled"
>       return 0
> @@ -40,6 +152,8 @@ foreach sframe_test $sframe_test_list {
>       run_dump_test [file rootname $sframe_test]
>   }
>   
> +check_pr33401 {StateClient.cpp  StatePlaying.cpp}
> +
>   if {[info exists old_lc_all]} {
>       set env(LC_ALL) $old_lc_all
>   } else {
  
Indu Bhagat Dec. 9, 2025, 11:41 p.m. UTC | #2
On 12/3/25 1:20 AM, claudiu.zissulescu-ianculescu@oracle.com wrote:
> From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
> 
> When linking for a relocable output file (-r), one or more R_*_NONE
> relocations may be generated for .sframe section. Two new tcl
> procedures are added to sframe.exp file. 'check-dump' is checking if
> an input bin file has the same relocation as specified in the second
> input argument. 'check_pr33401' is the main checking function for
> PR33401 which calls twice the ld tool to produce an relocable output
> file.
> 
> ld:
> 
> 	PR ld/33401
> 	* testsuite/ld-sframe/StateClient.cpp:  New file.
> 	* testsuite/ld-sframe/StatePlaying.cpp: Likewise.
> 	* testsuite/ld-sframe/pr33401.rd: Likewise.
> 	* testsuite/ld-sframe/sframe.exp (check_dump): New procedure.
> 	(check_pr33401): Likewise.

Is it possible to refactor it a bit so more tests of similar nature may 
be added later.  Like:

run_sframe_reloc_test { "name of test", {file1.cpp file2.cpp}, "ld -r", 
outfile.o, "readelf -r", dumpfile.rd}
run_sframe_reloc_test { "name of test", {test1.c test2.c test3.c}, "ld 
-r", outfile2.o, "readelf -r", dumpfile2.rd}
...

In this test, I see you run a ld -r one final time, so for 33401, we 
could invoke:

check_pr33401 {
   run_sframe_reloc_test { "name of test", {file1.cpp file2.cpp}, "ld 
-r", outfile.o, "readelf -r", dumpfile.rd}
   # run ld -r
   ...
}

Thanks

> ---
>   ld/testsuite/ld-sframe/StateClient.cpp  |  26 ++++++
>   ld/testsuite/ld-sframe/StatePlaying.cpp |  41 +++++++++
>   ld/testsuite/ld-sframe/pr33401.rd       |   3 +
>   ld/testsuite/ld-sframe/sframe.exp       | 114 ++++++++++++++++++++++++
>   4 files changed, 184 insertions(+)
>   create mode 100644 ld/testsuite/ld-sframe/StateClient.cpp
>   create mode 100644 ld/testsuite/ld-sframe/StatePlaying.cpp
>   create mode 100644 ld/testsuite/ld-sframe/pr33401.rd
> 
> diff --git a/ld/testsuite/ld-sframe/StateClient.cpp b/ld/testsuite/ld-sframe/StateClient.cpp
> new file mode 100644
> index 00000000000..0154469ce6c
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/StateClient.cpp
> @@ -0,0 +1,26 @@
> +void a(void *);
> +class b {
> +  long ag;
> +  bool c();
> +  void m_fn2() {
> +    if (c())
> +      d(ag);
> +  }
> +  void d(long);
> +
> +public:
> +  ~b() { m_fn2(); }
> +};
> +class Player {
> +  int *an;
> +  b ao;
> +  char be;
> +
> +public:
> +  virtual ~Player() {
> +    a(&be);
> +    a(&be);
> +    a(&be);
> +    delete an;
> +  }
> +} e;
> diff --git a/ld/testsuite/ld-sframe/StatePlaying.cpp b/ld/testsuite/ld-sframe/StatePlaying.cpp
> new file mode 100644
> index 00000000000..f61c32d54c1
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/StatePlaying.cpp
> @@ -0,0 +1,41 @@
> +void b(void *);
> +class c {
> +public:
> +  long am;
> +  bool d();
> +  void e() {
> +    if (d())
> +      f(am);
> +  }
> +  void f(long);
> +  ~c() { e(); }
> +};
> +class g {
> +public:
> +  virtual ~g();
> +};
> +class Player {
> +  int *bh;
> +  c bi;
> +  char bj;
> +
> +public:
> +  virtual ~Player() {
> +    b(&bj);
> +    b(&bj);
> +    b(&bj);
> +    delete bh;
> +  }
> +};
> +class h {
> +public:
> +  ~h() {
> +    Player *a[0];
> +    delete a[0];
> +  }
> +};
> +class i : g {
> +  h bo;
> +  virtual int j();
> +};
> +int i::j() {}
> diff --git a/ld/testsuite/ld-sframe/pr33401.rd b/ld/testsuite/ld-sframe/pr33401.rd
> new file mode 100644
> index 00000000000..00142818b34
> --- /dev/null
> +++ b/ld/testsuite/ld-sframe/pr33401.rd
> @@ -0,0 +1,3 @@
> +#...
> +[0-9a-f]+ +0+ +R_.*_NONE +.*
> +#pass
> \ No newline at end of file
> diff --git a/ld/testsuite/ld-sframe/sframe.exp b/ld/testsuite/ld-sframe/sframe.exp
> index 61dc4dafa2e..42faeafca5f 100644
> --- a/ld/testsuite/ld-sframe/sframe.exp
> +++ b/ld/testsuite/ld-sframe/sframe.exp
> @@ -18,6 +18,118 @@
>   # MA 02110-1301, USA.
>   #
>   
> +proc check_dump { binfile dumpfile } {
> +    global srcdir
> +    global READELF
> +    global subdir
> +    global env
> +    global runtests
> +
> +    set binary $READELF
> +    set progopts "-j .rela.sframe"
> +    set failed 0
> +
> +    # Ensure consistent sorting of symbols
> +    if {[info exists env(LC_ALL)]} {
> +	set old_lc_all $env(LC_ALL)
> +    }
> +    set env(LC_ALL) "C"
> +    set cmd "$binary $progopts $binfile > dump.out"
> +    send_log "$cmd\n"
> +    catch "exec $cmd" comp_output
> +    if {[info exists old_lc_all]} {
> +	set env(LC_ALL) $old_lc_all
> +    } else {
> +	unset env(LC_ALL)
> +    }
> +    set comp_output [prune_warnings $comp_output]
> +    if ![string match "" $comp_output] then {
> +	send_log "$comp_output\n"
> +	return 1
> +    }
> +
> +    if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
> +	verbose -log "output is [file_contents "dump.out"]" 2
> +	return 1
> +    }
> +    return 0
> +}
> +
> +# Test infrastructure for bug 33401
> +# https://sourceware.org/bugzilla/show_bug.cgi?id=33401
> +# Sframe section contains R_*_NONE relocations intermingled with other
> +# relas in the output relocatable object.
> +#
> +# src_files filenames of assembler files
> +proc check_pr33401 { src_files } {
> +    global ld
> +    global CXX_FOR_TARGET
> +    global as
> +    global LDFLAGS
> +    global srcdir
> +    global subdir
> +    global env
> +    global runtests
> +
> +    set objfiles {}
> +    set testname "PR33401"
> +    set failed 0
> +    set linkfile "tmpdir/automa_module.o"
> +
> +    if ![runtest_file_p $runtests $testname] then {
> +	return 0
> +    }
> +
> +    # Assemble each file in the test.
> +    foreach src_file $src_files {
> +	set fileroot "[file rootname [file tail $src_file]]"
> +	set objfile "tmpdir/$fileroot.o"
> +
> +	if { [file extension $src_file] == ".cpp" } {
> +	    set as_file "tmpdir/$fileroot.s"
> +	    if ![ld_compile "$CXX_FOR_TARGET -S -O2 -w" $srcdir/$subdir/$src_file $as_file] {
> +		set failed 1
> +		break
> +	    }
> +	} else {
> +	    set as_file "$srcdir/$subdir/$src_file"
> +	}
> +	if { ![ld_assemble $as "--gsframe $as_file" $objfile] } {
> +	    set failed 1
> +	    break
> +	}
> +	lappend objfiles $objfile
> +    }
> +
> +    # Catch assembler errors.
> +    if { $failed } {
> +	verbose -log "Error during assembling one if the input files."
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Do the first linking. If this fails, we cannot resolve the test.
> +    if { ![ld_link $ld $linkfile "-L$srcdir/$subdir -r $objfiles"] } {
> +	verbose -log "Error during linking assembled objects."
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Check the output of the first ld invocation
> +    if { [check_dump $linkfile pr33401.rd] } {
> +	verbose -log "No R_*_NONE in .rela.sframe"
> +	unresolved $testname
> +	return 0
> +    }
> +
> +    # Check if the second ld -r invocation is ok
> +    if { ![ld_link $ld /dev/null "-L$srcdir/$subdir -r $linkfile"] } {
> +	fail $testname
> +    } else {
> +	pass $testname
> +    }
> +}
> +
>   if [skip_sframe_tests] {
>       unsupported "no SFrame format support in the assembler, or SFrame disabled"
>       return 0
> @@ -40,6 +152,8 @@ foreach sframe_test $sframe_test_list {
>       run_dump_test [file rootname $sframe_test]
>   }
>   
> +check_pr33401 {StateClient.cpp  StatePlaying.cpp}
> +
>   if {[info exists old_lc_all]} {
>       set env(LC_ALL) $old_lc_all
>   } else {
  
Claudiu Zissulescu Dec. 10, 2025, 10:06 a.m. UTC | #3
On 12/10/25 1:41 AM, Indu Bhagat wrote:
> On 12/3/25 1:20 AM, claudiu.zissulescu-ianculescu@oracle.com wrote:
>> From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
>>
>> When linking for a relocable output file (-r), one or more R_*_NONE
>> relocations may be generated for .sframe section. Two new tcl
>> procedures are added to sframe.exp file. 'check-dump' is checking if
>> an input bin file has the same relocation as specified in the second
>> input argument. 'check_pr33401' is the main checking function for
>> PR33401 which calls twice the ld tool to produce an relocable output
>> file.
>>
>> ld:
>>
>>     PR ld/33401
>>     * testsuite/ld-sframe/StateClient.cpp:  New file.
>>     * testsuite/ld-sframe/StatePlaying.cpp: Likewise.
>>     * testsuite/ld-sframe/pr33401.rd: Likewise.
>>     * testsuite/ld-sframe/sframe.exp (check_dump): New procedure.
>>     (check_pr33401): Likewise.
> 
> Is it possible to refactor it a bit so more tests of similar nature may 
> be added later.  Like:
> 
> run_sframe_reloc_test { "name of test", {file1.cpp file2.cpp}, "ld -r", 
> outfile.o, "readelf -r", dumpfile.rd}
> run_sframe_reloc_test { "name of test", {test1.c test2.c test3.c}, "ld - 
> r", outfile2.o, "readelf -r", dumpfile2.rd}
> ...

I think for the above exercise, we can use the already in procedure 
`run_ld_link_test` which does exactly what you want.

In my case, the issue is that the ld command is called twice, and the 
results are checked after each invocation. Thus the above existing 
testing command is not sufficient.

//Claudiu
  
Indu Bhagat Dec. 11, 2025, 7:59 a.m. UTC | #4
On 12/10/25 2:06 AM, Claudiu Zissulescu wrote:
> 
> 
> On 12/10/25 1:41 AM, Indu Bhagat wrote:
>> On 12/3/25 1:20 AM, claudiu.zissulescu-ianculescu@oracle.com wrote:
>>> From: Claudiu Zissulescu <claudiu.zissulescu-ianculescu@oracle.com>
>>>
>>> When linking for a relocable output file (-r), one or more R_*_NONE
>>> relocations may be generated for .sframe section. Two new tcl
>>> procedures are added to sframe.exp file. 'check-dump' is checking if
>>> an input bin file has the same relocation as specified in the second
>>> input argument. 'check_pr33401' is the main checking function for
>>> PR33401 which calls twice the ld tool to produce an relocable output
>>> file.
>>>
>>> ld:
>>>
>>>     PR ld/33401
>>>     * testsuite/ld-sframe/StateClient.cpp:  New file.
>>>     * testsuite/ld-sframe/StatePlaying.cpp: Likewise.
>>>     * testsuite/ld-sframe/pr33401.rd: Likewise.
>>>     * testsuite/ld-sframe/sframe.exp (check_dump): New procedure.
>>>     (check_pr33401): Likewise.
>>
>> Is it possible to refactor it a bit so more tests of similar nature 
>> may be added later.  Like:
>>
>> run_sframe_reloc_test { "name of test", {file1.cpp file2.cpp}, "ld - 
>> r", outfile.o, "readelf -r", dumpfile.rd}
>> run_sframe_reloc_test { "name of test", {test1.c test2.c test3.c}, "ld 
>> - r", outfile2.o, "readelf -r", dumpfile2.rd}
>> ...
> 
> I think for the above exercise, we can use the already in procedure 
> `run_ld_link_test` which does exactly what you want.
> 
> In my case, the issue is that the ld command is called twice, and the 
> results are checked after each invocation. Thus the above existing 
> testing command is not sufficient.
> 

Wont run_cc_link_tests work for the case of PR 33401 then?

I will send a test stub on your updated patch proposal.  Let me know 
what you think

Thanks
  

Patch

diff --git a/ld/testsuite/ld-sframe/StateClient.cpp b/ld/testsuite/ld-sframe/StateClient.cpp
new file mode 100644
index 00000000000..0154469ce6c
--- /dev/null
+++ b/ld/testsuite/ld-sframe/StateClient.cpp
@@ -0,0 +1,26 @@ 
+void a(void *);
+class b {
+  long ag;
+  bool c();
+  void m_fn2() {
+    if (c())
+      d(ag);
+  }
+  void d(long);
+
+public:
+  ~b() { m_fn2(); }
+};
+class Player {
+  int *an;
+  b ao;
+  char be;
+
+public:
+  virtual ~Player() {
+    a(&be);
+    a(&be);
+    a(&be);
+    delete an;
+  }
+} e;
diff --git a/ld/testsuite/ld-sframe/StatePlaying.cpp b/ld/testsuite/ld-sframe/StatePlaying.cpp
new file mode 100644
index 00000000000..f61c32d54c1
--- /dev/null
+++ b/ld/testsuite/ld-sframe/StatePlaying.cpp
@@ -0,0 +1,41 @@ 
+void b(void *);
+class c {
+public:
+  long am;
+  bool d();
+  void e() {
+    if (d())
+      f(am);
+  }
+  void f(long);
+  ~c() { e(); }
+};
+class g {
+public:
+  virtual ~g();
+};
+class Player {
+  int *bh;
+  c bi;
+  char bj;
+
+public:
+  virtual ~Player() {
+    b(&bj);
+    b(&bj);
+    b(&bj);
+    delete bh;
+  }
+};
+class h {
+public:
+  ~h() {
+    Player *a[0];
+    delete a[0];
+  }
+};
+class i : g {
+  h bo;
+  virtual int j();
+};
+int i::j() {}
diff --git a/ld/testsuite/ld-sframe/pr33401.rd b/ld/testsuite/ld-sframe/pr33401.rd
new file mode 100644
index 00000000000..00142818b34
--- /dev/null
+++ b/ld/testsuite/ld-sframe/pr33401.rd
@@ -0,0 +1,3 @@ 
+#...
+[0-9a-f]+ +0+ +R_.*_NONE +.*
+#pass
\ No newline at end of file
diff --git a/ld/testsuite/ld-sframe/sframe.exp b/ld/testsuite/ld-sframe/sframe.exp
index 61dc4dafa2e..42faeafca5f 100644
--- a/ld/testsuite/ld-sframe/sframe.exp
+++ b/ld/testsuite/ld-sframe/sframe.exp
@@ -18,6 +18,118 @@ 
 # MA 02110-1301, USA.
 #
 
+proc check_dump { binfile dumpfile } {
+    global srcdir
+    global READELF
+    global subdir
+    global env
+    global runtests
+
+    set binary $READELF
+    set progopts "-j .rela.sframe"
+    set failed 0
+
+    # Ensure consistent sorting of symbols
+    if {[info exists env(LC_ALL)]} {
+	set old_lc_all $env(LC_ALL)
+    }
+    set env(LC_ALL) "C"
+    set cmd "$binary $progopts $binfile > dump.out"
+    send_log "$cmd\n"
+    catch "exec $cmd" comp_output
+    if {[info exists old_lc_all]} {
+	set env(LC_ALL) $old_lc_all
+    } else {
+	unset env(LC_ALL)
+    }
+    set comp_output [prune_warnings $comp_output]
+    if ![string match "" $comp_output] then {
+	send_log "$comp_output\n"
+	return 1
+    }
+
+    if { [regexp_diff "dump.out" "$srcdir/$subdir/$dumpfile"] } then {
+	verbose -log "output is [file_contents "dump.out"]" 2
+	return 1
+    }
+    return 0
+}
+
+# Test infrastructure for bug 33401
+# https://sourceware.org/bugzilla/show_bug.cgi?id=33401
+# Sframe section contains R_*_NONE relocations intermingled with other
+# relas in the output relocatable object.
+#
+# src_files filenames of assembler files
+proc check_pr33401 { src_files } {
+    global ld
+    global CXX_FOR_TARGET
+    global as
+    global LDFLAGS
+    global srcdir
+    global subdir
+    global env
+    global runtests
+
+    set objfiles {}
+    set testname "PR33401"
+    set failed 0
+    set linkfile "tmpdir/automa_module.o"
+
+    if ![runtest_file_p $runtests $testname] then {
+	return 0
+    }
+
+    # Assemble each file in the test.
+    foreach src_file $src_files {
+	set fileroot "[file rootname [file tail $src_file]]"
+	set objfile "tmpdir/$fileroot.o"
+
+	if { [file extension $src_file] == ".cpp" } {
+	    set as_file "tmpdir/$fileroot.s"
+	    if ![ld_compile "$CXX_FOR_TARGET -S -O2 -w" $srcdir/$subdir/$src_file $as_file] {
+		set failed 1
+		break
+	    }
+	} else {
+	    set as_file "$srcdir/$subdir/$src_file"
+	}
+	if { ![ld_assemble $as "--gsframe $as_file" $objfile] } {
+	    set failed 1
+	    break
+	}
+	lappend objfiles $objfile
+    }
+
+    # Catch assembler errors.
+    if { $failed } {
+	verbose -log "Error during assembling one if the input files."
+	unresolved $testname
+	return 0
+    }
+
+    # Do the first linking. If this fails, we cannot resolve the test.
+    if { ![ld_link $ld $linkfile "-L$srcdir/$subdir -r $objfiles"] } {
+	verbose -log "Error during linking assembled objects."
+	unresolved $testname
+	return 0
+    }
+
+    # Check the output of the first ld invocation
+    if { [check_dump $linkfile pr33401.rd] } {
+	verbose -log "No R_*_NONE in .rela.sframe"
+	unresolved $testname
+	return 0
+    }
+
+    # Check if the second ld -r invocation is ok
+    if { ![ld_link $ld /dev/null "-L$srcdir/$subdir -r $linkfile"] } {
+	fail $testname
+    } else {
+	pass $testname
+    }
+}
+
 if [skip_sframe_tests] {
     unsupported "no SFrame format support in the assembler, or SFrame disabled"
     return 0
@@ -40,6 +152,8 @@  foreach sframe_test $sframe_test_list {
     run_dump_test [file rootname $sframe_test]
 }
 
+check_pr33401 {StateClient.cpp  StatePlaying.cpp}
+
 if {[info exists old_lc_all]} {
     set env(LC_ALL) $old_lc_all
 } else {