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