_relocate.c revision 11053:f33a1c7f3155
1169689Skan/*
2169689Skan * CDDL HEADER START
3169689Skan *
4169689Skan * The contents of this file are subject to the terms of the
5169689Skan * Common Development and Distribution License (the "License").
6169689Skan * You may not use this file except in compliance with the License.
7169689Skan *
8169689Skan * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9169689Skan * or http://www.opensolaris.org/os/licensing.
10169689Skan * See the License for the specific language governing permissions
11169689Skan * and limitations under the License.
12169689Skan *
13169689Skan * When distributing Covered Code, include this CDDL HEADER in each
14169689Skan * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15169689Skan * If applicable, add the following below this CDDL HEADER, with the
16169689Skan * fields enclosed by brackets "[]" replaced with your own identifying
17169689Skan * information: Portions Copyright [yyyy] [name of copyright owner]
18169689Skan *
19169689Skan * CDDL HEADER END
20169689Skan */
21169689Skan
22169689Skan/*
23169689Skan * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24169689Skan * Use is subject to license terms.
25169689Skan */
26169689Skan
27169689Skan#include	<string.h>
28169689Skan#include	"machdep.h"
29169689Skan#include	"reloc.h"
30169689Skan#include	"_librtld.h"
31169689Skan#include	"_elf.h"
32169689Skan
33169689Skan/*
34169689Skan * Undo relocations that have been applied to a memory image.  Basically this
35169689Skan * involves copying the original files relocation offset into the new image
36169689Skan * being created.
37169689Skan */
38169689Skan/* ARGSUSED3 */
39169689Skanvoid
40169689Skanundo_reloc(void *vrel, uchar_t *oaddr, uchar_t *iaddr, Reloc *reloc)
41169689Skan{
42169689Skan	Rela		*rel = vrel;
43169689Skan	const Rel_entry	*rep;
44169689Skan	Xword		rtype = ELF_R_TYPE(rel->r_info, M_MACH);
45169689Skan	ulong_t		*_oaddr;
46169689Skan	ulong_t		*_iaddr;
47169689Skan
48169689Skan	switch (rtype) {
49169689Skan	case R_SPARC_NONE:
50169689Skan		break;
51169689Skan	case R_SPARC_COPY:
52169689Skan		(void) memset((void *)oaddr, 0, (size_t)reloc->r_size);
53169689Skan		break;
54169689Skan	case R_SPARC_JMP_SLOT:
55169689Skan		/* LINTED */
56169689Skan		_oaddr = (unsigned long *)oaddr;
57169689Skan		/* LINTED */
58169689Skan		_iaddr = (unsigned long *)iaddr;
59169689Skan
60169689Skan		if (_iaddr) {
61169689Skan			*_oaddr++ = *_iaddr++;
62169689Skan			*_oaddr++ = *_iaddr++;
63169689Skan			*_oaddr = *_iaddr;
64169689Skan		} else {
65169689Skan			*_oaddr++ = 0;
66169689Skan			*_oaddr++ = 0;
67169689Skan			*_oaddr = 0;
68169689Skan		}
69169689Skan		break;
70169689Skan	default:
71169689Skan		rep = &reloc_table[rtype];
72169689Skan		if (iaddr)
73169689Skan			(void) memcpy(oaddr, iaddr, rep->re_fsize);
74169689Skan		else
75169689Skan			(void) memset(oaddr, 0, rep->re_fsize);
76169689Skan	}
77169689Skan}
78169689Skan
79169689Skan/*
80169689Skan * Copy a relocation record and increment its value.  The record must reflect
81169689Skan * the new address to which this image is fixed.
82169689Skan */
83169689Skan/* ARGSUSED3 */
84169689Skanvoid
85169689Skaninc_reloc(void *vnrel, void *vorel, Reloc *reloc, uchar_t *oaddr,
86169689Skan    uchar_t *iaddr)
87169689Skan{
88169689Skan	Rela	*nrel = vnrel;
89169689Skan	Rela	*orel = vorel;
90169689Skan
91169689Skan	*nrel = *orel;
92169689Skan	nrel->r_offset += reloc->r_value;
93169689Skan}
94169689Skan
95169689Skan/*
96169689Skan * Clear a relocation record.  The relocation has been applied to the image and
97169689Skan * thus the relocation must not occur again.
98169689Skan */
99169689Skanvoid
100169689Skanclear_reloc(void *vrel)
101169689Skan{
102169689Skan	Rela	*rel = vrel;
103169689Skan
104169689Skan	rel->r_offset = 0;
105169689Skan	rel->r_info = ELF_R_INFO(0, R_SPARC_NONE);
106169689Skan	rel->r_addend = 0;
107169689Skan}
108169689Skan
109169689Skan/*
110169689Skan * Apply a relocation to an image being built from an input file.  Use the
111169689Skan * runtime linkers routines to do the necessary magic.
112169689Skan */
113169689Skanvoid
114169689Skanapply_reloc(void *vrel, Reloc *reloc, const char *name, uchar_t *oaddr,
115169689Skan    Rt_map *lmp)
116171825Skan{
117171825Skan	Rela	*rel = vrel;
118169689Skan	Xword	type = ELF_R_TYPE(rel->r_info, M_MACH);
119169689Skan	Xword	value = reloc->r_value + rel->r_addend;
120169689Skan
121169689Skan	if (type == R_SPARC_JMP_SLOT) {
122169689Skan		uintptr_t	addr, vaddr;
123169689Skan
124169689Skan		if (FLAGS(lmp) & FLG_RT_FIXED)
125169689Skan			vaddr = 0;
126169689Skan		else
127169689Skan			vaddr = ADDR(lmp);
128169689Skan
129169689Skan		addr = (uintptr_t)oaddr - rel->r_offset;
130169689Skan		/* LINTED */
131169689Skan		(void) elf_plt_write((uintptr_t)addr, vaddr, rel,
132169689Skan		    (uintptr_t)value, reloc->r_pltndx);
133169689Skan
134169689Skan	} else if (type == R_SPARC_COPY) {
135169689Skan		(void) memcpy((void *)oaddr, (void *)value,
136169689Skan		    (size_t)reloc->r_size);
137169689Skan	} else {
138169689Skan		if (IS_EXTOFFSET(type))
139169689Skan			value += ELF_R_TYPE_DATA(rel->r_info);
140169689Skan		(void) do_reloc_rtld(type, oaddr, &value, reloc->r_name, name,
141169689Skan		    LIST(lmp));
142169689Skan	}
143169689Skan}
144169689Skan