diff mbox series

[uclibc-ng-devel,v2] Static PIE support for mips

Message ID CANP1oa1+OhonZsG_CY6EYCCWeLFHju2zMGTv6HHv0bVg1kaxKw@mail.gmail.com
State Superseded
Headers show
Series [uclibc-ng-devel,v2] Static PIE support for mips | expand

Commit Message

linted Sept. 1, 2022, 9:25 p.m. UTC
Hello,
This is the second iteration of the patch for mips static pie support. This
version fixes two truncation errors which were occurring.

The first problem came from calling reloc_static_pie() directly from
__start which caused gcc to request a R_MIPS_PC16 relocation. Unfortunately
that type of relocation would not be large enough for the linker to place
the PC relative address if the supplied user code was too large. By
changing the call to be a register relative jump which we were already
correctly calculating, the problem went away.

The other bug was the improper usage of the mips assembly macros. I had
chosen to use INT_* functions for the calculation to determine the load
address. These macros ended up truncating the results since they can use
the 32bit instructions on mips64. This was remedied by changing to PTR_*
macros.

-------
From 051a7536e8f3bfb96c290bda74749886ae7d1693 Mon Sep 17 00:00:00 2001
From: linted <linted@users.noreply.github.com>
Date: Sat, 20 Aug 2022 16:41:38 -0400
Subject: [PATCH] Added support for creation of Static Position-Independent
 Executables (PIE) on mips

Updated config to allow compilation of rcrt1.o for mips and modified it's
crt1.S to perform relocates in __start.

The mips architecture performs relocations differently then most other
architectures. reloc_static_pie was rewritten, taking code from
dl-startup.c, in order to perfrom the additional relocations. Modifications
were made to mips' dl-startup.h to allow for the use of contained macros
without including _start definition.

Signed-off-by: linted <linted@users.noreply.github.com>
---
 extra/Configs/Config.in                |  2 +-
 ldso/ldso/mips/dl-startup.h            |  3 +-
 libc/misc/internals/Makefile.in        |  2 +-
 libc/misc/internals/reloc_static_pie.c | 93 +++++++++++++++++++++-----
 libc/sysdeps/linux/mips/crt1.S         | 29 ++++++++
 5 files changed, 111 insertions(+), 18 deletions(-)
diff mbox series

Patch

From 051a7536e8f3bfb96c290bda74749886ae7d1693 Mon Sep 17 00:00:00 2001
From: linted <linted@users.noreply.github.com>
Date: Sat, 20 Aug 2022 16:41:38 -0400
Subject: [PATCH] Added support for creation of Static Position-Independent
 Executables (PIE) on mips

Updated config to allow compilation of rcrt1.o for mips and modified it's crt1.S to perform relocates in __start.

The mips architecture performs relocations differently then most other architectures. reloc_static_pie was rewritten, taking code from dl-startup.c, in order to perfrom the additional relocations. Modifications were made to mips' dl-startup.h to allow for the use of contained macros without including _start definition.

Signed-off-by: linted <linted@users.noreply.github.com>
---
 extra/Configs/Config.in                |  2 +-
 ldso/ldso/mips/dl-startup.h            |  3 +-
 libc/misc/internals/Makefile.in        |  2 +-
 libc/misc/internals/reloc_static_pie.c | 93 +++++++++++++++++++++-----
 libc/sysdeps/linux/mips/crt1.S         | 29 ++++++++
 5 files changed, 111 insertions(+), 18 deletions(-)

diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index e0905e956..43c04fd0a 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -324,7 +324,7 @@  config DOPIC
 config STATIC_PIE
 	bool "Add support for Static Position Independent Executables (PIE)"
 	default n
-	depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm || TARGET_i386 || TARGET_x86_64 || TARGET_aarch64)
+	depends on DOPIC && !UCLIBC_FORMAT_FDPIC_ELF && (TARGET_arm || TARGET_i386 || TARGET_x86_64 || TARGET_aarch64 || TARGET_mips)
 
 config ARCH_HAS_NO_SHARED
 	bool
diff --git a/ldso/ldso/mips/dl-startup.h b/ldso/ldso/mips/dl-startup.h
index 8026f1702..c2168d774 100644
--- a/ldso/ldso/mips/dl-startup.h
+++ b/ldso/ldso/mips/dl-startup.h
@@ -7,6 +7,7 @@ 
 
 
 #include <sgidefs.h>
