[git commit 0_9_30] - non-pic support for MIPS (Catherine Moore, clm at codesourcery com)

Bernhard Reutner-Fischer rep.dot.nop at gmail.com
Sat Oct 10 16:44:02 UTC 2009


commit: http://git.uclibc.org/uClibc/commit/?id=d6b4e62dc25b375b1400889dd14ac045f2c441c9
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/0_9_30

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
---
 include/elf.h              |   14 ++++++-
 ldso/ldso/dl-hash.c        |    5 +++
 ldso/ldso/mips/dl-sysdep.h |   18 +++++++--
 ldso/ldso/mips/elfinterp.c |   85 ++++++++++++++++++++++++++++++++++++++++++++
 ldso/ldso/mips/resolve.S   |   51 ++++++++++++++++++++++++++
 5 files changed, 167 insertions(+), 6 deletions(-)

diff --git a/include/elf.h b/include/elf.h
index 4c6d090..9f00970 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1544,6 +1544,7 @@ typedef struct
 #define STO_MIPS_INTERNAL		0x1
 #define STO_MIPS_HIDDEN			0x2
 #define STO_MIPS_PROTECTED		0x3
+#define STO_MIPS_PLT			0x8
 #define STO_MIPS_SC_ALIGN_UNUSED	0xff
 
 /* MIPS specific values for `st_info'.  */
@@ -1689,8 +1690,11 @@ typedef struct
 #define R_MIPS_TLS_TPREL64	48	/* TP-relative offset, 64 bit */
 #define R_MIPS_TLS_TPREL_HI16	49	/* TP-relative offset, high 16 bits */
 #define R_MIPS_TLS_TPREL_LO16	50	/* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT		51
+#define R_MIPS_COPY		126
+#define R_MIPS_JUMP_SLOT        127
 /* Keep this the last entry.  */
-#define R_MIPS_NUM		51
+#define R_MIPS_NUM		128
 
 /* Legal values for p_type field of Elf32_Phdr.  */
 
@@ -1756,7 +1760,13 @@ typedef struct
 #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
 #define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
 #define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
-#define DT_MIPS_NUM	     0x32
+/* The address of .got.plt in an executable using the new non-PIC ABI.  */
+#define DT_MIPS_PLTGOT	     0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
+   value.  */
+#define DT_MIPS_RWPLT        0x70000034
+#define DT_MIPS_NUM	     0x35
 
 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
 
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index b44bd3a..a251aaf 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -160,6 +160,11 @@ check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int typ
 		/* undefined symbol itself */
 		return NULL;
 
+#ifdef __mips__
+    if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT))
+        return NULL;
+#endif
+
 	if (sym->st_value == 0)
 		/* No value */
 		return NULL;
diff --git a/ldso/ldso/mips/dl-sysdep.h b/ldso/ldso/mips/dl-sysdep.h
index ad0b197..e07f1c2 100644
--- a/ldso/ldso/mips/dl-sysdep.h
+++ b/ldso/ldso/mips/dl-sysdep.h
@@ -93,10 +93,11 @@ typedef struct
 
 #include <link.h>
 
-#define ARCH_NUM 3
+#define ARCH_NUM 4
 #define DT_MIPS_GOTSYM_IDX	(DT_NUM + OS_NUM)
 #define DT_MIPS_LOCAL_GOTNO_IDX	(DT_NUM + OS_NUM +1)
 #define DT_MIPS_SYMTABNO_IDX	(DT_NUM + OS_NUM +2)
+#define DT_MIPS_PLTGOT_IDX	(DT_NUM + OS_NUM +3)
 
 #define ARCH_DYNAMIC_INFO(dpnt,  dynamic, debug_addr) \
 do { \
@@ -106,6 +107,8 @@ else if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO) \
      dynamic[DT_MIPS_LOCAL_GOTNO_IDX] = dpnt->d_un.d_val; \
 else if (dpnt->d_tag == DT_MIPS_SYMTABNO) \
      dynamic[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; \
+else if (dpnt->d_tag == DT_MIPS_PLTGOT) \
+     dynamic[DT_MIPS_PLTGOT_IDX] = dpnt->d_un.d_val; \
 else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \
      *(ElfW(Addr) *)(dpnt->d_un.d_ptr) =  (ElfW(Addr)) debug_addr; \
 } while (0)
