reloc.c revision 294981
116125Swpaul/*- 216125Swpaul * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org> 316125Swpaul * All rights reserved. 416125Swpaul * 516125Swpaul * Redistribution and use in source and binary forms, with or without 616125Swpaul * modification, are permitted provided that the following conditions 716125Swpaul * are met: 816125Swpaul * 1. Redistributions of source code must retain the above copyright 916125Swpaul * notice, this list of conditions and the following disclaimer. 1016125Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1116125Swpaul * notice, this list of conditions and the following disclaimer in the 1216125Swpaul * documentation and/or other materials provided with the distribution. 1316125Swpaul * 1416125Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1516125Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1616125Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1716125Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1816125Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1916125Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2016125Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2116125Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2216125Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2316125Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2416125Swpaul * SUCH DAMAGE. 2516125Swpaul */ 2616125Swpaul 2716125Swpaul#include <sys/cdefs.h> 2816125Swpaul__FBSDID("$FreeBSD: stable/10/sys/boot/efi/loader/arch/amd64/reloc.c 294981 2016-01-28 12:11:42Z smh $"); 2916125Swpaul 3016125Swpaul#include <sys/types.h> 3150479Speter#include <elf.h> 3216125Swpaul#include <efi.h> 3316125Swpaul#include <bootstrap.h> 3416125Swpaul 3516125Swpaul#ifdef __i386__ 3616125Swpaul#define ElfW_Rel Elf32_Rel 3716125Swpaul#define ElfW_Dyn Elf32_Dyn 3816125Swpaul#define ELFW_R_TYPE ELF32_R_TYPE 3916125Swpaul#elif __amd64__ 4068965Sru#define ElfW_Rel Elf64_Rel 4116125Swpaul#define ElfW_Dyn Elf64_Dyn 4216125Swpaul#define ELFW_R_TYPE ELF64_R_TYPE 4316125Swpaul#endif 4430378Scharnier 45108317SschweikhEFI_STATUS _reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle __unused, 4657673Ssheldonh EFI_SYSTEM_TABLE *system_table __unused); 47210723Sjoel 4816125Swpaul/* 4916125Swpaul * A simple relocator for IA32/AMD64 EFI binaries. 5016125Swpaul */ 5116125SwpaulEFI_STATUS 5216125Swpaul_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle __unused, 5316125Swpaul EFI_SYSTEM_TABLE *system_table __unused) 5416125Swpaul{ 5516125Swpaul unsigned long relsz, relent; 5616125Swpaul unsigned long *newaddr; 5716125Swpaul ElfW_Rel *rel; 5816125Swpaul ElfW_Dyn *dynp; 5916125Swpaul 6016125Swpaul /* 6116125Swpaul * Find the relocation address, its size and the relocation entry. 6216125Swpaul */ 6316125Swpaul relsz = 0; 6416125Swpaul relent = 0; 6516125Swpaul for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) { 6616125Swpaul switch (dynp->d_tag) { 6716125Swpaul case DT_REL: 6816125Swpaul case DT_RELA: 6916125Swpaul rel = (ElfW_Rel *) ((unsigned long) dynp->d_un.d_ptr + 7016125Swpaul ImageBase); 7116125Swpaul break; 7216125Swpaul case DT_RELSZ: 7316125Swpaul case DT_RELASZ: 7416125Swpaul relsz = dynp->d_un.d_val; 7557673Ssheldonh break; 7657673Ssheldonh case DT_RELENT: 7716125Swpaul case DT_RELAENT: 7816125Swpaul relent = dynp->d_un.d_val; 7916125Swpaul break; 8016125Swpaul default: 8157673Ssheldonh break; 8257673Ssheldonh } 8316125Swpaul } 8416125Swpaul 8516125Swpaul /* 8616125Swpaul * Perform the actual relocation. 8716125Swpaul * XXX: We are reusing code for the amd64 version of this, but 8816125Swpaul * we must make sure the relocation types are the same. 8930378Scharnier */ 9099968Scharnier CTASSERT(R_386_NONE == R_X86_64_NONE); 9116125Swpaul CTASSERT(R_386_RELATIVE == R_X86_64_RELATIVE); 9257673Ssheldonh for (; relsz > 0; relsz -= relent) { 9357673Ssheldonh switch (ELFW_R_TYPE(rel->r_info)) { 9430378Scharnier case R_386_NONE: 9557673Ssheldonh /* No relocation needs be performed. */ 96210723Sjoel break; 9716125Swpaul case R_386_RELATIVE: 9816125Swpaul /* Address relative to the base address. */ 9916125Swpaul newaddr = (unsigned long *)(ImageBase + rel->r_offset); 10016125Swpaul *newaddr += ImageBase; 10116125Swpaul break; 10230378Scharnier default: 10399968Scharnier /* XXX: do we need other relocations ? */ 10416125Swpaul break; 10516125Swpaul } 10616125Swpaul rel = (ElfW_Rel *)(void *) ((caddr_t) rel + relent); 107163902Smaxim } 108163902Smaxim 109163902Smaxim return (EFI_SUCCESS); 110163902Smaxim} 111163902Smaxim