[PATCH 0/6] ld: Add "-z textonly" option to ELF linker

classic Classic list List threaded Threaded
20 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
Text-only LOAD segment has the same requirement for segment alignment
and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
segment may not end at the same address of the end of data segment.  But
for text-only LOAD segment, it is exactly the same as text LOAD segment.

The new "-z textonly" option will turn on both text-only LOAD segment and
GNU_RELRO segment.  The new "-z notextonly" option will turn off only
text-only LOAD segment.  "-z relro" is updated not to turn off text-only
LOAD segment.  "-z norelro" is updated to turn off both GNU_RELRO segment
and text-only LOAD segment.

When there is a text-only LOAD segment, create a new LOAD segment if the
previous section contains text and the current section doesn't or vice
versa:

Elf file type is DYN (Shared object file)
Entry point 0x200ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
  LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
  LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
  LOAD           0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000
  DYNAMIC        0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

This is to prevent executing data in read-only sections as instructions.

Also don't put a writable section in a read-only segment if there is a
RELRO segment.

Since there are more than 2 LOAD segments, the minimum file size is
bigger than the maximum page size which is 2MB (0x200000):

-rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 libfoo.so

"-z max-page-size=0x1000" can be used to reduce the maximum page size to
4KB (0x1000):

-rwxr-xr-x 1 hjl hjl 11836 Nov 12 13:22 libfoo.so

Elf file type is DYN (Shared object file)
Entry point 0x1ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
  LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
  LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
  LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000
  DYNAMIC        0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

H.J. Lu (6):
  ld: Add "-z textonly" option to ELF linker
  ld: Add TEXT_SEGMENT_ALIGN/TEXT_SEGMENT_{RELRO_}END
  ld: Create a new LOAD segment for text-only LOAD segment
  ld/ppc/spu: Also set expld.textseg.phase to exp_seg_none
  ld: Add tests for -z textonly
  x86-64: Add tests for -z textonly -z max-page-size=0x1000

 bfd/elf.c                            |  32 +++++++---
 include/bfdlink.h                    |   9 ++-
 ld/NEWS                              |   2 +
 ld/emultempl/elf32.em                | 104 +++++++++++++++++++++++++++++----
 ld/emultempl/ppc32elf.em             |   1 +
 ld/emultempl/ppc64elf.em             |   1 +
 ld/emultempl/spuelf.em               |   1 +
 ld/genscripts.sh                     |  76 +++++++++++++++++++++---
 ld/ld.texinfo                        |  10 +++-
 ld/ldexp.c                           |  18 +++++-
 ld/ldexp.h                           |   3 +
 ld/ldgram.y                          |   7 +++
 ld/ldlang.c                          | 109 ++++++++++++++++++++++++++---------
 ld/ldlex.l                           |   3 +
 ld/lexsup.c                          |   8 ++-
 ld/scripttempl/elf.sc                |  21 +++++++
 ld/testsuite/ld-elf/pr22393-1.s      |  21 +++++++
 ld/testsuite/ld-elf/pr22393-1a.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-1b.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-1c.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-1d.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-1e.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-1f.d     |   9 +++
 ld/testsuite/ld-elf/pr22393-2a.c     |   7 +++
 ld/testsuite/ld-elf/pr22393-2a.rd    |   9 +++
 ld/testsuite/ld-elf/pr22393-2b.c     |   7 +++
 ld/testsuite/ld-elf/pr22393-2b.rd    |   9 +++
 ld/testsuite/ld-elf/shared.exp       |  71 +++++++++++++++++++++++
 ld/testsuite/ld-x86-64/pr22393-3a.c  |   7 +++
 ld/testsuite/ld-x86-64/pr22393-3a.rd |   9 +++
 ld/testsuite/ld-x86-64/pr22393-3b.c  |   7 +++
 ld/testsuite/ld-x86-64/pr22393-3b.rd |   9 +++
 ld/testsuite/ld-x86-64/x86-64.exp    |  71 +++++++++++++++++++++++
 33 files changed, 626 insertions(+), 60 deletions(-)
 create mode 100644 ld/testsuite/ld-elf/pr22393-1.s
 create mode 100644 ld/testsuite/ld-elf/pr22393-1a.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1b.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1c.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1d.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1e.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1f.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-2a.c
 create mode 100644 ld/testsuite/ld-elf/pr22393-2a.rd
 create mode 100644 ld/testsuite/ld-elf/pr22393-2b.c
 create mode 100644 ld/testsuite/ld-elf/pr22393-2b.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3a.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3b.rd

--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 1/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
Text-only LOAD segment has the same requirement for segment alignment
and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
segment may not end at the same address of the end of data segment.  But
for text-only LOAD segment, it is exactly the same as text LOAD segment.

The new "-z textonly" option will turn on both text-only LOAD segment and
GNU_RELRO segment.  The new "-z notextonly" option will turn off only
text-only LOAD segment.  "-z relro" is updated not to turn off text-only
LOAD segment.  "-z norelro" is updated to turn off both GNU_RELRO segment
and text-only LOAD segment.

include/

        PR ld/22393
        * bfdlink.h (bfd_link_info): Change the relro field to 2 bits.

ld/

        PR ld/22393
        * NEWS: Mention "-z textonly".
        * emultempl/elf32.em (gld${EMULATION_NAME}_get_script): Get
        builtin linker scripts and return linker scripts from disk for
        "-z textonly".
        (gld${EMULATION_NAME}_handle_option): Set the first bit of
        link_info.relro for "-z relro".  Clear link_info.relro for
        "-z norelro".  Set link_info.relro to 2 for "-z textonly".
        Keep only the first bit of link_info.relro for "notextonly".
        * genscripts.sh: Generate linker scripts for "-z textonly".
        (LD_FLAG): Set to *textonly for "-z textonly".
        * lexsup.c (elf_shlib_list_options): Update linker help messsages
        for "-z relro" and "-z norelro".  Add linker help messsages for
        "-z textonly" and "-z notextonly".
        * ld.texinfo: Update "-z norelro".  Document "-z textonly".
---
 include/bfdlink.h     |   6 ++-
 ld/NEWS               |   2 +
 ld/emultempl/elf32.em | 104 ++++++++++++++++++++++++++++++++++++++++++++------
 ld/genscripts.sh      |  76 ++++++++++++++++++++++++++++++++----
 ld/ld.texinfo         |  10 ++++-
 ld/lexsup.c           |   8 +++-
 6 files changed, 182 insertions(+), 24 deletions(-)

diff --git a/include/bfdlink.h b/include/bfdlink.h
index 2370c0d45a..d283429fdb 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -383,8 +383,10 @@ struct bfd_link_info
      executable.  */
   unsigned int emitrelocations: 1;
 
-  /* TRUE if PT_GNU_RELRO segment should be created.  */
-  unsigned int relro: 1;
+  /* Non-zero if PT_GNU_RELRO and text-only PT_LOAD segments should be
+     created.  1 for PT_GNU_RELRO segment only, > 1 for PT_GNU_RELRO
+     segment as well as text-only PT_LOAD segment.  */
+  unsigned int relro: 2;
 
   /* Nonzero if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment
      should be created.  1 for DWARF2 tables, 2 for compact tables.  */
diff --git a/ld/NEWS b/ld/NEWS
index 8f67fbe179..4da1cc07b3 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,4 +1,6 @@
 -*- text -*-
+* Add -z textonly to generate text-only PT_LOAD segment.
+
 * Add -z globalaudit command line option to force audit libraries to be run
   for every dynamic object loaded by an executable - provided that the loader
   supports this functionality.
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index edd8944f04..b633977438 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -2367,13 +2367,25 @@ if test -n "$GENERATE_PIE_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdwe >> e${EMULATION_NAME}.c
+echo '  ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc' >> e${EMULATION_NAME}.c
 echo '             && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdw >> e${EMULATION_NAME}.c
 echo '  ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1' >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xdce >> e${EMULATION_NAME}.c
+echo '  ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xdc >> e${EMULATION_NAME}.c
 fi
+echo '  ; else if (bfd_link_pie (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xde >> e${EMULATION_NAME}.c
 echo '  ; else if (bfd_link_pie (&link_info)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xd >> e${EMULATION_NAME}.c
 fi
@@ -2381,24 +2393,45 @@ if test -n "$GENERATE_SHLIB_SCRIPT" ; then
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xswe >> e${EMULATION_NAME}.c
+echo '  ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc' >> e${EMULATION_NAME}.c
 echo '             && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsw >> e${EMULATION_NAME}.c
 echo '  ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsce >> e${EMULATION_NAME}.c
+echo '  ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
 echo '             && link_info.combreloc) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c
 fi
+echo '  ; else if (bfd_link_dll (&link_info)' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xse >> e${EMULATION_NAME}.c
 echo '  ; else if (bfd_link_dll (&link_info)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c
 fi
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 echo '  ; else if (link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1' >> e${EMULATION_NAME}.c
+echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xwe >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.combreloc' >> e${EMULATION_NAME}.c
 echo '             && link_info.relro' >> e${EMULATION_NAME}.c
 echo '             && (link_info.flags & DF_BIND_NOW)) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xw >> e${EMULATION_NAME}.c
+echo '  ; else if (link_info.combreloc' >> e${EMULATION_NAME}.c
+echo '             && link_info.relro > 1) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xce >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c
 fi
+echo '  ; else if (link_info.relro > 1) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xe >> e${EMULATION_NAME}.c
 echo '  ; else return' >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c
 echo '; }' >> e${EMULATION_NAME}.c
@@ -2431,15 +2464,30 @@ fragment <<EOF
    && link_info.combreloc
    && link_info.relro
    && (link_info.flags & DF_BIND_NOW))
-    return "ldscripts/${EMULATION_NAME}.xdw";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xdwe";
+      else
+ return "ldscripts/${EMULATION_NAME}.xdw";
+    }
   else if (bfd_link_pie (&link_info)
    && link_info.combreloc)
-    return "ldscripts/${EMULATION_NAME}.xdc";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xdce";
+      else
+ return "ldscripts/${EMULATION_NAME}.xdc";
+    }
 EOF
 fi
 fragment <<EOF
   else if (bfd_link_pie (&link_info))
-    return "ldscripts/${EMULATION_NAME}.xd";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xde";
+      else
+ return "ldscripts/${EMULATION_NAME}.xd";
+    }
 EOF
 fi
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
@@ -2447,28 +2495,58 @@ if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 fragment <<EOF
   else if (bfd_link_dll (&link_info) && link_info.combreloc
    && link_info.relro && (link_info.flags & DF_BIND_NOW))
