A linker supporting shared libraries (sparc dependent code).

This commit is contained in:
pk 1993-10-16 21:54:33 +00:00
parent 3d68d0acae
commit 0aebf1d941
12 changed files with 1959 additions and 0 deletions

View File

@ -0,0 +1,35 @@
/*
* Simple SPARC relocations for the benefit of self-relocation of ld.so
* avoiding the use of global variables (ie. reloc_bitshift[] et. al.).
* Only types supported are RELOC_32 and RELOC_RELATIVE.
*
* This *must* be a static function, so it is not called through a jmpslot.
*/
static void
md_relocate_simple(r, relocation, addr)
struct relocation_info *r;
long relocation;
char *addr;
{
register unsigned long mask;
register unsigned long shift;
switch (r->r_type) {
case RELOC_32:
mask = 0xffffffff;
shift = 0;
break;
case RELOC_RELATIVE:
mask = 0x003fffff;
shift = 10;
break;
}
relocation += (*(long *)addr & mask) << shift;
relocation >>= shift;
relocation &= mask;
*(long *) (addr) &= ~mask;
*(long *) (addr) |= relocation;
}

View File

@ -0,0 +1,279 @@
/*
* $Id: md.c,v 1.1 1993/10/16 21:54:34 pk Exp $
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
#include <string.h>
#include "ld.h"
/*
* Relocation masks and sizes for the Sparc architecture.
*
* Note that these are very dependent on the order of the enums in
* enum reloc_type (in a.out.h); if they change the following must be
* changed.
* Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
* This should work provided that relocations values have zeroes in their
* least significant 10 bits. As RELOC_RELATIVE is used only to relocate
* with load address values - which are page aligned - this condition is
* fulfilled as long as the system's page size is > 1024 (and a power of 2).
*/
static int reloc_target_rightshift[] = {
0, 0, 0, /* RELOC_8, _16, _32 */
0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
10, 0, /* HI22, _22 */
0, 0, /* RELOC_13, _LO10 */
0, 0, /* _SFA_BASE, _SFA_OFF13 */
0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
0, 10, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_size[] = {
0, 1, 2, /* RELOC_8, _16, _32 */
0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
2, 2, /* HI22, _22 */
2, 2, /* RELOC_13, _LO10 */
2, 2, /* _SFA_BASE, _SFA_OFF13 */
2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
2, 2, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_bitsize[] = {
8, 16, 32, /* RELOC_8, _16, _32 */
8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
22, 22, /* HI22, _22 */
13, 10, /* RELOC_13, _LO10 */
32, 32, /* _SFA_BASE, _SFA_OFF13 */
10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
10, 22, /* _PC10, _PC22 */
30, 0, /* _JMP_TBL, _SEGOFF16 */
32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
/*
* Get relocation addend corresponding to relocation record RP
* ADDR unused by SPARC impl.
*/
long
md_get_addend(r, addr)
struct relocation_info *r;
unsigned char *addr;
{
return r->r_addend;
}
void
md_relocate(r, relocation, addr, relocatable_output)
struct relocation_info *r;
long relocation;
unsigned char *addr;
int relocatable_output;
{
register unsigned long mask;
if (relocatable_output) {
/*
* Non-PC relative relocations which are absolute or
* which have become non-external now have fixed
* relocations. Set the ADD_EXTRA of this relocation
* to be the relocation we have now determined.
*/
if (!RELOC_PCREL_P(r)) {
if ((int) r->r_type <= RELOC_32
|| RELOC_EXTERN_P(r) == 0)
RELOC_ADD_EXTRA(r) = relocation;
} else if (RELOC_EXTERN_P(r))
/*
* External PC-relative relocations continue
* to move around; update their relocations
* by the amount they have moved so far.
*/
RELOC_ADD_EXTRA(r) -= pc_relocation;
return;
}
relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
/* Unshifted mask for relocation */
mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
mask |= mask - 1;
relocation &= mask;
/* Shift everything up to where it's going to be used */
relocation <<= RELOC_TARGET_BITPOS(r);
mask <<= RELOC_TARGET_BITPOS(r);
switch (RELOC_TARGET_SIZE(r)) {
case 0:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_char *) (addr));
*(u_char *) (addr) &= ~mask;
*(u_char *) (addr) |= relocation;
break;
case 1:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_short *) (addr));
*(u_short *) (addr) &= ~mask;
*(u_short *) (addr) |= relocation;
break;
case 2:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_long *) (addr));
*(u_long *) (addr) &= ~mask;
*(u_long *) (addr) |= relocation;
break;
default:
fatal( "Unimplemented relocation field length in");
}
}
/*
* Initialize (output) exec header such that useful values are
* obtained from subsequent N_*() macro evaluations.
*/
void
md_init_header(hp, magic, flags)
struct exec *hp;
int magic, flags;
{
hp->a_magic = magic;
hp->a_machtype = M_SPARC;
hp->a_toolversion = 1;
hp->a_dynamic = ((flags) & EX_DYNAMIC);
/* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
if (entry_symbol)
hp->a_entry = N_PAGSIZ(*hp);
}
/*
* Machine dependent part of claim_rrs_reloc().
* On the Sparc the relocation offsets are stored in the r_addend member.
*/
int
md_make_reloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
r->r_type = rp->r_type;
r->r_addend = rp->r_addend;
#if 1
/*
* This wouldn't be strictly necessary - we could record the
* location value "in situ" in stead of in the r_addend field -
* but we are being Sun compatible here. Besides, Sun's ld.so
* has a bug that prevents it from handling this alternate method
*/
if (RELOC_PCREL_P(rp))
r->r_addend -= pc_relocation;
#endif
return 1;
}
/*
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
* to the binder slot (which is at offset 0 of the PLT).
*/
void
md_make_jmpslot(sp, offset, index)
jmpslot_t *sp;
long offset;
long index;
{
u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
sp->opcode1 = SAVE;
/* The following is a RELOC_WDISP30 relocation */
sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
sp->reloc_index = NOP | index;
}
/*
* Set up a "direct" transfer (ie. not through the run-time binder) from
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
* and by `ld.so' after resolving the symbol.
* On the i386, we use the JMP instruction which is PC relative, so no
* further RRS relocations will be necessary for such a jmpslot.
*
* OFFSET unused on Sparc.
*/
void
md_fix_jmpslot(sp, offset, addr)
jmpslot_t *sp;
long offset;
u_long addr;
{
/*
* Here comes a RELOC_{LO10,HI22} relocation pair
* The resulting code is:
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
* nop ! delay slot
*/
sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
sp->opcode2 = JMP | (addr & 0x000003ff);
sp->reloc_index = NOP;
}
/*
* Update the relocation record for a jmpslot.
*/
void
md_make_jmpreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_RELATIVE;
else
r->r_type = RELOC_JMP_SLOT;
r->r_addend = rp->r_addend;
}
/*
* Set relocation type for a GOT RRS relocation.
*/
void
md_make_gotreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
/*
* GOT value resolved (symbolic or entry point): R_32
* GOT not resolved: GLOB_DAT
*
* NOTE: I don't think it makes a difference.
*/
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_32;
else
r->r_type = RELOC_GLOB_DAT;
r->r_addend = 0;
}
/*
* Set relocation type for a RRS copy operation.
*/
void
md_make_cpyreloc(rp, r)
struct relocation_info *rp, *r;
{
r->r_type = RELOC_COPY_DAT;
r->r_addend = 0;
}

