diff mbox series

VAX: Fix the LTO compiler downgrading code to non-PIC model

Message ID alpine.LFD.2.21.2011301023470.656242@eddie.linux-mips.org
State Accepted
Headers show
Series VAX: Fix the LTO compiler downgrading code to non-PIC model | expand

Commit Message

Maciej W. Rozycki Nov. 30, 2020, 3:11 p.m. UTC
Fix a testsuite failure:

/tmp/ccL65Mmt.s: Assembler messages:
/tmp/ccL65Mmt.s:36: Warning: Symbol n used as immediate operand in PIC mode.
FAIL: gcc.dg/lto/pr55660 c_lto_pr55660_0.o-c_lto_pr55660_1.o link, -O0 -flto -flto-partition=none -fuse-linker-plugin

where non-PIC code is substituted by the LTO compiler at the link stage 
for what used to be PIC code in the original compilation.  This happens 
because in the de-facto VAX ELF psABI we rely on code being PIC for GOT 
support in dynamic executables and arrange that by having `-fPIC' passed 
to the compiler by default by means of a specs recipe.

That is however canceled where the LTO wrapper is used, by an internal 
arrangement in the LTO compiler that clears the PIC flag whenever the 
`-flinker-output=exec' option has been used.  This has been deliberately 
introduced with commit 1ff9ed6fb282 ("re PR lto/67548 (LTO drops weak 
binding with "ld -r")")[1]:

"In the log of PR67548 HJ actually pointed out that we do have API at 
linker plugin side which says what type of output is done.  This is cool 
because we can also use it to drop -fpic when building static binary. 
This is common in Firefox, where some objects are built with -fpic and 
linked to both binaries and libraries."

with this code:

    case LTO_LINKER_OUTPUT_EXEC: /* Normal executable */
      flag_pic = 0;
      flag_pie = 0;
      flag_shlib = 0;
      break;

Consequently code like:

.L6:
	addl3 -8(%fp),$n,%r0
	pushl %r0
	calls $1,foo
	addl2 %r0,-12(%fp)
	incl -8(%fp)
.L5:

is produced by the LTO compiler, where a reference to `n' is used that 
is invalid in PIC code, because it uses the immediate addressing mode, 
denoted by the `$' prefix.

For that not to happen we must never pass `-flinker-output=exec' to the 
LTO compiler unless non-PIC code has been explicitly requested.  Using 
`-flinker-output=dyn' except for relocatable output would seem the 
simplest approach, as it does not fiddle with any of the internal code 
model settings beyond what the command-line options have arranged and 
therefore lets them remain the same as with the original compilation, 
but it breaks as well causing PR lto/69866 to retrigger, as that code 
seems sensitive to `flag_shlib':

lto1: internal compiler error: in add_symbol_to_partition_1, at lto/lto-partition.c:152
0x105be1cb add_symbol_to_partition_1
	.../gcc/lto/lto-partition.c:152
0x105be443 add_symbol_to_partition_1
	.../gcc/lto/lto-partition.c:194
0x105be80f add_symbol_to_partition
	.../gcc/lto/lto-partition.c:270
0x105bee6f add_sorted_nodes
	.../gcc/lto/lto-partition.c:395
0x105c0903 lto_balanced_map(int, int)
	.../gcc/lto/lto-partition.c:815
0x105aa91f do_whole_program_analysis
	.../gcc/lto/lto.c:499
0x105aac97 lto_main()
	.../gcc/lto/lto.c:637
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
lto-wrapper: fatal error: .../gcc/xgcc returned 1 exit status
compilation terminated.
.../usr/bin/vax-netbsdelf-ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
compiler exited with status 1
FAIL: gcc.dg/lto/pr69866 c_lto_pr69866_0.o-c_lto_pr69866_1.o link, -O0 -flto -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)

Substitute `-flinker-output=pie' for `-flinker-output=exec' in the specs 
then unless `-no-pie' has also been used, preserving the original intent 
of emitting PIC code by default for executables while keeping the linker 
arrangement unchanged.  The LTO compiler uses the `cc1' spec, so keep 
`cc1plus' unmodified.

This makes code like:

.L6:
	movab n,%r0
	addl2 -8(%fp),%r0
	pushl %r0
	calls $1,foo
	addl2 %r0,-12(%fp)
	incl -8(%fp)
.L5:

be produced instead corresponding to the fragment quoted above, which is 
valid PIC code as it uses the PC-relative addressing mode denoted by the 
absence of a prefix to `n' (which can be redirected to GOT as required, 
by changing the addressing mode to PC-relative indirect in the operand 
specifier).

