[PATCH] LD: Always make a SEGMENT_START expression section-relative

Maciej W. Rozycki macro@mips.com
Thu Jul 19 17:37:00 GMT 2018


Fix an issue with the SEGMENT_START builtin function where its result is 
absolute when taken from the default supplied, and section-relative when 
taken from a `-T' command-line override.  This is against documentation, 
inconsistent and unexpected, and with PIE executables gives an incorrect 
result with the `__executable_start' symbol.

Make the result of SEGMENT_START always section-relative then.

	ld/
	* ldexp.c (fold_binary): Always make the result of SEGMENT_START
	section-relative.
	* testsuite/ld-scripts/segment-start.d: New test.
	* testsuite/ld-scripts/segment-start.ld: New test linker script.
	* testsuite/ld-scripts/segment-start.s: New test source.
	* testsuite/ld-scripts/script.exp: Run the new test.
---
Hi Alan,

 I will appreciate if you review this quickly as my time is running out 
and this blocks PR ld/21375, because it makes MIPS programs that use the 
`__executable_start' symbol stop working with unfixed `ld.so'.

 Continuing the saga of absolute symbols...

 I got tempted to run final native MIPS testing (which is not something I 
do regularly) before committing the fix for PR ld/21375 and lo and behold, 
it did trigger a regression.  I got a bit concerned I did something wrong 
with my fix, but not.  Here's what the regression looked like:

Running: tmpdir/pr14525 > tmpdir/pr14525.out
tmpdir/pr14525: symbol lookup error: tmpdir/pr14525: undefined symbol: __executable_start
FAIL: PIE PR ld/14525

This looked remarkably familiar to me, and yes, this is another case of 
glibc BZ #23307.  Indeed looking at `tmpdir/pr14525' I discovered it has 
an absolute `__executable_start' symbol, any my PR ld/21375 fix has duly 
exported it so as to make a GOT entry that does not get relocated at load 
time:

$ readelf --dyn-syms -A tmpdir/pr14525 | grep __executable_start
    14: 00000000     0 NOTYPE  GLOBAL DEFAULT  ABS __executable_start
  00010a10 -32672(gp) 00000000 00000000 NOTYPE  ABS __executable_start
$ objdump -d tmpdir/pr14525 | grep -- -32672\(gp\)
 814:	8f828060 	lw	v0,-32672(gp)
$

And my native test environment has an `ld.so' binary that does not carry 
my recent BZ #23307 fix.

 Obviously `__executable_start' is a program address and is not supposed 
to be absolute, not the least because this is going to break with PIE 
executables.  The culprit turned out to be the SEGMENT_START function 
whose result is only section-relative if an override has been made at the 
command line (`-Ttext-segment=' in this case).  This is covered by the 
test case provided.

 No regressions across my usual targets, though the new test case does 
introduce a couple of new failures for a bunch of obscure targets:

arm-wince-pe  +FAIL: SEGMENT_START expression not absolute (overridden)
i686-pe  +FAIL: SEGMENT_START expression not absolute (overridden)
mcore-pe  +FAIL: SEGMENT_START expression not absolute (overridden)
mmix  +FAIL: SEGMENT_START expression not absolute (default)
mmix  +FAIL: SEGMENT_START expression not absolute (overridden)
ns32k-netbsd  +FAIL: SEGMENT_START expression not absolute (overridden)
pdp11-dec-aout  +FAIL: SEGMENT_START expression not absolute (default)
pdp11-dec-aout  +FAIL: SEGMENT_START expression not absolute (overridden)
powerpc-beos  +FAIL: SEGMENT_START expression not absolute (default)
powerpc-beos  +FAIL: SEGMENT_START expression not absolute (overridden)
powerpc-ibm-aix5.2.0  +FAIL: SEGMENT_START expression not absolute (default)
powerpc-ibm-aix5.2.0  +FAIL: SEGMENT_START expression not absolute (overridden)
rs6000-aix4.3.3  +FAIL: SEGMENT_START expression not absolute (default)
rs6000-aix4.3.3  +FAIL: SEGMENT_START expression not absolute (overridden)
rs6000-aix5.1  +FAIL: SEGMENT_START expression not absolute (default)
rs6000-aix5.1  +FAIL: SEGMENT_START expression not absolute (overridden)
sh-pe  +FAIL: SEGMENT_START expression not absolute (default)
sh-pe  +FAIL: SEGMENT_START expression not absolute (overridden)
tic30-unknown-aout  +FAIL: SEGMENT_START expression not absolute (default)
tic30-unknown-aout  +FAIL: SEGMENT_START expression not absolute (overridden)
tic30-unknown-coff  +FAIL: SEGMENT_START expression not absolute (overridden)
tic4x-coff  +FAIL: SEGMENT_START expression not absolute (overridden)
tic54x-coff  +FAIL: SEGMENT_START expression not absolute (default)
tic54x-coff  +FAIL: SEGMENT_START expression not absolute (overridden)
x86_64-mingw32  +FAIL: SEGMENT_START expression not absolute (overridden)
z8k-coff  +FAIL: SEGMENT_START expression not absolute (overridden)

