diff mbox series

[uclibc-ng-devel] Re: [PATCH] ld.so: Add support of DT_RELR relocation format.

Message ID CA+RUeSo6ynbs-OuZcTCC_uA1oo1yuUbXP6KtJRGsA=EiRJgB5g@mail.gmail.com
State Accepted
Headers show
Series [uclibc-ng-devel] Re: [PATCH] ld.so: Add support of DT_RELR relocation format. | expand

Commit Message

Dmitry Chestnykh Feb. 7, 2024, 9:30 a.m. UTC
Can you test please a new version of the patch?
I have wrapped DL_RELOCATE_RELR() with #if !define(__FDPIC__).



From f805b20fac1c77a3aa021825701ba36735cf3060 Mon Sep 17 00:00:00 2001
From: Dmitry Chestnykh <dm.chestnykh@gmail.com>
Date: Tue, 6 Feb 2024 09:13:41 +0300
Subject: [PATCH v3] ld.so: Add support of DT_RELR relocation format.

Nowadays modern libcs like Glibc and musl currently
support processing of RELATIVE relocations compressed
with DT_RELR format. However I have noticed that uClibc-ng
doesn't support this feature and if the source will be linked with
`-Wl,-z,pack-relative-relos` (bfd) or `-Wl,--pack-dyn-relocs=relr`
(lld) then ld.so cannot properly load the produced DSO.
This patch is intended to fix this issue and adds applying
of DT_RELR relative relocation.

Signed-off-by: Dmitry Chestnykh <dm.chestnykh@gmail.com>
---
 include/elf.h                          |  8 ++++-
 ldso/include/dl-elf.h                  | 41 ++++++++++++++++++++++++++
 ldso/ldso/dl-elf.c                     |  5 ++++
 ldso/ldso/dl-startup.c                 |  5 ++++
 libc/misc/internals/reloc_static_pie.c |  3 ++
 5 files changed, 61 insertions(+), 1 deletion(-)

Comments

Waldemar Brodkorb Feb. 9, 2024, 5:56 p.m. UTC | #1
Hi Dmitry,
Dmitriy Chestnykh wrote,

> Can you test please a new version of the patch?
> I have wrapped DL_RELOCATE_RELR() with #if !define(__FDPIC__).
 
That worked now even for FDPIC toolchains.
Thanks.
Applied and pushed,
 best regards
  Waldemar
 
