2 * Copyright (c) 1993 Paul Kranenburg
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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 without specific prior written permission
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.
30 * $FreeBSD: src/gnu/usr.bin/ld/sparc/md.c,v 1.12 1999/08/27 23:36:04 peter Exp $
31 * $DragonFly: src/gnu/usr.bin/ld/sparc/Attic/md.c,v 1.2 2003/06/17 04:25:46 dillon Exp $
34 #include <sys/param.h>
35 #include <sys/types.h>
47 * Relocation masks and sizes for the Sparc architecture.
49 * Note that these are very dependent on the order of the enums in
50 * enum reloc_type (in a.out.h); if they change the following must be
52 * Also, note that RELOC_RELATIVE is handled as if it were a RELOC_HI22.
53 * This should work provided that relocations values have zeroes in their
54 * least significant 10 bits. As RELOC_RELATIVE is used only to relocate
55 * with load address values - which are page aligned - this condition is
56 * fulfilled as long as the system's page size is > 1024 (and a power of 2).
58 static int reloc_target_rightshift[] = {
59 0, 0, 0, /* RELOC_8, _16, _32 */
60 0, 0, 0, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
61 10, 0, /* HI22, _22 */
62 0, 0, /* RELOC_13, _LO10 */
63 0, 0, /* _SFA_BASE, _SFA_OFF13 */
64 0, 0, 10, /* _BASE10, _BASE13, _BASE22 */
65 0, 10, /* _PC10, _PC22 */
66 2, 0, /* _JMP_TBL, _SEGOFF16 */
67 0, 0, 0 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
69 static int reloc_target_size[] = {
70 0, 1, 2, /* RELOC_8, _16, _32 */
71 0, 1, 2, 2, 2, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
73 2, 2, /* RELOC_13, _LO10 */
74 2, 2, /* _SFA_BASE, _SFA_OFF13 */
75 2, 2, 2, /* _BASE10, _BASE13, _BASE22 */
76 2, 2, /* _PC10, _PC22 */
77 2, 0, /* _JMP_TBL, _SEGOFF16 */
78 2, 0, 2 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
80 static int reloc_target_bitsize[] = {
81 8, 16, 32, /* RELOC_8, _16, _32 */
82 8, 16, 32, 30, 22, /* DISP8, DISP16, DISP32, WDISP30, WDISP22 */
83 22, 22, /* HI22, _22 */
84 13, 10, /* RELOC_13, _LO10 */
85 32, 32, /* _SFA_BASE, _SFA_OFF13 */
86 10, 13, 22, /* _BASE10, _BASE13, _BASE22 */
87 10, 22, /* _PC10, _PC22 */
88 30, 0, /* _JMP_TBL, _SEGOFF16 */
89 32, 0, 22 /* _GLOB_DAT, JMP_SLOT, _RELATIVE */
94 * Get relocation addend corresponding to relocation record RP
95 * ADDR unused by SPARC impl.
98 md_get_addend(r, addr)
99 struct relocation_info *r;
106 md_relocate(r, relocation, addr, relocatable_output)
107 struct relocation_info *r;
110 int relocatable_output;
112 register unsigned long mask;
115 if (relocatable_output) {
117 * Non-PC relative relocations which are absolute or
118 * which have become non-external now have fixed
119 * relocations. Set the ADD_EXTRA of this relocation
120 * to be the relocation we have now determined.
122 if (!RELOC_PCREL_P(r)) {
123 if ((int) r->r_type <= RELOC_32
124 || RELOC_EXTERN_P(r) == 0)
125 RELOC_ADD_EXTRA(r) = relocation;
126 } else if (RELOC_EXTERN_P(r))
128 * External PC-relative relocations continue
129 * to move around; update their relocations
130 * by the amount they have moved so far.
132 RELOC_ADD_EXTRA(r) -= pc_relocation;
137 relocation >>= RELOC_VALUE_RIGHTSHIFT(r);
139 /* Unshifted mask for relocation */
140 mask = 1 << RELOC_TARGET_BITSIZE(r) - 1;
144 /* Shift everything up to where it's going to be used */
145 relocation <<= RELOC_TARGET_BITPOS(r);
146 mask <<= RELOC_TARGET_BITPOS(r);
148 switch (RELOC_TARGET_SIZE(r)) {
150 if (RELOC_MEMORY_ADD_P(r))
151 relocation += (mask & *(u_char *) (addr));
152 *(u_char *) (addr) &= ~mask;
153 *(u_char *) (addr) |= relocation;
157 if (RELOC_MEMORY_ADD_P(r))
158 relocation += (mask & *(u_short *) (addr));
159 *(u_short *) (addr) &= ~mask;
160 *(u_short *) (addr) |= relocation;
164 if (RELOC_MEMORY_ADD_P(r))
165 relocation += (mask & *(u_long *) (addr));
166 *(u_long *) (addr) &= ~mask;
167 *(u_long *) (addr) |= relocation;
170 errx(1, "Unimplemented relocation field length: %d",
171 RELOC_TARGET_SIZE(r));
177 * Machine dependent part of claim_rrs_reloc().
178 * On the Sparc the relocation offsets are stored in the r_addend member.
181 md_make_reloc(rp, r, type)
182 struct relocation_info *rp, *r;
185 r->r_type = rp->r_type;
186 r->r_addend = rp->r_addend;
190 * This wouldn't be strictly necessary - we could record the
191 * relocation value "in situ" in stead of in the r_addend field -
192 * but we are being Sun compatible here. Besides, Sun's ld.so
193 * has a bug that prevents it from handling this alternate method.
195 * IT WOULD BE REALLY NICE TO HAVE CONSISTENCY THROUGHOUT THE ENTIRE
196 * RELOCATION PROCESS, ie. using `r_addend' for storing all partially
197 * completed relocations, in stead of mixing them in both relocation
198 * records and in the segment data.
200 if (RELOC_PCREL_P(rp))
201 r->r_addend -= pc_relocation;
209 * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
210 * to the binder slot (which is at offset 0 of the PLT).
213 md_make_jmpslot(sp, offset, index)
218 u_long fudge = (u_long) -(sizeof(sp->opcode1) + offset);
220 /* The following is a RELOC_WDISP30 relocation */
221 sp->opcode2 = CALL | ((fudge >> 2) & 0x3fffffff);
222 sp->reloc_index = NOP | index;
226 * Set up a "direct" transfer (ie. not through the run-time binder) from
227 * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
228 * and by `ld.so' after resolving the symbol.
229 * On the i386, we use the JMP instruction which is PC relative, so no
230 * further RRS relocations will be necessary for such a jmpslot.
232 * OFFSET unused on Sparc.
235 md_fix_jmpslot(sp, offset, addr)
241 * Here comes a RELOC_{LO10,HI22} relocation pair
242 * The resulting code is:
243 * sethi %hi(addr), %g1
247 sp->opcode1 = SETHI | ((addr >> 10) & 0x003fffff);
248 sp->opcode2 = JMP | (addr & 0x000003ff);
249 sp->reloc_index = NOP;
253 * Update the relocation record for a jmpslot.
256 md_make_jmpreloc(rp, r, type)
257 struct relocation_info *rp, *r;
260 if (type & RELTYPE_RELATIVE)
261 r->r_type = RELOC_RELATIVE;
263 r->r_type = RELOC_JMP_SLOT;
265 r->r_addend = rp->r_addend;
269 * Set relocation type for a GOT RRS relocation.
272 md_make_gotreloc(rp, r, type)
273 struct relocation_info *rp, *r;
277 * GOT value resolved (symbolic or entry point): R_32
278 * GOT not resolved: GLOB_DAT
280 * NOTE: I don't think it makes a difference.
282 if (type & RELTYPE_RELATIVE)
283 r->r_type = RELOC_32;
285 r->r_type = RELOC_GLOB_DAT;
291 * Set relocation type for a RRS copy operation.
294 md_make_cpyreloc(rp, r)
295 struct relocation_info *rp, *r;
297 r->r_type = RELOC_COPY_DAT;
302 md_set_breakpoint(where, savep)
306 *savep = *(long *)where;
307 *(long *)where = TRAP;
312 * Initialize (output) exec header such that useful values are
313 * obtained from subsequent N_*() macro evaluations.
316 md_init_header(hp, magic, flags)
321 N_SETMAGIC((*hp), magic, MID_MACHINE, flags);
323 /* TEXT_START depends on the value of outheader.a_entry. */
324 if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
325 hp->a_entry = PAGSIZ;
328 hp->a_machtype = M_SPARC;
329 hp->a_toolversion = 1;
330 hp->a_dynamic = ((flags) & EX_DYNAMIC);
332 /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
333 if (!(link_mode & SHAREABLE)) /*WAS: if (entry_symbol) */
334 hp->a_entry = N_PAGSIZ(*hp);
339 * Check for acceptable foreign machine Ids
346 #define SUN_M_SPARC 3
347 return (((md_swap_long(hp->a_midmag)&0x00ff0000) >> 16) == SUN_M_SPARC);
349 return hp->a_machtype == M_SPARC;