[uClibc][PATCH] MIPS dynamic loader now bootsraps correctly...

Steven J. Hill sjhill at realitydiluted.com
Tue Apr 2 20:35:29 UTC 2002


Greetings.

Attached you will find the patch that allows the MIPS dynamic
loader to bootstrap itself. Please apply. Also, below is output
of an attempted run of an application.

-----------------------------------------------------
ELF header=0x2aaa8000
First Dynamic section entry=0x2aaa80cc
About to do library loader relocations.
Done relocating library loader, so we can now
	use globals and make function calls!
GOT found at 0x2aaae000
Lib Loader:	(0x2aaa8000) /usr/mipsel-linux-uclibc/lib/ld-uClibc.so.0
searching for library: 'libc.so.0'
searching in ldso dir: /usr/mipsel-linux-uclibc/lib
Segmentation fault (core dumped)
-----------------------------------------------------

-Steve

diff -urN uclibc/Makefile uclibc-patched/Makefile
--- uclibc/Makefile	Tue Mar 26 09:31:10 2002
+++ uclibc-patched/Makefile	Mon Mar 25 13:07:21 2002
@@ -332,16 +332,17 @@
 
 distclean clean:
 	@rm -rf tmp lib include/bits libc/tmp _install
-	- find include -type l -exec rm -f {} \;
-	- find . \( -name \*.o -o -name \*.a -o -name \*.so -o -name core -o -name .\#\* \) -exec rm -f {} \;
 	$(MAKE) -C test clean
 	$(MAKE) -C ldso clean
 	$(MAKE) -C libc/misc clean
 	$(MAKE) -C libc/unistd clean
 	$(MAKE) -C libc/sysdeps/linux/common clean
-	$(MAKE) -C libc/sysdeps/linux/$(TARGET_ARCH) clean
 	$(MAKE) -C extra/gcc-uClibc clean
-	find . -name mipsel -exec rm -rf {} \;
+	@if [ -d libc/sysdeps/linux/$(TARGET_ARCH) ]; then		\
+	    $(MAKE) -C libc/sysdeps/linux/$(TARGET_ARCH) clean;		\
+	fi;
+	- find . \( -name \*.o -o -name \*.a -o -name \*.so -o -name core -o -name .\#\* \) -exec rm -f {} \;
+	- find -type l -exec rm -f {} \;
 
 dist release: distclean
 	cd ..;					\
diff -urN uclibc/ldso/ldso/ld_string.h uclibc-patched/ldso/ldso/ld_string.h
--- uclibc/ldso/ldso/ld_string.h	Sun Feb 17 05:05:02 2002
+++ uclibc-patched/ldso/ldso/ld_string.h	Tue Apr  2 14:21:34 2002
@@ -221,7 +221,7 @@
 }
 
 
-#if defined mc68000 || defined __arm__
+#if defined mc68000 || defined __arm__ || defined __mips__
 /* On some arches constant strings are referenced through the GOT. */
 /* XXX Requires load_addr to be defined. */
 #define SEND_STDERR(X)				\
diff -urN uclibc/ldso/ldso/ld_syscall.h uclibc-patched/ldso/ldso/ld_syscall.h
--- uclibc/ldso/ldso/ld_syscall.h	Tue Mar 19 08:41:30 2002
+++ uclibc-patched/ldso/ldso/ld_syscall.h	Mon Apr  1 10:35:24 2002
@@ -51,8 +51,8 @@
 static inline _syscall1(int, _dl_close, int, fd);
 
 
-#ifdef __powerpc__
-/* PowerPC has a different calling convention for mmap(). */
+#if defined(__powerpc) || defined(__mips__)
+/* PowerPC and MIPS have a different calling convention for mmap(). */
 #define __NR__dl_mmap __NR_mmap
 static inline _syscall6(void *, _dl_mmap, void *, start, size_t, length,
 		int, prot, int, flags, int, fd, off_t, offset);
diff -urN uclibc/ldso/ldso/ldso.c uclibc-patched/ldso/ldso/ldso.c
--- uclibc/ldso/ldso/ldso.c	Mon Apr  1 06:56:40 2002
+++ uclibc-patched/ldso/ldso/ldso.c	Tue Apr  2 13:43:01 2002
@@ -20,11 +20,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
  */
 
-/* Enable this to turn on debugging noise */
-//#define DL_DEBUG
-
-/* Enable mprotect protection munging.  ARM Linux needs this it seems,
- * so leave this enabled by default */
+/* Enable mprotect protection munging.  ARM and MIPS Linux needs this
+ * it seems, so leave this enabled by default */
 #define DO_MPROTECT_HACKS
 
 // Support a list of library preloads in /etc/ld.so.preload
@@ -209,10 +206,16 @@
 	Elf32_auxv_t auxvt[AT_EGID + 1];
 	unsigned char *malloc_buffer, *mmap_zero;
 	Elf32_Dyn *dpnt;
+	Elf32_Dyn *dpnt_debug = NULL;
 	unsigned long *hash_addr;
 	struct r_debug *debug_addr;
 	int indx;
 	int status;
+#if defined(__mips__)
+	unsigned long mips_gotsym = 0;
+	unsigned long mips_local_gotno = 0;
+	unsigned long mips_symtabno = 0;
+#endif
 
 
 	/* WARNING! -- we cannot make _any_ funtion calls until we have
@@ -223,7 +226,7 @@
 	/* First obtain the information on the stack that tells us more about
 	   what binary is loaded, where it is loaded, etc, etc */
 	GET_ARGV(aux_dat, args);
-#if defined(__arm__) || defined(__mips__)
+#if defined (__arm__) || defined (__mips__)
 	aux_dat += 1;
 #endif
 	argc = *(aux_dat - 1);
@@ -267,7 +270,7 @@
 		_dl_exit(0);
 	}
 #ifdef DL_DEBUG
