[v2,0/9] ld: Implement DT_RELR for x86

Message ID 20220108183838.1920397-1-hjl.tools@gmail.com
Headers
Series ld: Implement DT_RELR for x86 |

Message

H.J. Lu Jan. 8, 2022, 6:38 p.m. UTC
  Hi Nick,

I'd like to enable DT_RELR for x86 in binutils 2.38.


H.J.
---
Changes in v2:

1. Drop the _bfd_elf_link_iterate_on_relocs patch, which has been checked
into master branch.
2. Also pack R_*_RELATIVE relocations against dynamic symbols.
3. Skip relocation against IFUNC symbol earlier.
4. Don't require the --relax option enabled.
5. Add more DT_RELR tests:
   a. Add a test with relative relocation in section with 1-byte
      alignment.
   b. Add a test with -z pack-relative-relocs --no-relax.
   c. Add tests for packing R_*_RELATIVE relocations against dynamic
      symbols.

DT_RELR encodes consecutive R_*_RELATIVE relocations in GOT (the global
offset table) and data sections in a compact format:

https://groups.google.com/g/generic-abi/c/bX460iggiKg

On some targets, R_*_RELATIVE relocations are counted and the GOT offsets
are allocated when setting the dynamic section sizes after seeing all
relocations.  R_*_RELATIVE relocations are generated while relocating
sections after section layout has been finalized.

For x86 targets, the old check_relocs is renamed to scan_relocs and a
new check_relocs is added to chek input sections and create dynamic
relocation sections so that they will be mapped to output sections.
scan_relocs is now called from elf_backend_always_size_sections.

On some targets, the DT_RELR section size can be computed only after all
symbols addresses can be determined:

1. Update ldelf_map_segments to pass need_layout to
_bfd_elf_map_sections_to_segments which will size DT_RELR section and
set need_layout to true if the DT_RELR section size is changed.
2.  Set the preliminary DT_RELR section size before mapping sections to
segments and set the final DT_RELR section size after regular symbol
processing is done.

On x86, DT_RELR is implemented with linker relaxation:

1. During linker relaxation, we scan input relocations with the same
logic in relocate_section to determine if a relative relocation should
be generated and save the relative relocation candidate information for
sizing the DT_RELR section later after all symbols addresses can be
determined.  For these relative relocations which can't be placed in
the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
section.
2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
backend function to size the DT_RELR section which will compute the
DT_RELR section size and tell ldelf_map_segments to layout sections
again when the DT_RELR section size has been increased.
3. After regular symbol processing is finished, bfd_elf_final_link calls
a backend function to finish the DT_RELR section.

When DT_RELR is enabled, to avoid random run-time crash with older glibc
binaries without DT_RELR support, add a GLIBC_ABI_DT_RELR symbol version,
which is provided by glibc with DT_RELR support, dependency on the shared
C library if it provides a GLIBC_2.XX symbol version.

It can build DT_RELR enabled glibc successfully on x86-64, x32 and
i686.

