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
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
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
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
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
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(-)
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
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