reloc.c revision 293297
199651Sbenno/*-
299651Sbenno * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org>
399651Sbenno * All rights reserved.
499651Sbenno *
599651Sbenno * Redistribution and use in source and binary forms, with or without
699651Sbenno * modification, are permitted provided that the following conditions
799651Sbenno * are met:
899651Sbenno * 1. Redistributions of source code must retain the above copyright
999651Sbenno *    notice, this list of conditions and the following disclaimer.
1099651Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1199651Sbenno *    notice, this list of conditions and the following disclaimer in the
1299651Sbenno *    documentation and/or other materials provided with the distribution.
1399651Sbenno *
1499651Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1599651Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1699651Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1799651Sbenno * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1899651Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1999651Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2099651Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2199651Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2299651Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2399651Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2499651Sbenno * SUCH DAMAGE.
2599651Sbenno */
2699651Sbenno
2799651Sbenno#include <sys/cdefs.h>
2899651Sbenno__FBSDID("$FreeBSD: stable/10/sys/boot/efi/loader/arch/amd64/reloc.c 293297 2016-01-07 02:22:45Z emaste $");
2999651Sbenno
3099651Sbenno#include <sys/types.h>
3199651Sbenno#include <elf.h>
3299651Sbenno#include <efi.h>
3399651Sbenno#include <bootstrap.h>
3499651Sbenno
3599651Sbenno#ifdef __i386__
3699651Sbenno#define ElfW_Rel	Elf32_Rel
3799651Sbenno#define	ElfW_Dyn	Elf32_Dyn
3899651Sbenno#define	ELFW_R_TYPE	ELF32_R_TYPE
3999651Sbenno#elif __amd64__
4099651Sbenno#define ElfW_Rel	Elf64_Rel
4199651Sbenno#define	ElfW_Dyn	Elf64_Dyn
4299651Sbenno#define	ELFW_R_TYPE	ELF64_R_TYPE
4399651Sbenno#endif
4499651Sbenno
4599651Sbenno/*
4699651Sbenno * A simple relocator for IA32/AMD64 EFI binaries.
4799651Sbenno */
4899651SbennoEFI_STATUS
4999651Sbenno_reloc(unsigned long ImageBase, ElfW_Dyn *dynamic, EFI_HANDLE image_handle,
5099651Sbenno    EFI_SYSTEM_TABLE *system_table)
5199651Sbenno{
5299651Sbenno	unsigned long relsz, relent;
5399651Sbenno	unsigned long *newaddr;
5499651Sbenno	ElfW_Rel *rel;
5599651Sbenno	ElfW_Dyn *dynp;
5699651Sbenno
5799651Sbenno	/*
5899651Sbenno	 * Find the relocation address, its size and the relocation entry.
5999651Sbenno	 */
6099651Sbenno	relsz = 0;
6199651Sbenno	relent = 0;
6299651Sbenno	for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) {
63218075Smarcel		switch (dynp->d_tag) {
64218075Smarcel		case DT_REL:
6599651Sbenno		case DT_RELA:
6699651Sbenno			rel = (ElfW_Rel *) ((unsigned long) dynp->d_un.d_ptr +
6799651Sbenno			    ImageBase);
6899651Sbenno			break;
6999651Sbenno		case DT_RELSZ:
70222813Sattilio		case DT_RELASZ:
7199651Sbenno			relsz = dynp->d_un.d_val;
72164987Smarcel			break;
7399651Sbenno		case DT_RELENT:
7499651Sbenno		case DT_RELAENT:
7599651Sbenno			relent = dynp->d_un.d_val;
7699651Sbenno			break;
77209486Snwhitehorn		default:
78171805Smarcel			break;
7999651Sbenno		}
80125708Sgrehan	}
8199651Sbenno
8299651Sbenno	/*
8399651Sbenno	 * Perform the actual relocation.
84171805Smarcel	 * XXX: We are reusing code for the amd64 version of this, but
85178628Smarcel	 * we must make sure the relocation types are the same.
8699651Sbenno	 */
8799651Sbenno	CTASSERT(R_386_NONE == R_X86_64_NONE);
88171805Smarcel	CTASSERT(R_386_RELATIVE == R_X86_64_RELATIVE);
89171805Smarcel	for (; relsz > 0; relsz -= relent) {
9099651Sbenno		switch (ELFW_R_TYPE(rel->r_info)) {
9199651Sbenno		case R_386_NONE:
92227293Sed			/* No relocation needs be performed. */
9399651Sbenno			break;
94171805Smarcel		case R_386_RELATIVE:
95164987Smarcel			/* Address relative to the base address. */
96164987Smarcel			newaddr = (unsigned long *)(ImageBase + rel->r_offset);
97191450Smarcel			*newaddr += ImageBase;
98191450Smarcel			break;
99191450Smarcel		default:
100191450Smarcel			/* XXX: do we need other relocations ? */
101212453Smav			break;
102222813Sattilio		}
103176918Smarcel		rel = (ElfW_Rel *) ((caddr_t) rel + relent);
104176918Smarcel	}
105265969Sian
106266676Snwhitehorn	return (EFI_SUCCESS);
107164987Smarcel}
10899651Sbenno