H.J. Lu (9):
  elf: Add .relr.dyn to special_sections_r
  elf: Extract _bfd_elf_process_reverse_copy
  elf: Pass need_layout to _bfd_elf_map_sections_to_segments
  ld: Initial DT_RELR support
  elf: Add size_relative_relocs and finish_relative_relocs
  elf: Support DT_RELR in linker tests
  x86: Add DT_RELR support
  ld: Add simple DT_RELR tests
  ld: Add glibc dependency for DT_RELR

 bfd/elf-bfd.h                                 |  15 +-
 bfd/elf.c                                     |  22 +-
 bfd/elf32-i386.c                              |  77 +-
 bfd/elf64-x86-64.c                            |  92 +-
 bfd/elflink.c                                 | 168 ++-
 bfd/elfxx-target.h                            |   8 +
 bfd/elfxx-x86.c                               | 954 ++++++++++++++++++
 bfd/elfxx-x86.h                               | 147 ++-
 binutils/testsuite/lib/binutils-common.exp    |   1 +
 include/bfdlink.h                             |   4 +
 ld/NEWS                                       |   3 +
 ld/emulparams/dt-relr.sh                      |  21 +
 ld/emulparams/elf32_x86_64.sh                 |   1 +
 ld/emulparams/elf_i386.sh                     |   1 +
 ld/emulparams/elf_x86_64.sh                   |   1 +
 ld/emultempl/elf.em                           |   5 +-
 ld/ld.texi                                    |  13 +
 ld/ldelf.c                                    |   9 +
 ld/ldelfgen.c                                 |   3 +-
 ld/ldlang.c                                   |   3 +-
 ld/scripttempl/elf.sc                         |   4 +
 ld/testsuite/config/default.exp               |  16 +
 ld/testsuite/ld-elf/dt-relr-1.s               |  13 +
 ld/testsuite/ld-elf/dt-relr-1a.d              |  10 +
 ld/testsuite/ld-elf/dt-relr-1b.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-1c.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2.s               |  20 +
 ld/testsuite/ld-elf/dt-relr-2a.d              |  10 +
 ld/testsuite/ld-elf/dt-relr-2b.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2c.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2d.d              |  17 +
 ld/testsuite/ld-elf/dt-relr-2e.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2f.d              |   8 +
 ld/testsuite/ld-elf/dt-relr-2g.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-2h.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-3.s               |  12 +
 ld/testsuite/ld-elf/dt-relr-3a.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-3b.d              |   9 +
 ld/testsuite/ld-elf/dt-relr-glibc-1.c         |  11 +
 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd       |   4 +
 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd       |   7 +
 ld/testsuite/ld-elf/dt-relr.exp               |  44 +
 ld/testsuite/ld-elf/shared.exp                |   3 +-
 ld/testsuite/ld-i386/dt-relr-1.d              |  14 +
 ld/testsuite/ld-i386/dt-relr-1.s              |   3 +
 ld/testsuite/ld-i386/export-class.exp         |   2 +-
 ld/testsuite/ld-i386/i386.exp                 |  21 +-
 ld/testsuite/ld-i386/ibt-plt-2a.d             |   2 +-
 ld/testsuite/ld-i386/ibt-plt-3a.d             |   2 +-
 ld/testsuite/ld-i386/ibt-plt-3c.d             |   2 +-
 ld/testsuite/ld-i386/pr26869.d                |   2 +-
 ld/testsuite/ld-i386/report-reloc-1.d         |   2 +-
 ld/testsuite/ld-ifunc/ifunc-2-i386-now.d      |   2 +-
 .../ld-ifunc/ifunc-2-local-i386-now.d         |   2 +-
 .../ld-ifunc/ifunc-2-local-x86-64-now.d       |   2 +-
 ld/testsuite/ld-ifunc/ifunc-2-x86-64-now.d    |   2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64-now.d    |   2 +-
 ld/testsuite/ld-ifunc/pr17154-x86-64.d        |   2 +-
 ld/testsuite/ld-x86-64/bnd-branch-1-now.d     |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-1-now.d      |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2-now.d      |   2 +-
 ld/testsuite/ld-x86-64/bnd-ifunc-2.d          |   2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1-now.d        |   2 +-
 ld/testsuite/ld-x86-64/bnd-plt-1.d            |   2 +-
 ld/testsuite/ld-x86-64/dt-relr-1-x32.d        |  15 +
 ld/testsuite/ld-x86-64/dt-relr-1.d            |  14 +
 ld/testsuite/ld-x86-64/dt-relr-1.s            |   3 +
 ld/testsuite/ld-x86-64/export-class.exp       |   3 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a-x32.d       |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-2a.d           |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a-x32.d       |   2 +-
 ld/testsuite/ld-x86-64/ibt-plt-3a.d           |   2 +-
 ld/testsuite/ld-x86-64/ilp32-4.d              |   2 +-
 ld/testsuite/ld-x86-64/load1c.d               |   2 +-
 ld/testsuite/ld-x86-64/load1d.d               |   2 +-
 ld/testsuite/ld-x86-64/pr13082-2b.d           |   2 +-
 ld/testsuite/ld-x86-64/pr14207.d              |   2 +-
 ld/testsuite/ld-x86-64/pr18176.d              |   2 +-
 ld/testsuite/ld-x86-64/pr19162.d              |   2 +-
 ld/testsuite/ld-x86-64/pr19636-2d.d           |   2 +-
 ld/testsuite/ld-x86-64/pr19636-2l.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1d.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1f.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1j.d           |   2 +-
 ld/testsuite/ld-x86-64/pr20253-1l.d           |   2 +-
 ld/testsuite/ld-x86-64/report-reloc-1-x32.d   |   2 +-
 ld/testsuite/ld-x86-64/report-reloc-1.d       |   2 +-
 ld/testsuite/ld-x86-64/x86-64.exp             |  67 +-
 88 files changed, 1883 insertions(+), 155 deletions(-)
 create mode 100644 ld/emulparams/dt-relr.sh
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-1c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2c.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2d.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2e.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2f.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2g.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-2h.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3.s
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3a.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-3b.d
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1.c
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1a.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr-glibc-1b.rd
 create mode 100644 ld/testsuite/ld-elf/dt-relr.exp
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-i386/dt-relr-1.s
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1-x32.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.d
 create mode 100644 ld/testsuite/ld-x86-64/dt-relr-1.s
  

