Add an approximation of the necessary sparc bits in here.

I've not followed the trend in this file by trying to wrench the MD
code into individual functions. Rather I,ve replaced several functions
wholesale.  Anyway, this whole file needs to be re-done.
This commit is contained in:
pk 1999-02-22 17:06:11 +00:00
parent 220b8d9add
commit 4c7fbbb5c8
1 changed files with 256 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: reloc.c,v 1.8 1999/02/13 16:35:14 christos Exp $ */
/* $NetBSD: reloc.c,v 1.9 1999/02/22 17:06:11 pk Exp $ */
/*
* Copyright 1996 John D. Polstra.
@ -138,7 +138,241 @@ _rtld_do_copy_relocations(
return 0;
}
#ifdef __sparc__
/*
* The following table holds for each relocation type:
* - the width in bits of the memory location the relocation
* applies to (not currently used)
* - the number of bits the relocation value must be shifted to the
* right (i.e. discard least significant bits) to fit into
* the appropriate field in the instruction word.
* - flags indicating whether
* * the relocation involves a symbol
* * the relocation is relative to the current position
* * the relocation is for a GOT entry
* * the relocation is relative to the load address
*
*/
#define _RF_S 0x80000000 /* Resolve symbol */
#define _RF_A 0x40000000 /* Use addend */
#define _RF_P 0x20000000 /* Location relative */
#define _RF_G 0x10000000 /* GOT offset */
#define _RF_B 0x08000000 /* Load address relative */
#define _RF_SZ(s) (((s) & 0xff) << 8) /* memory target size */
#define _RF_RS(s) ( (s) & 0xff) /* right shift */
static int reloc_target_flags[] = {
0, /* NONE */
_RF_S|_RF_A| _RF_SZ(8) | _RF_RS(0), /* RELOC_8 */
_RF_S|_RF_A| _RF_SZ(16) | _RF_RS(0), /* RELOC_16 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELOC_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(8) | _RF_RS(0), /* DISP_8 */
_RF_S|_RF_A|_RF_P| _RF_SZ(16) | _RF_RS(0), /* DISP_16 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* DISP_32 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_30 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WDISP_22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(10), /* HI22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 22 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* 13 */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* LO10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT10 */
_RF_G| _RF_SZ(32) | _RF_RS(0), /* GOT13 */
_RF_G| _RF_SZ(32) | _RF_RS(10), /* GOT22 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(0), /* PC10 */
_RF_S|_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(10), /* PC22 */
_RF_A|_RF_P| _RF_SZ(32) | _RF_RS(2), /* WPLT30 */
_RF_SZ(32) | _RF_RS(0), /* COPY */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* GLOB_DAT */
_RF_SZ(32) | _RF_RS(0), /* JMP_SLOT */
_RF_A| _RF_SZ(32) | _RF_RS(0), /* RELATIVE */
_RF_S|_RF_A| _RF_SZ(32) | _RF_RS(0), /* UA_32 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PLT32 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HIPLT22 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LOPLT10 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PCPLT22 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* PCPLT32 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 10 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 11 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 64 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* OLO10 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HH22 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* HM10 */
_RF_S|_RF_A|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* LM22 */
_RF_S|_RF_A|_RF_P|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* WDISP16 */
_RF_S|_RF_A|_RF_P|/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* WDISP19 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* GLOB_JMP */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 7 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 5 */
/*unknown*/ _RF_SZ(32) | _RF_RS(0), /* 6 */
};
#define RELOC_RESOLVE_SYMBOL(t) ((reloc_target_flags[t] & _RF_S) != 0)
#define RELOC_PC_RELATIVE(t) ((reloc_target_flags[t] & _RF_P) != 0)
#define RELOC_TARGET_SIZE(t) ((reloc_target_flags[t] >> 8) & 0xff)
#define RELOC_VALUE_RIGHTSHIFT(t) (reloc_target_flags[t] & 0xff)
static int reloc_target_bitmask[] = {
#define _BM(x) (~(-(1ULL << (x))))
0, /* NONE */
_BM(8), _BM(16), _BM(32), /* RELOC_8, _16, _32 */
_BM(8), _BM(16), _BM(32), /* DISP8, DISP16, DISP32 */
_BM(30), _BM(22), /* WDISP30, WDISP22 */
_BM(22), _BM(22), /* HI22, _22 */
_BM(13), _BM(10), /* RELOC_13, _LO10 */
_BM(10), _BM(13), _BM(22), /* GOT10, GOT13, GOT22 */
_BM(10), _BM(22), /* _PC10, _PC22 */
_BM(30), 0, /* _WPLT30, _COPY */
-1, -1, _BM(22), /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
_BM(32), _BM(32), /* _UA32, PLT32 */
_BM(22), _BM(10), /* _HIPLT22, LOPLT10 */
_BM(32), _BM(22), _BM(10), /* _PCPLT32, _PCPLT22, _PCPLT10 */
_BM(10), _BM(11), -1, /* _10, _11, _64 */
_BM(10), _BM(22), /* _OLO10, _HH22 */
_BM(10), _BM(22), /* _HM10, _LM22 */
_BM(16), _BM(19), /* _WDISP16, _WDISP19 */
-1, /* GLOB_JMP */
_BM(7), _BM(5), _BM(6) /* _7, _5, _6 */
#undef _BM
};
#define RELOC_VALUE_BITMASK(t) (reloc_target_bitmask[t])
static int
_rtld_relocate_nonplt_object(
const Obj_Entry *obj,
const Elf_RelA *rela)
{
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
Elf_Word type, value, mask;
type = ELF_R_TYPE(rela->r_info);
if (type == R_TYPE(NONE))
return (0);
/*
* We use the fact that relocation types are an `enum'
* Note: R_SPARC_6 is currently numerically largest.
*/
if (type > R_TYPE(6))
return (-1);
value = rela->r_addend;
if (RELOC_RESOLVE_SYMBOL(type)) {
const Elf_Sym *def;
const Obj_Entry *defobj;
/* Find the symbol */
def = _rtld_find_symdef(_rtld_objlist, rela->r_info,
NULL, obj, &defobj, false);
if (def == NULL)
return (-1);
/* Add in the symbol's absolute address */
value += (Elf_Word)(defobj->relocbase + def->st_value);
}
if (RELOC_PC_RELATIVE(type)) {
value -= (Elf_Word)where;
}
mask = RELOC_VALUE_BITMASK(type);
value >>= RELOC_VALUE_RIGHTSHIFT(type);
value &= mask;
/* We ignore alignment restrictions here */
*where &= ~mask;
*where |= value;
return (0);
}
static int
__rtld_relocate_plt_object(
const Obj_Entry *obj,
const Elf_RelA *rela,
bool bind_now,
caddr_t *addrp)
{
const Elf_Sym *def;
const Obj_Entry *defobj;
Elf_Addr *where = (Elf_Addr *) (obj->relocbase + rela->r_offset);
Elf_Addr value;
if (bind_now == 0 && obj->pltgot != NULL)
return (0);
/* Fully resolve procedure addresses now */
assert(ELF_R_TYPE(rela->r_info) == R_TYPE(JMP_SLOT));
def = _rtld_find_symdef(_rtld_objlist, rela->r_info,
NULL, obj, &defobj, true);
if (def == NULL)
return (-1);
value = (Elf_Addr) (defobj->relocbase + def->st_value);
#ifdef RTLD_DEBUG_RELOC
dbg("bind now %d/fixup in %s --> old=%p new=%p",
(int)bind_now,
defobj->strtab + def->st_name,
(void *)*where, (void *)value);
#endif
/*
* At the PLT entry pointed at by `where', we now construct
* a direct transfer to the now fully resolved function
* address. The resulting code in the jump slot is:
*
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
* nop ! delay slot
*/
#define SETHI 0x03000000
#define JMP 0x81c06000
#define NOP 0x01000000
where[0] = SETHI | ((value >> 10) & 0x003fffff);
where[1] = JMP | (value & 0x000003ff);
where[2] = NOP;
if (addrp != NULL)
*addrp = (caddr_t)value;
return (0);
}
#define _rtld_relocate_plt_object(obj, rela, bind_now) \
__rtld_relocate_plt_object(obj, rela, bind_now, NULL)
caddr_t
_rtld_bind(
const Obj_Entry *obj,
Elf_Word reloff)
{
const Elf_RelA *rela;
Elf_RelA ourrela;
caddr_t addr;
if (obj->pltrel != NULL) {
const Elf_Rel *rel;
rel = (const Elf_Rel *) ((caddr_t) obj->pltrel + reloff);
ourrela.r_info = rel->r_info;
ourrela.r_offset = rel->r_offset;
rela = &ourrela;
} else {
rela = (const Elf_RelA *) ((caddr_t) obj->pltrela + reloff);
}
if (__rtld_relocate_plt_object(obj, rela, true, &addr) < 0)
_rtld_die();
return (addr);
return *(caddr_t *)(obj->relocbase + rela->r_offset);
}
#else /* __sparc__ */
static int
_rtld_relocate_nonplt_object(
const Obj_Entry *obj,
@ -391,7 +625,9 @@ _rtld_relocate_nonplt_object(
}
return 0;
}
static int
_rtld_relocate_plt_object(
const Obj_Entry *obj,
@ -444,7 +680,7 @@ _rtld_relocate_plt_object(
*where = new_value;
return 0;
}
caddr_t
_rtld_bind(
const Obj_Entry *obj,
@ -461,12 +697,13 @@ _rtld_bind(
rela = (const Elf_RelA *) ((caddr_t) obj->pltrela + reloff);
}
if (_rtld_relocate_plt_object(obj, rela, true) < 0)
if (__rtld_relocate_plt_object(obj, rela, true) < 0)
_rtld_die();
return *(caddr_t *)(obj->relocbase + rela->r_offset);
}
#endif /* __sparc__ */
/*
* Relocate newly-loaded shared objects. The argument is a pointer to
* the Obj_Entry for the first such object. All objects from the first
@ -601,6 +838,19 @@ _rtld_relocate_objects(
#endif
#if defined(__powerpc__)
_rtld_setup_powerpc_plt(obj);
#endif
#if defined(__sparc__)
/*
* PLTGOT is the PLT on the sparc.
* The first entry holds the call the dynamic linker.
* We construct a `call' instruction that transfers
* to `_rtld_bind_start()'.
* The second entry holds the object identification.
* Note: each PLT entry is three words long.
*/
obj->pltgot[1] = 0x40000000 |
((Elf_Addr)&_rtld_bind_start - (Elf_Addr)&obj->pltgot[1]);
obj->pltgot[3] = (Elf_Addr) obj;
#endif
}
}