-    return "ldscripts/${EMULATION_NAME}.xsw";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xswe";
+      else
+ return "ldscripts/${EMULATION_NAME}.xsw";
+    }
   else if (bfd_link_dll (&link_info) && link_info.combreloc)
-    return "ldscripts/${EMULATION_NAME}.xsc";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xsce";
+      else
+ return "ldscripts/${EMULATION_NAME}.xsc";
+    }
 EOF
 fi
 fragment <<EOF
   else if (bfd_link_dll (&link_info))
-    return "ldscripts/${EMULATION_NAME}.xs";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xse";
+      else
+ return "ldscripts/${EMULATION_NAME}.xs";
+    }
 EOF
 fi
 if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then
 fragment <<EOF
   else if (link_info.combreloc && link_info.relro
    && (link_info.flags & DF_BIND_NOW))
-    return "ldscripts/${EMULATION_NAME}.xw";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xwe";
+      else
+ return "ldscripts/${EMULATION_NAME}.xw";
+    }
   else if (link_info.combreloc)
-    return "ldscripts/${EMULATION_NAME}.xc";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xce";
+      else
+ return "ldscripts/${EMULATION_NAME}.xc";
+    }
 EOF
 fi
 fragment <<EOF
   else
-    return "ldscripts/${EMULATION_NAME}.x";
+    {
+      if (link_info.relro > 1)
+ return "ldscripts/${EMULATION_NAME}.xe";
+      else
+ return "ldscripts/${EMULATION_NAME}.x";
+    }
 }
 
 EOF
@@ -2735,9 +2813,13 @@ fragment <<EOF
       else if (strcmp (optarg, "nocopyreloc") == 0)
  link_info.nocopyreloc = TRUE;
       else if (strcmp (optarg, "relro") == 0)
- link_info.relro = TRUE;
+ link_info.relro |= 1;
       else if (strcmp (optarg, "norelro") == 0)
- link_info.relro = FALSE;
+ link_info.relro = 0;
+      else if (strcmp (optarg, "textonly") == 0)
+ link_info.relro = 2;
+      else if (strcmp (optarg, "notextonly") == 0)
+ link_info.relro &= 1;
       else if (strcmp (optarg, "common") == 0)
  link_info.elf_stt_common = elf_stt_common;
       else if (strcmp (optarg, "nocommon") == 0)
diff --git a/ld/genscripts.sh b/ld/genscripts.sh
index 53cd5ad95c..9d4edc04d1 100755
--- a/ld/genscripts.sh
+++ b/ld/genscripts.sh
@@ -290,14 +290,20 @@ CONSTRUCTING=" "
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xu
 
-LD_FLAG=
 DATA_ALIGNMENT=${DATA_ALIGNMENT_}
 RELOCATING=" "
