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> 32206376Srpaulo#include <efi.h> 33235153Savg#include <bootstrap.h> 34206376Srpaulo 35243977Srpaulo#ifdef __i386__ 36243977Srpaulo#define ElfW_Rel Elf32_Rel 37243977Srpaulo#define ElfW_Dyn Elf32_Dyn 38243977Srpaulo#define ELFW_R_TYPE ELF32_R_TYPE 39243977Srpaulo#elif __amd64__ 40243977Srpaulo#define ElfW_Rel Elf64_Rel 41243977Srpaulo#define ElfW_Dyn Elf64_Dyn 42243977Srpaulo#define ELFW_R_TYPE ELF64_R_TYPE 43243977Srpaulo#endif 44243977Srpaulo 45206376Srpaulo/* 46243977Srpaulo * A simple relocator for IA32/AMD64 EFI binaries. 47206376Srpaulo */ 48206376SrpauloEFI_STATUS 49243977Srpaulo_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle, 50206376Srpaulo EFI_SYSTEM_TABLE *system_table) 51206376Srpaulo{ 52206376Srpaulo unsigned long relsz, relent; 53206376Srpaulo unsigned long *newaddr; 54243977Srpaulo ElfW_Rel *rel; 55243977Srpaulo ElfW_Dyn *dynp; 56206376Srpaulo 57206376Srpaulo /* 58206376Srpaulo * Find the relocation address, its size and the relocation entry. 59206376Srpaulo */ 60206376Srpaulo relsz = 0; 61206376Srpaulo relent = 0; 62206376Srpaulo for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { 63206376Srpaulo switch (dynp->d_tag) { 64243977Srpaulo case DT_RELA: 65206376Srpaulo case DT_REL: 66243977Srpaulo rel = (ElfW_Rel *) ((unsigned long) dynp->d_un.d_ptr + 67206376Srpaulo ImageBase); 68206376Srpaulo break; 69206376Srpaulo case DT_RELSZ: 70243977Srpaulo case DT_RELASZ: 71206376Srpaulo relsz = dynp->d_un.d_val; 72206376Srpaulo break; 73206376Srpaulo case DT_RELENT: 74243977Srpaulo case DT_RELAENT: 75206376Srpaulo relent = dynp->d_un.d_val; 76206376Srpaulo break; 77206376Srpaulo default: 78206376Srpaulo break; 79206376Srpaulo } 80206376Srpaulo } 81206376Srpaulo 82206376Srpaulo /* 83206376Srpaulo * Perform the actual relocation. 84206376Srpaulo * XXX: We are reusing code for the amd64 version of this, but 85206376Srpaulo * we must make sure the relocation types are the same. 86206376Srpaulo */ 87206376Srpaulo CTASSERT(R_386_NONE == R_X86_64_NONE); 88206376Srpaulo CTASSERT(R_386_RELATIVE == R_X86_64_RELATIVE); 89206376Srpaulo for (; relsz > 0; relsz -= relent) { 90243977Srpaulo switch (ELFW_R_TYPE(rel->r_info)) { 91206376Srpaulo case R_386_NONE: 92206376Srpaulo /* No relocation needs be performed. */ 93206376Srpaulo break; 94206376Srpaulo case R_386_RELATIVE: 95206376Srpaulo /* Address relative to the base address. */ 96206376Srpaulo newaddr = (unsigned long *)(ImageBase + rel->r_offset); 97206376Srpaulo *newaddr += ImageBase; 98206376Srpaulo break; 99206376Srpaulo default: 100206376Srpaulo /* XXX: do we need other relocations ? */ 101243977Srpaulo break; 102206376Srpaulo } 103243977Srpaulo rel = (ElfW_Rel *) ((caddr_t) rel + relent); 104206376Srpaulo } 105206376Srpaulo 106206376Srpaulo return (EFI_SUCCESS); 107206376Srpaulo} 108