View File

@ -0,0 +1,238 @@
/*
* $Id: md.h,v 1.1 1993/10/16 21:54:35 pk Exp $ - SPARC machine dependent definitions
*/
#ifdef sun
#endif
#define MAX_ALIGNMENT (sizeof (double))
#ifndef EX_DYNAMIC
#define EX_DYNAMIC 1
#endif
#define N_SET_FLAG(ex, f) { \
(ex).a_dynamic = ((f) & EX_DYNAMIC); \
}
#define N_IS_DYNAMIC(ex) ((ex).a_dynamic)
/* Sparc (Sun 4) macros */
#undef relocation_info
#define relocation_info reloc_info_sparc
#define r_symbolnum r_index
#define RELOC_ADDRESS(r) ((r)->r_address)
#define RELOC_EXTERN_P(r) ((r)->r_extern)
#define RELOC_TYPE(r) ((r)->r_index)
#define RELOC_SYMBOL(r) ((r)->r_index)
#define RELOC_MEMORY_SUB_P(r) 0
#ifdef RTLD
#define RELOC_MEMORY_ADD_P(r) 1
#else
#define RELOC_MEMORY_ADD_P(r) 0
#endif
#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
#define RELOC_PCREL_P(r) \
(((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) \
|| ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) \
|| (r)->r_type == RELOC_JMP_TBL)
#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
#define RELOC_TARGET_BITPOS(r) 0
#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
#define RELOC_JMPTAB_P(r) ((r)->r_type == RELOC_JMP_TBL)
#define RELOC_BASEREL_P(r) \
((r)->r_type >= RELOC_BASE10 && (r)->r_type <= RELOC_BASE22)
#define RELOC_RELATIVE_P(r) ((r)->r_type == RELOC_RELATIVE)
#define RELOC_COPY_DAT (RELOC_RELATIVE+1) /*XXX*/
#define RELOC_COPY_P(r) ((r)->r_type == RELOC_COPY_DAT)
#define RELOC_LAZY_P(r) ((r)->r_type == RELOC_JMP_SLOT)
#define RELOC_STATICS_THROUGH_GOT_P(r) (1)
#define JMPSLOT_NEEDS_RELOC (1)
#define CHECK_GOT_RELOC(r) \
((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
#define md_got_reloc(r) (-(r)->r_address)
#ifdef SUN_COMPAT
/*
* Sun plays games with `r_addend'
*/
#define md_get_rt_segment_addend(r,a) (0)
#endif
/*
int reloc_target_rightshift[];
int reloc_target_size[];
int reloc_target_bitsize[];
*/
/* Width of a Global Offset Table entry */
#define GOT_ENTRY_SIZE 4
typedef long got_t;
typedef struct jmpslot {
u_long opcode1;
u_long opcode2;
u_long reloc_index;
#define JMPSLOT_RELOC_MASK (0x003fffff) /* 22 bits */
} jmpslot_t;
#define SAVE 0x9de3bfa0 /* Build stack frame (opcode1) */
#define SETHI 0x03000000 /* %hi(addr) -> %g1 (opcode1) */
#define CALL 0x40000000 /* Call instruction (opcode2) */
#define JMP 0x81c06000 /* Jump %g1 instruction (opcode2) */
#define NOP 0x01000000 /* Delay slot NOP for (reloc_index) */
/*
* Byte swap defs for cross linking
*/
#if !defined(NEED_SWAP)
#define md_swapin_exec_hdr(h)
#define md_swapout_exec_hdr(h)
#define md_swapin_symbols(s,n)
#define md_swapout_symbols(s,n)
#define md_swapin_zsymbols(s,n)
#define md_swapout_zsymbols(s,n)
#define md_swapin_reloc(r,n)
#define md_swapout_reloc(r,n)
#define md_swapin_link_dynamic(l)
#define md_swapout_link_dynamic(l)
#define md_swapin_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l)
#define md_swapin_ld_debug(d)
#define md_swapout_ld_debug(d)
#define md_swapin_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n)
#define md_swapin_link_object(l,n)
#define md_swapout_link_object(l,n)
#define md_swapout_jmpslot(j,n)
#define md_swapout_got(g,n)
#define md_swapin_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n)
#endif /* NEED_SWAP */
#ifdef CROSS_LINKER
#ifdef NEED_SWAP
/* Define IO byte swapping routines */
void md_swapin_exec_hdr __P((struct exec *));
void md_swapout_exec_hdr __P((struct exec *));
void md_swapin_reloc __P((struct relocation_info *, int));
void md_swapout_reloc __P((struct relocation_info *, int));
void md_swapout_jmpslot __P((jmpslot_t *, int));
#define md_swapin_symbols(s,n) swap_symbols(s,n)
#define md_swapout_symbols(s,n) swap_symbols(s,n)
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapin_ld_debug(d) swap_ld_debug(d)
#define md_swapout_ld_debug(d) swap_ld_debug(d)
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
( ((unsigned char *)(p))[0] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
( ((unsigned char *)(p))[2] << 16) | \
( ((unsigned char *)(p))[1] << 8 ) | \
( ((unsigned char *)(p))[0] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#else /* We need not swap, but must pay attention to alignment: */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
( ((unsigned char *)(p))[1] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
( ((unsigned char *)(p))[1] << 16) | \
( ((unsigned char *)(p))[2] << 8 ) | \
( ((unsigned char *)(p))[3] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[3] = \
((((unsigned long)(v)) ) & 0xff); }
#endif /* NEED_SWAP */
#else /* Not a cross linker: use native */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(where) (*(char *)(where))
#define get_short(where) (*(short *)(where))
#define get_long(where) (*(long *)(where))
#define put_byte(where,what) (*(char *)(where) = (what))
#define put_short(where,what) (*(short *)(where) = (what))
#define put_long(where,what) (*(long *)(where) = (what))
#endif /* CROSS_LINKER */

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 1993 Paul Kranenburg
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: mdprologue.S,v 1.1 1993/10/16 21:54:36 pk Exp $
*/
/*
* SPARC run-time link editor entry points.
*/
#define CRT_VERSION_SUN 1
.seg "text" ! [internal]
.proc 16
.global _rtld_entry
_rtld_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
L.1B:
call L.2B
sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
L.2B:
!#PROLOGUE# 1
or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
add %l7,%o7,%l7
cmp %i0, CRT_VERSION_SUN ! is crtp passed in Sun style,
bne 1f ! ie. relative to stack frame ?
nop
add %i1, %fp, %i1 ! if so, adjust to absolute address
1:
ld [%i1], %o3 ! load base address (crtp->crt_ba)
ld [%l7], %o2 ! get rtld's __DYNAMIC address
! from 1st GOT entry
add %o2, %o3, %o2 ! relocate and make it 3rd arg.
ld [%l7 + _rtld], %g1 ! get address of rtld()
add %g1, %o3, %g1 ! relocate
mov %i1, %o1 ! set up args, #2: crtp
call %g1 ! rtld(version, crtp, dp)
mov %i0, %o0 ! arg #1: version
ret
restore
.seg "data" ! [internal]
.seg "text"
.global _binder_entry
_binder_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
!L.1C:
! call L.2C
! sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!L.2C:
! or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!#PROLOGUE# 1
sub %i7, 4, %o0 ! get to jmpslot through pc
ld [%i7+4], %o1 ! get relocation index
sethi %hi(0x3fffff), %o2 ! -> reloc_index & 0x003fffff
or %o2, %lo(0x3fffff), %o2 ! [internal]
call _binder ! and call binder(jsp, reloc_index)
and %o1, %o2, %o1
mov %o0, %g1 ! return value == function address
restore ! get rid of our context
jmp %g1 ! and go.
restore ! and the jmpslot's
nop
.seg "data" ! [internal]

View File

@ -0,0 +1,35 @@
/*
* Simple SPARC relocations for the benefit of self-relocation of ld.so
* avoiding the use of global variables (ie. reloc_bitshift[] et. al.).
* Only types supported are RELOC_32 and RELOC_RELATIVE.
*
* This *must* be a static function, so it is not called through a jmpslot.
*/
static void
md_relocate_simple(r, relocation, addr)
struct relocation_info *r;
long relocation;
char *addr;
{
register unsigned long mask;
register unsigned long shift;
switch (r->r_type) {
case RELOC_32:
mask = 0xffffffff;
shift = 0;
break;
case RELOC_RELATIVE:
mask = 0x003fffff;
shift = 10;
break;
}
relocation += (*(long *)addr & mask) << shift;
relocation >>= shift;
relocation &= mask;
*(long *) (addr) &= ~mask;
*(long *) (addr) |= relocation;
}

279
gnu/usr.bin/ld/sparc/md.c Normal file
View File

@ -0,0 +1,279 @@
/*
* $Id: md.c,v 1.1 1993/10/16 21:54:34 pk Exp $
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
#include <string.h>
#include "ld.h"
/*
* Relocation masks and sizes for the Sparc architecture.
*
* Note that these are very dependent on the order of the enums in
* enum reloc_type (in a.out.h); if they change the following must be
* changed.
* Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
* This should work provided that relocations values have zeroes in their
* least significant 10 bits. As RELOC_RELATIVE is used only to relocate
* with load address values - which are page aligned - this condition is
* fulfilled as long as the system's page size is > 1024 (and a power of 2).
*/
static int reloc_target_rightshift[] = {
0, 0, 0, /* RELOC_8, _16, _32 */
0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
10, 0, /* HI22, _22 */
0, 0, /* RELOC_13, _LO10 */
0, 0, /* _SFA_BASE, _SFA_OFF13 */
0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
0, 10, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_size[] = {
0, 1, 2, /* RELOC_8, _16, _32 */
0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
2, 2, /* HI22, _22 */
2, 2, /* RELOC_13, _LO10 */
2, 2, /* _SFA_BASE, _SFA_OFF13 */
2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
2, 2, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_bitsize[] = {
8, 16, 32, /* RELOC_8, _16, _32 */
8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
22, 22, /* HI22, _22 */
13, 10, /* RELOC_13, _LO10 */
32, 32, /* _SFA_BASE, _SFA_OFF13 */
10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
10, 22, /* _PC10, _PC22 */
30, 0, /* _JMP_TBL, _SEGOFF16 */
32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
/*
* Get relocation addend corresponding to relocation record RP
* ADDR unused by SPARC impl.
*/
long
md_get_addend(r, addr)
struct relocation_info *r;
unsigned char *addr;
{
return r->r_addend;
}
void
md_relocate(r, relocation, addr, relocatable_output)
struct relocation_info *r;
long relocation;
unsigned char *addr;
int relocatable_output;
{
register unsigned long mask;
if (relocatable_output) {
/*
* Non-PC relative relocations which are absolute or
* which have become non-external now have fixed
* relocations. Set the ADD_EXTRA of this relocation
* to be the relocation we have now determined.
*/
if (!RELOC_PCREL_P(r)) {
if ((int) r->r_type <= RELOC_32
|| RELOC_EXTERN_P(r) == 0)
RELOC_ADD_EXTRA(r) = relocation;
} else if (RELOC_EXTERN_P(r))
/*
* External PC-relative relocations continue
* to move around; update their relocations
* by the amount they have moved so far.
*/
RELOC_ADD_EXTRA(r) -= pc_relocation;
return;
}
relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
/* Unshifted mask for relocation */
mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
mask |= mask - 1;
relocation &= mask;
/* Shift everything up to where it's going to be used */
relocation <<= RELOC_TARGET_BITPOS(r);
mask <<= RELOC_TARGET_BITPOS(r);
switch (RELOC_TARGET_SIZE(r)) {
case 0:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_char *) (addr));
*(u_char *) (addr) &= ~mask;
*(u_char *) (addr) |= relocation;
break;
case 1:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_short *) (addr));
*(u_short *) (addr) &= ~mask;
*(u_short *) (addr) |= relocation;
break;
case 2:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_long *) (addr));
*(u_long *) (addr) &= ~mask;
*(u_long *) (addr) |= relocation;
break;
default:
fatal( "Unimplemented relocation field length in");
}
}
/*
* Initialize (output) exec header such that useful values are
* obtained from subsequent N_*() macro evaluations.
*/
void
md_init_header(hp, magic, flags)
struct exec *hp;
int magic, flags;
{
hp->a_magic = magic;
hp->a_machtype = M_SPARC;
hp->a_toolversion = 1;
hp->a_dynamic = ((flags) & EX_DYNAMIC);
/* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
if (entry_symbol)
hp->a_entry = N_PAGSIZ(*hp);
}
/*
* Machine dependent part of claim_rrs_reloc().
* On the Sparc the relocation offsets are stored in the r_addend member.
*/
int
md_make_reloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
r->r_type = rp->r_type;
r->r_addend = rp->r_addend;
#if 1
/*
* This wouldn't be strictly necessary - we could record the
* location value "in situ" in stead of in the r_addend field -
* but we are being Sun compatible here. Besides, Sun's ld.so
* has a bug that prevents it from handling this alternate method
*/
if (RELOC_PCREL_P(rp))
r->r_addend -= pc_relocation;
#endif
return 1;
}
/*
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
* to the binder slot (which is at offset 0 of the PLT).
*/
void
md_make_jmpslot(sp, offset, index)
jmpslot_t *sp;
long offset;
long index;
{
u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
sp->opcode1 = SAVE;
/* The following is a RELOC_WDISP30 relocation */
sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
sp->reloc_index = NOP | index;
}
/*
* Set up a "direct" transfer (ie. not through the run-time binder) from
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
* and by `ld.so' after resolving the symbol.
* On the i386, we use the JMP instruction which is PC relative, so no
* further RRS relocations will be necessary for such a jmpslot.
*
* OFFSET unused on Sparc.
*/
void
md_fix_jmpslot(sp, offset, addr)
jmpslot_t *sp;
long offset;
u_long addr;
{
/*
* Here comes a RELOC_{LO10,HI22} relocation pair
* The resulting code is:
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
* nop ! delay slot
*/
sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
sp->opcode2 = JMP | (addr & 0x000003ff);
sp->reloc_index = NOP;
}
/*
* Update the relocation record for a jmpslot.
*/
void
md_make_jmpreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_RELATIVE;
else
r->r_type = RELOC_JMP_SLOT;
r->r_addend = rp->r_addend;
}
/*
* Set relocation type for a GOT RRS relocation.
*/
void
md_make_gotreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
/*
* GOT value resolved (symbolic or entry point): R_32
* GOT not resolved: GLOB_DAT
*
* NOTE: I don't think it makes a difference.
*/
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_32;
else
r->r_type = RELOC_GLOB_DAT;
r->r_addend = 0;
}
/*
* Set relocation type for a RRS copy operation.
*/
void
md_make_cpyreloc(rp, r)
struct relocation_info *rp, *r;
{
r->r_type = RELOC_COPY_DAT;
r->r_addend = 0;
}