Comments

Fangrui Song Jan. 8, 2022, 9:53 p.m. UTC | #1
On 2022-01-08, H.J. Lu via Binutils wrote:
>Hi Nick,
>
>I'd like to enable DT_RELR for x86 in binutils 2.38.
>
>
>H.J.
>---
>Changes in v2:
>
>1. Drop the _bfd_elf_link_iterate_on_relocs patch, which has been checked
>into master branch.
>2. Also pack R_*_RELATIVE relocations against dynamic symbols.
>3. Skip relocation against IFUNC symbol earlier.
>4. Don't require the --relax option enabled.
>5. Add more DT_RELR tests:
>   a. Add a test with relative relocation in section with 1-byte
>      alignment.
>   b. Add a test with -z pack-relative-relocs --no-relax.
>   c. Add tests for packing R_*_RELATIVE relocations against dynamic
>      symbols.
>
>DT_RELR encodes consecutive R_*_RELATIVE relocations in GOT (the global
>offset table) and data sections in a compact format:
>
>https://groups.google.com/g/generic-abi/c/bX460iggiKg
>
>On some targets, R_*_RELATIVE relocations are counted and the GOT offsets
>are allocated when setting the dynamic section sizes after seeing all
>relocations.  R_*_RELATIVE relocations are generated while relocating
>sections after section layout has been finalized.
>
>For x86 targets, the old check_relocs is renamed to scan_relocs and a
>new check_relocs is added to chek input sections and create dynamic
>relocation sections so that they will be mapped to output sections.
>scan_relocs is now called from elf_backend_always_size_sections.
>
>On some targets, the DT_RELR section size can be computed only after all
>symbols addresses can be determined:
>
>1. Update ldelf_map_segments to pass need_layout to
>_bfd_elf_map_sections_to_segments which will size DT_RELR section and
>set need_layout to true if the DT_RELR section size is changed.
>2.  Set the preliminary DT_RELR section size before mapping sections to
>segments and set the final DT_RELR section size after regular symbol
>processing is done.
>
>On x86, DT_RELR is implemented with linker relaxation:
>
>1. During linker relaxation, we scan input relocations with the same
>logic in relocate_section to determine if a relative relocation should
>be generated and save the relative relocation candidate information for
>sizing the DT_RELR section later after all symbols addresses can be
>determined.  For these relative relocations which can't be placed in
>the DT_RELR section, they will be placed in the rela.dyn/rel.dyn
>section.
>2. When DT_RELR is enabled, _bfd_elf_map_sections_to_segments calls a
>backend function to size the DT_RELR section which will compute the
>DT_RELR section size and tell ldelf_map_segments to layout sections
>again when the DT_RELR section size has been increased.
>3. After regular symbol processing is finished, bfd_elf_final_link calls
>a backend function to finish the DT_RELR section.
>
>When DT_RELR is enabled, to avoid random run-time crash with older glibc
>binaries without DT_RELR support, add a GLIBC_ABI_DT_RELR symbol version,
>which is provided by glibc with DT_RELR support, dependency on the shared
>C library if it provides a GLIBC_2.XX symbol version.
>
>It can build DT_RELR enabled glibc successfully on x86-64, x32 and
>i686.
>
>H.J. Lu (9):
>  elf: Add .relr.dyn to special_sections_r
>  elf: Extract _bfd_elf_process_reverse_copy
>  elf: Pass need_layout to _bfd_elf_map_sections_to_segments
>  ld: Initial DT_RELR support
>  elf: Add size_relative_relocs and finish_relative_relocs
>  elf: Support DT_RELR in linker tests
>  x86: Add DT_RELR support
>  ld: Add simple DT_RELR tests
>  ld: Add glibc dependency for DT_RELR

