diff mbox series

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

Message ID 20240206124538.27667-1-dm.chestnykh@gmail.com
State Superseded
Headers show
Series [uclibc-ng-devel] ld.so: Add support of DT_RELR relocation format. | expand

Commit Message

Dmitry Chestnykh Feb. 6, 2024, 12:45 p.m. UTC
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                  | 38 ++++++++++++++++++++++++++
 ldso/ldso/dl-elf.c                     |  3 ++
 ldso/ldso/dl-startup.c                 |  3 ++
 libc/misc/internals/reloc_static_pie.c |  1 +
 5 files changed, 52 insertions(+), 1 deletion(-)

Comments

Waldemar Brodkorb Feb. 7, 2024, 8:53 a.m. UTC | #1
Hi Dmitry,

thanks for the patch.
Unfortunately it breaks ARM FDPIC toolchain building:
ldso/ldso/dl-startup.c: In function '_dl_start':
ldso/ldso/dl-startup.c:268:9: error: aggregate value used where an
integer was expected
  268 |         DL_RELOCATE_RELR(tpnt);
        |         ^~~~~~~~~~~~~~~~

You could use OpenADK to produce such a toolchain.

Any idea what is wrong?

best regards
 Waldemar

Dmitry Chestnykh wrote,

> 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                  | 38 ++++++++++++++++++++++++++
>  ldso/ldso/dl-elf.c                     |  3 ++
>  ldso/ldso/dl-startup.c                 |  3 ++
>  libc/misc/internals/reloc_static_pie.c |  1 +
>  5 files changed, 52 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..10b895733 100644
> --- a/ldso/include/dl-elf.h
> +++ b/ldso/include/dl-elf.h
> @@ -250,5 +250,43 @@ 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))
>  
> +/* 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 /* _DL_ELF_H */
> diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
> index 8210a012e..cc42b904f 100644
> --- a/ldso/ldso/dl-elf.c
> +++ b/ldso/ldso/dl-elf.c
> @@ -1027,6 +1027,9 @@ int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag)
>  		return goof;
>  	}
>  
> +	/* Process DT_RELR relative relocations */
> +	DL_RELOCATE_RELR(tpnt);
> +
>  	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..674c4b7b9 100644
> --- a/ldso/ldso/dl-startup.c
> +++ b/ldso/ldso/dl-startup.c
> @@ -264,6 +264,9 @@ 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");
>  
> +	/* Process DT_RELR relative relocations */
> +	DL_RELOCATE_RELR(tpnt);
> +
>  	{
>  		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..7ad80f97b 100644
> --- a/libc/misc/internals/reloc_static_pie.c
> +++ b/libc/misc/internals/reloc_static_pie.c
> @@ -53,6 +53,7 @@ reloc_static_pie(ElfW(Addr) load_addr)
>  	PERFORM_BOOTSTRAP_GOT(tpnt);
>  #endif
>  
> +    DL_RELOCATE_RELR(tpnt);
>  
>  #if defined(ELF_MACHINE_PLTREL_OVERLAP)
>  # define INDX_MAX 1
> -- 
> 2.43.0
> 
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
Dmitry Chestnykh Feb. 7, 2024, 8:58 a.m. UTC | #2
Hello Waldemar, currently i haven't any ideas but i will check this ASAP
and fix the issue.

ср, 7 февр. 2024 г. в 11:53, Waldemar Brodkorb <wbx@openadk.org>:

> Hi Dmitry,
>
> thanks for the patch.
> Unfortunately it breaks ARM FDPIC toolchain building:
> ldso/ldso/dl-startup.c: In function '_dl_start':
> ldso/ldso/dl-startup.c:268:9: error: aggregate value used where an
> integer was expected
>   268 |         DL_RELOCATE_RELR(tpnt);
>         |         ^~~~~~~~~~~~~~~~
>
> You could use OpenADK to produce such a toolchain.
>
> Any idea what is wrong?
>
> best regards
>  Waldemar
>
> Dmitry Chestnykh wrote,
>
> > 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                  | 38 ++++++++++++++++++++++++++
> >  ldso/ldso/dl-elf.c                     |  3 ++
> >  ldso/ldso/dl-startup.c                 |  3 ++
> >  libc/misc/internals/reloc_static_pie.c |  1 +
> >  5 files changed, 52 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..10b895733 100644
> > --- a/ldso/include/dl-elf.h
> > +++ b/ldso/include/dl-elf.h
> > @@ -250,5 +250,43 @@ 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))
> >
> > +/* 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 /* _DL_ELF_H */
> > diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
> > index 8210a012e..cc42b904f 100644
> > --- a/ldso/ldso/dl-elf.c
> > +++ b/ldso/ldso/dl-elf.c
> > @@ -1027,6 +1027,9 @@ int _dl_fixup(struct dyn_elf *rpnt, struct
> r_scope_elem *scope, int now_flag)
> >               return goof;
> >       }
> >
> > +     /* Process DT_RELR relative relocations */
> > +     DL_RELOCATE_RELR(tpnt);
> > +
> >       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..674c4b7b9 100644
> > --- a/ldso/ldso/dl-startup.c
> > +++ b/ldso/ldso/dl-startup.c
> > @@ -264,6 +264,9 @@ 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");
> >
> > +     /* Process DT_RELR relative relocations */
> > +     DL_RELOCATE_RELR(tpnt);
> > +
> >       {
> >               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..7ad80f97b 100644
> > --- a/libc/misc/internals/reloc_static_pie.c
> > +++ b/libc/misc/internals/reloc_static_pie.c
> > @@ -53,6 +53,7 @@ reloc_static_pie(ElfW(Addr) load_addr)
> >       PERFORM_BOOTSTRAP_GOT(tpnt);
> >  #endif
> >
> > +    DL_RELOCATE_RELR(tpnt);
> >
> >  #if defined(ELF_MACHINE_PLTREL_OVERLAP)
> >  # define INDX_MAX 1
> > --
> > 2.43.0
> >
> > _______________________________________________
> > devel mailing list -- devel@uclibc-ng.org
> > To unsubscribe send an email to devel-leave@uclibc-ng.org
> >
>
Dmitry Chestnykh Feb. 7, 2024, 9:08 a.m. UTC | #3
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?

ср, 7 февр. 2024 г. в 11:53, Waldemar Brodkorb <wbx@openadk.org>:

> Hi Dmitry,
>
> thanks for the patch.
> Unfortunately it breaks ARM FDPIC toolchain building:
> ldso/ldso/dl-startup.c: In function '_dl_start':
> ldso/ldso/dl-startup.c:268:9: error: aggregate value used where an
> integer was expected
>   268 |         DL_RELOCATE_RELR(tpnt);
>         |         ^~~~~~~~~~~~~~~~
>
> You could use OpenADK to produce such a toolchain.
>
> Any idea what is wrong?
>
> best regards
>  Waldemar
>
> Dmitry Chestnykh wrote,
>
> > 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                  | 38 ++++++++++++++++++++++++++
> >  ldso/ldso/dl-elf.c                     |  3 ++
> >  ldso/ldso/dl-startup.c                 |  3 ++
> >  libc/misc/internals/reloc_static_pie.c |  1 +
> >  5 files changed, 52 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..10b895733 100644
> > --- a/ldso/include/dl-elf.h
> > +++ b/ldso/include/dl-elf.h
> > @@ -250,5 +250,43 @@ 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))
> >
> > +/* 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 /* _DL_ELF_H */
> > diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
> > index 8210a012e..cc42b904f 100644
> > --- a/ldso/ldso/dl-elf.c
> > +++ b/ldso/ldso/dl-elf.c
> > @@ -1027,6 +1027,9 @@ int _dl_fixup(struct dyn_elf *rpnt, struct
> r_scope_elem *scope, int now_flag)
> >               return goof;
> >       }
> >
> > +     /* Process DT_RELR relative relocations */
> > +     DL_RELOCATE_RELR(tpnt);
> > +
> >       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..674c4b7b9 100644
> > --- a/ldso/ldso/dl-startup.c
> > +++ b/ldso/ldso/dl-startup.c
> > @@ -264,6 +264,9 @@ 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");
> >
> > +     /* Process DT_RELR relative relocations */
> > +     DL_RELOCATE_RELR(tpnt);
> > +
> >       {
> >               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..7ad80f97b 100644
> > --- a/libc/misc/internals/reloc_static_pie.c
> > +++ b/libc/misc/internals/reloc_static_pie.c
> > @@ -53,6 +53,7 @@ reloc_static_pie(ElfW(Addr) load_addr)
> >       PERFORM_BOOTSTRAP_GOT(tpnt);
> >  #endif
> >
> > +    DL_RELOCATE_RELR(tpnt);
> >
> >  #if defined(ELF_MACHINE_PLTREL_OVERLAP)
> >  # define INDX_MAX 1
> > --
> > 2.43.0
> >
> > _______________________________________________
> > devel mailing list -- devel@uclibc-ng.org
> > To unsubscribe send an email to devel-leave@uclibc-ng.org
> >
>
Waldemar Brodkorb Feb. 7, 2024, 9:20 a.m. UTC | #4
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..10b895733 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -250,5 +250,43 @@  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))
 
+/* 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 /* _DL_ELF_H */
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 8210a012e..cc42b904f 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -1027,6 +1027,9 @@  int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag)
 		return goof;
 	}
 
+	/* Process DT_RELR relative relocations */
+	DL_RELOCATE_RELR(tpnt);
+
 	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..674c4b7b9 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -264,6 +264,9 @@  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");
 
+	/* Process DT_RELR relative relocations */
+	DL_RELOCATE_RELR(tpnt);
+
 	{
 		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..7ad80f97b 100644
--- a/libc/misc/internals/reloc_static_pie.c
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -53,6 +53,7 @@  reloc_static_pie(ElfW(Addr) load_addr)
 	PERFORM_BOOTSTRAP_GOT(tpnt);
 #endif
 
+    DL_RELOCATE_RELR(tpnt);
 
 #if defined(ELF_MACHINE_PLTREL_OVERLAP)
 # define INDX_MAX 1