+LD_FLAG=
 ( echo "/* Default linker script, for normal executables */"
   . ${CUSTOMIZER_SCRIPT}
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
 ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.x
 
+LD_FLAG=textonly
+( echo "/* Script for -z textonly: generate normal executables with text-only segment */"
+  . ${CUSTOMIZER_SCRIPT}
+  . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xe
+
 LD_FLAG=n
 DATA_ALIGNMENT=${DATA_ALIGNMENT_n}
 ( echo "/* Script for -n: mix text and data on same page */"
@@ -321,44 +327,78 @@ if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xc
   rm -f ${COMBRELOC}
-  LD_FLAG=w
+  LD_FLAG=ctextonly
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xce.tmp
+  ( echo "/* Script for -z combreloc -z textonly: combine and sort reloc sections with text-only segment */"
+    . ${CUSTOMIZER_SCRIPT}
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xce
+  rm -f ${COMBRELOC}
   RELRO_NOW=" "
+  LD_FLAG=w
   COMBRELOC=ldscripts/${EMULATION_NAME}.xw.tmp
   ( echo "/* Script for -z combreloc -z now -z relro: combine and sort reloc sections */"
     . ${CUSTOMIZER_SCRIPT}
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xw
   rm -f ${COMBRELOC}
+  LD_FLAG=wtextonly
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xwe.tmp
+  ( echo "/* Script for -z combreloc -z now -z relro -z textonly: combine and sort reloc sections with text-only segment */"
+    . ${CUSTOMIZER_SCRIPT}
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xwe
+  rm -f ${COMBRELOC}
   COMBRELOC=
   unset RELRO_NOW
 fi
 
 if test -n "$GENERATE_SHLIB_SCRIPT"; then
-  LD_FLAG=shared
   DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
   CREATE_SHLIB=" "
+  LD_FLAG=shared
   (
     echo "/* Script for ld --shared: link shared library */"
     . ${CUSTOMIZER_SCRIPT}
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xs
+  LD_FLAG=sharedtextonly
+  (
+    echo "/* Script for ld --shared -z textonly: link shared library with text-only segment */"
+    . ${CUSTOMIZER_SCRIPT}
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xse
   if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
-    LD_FLAG=cshared
     DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
+    LD_FLAG=cshared
     COMBRELOC=ldscripts/${EMULATION_NAME}.xsc.tmp
     ( echo "/* Script for --shared -z combreloc: shared library, combine & sort relocs */"
       . ${CUSTOMIZER_SCRIPT}
       . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xsc
     rm -f ${COMBRELOC}
-    LD_FLAG=wshared
+    LD_FLAG=csharedtextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xsce.tmp
+    ( echo "/* Script for --shared -z combreloc -z textonly: shared library, combine & sort relocs with text-only segment */"
+      . ${CUSTOMIZER_SCRIPT}
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xsce
+    rm -f ${COMBRELOC}
     RELRO_NOW=" "
+    LD_FLAG=wshared
     COMBRELOC=ldscripts/${EMULATION_NAME}.xsw.tmp
     ( echo "/* Script for --shared -z combreloc -z now -z relro: shared library, combine & sort relocs */"
       . ${CUSTOMIZER_SCRIPT}
       . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xsw
     rm -f ${COMBRELOC}
+    LD_FLAG=wsharedtextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xswe.tmp
+    ( echo "/* Script for --shared -z combreloc -z now -z relro -z textonly: shared library, combine & sort relocs with text-only segment */"
+      . ${CUSTOMIZER_SCRIPT}
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xswe
+    rm -f ${COMBRELOC}
     COMBRELOC=
     unset RELRO_NOW
   fi
@@ -366,31 +406,51 @@ if test -n "$GENERATE_SHLIB_SCRIPT"; then
 fi
 
 if test -n "$GENERATE_PIE_SCRIPT"; then
-  LD_FLAG=pie
   DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}}
   CREATE_PIE=" "
+  LD_FLAG=pie
   (
     echo "/* Script for ld -pie: link position independent executable */"
     . ${CUSTOMIZER_SCRIPT}
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
   ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xd
+  LD_FLAG=pietextonly
+  (
+    echo "/* Script for ld -pie -z textonly: link position independent executable with text-only segment */"
+    . ${CUSTOMIZER_SCRIPT}
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xde
   if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
-    LD_FLAG=cpie
     DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdc.tmp
+    LD_FLAG=cpie
     ( echo "/* Script for -pie -z combreloc: position independent executable, combine & sort relocs */"
       . ${CUSTOMIZER_SCRIPT}
       . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdc
     rm -f ${COMBRELOC}
-    LD_FLAG=wpie
+    LD_FLAG=cpietextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xdce.tmp
+    ( echo "/* Script for -pie -z combreloc -z textonly: position independent executable, combine & sort relocs with text-only segment */"
+      . ${CUSTOMIZER_SCRIPT}
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdce
+    rm -f ${COMBRELOC}
     RELRO_NOW=" "
+    LD_FLAG=wpie
     COMBRELOC=ldscripts/${EMULATION_NAME}.xdw.tmp
     ( echo "/* Script for -pie -z combreloc -z now -z relro: position independent executable, combine & sort relocs */"
       . ${CUSTOMIZER_SCRIPT}
       . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
     ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdw
     rm -f ${COMBRELOC}
+    LD_FLAG=wpietextonly
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xdwe.tmp
+    ( echo "/* Script for -pie -z combreloc -z now -z relro -z textonly: position independent executable, combine & sort relocs with text-only segment */"
+      . ${CUSTOMIZER_SCRIPT}
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xdwe
+    rm -f ${COMBRELOC}
     COMBRELOC=
     unset RELRO_NOW
   fi
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 14788884cc..88f0f9b27f 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -1262,7 +1262,15 @@ Create an ELF @code{PT_GNU_RELRO} segment header in the object.  This
 specifies a memory segment that should be made read-only after
 relocation, if supported.  Specifying @samp{common-page-size} smaller
 than the system page size will render this protection ineffective.
-Don't create an ELF @code{PT_GNU_RELRO} segment if @samp{norelro}.
+Don't create an ELF @code{PT_GNU_RELRO} segment if @samp{norelro} is
+used, which also implies @option{-z notextonly}.
+
+@item textonly
+@itemx notextonly
+Create an ELF text-only @code{PT_LOAD} segment header in the object.
+This specifies a memory segment that should contain only instructions.
+This option also implies @option{-z relro}.  Don't create an ELF
+text-only @code{PT_LOAD} segment if @samp{notext} is used.
 
 @item shstk
 Generate GNU_PROPERTY_X86_FEATURE_1_SHSTK in .note.gnu.property section
diff --git a/ld/lexsup.c b/ld/lexsup.c
index cb9edaf7a6..dc025da5ed 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -1780,14 +1780,18 @@ elf_shlib_list_options (FILE *file)
   fprintf (file, _("\
   -z relro                    Create RELRO program header (default)\n"));
   fprintf (file, _("\
-  -z norelro                  Don't create RELRO program header\n"));
+  -z norelro                  Don't create RELRO nor read-only LOAD program header\n"));
 #else
   fprintf (file, _("\
   -z relro                    Create RELRO program header\n"));
   fprintf (file, _("\
-  -z norelro                  Don't create RELRO program header (default)\n"));
+  -z norelro                  Don't create RELRO nor read-only LOAD program header (default)\n"));
 #endif
   fprintf (file, _("\
+  -z readonly                 Create RELRO and read-only LOAD program header\n"));
+  fprintf (file, _("\
+  -z noreadonly               Don't create read-only LOAD program header (default)\n"));
+  fprintf (file, _("\
   -z common                   Generate common symbols with STT_COMMON type\n"));
   fprintf (file, _("\
   -z nocommon                 Generate common symbols with STT_OBJECT type\n"));
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 2/6] ld: Add TEXT_SEGMENT_ALIGN/TEXT_SEGMENT_{RELRO_}END

H.J. Lu-30
In reply to this post by H.J. Lu-30
Text-only LOAD segment has the same requirement for segment alignment
and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
segment may not end at the same address of the end of data segment.  But
text-only LOAD segment is exactly the same as text LOAD segment.

This patch adds TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END and
TEXT_SEGMENT_END, which mimic DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END
and DATA_SEGMENT_END.  They work on text segment, instead of data
segment.  TEXT_SEGMENT_ALIGN is placed at the start of text sections.
Both TEXT_SEGMENT_RELRO_END and TEXT_SEGMENT_END are placed at the end
of text sections.  TEXT_SEGMENT_ALIGN is created from DATA_SEGMENT_ALIGN
by replacing DATA_SEGMENT_ALIGN with TEXT_SEGMENT_ALIGN.  It simply sets
text_start and text_end from TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END
and TEXT_SEGMENT_END the same way as relro_start and relro_end are set
from DATA_SEGMENT_ALIGN, DATA_SEGMENT_RELRO_END and DATA_SEGMENT_END.

include/

        PR ld/22393
        * bfdlink.h (bfd_link_info): Add text_start and text_end.

ld/

        PR ld/22393
        * ldexp.c (exp_print_token): Add TEXT_SEGMENT_ALIGN,
        TEXT_SEGMENT_RELRO_END and TEXT_SEGMENT_END.
        (fold_unary): Handle TEXT_SEGMENT_END.
        (fold_binary): Handle TEXT_SEGMENT_RELRO_END and
        TEXT_SEGMENT_END.
        (exp_unop): Also check TEXT_SEGMENT_END.
        * ldexp.h (ldexp_control): Add textseg.
        * ldgram.y: Handle TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END
        and TEXT_SEGMENT_END.
        * ldlang.c (strip_excluded_output_sections): Also set
        expld.textseg.phase to exp_seg_none.
        (lang_size_sections_1): Also call ldlang_check_relro_region with
        &expld.textseg.
        (lang_size_relro_segment): Also handle expld.textseg.
        (lang_size_sections): Also handle expld.textseg.  Set
        link_info.text_start and link_info.text_end for -z textonly.
        (lang_find_relro_sections): Also check expld.textseg.
        * ldlex.l: Add TEXT_SEGMENT_ALIGN, TEXT_SEGMENT_RELRO_END and
        TEXT_SEGMENT_END.
        * scripttempl/elf.sc (TEXT_SEGMENT_ALIGN): New.
        (TEXT_SEGMENT_RELRO_END): Likewise.
        (TEXT_SEGMENT_END): Likewise.
        Add ${TEXT_SEGMENT_ALIGN} before text sections and add
        ${TEXT_SEGMENT_RELRO_END}/${TEXT_SEGMENT_END} after text
        sections for non-relocatable link.
---
 include/bfdlink.h     |   3 ++
 ld/ldexp.c            |  18 ++++++++-
 ld/ldexp.h            |   3 ++
 ld/ldgram.y           |   7 ++++
 ld/ldlang.c           | 109 +++++++++++++++++++++++++++++++++++++-------------
 ld/ldlex.l            |   3 ++
 ld/scripttempl/elf.sc |  21 ++++++++++
 7 files changed, 135 insertions(+), 29 deletions(-)

diff --git a/include/bfdlink.h b/include/bfdlink.h
index d283429fdb..2fdfb2ab71 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -626,6 +626,9 @@ struct bfd_link_info
   /* May be used to set DT_FLAGS_1 for ELF. */
   bfd_vma flags_1;
 
+  /* Start and end of text-only region.  */
+  bfd_vma text_start, text_end;
+
   /* Start and end of RELRO region.  */
   bfd_vma relro_start, relro_end;
 
diff --git a/ld/ldexp.c b/ld/ldexp.c
index 83d9f8f2a7..71051ceb19 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -134,6 +134,9 @@ exp_print_token (token_code_type code, int infix_p)
     { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
     { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
     { DATA_SEGMENT_END, "DATA_SEGMENT_END" },
+    { TEXT_SEGMENT_ALIGN, "TEXT_SEGMENT_ALIGN" },
+    { TEXT_SEGMENT_RELRO_END, "TEXT_SEGMENT_RELRO_END" },
+    { TEXT_SEGMENT_END, "TEXT_SEGMENT_END" },
     { ORIGIN, "ORIGIN" },
     { LENGTH, "LENGTH" },
     { SEGMENT_START, "SEGMENT_START" }
@@ -416,6 +419,10 @@ fold_unary (etree_type *tree)
   fold_segment_end (&expld.dataseg);
   break;
 
+ case TEXT_SEGMENT_END:
+  fold_segment_end (&expld.textseg);
+  break;
+
  default:
   FAIL ();
   break;
@@ -664,6 +671,14 @@ fold_binary (etree_type *tree)
   fold_segment_relro_end (&expld.dataseg, &lhs);
   break;
 
+ case TEXT_SEGMENT_ALIGN:
+  fold_segment_align (&expld.textseg, &lhs);
+  break;
+
+ case TEXT_SEGMENT_RELRO_END:
+  fold_segment_relro_end (&expld.textseg, &lhs);
+  break;
+
  default:
   FAIL ();
  }
@@ -1342,7 +1357,8 @@ exp_unop (int code, etree_type *child)
       && code != ALIGN_K
       && code != ABSOLUTE
       && code != NEXT
-      && code != DATA_SEGMENT_END)
+      && code != DATA_SEGMENT_END
+      && code != TEXT_SEGMENT_END)
     exp_value_fold (new_e);
   return new_e;
 }
diff --git a/ld/ldexp.h b/ld/ldexp.h
index 5ff0fa0a1f..d1429353e1 100644
--- a/ld/ldexp.h
+++ b/ld/ldexp.h
@@ -173,6 +173,9 @@ struct ldexp_control {
 
   /* State machine and results for DATASEG.  */
   seg_align_type dataseg;
+
+  /* State machine and results for TEXTSEG.  */
+  seg_align_type textseg;
 };
 
 extern struct ldexp_control expld;
diff --git a/ld/ldgram.y b/ld/ldgram.y
index d701e076a2..53da2d062a 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -127,6 +127,7 @@ static int error_index;
 %token <token> ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE
 %token SECTIONS PHDRS INSERT_K AFTER BEFORE
 %token DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END DATA_SEGMENT_END
+%token TEXT_SEGMENT_ALIGN TEXT_SEGMENT_RELRO_END TEXT_SEGMENT_END
 %token SORT_BY_NAME SORT_BY_ALIGNMENT SORT_NONE
 %token SORT_BY_INIT_PRIORITY
 %token '{' '}'
@@ -993,6 +994,12 @@ exp :
  { $$ = exp_binop (DATA_SEGMENT_RELRO_END, $5, $3); }
  | DATA_SEGMENT_END '(' exp ')'
  { $$ = exp_unop (DATA_SEGMENT_END, $3); }
+ | TEXT_SEGMENT_ALIGN '(' exp ',' exp ')'
+ { $$ = exp_binop (TEXT_SEGMENT_ALIGN, $3, $5); }
+ | TEXT_SEGMENT_RELRO_END '(' exp ',' exp ')'
+ { $$ = exp_binop (TEXT_SEGMENT_RELRO_END, $5, $3); }
+ | TEXT_SEGMENT_END '(' exp ')'
+ { $$ = exp_unop (TEXT_SEGMENT_END, $3); }
  | SEGMENT_START '(' NAME ',' exp ')'
  { /* The operands to the expression node are
      placed in the opposite order from the way
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 674004ee38..ea45bc5639 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -3891,6 +3891,7 @@ strip_excluded_output_sections (void)
     {
       expld.phase = lang_mark_phase_enum;
       expld.dataseg.phase = exp_seg_none;
+      expld.textseg.phase = exp_seg_none;
       one_lang_size_sections_pass (NULL, FALSE);
       lang_reset_memory_regions ();
     }
@@ -5450,14 +5451,17 @@ lang_size_sections_1
     bfd_vma newdot = dot;
     etree_type *tree = s->assignment_statement.exp;
 
+    expld.textseg.relro = exp_seg_relro_none;
     expld.dataseg.relro = exp_seg_relro_none;
 
     exp_fold_tree (tree,
    output_section_statement->bfd_section,
    &newdot);
 
+    ldlang_check_relro_region (s, &expld.textseg);
     ldlang_check_relro_region (s, &expld.dataseg);
 
+    expld.textseg.relro = exp_seg_relro_none;
     expld.dataseg.relro = exp_seg_relro_none;
 
     /* This symbol may be relative to this section.  */
@@ -5664,35 +5668,56 @@ static bfd_boolean
 lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions)
 {
   bfd_boolean do_reset = FALSE;
-  bfd_boolean do_data_relro;
-  bfd_vma data_initial_base, data_relro_end;
+  bfd_boolean do_text_relro = FALSE;
+  bfd_boolean do_data_relro = FALSE;
 
-  if (link_info.relro && expld.dataseg.relro_end)
+  if (link_info.relro)
     {
-      do_data_relro = TRUE;
-      data_initial_base = expld.dataseg.base;
-      data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
-    }
-  else
-    {
-      do_data_relro = FALSE;
-      data_initial_base = data_relro_end = 0;
-    }
+      bfd_vma text_initial_base, text_relro_end;
+      bfd_vma data_initial_base, data_relro_end;
 
-  if (do_data_relro)
-    {
-      lang_reset_memory_regions ();
-      one_lang_size_sections_pass (relax, check_regions);
+      if (link_info.relro > 1 && expld.textseg.relro_end)
+ {
+  do_text_relro = TRUE;
+  text_initial_base = expld.textseg.base;
+  text_relro_end = lang_size_relro_segment_1 (&expld.textseg);
+ }
+      else
+ text_initial_base = text_relro_end = 0;
 
-      /* Assignments to dot, or to output section address in a user
- script have increased padding over the original.  Revert.  */
-      if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+      if (expld.dataseg.relro_end)
  {
-  expld.dataseg.base = data_initial_base;;
-  do_reset = TRUE;
+  do_data_relro = TRUE;
+  data_initial_base = expld.dataseg.base;
+  data_relro_end = lang_size_relro_segment_1 (&expld.dataseg);
+ }
+      else
+ data_initial_base = data_relro_end = 0;
+
+      if (do_text_relro || do_data_relro)
+ {
+  lang_reset_memory_regions ();
+  one_lang_size_sections_pass (relax, check_regions);
+
+  /* Assignments to dot, or to output section address in a user
+     script have increased padding over the original.  Revert.  */
+  if (do_text_relro && expld.textseg.relro_end > text_relro_end)
+    {
+      expld.textseg.base = text_initial_base;
+      do_reset = TRUE;
+    }
+
+  if (do_data_relro && expld.dataseg.relro_end > data_relro_end)
+    {
+      expld.dataseg.base = data_initial_base;;
+      do_reset = TRUE;
+    }
  }
     }
 
+  if (!do_text_relro && lang_size_segment (&expld.textseg))
+    do_reset = TRUE;
+
   if (!do_data_relro && lang_size_segment (&expld.dataseg))
     do_reset = TRUE;
 
@@ -5704,13 +5729,17 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
 {
   expld.phase = lang_allocating_phase_enum;
   expld.dataseg.phase = exp_seg_none;
+  expld.textseg.phase = exp_seg_none;
 
   one_lang_size_sections_pass (relax, check_regions);
 
+  if (expld.textseg.phase != exp_seg_end_seen)
+    expld.textseg.phase = exp_seg_done;
   if (expld.dataseg.phase != exp_seg_end_seen)
     expld.dataseg.phase = exp_seg_done;
 
-  if (expld.dataseg.phase == exp_seg_end_seen)
+  if (expld.textseg.phase == exp_seg_end_seen
+      || expld.dataseg.phase == exp_seg_end_seen)
     {
       bfd_boolean do_reset
  = lang_size_relro_segment (relax, check_regions);
@@ -5721,6 +5750,12 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions)
   one_lang_size_sections_pass (relax, check_regions);
  }
 
+      if (link_info.relro > 1 && expld.textseg.relro_end)
+ {
+  link_info.text_start = expld.textseg.base;
+  link_info.text_end = expld.textseg.relro_end;
+ }
+
       if (link_info.relro && expld.dataseg.relro_end)
  {
   link_info.relro_start = expld.dataseg.base;
@@ -6906,15 +6941,33 @@ lang_find_relro_sections_1 (lang_statement_union_type *s,
 static void
 lang_find_relro_sections (void)
 {
-  bfd_boolean has_relro_section = FALSE;
-
   /* Check all sections in the link script.  */
+  if (link_info.relro)
+    {
+      bfd_boolean has_relro_section;
 
-  lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
-      &expld.dataseg, &has_relro_section);
+      if (link_info.relro > 1)
+ {
+  has_relro_section = FALSE;
+  lang_find_relro_sections_1 (expld.textseg.relro_start_stat,
+      &expld.textseg,
+      &has_relro_section);
+  if (!has_relro_section)
+    link_info.relro = 1;
+ }
 
-  if (!has_relro_section)
-    link_info.relro = FALSE;
+      /* We can't turn off RELRO if we need to generate read-only
+ PT_LOAD segment.  */
+      if (link_info.relro == 1)
+ {
+  has_relro_section = FALSE;
+  lang_find_relro_sections_1 (expld.dataseg.relro_start_stat,
+      &expld.dataseg,
+      &has_relro_section);
+  if (!has_relro_section)
+    link_info.relro = 0;
+ }
+    }
 }
 
 /* Relax all sections until bfd_relax_section gives up.  */
diff --git a/ld/ldlex.l b/ld/ldlex.l
index 207c97f323..538c372a0f 100644
--- a/ld/ldlex.l
+++ b/ld/ldlex.l
@@ -250,6 +250,9 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_ALIGN" { RTOKEN(DATA_SEGMENT_ALIGN);}
 <EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_RELRO_END" { RTOKEN(DATA_SEGMENT_RELRO_END);}
 <EXPRESSION,BOTH,SCRIPT>"DATA_SEGMENT_END" { RTOKEN(DATA_SEGMENT_END);}
+<EXPRESSION,BOTH,SCRIPT>"TEXT_SEGMENT_ALIGN" { RTOKEN(TEXT_SEGMENT_ALIGN);}
+<EXPRESSION,BOTH,SCRIPT>"TEXT_SEGMENT_RELRO_END" { RTOKEN(TEXT_SEGMENT_RELRO_END);}
+<EXPRESSION,BOTH,SCRIPT>"TEXT_SEGMENT_END" { RTOKEN(TEXT_SEGMENT_END);}
 <EXPRESSION,BOTH,SCRIPT>"ADDR" { RTOKEN(ADDR);}
 <EXPRESSION,BOTH,SCRIPT>"LOADADDR" { RTOKEN(LOADADDR);}
 <EXPRESSION,BOTH,SCRIPT>"ALIGNOF" { RTOKEN(ALIGNOF); }
diff --git a/ld/scripttempl/elf.sc b/ld/scripttempl/elf.sc
index 9f291b359f..9eb024e809 100644
--- a/ld/scripttempl/elf.sc
+++ b/ld/scripttempl/elf.sc
@@ -139,6 +139,23 @@ if test -z "$DATA_SEGMENT_ALIGN"; then
     DATA_SEGMENT_RELRO_END=". = DATA_SEGMENT_RELRO_END (${SEPARATE_GOTPLT-0}, .);"
   fi
 fi
+# Don't bother with text-only segment when there are data sections between
+# .plt and .text.
+if test -n "$TINY_READONLY_SECTION"; then
+  TEXT_SEGMENT_ALIGN=" "
+  TEXT_SEGMENT_RELRO_END=" "
+  TEXT_SEGMENT_END=" "
+fi
+if test -z "$TEXT_SEGMENT_ALIGN" && test -n "$DATA_SEGMENT_ALIGN"; then
+  case "$LD_FLAG" in
+    *textonly*)
+      TEXT_SEGMENT_ALIGN=`echo $DATA_SEGMENT_ALIGN | sed -e "s/DATA/TEXT/g"`
+      TEXT_SEGMENT_ALIGN=". = $TEXT_SEGMENT_ALIGN;"
+      TEXT_SEGMENT_RELRO_END=". = TEXT_SEGMENT_RELRO_END (0, .);"
+      TEXT_SEGMENT_END=". = TEXT_SEGMENT_END (.);"
+      ;;
+  esac
+fi
 if test -z "${INITIAL_READONLY_SECTIONS}${CREATE_SHLIB}"; then
   INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }"
 fi
@@ -478,6 +495,8 @@ emit_dyn()
 test -n "${NON_ALLOC_DYN}${SEPARATE_CODE}" || emit_dyn
 
 cat <<EOF
+  ${RELOCATING+${TEXT_SEGMENT_ALIGN}}
+
   .init         ${RELOCATING-0}${RELOCATING+${INIT_ADDR}} :
   {
     ${RELOCATING+${INIT_START}}
@@ -508,6 +527,8 @@ cat <<EOF
   ${RELOCATING+PROVIDE (__${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (_${ETEXT_NAME} = .);}
   ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);}
+  ${RELOCATING+${TEXT_SEGMENT_RELRO_END}}
+  ${RELOCATING+${TEXT_SEGMENT_END}}
 EOF
 
 if test -n "${SEPARATE_CODE}"; then
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 3/6] ld: Create a new LOAD segment for text-only LOAD segment

H.J. Lu-30
In reply to this post by H.J. Lu-30
When there is a text-only LOAD segment, create a new LOAD segment if the
previous section contains text and the current section doesn't or vice
versa:

Elf file type is DYN (Shared object file)
Entry point 0x200ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
  LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
  LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
  LOAD           0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000
  DYNAMIC        0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x200f80 0x00400f80 0x00400f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

This is to prevent executing data in read-only sections as instructions.

Also don't put a writable section in a read-only segment if there is a
RELRO segment.

Since there are more than 2 LOAD segments, the minimum file size is
bigger than the maximum page size which is 2MB (0x200000):

-rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 libfoo.so

"-z max-page-size=0x1000" can be used to reduce the maximum page size to
4KB (0x1000):

-rwxr-xr-x 1 hjl hjl 11836 Nov 12 13:22 libfoo.so

Elf file type is DYN (Shared object file)
Entry point 0x1ff0
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
  LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
  LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
  LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000
  DYNAMIC        0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

        PR ld/22393
        * elf.c (_bfd_elf_map_sections_to_segments): When there is a
        text-only LOAD segment, create a new LOAD segment if the
        previous section contains text and the current section doesn't
        or vice versa.  Don't put a writable section in a read-only
        segment if there is a RELRO segment.
---
 bfd/elf.c | 32 +++++++++++++++++++++++++-------
 1 file changed, 25 insertions(+), 7 deletions(-)

diff --git a/bfd/elf.c b/bfd/elf.c
index 694e43540f..9c5de9675c 100644
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -4555,6 +4555,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       asection **hdrpp;
       bfd_boolean phdr_in_segment = TRUE;
       bfd_boolean writable;
+      bfd_boolean executable;
       int tls_count = 0;
       asection *first_tls = NULL;
       asection *first_mbind = NULL;
@@ -4643,6 +4644,7 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
       if (maxpagesize == 0)
  maxpagesize = 1;
       writable = FALSE;
+      executable = FALSE;
       dynsec = bfd_get_section_by_name (abfd, ".dynamic");
       if (dynsec != NULL
   && (dynsec->flags & SEC_LOAD) == 0)
@@ -4745,18 +4747,27 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
  file, then there is no other reason for a new segment.  */
       new_segment = FALSE;
     }
+  else if (info != NULL
+   && info->text_end > info->text_start
+   && executable != ((hdr->flags & SEC_CODE) != 0))
+    {
+      new_segment = TRUE;
+    }
   else if (! writable
    && (hdr->flags & SEC_READONLY) == 0
-   && (((last_hdr->lma + last_size - 1) & -maxpagesize)
-       != (hdr->lma & -maxpagesize)))
+   && ((info != NULL
+ && info->relro_end > info->relro_start)
+       || (((last_hdr->lma + last_size - 1) & -maxpagesize)
+   != (hdr->lma & -maxpagesize))))
     {
       /* We don't want to put a writable section in a read only
  segment, unless they are on the same page in memory
- anyhow.  We already know that the last section does not
- bring us past the current section on the page, so the
- only case in which the new section is not on the same
- page as the previous section is when the previous section
- ends precisely on a page boundary.  */
+ anyhow and there is no RELRO segment.  We already
+ know that the last section does not bring us past the
+ current section on the page, so the only case in which
+ the new section is not on the same page as the previous
+ section is when the previous section ends precisely on
+ a page boundary.  */
       new_segment = TRUE;
     }
   else
@@ -4778,6 +4789,8 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
     {
       if ((hdr->flags & SEC_READONLY) == 0)
  writable = TRUE;
+      if ((hdr->flags & SEC_CODE) != 0)
+ executable = TRUE;
       last_hdr = hdr;
       /* .tbss sections effectively have zero size.  */
       if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
@@ -4803,6 +4816,11 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info)
   else
     writable = FALSE;
 
+  if ((hdr->flags & SEC_CODE) == 0)
+    executable = FALSE;
+  else
+    executable = TRUE;
+
   last_hdr = hdr;
   /* .tbss sections effectively have zero size.  */
   if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL)
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 4/6] ld/ppc/spu: Also set expld.textseg.phase to exp_seg_none

H.J. Lu-30
In reply to this post by H.J. Lu-30
        * emultempl/ppc32elf.em (ppc_before_allocation): Also set
        expld.textseg.phase to exp_seg_none.
        * emultempl/ppc64elf.em (prelim_size_sections): Likewise.
        * emultempl/spuelf.em (spu_before_allocation): Likewise.
---
 ld/emultempl/ppc32elf.em | 1 +
 ld/emultempl/ppc64elf.em | 1 +
 ld/emultempl/spuelf.em   | 1 +
 3 files changed, 3 insertions(+)

diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index f78a117222..5817fc99c0 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -149,6 +149,7 @@ ppc_before_allocation (void)
       if (expld.phase != lang_mark_phase_enum)
  {
   expld.phase = lang_mark_phase_enum;
+  expld.textseg.phase = exp_seg_none;
   expld.dataseg.phase = exp_seg_none;
   one_lang_size_sections_pass (NULL, FALSE);
   lang_reset_memory_regions ();
diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em
index d6d5b0acf3..131bae7b54 100644
--- a/ld/emultempl/ppc64elf.em
+++ b/ld/emultempl/ppc64elf.em
@@ -266,6 +266,7 @@ prelim_size_sections (void)
   if (expld.phase != lang_mark_phase_enum)
     {
       expld.phase = lang_mark_phase_enum;
+      expld.textseg.phase = exp_seg_none;
       expld.dataseg.phase = exp_seg_none;
       one_lang_size_sections_pass (NULL, FALSE);
       /* We must not cache anything from the preliminary sizing.  */
diff --git a/ld/emultempl/spuelf.em b/ld/emultempl/spuelf.em
index 8d8aa25d0a..3878086c0d 100644
--- a/ld/emultempl/spuelf.em
+++ b/ld/emultempl/spuelf.em
@@ -272,6 +272,7 @@ spu_before_allocation (void)
       /* Size the sections.  This is premature, but we need to know the
  rough layout so that overlays can be found.  */
       expld.phase = lang_mark_phase_enum;
+      expld.textseg.phase = exp_seg_none;
       expld.dataseg.phase = exp_seg_none;
       one_lang_size_sections_pass (NULL, TRUE);
 
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 5/6] ld: Add tests for -z textonly

H.J. Lu-30
In reply to this post by H.J. Lu-30
        PR ld/22393
        * testsuite/ld-elf/pr22393-1.s: New file.
        * testsuite/ld-elf/pr22393-1a.d: Likewise.
        * testsuite/ld-elf/pr22393-1b.d: Likewise.
        * testsuite/ld-elf/pr22393-1c.d: Likewise.
        * testsuite/ld-elf/pr22393-1d.d: Likewise.
        * testsuite/ld-elf/pr22393-1e.d: Likewise.
        * testsuite/ld-elf/pr22393-1f.d: Likewise.
        * testsuite/ld-elf/pr22393-2a.c: Likewise.
        * testsuite/ld-elf/pr22393-2a.rd: Likewise.
        * testsuite/ld-elf/pr22393-2b.c: Likewise.
        * testsuite/ld-elf/pr22393-2b.rd: Likewise.
        * testsuite/ld-elf/shared.exp: Run tests for -z textonly.
---
 ld/testsuite/ld-elf/pr22393-1.s   | 21 ++++++++++++
 ld/testsuite/ld-elf/pr22393-1a.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-1b.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-1c.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-1d.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-1e.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-1f.d  |  9 +++++
 ld/testsuite/ld-elf/pr22393-2a.c  |  7 ++++
 ld/testsuite/ld-elf/pr22393-2a.rd |  9 +++++
 ld/testsuite/ld-elf/pr22393-2b.c  |  7 ++++
 ld/testsuite/ld-elf/pr22393-2b.rd |  9 +++++
 ld/testsuite/ld-elf/shared.exp    | 71 +++++++++++++++++++++++++++++++++++++++
 12 files changed, 178 insertions(+)
 create mode 100644 ld/testsuite/ld-elf/pr22393-1.s
 create mode 100644 ld/testsuite/ld-elf/pr22393-1a.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1b.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1c.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1d.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1e.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-1f.d
 create mode 100644 ld/testsuite/ld-elf/pr22393-2a.c
 create mode 100644 ld/testsuite/ld-elf/pr22393-2a.rd
 create mode 100644 ld/testsuite/ld-elf/pr22393-2b.c
 create mode 100644 ld/testsuite/ld-elf/pr22393-2b.rd

diff --git a/ld/testsuite/ld-elf/pr22393-1.s b/ld/testsuite/ld-elf/pr22393-1.s
new file mode 100644
index 0000000000..ffdb620915
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1.s
@@ -0,0 +1,21 @@
+ .section .rodata,"a",%progbits
+ .globl fx1
+ .type fx1, %object
+fx1:
+ .zero 20
+ .section .data.rel.ro,"aw",%progbits
+ .globl px1
+ .type px1, %object
+px1:
+ .dc.a fx1
+
+ .text
+ .global start /* Used by SH targets.  */
+start:
+ .global _start
+_start:
+ .global __start
+__start:
+ .global main /* Used by HPPA targets.  */
+main:
+ .dc.a 0
diff --git a/ld/testsuite/ld-elf/pr22393-1a.d b/ld/testsuite/ld-elf/pr22393-1a.d
new file mode 100644
index 0000000000..b7ba110095
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1a.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-1b.d b/ld/testsuite/ld-elf/pr22393-1b.d
new file mode 100644
index 0000000000..6066e1584f
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1b.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*.text.*(.eh_frame|\.rodata).*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-1c.d b/ld/testsuite/ld-elf/pr22393-1c.d
new file mode 100644
index 0000000000..e69281e4bb
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1c.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -pie -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-1d.d b/ld/testsuite/ld-elf/pr22393-1d.d
new file mode 100644
index 0000000000..83e8c3e4b6
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1d.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -pie -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*.text.*(.eh_frame|\.rodata).*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-1e.d b/ld/testsuite/ld-elf/pr22393-1e.d
new file mode 100644
index 0000000000..df723921c2
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1e.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-1f.d b/ld/testsuite/ld-elf/pr22393-1f.d
new file mode 100644
index 0000000000..3c80e70da1
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-1f.d
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*.text.*(.eh_frame|\.rodata).*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-2a.c b/ld/testsuite/ld-elf/pr22393-2a.c
new file mode 100644
index 0000000000..68fa4a0dd0
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-2a.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+test()
+{
+  printf ("PASS\n");
+}
diff --git a/ld/testsuite/ld-elf/pr22393-2a.rd b/ld/testsuite/ld-elf/pr22393-2a.rd
new file mode 100644
index 0000000000..b7ba110095
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-2a.rd
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-elf/pr22393-2b.c b/ld/testsuite/ld-elf/pr22393-2b.c
new file mode 100644
index 0000000000..3033809b02
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-2b.c
@@ -0,0 +1,7 @@
+void test(void);
+
+int main()
+{
+  test();
+  return 0;
+}
diff --git a/ld/testsuite/ld-elf/pr22393-2b.rd b/ld/testsuite/ld-elf/pr22393-2b.rd
new file mode 100644
index 0000000000..b7ba110095
--- /dev/null
+++ b/ld/testsuite/ld-elf/pr22393-2b.rd
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-elf/shared.exp b/ld/testsuite/ld-elf/shared.exp
index a40f8e0f59..b382a2591b 100644
--- a/ld/testsuite/ld-elf/shared.exp
+++ b/ld/testsuite/ld-elf/shared.exp
@@ -756,6 +756,51 @@ if { [istarget *-*-linux*]
     {} \
     "libpr19579.so" \
  ] \
+ [list \
+    "Build pr22393-2a.so" \
+    "-shared -Wl,-z,textonly" \
+    "-fPIC" \
+    {pr22393-2a.c} \
+    {{readelf -lW pr22393-2a.rd} \
+     {readelf -lW pr22393-2b.rd}} \
+    "pr22393-2a.so" \
+ ] \
+ [list \
+    "Build pr22393-2a-now.so" \
+    "-shared -Wl,-z,textonly,-z,now" \
+    "-fPIC" \
+    {pr22393-2a.c} \
+    {{readelf -lW pr22393-2a.rd} \
+     {readelf -lW pr22393-2b.rd}} \
+    "pr22393-2a-now.so" \
+ ] \
+ [list \
+    "Build pr22393-2" \
+    "$NOPIE_LDFLAGS -Wl,-z,textonly,--no-as-needed tmpdir/pr22393-2a.so" \
+    "$NOPIE_CFLAGS" \
+    {pr22393-2b.c} \
+    {{readelf -lW pr22393-2a.rd} \
+     {readelf -lW pr22393-2b.rd}} \
+    "pr22393-2" \
+ ] \
+ [list \
+    "Build pr22393-2 (PIE)" \
+    "-pie -Wl,-z,textonly,--no-as-needed tmpdir/pr22393-2a-now.so" \
+    "-fPIE" \
+    {pr22393-2b.c} \
+    {{readelf -lW pr22393-2a.rd} \
+     {readelf -lW pr22393-2b.rd}} \
+    "pr22393-2-pie" \
+ ] \
+ [list \
+    "Build pr22393-2 (static)" \
+    "-static -Wl,-z,textonly" \
+    "" \
+    {pr22393-2a.c pr22393-2b.c} \
+    {{readelf -lW pr22393-2a.rd} \
+     {readelf -lW pr22393-2b.rd}} \
+    "pr22393-2-static" \
+ ] \
     ]
     run_ld_link_exec_tests [list \
  [list \
@@ -893,6 +938,32 @@ if { [istarget *-*-linux*]
     "pass.out" \
     "-fPIE" \
  ] \
+ [list \
+    "Run pr22393-2" \
+    "$NOPIE_LDFLAGS -Wl,-z,textonly,--no-as-needed tmpdir/pr22393-2a.so" \
+    "" \
+    {pr22393-2b.c} \
+    "pr22393-2" \
+    "pass.out" \
+    "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+    "Run pr22393-2 (PIE)" \
+    "-pie -Wl,-z,textonly,--no-as-needed tmpdir/pr22393-2a-now.so" \
+    "" \
+    {pr22393-2b.c} \
+    "pr22393-2-pie" \
+    "pass.out" \
+    "-fPIE" \
+ ] \
+ [list \
+    "Run pr22393-2 (static)" \
+    "-static -Wl,-z,textonly" \
+    "" \
+    {pr22393-2a.c pr22393-2b.c} \
+    "pr22393-2-static" \
+    "pass.out" \
+ ] \
     ]
 }
 
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

[PATCH 6/6] x86-64: Add tests for -z textonly -z max-page-size=0x1000

H.J. Lu-30
In reply to this post by H.J. Lu-30
        PR ld/22393
        * testsuite/ld-x86-64/pr22393-3a.c: New file.
        * testsuite/ld-x86-64/pr22393-3a.rd: Likewise.
        * testsuite/ld-x86-64/pr22393-3b.c: Likewise.
        * testsuite/ld-x86-64/pr22393-3b.rd: Likewise.
        * testsuite/ld-x86-64/x86-64.exp: Run tests for -z textonly
        -z max-page-size=0x1000.
---
 ld/testsuite/ld-x86-64/pr22393-3a.c  |  7 ++++
 ld/testsuite/ld-x86-64/pr22393-3a.rd |  9 +++++
 ld/testsuite/ld-x86-64/pr22393-3b.c  |  7 ++++
 ld/testsuite/ld-x86-64/pr22393-3b.rd |  9 +++++
 ld/testsuite/ld-x86-64/x86-64.exp    | 71 ++++++++++++++++++++++++++++++++++++
 5 files changed, 103 insertions(+)
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3a.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3a.rd
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3b.c
 create mode 100644 ld/testsuite/ld-x86-64/pr22393-3b.rd

diff --git a/ld/testsuite/ld-x86-64/pr22393-3a.c b/ld/testsuite/ld-x86-64/pr22393-3a.c
new file mode 100644
index 0000000000..68fa4a0dd0
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22393-3a.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+test()
+{
+  printf ("PASS\n");
+}
diff --git a/ld/testsuite/ld-x86-64/pr22393-3a.rd b/ld/testsuite/ld-x86-64/pr22393-3a.rd
new file mode 100644
index 0000000000..b7ba110095
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22393-3a.rd
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-x86-64/pr22393-3b.c b/ld/testsuite/ld-x86-64/pr22393-3b.c
new file mode 100644
index 0000000000..3033809b02
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22393-3b.c
@@ -0,0 +1,7 @@
+void test(void);
+
+int main()
+{
+  test();
+  return 0;
+}
diff --git a/ld/testsuite/ld-x86-64/pr22393-3b.rd b/ld/testsuite/ld-x86-64/pr22393-3b.rd
new file mode 100644
index 0000000000..b7ba110095
--- /dev/null
+++ b/ld/testsuite/ld-x86-64/pr22393-3b.rd
@@ -0,0 +1,9 @@
+#source: pr22393-1.s
+#ld: -shared -z textonly
+#readelf: -l --wide
+#target: *-*-linux-gnu *-*-gnu* *-*-nacl*
+
+#failif
+#...
+ +[0-9]+  +.*(\.note|\.gnu|\.hash|\.dyn|\.rel).*\.text.*
+#...
diff --git a/ld/testsuite/ld-x86-64/x86-64.exp b/ld/testsuite/ld-x86-64/x86-64.exp
index ef2cb1551c..304128e165 100644
--- a/ld/testsuite/ld-x86-64/x86-64.exp
+++ b/ld/testsuite/ld-x86-64/x86-64.exp
@@ -1104,6 +1104,51 @@ if { [isnative] && [which $CC] != 0 } {
     {} \
     "pr22064.so" \
  ] \
+ [list \
+    "Build pr22393-3a.so" \
+    "-shared -Wl,-z,textonly,-z,max-page-size=0x1000" \
+    "-fPIC" \
+    {pr22393-3a.c} \
+    {{readelf -lW pr22393-3a.rd} \
+     {readelf -lW pr22393-3b.rd}} \
+    "pr22393-3a.so" \
+ ] \
+ [list \
+    "Build pr22393-3a-now.so" \
+    "-shared -Wl,-z,textonly,-z,now,-z,max-page-size=0x1000" \
+    "-fPIC" \
+    {pr22393-3a.c} \
+    {{readelf -lW pr22393-3a.rd} \
+     {readelf -lW pr22393-3b.rd}} \
+    "pr22393-3a-now.so" \
+ ] \
+ [list \
+    "Build pr22393-3" \
+    "$NOPIE_LDFLAGS -Wl,-z,textonly,-z,max-page-size=0x1000,--no-as-needed tmpdir/pr22393-2a.so" \
+    "$NOPIE_CFLAGS" \
+    {pr22393-3b.c} \
+    {{readelf -lW pr22393-3a.rd} \
+     {readelf -lW pr22393-3b.rd}} \
+    "pr22393-3" \
+ ] \
+ [list \
+    "Build pr22393-3 (PIE)" \
+    "-pie -Wl,-z,textonly,-z,max-page-size=0x1000,--no-as-needed tmpdir/pr22393-2a-now.so" \
+    "-fPIE" \
+    {pr22393-3b.c} \
+    {{readelf -lW pr22393-3a.rd} \
+     {readelf -lW pr22393-3b.rd}} \
+    "pr22393-3-pie" \
+ ] \
+ [list \
+    "Build pr22393-3 (static)" \
+    "-static -Wl,-z,textonly,-z,max-page-size=0x1000" \
+    "" \
+    {pr22393-3a.c pr22393-3b.c} \
+    {{readelf -lW pr22393-3a.rd} \
+     {readelf -lW pr22393-3b.rd}} \
+    "pr22393-3-static" \
+ ] \
     ]
 
     if  {[istarget "x86_64-*-linux*-gnux32"]} {
@@ -1403,6 +1448,32 @@ if { [isnative] && [which $CC] != 0 } {
     "pass.out" \
     "-fPIE" \
  ] \
+ [list \
+    "Run pr22393-3" \
+    "$NOPIE_LDFLAGS -Wl,-z,textonly,-z,max-page-size=0x1000,--no-as-needed tmpdir/pr22393-3a.so" \
+    "" \
+    {pr22393-3b.c} \
+    "pr22393-3" \
+    "pass.out" \
+    "$NOPIE_CFLAGS" \
+ ] \
+ [list \
+    "Run pr22393-3 (PIE)" \
+    "-pie -Wl,-z,textonly,-z,max-page-size=0x1000,--no-as-needed tmpdir/pr22393-3a-now.so" \
+    "" \
+    {pr22393-3b.c} \
+    "pr22393-3-pie" \
+    "pass.out" \
+    "-fPIE" \
+ ] \
+ [list \
+    "Run pr22393-3 (static)" \
+    "-static -Wl,-z,textonly,-z,max-page-size=0x1000" \
+    "" \
+    {pr22393-3a.c pr22393-3b.c} \
+    "pr22393-3-static" \
+    "pass.out" \
+ ] \
     ]
 
     # Run-time tests which require working ifunc attribute support.
--
2.13.6

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Michael Matz
In reply to this post by H.J. Lu-30
Hi,

On Mon, 13 Nov 2017, H.J. Lu wrote:

> Text-only LOAD segment has the same requirement for segment alignment
> and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
> segment may not end at the same address of the end of data segment.  
> But for text-only LOAD segment, it is exactly the same as text LOAD
> segment.
>
> The new "-z textonly" option will turn on both text-only LOAD segment
> and GNU_RELRO segment.  The new "-z notextonly" option will turn off
> only text-only LOAD segment.  "-z relro" is updated not to turn off
> text-only LOAD segment.  "-z norelro" is updated to turn off both
> GNU_RELRO segment and text-only LOAD segment.
>
> When there is a text-only LOAD segment, create a new LOAD segment if the
> previous section contains text and the current section doesn't or vice
> versa:
>
> Elf file type is DYN (Shared object file)
> Entry point 0x200ff0
> There are 7 program headers, starting at offset 52
>
> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>   LOAD           0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000

This seems strange.  The (file)offset of the fourth segment is much larger
than than the added sizes of the individual segments, which isn't
necessary.

> Since there are more than 2 LOAD segments, the minimum file size is
> bigger than the maximum page size which is 2MB (0x200000):
>
> -rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 libfoo.so

This is the result of the above problem, but it's not necessary.  Like in
a traditional two-LOAD-segment file, which also isn't larger than 2MB,
just because the page size is 2MB.  It achieves this by mapping the same
file bytes multiple times, and you could do the same.  E.g. for the file
above the better layout would be:

  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
  LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
  LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
  LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000

But even then something is wrong: The RE and the second R page are both
mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
protections.  (You'd need 4k pages again, which defeats the whole purpose
of having 2MB pages in the file to start with).

>
> "-z max-page-size=0x1000" can be used to reduce the maximum page size to
> 4KB (0x1000):
>
> -rwxr-xr-x 1 hjl hjl 11836 Nov 12 13:22 libfoo.so
>
> Elf file type is DYN (Shared object file)
> Entry point 0x1ff0
> There are 7 program headers, starting at offset 52
>
> Program Headers:
>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
>   LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
>   LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
>   LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000

Also this shows strangeness.  The second R and the RW page are both mapped
to 0x2xxx, the same 4k page, which can't have different protections.  Also
the offsets are somehow wrong.  The second R page starts at 0x1000 (in
file), and is 0x58 bytes long (memsize is 0x58 as well).  So the next
thing in file should start at 0x1060, not 0x1f80 (and should be mapped to
0x3060, not 0x2f80).

So, I think something in your patch series is quite wrong with offset,
size and vaddr calculations.


Ciao,
Michael.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Tue, Nov 14, 2017 at 4:55 AM, Michael Matz <[hidden email]> wrote:

> Hi,
>
> On Mon, 13 Nov 2017, H.J. Lu wrote:
>
>> Text-only LOAD segment has the same requirement for segment alignment
>> and page sizes as GNU_RELRO segment.  But for GNU_RELRO segment, the
>> segment may not end at the same address of the end of data segment.
>> But for text-only LOAD segment, it is exactly the same as text LOAD
>> segment.
>>
>> The new "-z textonly" option will turn on both text-only LOAD segment
>> and GNU_RELRO segment.  The new "-z notextonly" option will turn off
>> only text-only LOAD segment.  "-z relro" is updated not to turn off
>> text-only LOAD segment.  "-z norelro" is updated to turn off both
>> GNU_RELRO segment and text-only LOAD segment.
>>
>> When there is a text-only LOAD segment, create a new LOAD segment if the
>> previous section contains text and the current section doesn't or vice
>> versa:
>>
>> Elf file type is DYN (Shared object file)
>> Entry point 0x200ff0
>> There are 7 program headers, starting at offset 52
>>
>> Program Headers:
>>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>>   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>>   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>>   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>>   LOAD           0x200f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000
>
> This seems strange.  The (file)offset of the fourth segment is much larger
> than than the added sizes of the individual segments, which isn't
> necessary.
>
>> Since there are more than 2 LOAD segments, the minimum file size is
>> bigger than the maximum page size which is 2MB (0x200000):
>>
>> -rwxr-xr-x 1 hjl hjl 2104892 Nov 12 11:53 libfoo.so
>
> This is the result of the above problem, but it's not necessary.  Like in
> a traditional two-LOAD-segment file, which also isn't larger than 2MB,
> just because the page size is 2MB.  It achieves this by mapping the same
> file bytes multiple times, and you could do the same.  E.g. for the file
> above the better layout would be:
>
>   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
>
> But even then something is wrong: The RE and the second R page are both
> mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
> protections.  (You'd need 4k pages again, which defeats the whole purpose
> of having 2MB pages in the file to start with).

You have found out yourself that it is impossible.   In elf.c, there are

static file_ptr
vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize)
{
  /* PR binutils/16199: Handle an alignment of zero.  */
  if (maxpagesize == 0)
    maxpagesize = 1;
  return ((vma - off) % maxpagesize);
}

It is used to adjust file offset to align to the maximum page size.   It can
be quite large, up to the maximum page size.

>>
>> "-z max-page-size=0x1000" can be used to reduce the maximum page size to
>> 4KB (0x1000):
>>
>> -rwxr-xr-x 1 hjl hjl 11836 Nov 12 13:22 libfoo.so
>>
>> Elf file type is DYN (Shared object file)
>> Entry point 0x1ff0
>> There are 7 program headers, starting at offset 52
>>
>> Program Headers:
>>   Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
>>   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
>>   LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
>>   LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
>>   LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000
>
> Also this shows strangeness.  The second R and the RW page are both mapped
> to 0x2xxx, the same 4k page, which can't have different protections.  Also
> the offsets are somehow wrong.  The second R page starts at 0x1000 (in
> file), and is 0x58 bytes long (memsize is 0x58 as well).  So the next
> thing in file should start at 0x1060, not 0x1f80 (and should be mapped to
> 0x3060, not 0x2f80).
>

You need to look at the whole picture:

      LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x1000
      LOAD           0x000fd0 0x00001fd0 0x00001fd0 0x0002b 0x0002b R E 0x1000
      LOAD           0x001000 0x00002000 0x00002000 0x00058 0x00058 R   0x1000
      LOAD           0x001f80 0x00002f80 0x00002f80 0x000a0 0x000a0 RW  0x1000
      DYNAMIC        0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 RW  0x4
      GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
      GNU_RELRO      0x001f80 0x00002f80 0x00002f80 0x00080 0x00080 R   0x1

     Section to Segment mapping:
      Segment Sections...
       00     .hash .gnu.hash .dynsym .dynstr .rela.plt
       01     .plt .text
       02     .rodata .eh_frame
       03     .dynamic .got.plt
       04     .dynamic
       05
       06     .dynamic

Part of the 4th segment is in GNU_RELRO segment which becomes read-only after
relocation and is merged with the 3rd R page:

  [ 8] .rodata           PROGBITS        00002000 001000 000006 01 AMS  0   0  1
  [ 9] .eh_frame         PROGBITS        00002008 001008 000050 00   A  0   0  4
  [10] .dynamic          DYNAMIC         00002f80 001f80 000080 08  WA  4   0  4
  [11] .got.plt          PROGBITS        00003000 002000 000020 08  WA  0   0  8

After relocation, the 3rd page has .rodata, .eh_frame and .dynamic.


--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Michael Matz
Hi,

On Tue, 14 Nov 2017, H.J. Lu wrote:

> > This is the result of the above problem, but it's not necessary.  Like in
> > a traditional two-LOAD-segment file, which also isn't larger than 2MB,
> > just because the page size is 2MB.  It achieves this by mapping the same
> > file bytes multiple times, and you could do the same.  E.g. for the file
> > above the better layout would be:
> >
> >   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
> >   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
> >   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
> >   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
> >
> > But even then something is wrong: The RE and the second R page are both
> > mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
> > protections.  (You'd need 4k pages again, which defeats the whole purpose
> > of having 2MB pages in the file to start with).
>
> You have found out yourself that it is impossible.

Well, as is the above makes not much sense.  It wants to stay at 2MB
alignment but can't actually make use of it due to having protection
changes within one 2MB page (from RE to R).  Hmm, which means the very
introduction of GNU_RELRO already broke the whole 2MB pages optimization
:-/ You're just increasing this detrimental effect to now also cause
uselessly huge files.

Probably 4k pages should be default with "-z textonly"  Hmpf :(

> > Also this shows strangeness.  The second R and the RW page are both mapped
> > to 0x2xxx, the same 4k page, which can't have different protections.  Also
> > the offsets are somehow wrong.  The second R page starts at 0x1000 (in
> > file), and is 0x58 bytes long (memsize is 0x58 as well).  So the next
> > thing in file should start at 0x1060, not 0x1f80 (and should be mapped to
> > 0x3060, not 0x2f80).
> >
>
> You need to look at the whole picture:

Ah, true, the GNU_RELRO segment covers the (eventually) read-only part of
the RW segment.


Ciao,
Michael.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Tue, Nov 14, 2017 at 5:58 AM, Michael Matz <[hidden email]> wrote:

> Hi,
>
> On Tue, 14 Nov 2017, H.J. Lu wrote:
>
>> > This is the result of the above problem, but it's not necessary.  Like in
>> > a traditional two-LOAD-segment file, which also isn't larger than 2MB,
>> > just because the page size is 2MB.  It achieves this by mapping the same
>> > file bytes multiple times, and you could do the same.  E.g. for the file
>> > above the better layout would be:
>> >
>> >   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>> >   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>> >   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>> >   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
>> >
>> > But even then something is wrong: The RE and the second R page are both
>> > mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
>> > protections.  (You'd need 4k pages again, which defeats the whole purpose
>> > of having 2MB pages in the file to start with).
>>
>> You have found out yourself that it is impossible.
>
> Well, as is the above makes not much sense.  It wants to stay at 2MB
> alignment but can't actually make use of it due to having protection
> changes within one 2MB page (from RE to R).  Hmm, which means the very
> introduction of GNU_RELRO already broke the whole 2MB pages optimization
> :-/ You're just increasing this detrimental effect to now also cause
> uselessly huge files.

GNU_RELRO is intended for common page size, which is 4K on x86-64.  If
the page size is 2MB at run-time, GNU_RELRO isn't applied.

> Probably 4k pages should be default with "-z textonly"  Hmpf :(

We can discuss this after "-z textonly" is checked in.


--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Tue, Nov 14, 2017 at 6:41 AM, H.J. Lu <[hidden email]> wrote:

> On Tue, Nov 14, 2017 at 5:58 AM, Michael Matz <[hidden email]> wrote:
>> Hi,
>>
>> On Tue, 14 Nov 2017, H.J. Lu wrote:
>>
>>> > This is the result of the above problem, but it's not necessary.  Like in
>>> > a traditional two-LOAD-segment file, which also isn't larger than 2MB,
>>> > just because the page size is 2MB.  It achieves this by mapping the same
>>> > file bytes multiple times, and you could do the same.  E.g. for the file
>>> > above the better layout would be:
>>> >
>>> >   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>>> >   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>>> >   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>>> >   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
>>> >
>>> > But even then something is wrong: The RE and the second R page are both
>>> > mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
>>> > protections.  (You'd need 4k pages again, which defeats the whole purpose
>>> > of having 2MB pages in the file to start with).
>>>
>>> You have found out yourself that it is impossible.
>>
>> Well, as is the above makes not much sense.  It wants to stay at 2MB
>> alignment but can't actually make use of it due to having protection
>> changes within one 2MB page (from RE to R).  Hmm, which means the very
>> introduction of GNU_RELRO already broke the whole 2MB pages optimization
>> :-/ You're just increasing this detrimental effect to now also cause
>> uselessly huge files.
>
> GNU_RELRO is intended for common page size, which is 4K on x86-64.  If
> the page size is 2MB at run-time, GNU_RELRO isn't applied.
>
>> Probably 4k pages should be default with "-z textonly"  Hmpf :(
>
> We can discuss this after "-z textonly" is checked in.
>

Given what happened, I'd like to check this patch set into binutils 2.30.

--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Michael Matz
Hi,

On Mon, 8 Jan 2018, H.J. Lu wrote:

> On Tue, Nov 14, 2017 at 6:41 AM, H.J. Lu <[hidden email]> wrote:
> > On Tue, Nov 14, 2017 at 5:58 AM, Michael Matz <[hidden email]> wrote:
> >> Hi,
> >>
> >> On Tue, 14 Nov 2017, H.J. Lu wrote:
> >>
> >>> > This is the result of the above problem, but it's not necessary.  Like in
> >>> > a traditional two-LOAD-segment file, which also isn't larger than 2MB,
> >>> > just because the page size is 2MB.  It achieves this by mapping the same
> >>> > file bytes multiple times, and you could do the same.  E.g. for the file
> >>> > above the better layout would be:
> >>> >
> >>> >   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
> >>> >   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
> >>> >   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
> >>> >   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
> >>> >
> >>> > But even then something is wrong: The RE and the second R page are both
> >>> > mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
> >>> > protections.  (You'd need 4k pages again, which defeats the whole purpose
> >>> > of having 2MB pages in the file to start with).
> >>>
> >>> You have found out yourself that it is impossible.
> >>
> >> Well, as is the above makes not much sense.  It wants to stay at 2MB
> >> alignment but can't actually make use of it due to having protection
> >> changes within one 2MB page (from RE to R).  Hmm, which means the very
> >> introduction of GNU_RELRO already broke the whole 2MB pages optimization
> >> :-/ You're just increasing this detrimental effect to now also cause
> >> uselessly huge files.
> >
> > GNU_RELRO is intended for common page size, which is 4K on x86-64.  If
> > the page size is 2MB at run-time, GNU_RELRO isn't applied.
> >
> >> Probably 4k pages should be default with "-z textonly"  Hmpf :(
> >
> > We can discuss this after "-z textonly" is checked in.
> >
>
> Given what happened, I'd like to check this patch set into binutils
> 2.30.

I'm assuming you mean Spectre and Meltdown?  I'm not sure what those have
to do with your patch.  I don't see what changed since November; I still
think 4k pages should be default for this new option (and eventually also
for GNU_RELRO, as even there 2MB pages are effectively useless).  Note
that I haven't anything against the page per se (and don't have any say
anyway); just the name is a bit generic, "textonly" ... what's that
supposed to mean? :)  -z separate-text-segment perhaps?


Ciao,
Michael.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Mon, Jan 8, 2018 at 7:26 AM, Michael Matz <[hidden email]> wrote:

> Hi,
>
> On Mon, 8 Jan 2018, H.J. Lu wrote:
>
>> On Tue, Nov 14, 2017 at 6:41 AM, H.J. Lu <[hidden email]> wrote:
>> > On Tue, Nov 14, 2017 at 5:58 AM, Michael Matz <[hidden email]> wrote:
>> >> Hi,
>> >>
>> >> On Tue, 14 Nov 2017, H.J. Lu wrote:
>> >>
>> >>> > This is the result of the above problem, but it's not necessary.  Like in
>> >>> > a traditional two-LOAD-segment file, which also isn't larger than 2MB,
>> >>> > just because the page size is 2MB.  It achieves this by mapping the same
>> >>> > file bytes multiple times, and you could do the same.  E.g. for the file
>> >>> > above the better layout would be:
>> >>> >
>> >>> >   LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
>> >>> >   LOAD           0x000fd0 0x00200fd0 0x00200fd0 0x0002b 0x0002b R E 0x200000
>> >>> >   LOAD           0x001000 0x00201000 0x00201000 0x00058 0x00058 R   0x200000
>> >>> >   LOAD           0x001060 0x00401060 0x00401060 0x000a0 0x000a0 RW  0x200000
>> >>> >
>> >>> > But even then something is wrong: The RE and the second R page are both
>> >>> > mapped onto 0x0020xxxx, i.e. the same 2MB page, so can't have different
>> >>> > protections.  (You'd need 4k pages again, which defeats the whole purpose
>> >>> > of having 2MB pages in the file to start with).
>> >>>
>> >>> You have found out yourself that it is impossible.
>> >>
>> >> Well, as is the above makes not much sense.  It wants to stay at 2MB
>> >> alignment but can't actually make use of it due to having protection
>> >> changes within one 2MB page (from RE to R).  Hmm, which means the very
>> >> introduction of GNU_RELRO already broke the whole 2MB pages optimization
>> >> :-/ You're just increasing this detrimental effect to now also cause
>> >> uselessly huge files.
>> >
>> > GNU_RELRO is intended for common page size, which is 4K on x86-64.  If
>> > the page size is 2MB at run-time, GNU_RELRO isn't applied.
>> >
>> >> Probably 4k pages should be default with "-z textonly"  Hmpf :(
>> >
>> > We can discuss this after "-z textonly" is checked in.
>> >
>>
>> Given what happened, I'd like to check this patch set into binutils
>> 2.30.
>
> I'm assuming you mean Spectre and Meltdown?  I'm not sure what those have

See:

https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00484.html

> to do with your patch.  I don't see what changed since November; I still
> think 4k pages should be default for this new option (and eventually also
> for GNU_RELRO, as even there 2MB pages are effectively useless).  Note

Page size should be a separate issue.

> that I haven't anything against the page per se (and don't have any say
> anyway); just the name is a bit generic, "textonly" ... what's that
> supposed to mean? :)  -z separate-text-segment perhaps?

-z codeonly -or z insnonly?


--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Alan Modra-3
On Mon, Jan 08, 2018 at 08:10:53AM -0800, H.J. Lu wrote:
> On Mon, Jan 8, 2018 at 7:26 AM, Michael Matz <[hidden email]> wrote:
> > supposed to mean? :)  -z separate-text-segment perhaps?
>
> -z codeonly -or z insnonly?

-z separate-code perhaps?

Regarding the implementation, I'm wondering why you didn't implement
the vma adjustments entirely in the new linker scripts.  It seems like
this ought to be possible.

You're stuck with multiple new PT_LOAD segments.  The R, RE, R, RW
order is necessary because the first R must cover the ELF header, and
the second R is needed for relro support (but you might be able to
reorder sections to get R, RE, RW for non-relro).

--
Alan Modra
Australia Development Lab, IBM
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Tue, Jan 9, 2018 at 5:21 AM, Alan Modra <[hidden email]> wrote:
> On Mon, Jan 08, 2018 at 08:10:53AM -0800, H.J. Lu wrote:
>> On Mon, Jan 8, 2018 at 7:26 AM, Michael Matz <[hidden email]> wrote:
>> > supposed to mean? :)  -z separate-text-segment perhaps?
>>
>> -z codeonly -or z insnonly?
>
> -z separate-code perhaps?

Done.   I updated to -z separate-code on users/hjl/pr22393 branch.

> Regarding the implementation, I'm wondering why you didn't implement
> the vma adjustments entirely in the new linker scripts.  It seems like
> this ought to be possible.

It may be doable without RELRO.   My current approach is built on top
of RELRO.  Maybe I missed something.  Can you show me how to do
it entirely in linker scripts?

> You're stuck with multiple new LOAD segments.  The R, RE, R, RW
> order is necessary because the first R must cover the ELF header, and
> the second R is needed for relro support (but you might be able to
> reorder sections to get R, RE, RW for non-relro).
>

In my implementation, -z norelro implies -z noseparate-code.

--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Alan Modra-3
On Tue, Jan 09, 2018 at 09:39:04AM -0800, H.J. Lu wrote:

> On Tue, Jan 9, 2018 at 5:21 AM, Alan Modra <[hidden email]> wrote:
> > On Mon, Jan 08, 2018 at 08:10:53AM -0800, H.J. Lu wrote:
> >> On Mon, Jan 8, 2018 at 7:26 AM, Michael Matz <[hidden email]> wrote:
> >> > supposed to mean? :)  -z separate-text-segment perhaps?
> >>
> >> -z codeonly -or z insnonly?
> >
> > -z separate-code perhaps?
>
> Done.   I updated to -z separate-code on users/hjl/pr22393 branch.
>
> > Regarding the implementation, I'm wondering why you didn't implement
> > the vma adjustments entirely in the new linker scripts.  It seems like
> > this ought to be possible.
>
> It may be doable without RELRO.   My current approach is built on top
> of RELRO.

Yes, that's what I don't like about the current implementation.  In
practice users will likely want both turned on, but that fact
shouldn't affect the design.  From a high level perspective, -z relro
and -z separate-code are two different and independent concepts, with
-z relro being more complicated.  So it would be nicer if the relro
machinery wasn't made more complicated than it is now by also handling
-z separate-code.

So let's talk about the design.

For -z separate-code you do need to start with a PF_R PT_LOAD segment,
for the ELF header.  The header can't be PF_X since its data, if
interpreted as instructions might contain exploitable code.  Initial
read-only sections like .interp will be placed into this segment too.

Next we'll have a PF_X PT_LOAD segment.  This will start at a
-z common-page-size boundary, or if you want to save disk space *and*
you have support in ld.so to clear the beginning of the segment, at
the end of the previous segment plus one common-page-size.  I don't
think we currently have glibc ld.so clearing the beginning of
segments..  I'm following your choice of common-page-size rather than
max-page-size because aligning to max-page-size will create large
binaries on disk.  However, using a common-page-size alignment means
the resulting binary will not have effective separation of code from
data if the system page size is larger than common-page-size,
similarly to the way relro is ineffective under the same condition.

So that's the first questionable design decision.  I strongly suspect
we should add max-page-size to the end of the previous segment, but
that means a glibc change is needed (I think).  Can we make ld.so
clear out leading and trailing rubbish from PF_X segments for glibc
2.27?

Next we have another PF_R PT_LOAD segment, for .rodata and other
read-only sections that normally are placed after .text.  As before,
this segment needs to be aligned to a -z common-page-size boundary (or
you need glibc ld.so support for clearing the end of the previous
PF_X segment).

None of the above has any effect on the relro support.

>  Maybe I missed something.  Can you show me how to do
> it entirely in linker scripts?

It's more likely I'm missing something. :)  Hmm, probably code in
elf.c packing sections to segments will need to know whether -z
separate-code is in effect, at least if we don't go for the
max-page-size vma adjustment.

--
Alan Modra
Australia Development Lab, IBM
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

Alan Modra-3
On Wed, Jan 10, 2018 at 09:40:19AM +1030, Alan Modra wrote:
> that means a glibc change is needed (I think).  Can we make ld.so
> clear out leading and trailing rubbish from PF_X segments for glibc
> 2.27?

On second thoughts, that's not such a good idea.  If we write to a
memory page it becomes unshared.  So it seems we must align to
common-page-size.

--
Alan Modra
Australia Development Lab, IBM
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Tue, Jan 9, 2018 at 8:45 PM, Alan Modra <[hidden email]> wrote:
> On Wed, Jan 10, 2018 at 09:40:19AM +1030, Alan Modra wrote:
>> that means a glibc change is needed (I think).  Can we make ld.so
>> clear out leading and trailing rubbish from PF_X segments for glibc
>> 2.27?
>
> On second thoughts, that's not such a good idea.  If we write to a
> memory page it becomes unshared.  So it seems we must align to
> common-page-size.
>

LOAD segments needs to aligned to max-page-size.  RELRO is
optional, ignore it at run-time won't break programs.

--
H.J.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH 0/6] ld: Add "-z textonly" option to ELF linker

H.J. Lu-30
On Wed, Jan 10, 2018 at 5:08 AM, H.J. Lu <[hidden email]> wrote:

> On Tue, Jan 9, 2018 at 8:45 PM, Alan Modra <[hidden email]> wrote:
>> On Wed, Jan 10, 2018 at 09:40:19AM +1030, Alan Modra wrote:
>>> that means a glibc change is needed (I think).  Can we make ld.so
>>> clear out leading and trailing rubbish from PF_X segments for glibc
>>> 2.27?
>>
>> On second thoughts, that's not such a good idea.  If we write to a
>> memory page it becomes unshared.  So it seems we must align to
>> common-page-size.
>>
>
> LOAD segments needs to aligned to max-page-size.  RELRO is
> optional, ignore it at run-time won't break programs.
>

I created users/hjl/pr22393/master branch.  Now I got

Elf file type is DYN (Shared object file)
Entry point 0x220
There are 7 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x00200 0x00200 R   0x200000
  LOAD           0x000200 0x00000200 0x00000200 0x0002b 0x0002b R E 0x200000
  LOAD           0x00022b 0x0020022b 0x0020022b 0x00059 0x00059 R   0x200000
  LOAD           0x000f80 0x00400f80 0x00400f80 0x000a0 0x000a0 RW  0x200000
  DYNAMIC        0x000f80 0x00400f80 0x00400f80 0x00080 0x00080 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000f80 0x00400f80 0x00400f80 0x00080 0x00080 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     .hash .gnu.hash .dynsym .dynstr .rela.plt
   01     .plt .text
   02     .rodata .eh_frame
   03     .dynamic .got.plt
   04     .dynamic
   05
   06     .dynamic

Will code page mapped from the code segment contain data?

--
H.J.