> 
> From f805b20fac1c77a3aa021825701ba36735cf3060 Mon Sep 17 00:00:00 2001
> From: Dmitry Chestnykh <dm.chestnykh@gmail.com>
> Date: Tue, 6 Feb 2024 09:13:41 +0300
> Subject: [PATCH v3] ld.so: Add support of DT_RELR relocation format.
> 
> Nowadays modern libcs like Glibc and musl currently
> support processing of RELATIVE relocations compressed
> with DT_RELR format. However I have noticed that uClibc-ng
> doesn't support this feature and if the source will be linked with
> `-Wl,-z,pack-relative-relos` (bfd) or `-Wl,--pack-dyn-relocs=relr`
> (lld) then ld.so cannot properly load the produced DSO.
> This patch is intended to fix this issue and adds applying
> of DT_RELR relative relocation.
> 
> Signed-off-by: Dmitry Chestnykh <dm.chestnykh@gmail.com>
> ---
>  include/elf.h                          |  8 ++++-
>  ldso/include/dl-elf.h                  | 41 ++++++++++++++++++++++++++
>  ldso/ldso/dl-elf.c                     |  5 ++++
>  ldso/ldso/dl-startup.c                 |  5 ++++
>  libc/misc/internals/reloc_static_pie.c |  3 ++
>  5 files changed, 61 insertions(+), 1 deletion(-)
> 
> diff --git a/include/elf.h b/include/elf.h
> index b7edbade2..c2efa9978 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -60,6 +60,9 @@ typedef uint16_t Elf64_Section;
>  typedef Elf32_Half Elf32_Versym;
>  typedef Elf64_Half Elf64_Versym;
>  
> +/* Type for relative relocations in DT_RELR format */
> +typedef Elf32_Word  Elf32_Relr;
> +typedef Elf64_Xword Elf64_Relr;
>  
>  /* The ELF file header.  This appears at the start of every ELF file.  */
>  
> @@ -818,7 +821,10 @@ typedef struct
>  #define DT_ENCODING    32              /* Start of encoded range */
>  #define DT_PREINIT_ARRAY 32            /* Array with addresses of preinit fct*
> /
>  #define DT_PREINIT_ARRAYSZ 33          /* size in bytes of DT_PREINIT_ARRAY */
> -#define        DT_NUM          34              /* Number used */
> +#define DT_RELRSZ          35          /* Size in bytes, of DT_RELR table */
> +#define DT_RELR            36          /* Address of Relr relocs */
> +#define DT_RELRENT         37          /* Size in bytes of one DT_RELR entry *
> /
> +#define DT_NUM            38           /* Number used */
>  #define DT_LOOS                0x6000000d      /* Start of OS-specific */
>  #define DT_HIOS                0x6ffff000      /* End of OS-specific */
>  #define DT_LOPROC      0x70000000      /* Start of processor-specific */
> diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
> index 2b99958d9..7d514c0f5 100644
> --- a/ldso/include/dl-elf.h
> +++ b/ldso/include/dl-elf.h
> @@ -250,5 +250,46 @@ unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt,
> unsigned long dynamic_info
>                     (((X) & PF_W) ? PROT_WRITE : 0) | \
>                     (((X) & PF_X) ? PROT_EXEC : 0))
>  
> +/* FDPIC ABI don't use relative relocations */
> +#if !defined(__FDPIC__)
> +/* Apply relocations in DT_RELR format */
> +#define DL_DO_RELOCATE_RELR(load_addr, relr_start, relr_end) \
> +               do { \
> +                       const ElfW(Relr) *relr = 0; \
> +                       ElfW(Addr) *reloc_addr = 0; \
> +                       for (relr = relr_start; relr < relr_end; relr++) { \
> +                               ElfW(Relr) relr_entry = *relr; \
> +                               if (!(relr_entry & 1)) \
> +                               { \
> +                                       reloc_addr = (ElfW(Addr) *)
> DL_RELOC_ADDR(load_addr, relr_entry); \
> +                                       *reloc_addr = (ElfW(Addr))DL_RELOC_ADDR
> (load_addr, reloc_addr); \
> +                                       reloc_addr++; \
> +                               } \
> +                               else \
> +                               { \
> +                                       for (long int i = 0; (relr_entry >>= 1)
> != 0; ++i) { \
> +                                               if ((relr_entry & 1) != 0) \
> +                                                       reloc_addr[i] = (ElfW
> (Addr))DL_RELOC_ADDR(load_addr, reloc_addr[i]); \
> +                                       } \
> +                                       reloc_addr += CHAR_BIT * sizeof(ElfW
> (Relr)) - 1; \
> +                               } \
> +                       } \
> +               } while (0);
> +
> +/* The macro to prepare data for the above DL_DO_RELOCATE_RELR */
> +#define DL_RELOCATE_RELR(dyn) \
> +               do { \
> +                       if (dyn->dynamic_info[DT_RELRENT]) \
> +                               _dl_assert(dyn->dynamic_info[DT_RELRENT] ==
> sizeof(ElfW(Relr))); \
> +                       if (dyn->dynamic_info[DT_RELR] && \
> +                               dyn->dynamic_info[DT_RELRSZ]) { \
> +                               ElfW(Relr) *relr_start = (ElfW(Relr) *)((ElfW
> (Addr))dyn->loadaddr + (ElfW(Addr))dyn->dynamic_info[DT_RELR]); \
> +                               ElfW(Relr) *relr_end = (ElfW(Relr) *)((const
> char *)relr_start + dyn->dynamic_info[DT_RELRSZ]); \
> +                               _dl_if_debug_dprint("Relocating DT_RELR in %s:
> start:%p, end:%p\n", \
> +                                                   dyn->libname, (void *)
> relr_start, (void *)relr_end); \
> +                               DL_DO_RELOCATE_RELR(dyn->loadaddr, relr_start,
> relr_end); \
> +                       } \
> +               } while (0);
> +#endif /* __FDPIC__ */
>  
>  #endif /* _DL_ELF_H */
> diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
> index 8210a012e..27907d355 100644
> --- a/ldso/ldso/dl-elf.c
> +++ b/ldso/ldso/dl-elf.c
> @@ -1027,6 +1027,11 @@ int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem
> *scope, int now_flag)
>                 return goof;
>         }
>  
> +#if !defined(__FDPIC__)
> +       /* Process DT_RELR relative relocations */
> +       DL_RELOCATE_RELR(tpnt);
> +#endif
> +
>         reloc_size = tpnt->dynamic_info[DT_RELOC_TABLE_SIZE];
>  /* On some machines, notably SPARC & PPC, DT_REL* includes DT_JMPREL in its
>     range.  Note that according to the ELF spec, this is completely legal! */
> diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
> index 989711fcc..d80ee75ea 100644
> --- a/ldso/ldso/dl-startup.c
> +++ b/ldso/ldso/dl-startup.c
> @@ -264,6 +264,11 @@ DL_START(unsigned long args)
>            that once we are done, we have considerably more flexibility. */
>         SEND_EARLY_STDERR_DEBUG("About to do library loader relocations\n");
>  
> +#if !defined(__FDPIC__)
> +       /* Process DT_RELR relative relocations */
> +       DL_RELOCATE_RELR(tpnt);
> +#endif
> +
>         {
>                 int indx;
>  #if defined(ELF_MACHINE_PLTREL_OVERLAP)
> diff --git a/libc/misc/internals/reloc_static_pie.c b/libc/misc/internals/
> reloc_static_pie.c
> index ab1923024..81af7d666 100644
> --- a/libc/misc/internals/reloc_static_pie.c
> +++ b/libc/misc/internals/reloc_static_pie.c
> @@ -53,6 +53,9 @@ reloc_static_pie(ElfW(Addr) load_addr)
>         PERFORM_BOOTSTRAP_GOT(tpnt);
>  #endif
>  
> +#if !defined(__FDPIC__)
> +    DL_RELOCATE_RELR(tpnt);
> +#endif
>  
>  #if defined(ELF_MACHINE_PLTREL_OVERLAP)
>  # define INDX_MAX 1
> --
> 2.43.0
> 
> ср, 7 февр. 2024 г. в 12:20, Waldemar Brodkorb <wbx@openadk.org>:
> 
>     Hi Dmitry,
>     Dmitriy Chestnykh wrote,
> 
>     > But I know that FDPIC ABIs don't use relative relocations because FDPIC
>     don't
>     > have single base address.
>     > Probably I can detect whether the toolchain is FDPIC by some predefined
>     > compiler macroses and wrap DL_RELOCATE_RELR with
>     > #ifndef FDPIC
>     > #endif.
>     > Would this be a suitable solution?
> 
>     Yes, __FDPIC__ is defined.
> 
>     best regards
>      Waldemar
> 
>
diff mbox series

Patch

diff --git a/include/elf.h b/include/elf.h
index b7edbade2..c2efa9978 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -60,6 +60,9 @@  typedef uint16_t Elf64_Section;
 typedef Elf32_Half Elf32_Versym;
 typedef Elf64_Half Elf64_Versym;

+/* Type for relative relocations in DT_RELR format */
+typedef Elf32_Word  Elf32_Relr;
+typedef Elf64_Xword Elf64_Relr;

 /* The ELF file header.  This appears at the start of every ELF file.  */

@@ -818,7 +821,10 @@  typedef struct
 #define DT_ENCODING    32              /* Start of encoded range */
 #define DT_PREINIT_ARRAY 32            /* Array with addresses of preinit
fct*/
 #define DT_PREINIT_ARRAYSZ 33          /* size in bytes of
DT_PREINIT_ARRAY */
-#define        DT_NUM          34              /* Number used */
+#define DT_RELRSZ          35          /* Size in bytes, of DT_RELR table
*/
+#define DT_RELR            36          /* Address of Relr relocs */
+#define DT_RELRENT         37          /* Size in bytes of one DT_RELR
entry */
+#define DT_NUM            38           /* Number used */
 #define DT_LOOS                0x6000000d      /* Start of OS-specific */
 #define DT_HIOS                0x6ffff000      /* End of OS-specific */
 #define DT_LOPROC      0x70000000      /* Start of processor-specific */
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index 2b99958d9..7d514c0f5 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -250,5 +250,46 @@  unsigned int __dl_parse_dynamic_info(ElfW(Dyn) *dpnt,
unsigned long dynamic_info
                    (((X) & PF_W) ? PROT_WRITE : 0) | \
                    (((X) & PF_X) ? PROT_EXEC : 0))

+/* FDPIC ABI don't use relative relocations */
+#if !defined(__FDPIC__)
+/* Apply relocations in DT_RELR format */
+#define DL_DO_RELOCATE_RELR(load_addr, relr_start, relr_end) \
+               do { \
+                       const ElfW(Relr) *relr = 0; \
+                       ElfW(Addr) *reloc_addr = 0; \
+                       for (relr = relr_start; relr < relr_end; relr++) { \
+                               ElfW(Relr) relr_entry = *relr; \
+                               if (!(relr_entry & 1)) \
+                               { \
+                                       reloc_addr = (ElfW(Addr)
*)DL_RELOC_ADDR(load_addr, relr_entry); \
+                                       *reloc_addr =
(ElfW(Addr))DL_RELOC_ADDR(load_addr, reloc_addr); \
+                                       reloc_addr++; \
+                               } \
+                               else \
+                               { \
+                                       for (long int i = 0; (relr_entry
>>= 1) != 0; ++i) { \
+                                               if ((relr_entry & 1) != 0) \
+                                                       reloc_addr[i] =
(ElfW(Addr))DL_RELOC_ADDR(load_addr, reloc_addr[i]); \
+                                       } \
+                                       reloc_addr += CHAR_BIT *
sizeof(ElfW(Relr)) - 1; \
+                               } \
+                       } \
+               } while (0);
+
+/* The macro to prepare data for the above DL_DO_RELOCATE_RELR */
+#define DL_RELOCATE_RELR(dyn) \
+               do { \
+                       if (dyn->dynamic_info[DT_RELRENT]) \
+                               _dl_assert(dyn->dynamic_info[DT_RELRENT] ==
sizeof(ElfW(Relr))); \
+                       if (dyn->dynamic_info[DT_RELR] && \
+                               dyn->dynamic_info[DT_RELRSZ]) { \
+                               ElfW(Relr) *relr_start = (ElfW(Relr)
*)((ElfW(Addr))dyn->loadaddr + (ElfW(Addr))dyn->dynamic_info[DT_RELR]); \
+                               ElfW(Relr) *relr_end = (ElfW(Relr)
*)((const char *)relr_start + dyn->dynamic_info[DT_RELRSZ]); \
+                               _dl_if_debug_dprint("Relocating DT_RELR in
%s: start:%p, end:%p\n", \
+                                                   dyn->libname, (void
*)relr_start, (void *)relr_end); \
+                               DL_DO_RELOCATE_RELR(dyn->loadaddr,
relr_start, relr_end); \
+                       } \
+               } while (0);
+#endif /* __FDPIC__ */

 #endif /* _DL_ELF_H */
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 8210a012e..27907d355 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -1027,6 +1027,11 @@  int _dl_fixup(struct dyn_elf *rpnt, struct
r_scope_elem *scope, int now_flag)
                return goof;
        }

