1 /* $NetBSD: md.c,v 1.11 1999/02/27 03:34:05 tv Exp $ */
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
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>
41 #include <sys/types.h>
48 #include <machine/sysarch.h>
49 #include <sys/syscall.h>
54 /* Pull in the ld(1) bits as well */
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.
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
81 __asm
volatile("mov r0, %0; mov r1, %1; swi %2"
82 : : "I" (ARM32_SYNC_ICACHE
), "r" (&p
), "J" (SYS_sysarch
));
88 * Get relocation addend corresponding to relocation record RP
92 md_get_addend(rp
, addr
)
93 struct relocation_info
*rp
;
98 switch (rp
->r_length
) {
100 rel
= get_byte(addr
);
103 rel
= get_short(addr
);
106 rel
= get_long(addr
);
108 case 3: /* looks like a special hack for b & bl */
109 rel
= (((long)get_long(addr
) & 0xffffff) << 8) >> 6;
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.
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
;
127 errx(1, "Unsupported relocation size: %x",
130 return rp
->r_neg
? -rel
: rel
; /* Hack to make r_neg work */
134 * Put RELOCATION at ADDR according to relocation record RP.
137 md_relocate(rp
, relocation
, addr
, relocatable_output
)
138 struct relocation_info
*rp
;
141 int relocatable_output
;
145 * See comments above in md_get_addend
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
;
154 if (rp
->r_neg
) /* Not sure, whether this works in all cases XXX */
155 relocation
= -relocation
;
157 switch (rp
->r_length
) {
159 put_byte(addr
, relocation
);
162 put_short(addr
, relocation
);
165 put_long(addr
, relocation
);
169 (get_long(addr
)&0xff000000)
170 | ((relocation
>>2)&0xffffff));
173 errx(1, "Unsupported relocation size: %x",
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.
185 extern void binder_entry
__P((void));
189 md_fix_jmpslot(sp
, offset
, addr
, first
)
196 * For jmpslot 0 (the binder)
203 * For jump slots generated by the linker (i.e. -Bsymbolic)
204 * build a direct jump to the absolute address
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().
221 /* Build binder jump slot */
222 sp
->opcode1
= GETSLOTADDR
;
223 sp
->opcode2
= LDRPCADDR
;
226 iflush(sp
, sizeof(jmpslot_t
));
231 * Change the relative offset to the binder
232 * into a relative offset to the function
234 sp
->address
= (addr
- (long)sp
- 12);
237 * Build a direct transfer jump slot
238 * as we not doing a run time fixup.
247 md_set_breakpoint(where
, savep
)
251 *savep
= *(long *)where
;
252 *(long *)where
= TRAP
;
254 iflush((long *)where
, sizeof(long));
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
;
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
;
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).
285 md_make_jmpslot(sp
, offset
, index
)
291 * Build the jump slot as follows
298 sp
->opcode1
= GETRELADDR
;
300 sp
->address
= - (offset
+ 12);
301 sp
->reloc_index
= index
;
306 * Update the relocation record for a RRS jmpslot.
309 md_make_jmpreloc(rp
, r
, type
)
310 struct relocation_info
*rp
, *r
;
323 * Set relocation type for a RRS GOT relocation.
326 md_make_gotreloc(rp
, r
, type
)
327 struct relocation_info
*rp
, *r
;
340 * Set relocation type for a RRS copy operation.
343 md_make_cpyreloc(rp
, r
)
344 struct relocation_info
*rp
, *r
;
355 * Initialize (output) exec header such that useful values are
356 * obtained from subsequent N_*() macro evaluations.
359 md_init_header(hp
, 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
;
374 * Byte swap routines for cross-linking.
378 md_swapin_exec_hdr(h
)
381 /* NetBSD: Always leave magic alone */
384 swap_longs((long *)h
+ skip
, sizeof(*h
)/sizeof(long) - skip
);
388 md_swapout_exec_hdr(h
)
391 /* NetBSD: Always leave magic alone */
394 swap_longs((long *)h
+ skip
, sizeof(*h
)/sizeof(long) - skip
);
398 md_swapout_jmpslot(j
, 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 */
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.
424 md_swapin_reloc(r
, n
)
425 struct relocation_info
*r
;
432 for (; n
; n
--, r
++) {
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;
445 /* Look for PIC relocation */
447 /* Look for baserel branch */
448 if (r
->r_length
== 3 && r
->r_pcrel
== 0) {
451 /* Look for GOTPC reloc */
452 if (r
->r_length
== 2 && r
->r_pcrel
== 1)
459 md_swapout_reloc(r
, n
)
460 struct relocation_info
*r
;
467 for (; n
; n
--, r
++) {
468 /* Look for jmptable relocation */
469 if (r
->r_jmptable
&& r
->r_pcrel
== 0 && r
->r_length
== 3) {
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
;