reloc_elf.c revision 223695
1219393Sadrian/*- 2219393Sadrian * Copyright (c) 2003 Jake Burkholder. 3219393Sadrian * Copyright 1996-1998 John D. Polstra. 4219393Sadrian * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 5219393Sadrian * Copyright (c) 1998 Peter Wemm <peter@freebsd.org> 6219393Sadrian * All rights reserved. 7219393Sadrian * 8219393Sadrian * Redistribution and use in source and binary forms, with or without 9219393Sadrian * modification, are permitted provided that the following conditions 10219393Sadrian * are met: 11219393Sadrian * 1. Redistributions of source code must retain the above copyright 12219393Sadrian * notice, this list of conditions and the following disclaimer. 13219393Sadrian * 2. Redistributions in binary form must reproduce the above copyright 14219393Sadrian * notice, this list of conditions and the following disclaimer in the 15219393Sadrian * documentation and/or other materials provided with the distribution. 16219393Sadrian * 17219393Sadrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219393Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219393Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219393Sadrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219393Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219393Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219393Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219393Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219393Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219393Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219393Sadrian * SUCH DAMAGE. 28219393Sadrian */ 29219393Sadrian 30219393Sadrian#include <sys/cdefs.h> 31219393Sadrian__FBSDID("$FreeBSD: head/sys/boot/common/reloc_elf.c 223695 2011-06-30 16:08:56Z dfr $"); 32219393Sadrian 33219393Sadrian#include <sys/types.h> 34219393Sadrian#include <machine/elf.h> 35219393Sadrian 36219393Sadrian#include <errno.h> 37219393Sadrian#include <stand.h> 38219393Sadrian 39219393Sadrian#define FREEBSD_ELF 40219393Sadrian#include <link.h> 41219393Sadrian 42219393Sadrian#include "bootstrap.h" 43219393Sadrian 44219393Sadrian#define COPYOUT(s,d,l) archsw.arch_copyout((vm_offset_t)(s), d, l) 45219393Sadrian 46219393Sadrian/* 47219393Sadrian * Apply a single intra-module relocation to the data. `relbase' is the 48219393Sadrian * target relocation base for the section (i.e. it corresponds to where 49219393Sadrian * r_offset == 0). `dataaddr' is the relocated address corresponding to 50219393Sadrian * the start of the data, and `len' is the number of bytes. 51219393Sadrian */ 52219393Sadrianint 53219393Sadrian__elfN(reloc)(struct elf_file *ef, symaddr_fn *symaddr, const void *reldata, 54219393Sadrian int reltype, Elf_Addr relbase, Elf_Addr dataaddr, void *data, size_t len) 55219393Sadrian{ 56219393Sadrian#ifdef __sparc__ 57219393Sadrian Elf_Size w; 58219393Sadrian const Elf_Rela *a; 59219393Sadrian 60219393Sadrian switch (reltype) { 61219393Sadrian case ELF_RELOC_RELA: 62219393Sadrian a = reldata; 63219393Sadrian if (relbase + a->r_offset >= dataaddr && 64219393Sadrian relbase + a->r_offset < dataaddr + len) { 65219393Sadrian switch (ELF_R_TYPE(a->r_info)) { 66219393Sadrian case R_SPARC_RELATIVE: 67219393Sadrian w = relbase + a->r_addend; 68219393Sadrian bcopy(&w, (u_char *)data + (relbase + 69219393Sadrian a->r_offset - dataaddr), sizeof(w)); 70219393Sadrian break; 71219393Sadrian default: 72219393Sadrian printf("\nunhandled relocation type %u\n", 73219393Sadrian (u_int)ELF_R_TYPE(a->r_info)); 74219393Sadrian return (EFTYPE); 75219393Sadrian } 76219393Sadrian } 77219393Sadrian break; 78219393Sadrian } 79219393Sadrian 80219393Sadrian return (0); 81219393Sadrian#elif (defined(__i386__) || defined(__amd64__)) && __ELF_WORD_SIZE == 64 82219393Sadrian Elf64_Addr *where, val; 83219393Sadrian Elf_Addr addend, addr; 84219393Sadrian Elf_Size rtype, symidx; 85219393Sadrian const Elf_Rel *rel; 86219393Sadrian const Elf_Rela *rela; 87219393Sadrian 88219393Sadrian switch (reltype) { 89219393Sadrian case ELF_RELOC_REL: 90219393Sadrian rel = (const Elf_Rel *)reldata; 91219393Sadrian where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 92219393Sadrian dataaddr); 93219393Sadrian addend = 0; 94219393Sadrian rtype = ELF_R_TYPE(rel->r_info); 95219393Sadrian symidx = ELF_R_SYM(rel->r_info); 96219393Sadrian addend = 0; 97219393Sadrian break; 98219393Sadrian case ELF_RELOC_RELA: 99219393Sadrian rela = (const Elf_Rela *)reldata; 100219393Sadrian where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 101219393Sadrian dataaddr); 102219393Sadrian addend = rela->r_addend; 103219393Sadrian rtype = ELF_R_TYPE(rela->r_info); 104219393Sadrian symidx = ELF_R_SYM(rela->r_info); 105219393Sadrian break; 106219393Sadrian default: 107219393Sadrian return (EINVAL); 108219393Sadrian } 109219393Sadrian 110219393Sadrian if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 111219393Sadrian return (0); 112219393Sadrian 113219393Sadrian if (reltype == ELF_RELOC_REL) 114219393Sadrian addend = *where; 115219393Sadrian 116219393Sadrian/* XXX, definitions not available on i386. */ 117219393Sadrian#define R_X86_64_64 1 118219393Sadrian#define R_X86_64_RELATIVE 8 119219393Sadrian 120219393Sadrian switch (rtype) { 121219393Sadrian case R_X86_64_64: /* S + A */ 122219393Sadrian addr = symaddr(ef, symidx); 123219393Sadrian if (addr == 0) 124219393Sadrian return (ESRCH); 125219393Sadrian val = addr + addend; 126219393Sadrian *where = val; 127219393Sadrian break; 128219393Sadrian case R_X86_64_RELATIVE: 129219393Sadrian addr = (Elf_Addr)addend + relbase; 130219393Sadrian val = addr; 131219393Sadrian *where = val; 132219393Sadrian break; 133219393Sadrian default: 134219393Sadrian printf("\nunhandled relocation type %u\n", (u_int)rtype); 135219393Sadrian return (EFTYPE); 136219393Sadrian } 137219393Sadrian 138219393Sadrian return (0); 139219393Sadrian#elif defined(__i386__) && __ELF_WORD_SIZE == 32 140219393Sadrian Elf_Addr addend, addr, *where, val; 141219393Sadrian Elf_Size rtype, symidx; 142219393Sadrian const Elf_Rel *rel; 143219393Sadrian const Elf_Rela *rela; 144219393Sadrian 145219393Sadrian switch (reltype) { 146219393Sadrian case ELF_RELOC_REL: 147219393Sadrian rel = (const Elf_Rel *)reldata; 148219393Sadrian where = (Elf_Addr *)((char *)data + relbase + rel->r_offset - 149219393Sadrian dataaddr); 150219393Sadrian addend = 0; 151219393Sadrian rtype = ELF_R_TYPE(rel->r_info); 152219393Sadrian symidx = ELF_R_SYM(rel->r_info); 153219393Sadrian addend = 0; 154219393Sadrian break; 155219393Sadrian case ELF_RELOC_RELA: 156219393Sadrian rela = (const Elf_Rela *)reldata; 157219393Sadrian where = (Elf_Addr *)((char *)data + relbase + rela->r_offset - 158219393Sadrian dataaddr); 159219393Sadrian addend = rela->r_addend; 160219393Sadrian rtype = ELF_R_TYPE(rela->r_info); 161219393Sadrian symidx = ELF_R_SYM(rela->r_info); 162219393Sadrian break; 163219444Sadrian default: 164219444Sadrian return (EINVAL); 165219444Sadrian } 166219444Sadrian 167219444Sadrian if ((char *)where < (char *)data || (char *)where >= (char *)data + len) 168219444Sadrian return (0); 169219444Sadrian 170219444Sadrian if (reltype == ELF_RELOC_REL) 171219444Sadrian addend = *where; 172219444Sadrian 173219444Sadrian/* XXX, definitions not available on amd64. */ 174219444Sadrian#define R_386_32 1 /* Add symbol value. */ 175219444Sadrian#define R_386_GLOB_DAT 6 /* Set GOT entry to data address. */ 176219444Sadrian#define R_386_RELATIVE 8 /* Add load address of shared object. */ 177219444Sadrian 178219444Sadrian switch (rtype) { 179219444Sadrian case R_386_RELATIVE: 180219444Sadrian addr = addend + relbase; 181219444Sadrian *where = addr; 182219444Sadrian break; 183219444Sadrian case R_386_32: /* S + A */ 184219444Sadrian addr = symaddr(ef, symidx); 185219444Sadrian if (addr == 0) 186219444Sadrian return (ESRCH); 187219444Sadrian val = addr + addend; 188219444Sadrian *where = val; 189219444Sadrian break; 190219444Sadrian default: 191219444Sadrian printf("\nunhandled relocation type %u\n", (u_int)rtype); 192219444Sadrian return (EFTYPE); 193219444Sadrian } 194219444Sadrian 195219444Sadrian return (0); 196219444Sadrian#else 197219444Sadrian return (EOPNOTSUPP); 198219444Sadrian#endif 199219444Sadrian} 200219444Sadrian