-	SEND_STDERR("ELF header =");
+	SEND_STDERR("ELF header=");
 	SEND_ADDRESS_STDERR(load_addr, 1);
 #endif
 
@@ -287,7 +290,7 @@
 #elif defined(__powerpc__)
   __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4 at local\n\t":"=l"(got));
 #elif defined(__mips__)
-  __asm__("\tmove %0, $28\n\t":"=r"(got));
+  __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
 #else
 	/* Do things the slow way in C */
 	{
@@ -334,7 +337,7 @@
 		_dl_exit(0);
 
 	  found_got:
-		got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc + 
+		got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc +
 				(char *) header);
 	}
 #endif
@@ -376,6 +379,14 @@
 				tpnt->dynamic_info[DT_TEXTREL] = 1;
 			}
 		}
+#if defined(__mips__)
+		if (dpnt->d_tag == DT_MIPS_GOTSYM)
+			mips_gotsym = (unsigned long) dpnt->d_un.d_val;
+		if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
+			mips_local_gotno = (unsigned long) dpnt->d_un.d_val;
+		if (dpnt->d_tag == DT_MIPS_SYMTABNO)
+			mips_symtabno = (unsigned long) dpnt->d_un.d_val;
+#endif
 		dpnt++;
 	}
 
@@ -394,7 +405,11 @@
 					}
 					app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
 					if (dpnt->d_tag == DT_DEBUG)
+#ifndef DO_MPROTECT_HACKS
 						dpnt->d_un.d_val = (unsigned long) debug_addr;
+#else
+						dpnt_debug = dpnt;
+#endif
 					if (dpnt->d_tag == DT_TEXTREL || SVR4_BUGCOMPAT)
 						app_tpnt->dynamic_info[DT_TEXTREL] = 1;
 					dpnt++;
@@ -446,6 +461,16 @@
 			}
 		}
 	}
+
+	/* Now we can store the debug structure address */
+	dpnt_debug->d_un.d_val = (unsigned long) debug_addr;
+#endif
+
+
+	/* For MIPS, we have to do special stuff to the GOT before we do
+	   any relocations. */
+#if defined(__mips__)
+	PERFORM_BOOTSTRAP_GOT(got);
 #endif
 
 
@@ -454,6 +479,7 @@
 #ifdef DL_DEBUG
 	SEND_STDERR("About to do library loader relocations.\n");
 #endif