Thank you so much for the heroic work.
I cannot think of other items.

When linking clang, there is no longer RELA R_X86_64_RELATIVE. Nice!
clang -fsanitize=memory built ld passed.
gcc -fsanitize=address built ld passed (ld has pre-existing leaks. This
patch series does not add more leaks.)

Reviewed-by: Fangrui Song <i@maskray.me>
(perhaps binutils doesn't use this...)
  
Alexander Monakov Jan. 9, 2022, 8:13 a.m. UTC | #2
On Sat, 8 Jan 2022, Fangrui Song wrote:

> Thank you so much for the heroic work.
> I cannot think of other items.

I am bummed that Rich Felker's solution for compatibility (sane diagnostic
for loading a new PIE/DSO with old ld.so) was not accepted:
https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html

(add just one new relocation to indicate presence of SHT_RELR)

It would have been a nice solution that works the same across all OS'es,
without requiring changes in ld.so. Was there something wrong with it?

Alexander
  
Nick Clifton Jan. 11, 2022, 10:13 a.m. UTC | #3
Hi H.J.

   The patch set looks good to me, but there is one problem.  With the
   set applied there is a new linker testsuite regression for non x86
   ELF based targets (eg: s390-linux, xtensa-elf, aarch64-linux-gnu to
   mention just a few):

     Executing on host: sh -c {./ld-new -o tmpdir/symbolic-func.so
      -z norelro -L/ld/testsuite/ld-elf -shared -Bsymbolic-functions
      -z nopack-relative-relocs tmpdir/symbolic-func.o  2>&1}
       /dev/null ld.tmp (timeout = 300)
     spawn [open ...]

     ./ld-new: warning: -z nopack-relative-relocs ignored
     ./ld-new: warning: -z nopack-relative-relocs ignored
     FAIL: -Bsymbolic-functions

   Please could you investigate and fix this issue ?

Cheers
   Nick
  
H.J. Lu Jan. 11, 2022, 2:08 p.m. UTC | #4
On Tue, Jan 11, 2022 at 2:13 AM Nick Clifton <nickc@redhat.com> wrote:
>
> Hi H.J.
>
>    The patch set looks good to me, but there is one problem.  With the
>    set applied there is a new linker testsuite regression for non x86
>    ELF based targets (eg: s390-linux, xtensa-elf, aarch64-linux-gnu to
>    mention just a few):
>
>      Executing on host: sh -c {./ld-new -o tmpdir/symbolic-func.so
>       -z norelro -L/ld/testsuite/ld-elf -shared -Bsymbolic-functions
>       -z nopack-relative-relocs tmpdir/symbolic-func.o  2>&1}
>        /dev/null ld.tmp (timeout = 300)
>      spawn [open ...]
>
>      ./ld-new: warning: -z nopack-relative-relocs ignored
>      ./ld-new: warning: -z nopack-relative-relocs ignored
>      FAIL: -Bsymbolic-functions
>
>    Please could you investigate and fix this issue ?
>

Fixed in the v3 patch:

https://sourceware.org/pipermail/binutils/2022-January/119292.html

by

Changes in v3:

1. Set DT_RELR_LDFLAGS, DT_RELR_CC_LDFLAGS, NO_DT_RELR_LDFLAGS and
NO_DT_RELR_CC_LDFLAGS to empty for non-Linux/x86 targets.
2. Run x86 DT_RELR tests only for Linux/x86 targets.

