This is Paul K's latest set of ld changes. A commit was necessary at this
[unix-history] / gnu / usr.bin / ld / sparc / md.c
CommitLineData
1136f72d 1/*
0f052032
JH
2 * Copyright (c) 1993 Paul Kranenburg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Paul Kranenburg.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software withough specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
6a61ea88 30 * $Id: md.c,v 1.6 1993/12/11 12:02:10 jkh Exp $
1136f72d
PR
31 */
32
33#include <sys/param.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <sys/types.h>
37#include <fcntl.h>
38#include <a.out.h>
39#include <stab.h>
40#include <string.h>
41
42#include "ld.h"
43
44/*
45 * Relocation masks and sizes for the Sparc architecture.
46 *
47 * Note that these are very dependent on the order of the enums in
48 * enum reloc_type (in a.out.h); if they change the following must be
49 * changed.
50 * Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
51 * This should work provided that relocations values have zeroes in their
52 * least significant 10 bits. As RELOC_RELATIVE is used only to relocate
53 * with load address values - which are page aligned - this condition is
54 * fulfilled as long as the system's page size is > 1024 (and a power of 2).
55 */
56static int reloc_target_rightshift[] = {
57 0, 0, 0, /* RELOC_8, _16, _32 */
58 0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
59 10, 0, /* HI22, _22 */
60 0, 0, /* RELOC_13, _LO10 */
61 0, 0, /* _SFA_BASE, _SFA_OFF13 */
62 0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
63 0, 10, /* _PC10, _PC22 */
64 2, 0, /* _JMP_TBL, _SEGOFF16 */
65 0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
66};
67static int reloc_target_size[] = {
68 0, 1, 2, /* RELOC_8, _16, _32 */
69 0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
70 2, 2, /* HI22, _22 */
71 2, 2, /* RELOC_13, _LO10 */
72 2, 2, /* _SFA_BASE, _SFA_OFF13 */
73 2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
74 2, 2, /* _PC10, _PC22 */
75 2, 0, /* _JMP_TBL, _SEGOFF16 */
76 2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
77};
78static int reloc_target_bitsize[] = {
79 8, 16, 32, /* RELOC_8, _16, _32 */
80 8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
81 22, 22, /* HI22, _22 */
82 13, 10, /* RELOC_13, _LO10 */
83 32, 32, /* _SFA_BASE, _SFA_OFF13 */
84 10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
85 10, 22, /* _PC10, _PC22 */
86 30, 0, /* _JMP_TBL, _SEGOFF16 */
87 32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
88};
89
90
91/*
92 * Get relocation addend corresponding to relocation record RP
93 * ADDR unused by SPARC impl.
94 */
95long
96md_get_addend(r, addr)
97struct relocation_info *r;
98unsigned char *addr;
99{
100 return r->r_addend;
101}
102
103void
104md_relocate(r, relocation, addr, relocatable_output)
105struct relocation_info *r;
106long relocation;
107unsigned char *addr;
108int relocatable_output;
109{
110 register unsigned long mask;
111
6a61ea88 112#ifndef RTLD
1136f72d
PR
113 if (relocatable_output) {
114 /*
115 * Non-PC relative relocations which are absolute or
116 * which have become non-external now have fixed
117 * relocations. Set the ADD_EXTRA of this relocation
118 * to be the relocation we have now determined.
119 */
120 if (!RELOC_PCREL_P(r)) {
121 if ((int) r->r_type <= RELOC_32
122 || RELOC_EXTERN_P(r) == 0)
123 RELOC_ADD_EXTRA(r) = relocation;
124 } else if (RELOC_EXTERN_P(r))
125 /*
126 * External PC-relative relocations continue
127 * to move around; update their relocations
128 * by the amount they have moved so far.
129 */
130 RELOC_ADD_EXTRA(r) -= pc_relocation;
131 return;
132 }
6a61ea88 133#endif
1136f72d
PR
134
135 relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
136
137 /* Unshifted mask for relocation */
138 mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
139 mask |= mask - 1;
140 relocation &= mask;
141
142 /* Shift everything up to where it's going to be used */
143 relocation <<= RELOC_TARGET_BITPOS(r);
144 mask <<= RELOC_TARGET_BITPOS(r);
145
146 switch (RELOC_TARGET_SIZE(r)) {
147 case 0:
148 if (RELOC_MEMORY_ADD_P(r))
149 relocation += (mask & *(u_char *) (addr));
150 *(u_char *) (addr) &= ~mask;
151 *(u_char *) (addr) |= relocation;
152 break;
153
154 case 1:
155 if (RELOC_MEMORY_ADD_P(r))
156 relocation += (mask & *(u_short *) (addr));
157 *(u_short *) (addr) &= ~mask;
158 *(u_short *) (addr) |= relocation;
159 break;
160
161 case 2:
162 if (RELOC_MEMORY_ADD_P(r))
163 relocation += (mask & *(u_long *) (addr));
164 *(u_long *) (addr) &= ~mask;
165 *(u_long *) (addr) |= relocation;
166 break;
167 default:
168 fatal( "Unimplemented relocation field length in");
169 }
170}
171
6a61ea88 172#ifndef RTLD
1136f72d
PR
173/*
174 * Machine dependent part of claim_rrs_reloc().
175 * On the Sparc the relocation offsets are stored in the r_addend member.
176 */
177int
178md_make_reloc(rp, r, type)
179struct relocation_info *rp, *r;
180int type;
181{
182 r->r_type = rp->r_type;
183 r->r_addend = rp->r_addend;
184
185#if 1
186 /*
187 * This wouldn't be strictly necessary - we could record the
0f052032 188 * relocation value "in situ" in stead of in the r_addend field -
1136f72d 189 * but we are being Sun compatible here. Besides, Sun's ld.so
0f052032
JH
190 * has a bug that prevents it from handling this alternate method.
191 *
192 * IT WOULD BE REALLY NICE TO HAVE CONSISTENCY THROUGHOUT THE ENTIRE
193 * RELOCATION PROCESS, ie. using `r_addend' for storing all partially
194 * completed relocations, in stead of mixing them in both relocation
195 * records and in the segment data.
1136f72d
PR
196 */
197 if (RELOC_PCREL_P(rp))
198 r->r_addend -= pc_relocation;
199#endif
200
201 return 1;
202}
6a61ea88 203#endif
1136f72d
PR
204
205/*
206 * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
207 * to the binder slot (which is at offset 0 of the PLT).
208 */
209void
210md_make_jmpslot(sp, offset, index)
211jmpslot_t *sp;
212long offset;
213long index;
214{
215 u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
216 sp->opcode1 = SAVE;
217 /* The following is a RELOC_WDISP30 relocation */
218 sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
219 sp->reloc_index = NOP | index;
220}
221
222/*
223 * Set up a "direct" transfer (ie. not through the run-time binder) from
224 * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
225 * and by `ld.so' after resolving the symbol.
226 * On the i386, we use the JMP instruction which is PC relative, so no
227 * further RRS relocations will be necessary for such a jmpslot.
228 *
229 * OFFSET unused on Sparc.
230 */
231void
232md_fix_jmpslot(sp, offset, addr)
233jmpslot_t *sp;
234long offset;
235u_long addr;
236{
237 /*
238 * Here comes a RELOC_{LO10,HI22} relocation pair
239 * The resulting code is:
240 * sethi %hi(addr), %g1
241 * jmp %g1+%lo(addr)
242 * nop ! delay slot
243 */
244 sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
245 sp->opcode2 = JMP | (addr & 0x000003ff);
246 sp->reloc_index = NOP;
247}
248
249/*
250 * Update the relocation record for a jmpslot.
251 */
252void
253md_make_jmpreloc(rp, r, type)
254struct relocation_info *rp, *r;
255int type;
256{
257 if (type & RELTYPE_RELATIVE)
258 r->r_type = RELOC_RELATIVE;
259 else
260 r->r_type = RELOC_JMP_SLOT;
261
262 r->r_addend = rp->r_addend;
263}
264
265/*
266 * Set relocation type for a GOT RRS relocation.
267 */
268void
269md_make_gotreloc(rp, r, type)
270struct relocation_info *rp, *r;
271int type;
272{
273 /*
274 * GOT value resolved (symbolic or entry point): R_32
275 * GOT not resolved: GLOB_DAT
276 *
277 * NOTE: I don't think it makes a difference.
278 */
279 if (type & RELTYPE_RELATIVE)
280 r->r_type = RELOC_32;
281 else
282 r->r_type = RELOC_GLOB_DAT;
283
284 r->r_addend = 0;
285}
286
287/*
288 * Set relocation type for a RRS copy operation.
289 */
290void
291md_make_cpyreloc(rp, r)
292struct relocation_info *rp, *r;
293{
294 r->r_type = RELOC_COPY_DAT;
295 r->r_addend = 0;
296}
297
80f25b52
JH
298void
299md_set_breakpoint(where, savep)
300long where;
301long *savep;
302{
303 *savep = *(long *)where;
27b6ced7 304 *(long *)where = TRAP;
80f25b52
JH
305}
306
6a61ea88
JH
307#ifndef RTLD
308/*
309 * Initialize (output) exec header such that useful values are
310 * obtained from subsequent N_*() macro evaluations.
311 */
312void
313md_init_header(hp, magic, flags)
314struct exec *hp;
315int magic, flags;
316{
317#ifdef NetBSD
318 N_SETMAGIC((*hp), magic, MID_MACHINE, flags);
319
320 /* TEXT_START depends on the value of outheader.a_entry. */
321 if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
322 hp->a_entry = PAGSIZ;
323#else
324 hp->a_magic = magic;
325 hp->a_machtype = M_SPARC;
326 hp->a_toolversion = 1;
327 hp->a_dynamic = ((flags) & EX_DYNAMIC);
328
329 /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
330 if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
331 hp->a_entry = N_PAGSIZ(*hp);
332#endif
333}
334
335/*
336 * Check for acceptable foreign machine Ids
337 */
338int
339md_midcompat(hp)
340struct exec *hp;
341{
342#ifdef NetBSD
343#define SUN_M_SPARC 3
344 return (((md_swap_long(hp->a_midmag)&0x00ff0000) >> 16) == SUN_M_SPARC);
345#else
346 return hp->a_machtype == M_SPARC;
347#endif
348}
349#endif /* RTLD */