642a1836b112b2c51fb41f258f2c3dd0ffc5de3c
[dragonfly.git] / sys / platform / pc64 / amd64 / elf_machdep.c
1 /*-
2  * Copyright 1996-1998 John D. Polstra.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * $FreeBSD: src/sys/i386/i386/elf_machdep.c,v 1.8 1999/12/21 11:14:02 eivind Exp $
26  * $DragonFly: src/sys/platform/pc64/amd64/elf_machdep.c,v 1.1 2007/09/23 04:29:31 yanyh Exp $
27  * $DragonFly: src/sys/platform/pc64/amd64/elf_machdep.c,v 1.1 2007/09/23 04:29:31 yanyh Exp $
28  */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/linker.h>
33 #include <machine/elf.h>
34
35 /* Process one elf relocation with addend. */
36 int
37 elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
38 {
39         Elf_Addr relocbase = (Elf_Addr) lf->address;
40         Elf_Addr *where;
41         Elf_Addr addr;
42         Elf_Addr addend;
43         Elf_Word rtype;
44         caddr_t caddr;
45         const Elf_Rel *rel;
46         const Elf_Rela *rela;
47
48         switch (type) {
49         case ELF_RELOC_REL:
50                 rel = (const Elf_Rel *)data;
51                 where = (Elf_Addr *) (relocbase + rel->r_offset);
52                 addend = *where;
53                 rtype = ELF_R_TYPE(rel->r_info);
54                 break;
55         case ELF_RELOC_RELA:
56                 rela = (const Elf_Rela *)data;
57                 where = (Elf_Addr *) (relocbase + rela->r_offset);
58                 addend = rela->r_addend;
59                 rtype = ELF_R_TYPE(rela->r_info);
60                 break;
61         default:
62                 panic("unknown reloc type %d\n", type);
63         }
64
65         switch (rtype) {
66
67                 case R_X86_64_NONE:     /* none */
68                         break;
69
70                 case R_X86_64_64:               /* S + A */
71                         if (sym == NULL)
72                                 return -1;
73                         if (linker_file_lookup_symbol(lf, sym, 1, &caddr) != 0)
74                                 return -1;
75                         addr = (Elf_Addr)caddr;
76                         addr += addend;
77                         if (*where != addr)
78                                 *where = addr;
79                         break;
80
81                 case R_X86_64_PC32:     /* S + A - P */
82                         if (sym == NULL)
83                                 return -1;
84                         if (linker_file_lookup_symbol(lf, sym, 1, &caddr) != 0)
85                                 return -1;
86                         addr = (Elf_Addr)caddr;
87                         addr += addend - (Elf_Addr)where;
88                         if (*where != addr)
89                                 *where = addr;
90                         break;
91
92                 case R_X86_64_COPY:     /* none */
93                         /*
94                          * There shouldn't be copy relocations in kernel
95                          * objects.
96                          */
97                         kprintf("kldload: unexpected R_COPY relocation\n");
98                         return -1;
99                         break;
100
101                 case R_X86_64_GLOB_DAT: /* S */
102                         if (sym == NULL)
103                                 return -1;
104                         if (linker_file_lookup_symbol(lf, sym, 1, &caddr) != 0)
105                                 return -1;
106                         addr = (Elf_Addr)caddr;
107                         if (*where != addr)
108                                 *where = addr;
109                         break;
110
111                 case R_X86_64_RELATIVE: /* B + A */
112                         addr = relocbase + addend;
113                         if (*where != addr)
114                                 *where = addr;
115                         break;
116
117                 default:
118                         kprintf("kldload: unexpected relocation type %d\n",
119                                rtype);
120                         return -1;
121         }
122         return(0);
123 }