Initial import from FreeBSD RELENG_4:
[games.git] / libexec / rtld-aout / i386 / md.c
1 /*
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 without 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  *
30  * $FreeBSD: src/libexec/rtld-aout/i386/md.c,v 1.17 1999/08/28 00:10:07 peter Exp $
31  */
32
33 #include <sys/param.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/types.h>
38 #include <err.h>
39 #include <fcntl.h>
40 #include <a.out.h>
41 #include <stab.h>
42 #include <string.h>
43
44 #include "dynamic.h"
45
46 #if defined(RTLD) && defined(SUN_COMPAT)
47 #define REL_SIZE(r) (2)         /* !!!!! Sun BUG compatible */
48 #else
49 #define REL_SIZE(r) ((r)->r_length)
50 #endif
51
52 /*
53  * Get relocation addend corresponding to relocation record RP
54  * from address ADDR
55  */
56 long
57 md_get_addend(rp, addr)
58 struct relocation_info  *rp;
59 unsigned char           *addr;
60 {
61         switch (REL_SIZE(rp)) {
62         case 0:
63                 return get_byte(addr);
64         case 1:
65                 return get_short(addr);
66         case 2:
67                 return get_long(addr);
68         default:
69                 errx(1, "Unsupported relocation size: %x",
70                     REL_SIZE(rp));
71         }
72 }
73
74 /*
75  * Put RELOCATION at ADDR according to relocation record RP.
76  */
77 void
78 md_relocate(rp, relocation, addr, relocatable_output)
79 struct relocation_info  *rp;
80 long                    relocation;
81 unsigned char           *addr;
82 int                     relocatable_output;
83 {
84         switch (REL_SIZE(rp)) {
85         case 0:
86                 put_byte(addr, relocation);
87                 break;
88         case 1:
89                 put_short(addr, relocation);
90                 break;
91         case 2:
92                 put_long(addr, relocation);
93                 break;
94         default:
95                 errx(1, "Unsupported relocation size: %x",
96                     REL_SIZE(rp));
97         }
98 }
99
100 /*
101  * Machine dependent part of claim_rrs_reloc().
102  * Set RRS relocation type.
103  */
104 int
105 md_make_reloc(rp, r, type)
106 struct relocation_info  *rp, *r;
107 int                     type;
108 {
109         /* Relocation size */
110         r->r_length = rp->r_length;
111
112         if (rp->r_pcrel)
113                 r->r_pcrel = 1;
114
115         if (type & RELTYPE_RELATIVE)
116                 r->r_relative = 1;
117
118         if (type & RELTYPE_COPY)
119                 r->r_copy = 1;
120
121         return 0;
122 }
123
124 /*
125  * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
126  * to the binder slot (which is at offset 0 of the PLT).
127  */
128 void
129 md_make_jmpslot(sp, offset, index)
130 jmpslot_t       *sp;
131 long            offset;
132 long            index;
133 {
134         /*
135          * i386 PC-relative "fixed point" is located right after the
136          * instruction it pertains to.
137          */
138         u_long  fudge = - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
139
140         sp->opcode = CALL;
141 #if 0
142         sp->addr =  fudge;
143 #else
144         sp->addr[0] = fudge & 0xffff;
145         sp->addr[1] = fudge >> 16;
146 #endif
147         sp->reloc_index = index;
148 }
149
150 /*
151  * Set up a "direct" transfer (ie. not through the run-time binder) from
152  * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
153  * and by `ld.so' after resolving the symbol.
154  * On the i386, we use the JMP instruction which is PC relative, so no
155  * further RRS relocations will be necessary for such a jmpslot.
156  */
157 void
158 md_fix_jmpslot(sp, offset, addr)
159 jmpslot_t       *sp;
160 long            offset;
161 u_long          addr;
162 {
163         u_long  fudge = addr - (sizeof(sp->opcode) + sizeof(sp->addr) + offset);
164
165         sp->opcode = JUMP;
166 #if 0
167         sp->addr = fudge;
168 #else
169         sp->addr[0] = fudge & 0xffff;
170         sp->addr[1] = fudge >> 16;
171 #endif
172         sp->reloc_index = 0;
173 }
174
175 /*
176  * Bind a jmpslot to its target address.  TARGET is where the jmpslot
177  * should jump to, and WHERE is a pointer to the jmpslot's address field.
178  * This is called by the dynamic linker when LD_BIND_NOW is set in the
179  * environment.
180  */
181 void
182 md_bind_jmpslot(target, where)
183 u_long target;
184 caddr_t where;
185 {
186         jmpslot_t       *sp =
187                 (jmpslot_t *) (where - offsetof(jmpslot_t, addr[0]));
188
189         md_fix_jmpslot(sp, (long) sp, target);
190 }
191
192 /*
193  * Update the relocation record for a RRS jmpslot.
194  */
195 void
196 md_make_jmpreloc(rp, r, type)
197 struct relocation_info  *rp, *r;
198 int                     type;
199 {
200         jmpslot_t       *sp;
201
202         /*
203          * Fix relocation address to point to the correct
204          * location within this jmpslot.
205          */
206         r->r_address += sizeof(sp->opcode);
207
208         /* Relocation size */
209         r->r_length = 2;
210
211         /* Set relocation type */
212         r->r_jmptable = 1;
213         if (type & RELTYPE_RELATIVE)
214                 r->r_relative = 1;
215
216 }
217
218 /*
219  * Set relocation type for a RRS GOT relocation.
220  */
221 void
222 md_make_gotreloc(rp, r, type)
223 struct relocation_info  *rp, *r;
224 int                     type;
225 {
226         r->r_baserel = 1;
227         if (type & RELTYPE_RELATIVE)
228                 r->r_relative = 1;
229
230         /* Relocation size */
231         r->r_length = 2;
232 }
233
234 /*
235  * Set relocation type for a RRS copy operation.
236  */
237 void
238 md_make_cpyreloc(rp, r)
239 struct relocation_info  *rp, *r;
240 {
241         /* Relocation size */
242         r->r_length = 2;
243
244         r->r_copy = 1;
245 }
246
247 void
248 md_set_breakpoint(where, savep)
249 long    where;
250 long    *savep;
251 {
252         *savep = *(long *)where;
253         *(char *)where = TRAP;
254 }
255
256 #ifndef RTLD
257
258 #ifdef __FreeBSD__
259 int     netzmagic;
260 #endif
261
262 /*
263  * Initialize (output) exec header such that useful values are
264  * obtained from subsequent N_*() macro evaluations.
265  */
266 void
267 md_init_header(hp, magic, flags)
268 struct exec     *hp;
269 int             magic, flags;
270 {
271 #ifdef NetBSD
272         if (oldmagic || magic == QMAGIC)
273                 hp->a_midmag = magic;
274         else
275                 N_SETMAGIC((*hp), magic, MID_I386, flags);
276 #endif
277 #ifdef __FreeBSD__
278         if (oldmagic)
279                 hp->a_midmag = magic;
280         else if (netzmagic)
281                 N_SETMAGIC_NET((*hp), magic, MID_I386, flags);
282         else
283                 N_SETMAGIC((*hp), magic, MID_I386, flags);
284 #endif
285
286         /* TEXT_START depends on the value of outheader.a_entry.  */
287         if (!(link_mode & SHAREABLE))
288                 hp->a_entry = PAGSIZ;
289 }
290 #endif /* RTLD */
291
292
293 #ifdef NEED_SWAP
294 /*
295  * Byte swap routines for cross-linking.
296  */
297
298 void
299 md_swapin_exec_hdr(h)
300 struct exec *h;
301 {
302         int skip = 0;
303
304         if (!N_BADMAG(*h))
305                 skip = 1;
306
307         swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
308 }
309
310 void
311 md_swapout_exec_hdr(h)
312 struct exec *h;
313 {
314         /* NetBSD: Always leave magic alone */
315         int skip = 1;
316 #if 0
317         if (N_GETMAGIC(*h) == OMAGIC)
318                 skip = 0;
319 #endif
320
321         swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
322 }
323
324
325 void
326 md_swapin_reloc(r, n)
327 struct relocation_info *r;
328 int n;
329 {
330         int     bits;
331
332         for (; n; n--, r++) {
333                 r->r_address = md_swap_long(r->r_address);
334                 bits = ((int *)r)[1];
335                 r->r_symbolnum = md_swap_long(bits) & 0x00ffffff;
336                 r->r_pcrel = (bits & 1);
337                 r->r_length = (bits >> 1) & 3;
338                 r->r_extern = (bits >> 3) & 1;
339                 r->r_baserel = (bits >> 4) & 1;
340                 r->r_jmptable = (bits >> 5) & 1;
341                 r->r_relative = (bits >> 6) & 1;
342 #ifdef N_SIZE
343                 r->r_copy = (bits >> 7) & 1;
344 #endif
345         }
346 }
347
348 void
349 md_swapout_reloc(r, n)
350 struct relocation_info *r;
351 int n;
352 {
353         int     bits;
354
355         for (; n; n--, r++) {
356                 r->r_address = md_swap_long(r->r_address);
357                 bits = md_swap_long(r->r_symbolnum) & 0xffffff00;
358                 bits |= (r->r_pcrel & 1);
359                 bits |= (r->r_length & 3) << 1;
360                 bits |= (r->r_extern & 1) << 3;
361                 bits |= (r->r_baserel & 1) << 4;
362                 bits |= (r->r_jmptable & 1) << 5;
363                 bits |= (r->r_relative & 1) << 6;
364 #ifdef N_SIZE
365                 bits |= (r->r_copy & 1) << 7;
366 #endif
367                 ((int *)r)[1] = bits;
368         }
369 }
370
371 void
372 md_swapout_jmpslot(j, n)
373 jmpslot_t       *j;
374 int             n;
375 {
376         for (; n; n--, j++) {
377                 j->opcode = md_swap_short(j->opcode);
378                 j->addr[0] = md_swap_short(j->addr[0]);
379                 j->addr[1] = md_swap_short(j->addr[1]);
380                 j->reloc_index = md_swap_short(j->reloc_index);
381         }
382 }
383
384 #endif /* NEED_SWAP */