Some of them do not enter `__executable_start' into the symbol table 
produced for some reason, and I don't know offhand if that is expected or 
not with these targets and/or binary formats.  Most crash in LD with a 
floating-point exception where `-Ttext-segment=0x10000000' has been used, 
with no limitation to a specific binary format, which suggests a generic 
problem somewhere, possibly the generic BFD linker, and clearly a bug.  

 I'd rather pushed this change for these problems to stick out and bring 
maintainers' attention and not papered them over with XFAILs right away.

 OK to apply then?

  Maciej
---
 ld/ldexp.c                               |    4 +++-
 ld/testsuite/ld-scripts/script.exp       |    4 ++++
 ld/testsuite/ld-scripts/segment-start.d  |   16 ++++++++++++++++
 ld/testsuite/ld-scripts/segment-start.ld |   12 ++++++++++++
 ld/testsuite/ld-scripts/segment-start.s  |    2 ++
 5 files changed, 37 insertions(+), 1 deletion(-)

binutils-ld-segment-start-default-rel.diff
Index: binutils/ld/ldexp.c
===================================================================
--- binutils.orig/ld/ldexp.c	2018-07-19 16:05:39.935270697 +0100
+++ binutils/ld/ldexp.c	2018-07-19 16:05:49.440283166 +0100
@@ -534,6 +534,7 @@ fold_binary (etree_type *tree)
      operand, binary.rhs is first operand.  */
   if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
     {
+      bfd_vma value = expld.result.value;
       const char *segment_name;
       segment_type *seg;
 
@@ -550,9 +551,10 @@ fold_binary (etree_type *tree)
 		       "isn't multiple of maximum page size\n"),
 		     segment_name);
 	    seg->used = TRUE;
-	    new_rel_from_abs (seg->value);
+	    value = seg->value;
 	    break;
 	  }
+      new_rel_from_abs (value);
       return;
     }
 
Index: binutils/ld/testsuite/ld-scripts/script.exp
===================================================================
--- binutils.orig/ld/testsuite/ld-scripts/script.exp	2018-07-19 16:05:40.881609839 +0100
+++ binutils/ld/testsuite/ld-scripts/script.exp	2018-07-19 16:05:52.128902848 +0100
@@ -231,3 +231,7 @@ foreach test_script $test_script_list {
 
 run_dump_test "align-with-input"
 run_dump_test "pr20302"
+
+run_dump_test "segment-start" {{name (default)}}
+run_dump_test "segment-start" {{name (overridden)} \
+			       {ld -Ttext-segment=0x10000000}}
Index: binutils/ld/testsuite/ld-scripts/segment-start.d
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-scripts/segment-start.d	2018-07-19 16:05:52.156325561 +0100
@@ -0,0 +1,16 @@
+#PROG: nm
+#name: SEGMENT_START expression not absolute
+#source: segment-start.s
+#ld: -e 0 -u __executable_start -T segment-start.ld
+
+# Make sure `__executable_start' is regular:
+#
+# 10000000 T __executable_start
+#
+# not absolute:
+#
+# 10000000 A __executable_start
+
+#...
+0*10000000 T __executable_start
+#pass
Index: binutils/ld/testsuite/ld-scripts/segment-start.ld
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-scripts/segment-start.ld	2018-07-19 16:05:52.174501255 +0100
@@ -0,0 +1,12 @@
+SECTIONS
+{
+  PROVIDE (__executable_start = SEGMENT_START ("text-segment", 0x10000000));
+  .text : { *(.text) }
+  .data : { *(.data) }
+  .bss : { *(.bss) }
+  .loader : { *(.loader) }
+  .symtab : { *(.symtab) }
+  .strtab : { *(.strtab) }
+  .shstrtab : { *(.shstrtab) }
+  /DISCARD/ : { *(*) }
+}
Index: binutils/ld/testsuite/ld-scripts/segment-start.s
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-scripts/segment-start.s	2018-07-19 16:05:52.194658276 +0100
@@ -0,0 +1,2 @@
+	.text
+	.space	16



More information about the Binutils mailing list