+
 	goof = 0;
 	for (indx = 0; indx < 2; indx++) {
 		int i;
@@ -476,7 +502,6 @@
 			 dynamic_info[DT_RELSZ]);
 #endif
 
-
 		if (!rel_addr)
 			continue;
 
@@ -499,6 +524,7 @@
 				if (!_dl_symbol(strtab + symtab[symtab_index].st_name))
 					continue;
 				symbol_addr = load_addr + symtab[symtab_index].st_value;
+					SEND_NUMBER_STDERR(symbol_addr,1);
 
 				if (!symbol_addr) {
 					/* This will segfault - you cannot call a function until
diff -urN uclibc/ldso/ldso/mips/README uclibc-patched/ldso/ldso/mips/README
--- uclibc/ldso/ldso/mips/README	Wed Dec 31 18:00:00 1969
+++ uclibc-patched/ldso/ldso/mips/README	Tue Apr  2 13:54:52 2002
@@ -0,0 +1,43 @@
+Almost all of the code present in these source files was taken
+from GLIBC. In the descriptions below, all files mentioned are
+with respect to the top level GLIBC source directory accept for
+the code taken from the Linux kernel.
+
+boot1_arch.h
+------------
+Contains code to fix up the stack pointer so that the dynamic
+linker can find argc, argv and Auxillary Vector Table (AVT).
+The codes is taken from the function 'RTLD_START' in the
+file 'sysdeps/mips/dl-machine.h'.
+
+elfinterp.c
+-----------
+Contains '_dl_init_got' which initializes the GOT for the
+application being dynamically linked and loaded. The code is
+taken from the functions 'elf_machine_runtime_setup' and 
+'elf_machine_got_rel' in the file 'sysdeps/mips/dl-machine.h'.
+
+ld_syscalls.h
+-------------
+Contains all the macro function prototypes for the system calls
+as well as the list of system calls supported. The macros were
+taken from the Linux kernel source 2.4.17 found in the file
+'include/asm-mips/unistd.h'.
+
+ld_sysdep.h
+-----------
+Contains bootstrap code for the dynamic linker, magic numbers
+for detecting MIPS target types and some macros. The macro
+function 'PERFORM_BOOTSTRAP_GOT' is used to relocate the dynamic
+linker's GOT so that function calls can be made. The code is
+taken from the function 'ELF_MACHINE_BEFORE_RTLD_RELOC' in the
+file 'sysdep/mips/dl-machine.h'. The other macro function
+'PERFORM_BOOTSTRAP_RELOC' is used to do the relocations for
+the dynamic loader. The code is taken from the function
+'elf_machine_rel' in the file 'sysdep/mips/dl-machine.h'.
+
+resolve.S
+---------
+Contains the low-level assembly code for the dynamic runtime
+resolver. The code is taken from the assembly code function
+'_dl_runtime_resolve' in the file 'sysdesp/mips/dl-machine.h'.
diff -urN uclibc/ldso/ldso/mips/boot1_arch.h uclibc-patched/ldso/ldso/mips/boot1_arch.h
--- uclibc/ldso/ldso/mips/boot1_arch.h	Fri Mar 29 16:31:12 2002
+++ uclibc-patched/ldso/ldso/mips/boot1_arch.h	Mon Apr  1 16:01:00 2002
@@ -13,11 +13,8 @@
 	nop
 0:	.cpload $31
 	.set reorder
-	# i386 ABI book says that the first entry of GOT holds
-	# the address of the dynamic structure. Though MIPS ABI
-	# doesn't say nothing about this, I emulate this here.
+	# Store offset of DYNAMIC section in first entry of GOT
 	la $4, _DYNAMIC
-	# Subtract OFFSET_GP_GOT
 	sw $4, -0x7ff0($28)
 	move $4, $29
 	la $8, coff
diff -urN uclibc/ldso/ldso/mips/elfinterp.c uclibc-patched/ldso/ldso/mips/elfinterp.c
--- uclibc/ldso/ldso/mips/elfinterp.c	Wed Dec 31 18:00:00 1969
+++ uclibc-patched/ldso/ldso/mips/elfinterp.c	Tue Apr  2 13:46:34 2002
@@ -0,0 +1,49 @@
+/* Run an ELF binary on a linux system.
+
+   Copyright (C) 1993, Eric Youngdale.
+   Copyright (C) 2002, Steven J. Hill (sjhill at realitydiluted.com)
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+
+/* Program to load an ELF binary on a linux system, and run it.
+   References to symbols in sharable libraries can be resolved by either
+   an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+
+extern int _dl_linux_resolve(void);
+
+void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt)
+{
+	return;
+}
+
+unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
+{
+	return 0;
+}
+
+int _dl_parse_relocation_information(struct elf_resolve *tpnt, 
+	unsigned long rel_addr, unsigned long rel_size, int type)
+{
+	return 1;
+}
diff -urN uclibc/ldso/ldso/mips/ld_syscalls.h uclibc-patched/ldso/ldso/mips/ld_syscalls.h
--- uclibc/ldso/ldso/mips/ld_syscalls.h	Mon Apr  1 06:56:40 2002
+++ uclibc-patched/ldso/ldso/mips/ld_syscalls.h	Mon Apr  1 10:34:48 2002
@@ -142,4 +142,34 @@
 	return (type) -1; \
 }
 
+#define _syscall6(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e,ftype,f) \
+type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \
+{ \
+	register unsigned long __v0 asm("$2") = __NR_##name; \
+	register unsigned long __a0 asm("$4") = (unsigned long) a; \
+	register unsigned long __a1 asm("$5") = (unsigned long) b; \
+	register unsigned long __a2 asm("$6") = (unsigned long) c; \
+	register unsigned long __a3 asm("$7") = (unsigned long) d; \
+	\
+	__asm__ volatile ( \
+	".set\tnoreorder\n\t" \
+	"lw\t$2, %6\n\t" \
+	"lw\t$8, %7\n\t" \
+	"subu\t$29, 32\n\t" \
+	"sw\t$2, 16($29)\n\t" \
+	"sw\t$8, 20($29)\n\t" \
+	"li\t$2, %5\t\t\t# " #name "\n\t" \
+	"syscall\n\t" \
+	"addiu\t$29, 32\n\t" \
+	".set\treorder" \
+	: "=&r" (__v0), "+r" (__a3) \
+	: "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_##name), \
+	  "m" ((unsigned long)e), "m" ((unsigned long)f) \
+	: "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24"); \
+	\
+	if (__a3 == 0) \
+		return (type) __v0; \
+	return (type) -1; \
+}
+
 #endif
diff -urN uclibc/ldso/ldso/mips/ld_sysdep.h uclibc-patched/ldso/ldso/mips/ld_sysdep.h
--- uclibc/ldso/ldso/mips/ld_sysdep.h	Tue Mar 19 11:05:51 2002
+++ uclibc-patched/ldso/ldso/mips/ld_sysdep.h	Tue Apr  2 13:35:49 2002
@@ -8,36 +8,82 @@
  */
 #undef ELF_USES_RELOCA
 
+
 /*
  * Get a pointer to the argv array.  On many platforms this can be just
  * the address if the first argument, on other platforms we need to
  * do something a little more subtle here.
  */
-#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*)   ARGS)
+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long *) ARGS)
+
 
 /*
- * Initialization sequence for a GOT.
+ * Initialization sequence for the application GOT.
  */