238
gnu/usr.bin/ld/sparc/md.h Normal file
View File

@ -0,0 +1,238 @@
/*
* $Id: md.h,v 1.1 1993/10/16 21:54:35 pk Exp $ - SPARC machine dependent definitions
*/
#ifdef sun
#endif
#define MAX_ALIGNMENT (sizeof (double))
#ifndef EX_DYNAMIC
#define EX_DYNAMIC 1
#endif
#define N_SET_FLAG(ex, f) { \
(ex).a_dynamic = ((f) & EX_DYNAMIC); \
}
#define N_IS_DYNAMIC(ex) ((ex).a_dynamic)
/* Sparc (Sun 4) macros */
#undef relocation_info
#define relocation_info reloc_info_sparc
#define r_symbolnum r_index
#define RELOC_ADDRESS(r) ((r)->r_address)
#define RELOC_EXTERN_P(r) ((r)->r_extern)
#define RELOC_TYPE(r) ((r)->r_index)
#define RELOC_SYMBOL(r) ((r)->r_index)
#define RELOC_MEMORY_SUB_P(r) 0
#ifdef RTLD
#define RELOC_MEMORY_ADD_P(r) 1
#else
#define RELOC_MEMORY_ADD_P(r) 0
#endif
#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
#define RELOC_PCREL_P(r) \
(((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) \
|| ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) \
|| (r)->r_type == RELOC_JMP_TBL)
#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
#define RELOC_TARGET_BITPOS(r) 0
#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
#define RELOC_JMPTAB_P(r) ((r)->r_type == RELOC_JMP_TBL)
#define RELOC_BASEREL_P(r) \
((r)->r_type >= RELOC_BASE10 && (r)->r_type <= RELOC_BASE22)
#define RELOC_RELATIVE_P(r) ((r)->r_type == RELOC_RELATIVE)
#define RELOC_COPY_DAT (RELOC_RELATIVE+1) /*XXX*/
#define RELOC_COPY_P(r) ((r)->r_type == RELOC_COPY_DAT)
#define RELOC_LAZY_P(r) ((r)->r_type == RELOC_JMP_SLOT)
#define RELOC_STATICS_THROUGH_GOT_P(r) (1)
#define JMPSLOT_NEEDS_RELOC (1)
#define CHECK_GOT_RELOC(r) \
((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
#define md_got_reloc(r) (-(r)->r_address)
#ifdef SUN_COMPAT
/*
* Sun plays games with `r_addend'
*/
#define md_get_rt_segment_addend(r,a) (0)
#endif
/*
int reloc_target_rightshift[];
int reloc_target_size[];
int reloc_target_bitsize[];
*/
/* Width of a Global Offset Table entry */
#define GOT_ENTRY_SIZE 4
typedef long got_t;
typedef struct jmpslot {
u_long opcode1;
u_long opcode2;
u_long reloc_index;
#define JMPSLOT_RELOC_MASK (0x003fffff) /* 22 bits */
} jmpslot_t;
#define SAVE 0x9de3bfa0 /* Build stack frame (opcode1) */
#define SETHI 0x03000000 /* %hi(addr) -> %g1 (opcode1) */
#define CALL 0x40000000 /* Call instruction (opcode2) */
#define JMP 0x81c06000 /* Jump %g1 instruction (opcode2) */
#define NOP 0x01000000 /* Delay slot NOP for (reloc_index) */
/*
* Byte swap defs for cross linking
*/
#if !defined(NEED_SWAP)
#define md_swapin_exec_hdr(h)
#define md_swapout_exec_hdr(h)
#define md_swapin_symbols(s,n)
#define md_swapout_symbols(s,n)
#define md_swapin_zsymbols(s,n)
#define md_swapout_zsymbols(s,n)
#define md_swapin_reloc(r,n)
#define md_swapout_reloc(r,n)
#define md_swapin_link_dynamic(l)
#define md_swapout_link_dynamic(l)
#define md_swapin_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l)
#define md_swapin_ld_debug(d)
#define md_swapout_ld_debug(d)
#define md_swapin_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n)
#define md_swapin_link_object(l,n)
#define md_swapout_link_object(l,n)
#define md_swapout_jmpslot(j,n)
#define md_swapout_got(g,n)
#define md_swapin_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n)
#endif /* NEED_SWAP */
#ifdef CROSS_LINKER
#ifdef NEED_SWAP
/* Define IO byte swapping routines */
void md_swapin_exec_hdr __P((struct exec *));
void md_swapout_exec_hdr __P((struct exec *));
void md_swapin_reloc __P((struct relocation_info *, int));
void md_swapout_reloc __P((struct relocation_info *, int));
void md_swapout_jmpslot __P((jmpslot_t *, int));
#define md_swapin_symbols(s,n) swap_symbols(s,n)
#define md_swapout_symbols(s,n) swap_symbols(s,n)
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapin_ld_debug(d) swap_ld_debug(d)
#define md_swapout_ld_debug(d) swap_ld_debug(d)
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
( ((unsigned char *)(p))[0] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
( ((unsigned char *)(p))[2] << 16) | \
( ((unsigned char *)(p))[1] << 8 ) | \
( ((unsigned char *)(p))[0] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#else /* We need not swap, but must pay attention to alignment: */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
( ((unsigned char *)(p))[1] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
( ((unsigned char *)(p))[1] << 16) | \
( ((unsigned char *)(p))[2] << 8 ) | \
( ((unsigned char *)(p))[3] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[3] = \
((((unsigned long)(v)) ) & 0xff); }
#endif /* NEED_SWAP */
#else /* Not a cross linker: use native */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(where) (*(char *)(where))
#define get_short(where) (*(short *)(where))
#define get_long(where) (*(long *)(where))
#define put_byte(where,what) (*(char *)(where) = (what))
#define put_short(where,what) (*(short *)(where) = (what))
#define put_long(where,what) (*(long *)(where) = (what))
#endif /* CROSS_LINKER */

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 1993 Paul Kranenburg
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: mdprologue.S,v 1.1 1993/10/16 21:54:36 pk Exp $
*/
/*
* SPARC run-time link editor entry points.
*/
#define CRT_VERSION_SUN 1
.seg "text" ! [internal]
.proc 16
.global _rtld_entry
_rtld_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
L.1B:
call L.2B
sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
L.2B:
!#PROLOGUE# 1
or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
add %l7,%o7,%l7
cmp %i0, CRT_VERSION_SUN ! is crtp passed in Sun style,
bne 1f ! ie. relative to stack frame ?
nop
add %i1, %fp, %i1 ! if so, adjust to absolute address
1:
ld [%i1], %o3 ! load base address (crtp->crt_ba)
ld [%l7], %o2 ! get rtld's __DYNAMIC address
! from 1st GOT entry
add %o2, %o3, %o2 ! relocate and make it 3rd arg.
ld [%l7 + _rtld], %g1 ! get address of rtld()
add %g1, %o3, %g1 ! relocate
mov %i1, %o1 ! set up args, #2: crtp
call %g1 ! rtld(version, crtp, dp)
mov %i0, %o0 ! arg #1: version
ret
restore
.seg "data" ! [internal]
.seg "text"
.global _binder_entry
_binder_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
!L.1C:
! call L.2C
! sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!L.2C:
! or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!#PROLOGUE# 1
sub %i7, 4, %o0 ! get to jmpslot through pc
ld [%i7+4], %o1 ! get relocation index
sethi %hi(0x3fffff), %o2 ! -> reloc_index & 0x003fffff
or %o2, %lo(0x3fffff), %o2 ! [internal]
call _binder ! and call binder(jsp, reloc_index)
and %o1, %o2, %o1
mov %o0, %g1 ! return value == function address
restore ! get rid of our context
jmp %g1 ! and go.
restore ! and the jmpslot's
nop
.seg "data" ! [internal]

View File

@ -0,0 +1,35 @@
/*
* Simple SPARC relocations for the benefit of self-relocation of ld.so
* avoiding the use of global variables (ie. reloc_bitshift[] et. al.).
* Only types supported are RELOC_32 and RELOC_RELATIVE.
*
* This *must* be a static function, so it is not called through a jmpslot.
*/
static void
md_relocate_simple(r, relocation, addr)
struct relocation_info *r;
long relocation;
char *addr;
{
register unsigned long mask;
register unsigned long shift;
switch (r->r_type) {
case RELOC_32:
mask = 0xffffffff;
shift = 0;
break;
case RELOC_RELATIVE:
mask = 0x003fffff;
shift = 10;
break;
}
relocation += (*(long *)addr & mask) << shift;
relocation >>= shift;
relocation &= mask;
*(long *) (addr) &= ~mask;
*(long *) (addr) |= relocation;
}

View File

@ -0,0 +1,279 @@
/*
* $Id: md.c,v 1.1 1993/10/16 21:54:34 pk Exp $
*/
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <a.out.h>
#include <stab.h>
#include <string.h>
#include "ld.h"
/*
* Relocation masks and sizes for the Sparc architecture.
*
* Note that these are very dependent on the order of the enums in
* enum reloc_type (in a.out.h); if they change the following must be
* changed.
* Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
* This should work provided that relocations values have zeroes in their
* least significant 10 bits. As RELOC_RELATIVE is used only to relocate
* with load address values - which are page aligned - this condition is
* fulfilled as long as the system's page size is > 1024 (and a power of 2).
*/
static int reloc_target_rightshift[] = {
0, 0, 0, /* RELOC_8, _16, _32 */
0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
10, 0, /* HI22, _22 */
0, 0, /* RELOC_13, _LO10 */
0, 0, /* _SFA_BASE, _SFA_OFF13 */
0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
0, 10, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_size[] = {
0, 1, 2, /* RELOC_8, _16, _32 */
0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
2, 2, /* HI22, _22 */
2, 2, /* RELOC_13, _LO10 */
2, 2, /* _SFA_BASE, _SFA_OFF13 */
2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
2, 2, /* _PC10, _PC22 */
2, 0, /* _JMP_TBL, _SEGOFF16 */
2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
static int reloc_target_bitsize[] = {
8, 16, 32, /* RELOC_8, _16, _32 */
8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
22, 22, /* HI22, _22 */
13, 10, /* RELOC_13, _LO10 */
32, 32, /* _SFA_BASE, _SFA_OFF13 */
10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
10, 22, /* _PC10, _PC22 */
30, 0, /* _JMP_TBL, _SEGOFF16 */
32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
};
/*
* Get relocation addend corresponding to relocation record RP
* ADDR unused by SPARC impl.
*/
long
md_get_addend(r, addr)
struct relocation_info *r;
unsigned char *addr;
{
return r->r_addend;
}
void
md_relocate(r, relocation, addr, relocatable_output)
struct relocation_info *r;
long relocation;
unsigned char *addr;
int relocatable_output;
{
register unsigned long mask;
if (relocatable_output) {
/*
* Non-PC relative relocations which are absolute or
* which have become non-external now have fixed
* relocations. Set the ADD_EXTRA of this relocation
* to be the relocation we have now determined.
*/
if (!RELOC_PCREL_P(r)) {
if ((int) r->r_type <= RELOC_32
|| RELOC_EXTERN_P(r) == 0)
RELOC_ADD_EXTRA(r) = relocation;
} else if (RELOC_EXTERN_P(r))
/*
* External PC-relative relocations continue
* to move around; update their relocations
* by the amount they have moved so far.
*/
RELOC_ADD_EXTRA(r) -= pc_relocation;
return;
}
relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
/* Unshifted mask for relocation */
mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
mask |= mask - 1;
relocation &= mask;
/* Shift everything up to where it's going to be used */
relocation <<= RELOC_TARGET_BITPOS(r);
mask <<= RELOC_TARGET_BITPOS(r);
switch (RELOC_TARGET_SIZE(r)) {
case 0:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_char *) (addr));
*(u_char *) (addr) &= ~mask;
*(u_char *) (addr) |= relocation;
break;
case 1:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_short *) (addr));
*(u_short *) (addr) &= ~mask;
*(u_short *) (addr) |= relocation;
break;
case 2:
if (RELOC_MEMORY_ADD_P(r))
relocation += (mask & *(u_long *) (addr));
*(u_long *) (addr) &= ~mask;
*(u_long *) (addr) |= relocation;
break;
default:
fatal( "Unimplemented relocation field length in");
}
}
/*
* Initialize (output) exec header such that useful values are
* obtained from subsequent N_*() macro evaluations.
*/
void
md_init_header(hp, magic, flags)
struct exec *hp;
int magic, flags;
{
hp->a_magic = magic;
hp->a_machtype = M_SPARC;
hp->a_toolversion = 1;
hp->a_dynamic = ((flags) & EX_DYNAMIC);
/* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
if (entry_symbol)
hp->a_entry = N_PAGSIZ(*hp);
}
/*
* Machine dependent part of claim_rrs_reloc().
* On the Sparc the relocation offsets are stored in the r_addend member.
*/
int
md_make_reloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
r->r_type = rp->r_type;
r->r_addend = rp->r_addend;
#if 1
/*
* This wouldn't be strictly necessary - we could record the
* location value "in situ" in stead of in the r_addend field -
* but we are being Sun compatible here. Besides, Sun's ld.so
* has a bug that prevents it from handling this alternate method
*/
if (RELOC_PCREL_P(rp))
r->r_addend -= pc_relocation;
#endif
return 1;
}
/*
* Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
* to the binder slot (which is at offset 0 of the PLT).
*/
void
md_make_jmpslot(sp, offset, index)
jmpslot_t *sp;
long offset;
long index;
{
u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
sp->opcode1 = SAVE;
/* The following is a RELOC_WDISP30 relocation */
sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
sp->reloc_index = NOP | index;
}
/*
* Set up a "direct" transfer (ie. not through the run-time binder) from
* jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
* and by `ld.so' after resolving the symbol.
* On the i386, we use the JMP instruction which is PC relative, so no
* further RRS relocations will be necessary for such a jmpslot.
*
* OFFSET unused on Sparc.
*/
void
md_fix_jmpslot(sp, offset, addr)
jmpslot_t *sp;
long offset;
u_long addr;
{
/*
* Here comes a RELOC_{LO10,HI22} relocation pair
* The resulting code is:
* sethi %hi(addr), %g1
* jmp %g1+%lo(addr)
* nop ! delay slot
*/
sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
sp->opcode2 = JMP | (addr & 0x000003ff);
sp->reloc_index = NOP;
}
/*
* Update the relocation record for a jmpslot.
*/
void
md_make_jmpreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_RELATIVE;
else
r->r_type = RELOC_JMP_SLOT;
r->r_addend = rp->r_addend;
}
/*
* Set relocation type for a GOT RRS relocation.
*/
void
md_make_gotreloc(rp, r, type)
struct relocation_info *rp, *r;
int type;
{
/*
* GOT value resolved (symbolic or entry point): R_32
* GOT not resolved: GLOB_DAT
*
* NOTE: I don't think it makes a difference.
*/
if (type & RELTYPE_RELATIVE)
r->r_type = RELOC_32;
else
r->r_type = RELOC_GLOB_DAT;
r->r_addend = 0;
}
/*
* Set relocation type for a RRS copy operation.
*/
void
md_make_cpyreloc(rp, r)
struct relocation_info *rp, *r;
{
r->r_type = RELOC_COPY_DAT;
r->r_addend = 0;
}

View File

@ -0,0 +1,238 @@
/*
* $Id: md.h,v 1.1 1993/10/16 21:54:35 pk Exp $ - SPARC machine dependent definitions
*/
#ifdef sun
#endif
#define MAX_ALIGNMENT (sizeof (double))
#ifndef EX_DYNAMIC
#define EX_DYNAMIC 1
#endif
#define N_SET_FLAG(ex, f) { \
(ex).a_dynamic = ((f) & EX_DYNAMIC); \
}
#define N_IS_DYNAMIC(ex) ((ex).a_dynamic)
/* Sparc (Sun 4) macros */
#undef relocation_info
#define relocation_info reloc_info_sparc
#define r_symbolnum r_index
#define RELOC_ADDRESS(r) ((r)->r_address)
#define RELOC_EXTERN_P(r) ((r)->r_extern)
#define RELOC_TYPE(r) ((r)->r_index)
#define RELOC_SYMBOL(r) ((r)->r_index)
#define RELOC_MEMORY_SUB_P(r) 0
#ifdef RTLD
#define RELOC_MEMORY_ADD_P(r) 1
#else
#define RELOC_MEMORY_ADD_P(r) 0
#endif
#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
#define RELOC_PCREL_P(r) \
(((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22) \
|| ((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22) \
|| (r)->r_type == RELOC_JMP_TBL)
#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
#define RELOC_TARGET_BITPOS(r) 0
#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
#define RELOC_JMPTAB_P(r) ((r)->r_type == RELOC_JMP_TBL)
#define RELOC_BASEREL_P(r) \
((r)->r_type >= RELOC_BASE10 && (r)->r_type <= RELOC_BASE22)
#define RELOC_RELATIVE_P(r) ((r)->r_type == RELOC_RELATIVE)
#define RELOC_COPY_DAT (RELOC_RELATIVE+1) /*XXX*/
#define RELOC_COPY_P(r) ((r)->r_type == RELOC_COPY_DAT)
#define RELOC_LAZY_P(r) ((r)->r_type == RELOC_JMP_SLOT)
#define RELOC_STATICS_THROUGH_GOT_P(r) (1)
#define JMPSLOT_NEEDS_RELOC (1)
#define CHECK_GOT_RELOC(r) \
((r)->r_type == RELOC_PC10 || (r)->r_type == RELOC_PC22)
#define md_got_reloc(r) (-(r)->r_address)
#ifdef SUN_COMPAT
/*
* Sun plays games with `r_addend'
*/
#define md_get_rt_segment_addend(r,a) (0)
#endif
/*
int reloc_target_rightshift[];
int reloc_target_size[];
int reloc_target_bitsize[];
*/
/* Width of a Global Offset Table entry */
#define GOT_ENTRY_SIZE 4
typedef long got_t;
typedef struct jmpslot {
u_long opcode1;
u_long opcode2;
u_long reloc_index;
#define JMPSLOT_RELOC_MASK (0x003fffff) /* 22 bits */
} jmpslot_t;
#define SAVE 0x9de3bfa0 /* Build stack frame (opcode1) */
#define SETHI 0x03000000 /* %hi(addr) -> %g1 (opcode1) */
#define CALL 0x40000000 /* Call instruction (opcode2) */
#define JMP 0x81c06000 /* Jump %g1 instruction (opcode2) */
#define NOP 0x01000000 /* Delay slot NOP for (reloc_index) */
/*
* Byte swap defs for cross linking
*/
#if !defined(NEED_SWAP)
#define md_swapin_exec_hdr(h)
#define md_swapout_exec_hdr(h)
#define md_swapin_symbols(s,n)
#define md_swapout_symbols(s,n)
#define md_swapin_zsymbols(s,n)
#define md_swapout_zsymbols(s,n)
#define md_swapin_reloc(r,n)
#define md_swapout_reloc(r,n)
#define md_swapin_link_dynamic(l)
#define md_swapout_link_dynamic(l)
#define md_swapin_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l)
#define md_swapin_ld_debug(d)
#define md_swapout_ld_debug(d)
#define md_swapin_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n)
#define md_swapin_link_object(l,n)
#define md_swapout_link_object(l,n)
#define md_swapout_jmpslot(j,n)
#define md_swapout_got(g,n)
#define md_swapin_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n)
#endif /* NEED_SWAP */
#ifdef CROSS_LINKER
#ifdef NEED_SWAP
/* Define IO byte swapping routines */
void md_swapin_exec_hdr __P((struct exec *));
void md_swapout_exec_hdr __P((struct exec *));
void md_swapin_reloc __P((struct relocation_info *, int));
void md_swapout_reloc __P((struct relocation_info *, int));
void md_swapout_jmpslot __P((jmpslot_t *, int));
#define md_swapin_symbols(s,n) swap_symbols(s,n)
#define md_swapout_symbols(s,n) swap_symbols(s,n)
#define md_swapin_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapout_zsymbols(s,n) swap_zsymbols(s,n)
#define md_swapin_link_dynamic(l) swap_link_dynamic(l)
#define md_swapout_link_dynamic(l) swap_link_dynamic(l)
#define md_swapin_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapout_link_dynamic_2(l) swap_link_dynamic_2(l)
#define md_swapin_ld_debug(d) swap_ld_debug(d)
#define md_swapout_ld_debug(d) swap_ld_debug(d)
#define md_swapin_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapout_rrs_hash(f,n) swap_rrs_hash(f,n)
#define md_swapin_link_object(l,n) swapin_link_object(l,n)
#define md_swapout_link_object(l,n) swapout_link_object(l,n)
#define md_swapout_got(g,n) swap_longs((long*)(g),n)
#define md_swapin_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swapout_ranlib_hdr(h,n) swap_ranlib_hdr(h,n)
#define md_swap_short(x) ( (((x) >> 8) & 0xff) | (((x) & 0xff) << 8) )
#define md_swap_long(x) ( (((x) >> 24) & 0xff ) | (((x) >> 8 ) & 0xff00 ) | \
(((x) << 8 ) & 0xff0000) | (((x) << 24) & 0xff000000))
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[1] << 8) | \
( ((unsigned char *)(p))[0] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[3] << 24) | \
( ((unsigned char *)(p))[2] << 16) | \
( ((unsigned char *)(p))[1] << 8 ) | \
( ((unsigned char *)(p))[0] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[3] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[0] = \
((((unsigned long)(v)) ) & 0xff); }
#else /* We need not swap, but must pay attention to alignment: */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(p) ( ((unsigned char *)(p))[0] )
#define get_short(p) ( ( ((unsigned char *)(p))[0] << 8) | \
( ((unsigned char *)(p))[1] ) \
)
#define get_long(p) ( ( ((unsigned char *)(p))[0] << 24) | \
( ((unsigned char *)(p))[1] << 16) | \
( ((unsigned char *)(p))[2] << 8 ) | \
( ((unsigned char *)(p))[3] ) \
)
#define put_byte(p, v) { ((unsigned char *)(p))[0] = ((unsigned long)(v)); }
#define put_short(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) ) & 0xff); }
#define put_long(p, v) { ((unsigned char *)(p))[0] = \
((((unsigned long)(v)) >> 24) & 0xff); \
((unsigned char *)(p))[1] = \
((((unsigned long)(v)) >> 16) & 0xff); \
((unsigned char *)(p))[2] = \
((((unsigned long)(v)) >> 8) & 0xff); \
((unsigned char *)(p))[3] = \
((((unsigned long)(v)) ) & 0xff); }
#endif /* NEED_SWAP */
#else /* Not a cross linker: use native */
#define md_swap_short(x) (x)
#define md_swap_long(x) (x)
#define get_byte(where) (*(char *)(where))
#define get_short(where) (*(short *)(where))
#define get_long(where) (*(long *)(where))
#define put_byte(where,what) (*(char *)(where) = (what))
#define put_short(where,what) (*(short *)(where) = (what))
#define put_long(where,what) (*(long *)(where) = (what))
#endif /* CROSS_LINKER */

