[0/10] ld: Implement DT_RELR for x86

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

Message

H.J. Lu Jan. 7, 2022, 7:06 p.m. UTC
  Hi Nick,

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


H.J.
---
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.

To prepare for DT_RELR implementation on these targets, extract
_bfd_elf_link_iterate_on_relocs from _bfd_elf_link_check_relocs so
that a backend can scan relocations in elf_backend_always_size_sections

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 (10):
  ld: Extract _bfd_elf_link_iterate_on_relocs
  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                                 |   19 +-
 bfd/elf.c                                     |   22 +-
 bfd/elf32-i386.c                              |  112 +-
 bfd/elf64-x86-64.c                            |  118 +-
 bfd/elflink.c                                 |  191 ++-
 bfd/elfxx-target.h                            |    8 +
 bfd/elfxx-x86.c                               | 1022 +++++++++++++++++
 bfd/elfxx-x86.h                               |  197 +++-
 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                                    |   16 +-
 ld/ldelf.c                                    |   13 +
 ld/ldelfgen.c                                 |    3 +-
 ld/lexsup.c                                   |    1 +
 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              |    9 +
 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-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/export-class.exp         |    2 +-
 ld/testsuite/ld-i386/i386.exp                 |   20 +-
 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/pr27491-1a.d             |    4 +-
 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/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/pr27491-1a.d           |    4 +-
 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             |   65 +-
 81 files changed, 1931 insertions(+), 234 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-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
  

Comments

Fangrui Song Jan. 7, 2022, 11:45 p.m. UTC | #1
On 2022-01-07, H.J. Lu via Libc-alpha wrote:
>Hi Nick,
>
>I'd like to enable DT_RELR for x86 in binutils 2.38.
>
>
>H.J.
>---

Thanks for the patch!

Is the Clang crash
https://sourceware.org/pipermail/libc-alpha/2022-January/134992.html
fixed now?


> 10/10 ld: Add glibc dependency for DT_RELR
>
> if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))

Thanks for adding the GLIBC_ABI_DT_RELR verneed only if GLIBC_2.* exists, this will make
musl/FreeBSD/NetBSD/etc happy.
  
H.J. Lu Jan. 7, 2022, 11:56 p.m. UTC | #2
On Fri, Jan 7, 2022 at 3:46 PM Fangrui Song <maskray@google.com> wrote:
>
> On 2022-01-07, H.J. Lu via Libc-alpha wrote:
> >Hi Nick,
> >
> >I'd like to enable DT_RELR for x86 in binutils 2.38.
> >
> >
> >H.J.
> >---
>
> Thanks for the patch!
>
> Is the Clang crash
> https://sourceware.org/pipermail/libc-alpha/2022-January/134992.html
> fixed now?
>

It should be fixed.  Please try my current DT_RELR branch.

> > 10/10 ld: Add glibc dependency for DT_RELR
> >
> > if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
>
> Thanks for adding the GLIBC_ABI_DT_RELR verneed only if GLIBC_2.* exists, this will make
> musl/FreeBSD/NetBSD/etc happy.
  
Fangrui Song Jan. 8, 2022, 1:31 a.m. UTC | #3
On 2022-01-07, H.J. Lu via Binutils wrote:
>On Fri, Jan 7, 2022 at 3:46 PM Fangrui Song <maskray@google.com> wrote:
>>
>> On 2022-01-07, H.J. Lu via Libc-alpha wrote:
>> >Hi Nick,
>> >
>> >I'd like to enable DT_RELR for x86 in binutils 2.38.
>> >
>> >
>> >H.J.
>> >---
>>
>> Thanks for the patch!
>>
>> Is the Clang crash
>> https://sourceware.org/pipermail/libc-alpha/2022-January/134992.html
>> fixed now?
>>
>
>It should be fixed.  Please try my current DT_RELR branch.

Thanks. It works.

% rm /tmp/out/custom1/clang
% ninja -C /tmp/out/custom1/clang -v  # find the linker command line
% <linker-command-line> -Wl,--reproduce=/tmp/clang-relassert.tar
% cd /tmp && tar xf clang-relassert.tar && cd clang-relassert
# Remove --chroot from response.txt

# Managed to compile a file with the linked clang 
% ~/Dev/binutils-gdb/out/release/ld/ld-new -z pack-relative-relocs @response.txt -o bfd.relr 
% LD_LIBRARY_PATH=/tmp/glibc/lld/lib:/usr/lib/x86_64-linux-gnu /tmp/glibc/lld/lib/ld-linux-x86-64.so.2 ./bfd.relr -c /tmp/c/a.c -O2 


There are still quite a few even-address R_X86_64_RELATIVE relocations.
Any idea why they are present?


% ~/Dev/binutils-gdb/out/release/binutils/readelf -r bfd.relr
...
Relocation section '.rela.dyn' at offset 0x5fb400 contains 3133 entries:
   Offset          Info           Type           Sym. Value    Sym. Name + Addend
