Bug 29226 - gcc -fcf-protection option causes GCC 12 gccgo build to fail : "failed to match split-stack sequence"
Summary: gcc -fcf-protection option causes GCC 12 gccgo build to fail : "failed to mat...
Status: UNCONFIRMED
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.38
: P1 normal
Target Milestone: ---
Assignee: Cary Coutant
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-06-05 13:04 UTC by Jason Vas Dias
Modified: 2022-06-07 22:22 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
binutils-local.spec (38.85 KB, text/x-rpm-spec)
2022-06-05 18:49 UTC, Jason Vas Dias
Details
gcc-12-local.spec (24.94 KB, text/x-rpm-spec)
2022-06-05 18:49 UTC, Jason Vas Dias
Details
binutils-2.38-bug29226.patch (1.18 KB, text/x-patch)
2022-06-05 18:49 UTC, Jason Vas Dias
Details
binutils-2.38-gcc12-libtool-no-rpath.patch (359 bytes, text/x-patch)
2022-06-05 18:49 UTC, Jason Vas Dias
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jason Vas Dias 2022-06-05 13:04:58 UTC
When building the Fedora 37 'gcc-12.1.1.1-fc37.src.rpm' on a Rocky Linux EL8
system, only modified by setting "%define _prefix /usr/local", renaming to
'gcc-12-local', and changing the Provides and sub-package Requires from 'gcc' to
to 'gcc-12-local*' & removing the Obsoletes, AFTER building the binutils-2.38-14.1-fc37.src.rpm, similarly renamed 'binutils-local-2.38-14.1.el8',  similarly relocated under /usr/local ,
with $PATH set to /usr/local/bin:/usr/bin , to build EVERY supported
GCC language, including gnat, d, gccgo, and objc, the gccgo build 
fails on this command:


```<quote><lit>
echo timestamp > s-zdefaultcc 
/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/gccgo -B/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/ -B/usr/local/x86_64-redhat-linux/bin/ -B/usr/local/x86_64-redhat-linux/lib/ -isystem /usr/local/x86_64-redhat-linux/include -isystem /usr/local/x86_64-redhat-linux/sys-include   -O2 -fexceptions -g -grecord-gcc-switches -Wall -Wformat-security -Wp,-D_GLIBCXX_ASSERTIONS -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -I ../x86_64-redhat-linux/libgo -static-libstdc++ -static-libgcc -Wl,-z,relro,-z,now -L ../x86_64-redhat-linux/libgo -L ../x86_64-redhat-linux/libgo/.libs -o cgo ../../gotools/../libgo/go/cmd/cgo/ast.go ../../gotools/../libgo/go/cmd/cgo/ast_go118.go ../../gotools/../libgo/go/cmd/cgo/doc.go ../../gotools/../libgo/go/cmd/cgo/gcc.go ../../gotools/../libgo/go/cmd/cgo/godefs.go ../../gotools/../libgo/go/cmd/cgo/main.go ../../gotools/../libgo/go/cmd/cgo/out.go ../../gotools/../libgo/go/cmd/cgo/util.go zdefaultcc.go ../x86_64-redhat-linux/libgo/libgotool.a  
go1: warning: command-line option '-Wformat-security' is valid for C/C++/ObjC/ObjC++ but not for Go
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 150
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 1e0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 220
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 260
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 2a0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 2e0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 320
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 360
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 3a0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 3e0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 420
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 460
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 4a0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 4e0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 520
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 560
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 5f0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 630
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 670
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 6b0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 6f0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 730
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 770
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 7b0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 7f0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 830
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 870
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 8b0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 8f0
/usr/local/bin/ld: error: /tmp/ccFdAbSm.o: failed to match split-stack sequence at section 4 offset 1130
collect2: error: ld returned 1 exit status
make[2]: *** [Makefile:830: buildid] Error 1
make[2]: *** Waiting for unfinished jobs....

</lit></quote>


Investigation shows that ONLY removing '-fcf-protection' flag
allows the above command line to succeed with no errors or warnings.

I guess this COULD be either a GCC 12 bug, with gcc somehow putting
the wrong / incorrect information into objs for '-fcf-protection',
OR binutils's 'ld' is somehow interpreting this information incorrectly.

This is most annoying, as everything else about the build worked perfectly.

I will investigate to see if I can pin down precisely what 
-fcf-protection information is being inserted and if / how it
is incorrect or ld is mis-interpreting it, unless anyone might know 
and would please tell me ?
Comment 1 Jason Vas Dias 2022-06-05 13:18:24 UTC
Also, doing this, as root, solves the problem:
  $ cd /usr/local/bin
  $ mv ld not-ld
  $ ln -s /opt/rh/gcc-toolset-11/root/usr/bin/ld ld

So this is why I raised the bug against binutils 2.38 in the first instance -
it DOES NOT happen with ld 2.35 , ie. WITH '-fcf-protection' ld 2.35
handles the same command line fine.

So this IS a bug with ld v2.38, and a regression, OR the RedHat
distro maintainers have somehow messed up ld v2.38 with their 
patches...

Investigating ...
Comment 2 Jason Vas Dias 2022-06-05 13:39:18 UTC
Does NOT happen when option is changed from
 '-fcf-protection' to '-fcf-protection=check' -
 '-fcf-protection=branch' and '-fcf-protection=full'
also trigger the bug.

So I COULD make GCC use this option instead, and rebuild,
but it is a shame to have to do this to workaround this bug
in ld 2.38 (I think it is using ld.gold for this under the hood -
the '-fcf-protection' code only seems to be in the 'gold' source ?
Comment 3 Jason Vas Dias 2022-06-05 14:29:12 UTC
OK, as root, if I install the binutils-local-debuginfo and 
binutils-local-gold debuginfo RPMs, I can do :

 $ cd /usr/local/bin
 $ mv ld ld.bin
 $ echo '#!/bin/bash
/usr/bin/gdb -q --batch-silent -ex 'set breakpoint pending on' -ex 'b x86_64.cc:6113' -ex run --args /usr/local/bin/ld.bin "$@"
 
To make gdb load debuginfo for 'ld' and break at the point
in binutils' gold/x86_64.cc where it is about to log the
error message:

template<int size>
void
Target_x86_64<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
					section_offset_type fnoffset,
					section_size_type fnsize,
					const unsigned char*,
					size_t,
					unsigned char* view,
					section_size_type view_size,
					std::string* from,
					std::string* to) const
{
  const char* const cmp_insn = reinterpret_cast<const char*>
      (size == 32 ? cmp_insn_32 : cmp_insn_64);
  const char* const lea_r10_insn = reinterpret_cast<const char*>
      (size == 32 ? lea_r10_insn_32 : lea_r10_insn_64);
  const char* const lea_r11_insn = reinterpret_cast<const char*>
      (size == 32 ? lea_r11_insn_32 : lea_r11_insn_64);

  const size_t cmp_insn_len =
      (size == 32 ? sizeof(cmp_insn_32) : sizeof(cmp_insn_64));
  const size_t lea_r10_insn_len =
      (size == 32 ? sizeof(lea_r10_insn_32) : sizeof(lea_r10_insn_64));
  const size_t lea_r11_insn_len =
      (size == 32 ? sizeof(lea_r11_insn_32) : sizeof(lea_r11_insn_64));
  const size_t nop_len = (size == 32 ? 7 : 8);

  // The function starts with a comparison of the stack pointer and a
  // field in the TCB.  This is followed by a jump.

  // cmp %fs:NN,%rsp
  if (this->match_view(view, view_size, fnoffset, cmp_insn, cmp_insn_len)
      && fnsize > nop_len + 1)
    {
      // We will call __morestack if the carry flag is set after this
      // comparison.  We turn the comparison into an stc instruction
      // and some nops.
      view[fnoffset] = '\xf9';
      this->set_view_to_nop(view, view_size, fnoffset + 1, nop_len);
    }
  // lea NN(%rsp),%r10
  // lea NN(%rsp),%r11
  else if ((this->match_view(view, view_size, fnoffset,
			     lea_r10_insn, lea_r10_insn_len)
	    || this->match_view(view, view_size, fnoffset,
				lea_r11_insn, lea_r11_insn_len))
	   && fnsize > 8)
    {
      // This is loading an offset from the stack pointer for a
      // comparison.  The offset is negative, so we decrease the
      // offset by the amount of space we need for the stack.  This
      // means we will avoid calling __morestack if there happens to
      // be plenty of space on the stack already.
      unsigned char* pval = view + fnoffset + 4;
      uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval);
      val -= parameters->options().split_stack_adjust_size();
      elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
    }
  else
    {
      if (!object->has_no_split_stack())
/*LINE #6113:*/object->error(_("failed to match split-stack sequence at "
			"section %u offset %0zx"),
		      shndx, static_cast<size_t>(fnoffset));
      return;
    }

  // We have to change the function so that it calls
  // __morestack_non_split instead of __morestack.  The former will
  // allocate additional stack space.
  *from = "__morestack";
  *to = "__morestack_non_split";
}


AARGH !  The bug does NOT happen when I run ld this way
         under GDB - the command works !

That was most unexpected.

I am now going to have to rebuild ld/gold with line 6113 modified to be:

object->error(_("failed to match split-stack sequence at "
			"section %u offset %0zx - r10:%c r11:%c fnsize: %u"),
		      shndx, static_cast<size_t>(fnoffset)
             , this->match_view(view, view_size, fnoffset,
			        lea_r10_insn, lea_r10_insn_len
                               ) ? '1' : '0'
	     , this->match_view(view, view_size, fnoffset,
				lea_r11_insn, lea_r11_insn_len

	   && fnsize > 8)
             );
Comment 4 Jason Vas Dias 2022-06-05 14:34:04 UTC
Oops, had not finished editing last line of previous comment:
gold/x86_64.c, line 6113 will become:
object->error(_("failed to match split-stack sequence at "
			"section %u offset %0zx - r10:%c r11:%c fnsize: %u"),
		      shndx, static_cast<size_t>(fnoffset)
             , this->match_view(view, view_size, fnoffset,
			        lea_r10_insn, lea_r10_insn_len
                               ) ? '1' : '0'
	     , this->match_view(view, view_size, fnoffset,
				lea_r11_insn, lea_r11_insn_len
                               ) ? '1' : '0'
	     , static_cast<uint32_t>(fnsize)
             );

With ld/gold augmented to print that under those circumstances, then we should be a bit further forward in understanding what is going on here.

The fact that it strangely WORKS when run under the old binutils-2.35 using
gdb (I have not got round to building latest gdb yet, was going to do that
with GCC 12), DOES indicate something rather strange and subtle is going on
here.
Comment 5 Jason Vas Dias 2022-06-05 15:20:48 UTC
OK, with binutils 's gold/ld-new and libbfd recompiled with the
above error statement in gold/x86_64.cc, we get:

/usr/local/bin/ld: Unlocking file "/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/libgcc.a"
/usr/local/bin/ld: Closed descriptor 5 for "/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/libgcc_eh.a"
/usr/local/bin/ld: Opened new descriptor 4 for "cgo"
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 540 r10:0 r11:0 115
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 660 r10:0 r11:0 93
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 7e0 r10:0 r11:0 204
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8b0 r10:0 r11:0 191
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 970 r10:0 r11:0 177
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset a30 r10:0 r11:0 369
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset bb0 r10:0 r11:0 161
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset c60 r10:0 r11:0 118
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset ce0 r10:0 r11:0 132
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset d70 r10:0 r11:0 135
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset ec0 r10:0 r11:0 2625
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1910 r10:0 r11:0 240
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1a00 r10:0 r11:0 240
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1af0 r10:0 r11:0 102
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1c70 r10:0 r11:0 218
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1d50 r10:0 r11:0 395
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 1ee0 r10:0 r11:0 277
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 2390 r10:0 r11:0 3519
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3150 r10:0 r11:0 263
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3260 r10:0 r11:0 204
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3330 r10:0 r11:0 282
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3450 r10:0 r11:0 296
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3580 r10:0 r11:0 68
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 35d0 r10:0 r11:0 428
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 39f0 r10:0 r11:0 228
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 3b70 r10:0 r11:0 1496
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 4150 r10:0 r11:0 1421
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 4780 r10:0 r11:0 4649
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 59b0 r10:0 r11:0 304
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 5b90 r10:0 r11:0 1194
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6040 r10:0 r11:0 469
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6220 r10:0 r11:0 401
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6480 r10:0 r11:0 1505
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6a70 r10:0 r11:0 175
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6b20 r10:0 r11:0 205
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 6bf0 r10:0 r11:0 4529
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 7db0 r10:0 r11:0 542
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 7fd0 r10:0 r11:0 344
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8130 r10:0 r11:0 179
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 81f0 r10:0 r11:0 360
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8360 r10:0 r11:0 1810
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8a80 r10:0 r11:0 411
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8c20 r10:0 r11:0 56
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 8c60 r10:0 r11:0 1838
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 938e r10:0 r11:0 68
/usr/local/bin/ld: error: /tmp/ccAgu0zM.o: failed to match split-stack sequence at section 265 offset 93d2 r10:0 r11:0 68




So yes, it is neither an lea_r10_insn nor an lea_r10_insn, and fnsize appears
always to be > 8, so the logic there definitely needs improvement - 
lack masking out the register number in the instruction, so that
ANY 'lea' instruction would trigger insertion of correct code ?

I will try to get it to break there now and see if I can get it to print
what the instruction actually is, in /home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/libgcc_eh.a,
that is causing this issue.
Comment 6 Jason Vas Dias 2022-06-05 15:50:23 UTC
OK, now the error message printing code looks like this:

    {
      if (!object->has_no_split_stack())
      {	unsigned char ib[16]={0};
	if ( view )
	{ ib[0] = *(((unsigned char*)view) + fnoffset);
	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
	}
	object->error(_("failed to match split-stack sequence at "
			"section %u offset %0zx r10:%c r11:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
		      shndx, static_cast<size_t>(fnoffset)
	              , (this->match_view(view, view_size, fnoffset,
		  	                  lea_r10_insn, lea_r10_insn_len
                                         ) ? '1' : '0'
                        )
	              , (this->match_view(view, view_size, fnoffset,
				          lea_r11_insn, lea_r11_insn_len
                                         ) ? '1' : '0'
                        )
                      , static_cast<uint32_t>(fnsize)
                      , ib[0], ib[1], ib[2], ib[3]
	             );
      }
      return;


So we will see what instruction is actually at 'view + fnoffset' in
gcc 12's libgcc_eh.a :

/usr/local/bin/ld: Unlocking file "/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/libgcc.a"
/usr/local/bin/ld: Closed descriptor 5 for "/home/jvd/rpmbuild/BUILD/gcc-12.1.1-20220507/obj-x86_64-redhat-linux/./gcc/libgcc_eh.a"
/usr/local/bin/ld: Opened new descriptor 4 for "cgo"
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 540 r10:0 r11:0 115 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 660 r10:0 r11:0 93 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 7e0 r10:0 r11:0 204 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 8b0 r10:0 r11:0 191 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 970 r10:0 r11:0 177 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset a30 r10:0 r11:0 369 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset bb0 r10:0 r11:0 161 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset c60 r10:0 r11:0 118 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset ce0 r10:0 r11:0 132 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset d70 r10:0 r11:0 135 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset ec0 r10:0 r11:0 2625 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1910 r10:0 r11:0 240 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1a00 r10:0 r11:0 240 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1af0 r10:0 r11:0 102 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1c70 r10:0 r11:0 218 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1d50 r10:0 r11:0 395 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 1ee0 r10:0 r11:0 277 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 2390 r10:0 r11:0 3519 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3150 r10:0 r11:0 263 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3260 r10:0 r11:0 204 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3330 r10:0 r11:0 282 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3450 r10:0 r11:0 296 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3580 r10:0 r11:0 68 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 35d0 r10:0 r11:0 428 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 39f0 r10:0 r11:0 228 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 3b70 r10:0 r11:0 1496 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 4150 r10:0 r11:0 1421 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 4780 r10:0 r11:0 4649 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 59b0 r10:0 r11:0 304 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 5b90 r10:0 r11:0 1194 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 6040 r10:0 r11:0 469 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 6220 r10:0 r11:0 401 f3.0f.1e.fa
/usr/local/bin/ld: error: /tmp/ccGv8QZX.o: failed to match split-stack sequence at section 265 offset 6480 r10:0 r11:0 1505 f3.0f.1e.fa
...

Aha, so the instruction that causes the problem is (in hex) 'f3.0f.1e.fa' ?

I will look this up in my Intel SDM .

Maybe ld should make an exception for this sequence ? it always
appears to be the same in every occurrence of this issue.
Comment 7 Jason Vas Dias 2022-06-05 16:08:02 UTC
Aha! Am I right in thinking 'f3.0f.1e.fa' (hex byte string) specifies x86_64
instruction 'RDSSPD/RDSSPQ' ?  

I think so ! :

From Intel Software Developer's Manual (SDM), Book 2, Instructions,
Chapter 3, Instruction Set Reference, page Vol-2B,4-553 (pp.1735)  :
"
 RDSSPD/RDSSPQ—Read Shadow Stack Pointer Opcode/ Op/ 64/32 CPUID 

 F3 0F 1E /1 (mod=11) R V/V CET_SS 

 Copy low 32 bits of shadow stack pointer (SSP) to r32. RDSSPD r32 
 F3 REX.W 0F 1E /1 (mod=11) R V/N.E. CET_SS 
 Copies shadow stack pointer (SSP) to r64. RDSSPQ r64
"

So, then maybe the code should take this as an indication that the
job has been done OK and so NOT to raise an error here ?
Comment 8 Jason Vas Dias 2022-06-05 16:35:29 UTC
So my best guess at a patch would currently be:

$ diff -U1  x86_64.cc~  x86_64.cc
--- x86_64.cc~	2022-01-22 12:14:09.000000000 +0000
+++ x86_64.cc	2022-06-05 17:34:26.400079527 +0100
@@ -6050,2 +6050,3 @@
 static const unsigned char lea_r11_insn_64[] = { 0x4c, 0x8d, 0x9c, 0x24 };
+static const unsigned char rdssp_insn_64[] =   { 0xf3, 0x0f, 0x1e, 0xfa };
 
@@ -6077,3 +6078,3 @@
   const size_t nop_len = (size == 32 ? 7 : 8);
-
+  const size_t rdssp_insn_len = 4;
   // The function starts with a comparison of the stack pointer and a
@@ -6111,7 +6112,28 @@
     {
-      if (!object->has_no_split_stack())
+      if ( (!object->has_no_split_stack())
+         &&(!this_match_view( view, view_size, fnoffset, rdssp_insn, rdssp_insn_len))
+         )
+      {	unsigned char ib[16]={0};
+	if ( view )
+	{ ib[0] = *(((unsigned char*)view) + fnoffset);
+	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
+	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
+	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
+	}
 	object->error(_("failed to match split-stack sequence at "
-			"section %u offset %0zx"),
-		      shndx, static_cast<size_t>(fnoffset));
-      return;
+			"section %u offset %0zx r10:%c r11:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
+		      shndx, static_cast<size_t>(fnoffset)
+	              , (this->match_view(view, view_size, fnoffset,
+		  	                  lea_r10_insn, lea_r10_insn_len
+                                         ) ? '1' : '0'
+                        )
+	              , (this->match_view(view, view_size, fnoffset,
+				          lea_r11_insn, lea_r11_insn_len
+                                         ) ? '1' : '0'
+                        )
+                      , static_cast<uint32_t>(fnsize)
+                      , ib[0], ib[1], ib[2], ib[3]
+	             );
+	return;
+      }
     }
Comment 9 Jason Vas Dias 2022-06-05 16:57:03 UTC
Oops, a better patch is given by :
 $ gendiff gold \~
--- BEGIN PATCH
diff -up gold/i386.cc~ gold/i386.cc
--- gold/i386.cc~	2022-06-05 02:23:38.826984954 +0100
+++ gold/i386.cc	2022-06-05 17:44:30.359415929 +0100
@@ -4191,10 +4191,31 @@ Target_i386::do_calls_non_split(Relobj*
     }
   else
     {
-      if (!object->has_no_split_stack())
+      if ((!object->has_no_split_stack()) &&
+          (!this->match_view(view, view_size, fnoffset, "\xf3\x0f\x1e", 3))
+         )
+      {	unsigned char ib[16]={0};
+	if ( view )
+	{ ib[0] = *(((unsigned char*)view) + fnoffset);
+	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
+	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
+	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
+	}
 	object->error(_("failed to match split-stack sequence at "
-			"section %u offset %0zx"),
-		      shndx, static_cast<size_t>(fnoffset));
+			"section %u offset %0zx #1:%c #2:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
+		      shndx, static_cast<size_t>(fnoffset)
+	              , (this->match_view(view, view_size, fnoffset,
+		  	                  "\x8d\x8c\x24", 3
+                                         ) ? '1' : '0'
+                        )
+	              , (this->match_view(view, view_size, fnoffset,
+				          "\x8d\x8c\x94", 3
+                                         ) ? '1' : '0'
+                        )
+                      , static_cast<uint32_t>(fnsize)
+	              , ib[0], ib[1], ib[2], ib[3]
+	             );
+      }
       return;
     }
 
diff -up gold/x86_64.cc~ gold/x86_64.cc
--- gold/x86_64.cc~	2022-01-22 12:14:09.000000000 +0000
+++ gold/x86_64.cc	2022-06-05 17:52:24.813322107 +0100
@@ -6044,10 +6044,12 @@ Target_x86_64<size>::do_ehframe_datarel_
 static const unsigned char cmp_insn_32[] = { 0x64, 0x3b, 0x24, 0x25 };
 static const unsigned char lea_r10_insn_32[] = { 0x44, 0x8d, 0x94, 0x24 };
 static const unsigned char lea_r11_insn_32[] = { 0x44, 0x8d, 0x9c, 0x24 };
+static const unsigned char rdssp_insn_32[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
 
 static const unsigned char cmp_insn_64[] = { 0x64, 0x48, 0x3b, 0x24, 0x25 };
 static const unsigned char lea_r10_insn_64[] = { 0x4c, 0x8d, 0x94, 0x24 };
 static const unsigned char lea_r11_insn_64[] = { 0x4c, 0x8d, 0x9c, 0x24 };
+static const unsigned char rdssp_insn_64[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
 
 template<int size>
 void
@@ -6067,7 +6069,9 @@ Target_x86_64<size>::do_calls_non_split(
       (size == 32 ? lea_r10_insn_32 : lea_r10_insn_64);
   const char* const lea_r11_insn = reinterpret_cast<const char*>
       (size == 32 ? lea_r11_insn_32 : lea_r11_insn_64);
-
+  const char* const rdssp_insn = reinterpret_cast<const char*>
+      (size == 32 ? rdssp_insn_32 : rdssp_insn_64);
+  
   const size_t cmp_insn_len =
       (size == 32 ? sizeof(cmp_insn_32) : sizeof(cmp_insn_64));
   const size_t lea_r10_insn_len =
@@ -6075,6 +6079,7 @@ Target_x86_64<size>::do_calls_non_split(
   const size_t lea_r11_insn_len =
       (size == 32 ? sizeof(lea_r11_insn_32) : sizeof(lea_r11_insn_64));
   const size_t nop_len = (size == 32 ? 7 : 8);
+  const size_t rdssp_insn_len = 4;
 
   // The function starts with a comparison of the stack pointer and a
   // field in the TCB.  This is followed by a jump.
@@ -6109,10 +6114,31 @@ Target_x86_64<size>::do_calls_non_split(
     }
   else
     {
-      if (!object->has_no_split_stack())
+      if ( (!object->has_no_split_stack())
+         &&(!this->match_view( view, view_size, fnoffset, rdssp_insn, rdssp_insn_len))
+         )
+      {	unsigned char ib[16]={0};
+	if ( view )
+	{ ib[0] = *(((unsigned char*)view) + fnoffset);
+	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
+	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
+	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
+	}
 	object->error(_("failed to match split-stack sequence at "
-			"section %u offset %0zx"),
-		      shndx, static_cast<size_t>(fnoffset));
+			"section %u offset %0zx r10:%c r11:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
+		      shndx, static_cast<size_t>(fnoffset)
+	              , (this->match_view(view, view_size, fnoffset,
+		  	                  lea_r10_insn, lea_r10_insn_len
+                                         ) ? '1' : '0'
+                        )
+	              , (this->match_view(view, view_size, fnoffset,
+				          lea_r11_insn, lea_r11_insn_len
+                                         ) ? '1' : '0'
+                        )
+                      , static_cast<uint32_t>(fnsize)
+                      , ib[0], ib[1], ib[2], ib[3]
+	             );
+      }
       return;
     }
 
---END PATCH
Comment 10 Jason Vas Dias 2022-06-05 17:00:37 UTC
OK, I am now running the full binutils test suite with the above
patch applied, which DOES at least make the gcc build now work OK.
Comment 11 Jason Vas Dias 2022-06-05 17:06:49 UTC
Hmm, close but no cigar - the test suite now bombs out at :

`echo g++ -W -Wall    -Wstack-usage=262144 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -fmerge-constants -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64  -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection     -fno-use-linker-plugin  -Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld  -Wl,--enable-new-dtags -o copy_test_2.so | sed -e 's/\([^ ]*\)\(.*\)/\1 -Bgcctestdir\/\2/' -e 's/-Wp,-D_FORTIFY_SOURCE=[0-9][0-9]*//'` -shared copy_test_2_pic.o
  CXXLD    copy_test
gcctestdir/collect-ld: error: /tmp/cch1aq9d.ltrans0.ltrans.o: cannot make copy relocation for protected symbol 'ip', defined in copy_test_2.so
collect2: error: ld returned 1 exit status
Comment 12 Jason Vas Dias 2022-06-05 17:10:06 UTC
I will try with the last 'return' INSIDE the clause:
+	             );
+        return;
+      }
     }
Comment 13 Jason Vas Dias 2022-06-05 17:27:04 UTC
OK, I discovered the SAME test fails completely without either of my
patches, but BOTH allow the particular GCC build I was trying to succeed -
I'm going with the last one :

---BEGIN PATCH
diff -up gold/i386.cc~ gold/i386.cc
--- gold/i386.cc~	2022-06-05 02:23:38.826984954 +0100
+++ gold/i386.cc	2022-06-05 18:16:55.215927752 +0100
@@ -4190,12 +4190,34 @@ Target_i386::do_calls_non_split(Relobj*
       elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
     }
   else
-    {
-      if (!object->has_no_split_stack())
+    { bool is_rdssp = this->match_view(view, view_size, fnoffset, "\xf3\x0f\x1e", 3);
+      if ((!object->has_no_split_stack()) &&
+           !is_rdssp
+         )
+      {	unsigned char ib[16]={0};
+	if ( view )
+	{ ib[0] = *(((unsigned char*)view) + fnoffset);
+	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
+	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
+	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
+	}
 	object->error(_("failed to match split-stack sequence at "
-			"section %u offset %0zx"),
-		      shndx, static_cast<size_t>(fnoffset));
-      return;
+			"section %u offset %0zx #1:%c #2:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
+		      shndx, static_cast<size_t>(fnoffset)
+	              , (this->match_view(view, view_size, fnoffset,
+		  	                  "\x8d\x8c\x24", 3
+                                         ) ? '1' : '0'
+                        )
+	              , (this->match_view(view, view_size, fnoffset,
+				          "\x8d\x8c\x94", 3
+                                         ) ? '1' : '0'
+                        )
+                      , static_cast<uint32_t>(fnsize)
+	              , ib[0], ib[1], ib[2], ib[3]
+	             );
+      }
+      if ( ! is_rdssp )
+	return;
     }
 
   // We have to change the function so that it calls
diff -up gold/x86_64.cc~ gold/x86_64.cc
--- gold/x86_64.cc~	2022-01-22 12:14:09.000000000 +0000
+++ gold/x86_64.cc	2022-06-05 18:13:08.085938171 +0100
@@ -6044,10 +6044,12 @@ Target_x86_64<size>::do_ehframe_datarel_
 static const unsigned char cmp_insn_32[] = { 0x64, 0x3b, 0x24, 0x25 };
 static const unsigned char lea_r10_insn_32[] = { 0x44, 0x8d, 0x94, 0x24 };
 static const unsigned char lea_r11_insn_32[] = { 0x44, 0x8d, 0x9c, 0x24 };
+static const unsigned char rdssp_insn_32[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
 
 static const unsigned char cmp_insn_64[] = { 0x64, 0x48, 0x3b, 0x24, 0x25 };
 static const unsigned char lea_r10_insn_64[] = { 0x4c, 0x8d, 0x94, 0x24 };
 static const unsigned char lea_r11_insn_64[] = { 0x4c, 0x8d, 0x9c, 0x24 };
+static const unsigned char rdssp_insn_64[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
 
 template<int size>
 void
@@ -6067,7 +6069,9 @@ Target_x86_64<size>::do_calls_non_split(
       (size == 32 ? lea_r10_insn_32 : lea_r10_insn_64);
   const char* const lea_r11_insn = reinterpret_cast<const char*>
       (size == 32 ? lea_r11_insn_32 : lea_r11_insn_64);
-
+  const char* const rdssp_insn = reinterpret_cast<const char*>
+      (size == 32 ? rdssp_insn_32 : rdssp_insn_64);
+  
   const size_t cmp_insn_len =
       (size == 32 ? sizeof(cmp_insn_32) : sizeof(cmp_insn_64));
   const size_t lea_r10_insn_len =
@@ -6075,6 +6079,7 @@ Target_x86_64<size>::do_calls_non_split(
   const size_t lea_r11_insn_len =
       (size == 32 ? sizeof(lea_r11_insn_32) : sizeof(lea_r11_insn_64));
   const size_t nop_len = (size == 32 ? 7 : 8);
+  const size_t rdssp_insn_len = 4;
 
   // The function starts with a comparison of the stack pointer and a
   // field in the TCB.  This is followed by a jump.
@@ -6108,12 +6113,34 @@ Target_x86_64<size>::do_calls_non_split(
       elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
     }
   else
-    {
-      if (!object->has_no_split_stack())
+    { bool is_rdssp = this->match_view( view, view_size, fnoffset, rdssp_insn, rdssp_insn_len);
+      if ( (!object->has_no_split_stack())
+         && !is_rdssp
+         )
+      {	unsigned char ib[16]={0};
+	if ( view )
+	{ ib[0] = *(((unsigned char*)view) + fnoffset);
+	  ib[1] = *(((unsigned char*)view) + fnoffset + 1);
+	  ib[2] = *(((unsigned char*)view) + fnoffset + 2);
+	  ib[3] = *(((unsigned char*)view) + fnoffset + 3);
+	}
 	object->error(_("failed to match split-stack sequence at "
-			"section %u offset %0zx"),
-		      shndx, static_cast<size_t>(fnoffset));
-      return;
+			"section %u offset %0zx r10:%c r11:%c %u %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
+		      shndx, static_cast<size_t>(fnoffset)
+	              , (this->match_view(view, view_size, fnoffset,
+		  	                  lea_r10_insn, lea_r10_insn_len
+                                         ) ? '1' : '0'
+                        )
+	              , (this->match_view(view, view_size, fnoffset,
+				          lea_r11_insn, lea_r11_insn_len
+                                         ) ? '1' : '0'
+                        )
+                      , static_cast<uint32_t>(fnsize)
+                      , ib[0], ib[1], ib[2], ib[3]
+	             );
+      }
+      if( !is_rdssp )
+	return;
     }
 
   // We have to change the function so that it calls
---END PATCH
Comment 14 Jason Vas Dias 2022-06-05 18:49:16 UTC
Created attachment 14130 [details]
binutils-local.spec

OK, CC'ing the RedHat maintainer on this - I do think this
is a bug, and it DOES appear to be fixed by the attached
'binutils-2.38-bug29226.patch', which was successfully
applied by the modified binutils-2.38-14.fc37.src.rpm spec
file , also attached : 'binutils-local.spec', which ran all its
tests successfully with the patch applied, and 'gcc-local.spec',
which finally was able to use the patched binutils 2.38 to
build everything.

Note also that the 'gcc12-libtool-no-rpath.patch' file
is also owned by the gcc SRPM, so if both SRPMs are installed,
one file gets overwritten by the other, which failed the binutils build
after the gcc SRPM is installed - so I renamed the binutils version
'binutils-2.38-libtool-no-rpath.patch' (also attached).

The problem was also that the install scripts get confused by
presence of /usr/bin/ld, and do not install /usr/local/bin/ld,
if /usr/bin/ld exists, so I mistakenly linked 'ld.gold' to ld,
leading me to discover the bug in the first place .
I am fixing that in my binutils-local spec file.

Anyway, GCC now builds either with my patched ld.gold, or with
the proper 'ld' binary produced by the same build.

Please review the attached patch to gold/i386.cc and gold/x86_64.cc -
should they be returning WITHOUT changing the strings, or WITH
changing the strings, IFF we discover that the view+offset points
to an 'rdssp' instruction ?

Best Regards,
Jason Vas Dias, a Software+Embedded Systems (VOIP) Engineer,
West Cork, Ireland
+353 84 874 9040






On 05/06/2022, jason.vas.dias at gmail dot com
<sourceware-bugzilla@sourceware.org> wrote:
> https://sourceware.org/bugzilla/show_bug.cgi?id=29226
>
> Jason Vas Dias <jason.vas.dias at gmail dot com> changed:
>
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>            Priority|P2                          |P1
>                  CC|                            |jason.vas.dias at gmail dot
> com
>
> --- Comment #13 from Jason Vas Dias <jason.vas.dias at gmail dot com> ---
> OK, I discovered the SAME test fails completely without either of my
> patches, but BOTH allow the particular GCC build I was trying to succeed -
> I'm going with the last one :
>
> ---BEGIN PATCH
> diff -up gold/i386.cc~ gold/i386.cc
> --- gold/i386.cc~       2022-06-05 02:23:38.826984954 +0100
> +++ gold/i386.cc        2022-06-05 18:16:55.215927752 +0100
> @@ -4190,12 +4190,34 @@ Target_i386::do_calls_non_split(Relobj*
>        elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
>      }
>    else
> -    {
> -      if (!object->has_no_split_stack())
> +    { bool is_rdssp = this->match_view(view, view_size, fnoffset,
> "\xf3\x0f\x1e", 3);
> +      if ((!object->has_no_split_stack()) &&
> +           !is_rdssp
> +         )
> +      {        unsigned char ib[16]={0};
> +       if ( view )
> +       { ib[0] = *(((unsigned char*)view) + fnoffset);
> +         ib[1] = *(((unsigned char*)view) + fnoffset + 1);
> +         ib[2] = *(((unsigned char*)view) + fnoffset + 2);
> +         ib[3] = *(((unsigned char*)view) + fnoffset + 3);
> +       }
>         object->error(_("failed to match split-stack sequence at "
> -                       "section %u offset %0zx"),
> -                     shndx, static_cast<size_t>(fnoffset));
> -      return;
> +                       "section %u offset %0zx #1:%c #2:%c %u
> %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
> +                     shndx, static_cast<size_t>(fnoffset)
> +                     , (this->match_view(view, view_size, fnoffset,
> +                                         "\x8d\x8c\x24", 3
> +                                         ) ? '1' : '0'
> +                        )
> +                     , (this->match_view(view, view_size, fnoffset,
> +                                         "\x8d\x8c\x94", 3
> +                                         ) ? '1' : '0'
> +                        )
> +                      , static_cast<uint32_t>(fnsize)
> +                     , ib[0], ib[1], ib[2], ib[3]
> +                    );
> +      }
> +      if ( ! is_rdssp )
> +       return;
>      }
>
>    // We have to change the function so that it calls
> diff -up gold/x86_64.cc~ gold/x86_64.cc
> --- gold/x86_64.cc~     2022-01-22 12:14:09.000000000 +0000
> +++ gold/x86_64.cc      2022-06-05 18:13:08.085938171 +0100
> @@ -6044,10 +6044,12 @@ Target_x86_64<size>::do_ehframe_datarel_
>  static const unsigned char cmp_insn_32[] = { 0x64, 0x3b, 0x24, 0x25 };
>  static const unsigned char lea_r10_insn_32[] = { 0x44, 0x8d, 0x94, 0x24 };
>  static const unsigned char lea_r11_insn_32[] = { 0x44, 0x8d, 0x9c, 0x24 };
> +static const unsigned char rdssp_insn_32[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
>
>  static const unsigned char cmp_insn_64[] = { 0x64, 0x48, 0x3b, 0x24, 0x25
> };
>  static const unsigned char lea_r10_insn_64[] = { 0x4c, 0x8d, 0x94, 0x24 };
>  static const unsigned char lea_r11_insn_64[] = { 0x4c, 0x8d, 0x9c, 0x24 };
> +static const unsigned char rdssp_insn_64[]   = { 0xf3, 0x0f, 0x1e, 0xfa };
>
>  template<int size>
>  void
> @@ -6067,7 +6069,9 @@ Target_x86_64<size>::do_calls_non_split(
>        (size == 32 ? lea_r10_insn_32 : lea_r10_insn_64);
>    const char* const lea_r11_insn = reinterpret_cast<const char*>
>        (size == 32 ? lea_r11_insn_32 : lea_r11_insn_64);
> -
> +  const char* const rdssp_insn = reinterpret_cast<const char*>
> +      (size == 32 ? rdssp_insn_32 : rdssp_insn_64);
> +
>    const size_t cmp_insn_len =
>        (size == 32 ? sizeof(cmp_insn_32) : sizeof(cmp_insn_64));
>    const size_t lea_r10_insn_len =
> @@ -6075,6 +6079,7 @@ Target_x86_64<size>::do_calls_non_split(
>    const size_t lea_r11_insn_len =
>        (size == 32 ? sizeof(lea_r11_insn_32) : sizeof(lea_r11_insn_64));
>    const size_t nop_len = (size == 32 ? 7 : 8);
> +  const size_t rdssp_insn_len = 4;
>
>    // The function starts with a comparison of the stack pointer and a
>    // field in the TCB.  This is followed by a jump.
> @@ -6108,12 +6113,34 @@ Target_x86_64<size>::do_calls_non_split(
>        elfcpp::Swap_unaligned<32, false>::writeval(pval, val);
>      }
>    else
> -    {
> -      if (!object->has_no_split_stack())
> +    { bool is_rdssp = this->match_view( view, view_size, fnoffset,
> rdssp_insn,
> rdssp_insn_len);
> +      if ( (!object->has_no_split_stack())
> +         && !is_rdssp
> +         )
> +      {        unsigned char ib[16]={0};
> +       if ( view )
> +       { ib[0] = *(((unsigned char*)view) + fnoffset);
> +         ib[1] = *(((unsigned char*)view) + fnoffset + 1);
> +         ib[2] = *(((unsigned char*)view) + fnoffset + 2);
> +         ib[3] = *(((unsigned char*)view) + fnoffset + 3);
> +       }
>         object->error(_("failed to match split-stack sequence at "
> -                       "section %u offset %0zx"),
> -                     shndx, static_cast<size_t>(fnoffset));
> -      return;
> +                       "section %u offset %0zx r10:%c r11:%c %u
> %2.2hhx.%2.2hhx.%2.2hhx.%2.2hhx"),
> +                     shndx, static_cast<size_t>(fnoffset)
> +                     , (this->match_view(view, view_size, fnoffset,
> +                                         lea_r10_insn, lea_r10_insn_len
> +                                         ) ? '1' : '0'
> +                        )
> +                     , (this->match_view(view, view_size, fnoffset,
> +                                         lea_r11_insn, lea_r11_insn_len
> +                                         ) ? '1' : '0'
> +                        )
> +                      , static_cast<uint32_t>(fnsize)
> +                      , ib[0], ib[1], ib[2], ib[3]
> +                    );
> +      }
> +      if( !is_rdssp )
> +       return;
>      }
>
>    // We have to change the function so that it calls
> ---END PATCH
>
> --
> You are receiving this mail because:
> You are on the CC list for the bug.
> You reported the bug.
Comment 15 Jason Vas Dias 2022-06-05 18:49:17 UTC
Created attachment 14131 [details]
gcc-12-local.spec
Comment 16 Jason Vas Dias 2022-06-05 18:49:17 UTC
Created attachment 14132 [details]
binutils-2.38-bug29226.patch
Comment 17 Jason Vas Dias 2022-06-05 18:49:17 UTC
Created attachment 14133 [details]
binutils-2.38-gcc12-libtool-no-rpath.patch
Comment 18 Cary Coutant 2022-06-07 22:22:10 UTC
I don't really see what CET has to do with split stack, so I would
guess that, with CET enabled, the RDSSPD/Q instruction gets generated
before the CMP or LEA instruction that we're expecting as the start
of the split stack sequence. I don't think it's safe to assume that
the presence of the RDSSPD/Q means that the split stack check is
already done. More likely, you'd need to look for the CMP or LEA
instruction following the shadow stack pointer check.

But I'm not familiar enough with either CET or split-stack to be sure.
Ian, can you please take a look?