View File

@ -0,0 +1,101 @@
/*
* Copyright (c) 1993 Paul Kranenburg
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Paul Kranenburg.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software withough specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $Id: mdprologue.S,v 1.1 1993/10/16 21:54:36 pk Exp $
*/
/*
* SPARC run-time link editor entry points.
*/
#define CRT_VERSION_SUN 1
.seg "text" ! [internal]
.proc 16
.global _rtld_entry
_rtld_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
L.1B:
call L.2B
sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
L.2B:
!#PROLOGUE# 1
or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1B-.))),%l7
add %l7,%o7,%l7
cmp %i0, CRT_VERSION_SUN ! is crtp passed in Sun style,
bne 1f ! ie. relative to stack frame ?
nop
add %i1, %fp, %i1 ! if so, adjust to absolute address
1:
ld [%i1], %o3 ! load base address (crtp->crt_ba)
ld [%l7], %o2 ! get rtld's __DYNAMIC address
! from 1st GOT entry
add %o2, %o3, %o2 ! relocate and make it 3rd arg.
ld [%l7 + _rtld], %g1 ! get address of rtld()
add %g1, %o3, %g1 ! relocate
mov %i1, %o1 ! set up args, #2: crtp
call %g1 ! rtld(version, crtp, dp)
mov %i0, %o0 ! arg #1: version
ret
restore
.seg "data" ! [internal]
.seg "text"
.global _binder_entry
_binder_entry:
!#PROLOGUE# 0
save %sp,-96,%sp
!L.1C:
! call L.2C
! sethi %hi((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!L.2C:
! or %l7,%lo((__GLOBAL_OFFSET_TABLE_-(L.1C-.))),%l7
!#PROLOGUE# 1
sub %i7, 4, %o0 ! get to jmpslot through pc
ld [%i7+4], %o1 ! get relocation index
sethi %hi(0x3fffff), %o2 ! -> reloc_index & 0x003fffff
or %o2, %lo(0x3fffff), %o2 ! [internal]
call _binder ! and call binder(jsp, reloc_index)
and %o1, %o2, %o1
mov %o0, %g1 ! return value == function address
restore ! get rid of our context
jmp %g1 ! and go.
restore ! and the jmpslot's
nop
.seg "data" ! [internal]