-#define INIT_GOT(GOT_BASE,MODULE) \
-{				\
-  GOT_BASE[0] = (unsigned long) _dl_linux_resolve; \
-  GOT_BASE[1] = (unsigned long) MODULE; \
-}
+#define INIT_GOT(GOT_BASE,MODULE)	_dl_init_got(GOT_BASE,MODULE)
+
+
+/*
+ * Here is a macro to perform the GOT relocation.  This is only
+ * used when bootstrapping the dynamic loader.
+ */
+#define PERFORM_BOOTSTRAP_GOT(got)					\
+do {									\
+	Elf32_Sym *sym;							\
+	unsigned long i;						\
+									\
+	/* Add load address displacement to all local GOT entries */	\
+	i = 2;								\
+	while (i < mips_local_gotno)					\
+		got[i++] += load_addr;					\
+									\
+	/* Handle global GOT entries */					\
+	got += mips_local_gotno;					\
+	sym = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] +		\
+		 load_addr) + mips_gotsym;				\
+	i = mips_symtabno - mips_gotsym;				\
+									\
+	while (i--) {							\
+		if (sym->st_shndx == SHN_UNDEF ||			\
+			sym->st_shndx == SHN_COMMON)			\
+			*got = load_addr + sym->st_value;		\
+		else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&	\
+			*got != sym->st_value)				\
+			*got += load_addr;				\
+		else if (ELF32_ST_TYPE(sym->st_info) == STT_SECTION) {	\
+			if (sym->st_other == 0)				\
+				*got += load_addr;			\
+		}							\
+		else							\
+			*got = load_addr + sym->st_value;		\
+									\
+		got++;							\
+		sym++;							\
+	}								\
+} while (0)
+
 
 /*
  * Here is a macro to perform a relocation.  This is only used when
- * bootstrapping the dynamic loader.  RELP is the relocation that we
- * are performing, REL is the pointer to the address we are relocating.
- * SYMBOL is the symbol involved in the relocation, and LOAD is the
- * load address.
- *
- * !!!NOTE!!!
- *
- * For MIPS, we don't have any DT_JMPREL or DT_PLTRELSZ dynamic
- * entries, so this macro function is empty. The code contained
- * in elfinterp.c does the real relocation work.
+ * bootstrapping the dynamic loader.
  */
