xref: /titanic_51/usr/src/boot/sys/boot/common/self_reloc.c (revision d76811be4a9c2b67f2c59840b640f1201293ada6)
14a5d661aSToomas Soome /*-
24a5d661aSToomas Soome  * Copyright (c) 2008-2010 Rui Paulo <rpaulo@FreeBSD.org>
34a5d661aSToomas Soome  * All rights reserved.
44a5d661aSToomas Soome  *
54a5d661aSToomas Soome  * Redistribution and use in source and binary forms, with or without
64a5d661aSToomas Soome  * modification, are permitted provided that the following conditions
74a5d661aSToomas Soome  * are met:
84a5d661aSToomas Soome  * 1. Redistributions of source code must retain the above copyright
94a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer.
104a5d661aSToomas Soome  * 2. Redistributions in binary form must reproduce the above copyright
114a5d661aSToomas Soome  *    notice, this list of conditions and the following disclaimer in the
124a5d661aSToomas Soome  *    documentation and/or other materials provided with the distribution.
134a5d661aSToomas Soome  *
144a5d661aSToomas Soome  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
154a5d661aSToomas Soome  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
164a5d661aSToomas Soome  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
174a5d661aSToomas Soome  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
184a5d661aSToomas Soome  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
194a5d661aSToomas Soome  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
204a5d661aSToomas Soome  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
214a5d661aSToomas Soome  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
224a5d661aSToomas Soome  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
234a5d661aSToomas Soome  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
244a5d661aSToomas Soome  * SUCH DAMAGE.
254a5d661aSToomas Soome  */
264a5d661aSToomas Soome 
274a5d661aSToomas Soome #include <sys/cdefs.h>
284a5d661aSToomas Soome 
294a5d661aSToomas Soome #include <sys/types.h>
304a5d661aSToomas Soome #include <elf.h>
314a5d661aSToomas Soome #include <bootstrap.h>
324a5d661aSToomas Soome 
33*d76811beSToomas Soome #if defined(__aarch64__) || defined(__amd64__)
344a5d661aSToomas Soome #define	ElfW_Rel	Elf64_Rela
354a5d661aSToomas Soome #define	ElfW_Dyn	Elf64_Dyn
364a5d661aSToomas Soome #define	ELFW_R_TYPE	ELF64_R_TYPE
374a5d661aSToomas Soome #define	ELF_RELA
384a5d661aSToomas Soome #elif defined(__arm__) || defined(__i386__)
394a5d661aSToomas Soome #define	ElfW_Rel	Elf32_Rel
404a5d661aSToomas Soome #define	ElfW_Dyn	Elf32_Dyn
414a5d661aSToomas Soome #define	ELFW_R_TYPE	ELF32_R_TYPE
424a5d661aSToomas Soome #else
434a5d661aSToomas Soome #error architecture not supported
444a5d661aSToomas Soome #endif
454a5d661aSToomas Soome #if defined(__aarch64__)
464a5d661aSToomas Soome #define	RELOC_TYPE_NONE		R_AARCH64_NONE
474a5d661aSToomas Soome #define	RELOC_TYPE_RELATIVE	R_AARCH64_RELATIVE
484a5d661aSToomas Soome #elif defined(__amd64__)
494a5d661aSToomas Soome #define	RELOC_TYPE_NONE		R_X86_64_NONE
504a5d661aSToomas Soome #define	RELOC_TYPE_RELATIVE	R_X86_64_RELATIVE
514a5d661aSToomas Soome #elif defined(__arm__)
524a5d661aSToomas Soome #define	RELOC_TYPE_NONE		R_ARM_NONE
534a5d661aSToomas Soome #define	RELOC_TYPE_RELATIVE	R_ARM_RELATIVE
544a5d661aSToomas Soome #elif defined(__i386__)
554a5d661aSToomas Soome #define	RELOC_TYPE_NONE		R_386_NONE
564a5d661aSToomas Soome #define	RELOC_TYPE_RELATIVE	R_386_RELATIVE
574a5d661aSToomas Soome #endif
584a5d661aSToomas Soome 
594a5d661aSToomas Soome void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic);
604a5d661aSToomas Soome 
614a5d661aSToomas Soome /*
624a5d661aSToomas Soome  * A simple elf relocator.
634a5d661aSToomas Soome  */
644a5d661aSToomas Soome void
654a5d661aSToomas Soome self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic)
664a5d661aSToomas Soome {
674a5d661aSToomas Soome 	Elf_Word relsz, relent;
684a5d661aSToomas Soome 	Elf_Addr *newaddr;
694a5d661aSToomas Soome 	ElfW_Rel *rel = 0;
704a5d661aSToomas Soome 	ElfW_Dyn *dynp;
714a5d661aSToomas Soome 
724a5d661aSToomas Soome 	/*
734a5d661aSToomas Soome 	 * Find the relocation address, its size and the relocation entry.
744a5d661aSToomas Soome 	 */
754a5d661aSToomas Soome 	relsz = 0;
764a5d661aSToomas Soome 	relent = 0;
774a5d661aSToomas Soome 	for (dynp = dynamic; dynp->d_tag != DT_NULL; dynp++) {
784a5d661aSToomas Soome 		switch (dynp->d_tag) {
794a5d661aSToomas Soome 		case DT_REL:
804a5d661aSToomas Soome 		case DT_RELA:
814a5d661aSToomas Soome 			rel = (ElfW_Rel *)(dynp->d_un.d_ptr + baseaddr);
824a5d661aSToomas Soome 			break;
834a5d661aSToomas Soome 		case DT_RELSZ:
844a5d661aSToomas Soome 		case DT_RELASZ:
854a5d661aSToomas Soome 			relsz = dynp->d_un.d_val;
864a5d661aSToomas Soome 			break;
874a5d661aSToomas Soome 		case DT_RELENT:
884a5d661aSToomas Soome 		case DT_RELAENT:
894a5d661aSToomas Soome 			relent = dynp->d_un.d_val;
904a5d661aSToomas Soome 			break;
914a5d661aSToomas Soome 		default:
924a5d661aSToomas Soome 			break;
934a5d661aSToomas Soome 		}
944a5d661aSToomas Soome 	}
954a5d661aSToomas Soome 
964a5d661aSToomas Soome 	/*
97*d76811beSToomas Soome 	 * Perform the actual relocation. We rely on the object having been
98*d76811beSToomas Soome 	 * linked at 0, so that the difference between the load and link
99*d76811beSToomas Soome 	 * address is the same as the load address.
1004a5d661aSToomas Soome 	 */
1014a5d661aSToomas Soome 	for (; relsz > 0; relsz -= relent) {
1024a5d661aSToomas Soome 		switch (ELFW_R_TYPE(rel->r_info)) {
1034a5d661aSToomas Soome 		case RELOC_TYPE_NONE:
1044a5d661aSToomas Soome 			/* No relocation needs be performed. */
1054a5d661aSToomas Soome 			break;
1064a5d661aSToomas Soome 
1074a5d661aSToomas Soome 		case RELOC_TYPE_RELATIVE:
1084a5d661aSToomas Soome 			newaddr = (Elf_Addr *)(rel->r_offset + baseaddr);
1094a5d661aSToomas Soome #ifdef ELF_RELA
110*d76811beSToomas Soome 			/* Addend relative to the base address. */
111*d76811beSToomas Soome 			*newaddr = baseaddr + rel->r_addend;
112*d76811beSToomas Soome #else
113*d76811beSToomas Soome 			/* Address relative to the base address. */
114*d76811beSToomas Soome 			*newaddr += baseaddr;
1154a5d661aSToomas Soome #endif
1164a5d661aSToomas Soome 			break;
1174a5d661aSToomas Soome 		default:
1184a5d661aSToomas Soome 			/* XXX: do we need other relocations ? */
1194a5d661aSToomas Soome 			break;
1204a5d661aSToomas Soome 		}
1214a5d661aSToomas Soome 		rel = (ElfW_Rel *)(void *)((caddr_t) rel + relent);
1224a5d661aSToomas Soome 	}
1234a5d661aSToomas Soome }
124