000009902608  000000000008 R_X86_64_RELATIVE                    9281940
000009902610  000000000008 R_X86_64_RELATIVE                    7a4d565
000009902618  000000000008 R_X86_64_RELATIVE                    91acf98
...
Relocation section '.relr.dyn' at offset 0x60f6e0 contains 19910 entries:
   535577 offsets
0000000008f83f58
0000000008f83f60
0000000008f83f68
...

>
>> > 10/10 ld: Add glibc dependency for DT_RELR
>> >
>> > if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
>>
>> Thanks for adding the GLIBC_ABI_DT_RELR verneed only if GLIBC_2.* exists, this will make
>> musl/FreeBSD/NetBSD/etc happy.

Does your DT_RELR patch have something like this?

+    // Don't allow the section to shrink, otherwise the size of the section can
+    // oscillate infinitely. Trailing 1s do not decode to more relocations.
+    if (entries_.size() < old_size)
+      entries_.resize(old_size, 1);
  
H.J. Lu Jan. 8, 2022, 1:55 a.m. UTC | #4
On Fri, Jan 7, 2022 at 5:31 PM Fangrui Song <i@maskray.me> wrote:
>
> On 2022-01-07, H.J. Lu via Binutils wrote:
> >On Fri, Jan 7, 2022 at 3:46 PM Fangrui Song <maskray@google.com> wrote:
> >>
> >> On 2022-01-07, H.J. Lu via Libc-alpha wrote:
> >> >Hi Nick,
> >> >
> >> >I'd like to enable DT_RELR for x86 in binutils 2.38.
> >> >
> >> >
> >> >H.J.
> >> >---
> >>
> >> Thanks for the patch!
> >>
> >> Is the Clang crash
> >> https://sourceware.org/pipermail/libc-alpha/2022-January/134992.html
> >> fixed now?
> >>
> >
> >It should be fixed.  Please try my current DT_RELR branch.
>
> Thanks. It works.
>
> % rm /tmp/out/custom1/clang
> % ninja -C /tmp/out/custom1/clang -v  # find the linker command line
> % <linker-command-line> -Wl,--reproduce=/tmp/clang-relassert.tar
> % cd /tmp && tar xf clang-relassert.tar && cd clang-relassert
> # Remove --chroot from response.txt
>
> # Managed to compile a file with the linked clang
> % ~/Dev/binutils-gdb/out/release/ld/ld-new -z pack-relative-relocs @response.txt -o bfd.relr
> % LD_LIBRARY_PATH=/tmp/glibc/lld/lib:/usr/lib/x86_64-linux-gnu /tmp/glibc/lld/lib/ld-linux-x86-64.so.2 ./bfd.relr -c /tmp/c/a.c -O2
>
>
> There are still quite a few even-address R_X86_64_RELATIVE relocations.
> Any idea why they are present?

ld can generate R_X86_64_RELATIVE in elf_x86_64_finish_dynamic_symbol:

     else if (bfd_link_pic (info)
               && SYMBOL_REFERENCES_LOCAL_P (info, h))
        {
          if (!SYMBOL_DEFINED_NON_SHARED_P (h))
            return false;
          BFD_ASSERT((h->got.offset & 1) != 0);
          rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
          rela.r_addend = (h->root.u.def.value
                           + h->root.u.def.section->output_section->vma
                           + h->root.u.def.section->output_offset);
          relative_reloc_name = "R_X86_64_RELATIVE";
        }

This case isn't handled yet.

>
> % ~/Dev/binutils-gdb/out/release/binutils/readelf -r bfd.relr
> ...
> Relocation section '.rela.dyn' at offset 0x5fb400 contains 3133 entries:
>    Offset          Info           Type           Sym. Value    Sym. Name + Addend
> 000009902608  000000000008 R_X86_64_RELATIVE                    9281940
> 000009902610  000000000008 R_X86_64_RELATIVE                    7a4d565
> 000009902618  000000000008 R_X86_64_RELATIVE                    91acf98
> ...
> Relocation section '.relr.dyn' at offset 0x60f6e0 contains 19910 entries:
>    535577 offsets
> 0000000008f83f58
> 0000000008f83f60
> 0000000008f83f68
> ...
>
> >
> >> > 10/10 ld: Add glibc dependency for DT_RELR
> >> >
> >> > if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
> >>
> >> Thanks for adding the GLIBC_ABI_DT_RELR verneed only if GLIBC_2.* exists, this will make
> >> musl/FreeBSD/NetBSD/etc happy.
>
> Does your DT_RELR patch have something like this?
>
> +    // Don't allow the section to shrink, otherwise the size of the section can
> +    // oscillate infinitely. Trailing 1s do not decode to more relocations.
> +    if (entries_.size() < old_size)
> +      entries_.resize(old_size, 1);

     if (dt_relr_bitmap_count > new_count)
        {
          /* Don't shrink the DT_RELR section size to avoid section
             layout oscillation.  Instead, pad the DT_RELR bitmap with
             1s which do not decode to more relocations.  */

          htab->dt_relr_bitmap.count = dt_relr_bitmap_count;
          count = dt_relr_bitmap_count - new_count;
          for (i = 0; i < count; i++)
            htab->dt_relr_bitmap.u.elf64[new_count + i] = 1;
        }
  