-#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)
+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD)			\
+	switch(ELF32_R_TYPE((RELP)->r_info)) {				\
+	case R_MIPS_REL32:						\
+		if (symtab_index) {					\
+			if (symtab_index < mips_gotsym)			\
+				*REL += SYMBOL + LOAD;			\
+		}							\
+		else {							\
+			*REL += LOAD;					\
+		}							\
+		break;							\
+	case R_MIPS_NONE:						\
+		break;							\
+	default:							\
+		SEND_STDERR("Aiieeee!");				\
+		_dl_exit(1);						\
+	}
 
 
 /*
@@ -45,19 +91,21 @@
  * is done.  This routine has to exit the current function, then 
  * call the _dl_elf_main function.
  */
-
 #define START()   return (void) _dl_elf_main;      
 
 
-
 /* Here we define the magic numbers that this dynamic loader should accept */
-
 #define MAGIC1 EM_MIPS
 #define MAGIC2 EM_MIPS_RS3_LE
+
+
 /* Used for error messages */
 #define ELF_TARGET "MIPS"
 
+
 struct elf_resolve;
-unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt,
+	int reloc_entry);
+void _dl_init_got(unsigned long *got, struct elf_resolve *tpnt);
 
 #define do_rem(result, n, base)  result = (n % base)
diff -urN uclibc/ldso/ldso/readelflib1.c uclibc-patched/ldso/ldso/readelflib1.c
--- uclibc/ldso/ldso/readelflib1.c	Thu Mar 21 11:39:07 2002
+++ uclibc-patched/ldso/ldso/readelflib1.c	Tue Apr  2 13:36:57 2002
@@ -308,7 +308,7 @@
 	int flags;
 	char header[4096];
 	unsigned long dynamic_info[24];
-	int *lpnt;
+	unsigned long *lpnt;
 	unsigned long libaddr;
 	unsigned long minvma = 0xffffffff, maxvma = 0;
 
@@ -553,10 +553,11 @@
 	 * resolved. 
 	 */
 
-	lpnt = (int *) dynamic_info[DT_PLTGOT];
+	lpnt = (unsigned long *) dynamic_info[DT_PLTGOT];
 
 	if (lpnt) {
-		lpnt = (int *) (dynamic_info[DT_PLTGOT] + ((int) libaddr));
+		lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] +
+			((int) libaddr));
 		INIT_GOT(lpnt, tpnt);
 	};
 



More information about the uClibc mailing list