1206376Srpaulo/*- 2206376Srpaulo * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org> 3206376Srpaulo * All rights reserved. 4206376Srpaulo * 5206376Srpaulo * Redistribution and use in source and binary forms, with or without 6206376Srpaulo * modification, are permitted provided that the following conditions 7206376Srpaulo * are met: 8206376Srpaulo * 1. Redistributions of source code must retain the above copyright 9206376Srpaulo * notice, this list of conditions and the following disclaimer. 10206376Srpaulo * 2. Redistributions in binary form must reproduce the above copyright 11206376Srpaulo * notice, this list of conditions and the following disclaimer in the 12206376Srpaulo * documentation and/or other materials provided with the distribution. 13206376Srpaulo * 14206376Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15206376Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16206376Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17206376Srpaulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18206376Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19206376Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20206376Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21206376Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22206376Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23206376Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24206376Srpaulo * SUCH DAMAGE. 25206376Srpaulo */ 26206376Srpaulo 27206376Srpaulo#include <sys/cdefs.h> 28206376Srpaulo__FBSDID("$FreeBSD$"); 29206376Srpaulo 30206376Srpaulo#include <sys/types.h> 31243977Srpaulo#include <elf.h> 32235153Savg#include <bootstrap.h> 33206376Srpaulo 34281357Sandrew#if defined(__aarch64__) 35281357Sandrew#define ElfW_Rel Elf64_Rela 36281357Sandrew#define ElfW_Dyn Elf64_Dyn 37281357Sandrew#define ELFW_R_TYPE ELF64_R_TYPE 38281357Sandrew#define ELF_RELA 39281357Sandrew#elif defined(__arm__) || defined(__i386__) 40282727Sian#define ElfW_Rel Elf32_Rel 41243977Srpaulo#define ElfW_Dyn Elf32_Dyn 42243977Srpaulo#define ELFW_R_TYPE ELF32_R_TYPE 43281237Semaste#elif defined(__amd64__) 44282727Sian#define ElfW_Rel Elf64_Rel 45243977Srpaulo#define ElfW_Dyn Elf64_Dyn 46243977Srpaulo#define ELFW_R_TYPE ELF64_R_TYPE 47281237Semaste#else 48281237Semaste#error architecture not supported 49243977Srpaulo#endif 50281357Sandrew#if defined(__aarch64__) 51281357Sandrew#define RELOC_TYPE_NONE R_AARCH64_NONE 52281357Sandrew#define RELOC_TYPE_RELATIVE R_AARCH64_RELATIVE 53281357Sandrew#elif defined(__amd64__) 54281237Semaste#define RELOC_TYPE_NONE R_X86_64_NONE 55281237Semaste#define RELOC_TYPE_RELATIVE R_X86_64_RELATIVE 56281237Semaste#elif defined(__arm__) 57281237Semaste#define RELOC_TYPE_NONE R_ARM_NONE 58281237Semaste#define RELOC_TYPE_RELATIVE R_ARM_RELATIVE 59281237Semaste#elif defined(__i386__) 60281237Semaste#define RELOC_TYPE_NONE R_386_NONE 61281237Semaste#define RELOC_TYPE_RELATIVE R_386_RELATIVE 62281237Semaste#endif 63243977Srpaulo 64294981Ssmhvoid self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic); 65294981Ssmh 66206376Srpaulo/* 67282727Sian * A simple elf relocator. 68206376Srpaulo */ 69282727Sianvoid 70282727Sianself_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic) 71206376Srpaulo{ 72282727Sian Elf_Word relsz, relent; 73282727Sian Elf_Addr *newaddr; 74243977Srpaulo ElfW_Rel *rel; 75243977Srpaulo ElfW_Dyn *dynp; 76206376Srpaulo 77206376Srpaulo /* 78206376Srpaulo * Find the relocation address, its size and the relocation entry. 79206376Srpaulo */ 80206376Srpaulo relsz = 0; 81206376Srpaulo relent = 0; 82206376Srpaulo for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { 83206376Srpaulo switch (dynp->d_tag) { 84258719Semaste case DT_REL: 85243977Srpaulo case DT_RELA: 86282727Sian rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr); 87206376Srpaulo break; 88206376Srpaulo case DT_RELSZ: 89243977Srpaulo case DT_RELASZ: 90206376Srpaulo relsz = dynp->d_un.d_val; 91206376Srpaulo break; 92206376Srpaulo case DT_RELENT: 93243977Srpaulo case DT_RELAENT: 94206376Srpaulo relent = dynp->d_un.d_val; 95206376Srpaulo break; 96206376Srpaulo default: 97206376Srpaulo break; 98206376Srpaulo } 99206376Srpaulo } 100206376Srpaulo 101206376Srpaulo /* 102206376Srpaulo * Perform the actual relocation. 103206376Srpaulo */ 104206376Srpaulo for (; relsz > 0; relsz -= relent) { 105243977Srpaulo switch (ELFW_R_TYPE(rel->r_info)) { 106281237Semaste case RELOC_TYPE_NONE: 107206376Srpaulo /* No relocation needs be performed. */ 108206376Srpaulo break; 109281237Semaste 110281237Semaste case RELOC_TYPE_RELATIVE: 111206376Srpaulo /* Address relative to the base address. */ 112282727Sian newaddr = (Elf_Addr *)(rel->r_offset + baseaddr); 113282727Sian *newaddr += baseaddr; 114281357Sandrew /* Add the addend when the ABI uses them */ 115281357Sandrew#ifdef ELF_RELA 116281357Sandrew *newaddr += rel->r_addend; 117281357Sandrew#endif 118206376Srpaulo break; 119206376Srpaulo default: 120206376Srpaulo /* XXX: do we need other relocations ? */ 121243977Srpaulo break; 122206376Srpaulo } 123294981Ssmh rel = (ElfW_Rel *)(void *)((caddr_t) rel + relent); 124206376Srpaulo } 125206376Srpaulo} 126