doreloc.c revision 75521904d7c3dbe11337904d9bead2518c94cc50
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(_KERNEL)
#include "reloc.h"
#else
#include <stdio.h>
#include "sgs.h"
#include "machdep.h"
#include "libld.h"
#include "reloc.h"
#include "conv.h"
#include "msg.h"
#endif
/*
* This table represents the current relocations that do_reloc() is able to
* process. The relocations below that are marked SPECIAL are relocations that
* take special processing and shouldn't actually ever be passed to do_reloc().
*/
/* R_SPARC_NONE */ {0x0, 0, 0, 0, 0},
1, 0, 0},
2, 0, 0},
4, 0, 0},
4, 2, 30},
4, 2, 22},
#if defined(_ELF64)
#else
#endif
4, 0, 13},
4, 0, 13},
4, 10, 22},
4, 2, 30},
/* R_SPARC_COPY */ {0x0, 0, 0, 0, 0}, /* SPECIAL */
#if defined(_ELF64)
#else
#endif
/* R_SPARC_JMP_SLOT */ {0x0, 0, 0, 0, 0}, /* SPECIAL */
#if defined(_ELF64)
#else
#endif
FLG_RE_ADDRELATIVE, 4, 0, 0},
4, 0, 0},
4, 10, 22},
4, 0, 13},
4, 0, 10},
4, 0, 11},
8, 0, 0}, /* V9 */
4, 42, 22}, /* V9 */
4, 32, 13}, /* V9 */
4, 10, 22}, /* V9 */
4, 10, 22}, /* V9 */
4, 2, 16},
4, 2, 19},
/* R_SPARC_GLOB_JMP */ {0x0, 0, 0, 0, 0}, /* V9 - not implemented */
/* removed from v9 ABI */
8, 0, 0},
FLG_RE_ADDRELATIVE, 8, 0, 0},
4, 10, 22}, /* V9 - HaL */
4, 0, 13}, /* V9 - HaL */
22, 22}, /* V9 */
0, 0, 0}, /* V9 - special */
8, 0, 0}, /* V9 */
2, 0, 0},
4, 10, 22},
4, 10, 22},
4, 10, 22},
4, 0, 13},
4, 10, 22},
4, 10, 22},
4, 0, 13},
4, 10, 22},
12, 22} /* V9 */
};
/*
* Write a single relocated value to its reference location.
* We assume we wish to add the relocation amount, value, to the
* the value of the address already present in the instruction.
*
* NAME VALUE FIELD CALCULATION
*
* R_SPARC_NONE 0 none none
* R_SPARC_8 1 V-byte8 S + A
* R_SPARC_16 2 V-half16 S + A
* R_SPARC_32 3 V-word32 S + A
* R_SPARC_DISP8 4 V-byte8 S + A - P
* R_SPARC_DISP16 5 V-half16 S + A - P
* R_SPARC_DISP32 6 V-word32 S + A - P
* R_SPARC_WDISP30 7 V-disp30 (S + A - P) >> 2
* R_SPARC_WDISP22 8 V-disp22 (S + A - P) >> 2
* R_SPARC_HI22 9 T-imm22 (S + A) >> 10
* R_SPARC_22 10 V-imm22 S + A
* R_SPARC_13 11 V-simm13 S + A
* R_SPARC_LO10 12 T-simm13 (S + A) & 0x3ff
* R_SPARC_GOT10 13 T-simm13 G & 0x3ff
* R_SPARC_GOT13 14 V-simm13 G
* R_SPARC_GOT22 15 T-imm22 G >> 10
* R_SPARC_PC10 16 T-simm13 (S + A - P) & 0x3ff
* R_SPARC_PC22 17 V-disp22 (S + A - P) >> 10
* R_SPARC_WPLT30 18 V-disp30 (L + A - P) >> 2
* R_SPARC_COPY 19 none none
* R_SPARC_GLOB_DAT 20 V-word32 S + A
* R_SPARC_JMP_SLOT 21 V-plt22 S + A
* R_SPARC_RELATIVE 22 V-word32 S + A
* R_SPARC_UA32 23 V-word32 S + A
* R_SPARC_PLT32 24 V-word32 L + A
* R_SPARC_HIPLT22 25 T-imm22 (L + A) >> 10
* R_SPARC_LOPLT10 26 T-simm13 (L + A) & 0x3ff
* R_SPARC_PCPLT32 27 V-word32 L + A - P
* R_SPARC_PCPLT22 28 V-disp22 (L + A - P) >> 10
* R_SPARC_PCPLT10 29 V-simm13 (L + A - P) & 0x3ff
* R_SPARC_10 30 V-simm10 S + A
* R_SPARC_11 31 V-simm11 S + A
* R_SPARC_64 32 V-xword64 S + A
* R_SPARC_OLO10 33 V-simm13 ((S + A) & 0x3ff) + O
* R_SPARC_HH22 34 V-imm22 (S + A) >> 42
* R_SPARC_HM10 35 T-simm13 ((S + A) >>32) & 0x3ff
* R_SPARC_LM22 36 T-imm22 (S + A) >> 10
* R_SPARC_PC_HH22 37 V-imm22 (S + A - P) >> 42
* R_SPARC_PC_HM10 38 T-simm13 ((S + A - P) >> 32) & 0x3ff
* R_SPARC_PC_LM22 39 T-imm22 (S + A - P) >> 10
* R_SPARC_WDISP19 41 V-disp19 (S + A - P) >> 2
* R_SPARC_GLOB_JMP 42 V-xword64 S + A
* R_SPARC_7 43 V-imm7 S + A
* R_SPARC_5 44 V-imm5 S + A
* R_SPARC_6 45 V-imm6 S + A
* R_SPARC_DISP64 46 V-xword64 S + A - P
* R_SPARC_PLT64 47 V-xword64 L + A
* R_SPARC_HIX22 48 V-imm22 ((S + A)^0xffffffffffffffff) >> 10
* R_SPARC_LOX10 49 T-simm13 ((S + A) & 0x3ff) | 0x1c00
* R_SPARC_H44 50 V-imm22 (S + A) >> 22
* R_SPARC_M44 51 T-imm10 ((S + A) >> 12) & 0x3ff
* R_SPARC_L44 52 T-imm13 (S + A) & 0xfff
* R_SPARC_REGISTER 53 V-xword64 S + A
* R_SPARC_UA64 54 V-xword64 S + A
* R_SPARC_UA16 55 V-half16 S + A
* R_SPARC_TLS_GD_HI22 56 T-simm22 @dtlndx(S+A) >> 10
* R_SPARC_TLS_GD_LO10 57 T-simm13 @dtlndx(S+A) & 0x3ff
* R_SPARC_TLS_GD_ADD 58 none special
* R_SPARC_TLS_GD_CALL 59 V-disp30 special
* R_SPARC_TLS_LDM_HI22 60 T-simm22 @tmndx(S+A) >> 10
* R_SPARC_TLS_LDM_LO10 61 T-simm13 @tmndx(S+A) & 0x3ff
* R_SPARC_TLS_LDM_ADD 62 none special
* R_SPARC_TLS_LDM_CALL 63 V-disp30 special
* R_SPARC_TLS_LDO_HIX22 64 V-simm22 @dtpoff(S+A) >> 10
* R_SPARC_TLS_LDO_LOX10 65 T-simm13 @dtpoff(S+A) & 0x3ff
* R_SPARC_TLS_LDO_ADD 66 none special
* R_SPARC_TLS_IE_HI22 67 T-simm22 @got(@tpoff(S+A)) >> 10
* R_SPARC_TLS_IE_LO10 68 T-simm13 @got(@tpoff(S+A)) & 0x3ff
* R_SPARC_TLS_IE_LD 69 none special
* R_SPARC_TLS_IE_LDX 70 none special
* R_SPARC_TLS_IE_ADD 71 none special
* R_SPARC_TLS_LE_HIX22 72 V-simm22 (@tpoff(S+A)^0xffffffff) >> 10
* R_SPARC_TLS_LE_LOX10 73 T-simm13 (@tpoff(S+A) & 0x3ff) | 0x1c00
* R_SPARC_TLS_DTPMOD32 74 V-word32 @dtmod(S+A)
* R_SPARC_TLS_DTPMOD64 75 V-word64 @dtmod(S+A)
* R_SPARC_TLS_DTPOFF32 76 V-word32 @dtpoff(S+A)
* R_SPARC_TLS_DTPOFF64 77 V-word64 @dtpoff(S+A)
* R_SPARC_TLS_TPOFF32 78 V-word32 @tpoff(S+A)
* R_SPARC_TLS_TPOFF64 79 V-word64 @tpoff(S+A)
* R_SPARC_GOTDATA_HIX22 80 T-imm22 ((S + A - G) >> 10) ^
* ((S + A- G) >> 42)
* R_SPARC_GOTDATA_LOX10 81 T-simm13 ((S + A - G) & 0x3ff) |
* (((S + A - G) >> 31) & 0x1c00)
* R_SPARC_GOTDATA_OP_HIX22 82 T-imm22 (G >> 10) & (G >> 42)
* R_SPARC_GOTDATA_OP_LOX10 T-simm13 (G & 0x3ff) |
* ((0x1c00^~((G>>50)&0x1c00)))
* R_SPARC_H34 V-imm22 (S + A) >> 12
*
* This is Figure 4-20: Relocation Types from the Draft Copy of
* the ABI, Printed on 11/29/88.
*
* NOTE1: relocations 24->45 are newly registered relocations to support
* C++ ABI & SPARC V8+ and SPARC V9 architectures (1/9/94), and
* 64-bit relocations 46-55 were added for SPARC V9.
*
* NOTE2: relocations 56->79 are added to support Thread-Local storage
* as recorded in PSARC/2001/509
*
* NOTE3: The value to be passed for relocations R_SPARC_HIX22 and
* R_SPARC_TLS_HIX22 are negative values. So the upper 10 or 40 bits
* are 1. (So when the exclusive OR is applied, the upper bits
* will be 0.)
*
* Relocation calculations:
*
* The FIELD names indicate whether the relocation type checks for overflow.
* A calculated relocation value may be larger than the intended field, and
* the relocation type may verify (V) that the value fits, or truncate (T)
* the result.
*
* CALCULATION uses the following notation:
* A the addend used
* B the base address of the shared object in memory
* G the offset into the global offset table
* L the procedure linkage entry
* P the place of the storage unit being relocated
* S the value of the symbol
* O secondary addend (extra offset) in v9 r_info field
*
* @dtlndx(x): Allocate two contiguous entries in the GOT table to hold
* a Tls_index structure (for passing to __tls_get_addr()). The
* instructions referencing this entry will be bound to the first
* of the two GOT entries.
*
* @tmndx(x): Allocate two contiguous entries in the GOT table to hold
* a Tls_index structure (for passing to __tls_get_addr()). The
* ti_offset field of the Tls_index will be set to 0 (zero) and the
* ti_module will be filled in at run-time. The call to
* __tls_get_addr() will return the starting offset of the dynamic
* TLS block.
*
* @dtpoff(x): calculate the tlsoffset relative to the TLS block.
*
* @tpoff(x): calculate the negative tlsoffset relative to the static
* TLS block. This value can be added to the thread-pointer to
* calculate the tls address.
*
* @dtpmod(x): calculate the module id of the object containing symbol x.
*
* The calculations in the CALCULATION column are assumed to have been performed
* before calling this function except for the addition of the addresses in the
* instructions.
*
* Upon successful completion of do_reloc() *value will be set to the
* 'bit-shifted' value that will be or'ed into memory.
*/
/* ARGSUSED3 */
int
{
unsigned char bshift;
int field_size, re_flags;
/*
* sigfit_mask takes into account that a value
* might be signed and discards the signbit for
* comparison.
*/
} else
if (field_size == 0) {
return (0);
}
if (re_flags & FLG_RE_UNALIGN) {
int i;
/*
* Adjust the offset.
*/
/* LINTED */
i = (int)(sizeof (Xword) - field_size);
if (i > 0)
dest += i;
basevalue = 0;
for (i = field_size - 1; i >= 0; i--)
} else {
return (0);
}
switch (field_size) {
case 1:
break;
case 2:
/* LINTED */
break;
case 4:
/* LINTED */
break;
case 8:
/* LINTED */
break;
default:
return (0);
}
}
if (sigbit_mask) {
/*
* The WDISP16 relocation is an unusual one in that it's bits
* are not all contiguous. We have to selectivly pull them out.
*/
if (re_flags & FLG_RE_WDISP16) {
(basevalue & 0x3fff);
basevalue &= ~0x303fff;
} else {
basevalue &= ~sigbit_mask;
}
/*
* If value is signed make sure that we signextend the uvalue.
*/
if (re_flags & FLG_RE_SIGN) {
uvalue |= ~sigbit_mask;
}
} else
if (bshift)
if (bshift) {
/*
* This is to check that we are not attempting to
* jump to a non-4 byte aligned address.
*/
return (0);
}
if (re_flags & FLG_RE_SIGN) {
} else {
}
}
if ((rtype == R_SPARC_GOTDATA_HIX22) ||
(rtype == R_SPARC_GOTDATA_OP_HIX22)) {
}
(rtype != R_SPARC_GOTDATA_HIX22))
uvalue |= 0x1c00;
corevalue |= 0x1c00;
}
if ((rtype == R_SPARC_GOTDATA_LOX10) ||
(rtype == R_SPARC_GOTDATA_OP_LOX10)) {
}
if (((re_flags & FLG_RE_SIGN) &&
(!(re_flags & FLG_RE_SIGN) &&
return (0);
}
}
if (sigbit_mask) {
/*
* Again the R_SPARC_WDISP16 relocation takes special
* processing because of its non-continguous bits.
*/
if (re_flags & FLG_RE_WDISP16)
(uvalue & 0x3fff);
else
uvalue &= sigbit_mask;
/*
* Combine value back with original word
*/
}
if (re_flags & FLG_RE_UNALIGN) {
int i;
/*
* Adjust the offset.
*/
/* LINTED */
i = (int)(sizeof (Xword) - field_size);
if (i > 0)
src += i;
for (i = field_size - 1; i >= 0; i--)
} else {
case 1:
break;
case 2:
/* LINTED */
break;
case 4:
/* LINTED */
break;
case 8:
/* LINTED */
break;
}
}
return (1);
}