+#ifndef L_rcrt1
 __asm__(""
     "	.text\n"
     "	.globl	_start\n"
@@ -114,6 +115,7 @@  __asm__(""
     "\n\n"
     ".previous\n"
 );
+#endif
 
 /*
  * Get a pointer to the argv array.  On many platforms this can be just
@@ -191,6 +193,5 @@  do {										\
 	case R_MIPS_NONE:							\
 		break;								\
 	default:								\
-		SEND_STDERR("Aiieeee!");					\
 		_dl_exit(1);							\
 	}
diff --git a/libc/misc/internals/Makefile.in b/libc/misc/internals/Makefile.in
index 69af8b76e..908b18321 100644
--- a/libc/misc/internals/Makefile.in
+++ b/libc/misc/internals/Makefile.in
@@ -17,7 +17,7 @@  MISC_INTERNALS_SRC := $(patsubst %.c,$(MISC_INTERNALS_DIR)/%.c,$(CSRC-y))
 MISC_INTERNALS_OBJ := $(patsubst %.c,$(MISC_INTERNALS_OUT)/%.o,$(CSRC-y))
 
 CFLAGS-__uClibc_main.c := $(SSP_DISABLE_FLAGS)
-CFLAGS-reloc_static_pie.c := $(SSP_DISABLE_FLAGS)
+CFLAGS-reloc_static_pie.c := $(SSP_DISABLE_FLAGS) -DL_rcrt1
 
 libc-y += $(MISC_INTERNALS_OBJ)
 ifneq ($(UCLIBC_FORMAT_SHARED_FLAT),y)
diff --git a/libc/misc/internals/reloc_static_pie.c b/libc/misc/internals/reloc_static_pie.c
index 578202d23..c0027de6f 100644
--- a/libc/misc/internals/reloc_static_pie.c
+++ b/libc/misc/internals/reloc_static_pie.c
@@ -15,33 +15,96 @@ 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <https://www.gnu.org/licenses/>.  */
-
+#define IS_IN_rtld      // force inline function calls
 #include <link.h>
 #include <elf.h>
 #include <dl-elf.h>
 
+#include <ldso.h>
+#ifdef __mips__
+#include <dl-startup.h>
+#endif
+
 ElfW(Addr) _dl_load_base = NULL;
 
 void
 reloc_static_pie (ElfW(Addr) load_addr);
 
 void
-reloc_static_pie (ElfW(Addr) load_addr)
+reloc_static_pie(ElfW(Addr) load_addr)
 {
-    ElfW(Word) relative_count = 0;
-    ElfW(Addr) rel_addr = 0;
-    ElfW(Dyn) * dyn_addr = NULL;
-    unsigned long dynamic_info[DYNAMIC_SIZE] = {0};
+    int indx;
+    ElfW(Addr) got;
+    ElfW(Dyn) *dpnt;
+    struct elf_resolve tpnt_tmp;
+	struct elf_resolve *tpnt = &tpnt_tmp;
+
+    DL_BOOT_COMPUTE_GOT(got);
+    DL_BOOT_COMPUTE_DYN(dpnt, got, (DL_LOADADDR_TYPE)load_addr);
+
+    _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
+    tpnt->loadaddr = load_addr;
+    tpnt->dynamic_addr = dpnt;
+
+    __dl_parse_dynamic_info(dpnt, tpnt->dynamic_info, NULL, load_addr);
+
+#if defined(PERFORM_BOOTSTRAP_GOT)
+	/* some arches (like MIPS) we have to tweak the GOT before relocations */
+	PERFORM_BOOTSTRAP_GOT(tpnt);
+#endif
+
+
+#if defined(ELF_MACHINE_PLTREL_OVERLAP)
+# define INDX_MAX 1
+#else
+# define INDX_MAX 2
+#endif
+
+    for (indx = 0; indx < INDX_MAX; indx++) {
+        unsigned long rel_addr, rel_size;
+        ElfW(Word) relative_count = tpnt->dynamic_info[DT_RELCONT_IDX];
+
+        rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] :
+                           tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]);
+        rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] :
+			               tpnt->dynamic_info[DT_RELOC_TABLE_SIZE]);
+
+        if (!rel_addr)
+            continue;
 
