summaryrefslogtreecommitdiff
path: root/ldso/ldso/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'ldso/ldso/sparc')
-rw-r--r--ldso/ldso/sparc/dl-debug.h2
-rw-r--r--ldso/ldso/sparc/dl-startup.h3
-rw-r--r--ldso/ldso/sparc/dl-syscalls.h7
-rw-r--r--ldso/ldso/sparc/dl-sysdep.h29
-rw-r--r--ldso/ldso/sparc/elfinterp.c116
5 files changed, 77 insertions, 80 deletions
diff --git a/ldso/ldso/sparc/dl-debug.h b/ldso/ldso/sparc/dl-debug.h
index 1249f7798..5c62cefad 100644
--- a/ldso/ldso/sparc/dl-debug.h
+++ b/ldso/ldso/sparc/dl-debug.h
@@ -28,7 +28,7 @@
* SUCH DAMAGE.
*/
-static const char * _dl_reltypes_tab[] = {
+static const char * const _dl_reltypes_tab[] = {
"R_SPARC_NONE", "R_SPARC_8",
"R_SPARC_16", "R_SPARC_32", "R_SPARC_DISP8", "R_SPARC_DISP16",
"R_SPARC_DISP32", "R_SPARC_WDISP30", "R_SPARC_WDISP22",
diff --git a/ldso/ldso/sparc/dl-startup.h b/ldso/ldso/sparc/dl-startup.h
index cc11ec103..8c8c2c4f3 100644
--- a/ldso/ldso/sparc/dl-startup.h
+++ b/ldso/ldso/sparc/dl-startup.h
@@ -8,6 +8,7 @@ __asm__ ("\
.text\n\
.global _start\n\
.type _start,%function\n\
+ .hidden _start\n\
.align 32\n\
.register %g2, #scratch\n\
_start:\n\
@@ -47,7 +48,7 @@ _dl_start_user:\n\
/*
* 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
+ * the address of the first argument, on other platforms we need to
* do something a little more subtle here. We assume that argc is stored
* at the word just below the argvp that we return here.
*/
diff --git a/ldso/ldso/sparc/dl-syscalls.h b/ldso/ldso/sparc/dl-syscalls.h
index 996bb87c6..f40c4fd31 100644
--- a/ldso/ldso/sparc/dl-syscalls.h
+++ b/ldso/ldso/sparc/dl-syscalls.h
@@ -1,6 +1 @@
-/* We can't use the real errno in ldso, since it has not yet
- * been dynamicly linked in yet. */
-#include "sys/syscall.h"
-extern int _dl_errno;
-#undef __set_errno
-#define __set_errno(X) {(_dl_errno) = (X);}
+/* stub for arch-specific syscall issues */
diff --git a/ldso/ldso/sparc/dl-sysdep.h b/ldso/ldso/sparc/dl-sysdep.h
index 27cb97e38..d35a39147 100644
--- a/ldso/ldso/sparc/dl-sysdep.h
+++ b/ldso/ldso/sparc/dl-sysdep.h
@@ -29,7 +29,7 @@
/* Here we define the magic numbers that this dynamic loader should accept
* Note that SPARCV9 doesn't use EM_SPARCV9 since the userland is still 32-bit.
*/
-#if defined(__sparc_v9__) || defined(__sparc_v8__)
+#if defined(__sparc_v9__)
#define MAGIC1 EM_SPARC32PLUS
#else
#define MAGIC1 EM_SPARC
@@ -40,6 +40,9 @@
/* Used for error messages */
#define ELF_TARGET "sparc"
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
struct elf_resolve;
unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
@@ -49,7 +52,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry);
#ifndef COMPILE_ASM
/* Cheap modulo implementation, taken from arm/ld_sysdep.h. */
-static __inline__ unsigned long
+static __always_inline unsigned long
sparc_mod(unsigned long m, unsigned long p)
{
unsigned long i, t, inc;
@@ -89,24 +92,14 @@ sparc_mod(unsigned long m, unsigned long p)
#define do_rem(result, n, base) ((result) = sparc_mod(n, base))
#endif
-/* 4096 bytes alignment */
-#if defined(__sparc_v9__)
-/* ...but 8192 is required for mmap() on sparc64 kernel */
-#define PAGE_ALIGN 0xffffe000
-#define ADDR_ALIGN 0x1fff
-#define OFFS_ALIGN 0x7fffe000
-#elif defined(__sparc_v8__)
-#define PAGE_ALIGN 0xfffff000
-#define ADDR_ALIGN 0xfff
-#define OFFS_ALIGN 0x7ffff000
-#endif
-
/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so
PLT entries should not be allowed to define the value.
ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
of the main executable's symbols, as for a COPY reloc. */
#define elf_machine_type_class(type) \
- ((((type) == R_SPARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ ((((type) == R_SPARC_JMP_SLOT || (type) == R_SPARC_TLS_DTPMOD32 \
+ || (type) == R_SPARC_TLS_DTPOFF32 || (type) == R_SPARC_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
| (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
/* The SPARC overlaps DT_RELA and DT_PLTREL. */
@@ -127,7 +120,7 @@ do { register Elf32_Addr pc __asm__("o7"); \
/* Return the link-time address of _DYNAMIC. Conveniently, this is the
first element of the GOT. This must be inlined in a function which
uses global data. */
-static __inline__ Elf32_Addr
+static __always_inline Elf32_Addr
elf_machine_dynamic (void)
{
register Elf32_Addr *got __asm__ ("%l7");
@@ -138,7 +131,7 @@ elf_machine_dynamic (void)
}
/* Return the run-time load address of the shared object. */
-static __inline__ Elf32_Addr
+static __always_inline Elf32_Addr
elf_machine_load_address (void)
{
register Elf32_Addr *pc __asm__ ("%o7"), *got __asm__ ("%l7");
@@ -157,7 +150,7 @@ elf_machine_load_address (void)
return (Elf32_Addr) got - *got + (pc[2] - pc[3]) * 4 - 4;
}
-static __inline__ void
+static __always_inline void
elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
Elf32_Word relative_count)
{
diff --git a/ldso/ldso/sparc/elfinterp.c b/ldso/ldso/sparc/elfinterp.c
index 9b425fcee..bb61be9eb 100644
--- a/ldso/ldso/sparc/elfinterp.c
+++ b/ldso/ldso/sparc/elfinterp.c
@@ -52,7 +52,6 @@ extern int _dl_linux_resolve(void);
unsigned long
_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
{
- int reloc_type;
ELF_RELOC *this_reloc;
char *strtab;
ElfW(Sym) *symtab;
@@ -70,25 +69,18 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
reloc_entry = (reloc_entry >> 10) - 0xc;
this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry);
- reloc_type = ELF_R_TYPE(this_reloc->r_info);
symtab_index = ELF_R_SYM(this_reloc->r_info);
symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
symname = strtab + symtab[symtab_index].st_name;
- if (unlikely(reloc_type != R_SPARC_JMP_SLOT)) {
- _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
- _dl_progname);
- _dl_exit(1);
- }
-
/* Address of the jump instruction to fix up. */
instr_addr = (this_reloc->r_offset + 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);
+ new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
if (unlikely(!new_addr)) {
_dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname);
_dl_exit(1);
@@ -107,17 +99,17 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
if (!_dl_debug_nofixups)
#endif
{
- got_addr[1] = (char *) (0x03000000 | (((unsigned int) new_addr >> 10) & 0x3fffff));
- got_addr[2] = (char *) (0x81c06000 | ((unsigned int) new_addr & 0x3ff));
+ got_addr[1] = (char *) (OPCODE_SETHI_G1 | (((unsigned int) new_addr >> 10) & 0x3fffff));
+ got_addr[2] = (char *) (OPCODE_JMP_G1 | ((unsigned int) new_addr & 0x3ff));
}
return (unsigned long)new_addr;
}
static int
-_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
unsigned long rel_addr, unsigned long rel_size,
- int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope,
+ int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
{
unsigned int i;
@@ -172,13 +164,14 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
}
static int
-_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
{
int reloc_type;
int symtab_index;
char *symname;
- ElfW(Sym) *sym;
+ struct elf_resolve *tls_tpnt = NULL;
+ struct symbol_ref sym_ref;
ElfW(Addr) *reloc_addr;
ElfW(Addr) symbol_addr;
#if defined (__SUPPORT_LD_DEBUG__)
@@ -188,22 +181,36 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
reloc_type = ELF_R_TYPE(rpnt->r_info);
symtab_index = ELF_R_SYM(rpnt->r_info);
- sym = &symtab[symtab_index];
+ sym_ref.sym = &symtab[symtab_index];
+ sym_ref.tpnt = NULL;
symbol_addr = 0;
- symname = strtab + sym->st_name;
+ symname = strtab + sym_ref.sym->st_name;
if (symtab_index) {
symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt,
- elf_machine_type_class(reloc_type));
+ elf_machine_type_class(reloc_type), &sym_ref);
/*
* We want to allow undefined references to weak symbols - this
* might have been intentional. We should not be linking local
* symbols here, so all bases should be covered.
*/
- if (unlikely(!symbol_addr && ELF_ST_BIND(sym->st_info) != STB_WEAK)) {
- _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
- _dl_exit(1);
+ if (unlikely(!symbol_addr && (ELF_ST_TYPE(sym_ref.sym->st_info) != STT_TLS)
+ && (ELF_ST_BIND(sym_ref.sym->st_info) != STB_WEAK))) {
+ /* This may be non-fatal if called from dlopen. */
+ return 1;
+
}
+ if (_dl_trace_prelink) {
+ _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+ &sym_ref, elf_machine_type_class(reloc_type));
+ }
+ tls_tpnt = sym_ref.tpnt;
+ } else {
+ /* Relocs against STN_UNDEF are usually treated as using a
+ * symbol value of zero, and using the module containing the
+ * reloc itself. */
+ symbol_addr = sym_ref.sym->st_value;
+ tls_tpnt = tpnt;
}
#if defined (__SUPPORT_LD_DEBUG__)
@@ -216,21 +223,6 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
case R_SPARC_NONE:
break;
-#if 0 /* these dont really seem to be useful */
- case R_SPARC_8:
- *(char *) reloc_addr = symbol_addr;
- break;
- case R_SPARC_16:
- *(short *) reloc_addr = symbol_addr;
- break;
- case R_SPARC_DISP8:
- *(char *) reloc_addr = (symbol_addr) - (Elf32_Addr) reloc_addr;
- break;
- case R_SPARC_DISP16:
- *(short *) reloc_addr = (symbol_addr) - (Elf32_Addr) reloc_addr;
- break;
-#endif
-
case R_SPARC_DISP32:
*reloc_addr = symbol_addr - (unsigned int) reloc_addr;
break;
@@ -240,7 +232,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
symbol_addr = tpnt->loadaddr + rpnt->r_addend;
else
symbol_addr += rpnt->r_addend;
- *reloc_addr = (*reloc_addr & ~0x3ff)|(symbol_addr & 0x3ff);
+ *reloc_addr = (*reloc_addr & ~0x3ff) | (symbol_addr & 0x3ff);
break;
case R_SPARC_GLOB_DAT:
@@ -249,17 +241,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
break;
case R_SPARC_JMP_SLOT:
-/*
-value = symbol_addr;
-value += reloc->r_addend;
-disp = value - reloc_addr;
-reloc_addr[1] = OPCODE_JMP_G1 | (value & 0x3ff);
-reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
- reloc_addr[1] = OPCODE_JMP_G1 | ((symbol_addr-(Elf32_Addr)reloc_addr) & 0x3ff);
- reloc_addr[0] = OPCODE_SETHI_G1 | ((symbol_addr-(Elf32_Addr)reloc_addr) >> 10);
-*/
- reloc_addr[1] = 0x03000000 | ((symbol_addr >> 10) & 0x3fffff);
- reloc_addr[2] = 0x81c06000 | (symbol_addr & 0x3ff);
+ reloc_addr[1] = OPCODE_SETHI_G1 | (( symbol_addr >> 10 ) & 0x3fffff);
+ reloc_addr[2] = OPCODE_JMP_G1 | ( symbol_addr & 0x3ff );
break;
case R_SPARC_RELATIVE:
@@ -285,16 +268,39 @@ reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
if (_dl_debug_move)
_dl_dprintf(_dl_debug_file,
"\t%s move %d bytes from %x to %x\n",
- symname, sym->st_size,
+ symname, sym_ref.sym->st_size,
symbol_addr, reloc_addr);
#endif
_dl_memcpy((char *)reloc_addr,
(char *)symbol_addr,
- sym->st_size);
- } else
+ sym_ref.sym->st_size);
+ }
+#if defined (__SUPPORT_LD_DEBUG__)
+ else
_dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n");
+#endif
+ break;
+#if defined USE_TLS && USE_TLS
+ case R_SPARC_TLS_DTPMOD32:
+ *reloc_addr = tls_tpnt->l_tls_modid;
break;
+
+ case R_SPARC_TLS_DTPOFF32:
+ /* During relocation all TLS symbols are defined and used.
+ * Therefore the offset is already correct. */
+ *reloc_addr = sym_ref.sym->st_value + rpnt->r_addend;
+ break;
+
+ case R_SPARC_TLS_TPOFF32:
+ /* The offset is negative, forward from the thread pointer.
+ * We know the offset of the object the symbol is contained in.
+ * It is a negative value which will be added to the
+ * thread pointer. */
+ CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+ *reloc_addr = sym_ref.sym->st_value - tls_tpnt->l_tls_offset + rpnt->r_addend;
+ break;
+#endif
default:
return -1; /* Calls _dl_exit(1). */
}
@@ -311,7 +317,7 @@ reloc_addr[0] = OPCODE_SETHI_G1 | (value >> 10);
#undef __SPARC_LAZY_RELOC_WORKS
#ifdef __SPARC_LAZY_RELOC_WORKS
static int
-_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
{
int reloc_type;
@@ -359,14 +365,16 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
#ifdef __SPARC_LAZY_RELOC_WORKS
(void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
#else
- _dl_parse_relocation_information(rpnt, rel_addr, rel_size);
+ _dl_parse_relocation_information(rpnt, &_dl_loaded_modules->symbol_scope,
+ rel_addr, rel_size);
#endif
}
int
_dl_parse_relocation_information(struct dyn_elf *rpnt,
+ struct r_scope_elem *scope,
unsigned long rel_addr,
unsigned long rel_size)
{
- return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
+ return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
}