H.J. Lu Jan. 8, 2022, 6:30 p.m. UTC | #5
On Fri, Jan 7, 2022 at 5:55 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Fri, Jan 7, 2022 at 5:31 PM Fangrui Song <i@maskray.me> wrote:
> >
> > On 2022-01-07, H.J. Lu via Binutils wrote:
> > >On Fri, Jan 7, 2022 at 3:46 PM Fangrui Song <maskray@google.com> wrote:
> > >>
> > >> On 2022-01-07, H.J. Lu via Libc-alpha wrote:
> > >> >Hi Nick,
> > >> >
> > >> >I'd like to enable DT_RELR for x86 in binutils 2.38.
> > >> >
> > >> >
> > >> >H.J.
> > >> >---
> > >>
> > >> Thanks for the patch!
> > >>
> > >> Is the Clang crash
> > >> https://sourceware.org/pipermail/libc-alpha/2022-January/134992.html
> > >> fixed now?
> > >>
> > >
> > >It should be fixed.  Please try my current DT_RELR branch.
> >
> > Thanks. It works.
> >
> > % rm /tmp/out/custom1/clang
> > % ninja -C /tmp/out/custom1/clang -v  # find the linker command line
> > % <linker-command-line> -Wl,--reproduce=/tmp/clang-relassert.tar
> > % cd /tmp && tar xf clang-relassert.tar && cd clang-relassert
> > # Remove --chroot from response.txt
> >
> > # Managed to compile a file with the linked clang
> > % ~/Dev/binutils-gdb/out/release/ld/ld-new -z pack-relative-relocs @response.txt -o bfd.relr
> > % LD_LIBRARY_PATH=/tmp/glibc/lld/lib:/usr/lib/x86_64-linux-gnu /tmp/glibc/lld/lib/ld-linux-x86-64.so.2 ./bfd.relr -c /tmp/c/a.c -O2
> >
> >
> > There are still quite a few even-address R_X86_64_RELATIVE relocations.
> > Any idea why they are present?
>
> ld can generate R_X86_64_RELATIVE in elf_x86_64_finish_dynamic_symbol:
>
>      else if (bfd_link_pic (info)
>                && SYMBOL_REFERENCES_LOCAL_P (info, h))
>         {
>           if (!SYMBOL_DEFINED_NON_SHARED_P (h))
>             return false;
>           BFD_ASSERT((h->got.offset & 1) != 0);
>           rela.r_info = htab->r_info (0, R_X86_64_RELATIVE);
>           rela.r_addend = (h->root.u.def.value
>                            + h->root.u.def.section->output_section->vma
>                            + h->root.u.def.section->output_offset);
>           relative_reloc_name = "R_X86_64_RELATIVE";
>         }
>
> This case isn't handled yet.

Fixed in the v2 patch.

> >
> > % ~/Dev/binutils-gdb/out/release/binutils/readelf -r bfd.relr
> > ...
> > Relocation section '.rela.dyn' at offset 0x5fb400 contains 3133 entries:
> >    Offset          Info           Type           Sym. Value    Sym. Name + Addend
> > 000009902608  000000000008 R_X86_64_RELATIVE                    9281940
> > 000009902610  000000000008 R_X86_64_RELATIVE                    7a4d565
> > 000009902618  000000000008 R_X86_64_RELATIVE                    91acf98
> > ...
> > Relocation section '.relr.dyn' at offset 0x60f6e0 contains 19910 entries:
> >    535577 offsets
> > 0000000008f83f58
> > 0000000008f83f60
> > 0000000008f83f68
> > ...
> >
> > >
> > >> > 10/10 ld: Add glibc dependency for DT_RELR
> > >> >
> > >> > if (!glibc_bfd && startswith (a->vna_nodename, "GLIBC_2."))
> > >>
> > >> Thanks for adding the GLIBC_ABI_DT_RELR verneed only if GLIBC_2.* exists, this will make
> > >> musl/FreeBSD/NetBSD/etc happy.
> >
> > Does your DT_RELR patch have something like this?
> >
> > +    // Don't allow the section to shrink, otherwise the size of the section can
> > +    // oscillate infinitely. Trailing 1s do not decode to more relocations.
> > +    if (entries_.size() < old_size)
> > +      entries_.resize(old_size, 1);
>
>      if (dt_relr_bitmap_count > new_count)
>         {
>           /* Don't shrink the DT_RELR section size to avoid section
>              layout oscillation.  Instead, pad the DT_RELR bitmap with
>              1s which do not decode to more relocations.  */
>
>           htab->dt_relr_bitmap.count = dt_relr_bitmap_count;
>           count = dt_relr_bitmap_count - new_count;
>           for (i = 0; i < count; i++)
>             htab->dt_relr_bitmap.u.elf64[new_count + i] = 1;
>         }
>
>
> --
> H.J.