|
Packit |
6c4009 |
/* PLT trampoline. MIPS version.
|
|
Packit |
6c4009 |
Copyright (C) 1996-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
Contributed by Kazumoto Kojima <kkojima@info.kanagawa-u.ac.jp>.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library. If not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* FIXME: Profiling of shared libraries is not implemented yet. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <sysdep.h>
|
|
Packit |
6c4009 |
#include <link.h>
|
|
Packit |
6c4009 |
#include <elf.h>
|
|
Packit |
6c4009 |
#include <ldsodefs.h>
|
|
Packit |
6c4009 |
#include <dl-machine.h>
|
|
Packit |
6c4009 |
#include <sysdep-cancel.h>
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Get link map for callers object containing STUB_PC. */
|
|
Packit |
6c4009 |
static inline struct link_map *
|
|
Packit |
6c4009 |
elf_machine_runtime_link_map (ElfW(Addr) gpreg, ElfW(Addr) stub_pc)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
extern int _dl_mips_gnu_objects;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* got[1] is reserved to keep its link map address for the shared
|
|
Packit |
6c4009 |
object generated by the gnu linker. If all are such objects, we
|
|
Packit |
6c4009 |
can find the link map from current GPREG simply. If not so, get
|
|
Packit |
6c4009 |
the link map for caller's object containing STUB_PC. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (_dl_mips_gnu_objects)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
ElfW(Addr) *got = elf_mips_got_from_gpreg (gpreg);
|
|
Packit |
6c4009 |
ElfW(Word) g1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
g1 = ((ElfW(Word) *) got)[1];
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if ((g1 & ELF_MIPS_GNU_GOT1_MASK) != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct link_map *l =
|
|
Packit |
6c4009 |
(struct link_map *) (g1 & ~ELF_MIPS_GNU_GOT1_MASK);
|
|
Packit |
6c4009 |
ElfW(Addr) base, limit;
|
|
Packit |
6c4009 |
const ElfW(Phdr) *p = l->l_phdr;
|
|
Packit |
6c4009 |
ElfW(Half) this, nent = l->l_phnum;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* For the common case of a stub being called from the containing
|
|
Packit |
6c4009 |
object, STUB_PC will point to somewhere within the object that
|
|
Packit |
6c4009 |
is described by the link map fetched via got[1]. Otherwise we
|
|
Packit |
6c4009 |
have to scan all maps. */
|
|
Packit |
6c4009 |
for (this = 0; this < nent; this++)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (p[this].p_type == PT_LOAD)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
base = p[this].p_vaddr + l->l_addr;
|
|
Packit |
6c4009 |
limit = base + p[this].p_memsz;
|
|
Packit |
6c4009 |
if (stub_pc >= base && stub_pc < limit)
|
|
Packit |
6c4009 |
return l;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct link_map *l;
|
|
Packit |
6c4009 |
Lmid_t nsid;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
for (nsid = 0; nsid < DL_NNS; ++nsid)
|
|
Packit |
6c4009 |
for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
ElfW(Addr) base, limit;
|
|
Packit |
6c4009 |
const ElfW(Phdr) *p = l->l_phdr;
|
|
Packit |
6c4009 |
ElfW(Half) this, nent = l->l_phnum;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
for (this = 0; this < nent; ++this)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (p[this].p_type == PT_LOAD)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
base = p[this].p_vaddr + l->l_addr;
|
|
Packit |
6c4009 |
limit = base + p[this].p_memsz;
|
|
Packit |
6c4009 |
if (stub_pc >= base && stub_pc < limit)
|
|
Packit |
6c4009 |
return l;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
_dl_signal_error (0, NULL, NULL, "cannot find runtime link map");
|
|
Packit |
6c4009 |
return NULL;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Define mips specific runtime resolver. The function __dl_runtime_resolve
|
|
Packit |
6c4009 |
is called from assembler function _dl_runtime_resolve which converts
|
|
Packit |
6c4009 |
special argument registers t7 ($15) and t8 ($24):
|
|
Packit |
6c4009 |
t7 address to return to the caller of the function
|
|
Packit |
6c4009 |
t8 index for this function symbol in .dynsym
|
|
Packit |
6c4009 |
to usual c arguments.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
Other architectures call fixup from dl-runtime.c in
|
|
Packit |
6c4009 |
_dl_runtime_resolve. MIPS instead calls __dl_runtime_resolve. We
|
|
Packit |
6c4009 |
have to use our own version because of the way the got section is
|
|
Packit |
6c4009 |
treated on MIPS (we've also got ELF_MACHINE_PLT defined). */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* The flag _dl_mips_gnu_objects is set if all dynamic objects are
|
|
Packit |
6c4009 |
generated by the gnu linker. */
|
|
Packit |
6c4009 |
int _dl_mips_gnu_objects = 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* This is called from assembly stubs below which the compiler can't see. */
|
|
Packit |
6c4009 |
static ElfW(Addr)
|
|
Packit |
6c4009 |
__dl_runtime_resolve (ElfW(Word), ElfW(Word), ElfW(Addr), ElfW(Addr))
|
|
Packit |
6c4009 |
__attribute_used__;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static ElfW(Addr)
|
|
Packit |
6c4009 |
__dl_runtime_resolve (ElfW(Word) sym_index,
|
|
Packit |
6c4009 |
ElfW(Word) return_address,
|
|
Packit |
6c4009 |
ElfW(Addr) old_gpreg,
|
|
Packit |
6c4009 |
ElfW(Addr) stub_pc)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct link_map *l = elf_machine_runtime_link_map (old_gpreg, stub_pc);
|
|
Packit |
6c4009 |
const ElfW(Sym) *const symtab
|
|
Packit |
6c4009 |
= (const ElfW(Sym) *) D_PTR (l, l_info[DT_SYMTAB]);
|
|
Packit |
6c4009 |
const char *strtab = (const void *) D_PTR (l, l_info[DT_STRTAB]);
|
|
Packit |
6c4009 |
ElfW(Addr) *got
|
|
Packit |
6c4009 |
= (ElfW(Addr) *) D_PTR (l, l_info[DT_PLTGOT]);
|
|
Packit |
6c4009 |
const ElfW(Word) local_gotno
|
|
Packit |
6c4009 |
= (const ElfW(Word)) l->l_info[DT_MIPS (LOCAL_GOTNO)]->d_un.d_val;
|
|
Packit |
6c4009 |
const ElfW(Word) gotsym
|
|
Packit |
6c4009 |
= (const ElfW(Word)) l->l_info[DT_MIPS (GOTSYM)]->d_un.d_val;
|
|
Packit |
6c4009 |
const ElfW(Sym) *sym = &symtab[sym_index];
|
|
Packit |
6c4009 |
struct link_map *sym_map;
|
|
Packit |
6c4009 |
ElfW(Addr) value;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* FIXME: The symbol versioning stuff is not tested yet. */
|
|
Packit |
6c4009 |
if (__builtin_expect (ELFW(ST_VISIBILITY) (sym->st_other), 0) == 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
switch (l->l_info[VERSYMIDX (DT_VERSYM)] != NULL ? 1 : 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
default:
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const ElfW(Half) *vernum =
|
|
Packit |
6c4009 |
(const void *) D_PTR (l, l_info[VERSYMIDX (DT_VERSYM)]);
|
|
Packit |
6c4009 |
ElfW(Half) ndx = vernum[sym_index] & 0x7fff;
|
|
Packit |
6c4009 |
const struct r_found_version *version = &l->l_versions[ndx];
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (version->hash != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* We need to keep the scope around so do some locking. This is
|
|
Packit |
6c4009 |
not necessary for objects which cannot be unloaded or when
|
|
Packit |
6c4009 |
we are not using any threads (yet). */
|
|
Packit |
6c4009 |
if (!RTLD_SINGLE_THREAD_P)
|
|
Packit |
6c4009 |
THREAD_GSCOPE_SET_FLAG ();
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l,
|
|
Packit |
6c4009 |
&sym, l->l_scope, version,
|
|
Packit |
6c4009 |
ELF_RTYPE_CLASS_PLT, 0, 0);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* We are done with the global scope. */
|
|
Packit |
6c4009 |
if (!RTLD_SINGLE_THREAD_P)
|
|
Packit |
6c4009 |
THREAD_GSCOPE_RESET_FLAG ();
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
/* Fall through. */
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
case 0:
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* We need to keep the scope around so do some locking. This is
|
|
Packit |
6c4009 |
not necessary for objects which cannot be unloaded or when
|
|
Packit |
6c4009 |
we are not using any threads (yet). */
|
|
Packit |
6c4009 |
int flags = DL_LOOKUP_ADD_DEPENDENCY;
|
|
Packit |
6c4009 |
if (!RTLD_SINGLE_THREAD_P)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
THREAD_GSCOPE_SET_FLAG ();
|
|
Packit |
6c4009 |
flags |= DL_LOOKUP_GSCOPE_LOCK;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
sym_map = _dl_lookup_symbol_x (strtab + sym->st_name, l, &sym,
|
|
Packit |
6c4009 |
l->l_scope, 0, ELF_RTYPE_CLASS_PLT,
|
|
Packit |
6c4009 |
flags, 0);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* We are done with the global scope. */
|
|
Packit |
6c4009 |
if (!RTLD_SINGLE_THREAD_P)
|
|
Packit |
6c4009 |
THREAD_GSCOPE_RESET_FLAG ();
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Currently value contains the base load address of the object
|
|
Packit |
6c4009 |
that defines sym. Now add in the symbol offset. */
|
|
Packit |
6c4009 |
value = SYMBOL_ADDRESS (sym_map, sym, true);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
/* We already found the symbol. The module (and therefore its load
|
|
Packit |
6c4009 |
address) is also known. */
|
|
Packit |
6c4009 |
value = SYMBOL_ADDRESS (l, sym, true);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Apply the relocation with that value. */
|
|
Packit |
6c4009 |
*(got + local_gotno + sym_index - gotsym) = value;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#if _MIPS_SIM == _ABIO32
|
|
Packit |
6c4009 |
#define ELF_DL_FRAME_SIZE 40
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
sw $15, 36($29)\n \
|
|
Packit |
6c4009 |
sw $4, 16($29)\n \
|
|
Packit |
6c4009 |
sw $5, 20($29)\n \
|
|
Packit |
6c4009 |
sw $6, 24($29)\n \
|
|
Packit |
6c4009 |
sw $7, 28($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
lw $31, 36($29)\n \
|
|
Packit |
6c4009 |
lw $4, 16($29)\n \
|
|
Packit |
6c4009 |
lw $5, 20($29)\n \
|
|
Packit |
6c4009 |
lw $6, 24($29)\n \
|
|
Packit |
6c4009 |
lw $7, 28($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* The PLT resolver should also save and restore $2 and $3, which are used
|
|
Packit |
6c4009 |
as arguments to MIPS16 stub functions. */
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_FRAME_SIZE 48
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_SAVE_ARG_REGS \
|
|
Packit |
6c4009 |
ELF_DL_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
sw $2, 40($29)\n \
|
|
Packit |
6c4009 |
sw $3, 44($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_RESTORE_ARG_REGS \
|
|
Packit |
6c4009 |
ELF_DL_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
lw $2, 40($29)\n \
|
|
Packit |
6c4009 |
lw $3, 44($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define IFABIO32(X) X
|
|
Packit |
6c4009 |
#define IFNEWABI(X)
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#else /* _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64 */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_FRAME_SIZE 80
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
sd $15, 72($29)\n \
|
|
Packit |
6c4009 |
sd $4, 8($29)\n \
|
|
Packit |
6c4009 |
sd $5, 16($29)\n \
|
|
Packit |
6c4009 |
sd $6, 24($29)\n \
|
|
Packit |
6c4009 |
sd $7, 32($29)\n \
|
|
Packit |
6c4009 |
sd $8, 40($29)\n \
|
|
Packit |
6c4009 |
sd $9, 48($29)\n \
|
|
Packit |
6c4009 |
sd $10, 56($29)\n \
|
|
Packit |
6c4009 |
sd $11, 64($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
ld $31, 72($29)\n \
|
|
Packit |
6c4009 |
ld $4, 8($29)\n \
|
|
Packit |
6c4009 |
ld $5, 16($29)\n \
|
|
Packit |
6c4009 |
ld $6, 24($29)\n \
|
|
Packit |
6c4009 |
ld $7, 32($29)\n \
|
|
Packit |
6c4009 |
ld $8, 40($29)\n \
|
|
Packit |
6c4009 |
ld $9, 48($29)\n \
|
|
Packit |
6c4009 |
ld $10, 56($29)\n \
|
|
Packit |
6c4009 |
ld $11, 64($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* The PLT resolver should also save and restore $2 and $3, which are used
|
|
Packit |
6c4009 |
as arguments to MIPS16 stub functions. */
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_FRAME_SIZE 96
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_SAVE_ARG_REGS \
|
|
Packit |
6c4009 |
ELF_DL_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
sd $2, 80($29)\n \
|
|
Packit |
6c4009 |
sd $3, 88($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define ELF_DL_PLT_RESTORE_ARG_REGS \
|
|
Packit |
6c4009 |
ELF_DL_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
ld $2, 80($29)\n \
|
|
Packit |
6c4009 |
ld $3, 88($29)\n \
|
|
Packit |
6c4009 |
"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define IFABIO32(X)
|
|
Packit |
6c4009 |
#define IFNEWABI(X) X
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifndef __mips16
|
|
Packit |
6c4009 |
asm ("\n\
|
|
Packit |
6c4009 |
.text\n\
|
|
Packit |
6c4009 |
.align 2\n\
|
|
Packit |
6c4009 |
.set nomips16\n\
|
|
Packit |
6c4009 |
.globl _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
.type _dl_runtime_resolve,@function\n\
|
|
Packit |
6c4009 |
.ent _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
_dl_runtime_resolve:\n\
|
|
Packit |
6c4009 |
.frame $29, " STRINGXP(ELF_DL_FRAME_SIZE) ", $31\n\
|
|
Packit |
6c4009 |
.set noreorder\n\
|
|
Packit |
6c4009 |
# Save GP.\n\
|
|
Packit |
6c4009 |
1: move $3, $28\n\
|
|
Packit |
6c4009 |
# Save arguments and sp value in stack.\n\
|
|
Packit |
6c4009 |
" STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
# Modify t9 ($25) so as to point .cpload instruction.\n\
|
|
Packit |
6c4009 |
" IFABIO32(STRINGXP(PTR_ADDIU) " $25, (2f-1b)\n") "\
|
|
Packit |
6c4009 |
# Compute GP.\n\
|
|
Packit |
6c4009 |
2: " STRINGXP(SETUP_GP) "\n\
|
|
Packit |
6c4009 |
" STRINGXV(SETUP_GP64 (0, _dl_runtime_resolve)) "\n\
|
|
Packit |
6c4009 |
.set reorder\n\
|
|
Packit |
6c4009 |
# Save slot call pc.\n\
|
|
Packit |
6c4009 |
move $2, $31\n\
|
|
Packit |
6c4009 |
" IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
|
|
Packit |
6c4009 |
" ELF_DL_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
move $4, $24\n\
|
|
Packit |
6c4009 |
move $5, $15\n\
|
|
Packit |
6c4009 |
move $6, $3\n\
|
|
Packit |
6c4009 |
move $7, $2\n\
|
|
Packit |
6c4009 |
jal __dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
" ELF_DL_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
" STRINGXP(RESTORE_GP64) "\n\
|
|
Packit |
6c4009 |
" STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
move $25, $2\n\
|
|
Packit |
6c4009 |
jr $25\n\
|
|
Packit |
6c4009 |
.end _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
.previous\n\
|
|
Packit |
6c4009 |
");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Assembler veneer called from the PLT header code when using PLTs.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
Code in each PLT entry and the PLT header fills in the arguments to
|
|
Packit |
6c4009 |
this function:
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
- $15 (o32 t7, n32/n64 t3) - caller's return address
|
|
Packit |
6c4009 |
- $24 (t8) - PLT entry index
|
|
Packit |
6c4009 |
- $25 (t9) - address of _dl_runtime_pltresolve
|
|
Packit |
6c4009 |
- o32 $28 (gp), n32/n64 $14 (t2) - address of .got.plt
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
Different registers are used for .got.plt because the ABI was
|
|
Packit |
6c4009 |
originally designed for o32, where gp was available (call
|
|
Packit |
6c4009 |
clobbered). On n32/n64 gp is call saved.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
_dl_fixup needs:
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
- $4 (a0) - link map address
|
|
Packit |
6c4009 |
- $5 (a1) - .rel.plt offset (== PLT entry index * 8) */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
asm ("\n\
|
|
Packit |
6c4009 |
.text\n\
|
|
Packit |
6c4009 |
.align 2\n\
|
|
Packit |
6c4009 |
.set nomips16\n\
|
|
Packit |
6c4009 |
.globl _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
.type _dl_runtime_pltresolve,@function\n\
|
|
Packit |
6c4009 |
.ent _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
_dl_runtime_pltresolve:\n\
|
|
Packit |
6c4009 |
.frame $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
|
|
Packit |
6c4009 |
.set noreorder\n\
|
|
Packit |
6c4009 |
# Save arguments and sp value in stack.\n\
|
|
Packit |
6c4009 |
1: " STRINGXP(PTR_SUBIU) " $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
" IFABIO32(STRINGXP(PTR_L) " $13, " STRINGXP(PTRSIZE) "($28)") "\n\
|
|
Packit |
6c4009 |
" IFNEWABI(STRINGXP(PTR_L) " $13, " STRINGXP(PTRSIZE) "($14)") "\n\
|
|
Packit |
6c4009 |
# Modify t9 ($25) so as to point .cpload instruction.\n\
|
|
Packit |
6c4009 |
" IFABIO32(STRINGXP(PTR_ADDIU) " $25, (2f-1b)\n") "\
|
|
Packit |
6c4009 |
# Compute GP.\n\
|
|
Packit |
6c4009 |
2: " STRINGXP(SETUP_GP) "\n\
|
|
Packit |
6c4009 |
" STRINGXV(SETUP_GP64 (0, _dl_runtime_pltresolve)) "\n\
|
|
Packit |
6c4009 |
.set reorder\n\
|
|
Packit |
6c4009 |
" IFABIO32(STRINGXP(CPRESTORE(32))) "\n\
|
|
Packit |
6c4009 |
" ELF_DL_PLT_SAVE_ARG_REGS "\
|
|
Packit |
6c4009 |
move $4, $13\n\
|
|
Packit |
6c4009 |
sll $5, $24, " STRINGXP(PTRLOG) " + 1\n\
|
|
Packit |
6c4009 |
jal _dl_fixup\n\
|
|
Packit |
6c4009 |
move $25, $2\n\
|
|
Packit |
6c4009 |
" ELF_DL_PLT_RESTORE_ARG_REGS "\
|
|
Packit |
6c4009 |
" STRINGXP(RESTORE_GP64) "\n\
|
|
Packit |
6c4009 |
" STRINGXP(PTR_ADDIU) " $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
jr $25\n\
|
|
Packit |
6c4009 |
.end _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
.previous\n\
|
|
Packit |
6c4009 |
");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#elif _MIPS_SIM == _ABIO32 /* __mips16 */
|
|
Packit |
6c4009 |
/* MIPS16 version, O32 only. */
|
|
Packit |
6c4009 |
asm ("\n\
|
|
Packit |
6c4009 |
.text\n\
|
|
Packit |
6c4009 |
.align 2\n\
|
|
Packit |
6c4009 |
.set mips16\n\
|
|
Packit |
6c4009 |
.globl _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
.type _dl_runtime_resolve,@function\n\
|
|
Packit |
6c4009 |
.ent _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
_dl_runtime_resolve:\n\
|
|
Packit |
6c4009 |
.frame $29, " STRINGXP (ELF_DL_FRAME_SIZE) ", $31\n\
|
|
Packit |
6c4009 |
# Save arguments and sp value in stack.\n\t"
|
|
Packit |
6c4009 |
# if _MIPS_ISA >= _MIPS_ISA_MIPS32
|
|
Packit |
6c4009 |
"save " STRINGXP (ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
"addiu $sp, -" STRINGXP (ELF_DL_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
sw $7, 32($sp)\n\
|
|
Packit |
6c4009 |
sw $6, 28($sp)\n\
|
|
Packit |
6c4009 |
sw $5, 24($sp)\n\
|
|
Packit |
6c4009 |
sw $4, 20($sp)\n\t"
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
"# Preserve caller's $ra, for RESTORE instruction below.\n\
|
|
Packit |
6c4009 |
move $5, $15\n\
|
|
Packit |
6c4009 |
sw $5, 36($sp)\n\
|
|
Packit |
6c4009 |
# Compute GP into $2.\n\
|
|
Packit |
6c4009 |
li $2, %hi(_gp_disp)\n\
|
|
Packit |
6c4009 |
addiu $3, $pc, %lo(_gp_disp)\n\
|
|
Packit |
6c4009 |
sll $2, 16\n\
|
|
Packit |
6c4009 |
addu $2, $3\n\
|
|
Packit |
6c4009 |
lw $3, %got(__dl_runtime_resolve)($2)\n\
|
|
Packit |
6c4009 |
move $4, $24\n\
|
|
Packit |
6c4009 |
addiu $3, %lo(__dl_runtime_resolve)\n\
|
|
Packit |
6c4009 |
move $7, $ra\n\
|
|
Packit |
6c4009 |
move $6, $28\n\
|
|
Packit |
6c4009 |
move $25, $3\n\
|
|
Packit |
6c4009 |
jalr $3\n\t"
|
|
Packit |
6c4009 |
# if _MIPS_ISA >= _MIPS_ISA_MIPS32
|
|
Packit |
6c4009 |
"restore " STRINGXP(ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
"# Restore $ra, move placed further down to hide latency.\n\
|
|
Packit |
6c4009 |
lw $4, 36($sp)\n\
|
|
Packit |
6c4009 |
lw $5, 24($sp)\n\
|
|
Packit |
6c4009 |
lw $6, 28($sp)\n\
|
|
Packit |
6c4009 |
lw $7, 32($sp)\n\
|
|
Packit |
6c4009 |
move $ra, $4\n\
|
|
Packit |
6c4009 |
lw $4, 20($sp)\n\
|
|
Packit |
6c4009 |
addiu $sp, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\t"
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
"move $25, $2\n\
|
|
Packit |
6c4009 |
jr $2\n\
|
|
Packit |
6c4009 |
.end _dl_runtime_resolve\n\
|
|
Packit |
6c4009 |
.previous\n\
|
|
Packit |
6c4009 |
");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
asm ("\n\
|
|
Packit |
6c4009 |
.text\n\
|
|
Packit |
6c4009 |
.align 2\n\
|
|
Packit |
6c4009 |
.set mips16\n\
|
|
Packit |
6c4009 |
.globl _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
.type _dl_runtime_pltresolve,@function\n\
|
|
Packit |
6c4009 |
.ent _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
_dl_runtime_pltresolve:\n\
|
|
Packit |
6c4009 |
.frame $29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
|
|
Packit |
6c4009 |
# Save arguments and sp value in stack.\n\t"
|
|
Packit |
6c4009 |
# if _MIPS_ISA >= _MIPS_ISA_MIPS32
|
|
Packit |
6c4009 |
"save " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
"addiu $sp, -" STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
|
|
Packit |
6c4009 |
sw $7, 40($sp)\n\
|
|
Packit |
6c4009 |
sw $6, 36($sp)\n\
|
|
Packit |
6c4009 |
sw $5, 32($sp)\n\
|
|
Packit |
6c4009 |
sw $4, 28($sp)\n\t"
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
"# Preserve MIPS16 stub function arguments.\n\
|
|
Packit |
6c4009 |
sw $3, 20($sp)\n\
|
|
Packit |
6c4009 |
sw $2, 16($sp)\n\
|
|
Packit |
6c4009 |
# Preserve caller's $ra, for RESTORE instruction below.\n\
|
|
Packit |
6c4009 |
move $3, $15\n\
|
|
Packit |
6c4009 |
sw $3, 44($sp)\n\
|
|
Packit |
6c4009 |
# Compute GP into $2.\n\
|
|
Packit |
6c4009 |
li $2, %hi(_gp_disp)\n\
|
|
Packit |
6c4009 |
addiu $3, $pc, %lo(_gp_disp)\n\
|
|
Packit |
6c4009 |
sll $2, 16\n\
|
|
Packit |
6c4009 |
addu $2, $3\n\
|
|
Packit |
6c4009 |
# Save GP value in slot.\n\
|
|
Packit |
6c4009 |
sw $2, 24($sp)\n\
|
|
Packit |
6c4009 |
# Load _dl_fixup address.\n\
|
|
Packit |
6c4009 |
lw $6, %call16(_dl_fixup)($2)\n\
|
|
Packit |
6c4009 |
# Load link map address.\n\
|
|
Packit |
6c4009 |
move $3, $28\n\
|
|
Packit |
6c4009 |
lw $4, " STRINGXP (PTRSIZE) "($3)\n\
|
|
Packit |
6c4009 |
move $5, $24\n\
|
|
Packit |
6c4009 |
sll $5, " STRINGXP (PTRLOG) " + 1\n\
|
|
Packit |
6c4009 |
# Call _dl_fixup.\n\
|
|
Packit |
6c4009 |
move $25, $6\n\
|
|
Packit |
6c4009 |
jalr $6\n\
|
|
Packit |
6c4009 |
move $25, $2\n\
|
|
Packit |
6c4009 |
# Reload GP value into $28.\n\
|
|
Packit |
6c4009 |
lw $3, 24($sp)\n\
|
|
Packit |
6c4009 |
move $28, $3\n\
|
|
Packit |
6c4009 |
lw $3, 16($sp)\n\
|
|
Packit |
6c4009 |
move $15, $3\n\
|
|
Packit |
6c4009 |
lw $3, 20($sp)\n\t"
|
|
Packit |
6c4009 |
# if _MIPS_ISA >= _MIPS_ISA_MIPS32
|
|
Packit |
6c4009 |
"restore " STRINGXP (ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
|
|
Packit |
6c4009 |
# else
|
|
Packit |
6c4009 |
"# Restore $ra, move placed further down to hide latency.\n\
|
|
Packit |
6c4009 |
lw $4, 44($sp)\n\
|
|
Packit |
6c4009 |
lw $5, 32($sp)\n\
|
|
Packit |
6c4009 |
lw $6, 36($sp)\n\
|
|
Packit |
6c4009 |
lw $7, 40($sp)\n\
|
|
Packit |
6c4009 |
move $ra, $4\n\
|
|
Packit |
6c4009 |
lw $4, 28($sp)\n\
|
|
Packit |
6c4009 |
addiu $sp, " STRINGXP (ELF_DL_PLT_FRAME_SIZE) "\n\t"
|
|
Packit |
6c4009 |
# endif
|
|
Packit |
6c4009 |
".set noreorder\n\
|
|
Packit |
6c4009 |
jr $2\n\
|
|
Packit |
6c4009 |
move $2, $15\n\
|
|
Packit |
6c4009 |
.set reorder\n\
|
|
Packit |
6c4009 |
.end _dl_runtime_pltresolve\n\
|
|
Packit |
6c4009 |
.previous\n\
|
|
Packit |
6c4009 |
");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#else /* __mips16 && _MIPS_SIM != _ABIO32 */
|
|
Packit |
6c4009 |
# error "MIPS16 support for N32/N64 not implemented"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#endif /* __mips16 */
|