+#if !defined(__FDPIC__)
+       /* Process DT_RELR relative relocations */
+       DL_RELOCATE_RELR(tpnt);
+#endif
+
        reloc_size = tpnt->dynamic_info[DT_RELOC_TABLE_SIZE];
 /* On some machines, notably SPARC & PPC, DT_REL* includes DT_JMPREL in its
    range.  Note that according to the ELF spec, this is completely legal!
*/
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index 989711fcc..d80ee75ea 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -264,6 +264,11 @@  DL_START(unsigned long args)
           that once we are done, we have considerably more flexibility. */
        SEND_EARLY_STDERR_DEBUG("About to do library loader relocations\n");

+#if !defined(__FDPIC__)
+       /* Process DT_RELR relative relocations */
+       DL_RELOCATE_RELR(tpnt);
+#endif
+
        {
                int indx;
 #if defined(ELF_MACHINE_PLTREL_OVERLAP)
diff --git a/libc/misc/internals/reloc_static_pie.c
b/libc/misc/internals/reloc_static_pie.c
index ab1923024..81af7d666 100644
--- a/libc/misc/internals/reloc_static_pie.c
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -53,6 +53,9 @@  reloc_static_pie(ElfW(Addr) load_addr)
        PERFORM_BOOTSTRAP_GOT(tpnt);
 #endif

+#if !defined(__FDPIC__)
+    DL_RELOCATE_RELR(tpnt);
+#endif

 #if defined(ELF_MACHINE_PLTREL_OVERLAP)
 # define INDX_MAX 1