[RFC PATCH v2] ld: Optionally nullify default PIE in all linker tests

Jens Remus jremus@linux.ibm.com
Fri Mar 28 14:35:45 GMT 2025


Some distributions configure GCC with --enable-default-pie [1]. LLVM
defaults Clang to CLANG_DEFAULT_PIE_ON_LINUX=ON [2].  This causes
compiles to default to -fPIE and links to default to -pie, unless other
options are explicitly given.  As a consequence several linker tests
are compiled and linked in unexpected ways and may even unexpectedly
fail or pass.

Add the configuration variable "NULLIFY_DEFAULT_PIE" to the linker test
suite to optionally nullify default PIE, by prepending $NOPIE_CFLAGS to
the compile flags and $NOPIE_LDFLAGS to the link flags for all linker
tests.  These are then overridden by any deviating compiler flags
(e.g. -fPIC or -fPIE) and linker flags (e.g -pie or -shared) explicitly
specified by the tests.  Possible values of NULLIFY_DEFAULT_PIE are:

  0: Do not nullify default PIE. (default)
  1: Unconditionally prefix $NOPIE_CLFAGS and $NOPIE_LDFLAGS.
  auto: Prefix $NOPIE_CLFAGS and $NOPIE_LDFLAGS if compiler configured
    to default to PIE.

NULLIFY_DEFAULT_PIE can for instance be specified via RUNTESTFLAGS:

  $ make check RUNTESTFLAGS="NULLIFY_DEFAULT_PIE=1"

or in ~/.dejagnurc:

  # Prefix $NOPIE_CLFAGS and $NOPIE_LDFLAGS if compiler defaults to PIE.
  set nullify_default_pie "auto"

[1]: GCC Installation, step "Configuration", configuration option
     "--enable-default-pie", https://gcc.gnu.org/install/configure.html
[2]: LLVM D120305 "[Driver] Default CLANG_DEFAULT_PIE_ON_LINUX to ON",
     https://reviews.llvm.org/D120305

ld/
	PR ld/21090
	* NEWS: Mention new test suite configuration variable
	NULLIFY_DEFAULT_PIE.

ld/testsuite/
	PR ld/21090
	* lib/ld-lib.exp (check_default_pie): New test whether compiler
	configured to default to PIE.
	(check_nullify_default_pie): New test whether default PIE is to
	be nullified.
	(default_ld_compile): Prepend NOPIE_CFLAGS to nullify default
	-fPIE, if default PIE is to be nullified..
	(default_ld_link): Prepend NOPIE_LDFLAGS to nullify default
	-pie, if default PIE is to be nullified.

Bug: https://sourceware.org/PR21090
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---

Notes (jremus):
    Changes in V2:
    - Introduce linker test suite option NULLIFY_DEFAULT_PIE=0|1|auto to
      optionally nullify default PIE.  Can be set via RUNTESTFLAGS or
      ~/.dejagnurc.
    - Reword commit subject and message.  Add GNU ChangeLog.  Reference
      PR ld/21090.
    
    With my recent "ld: Pass $NOPIE_CFLAGS and $NOPIE_LDFLAGS to more tests"
    patch series I manually nullified GCC/Clang configured with default PIE
    in selected linker tests.  The tests addressed with that series is far
    from complete.
    
    With this patch I propose to introduce a new linker test suite option
    NULLIFY_DEFAULT_PIE=0|1|auto to optionally nullify GCC/Clang configured
    to default to PIE.
    
    Any feedback is very welcome!
    
    Thanks and regards,
    Jens

 ld/NEWS                     | 11 +++++++
 ld/testsuite/lib/ld-lib.exp | 58 +++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/ld/NEWS b/ld/NEWS
index 494bb83e49b3..b23fb02b13d7 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,16 @@
 -*- text -*-
 