Thanks.
  
Nick Clifton Jan. 12, 2022, 12:33 p.m. UTC | #5
Hi H.J.

> Fixed in the v3 patch:
> 
> https://sourceware.org/pipermail/binutils/2022-January/119292.html
> 
> by
> 
> Changes in v3:
> 
> 1. Set DT_RELR_LDFLAGS, DT_RELR_CC_LDFLAGS, NO_DT_RELR_LDFLAGS and
> NO_DT_RELR_CC_LDFLAGS to empty for non-Linux/x86 targets.
> 2. Run x86 DT_RELR tests only for Linux/x86 targets.

Patch series approved  - please apply.

Cheers
   Nick
  
Fangrui Song Jan. 13, 2022, 2:54 a.m. UTC | #6
On 2022-01-09, Alexander Monakov wrote:
>On Sat, 8 Jan 2022, Fangrui Song wrote:
>
>> Thank you so much for the heroic work.
>> I cannot think of other items.
>
>I am bummed that Rich Felker's solution for compatibility (sane diagnostic
>for loading a new PIE/DSO with old ld.so) was not accepted:
>https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html
>
>(add just one new relocation to indicate presence of SHT_RELR)
>
>It would have been a nice solution that works the same across all OS'es,
>without requiring changes in ld.so. Was there something wrong with it?
>
>Alexander

Hi Alexander, I think the .gnu.version_r approach is better.
For FreeBSD/musl/etc, there is no version node called GLIBC_2*,
ld.bfd -z pack-relative-relocs will not add anything.

For a relocation approach, every psABI needs to define which relocation
type is used as the available indicator (something like
R_*_GNU_VTENTRY). It's too much work for something only glibc needs.



Now that the ld patch series has landed on
https://sourceware.org/git/?p=binutils-gdb.git, what's the next step for the
glibc patch? The current diff I have is
https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/maskray/relr
I think making ld.so/libc.so themselves compatible with DT_RELR can
be separate changes (I personally do not know enough ld.so to contribute
it...)
  
H.J. Lu Jan. 13, 2022, 3 a.m. UTC | #7
On Wed, Jan 12, 2022 at 6:54 PM Fangrui Song <i@maskray.me> wrote:
>
> On 2022-01-09, Alexander Monakov wrote:
> >On Sat, 8 Jan 2022, Fangrui Song wrote:
> >
> >> Thank you so much for the heroic work.
> >> I cannot think of other items.
> >
> >I am bummed that Rich Felker's solution for compatibility (sane diagnostic
> >for loading a new PIE/DSO with old ld.so) was not accepted:
> >https://sourceware.org/pipermail/libc-alpha/2021-November/133313.html
> >
> >(add just one new relocation to indicate presence of SHT_RELR)
> >
> >It would have been a nice solution that works the same across all OS'es,
> >without requiring changes in ld.so. Was there something wrong with it?
> >
> >Alexander
>
> Hi Alexander, I think the .gnu.version_r approach is better.
> For FreeBSD/musl/etc, there is no version node called GLIBC_2*,
> ld.bfd -z pack-relative-relocs will not add anything.
>
> For a relocation approach, every psABI needs to define which relocation
> type is used as the available indicator (something like
> R_*_GNU_VTENTRY). It's too much work for something only glibc needs.
>
>
>
> Now that the ld patch series has landed on
> https://sourceware.org/git/?p=binutils-gdb.git, what's the next step for the
> glibc patch? The current diff I have is
> https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/maskray/relr
> I think making ld.so/libc.so themselves compatible with DT_RELR can
> be separate changes (I personally do not know enough ld.so to contribute
> it...)

It is too late for glibc 2.35.  It should go in after 2.35 is branched.
My DT_RELR branch is based on your patch:

https://gitlab.com/x86-glibc/glibc/-/commits/users/hjl/relr/master

My branch requires -z pack-relative-relocs to enable DT_RELR
and supports zero DT_RELA/DT_REL values generated by ld.