@@ -114,6 +117,7 @@ else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \
 #define INIT_GOT(GOT_BASE,MODULE)						\
 do {										\
 	unsigned long idx;							\
+	unsigned long *pltgot;							\
 										\
 	/* Check if this is the dynamic linker itself */			\
 	if (MODULE->libtype == program_interpreter)				\
@@ -123,6 +127,12 @@ do {										\
 	GOT_BASE[0] = (unsigned long) _dl_runtime_resolve;			\
 	GOT_BASE[1] = (unsigned long) MODULE;					\
 										\
+	pltgot = MODULE->dynamic_info[DT_MIPS_PLTGOT_IDX];			\
+	if (pltgot) {								\
+		pltgot[0] = (unsigned long) _dl_runtime_pltresolve;		\
+		pltgot[1] = (unsigned long) MODULE;				\
+	}									\
+										\
 	/* Add load address displacement to all local GOT entries */		\
 	idx = 2;									\
 	while (idx < MODULE->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX])		\
@@ -151,9 +161,9 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt, int lazy)
 #define OFFS_ALIGN (0x10000000000UL-0x1000)
 #endif	/* O32 || N32 */
 
-#define elf_machine_type_class(type)		ELF_RTYPE_CLASS_PLT
-/* MIPS does not have COPY relocs */
-#define DL_NO_COPY_RELOCS
+#define elf_machine_type_class(type) \
+  ((((type) == R_MIPS_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)	\
+   | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
 
 #define OFFSET_GP_GOT 0x7ff0
 
diff --git a/ldso/ldso/mips/elfinterp.c b/ldso/ldso/mips/elfinterp.c
index 1b03d94..0ed2757 100644
--- a/ldso/ldso/mips/elfinterp.c
+++ b/ldso/ldso/mips/elfinterp.c
@@ -30,6 +30,7 @@
 #include "ldso.h"
 
 extern int _dl_runtime_resolve(void);
+extern int _dl_runtime_pltresolve(void);
 
 #define OFFSET_GP_GOT 0x7ff0
 
@@ -83,6 +84,61 @@ unsigned long __dl_runtime_resolve(unsigned long sym_index,
 	return new_addr;
 }
 
+unsigned long
+__dl_runtime_pltresolve(struct elf_resolve *tpnt, int reloc_entry)
+{
+	int reloc_type;
+	ELF_RELOC *this_reloc;
+	char *strtab;
+	Elf32_Sym *symtab;
+	int symtab_index;
+	char *rel_addr;
+	char *new_addr;
+	char **got_addr;
+	unsigned long instr_addr;
+	char *symname;
+
+	rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
+	this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
+	reloc_type = ELF32_R_TYPE(this_reloc->r_info);
+	symtab_index = ELF32_R_SYM(this_reloc->r_info);
+
+	symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
+	strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
+	symname = strtab + symtab[symtab_index].st_name;
+
+	/* Address of the jump instruction to fix up. */
+	instr_addr = ((unsigned long)this_reloc->r_offset +
+		      (unsigned long)tpnt->loadaddr);
+	got_addr = (char **)instr_addr;
+
+	/* Get the address of the GOT entry. */
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
+	if (unlikely(!new_addr)) {
+		_dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
+		_dl_exit(1);
+	}
+
+#if defined (__SUPPORT_LD_DEBUG__)
+	if ((unsigned long)got_addr < 0x40000000) {
+		if (_dl_debug_bindings) {
+			_dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
+			if (_dl_debug_detail)
+				_dl_dprintf(_dl_debug_file,
+				            "\n\tpatched: %x ==> %x @ %x",
+				            *got_addr, new_addr, got_addr);
+		}
+	}
+	if (!_dl_debug_nofixups) {
+		*got_addr = new_addr;
+	}
+#else
+	*got_addr = new_addr;
+#endif
+
+	return (unsigned long)new_addr;
+}
+
 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 	unsigned long rel_addr, unsigned long rel_size)
 {
@@ -115,6 +171,7 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 	got = (unsigned long *) tpnt->dynamic_info[DT_PLTGOT];
 
 	for (i = 0; i < rel_size; i++, rpnt++) {
+		char *symname = NULL;
 		reloc_addr = (unsigned long *) (tpnt->loadaddr +
 			(unsigned long) rpnt->r_offset);
 		reloc_type = ELF_R_TYPE(rpnt->r_info);
@@ -128,6 +185,16 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 			old_val = *reloc_addr;
 #endif
 
+		if (reloc_type == R_MIPS_JUMP_SLOT || reloc_type == R_MIPS_COPY) {
+			symname = strtab + symtab[symtab_index].st_name;
+			symbol_addr = (unsigned long)_dl_find_hash(symname,
+								   tpnt->symbol_scope,
+								   tpnt,
+								   elf_machine_type_class(reloc_type));
+			if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))
+				return 1;
+		}
+
 		switch (reloc_type) {
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 		case (R_MIPS_64 << 8) | R_MIPS_REL32:
@@ -148,6 +215,24 @@ int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 				*reloc_addr += (unsigned long) tpnt->loadaddr;
 			}
 			break;
+		case R_MIPS_JUMP_SLOT:
+			*reloc_addr = symbol_addr;
+			break;
+		case R_MIPS_COPY:
+			if (symbol_addr) {
+#if defined (__SUPPORT_LD_DEBUG__)
+				if (_dl_debug_move)
+					_dl_dprintf(_dl_debug_file,
+						    "\n%s move %d bytes from %x to %x",
+						    symname, symtab[symtab_index].st_size,
+						    symbol_addr, reloc_addr);
+#endif
+
+				_dl_memcpy((char *)reloc_addr,
+					   (char *)symbol_addr,
+					   symtab[symtab_index].st_size);
+			}
+			break;
 		case R_MIPS_NONE:
 			break;
 		default:
diff --git a/ldso/ldso/mips/resolve.S b/ldso/ldso/mips/resolve.S
index f5d988a..d7951a1 100644
--- a/ldso/ldso/mips/resolve.S
+++ b/ldso/ldso/mips/resolve.S
@@ -112,3 +112,54 @@ _dl_runtime_resolve:
 .end	_dl_runtime_resolve
 .previous
 
+/* Assembler veneer called from the PLT header code when using the
+   non-PIC ABI.
+
+   Code in each PLT entry puts the caller's return address into t7 ($15),
+   the PLT entry index into t8 ($24), the address of _dl_runtime_pltresolve
+   into t9 ($25) and the address of .got.plt into gp ($28).  __dl_runtime_pltresolve
+   needs a0 ($4) to hold the link map and a1 ($5) to hold the index into
+   .rel.plt (== PLT entry index * 4).  */
+
+	.text
+	.align	2
+	.globl	_dl_runtime_pltresolve
+	.type	_dl_runtime_pltresolve, at function
+	.ent	_dl_runtime_pltresolve
+_dl_runtime_pltresolve:
+	.frame	$29, 40, $31
+	.set noreorder
+	# Save arguments and sp value in stack.
+	subu    $29, 40
+	lw      $10, 4($28)
+	# Modify t9 ($25) so as to point .cpload instruction.
+	addiu   $25, 12
+	# Compute GP.
+	.cpload $25
+	.set reorder
+
+	/* Store function arguments from registers to stack */
+	sw	$15, 36($29)
+	sw	$4, 16($29)
+	sw	$5, 20($29)
+	sw	$6, 24($29)
+	sw	$7, 28($29)
+
+	/* Setup functions args and call __dl_runtime_pltresolve.  */
+	move	$4, $10
+	sll     $5, $24, 3
+	jal	__dl_runtime_pltresolve
+
+	/* Restore function arguments from stack to registers */
+	lw	$31, 36($29)
+	lw	$4, 16($29)
+	lw	$5, 20($29)
+	lw	$6, 24($29)
+	lw	$7, 28($29)
+
+	/* Do a tail call to the original function */
+	addiu	$29, 40
+	move	$25, $2
+	jr	$25
+	.end	_dl_runtime_pltresolve
+	.previous
-- 
1.6.3.3



More information about the uClibc-cvs mailing list