/* $NetBSD: md.c,v 1.2 1996/08/21 18:43:29 mark Exp $ */ /* * Copyright (C) 1996 Wolfgang Solfrank * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Wolfgang Solfrank. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* First cut for arm32 (currently a simple copy of i386 code) */ #include #include #include #include #include #include #include #include #include #include "ld.h" /* * Get relocation addend corresponding to relocation record RP * from address ADDR */ long md_get_addend(rp, addr) struct relocation_info *rp; unsigned char *addr; { long rel; switch (rp->r_length) { case 0: rel = get_byte(addr); break; case 1: rel = get_short(addr); break; case 2: rel = get_long(addr); break; case 3: /* looks like a special hack for b & bl */ rel = (((long)get_long(addr) & 0xffffff) << 8) >> 6; rel -= rp->r_address; /* really? XXX */ break; default: errx(1, "Unsupported relocation size: %x", rp->r_length); } return rp->r_neg ? -rel : rel; /* Hack to make r_neg work */ } /* * Put RELOCATION at ADDR according to relocation record RP. */ static struct relocation_info *rrs_reloc; /* HACK HACK HACK XXX */ void md_relocate(rp, relocation, addr, relocatable_output) struct relocation_info *rp; long relocation; unsigned char *addr; int relocatable_output; { if (rp == rrs_reloc /* HACK HACK HACK XXX */ || (RELOC_PCREL_P(rp) && relocatable_output)) { rrs_reloc = NULL; return; } rrs_reloc = NULL; if (rp->r_neg) /* Not sure, whether this works in all cases XXX */ relocation = -relocation; switch (rp->r_length) { case 0: put_byte(addr, relocation); break; case 1: put_short(addr, relocation); break; case 2: put_long(addr, relocation); break; case 3: put_long(addr, (get_long(addr)&0xff000000) | ((relocation&0x3ffffff) >> 2)); break; default: errx(1, "Unsupported relocation size: %x", rp->r_length); } } #ifndef RTLD /* * Machine dependent part of claim_rrs_reloc(). * Set RRS relocation type. */ int md_make_reloc(rp, r, type) struct relocation_info *rp, *r; int type; { if (type == RELTYPE_EXTERN) rrs_reloc = rp; /* HACK HACK HACK XXX */ /* Copy most attributes */ r->r_pcrel = rp->r_pcrel; r->r_length = rp->r_length; r->r_neg = rp->r_neg; r->r_baserel = rp->r_baserel; r->r_jmptable = rp->r_jmptable; r->r_relative = rp->r_relative; return 0; } #endif /* RTLD */ /* * Set up a transfer from jmpslot at OFFSET (relative to the PLT table) * to the binder slot (which is at offset 0 of the PLT). */ void md_make_jmpslot(sp, offset, index) jmpslot_t *sp; long offset; long index; { u_long fudge = - (offset + 12); sp->opcode1 = SAVEPC; sp->opcode2 = CALL | ((fudge >> 2) & 0xffffff); sp->reloc_index = index; } /* * Set up a "direct" transfer (ie. not through the run-time binder) from * jmpslot at OFFSET to ADDR. Used by `ld' when the SYMBOLIC flag is on, * and by `ld.so' after resolving the symbol. */ void md_fix_jmpslot(sp, offset, addr) jmpslot_t *sp; long offset; u_long addr; { /* * Generate the following sequence: * ldr pc, [pc] * .word addr */ sp->opcode1 = JUMP; sp->reloc_index = addr; } /* * Update the relocation record for a RRS jmpslot. */ void md_make_jmpreloc(rp, r, type) struct relocation_info *rp, *r; int type; { r->r_address += 8; r->r_pcrel = 0; r->r_length = 2; r->r_neg = 0; r->r_baserel = 0; r->r_jmptable = 1; r->r_relative = 0; } /* * Set relocation type for a RRS GOT relocation. */ void md_make_gotreloc(rp, r, type) struct relocation_info *rp, *r; int type; { r->r_pcrel = 0; r->r_length = 2; r->r_neg = 0; r->r_baserel = 1; r->r_jmptable = 0; r->r_relative = 0; } /* * Set relocation type for a RRS copy operation. */ void md_make_cpyreloc(rp, r) struct relocation_info *rp, *r; { r->r_pcrel = 0; r->r_length = 2; r->r_neg = 0; r->r_baserel = 0; r->r_jmptable = 0; r->r_relative = 0; } void md_set_breakpoint(where, savep) long where; long *savep; { *savep = *(long *)where; *(long *)where = TRAP; } #ifndef RTLD /* * Initialize (output) exec header such that useful values are * obtained from subsequent N_*() macro evaluations. */ void md_init_header(hp, magic, flags) struct exec *hp; int magic, flags; { N_SETMAGIC((*hp), magic, MID_ARM6, flags); /* TEXT_START depends on the value of outheader.a_entry. */ if (!(link_mode & SHAREABLE)) hp->a_entry = PAGSIZ; } #endif /* RTLD */ #ifdef NEED_SWAP /* * Byte swap routines for cross-linking. */ void md_swapin_exec_hdr(h) struct exec *h; { /* NetBSD: Always leave magic alone */ int skip = 1; swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip); } void md_swapout_exec_hdr(h) struct exec *h; { /* NetBSD: Always leave magic alone */ int skip = 1; swap_longs((long *)h + skip, sizeof(*h)/sizeof(long) - skip); } void md_swapin_reloc(r, n) struct relocation_info *r; int n; { int bits; for (; n; n--, r++) { r->r_address = md_swap_long(r->r_address); bits = ((int *)r)[1]; r->r_symbolnum = md_swap_long(bits) & 0x00ffffff; r->r_pcrel = (bits & 1); r->r_length = (bits >> 1) & 3; r->r_extern = (bits >> 3) & 1; r->r_neg = (bits >> 4) & 1; r->r_baserel = (bits >> 5) & 1; r->r_jmptable = (bits >> 6) & 1; r->r_relative = (bits >> 7) & 1; } } void md_swapout_reloc(r, n) struct relocation_info *r; int n; { int bits; for (; n; n--, r++) { r->r_address = md_swap_long(r->r_address); bits = md_swap_long(r->r_symbolnum) & 0xffffff00; bits |= (r->r_pcrel & 1); bits |= (r->r_length & 3) << 1; bits |= (r->r_extern & 1) << 3; bits |= (r->r_neg & 1) << 4; bits |= (r->r_baserel & 1) << 5; bits |= (r->r_jmptable & 1) << 6; bits |= (r->r_relative & 1) << 7; ((int *)r)[1] = bits; } } void md_swapout_jmpslot(j, n) jmpslot_t *j; int n; { for (; n; n--, j++) { j->opcode1 = md_swap_long(j->opcode1); j->opcode2 = md_swap_long(j->opcode2); j->reloc_index = md_swap_long(j->reloc_index); } } #endif /* NEED_SWAP */