Ideally we would instead default to the PIE model for executables, but 
that triggers a BFD bug where for a change the LTO wrapper is not used:

.../usr/bin/vax-netbsdelf-ld: /tmp/ccV2sWQt.ltrans0.ltrans.o: warning: GOT addend of 3 to `n' does not match previous GOT addend of 0
FAIL: gcc.dg/lto/pr55660 c_lto_pr55660_0.o-c_lto_pr55660_1.o link, -O2 -flto -flto-partition=1to1 -fno-use-linker-plugin

which is due to assembly code like:

main:
	.word 0
	subl2 $4,%sp
	movab n,%r0
	movab n+3,%r2
	clrl %r3
	movb $98,%r1
.L4:

and consequently object code like:

00000000 <main>:
   0:	00 00       	.word 0x0000 # Entry mask: < >
   2:	c2 04 5e    	subl2 $0x4,sp
   5:	9e ef 00 00 	movab b <main+0xb>,r0
   9:	00 00 50 
			7: R_VAX_GOT32	n
   c:	9e ef 00 00 	movab 12 <main+0x12>,r2
  10:	00 00 52 
			e: R_VAX_GOT32	n+0x3
  13:	d4 53       	clrf r3
  15:	90 8f 62 51 	movb $0x62,r1

being produced.  This would be problematic for external `n', because we 
do not support multiple GOT entries for the same symbol referred to with 
different offsets in a single link unit.  In this case however the LTO 
compiler correctly observes that `n' is defined by the executable and 
not preemptible and therefore no GOT entry will be made for it.

Indeed a valid executable is produced:

00010548 <main>:
   10548:	00 00       	.word 0x0000 # Entry mask: < >
   1054a:	c2 04 5e    	subl2 $0x4,sp
   1054d:	9e ef dd 14 	movab 11a30 <n>,r0
   10551:	00 00 50 
   10554:	9e ef d9 14 	movab 11a33 <__bss_start>,r2
   10558:	00 00 52 
   1055b:	d4 53       	clrf r3
   1055d:	90 8f 62 51 	movb $0x62,r1

despite the warning, but it would be rather bad to have users annoyed 
with this message from BFD, however harmless, especially as it triggers 
outside LTO compilations as well.

Therefore this change is the best we can do until binutils have been 
fixed.

References:

[1] Jan Hubicka, "Getting LTO incremental linking work",
    <https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02986.html>

	gcc/
	* config/vax/elf.h (VAX_CC1_SPEC, VAX_CC1PLUS_SPEC): New macros.
	* config/vax/netbsd-elf.h (CC1_SPEC): Use VAX_CC1_SPEC rather 
	than VAX_CC1_AND_CC1PLUS_SPEC.
	(CC1PLUS_SPEC): Use VAX_CC1PLUS_SPEC rather than 
	VAX_CC1_AND_CC1PLUS_SPEC.
---
Hi,

 This is currently getting through verification, which I expect to end by 
Wed.  I would like to insert it into the original VAX series between 29/31 
and 30/31 so as to get rid of the sole regression mentioned with the cover 
letter there, and obviously to get LTO compilations fixed.

 I'll be posting a BFD fix separately right away and then we can switch to 
PIE by default in the next development cycle, when we have had at least 
one binutils release made with the fix applied.

 Meanwhile, OK to apply this interim fix, once verification has completed?

  Maciej
---
 gcc/config/vax/elf.h        |   10 ++++++++++
 gcc/config/vax/netbsd-elf.h |    4 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

Comments

Jeff Law Nov. 30, 2020, 8:43 p.m. UTC | #1
On 11/30/20 8:11 AM, Maciej W. Rozycki wrote:
> Fix a testsuite failure:
>
> /tmp/ccL65Mmt.s: Assembler messages:
> /tmp/ccL65Mmt.s:36: Warning: Symbol n used as immediate operand in PIC mode.
> FAIL: gcc.dg/lto/pr55660 c_lto_pr55660_0.o-c_lto_pr55660_1.o link, -O0 -flto -flto-partition=none -fuse-linker-plugin
>
> where non-PIC code is substituted by the LTO compiler at the link stage 
> for what used to be PIC code in the original compilation.  This happens 
> because in the de-facto VAX ELF psABI we rely on code being PIC for GOT 
> support in dynamic executables and arrange that by having `-fPIC' passed 
> to the compiler by default by means of a specs recipe.
>
> That is however canceled where the LTO wrapper is used, by an internal 
> arrangement in the LTO compiler that clears the PIC flag whenever the 
> `-flinker-output=exec' option has been used.  This has been deliberately 
> introduced with commit 1ff9ed6fb282 ("re PR lto/67548 (LTO drops weak 
> binding with "ld -r")")[1]:
>
> "In the log of PR67548 HJ actually pointed out that we do have API at 
> linker plugin side which says what type of output is done.  This is cool 
> because we can also use it to drop -fpic when building static binary. 
> This is common in Firefox, where some objects are built with -fpic and 
> linked to both binaries and libraries."
>
> with this code:
>
>     case LTO_LINKER_OUTPUT_EXEC: /* Normal executable */
>       flag_pic = 0;
>       flag_pie = 0;
>       flag_shlib = 0;
>       break;
>
> Consequently code like:
>
> .L6:
> 	addl3 -8(%fp),$n,%r0
> 	pushl %r0
> 	calls $1,foo
> 	addl2 %r0,-12(%fp)
> 	incl -8(%fp)
> .L5:
>
> is produced by the LTO compiler, where a reference to `n' is used that 
> is invalid in PIC code, because it uses the immediate addressing mode, 
> denoted by the `$' prefix.
>
> For that not to happen we must never pass `-flinker-output=exec' to the 
> LTO compiler unless non-PIC code has been explicitly requested.  Using 
> `-flinker-output=dyn' except for relocatable output would seem the 
> simplest approach, as it does not fiddle with any of the internal code 
> model settings beyond what the command-line options have arranged and 
> therefore lets them remain the same as with the original compilation, 
> but it breaks as well causing PR lto/69866 to retrigger, as that code 
> seems sensitive to `flag_shlib':
>
> lto1: internal compiler error: in add_symbol_to_partition_1, at lto/lto-partition.c:152
> 0x105be1cb add_symbol_to_partition_1
> 	.../gcc/lto/lto-partition.c:152
> 0x105be443 add_symbol_to_partition_1
> 	.../gcc/lto/lto-partition.c:194
> 0x105be80f add_symbol_to_partition
> 	.../gcc/lto/lto-partition.c:270
> 0x105bee6f add_sorted_nodes
> 	.../gcc/lto/lto-partition.c:395
> 0x105c0903 lto_balanced_map(int, int)
> 	.../gcc/lto/lto-partition.c:815
> 0x105aa91f do_whole_program_analysis
> 	.../gcc/lto/lto.c:499
> 0x105aac97 lto_main()
> 	.../gcc/lto/lto.c:637
> Please submit a full bug report,
> with preprocessed source if appropriate.
> Please include the complete backtrace with any bug report.
> See <https://gcc.gnu.org/bugs/> for instructions.
> lto-wrapper: fatal error: .../gcc/xgcc returned 1 exit status
> compilation terminated.
> .../usr/bin/vax-netbsdelf-ld: error: lto-wrapper failed
> collect2: error: ld returned 1 exit status
> compiler exited with status 1
> FAIL: gcc.dg/lto/pr69866 c_lto_pr69866_0.o-c_lto_pr69866_1.o link, -O0 -flto -fuse-linker-plugin -fno-fat-lto-objects  (internal compiler error)
>
> Substitute `-flinker-output=pie' for `-flinker-output=exec' in the specs 
> then unless `-no-pie' has also been used, preserving the original intent 
> of emitting PIC code by default for executables while keeping the linker 
> arrangement unchanged.  The LTO compiler uses the `cc1' spec, so keep 
> `cc1plus' unmodified.
>
> This makes code like:
>
> .L6:
> 	movab n,%r0
> 	addl2 -8(%fp),%r0
> 	pushl %r0
> 	calls $1,foo
> 	addl2 %r0,-12(%fp)
> 	incl -8(%fp)
> .L5:
>
> be produced instead corresponding to the fragment quoted above, which is 
> valid PIC code as it uses the PC-relative addressing mode denoted by the 
> absence of a prefix to `n' (which can be redirected to GOT as required, 
> by changing the addressing mode to PC-relative indirect in the operand 
> specifier).
>
> Ideally we would instead default to the PIE model for executables, but 
> that triggers a BFD bug where for a change the LTO wrapper is not used:
>
> .../usr/bin/vax-netbsdelf-ld: /tmp/ccV2sWQt.ltrans0.ltrans.o: warning: GOT addend of 3 to `n' does not match previous GOT addend of 0
> FAIL: gcc.dg/lto/pr55660 c_lto_pr55660_0.o-c_lto_pr55660_1.o link, -O2 -flto -flto-partition=1to1 -fno-use-linker-plugin
>
> which is due to assembly code like:
>
> main:
> 	.word 0
> 	subl2 $4,%sp
> 	movab n,%r0
> 	movab n+3,%r2
> 	clrl %r3
> 	movb $98,%r1
> .L4:
>
> and consequently object code like:
>
> 00000000 <main>:
>    0:	00 00       	.word 0x0000 # Entry mask: < >
>    2:	c2 04 5e    	subl2 $0x4,sp
>    5:	9e ef 00 00 	movab b <main+0xb>,r0
>    9:	00 00 50 
> 			7: R_VAX_GOT32	n
>    c:	9e ef 00 00 	movab 12 <main+0x12>,r2
>   10:	00 00 52 
> 			e: R_VAX_GOT32	n+0x3
>   13:	d4 53       	clrf r3
>   15:	90 8f 62 51 	movb $0x62,r1
>
> being produced.  This would be problematic for external `n', because we 
> do not support multiple GOT entries for the same symbol referred to with 
> different offsets in a single link unit.  In this case however the LTO 
> compiler correctly observes that `n' is defined by the executable and 
> not preemptible and therefore no GOT entry will be made for it.
>
> Indeed a valid executable is produced:
>
> 00010548 <main>:
>    10548:	00 00       	.word 0x0000 # Entry mask: < >
>    1054a:	c2 04 5e    	subl2 $0x4,sp
>    1054d:	9e ef dd 14 	movab 11a30 <n>,r0
>    10551:	00 00 50 
>    10554:	9e ef d9 14 	movab 11a33 <__bss_start>,r2
>    10558:	00 00 52 
>    1055b:	d4 53       	clrf r3
>    1055d:	90 8f 62 51 	movb $0x62,r1
>
> despite the warning, but it would be rather bad to have users annoyed 
> with this message from BFD, however harmless, especially as it triggers 
> outside LTO compilations as well.
>
> Therefore this change is the best we can do until binutils have been 
> fixed.
>
> References:
>
> [1] Jan Hubicka, "Getting LTO incremental linking work",
>     <https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02986.html>
>
> 	gcc/
> 	* config/vax/elf.h (VAX_CC1_SPEC, VAX_CC1PLUS_SPEC): New macros.
> 	* config/vax/netbsd-elf.h (CC1_SPEC): Use VAX_CC1_SPEC rather 
> 	than VAX_CC1_AND_CC1PLUS_SPEC.
> 	(CC1PLUS_SPEC): Use VAX_CC1PLUS_SPEC rather than 
> 	VAX_CC1_AND_CC1PLUS_SPEC.
OK
jeff
diff mbox series

Patch

Index: gcc/gcc/config/vax/elf.h
===================================================================
--- gcc.orig/gcc/config/vax/elf.h
+++ gcc/gcc/config/vax/elf.h
@@ -89,6 +89,16 @@  along with GCC; see the file COPYING3.
      %{!fpic: \
        %{!fPIC:-fPIC}}}"
 
+/* Don't let the LTO compiler switch the PIC options off.  */
+#define VAX_CC1_SPEC \
+  VAX_CC1_AND_CC1PLUS_SPEC \
+  " %{flinker-output=exec" \
+  ":%{no-pie:-flinker-output=exec;:-flinker-output=pie};" \
+  ":%{flinker-output=*}}" \
+  "%<flinker-output*"
+#define VAX_CC1PLUS_SPEC \
+  VAX_CC1_AND_CC1PLUS_SPEC
+
 /* VAX ELF is always gas; override the generic VAX ASM_SPEC.  */
 
 #undef ASM_SPEC
Index: gcc/gcc/config/vax/netbsd-elf.h
===================================================================
--- gcc.orig/gcc/config/vax/netbsd-elf.h
+++ gcc/gcc/config/vax/netbsd-elf.h
@@ -35,10 +35,10 @@  along with GCC; see the file COPYING3.
 #endif
 
 #undef CC1_SPEC
-#define CC1_SPEC NETBSD_CC1_AND_CC1PLUS_SPEC VAX_CC1_AND_CC1PLUS_SPEC
+#define CC1_SPEC NETBSD_CC1_AND_CC1PLUS_SPEC VAX_CC1_SPEC
 
 #undef CC1PLUS_SPEC
-#define CC1PLUS_SPEC NETBSD_CC1_AND_CC1PLUS_SPEC VAX_CC1_AND_CC1PLUS_SPEC
+#define CC1PLUS_SPEC NETBSD_CC1_AND_CC1PLUS_SPEC VAX_CC1PLUS_SPEC
 
 #define NETBSD_ENTRY_POINT "__start"