No empty .Rs/.Re
[netbsd-mini2440.git] / libexec / ld.aout_so / arch / arm32 / md.c
blob828818d10952beb76ddebda2c4f2cd9c83bce9df
1 /* $NetBSD: md.c,v 1.11 1999/02/27 03:34:05 tv Exp $ */
3 /*
4 * Copyright (C) 1997 Mark Brinicombe
5 * Copyright (C) 1997 Causality Limited
6 * Copyright (C) 1996 Wolfgang Solfrank
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Wolfgang Solfrank.
19 * This product includes software developed by Causality Limited.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 /* Second cut for arm32 (used to be a simple copy of i386 code) */
38 #include <sys/param.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <sys/types.h>
42 #include <err.h>
43 #include <fcntl.h>
44 #include <a.out.h>
45 #include <stab.h>
46 #include <string.h>
47 #ifdef RTLD
48 #include <machine/sysarch.h>
49 #include <sys/syscall.h>
50 #endif /* RTLD */
52 #include "ld.h"
53 #ifndef RTLD
54 /* Pull in the ld(1) bits as well */
55 #include "ld_i.h"
56 #endif
58 #ifdef RTLD
59 inline void iflush __P((void *addr, int len));
62 * Flush the instruction cache of the specified address
63 * Some processors have separate instruction caches and
64 * as such may need a flush following a jump slot fixup.
66 inline void
67 iflush(addr, len)
68 void *addr;
69 int len;
71 struct arm32_sync_icache_args p;
74 * This is not an efficient way to flush a chunk of memory
75 * if we need to flush lots of small chunks i.e. a jmpslot
76 * per function call.
78 p.addr = (u_int)addr;
79 p.len = len;
81 __asm volatile("mov r0, %0; mov r1, %1; swi %2"
82 : : "I" (ARM32_SYNC_ICACHE), "r" (&p), "J" (SYS_sysarch));
84 #endif /* RTLD */
88 * Get relocation addend corresponding to relocation record RP
89 * from address ADDR
91 long
92 md_get_addend(rp, addr)
93 struct relocation_info *rp;
94 unsigned char *addr;
96 long rel;
98 switch (rp->r_length) {
99 case 0:
100 rel = get_byte(addr);
101 break;
102 case 1:
103 rel = get_short(addr);
104 break;
105 case 2:
106 rel = get_long(addr);
107 break;
108 case 3: /* looks like a special hack for b & bl */
109 rel = (((long)get_long(addr) & 0xffffff) << 8) >> 6;
111 * XXX
112 * Address the addend to be relative to the start of the file
113 * The implecation of doing this is that this adjustment is
114 * done every time the reloc goes through ld.
115 * This means that the adjustment can be applied multiple
116 * times if ld -r is used to do a partial link.
118 * Solution:
119 * 1. Put a hack in md_relocate so that PC relative
120 * relocations are not modified if
121 * relocatable_output == 1
122 * 2. Modify the assembler to apply this adjustment.
124 rel -= rp->r_address;
125 break;
126 default:
127 errx(1, "Unsupported relocation size: %x",
128 rp->r_length);
130 return rp->r_neg ? -rel : rel; /* Hack to make r_neg work */
134 * Put RELOCATION at ADDR according to relocation record RP.
136 void
137 md_relocate(rp, relocation, addr, relocatable_output)
138 struct relocation_info *rp;
139 long relocation;
140 unsigned char *addr;
141 int relocatable_output;
144 * XXX
145 * See comments above in md_get_addend
147 #ifndef RTLD
148 if (RELOC_PCREL_P(rp) && relocatable_output)
149 relocation += (rp->r_address + pc_relocation);
150 if (rp->r_pcrel && rp->r_length == 2 && relocatable_output)
151 relocation -= rp->r_address;
152 #endif
154 if (rp->r_neg) /* Not sure, whether this works in all cases XXX */
155 relocation = -relocation;
157 switch (rp->r_length) {
158 case 0:
159 put_byte(addr, relocation);
160 break;
161 case 1:
162 put_short(addr, relocation);
163 break;
164 case 2:
165 put_long(addr, relocation);
166 break;
167 case 3:
168 put_long(addr,
169 (get_long(addr)&0xff000000)
170 | ((relocation>>2)&0xffffff));
171 break;
172 default:
173 errx(1, "Unsupported relocation size: %x",
174 rp->r_length);
179 * Set up a "direct" transfer (ie. not through the run-time binder) from
180 * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on,
181 * and by `ld.so' after resolving the symbol.
184 #ifdef RTLD
185 extern void binder_entry __P((void));
186 #endif
188 void
189 md_fix_jmpslot(sp, offset, addr, first)
190 jmpslot_t *sp;
191 long offset;
192 u_long addr;
193 int first;
196 * For jmpslot 0 (the binder)
197 * generate
198 * sub ip, pc, ip
199 * ldr pc, [pc, #-4]
200 * .word addr
201 * <unused>
203 * For jump slots generated by the linker (i.e. -Bsymbolic)
204 * build a direct jump to the absolute address
205 * i.e.
206 * ldr pc, [pc]
207 * <unused>
208 * .word new_addr
209 * <unused>
211 * For jump slots generated by ld.so at run time,
212 * just modify the address offset since the slot
213 * will have been created with md_make_jmpslot().
214 * i.e.
215 * ldr ip, [pc]
216 * add pc, pc, ip
217 * .word new_rel_addr
218 * <unused>
220 if (first) {
221 /* Build binder jump slot */
222 sp->opcode1 = GETSLOTADDR;
223 sp->opcode2 = LDRPCADDR;
224 sp->address = addr;
225 #ifdef RTLD
226 iflush(sp, sizeof(jmpslot_t));
227 #endif /* RTLD */
228 } else {
229 #ifdef RTLD
231 * Change the relative offset to the binder
232 * into a relative offset to the function
234 sp->address = (addr - (long)sp - 12);
235 #else
237 * Build a direct transfer jump slot
238 * as we not doing a run time fixup.
240 sp->opcode1 = JUMP;
241 sp->address = addr;
242 #endif /* RTLD */
246 void
247 md_set_breakpoint(where, savep)
248 long where;
249 long *savep;
251 *savep = *(long *)where;
252 *(long *)where = TRAP;
253 #ifdef RTLD
254 iflush((long *)where, sizeof(long));
255 #endif /* RTLD */
259 #ifndef RTLD
261 * Machine dependent part of claim_rrs_reloc().
262 * Set RRS relocation type.
265 md_make_reloc(rp, r, type)
266 struct relocation_info *rp, *r;
267 int type;
269 /* Copy most attributes */
270 r->r_pcrel = rp->r_pcrel;
271 r->r_length = rp->r_length;
272 r->r_neg = rp->r_neg;
273 r->r_baserel = rp->r_baserel;
274 r->r_jmptable = rp->r_jmptable;
275 r->r_relative = rp->r_relative;
277 return 0;
281 * Set up a transfer from jmpslot at OFFSET (relative to the PLT table)
282 * to the binder slot (which is at offset 0 of the PLT).
284 void
285 md_make_jmpslot(sp, offset, index)
286 jmpslot_t *sp;
287 long offset;
288 long index;
291 * Build the jump slot as follows
293 * ldr ip, [pc]
294 * add pc, pc, ip
295 * .word rel_addr
296 * .word reloc_index
298 sp->opcode1 = GETRELADDR;
299 sp->opcode2 = ADDPC;
300 sp->address = - (offset + 12);
301 sp->reloc_index = index;
306 * Update the relocation record for a RRS jmpslot.
308 void
309 md_make_jmpreloc(rp, r, type)
310 struct relocation_info *rp, *r;
311 int type;
313 r->r_address += 8;
314 r->r_pcrel = 0;
315 r->r_length = 2;
316 r->r_neg = 0;
317 r->r_baserel = 0;
318 r->r_jmptable = 1;
319 r->r_relative = 0;
323 * Set relocation type for a RRS GOT relocation.
325 void
326 md_make_gotreloc(rp, r, type)
327 struct relocation_info *rp, *r;
328 int type;
330 r->r_pcrel = 0;
331 r->r_length = 2;
332 r->r_neg = 0;
333 r->r_baserel = 1;
334 r->r_jmptable = 0;
335 r->r_relative = 0;
340 * Set relocation type for a RRS copy operation.
342 void
343 md_make_cpyreloc(rp, r)
344 struct relocation_info *rp, *r;
346 r->r_pcrel = 0;
347 r->r_length = 2;
348 r->r_neg = 0;
349 r->r_baserel = 0;
350 r->r_jmptable = 0;
351 r->r_relative = 0;
355 * Initialize (output) exec header such that useful values are
356 * obtained from subsequent N_*() macro evaluations.
358 void
359 md_init_header(hp, magic, flags)
360 struct exec *hp;
361 int magic, flags;
363 N_SETMAGIC((*hp), magic, MID_ARM6, flags);
365 /* TEXT_START depends on the value of outheader.a_entry. */
366 if (!(link_mode & SHAREABLE))
367 hp->a_entry = PAGSIZ;
369 #endif /* RTLD */
372 #ifdef NEED_SWAP
374 * Byte swap routines for cross-linking.
377 void
378 md_swapin_exec_hdr(h)
379 struct exec *h;
381 /* NetBSD: Always leave magic alone */
382 int skip = 1;
384 swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
387 void
388 md_swapout_exec_hdr(h)
389 struct exec *h;
391 /* NetBSD: Always leave magic alone */
392 int skip = 1;
394 swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip);
397 void
398 md_swapout_jmpslot(j, n)
399 jmpslot_t *j;
400 int n;
402 for (; n; n--, j++) {
403 j->opcode1 = md_swap_long(j->opcode1);
404 j->opcode2 = md_swap_long(j->opcode2);
405 j->address = md_swap_long(j->address);
406 j->reloc_index = md_swap_long(j->reloc_index);
410 #endif /* NEED_SWAP */
413 * md_swapin_reloc()
415 * As well as provide bit swapping for cross compiling with different
416 * endianness we need to munge some of the reloc bits.
417 * This munging is due to the assemble packing all the PIC related
418 * relocs so that only 1 extra bit in the reloc structure is needed
419 * The result is that jmpslot branches are packed as a baserel branch
420 * Spot this case and internally use a jmptable bit.
423 void
424 md_swapin_reloc(r, n)
425 struct relocation_info *r;
426 int n;
428 #ifdef NEED_SWAP
429 int bits;
430 #endif
432 for (; n; n--, r++) {
433 #ifdef NEED_SWAP
434 r->r_address = md_swap_long(r->r_address);
435 bits = ((int *)r)[1];
436 r->r_symbolnum = md_swap_long(bits) & 0x00ffffff;
437 r->r_pcrel = (bits & 1);
438 r->r_length = (bits >> 1) & 3;
439 r->r_extern = (bits >> 3) & 1;
440 r->r_neg = (bits >> 4) & 1;
441 r->r_baserel = (bits >> 5) & 1;
442 r->r_jmptable = (bits >> 6) & 1;
443 r->r_relative = (bits >> 7) & 1;
444 #endif
445 /* Look for PIC relocation */
446 if (r->r_baserel) {
447 /* Look for baserel branch */
448 if (r->r_length == 3 && r->r_pcrel == 0) {
449 r->r_jmptable = 1;
451 /* Look for GOTPC reloc */
452 if (r->r_length == 2 && r->r_pcrel == 1)
453 r->r_baserel = 0;
458 void
459 md_swapout_reloc(r, n)
460 struct relocation_info *r;
461 int n;
463 #ifdef NEED_SWAP
464 int bits;
465 #endif
467 for (; n; n--, r++) {
468 /* Look for jmptable relocation */
469 if (r->r_jmptable && r->r_pcrel == 0 && r->r_length == 3) {
470 r->r_jmptable = 0;
471 r->r_baserel = 1;
473 #ifdef NEED_SWAP
474 r->r_address = md_swap_long(r->r_address);
475 bits = md_swap_long(r->r_symbolnum) & 0xffffff00;
476 bits |= (r->r_pcrel & 1);
477 bits |= (r->r_length & 3) << 1;
478 bits |= (r->r_extern & 1) << 3;
479 bits |= (r->r_neg & 1) << 4;
480 bits |= (r->r_baserel & 1) << 5;
481 bits |= (r->r_jmptable & 1) << 6;
482 bits |= (r->r_relative & 1) << 7;
483 ((int *)r)[1] = bits;
484 #endif