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