1134458Siedowse/*- 2134458Siedowse * Copyright (c) 2003 Jake Burkholder. 3134458Siedowse * Copyright 1996-1998 John D. Polstra. 4134458Siedowse * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 5134458Siedowse * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 6134458Siedowse * All rights reserved. 7134458Siedowse * 8134458Siedowse * Redistribution and use in source and binary forms, with or without 9134458Siedowse * modification, are permitted provided that the following conditions 10134458Siedowse * are met: 11134458Siedowse * 1. Redistributions of source code must retain the above copyright 12134458Siedowse * notice, this list of conditions and the following disclaimer. 13134458Siedowse * 2. Redistributions in binary form must reproduce the above copyright 14134458Siedowse * notice, this list of conditions and the following disclaimer in the 15134458Siedowse * documentation and/or other materials provided with the distribution. 16134458Siedowse * 17134458Siedowse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18134458Siedowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19134458Siedowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20134458Siedowse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21134458Siedowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22134458Siedowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23134458Siedowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24134458Siedowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25134458Siedowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26134458Siedowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27134458Siedowse * SUCH DAMAGE. 28134458Siedowse */ 29134458Siedowse 30134458Siedowse#include <sys/cdefs.h> 31134458Siedowse__FBSDID("$FreeBSD$"); 32134458Siedowse 33134458Siedowse#include <sys/types.h> 34134458Siedowse#include <machine/elf.h> 35134458Siedowse 36134458Siedowse#include <errno.h> 37134458Siedowse#include <stand.h> 38134458Siedowse 39134458Siedowse#define FREEBSD_ELF 40134458Siedowse#include <link.h> 41134458Siedowse 42134458Siedowse#include "bootstrap.h" 43134458Siedowse 44134458Siedowse#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 45134458Siedowse 46134458Siedowse/* 47134458Siedowse * Apply a single intra-module relocation to the data. `relbase' is the 48134458Siedowse * target relocation base for the section (i.e. it corresponds to where 49134458Siedowse * r_offset == 0). `dataaddr' is the relocated address corresponding to 50134458Siedowse * the start of the data, and `len' is the number of bytes. 51134458Siedowse */ 52134458Siedowseint 53134458Siedowse__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, 54134458Siedowse int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) 55134458Siedowse{ 56134458Siedowse#ifdef __sparc__ 57153504Smarcel Elf_Size w; 58134458Siedowse const Elf_Rela *a; 59134458Siedowse 60134458Siedowse switch (reltype) { 61134458Siedowse case ELF_RELOC_RELA: 62134458Siedowse a = reldata; 63134458Siedowse if (relbase + a->r_offset >= dataaddr && 64134458Siedowse relbase + a->r_offset < dataaddr + len) { 65134458Siedowse switch (ELF_R_TYPE(a->r_info)) { 66134458Siedowse case R_SPARC_RELATIVE: 67134458Siedowse w = relbase + a->r_addend; 68134458Siedowse bcopy(&w, (u_char *)data + (relbase + 69134458Siedowse a->r_offset - dataaddr), sizeof(w)); 70134458Siedowse break; 71134458Siedowse default: 72134458Siedowse printf("\nunhandled relocation type %u\n", 73134458Siedowse (u_int)ELF_R_TYPE(a->r_info)); 74134458Siedowse return (EFTYPE); 75134458Siedowse } 76134458Siedowse } 77134458Siedowse break; 78134458Siedowse } 79134458Siedowse 80134458Siedowse return (0); 81223695Sdfr#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 82134458Siedowse Elf64_Addr *where, val; 83134458Siedowse Elf_Addr addend, addr; 84153504Smarcel Elf_Size rtype, symidx; 85134458Siedowse const Elf_Rel *rel; 86134458Siedowse const Elf_Rela *rela; 87134458Siedowse 88134458Siedowse switch (reltype) { 89134458Siedowse case ELF_RELOC_REL: 90134458Siedowse rel = (const Elf_Rel *)reldata; 91134458Siedowse where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 92134458Siedowse dataaddr); 93134458Siedowse addend = 0; 94134458Siedowse rtype = ELF_R_TYPE(rel->r_info); 95134458Siedowse symidx = ELF_R_SYM(rel->r_info); 96134458Siedowse addend = 0; 97134458Siedowse break; 98134458Siedowse case ELF_RELOC_RELA: 99134458Siedowse rela = (const Elf_Rela *)reldata; 100134458Siedowse where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 101134458Siedowse dataaddr); 102134458Siedowse addend = rela->r_addend; 103134458Siedowse rtype = ELF_R_TYPE(rela->r_info); 104134458Siedowse symidx = ELF_R_SYM(rela->r_info); 105134458Siedowse break; 106134458Siedowse default: 107134458Siedowse return (EINVAL); 108134458Siedowse } 109134458Siedowse 110134458Siedowse if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 111134458Siedowse return (0); 112134458Siedowse 113134458Siedowse if (reltype == ELF_RELOC_REL) 114134458Siedowse addend = *where; 115134458Siedowse 116134458Siedowse/* XXX, definitions not available on i386. */ 117134458Siedowse#define R_X86_64_64 1 118134458Siedowse#define R_X86_64_RELATIVE 8 119134458Siedowse 120134458Siedowse switch (rtype) { 121134458Siedowse case R_X86_64_64: /* S + A */ 122134458Siedowse addr = symaddr(ef, symidx); 123134458Siedowse if (addr == 0) 124134458Siedowse return (ESRCH); 125134458Siedowse val = addr + addend; 126134458Siedowse *where = val; 127134458Siedowse break; 128134458Siedowse case R_X86_64_RELATIVE: 129134458Siedowse addr = (Elf_Addr)addend + relbase; 130134458Siedowse val = addr; 131134458Siedowse *where = val; 132134458Siedowse break; 133134458Siedowse default: 134134458Siedowse printf("\nunhandled relocation type %u\n", (u_int)rtype); 135134458Siedowse return (EFTYPE); 136134458Siedowse } 137134458Siedowse 138134458Siedowse return (0); 139134458Siedowse#elif defined(__i386__) && __ELF_WORD_SIZE == 32 140134458Siedowse Elf_Addr addend, addr, *where, val; 141153504Smarcel Elf_Size rtype, symidx; 142134458Siedowse const Elf_Rel *rel; 143134458Siedowse const Elf_Rela *rela; 144134458Siedowse 145134458Siedowse switch (reltype) { 146134458Siedowse case ELF_RELOC_REL: 147134458Siedowse rel = (const Elf_Rel *)reldata; 148134458Siedowse where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 149134458Siedowse dataaddr); 150134458Siedowse addend = 0; 151134458Siedowse rtype = ELF_R_TYPE(rel->r_info); 152134458Siedowse symidx = ELF_R_SYM(rel->r_info); 153134458Siedowse addend = 0; 154134458Siedowse break; 155134458Siedowse case ELF_RELOC_RELA: 156134458Siedowse rela = (const Elf_Rela *)reldata; 157134458Siedowse where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 158134458Siedowse dataaddr); 159134458Siedowse addend = rela->r_addend; 160134458Siedowse rtype = ELF_R_TYPE(rela->r_info); 161134458Siedowse symidx = ELF_R_SYM(rela->r_info); 162134458Siedowse break; 163134458Siedowse default: 164134458Siedowse return (EINVAL); 165134458Siedowse } 166134458Siedowse 167134458Siedowse if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 168134458Siedowse return (0); 169134458Siedowse 170134458Siedowse if (reltype == ELF_RELOC_REL) 171134458Siedowse addend = *where; 172134458Siedowse 173134458Siedowse/* XXX, definitions not available on amd64. */ 174134458Siedowse#define R_386_32 1 /* Add symbol value. */ 175134458Siedowse#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ 176134458Siedowse#define R_386_RELATIVE 8 /* Add load address of shared object. */ 177134458Siedowse 178134458Siedowse switch (rtype) { 179134458Siedowse case R_386_RELATIVE: 180134458Siedowse addr = addend + relbase; 181134458Siedowse *where = addr; 182134458Siedowse break; 183134458Siedowse case R_386_32: /* S + A */ 184134458Siedowse addr = symaddr(ef, symidx); 185134458Siedowse if (addr == 0) 186134458Siedowse return (ESRCH); 187134458Siedowse val = addr + addend; 188134458Siedowse *where = val; 189134458Siedowse break; 190134458Siedowse default: 191134458Siedowse printf("\nunhandled relocation type %u\n", (u_int)rtype); 192134458Siedowse return (EFTYPE); 193134458Siedowse } 194134458Siedowse 195134458Siedowse return (0); 196240782Sandreast#elif defined(__powerpc__) 197240782Sandreast Elf_Size w; 198240782Sandreast const Elf_Rela *rela; 199240782Sandreast 200240782Sandreast switch (reltype) { 201240782Sandreast case ELF_RELOC_RELA: 202240782Sandreast rela = reldata; 203240782Sandreast if (relbase + rela->r_offset >= dataaddr && 204240782Sandreast relbase + rela->r_offset < dataaddr + len) { 205240782Sandreast switch (ELF_R_TYPE(rela->r_info)) { 206240782Sandreast case R_PPC_RELATIVE: 207240782Sandreast w = relbase + rela->r_addend; 208240782Sandreast bcopy(&w, (u_char *)data + (relbase + 209240782Sandreast rela->r_offset - dataaddr), sizeof(w)); 210240782Sandreast break; 211240782Sandreast default: 212240782Sandreast printf("\nunhandled relocation type %u\n", 213240782Sandreast (u_int)ELF_R_TYPE(rela->r_info)); 214240782Sandreast return (EFTYPE); 215240782Sandreast } 216240782Sandreast } 217240782Sandreast break; 218240782Sandreast } 219240782Sandreast 220240782Sandreast return (0); 221134458Siedowse#else 222134458Siedowse return (EOPNOTSUPP); 223134458Siedowse#endif 224134458Siedowse} 225