+* Add test suite configuration variable NULLIFY_DEFAULT_PIE to optionally
+  nullify GCC / Clang configured to default to PIE (compiling with -fPIE
+  and linking with -pie).  The variable can have the following values:
+    0: Do not nullify default PIE. (default)
+    1: Unconditionally nullify default PIE.
+    auto: Nullify default PIE if compiler is configured to default to PIE.
+  The variable can be specified via RUNTESTFLAGS:
+    make check RUNTESTFLAGS="NULLIFY_DEFAULT_PIE=1"
+  or in ~/.dejagnurc:
+    set NULLIFY_DEFAULT_PIE "auto"
+
 * Remove the linker -taso option for Alpha target, as Linux/Alpha kernel
   support for 32-bit pointers has been removed.
 
diff --git a/ld/testsuite/lib/ld-lib.exp b/ld/testsuite/lib/ld-lib.exp
index 96152718d6f2..ba6f9768516b 100644
--- a/ld/testsuite/lib/ld-lib.exp
+++ b/ld/testsuite/lib/ld-lib.exp
@@ -220,11 +220,17 @@ proc get_board_flags {} {
 proc default_ld_link { ld target objects } {
     global host_triplet
     global exec_output
+    global check_nullify_default_pie
+    global NOPIE_LDFLAGS
 
     set flags ""
     if [is_endian_output_format $objects] then {
 	set flags [big_or_little_endian]
     }
+    # Nullify default -pie, e.g. if GCC configured with --enable-default-pie.
+    if [check_nullify_default_pie] then {
+	set flags "$flags $NOPIE_LDFLAGS"
+    }
 
     # When using GCC as the linker driver, we need to specify board cflags when
     # linking because cflags may contain linker options.  For example when
@@ -257,6 +263,8 @@ proc default_ld_compile { cc source object } {
     global subdir
     global host_triplet
     global gcc_B_opt
+    global check_nullify_default_pie
+    global NOPIE_CFLAGS
 
     set cc_prog $cc
     if {[llength $cc_prog] > 1} then {
@@ -271,6 +279,10 @@ proc default_ld_compile { cc source object } {
     remote_file host delete "$object"
 
     set flags "$gcc_B_opt -I$srcdir/$subdir"
+    # Nullify default -fPIE, e.g. if GCC configured with --enable-default-pie.
+    if [check_nullify_default_pie] then {
+	append flags " $NOPIE_CFLAGS"
+    }
 
     # If we are compiling with gcc, we want to add gcc_B_opt to flags.
     # However, if $prog already has -B options, which might be the
@@ -1709,3 +1721,49 @@ proc skip_sframe_tests { } {
 
     return 1
 }
+
+# Returns true if the target compiler is configured with default PIE
+proc check_default_pie { } {
+    global default_pie_saved
+    global CC_FOR_TARGET
+
+    if {![info exists default_pie_saved]} {
+	# Check if gcc is configured with --enable-default-pie
+	set flags [get_board_flags]
+	set basename "tmpdir/check_default_pie[pid]"
+	set src ${basename}.c
+	set output ${basename}.out
+	set f [open $src "w"]
+	puts $f "#ifdef __PIE__"
+	puts $f "int main() { return 0; }"
+	puts $f "#else /* ! __PIE__ */"
+	puts $f "#error \"compiler is not configured with --enable-default-pie\""
+	puts $f "#endif /* ! __PIE__ */"
+	close $f
+	if [is_remote host] {
+	    set src [remote_download host $src]
+	}
+	set default_pie_saved [run_host_noleak "$CC_FOR_TARGET" "$flags $src -o $output"]
+	remote_file host delete $src
+	remote_file host delete $output
+	file delete $src
+    }
+    return $default_pie_saved
+}
+
+# Returns true if default PIE should be nullified
+proc check_nullify_default_pie { } {
+    global nullify_default_pie_saved
+    global NULLIFY_DEFAULT_PIE
+
+    if {![info exists nullify_default_pie_saved]} {
+	if { [info exists NULLIFY_DEFAULT_PIE]
+	     && ($NULLIFY_DEFAULT_PIE == 1
+		 || $NULLIFY_DEFAULT_PIE == "auto" && [check_default_pie]) } {
+	    set nullify_default_pie_saved 1
+	} else {
+	    set nullify_default_pie_saved 0
+	}
+    }
+    return $nullify_default_pie_saved
+}
-- 
2.45.2



More information about the Binutils mailing list