-    /* Read our own dynamic section and fill in the info array.  */
-    dyn_addr = ((void *) load_addr + elf_machine_dynamic ());
+        if((0 == indx) && relative_count) {
+			rel_size -= relative_count * sizeof(ELF_RELOC);
+            elf_machine_relative(load_addr, rel_addr, relative_count);
+			rel_addr += relative_count * sizeof(ELF_RELOC);
+        }
 
-    /* Use the underlying function to avoid TLS access before initialization */
-    __dl_parse_dynamic_info(dyn_addr, dynamic_info, NULL, load_addr);
+#ifdef ARCH_NEEDS_BOOTSTRAP_RELOCS
+			{
+				ELF_RELOC *rpnt;
+				unsigned int i;
+				ElfW(Sym) *sym;
+				unsigned long symbol_addr;
+				int symtab_index;
+				unsigned long *reloc_addr;
 
-    /* Perform relocations */
-    relative_count = dynamic_info[DT_RELCONT_IDX];
-    rel_addr = dynamic_info[DT_RELOC_TABLE_ADDR];
-    elf_machine_relative(load_addr, rel_addr, relative_count);
+				/* Now parse the relocation information */
+				rpnt = (ELF_RELOC *) rel_addr;
+				for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
+					reloc_addr = (unsigned long *) DL_RELOC_ADDR(load_addr, (unsigned long)rpnt->r_offset);
+					symtab_index = ELF_R_SYM(rpnt->r_info);
+					symbol_addr = 0;
+					sym = NULL;
+					if (symtab_index) {
+						ElfW(Sym) *symtab;
+						symtab = (ElfW(Sym) *) tpnt->dynamic_info[DT_SYMTAB];
+						sym = &symtab[symtab_index];
+						symbol_addr = (unsigned long) DL_RELOC_ADDR(load_addr, sym->st_value);
+					}
+					/* Use this machine-specific macro to perform the actual relocation.  */
+					PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, sym);
+				}
+			}
+#endif
+    }
     _dl_load_base = load_addr;
-}
+}
\ No newline at end of file
diff --git a/libc/sysdeps/linux/mips/crt1.S b/libc/sysdeps/linux/mips/crt1.S
index 083615515..6a4257b1f 100644
--- a/libc/sysdeps/linux/mips/crt1.S
+++ b/libc/sysdeps/linux/mips/crt1.S
@@ -77,6 +77,10 @@ 
 #ifndef __UCLIBC_CTOR_DTOR__
 	.weak	_init
 	.weak	_fini
+#endif
+#ifdef L_rcrt1
+	.type	reloc_static_pie,@function
+	.hidden	.L0
 #endif
 	.type	    main,@function
 	.type	    __uClibc_main,@function
@@ -89,6 +93,31 @@  __start:
 #else
 	PTR_LA $28, _gp             /* Setup GP correctly if we're non-PIC.  */
 	move $31, $0
+#endif
+#ifdef L_rcrt1
+/* #if _MIPS_SIM == _MIPS_SIM_ABI32 */
+	PTR_LA $4, _DYNAMIC           /* Place _DYNAMIC into the GOT */
+	REG_S $4, -0x7ff0($28)        /* offset to GOT stolen from dl-startup */
+	jal .L0                       /* Get the current $pc address */
+.L0:
+	PTR_SUBU $4, $31, $25         /* Calculate load addr */
+	move $31, $0                  /* Clear ra */
+	and $29, -2 * SZREG           /* Ensure stack is aligned */
+	PTR_ADDIU $29, (-2 * SZREG)   /* Allocate 2 register spaces on stack */
+	REG_S $2, SZREG($29)          /* Store atexit in case it exists */
+	PTR_LA $5, reloc_static_pie   /* function calls before relocation
+	                                 don't work unless we set $t9 manually */
+	PTR_ADDU $25, $4, $5          /* store reloc_static_pie in $t9 */
+	jalr $25                      /* call reloc_static_pie */
+	nop							  /* delay slot, just in case */
+	REG_L $2, SZREG($29)          /* cleanup stack */
+	PTR_ADDIU $29, $29, (2 * SZREG)
+#else
+	PTR_LA $4, _DYNAMIC           /* Place _DYNAMIC into the GOT */
+    REG_S $4, -0x7ff0($28)
+
+/* #endif */
+
 #endif
 
 	PTR_LA $4, main		/* main */
-- 
2.34.1