xref: /dragonfly/sys/cpu/x86_64/misc/elf_machdep.c (revision 2b49b9be)
12acda721SJordan Gordeev /*-
22acda721SJordan Gordeev  * Copyright 1996-1998 John D. Polstra.
32acda721SJordan Gordeev  * All rights reserved.
42acda721SJordan Gordeev  *
52acda721SJordan Gordeev  * Redistribution and use in source and binary forms, with or without
62acda721SJordan Gordeev  * modification, are permitted provided that the following conditions
72acda721SJordan Gordeev  * are met:
82acda721SJordan Gordeev  * 1. Redistributions of source code must retain the above copyright
92acda721SJordan Gordeev  *    notice, this list of conditions and the following disclaimer.
102acda721SJordan Gordeev  * 2. Redistributions in binary form must reproduce the above copyright
112acda721SJordan Gordeev  *    notice, this list of conditions and the following disclaimer in the
122acda721SJordan Gordeev  *    documentation and/or other materials provided with the distribution.
132acda721SJordan Gordeev  *
142acda721SJordan Gordeev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
152acda721SJordan Gordeev  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
162acda721SJordan Gordeev  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
172acda721SJordan Gordeev  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
182acda721SJordan Gordeev  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
192acda721SJordan Gordeev  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202acda721SJordan Gordeev  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
212acda721SJordan Gordeev  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
222acda721SJordan Gordeev  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
232acda721SJordan Gordeev  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
242acda721SJordan Gordeev  *
252acda721SJordan Gordeev  * $FreeBSD: src/sys/i386/i386/elf_machdep.c,v 1.8 1999/12/21 11:14:02 eivind Exp $
262acda721SJordan Gordeev  */
272acda721SJordan Gordeev 
282acda721SJordan Gordeev #include <sys/param.h>
29315b8b8bSJohn Marino #include <sys/kernel.h>
302acda721SJordan Gordeev #include <sys/systm.h>
312acda721SJordan Gordeev #include <sys/linker.h>
32315b8b8bSJohn Marino #include <sys/sysent.h>
33315b8b8bSJohn Marino #include <sys/imgact_elf.h>
34315b8b8bSJohn Marino #include <sys/syscall.h>
35315b8b8bSJohn Marino #include <sys/signalvar.h>
36315b8b8bSJohn Marino #include <sys/vnode.h>
372acda721SJordan Gordeev #include <machine/elf.h>
38315b8b8bSJohn Marino #include <machine/md_var.h>
39315b8b8bSJohn Marino 
40315b8b8bSJohn Marino static struct sysentvec elf64_dragonfly_sysvec = {
41315b8b8bSJohn Marino         .sv_size	= SYS_MAXSYSCALL,
42315b8b8bSJohn Marino         .sv_table	= sysent,
43315b8b8bSJohn Marino         .sv_sigsize	= 0,
44315b8b8bSJohn Marino         .sv_sigtbl	= NULL,
45315b8b8bSJohn Marino         .sv_errsize	= 0,
46315b8b8bSJohn Marino         .sv_errtbl	= NULL,
47315b8b8bSJohn Marino         .sv_transtrap	= NULL,
48315b8b8bSJohn Marino         .sv_fixup	= __elfN(dragonfly_fixup),
49315b8b8bSJohn Marino         .sv_sendsig	= sendsig,
50315b8b8bSJohn Marino         .sv_sigcode	= sigcode,
51315b8b8bSJohn Marino         .sv_szsigcode	= &szsigcode,
52315b8b8bSJohn Marino 	.sv_name	= "DragonFly ELF64",
53315b8b8bSJohn Marino 	.sv_coredump	= __elfN(coredump),
54315b8b8bSJohn Marino 	.sv_imgact_try	= NULL,
55315b8b8bSJohn Marino 	.sv_minsigstksz	= MINSIGSTKSZ,
56315b8b8bSJohn Marino };
57315b8b8bSJohn Marino 
58315b8b8bSJohn Marino static Elf64_Brandinfo dragonfly_brand_info = {
59315b8b8bSJohn Marino         .brand		= ELFOSABI_NONE,
60315b8b8bSJohn Marino         .machine	= EM_X86_64,
61315b8b8bSJohn Marino         .compat_3_brand	= "DragonFly",
62315b8b8bSJohn Marino         .emul_path	= NULL,
6316dbe6a9SFrançois Tigeot         .interp_path	= "/libexec/ld-elf.so.2",
64315b8b8bSJohn Marino         .sysvec		= &elf64_dragonfly_sysvec,
65315b8b8bSJohn Marino         .interp_newpath	= NULL,
66315b8b8bSJohn Marino         .flags		= BI_CAN_EXEC_DYN | BI_BRAND_NOTE,
67315b8b8bSJohn Marino         .brand_note	= &elf64_dragonfly_brandnote,
68315b8b8bSJohn Marino };
69315b8b8bSJohn Marino 
70315b8b8bSJohn Marino SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST,
71315b8b8bSJohn Marino         (sysinit_cfunc_t) elf64_insert_brand_entry,
72315b8b8bSJohn Marino         &dragonfly_brand_info);
732acda721SJordan Gordeev 
742acda721SJordan Gordeev /* Process one elf relocation with addend. */
752acda721SJordan Gordeev static int
elf_reloc_internal(linker_file_t lf,Elf_Addr relocbase,const void * data,int type,int local,elf_lookup_fn lookup)762acda721SJordan Gordeev elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data,
772acda721SJordan Gordeev     int type, int local, elf_lookup_fn lookup)
782acda721SJordan Gordeev {
792acda721SJordan Gordeev 	Elf64_Addr *where, val;
802acda721SJordan Gordeev 	Elf32_Addr *where32, val32;
812acda721SJordan Gordeev 	Elf_Addr addr;
822acda721SJordan Gordeev 	Elf_Addr addend;
832acda721SJordan Gordeev 	Elf_Size rtype, symidx;
842acda721SJordan Gordeev 	const Elf_Rel *rel;
852acda721SJordan Gordeev 	const Elf_Rela *rela;
862acda721SJordan Gordeev 
872acda721SJordan Gordeev 	switch (type) {
882acda721SJordan Gordeev 	case ELF_RELOC_REL:
892acda721SJordan Gordeev 		rel = (const Elf_Rel *)data;
902acda721SJordan Gordeev 		where = (Elf_Addr *) (relocbase + rel->r_offset);
912acda721SJordan Gordeev 		rtype = ELF_R_TYPE(rel->r_info);
922acda721SJordan Gordeev 		symidx = ELF_R_SYM(rel->r_info);
932acda721SJordan Gordeev 		/* Addend is 32 bit on 32 bit relocs */
942acda721SJordan Gordeev 		switch (rtype) {
952acda721SJordan Gordeev 		case R_X86_64_PC32:
96*2b49b9beSzrj 		case R_X86_64_PLT32:
972acda721SJordan Gordeev 		case R_X86_64_32:
982acda721SJordan Gordeev 		case R_X86_64_32S:
992acda721SJordan Gordeev 			addend = *(Elf32_Addr *)where;
1002acda721SJordan Gordeev 			break;
1012acda721SJordan Gordeev 		default:
1022acda721SJordan Gordeev 			addend = *where;
1032acda721SJordan Gordeev 			break;
1042acda721SJordan Gordeev 		}
1052acda721SJordan Gordeev 		break;
1062acda721SJordan Gordeev 	case ELF_RELOC_RELA:
1072acda721SJordan Gordeev 		rela = (const Elf_Rela *)data;
1082acda721SJordan Gordeev 		where = (Elf_Addr *) (relocbase + rela->r_offset);
1092acda721SJordan Gordeev 		addend = rela->r_addend;
1102acda721SJordan Gordeev 		rtype = ELF_R_TYPE(rela->r_info);
1112acda721SJordan Gordeev 		symidx = ELF_R_SYM(rela->r_info);
1122acda721SJordan Gordeev 		break;
1132acda721SJordan Gordeev 	default:
114ed20d0e3SSascha Wildner 		panic("unknown reloc type %d", type);
1152acda721SJordan Gordeev 	}
1162acda721SJordan Gordeev 
1172acda721SJordan Gordeev 	switch (rtype) {
1182acda721SJordan Gordeev 
1192acda721SJordan Gordeev 		case R_X86_64_NONE:	/* none */
1202acda721SJordan Gordeev 			break;
1212acda721SJordan Gordeev 
1222acda721SJordan Gordeev 		case R_X86_64_64:		/* S + A */
1232acda721SJordan Gordeev 			if (lookup(lf, symidx, 1, &addr))
1242acda721SJordan Gordeev 				return -1;
1252acda721SJordan Gordeev 			val = addr + addend;
1262acda721SJordan Gordeev 			if (*where != val)
1272acda721SJordan Gordeev 				*where = val;
1282acda721SJordan Gordeev 			break;
1292acda721SJordan Gordeev 
1302acda721SJordan Gordeev 		case R_X86_64_PC32:	/* S + A - P */
131*2b49b9beSzrj 		case R_X86_64_PLT32:	/* XXX assume PLT as S too */
1322acda721SJordan Gordeev 			if (lookup(lf, symidx, 1, &addr))
1332acda721SJordan Gordeev 				return -1;
1342acda721SJordan Gordeev 			where32 = (Elf32_Addr *)where;
1352acda721SJordan Gordeev 			val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where);
1362acda721SJordan Gordeev 			if (*where32 != val32)
1372acda721SJordan Gordeev 				*where32 = val32;
1382acda721SJordan Gordeev 			break;
1392acda721SJordan Gordeev 
1402acda721SJordan Gordeev 		case R_X86_64_32:	/* S + A zero extend */
1412acda721SJordan Gordeev 		case R_X86_64_32S:	/* S + A sign extend */
1422acda721SJordan Gordeev 			if (lookup(lf, symidx, 1, &addr))
1432acda721SJordan Gordeev 				return -1;
1442acda721SJordan Gordeev 			val32 = (Elf32_Addr)(addr + addend);
1452acda721SJordan Gordeev 			where32 = (Elf32_Addr *)where;
1462acda721SJordan Gordeev 			if (*where32 != val32)
1472acda721SJordan Gordeev 				*where32 = val32;
1482acda721SJordan Gordeev 			break;
1492acda721SJordan Gordeev 
1502acda721SJordan Gordeev 		case R_X86_64_COPY:	/* none */
1512acda721SJordan Gordeev 			/*
1522acda721SJordan Gordeev 			 * There shouldn't be copy relocations in kernel
1532acda721SJordan Gordeev 			 * objects.
1542acda721SJordan Gordeev 			 */
1552acda721SJordan Gordeev 			kprintf("kldload: unexpected R_COPY relocation\n");
1562acda721SJordan Gordeev 			return -1;
1572acda721SJordan Gordeev 			break;
1582acda721SJordan Gordeev 
1592acda721SJordan Gordeev 		case R_X86_64_GLOB_DAT:	/* S */
1602acda721SJordan Gordeev 		case R_X86_64_JMP_SLOT:	/* XXX need addend + offset */
1612acda721SJordan Gordeev 			if (lookup(lf, symidx, 1, &addr))
1622acda721SJordan Gordeev 				return -1;
1632acda721SJordan Gordeev 			if (*where != addr)
1642acda721SJordan Gordeev 				*where = addr;
1652acda721SJordan Gordeev 			break;
1662acda721SJordan Gordeev 
1672acda721SJordan Gordeev 		case R_X86_64_RELATIVE:	/* B + A */
1682acda721SJordan Gordeev 			addr = relocbase + addend;
1692acda721SJordan Gordeev 			val = addr;
1702acda721SJordan Gordeev 			if (*where != val)
1712acda721SJordan Gordeev 				*where = val;
1722acda721SJordan Gordeev 			break;
1732acda721SJordan Gordeev 
1742acda721SJordan Gordeev 		default:
1752acda721SJordan Gordeev 			kprintf("kldload: unexpected relocation type %ld\n",
1762acda721SJordan Gordeev 			       rtype);
1772acda721SJordan Gordeev 			return -1;
1782acda721SJordan Gordeev 	}
1792acda721SJordan Gordeev 	return(0);
1802acda721SJordan Gordeev }
1812acda721SJordan Gordeev 
1822acda721SJordan Gordeev int
elf_reloc(linker_file_t lf,Elf_Addr relocbase,const void * data,int type,elf_lookup_fn lookup)1832acda721SJordan Gordeev elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type,
1842acda721SJordan Gordeev     elf_lookup_fn lookup)
1852acda721SJordan Gordeev {
1862acda721SJordan Gordeev 
1872acda721SJordan Gordeev 	return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup));
1882acda721SJordan Gordeev }
1892acda721SJordan Gordeev 
1902acda721SJordan Gordeev int
elf_reloc_local(linker_file_t lf,Elf_Addr relocbase,const void * data,int type,elf_lookup_fn lookup)1912acda721SJordan Gordeev elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data,
1922acda721SJordan Gordeev     int type, elf_lookup_fn lookup)
1932acda721SJordan Gordeev {
1942acda721SJordan Gordeev 
1952acda721SJordan Gordeev 	return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup));
1962acda721SJordan Gordeev }
197