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