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$
26 */
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/linker.h>
31 #include <machine/elf.h>
32
33 /* Process one elf relocation with addend. */
34 int
35 elf_reloc(linker_file_t lf, const void *data, int type, const char *sym)
36 {
37 Elf_Addr relocbase = (Elf_Addr) lf->address;
38 Elf_Addr *where;
39 Elf_Addr addr;
40 Elf_Addr addend;
41 Elf_Word rtype;
42 const Elf_Rel *rel;
43 const Elf_Rela *rela;
44
45 switch (type) {
46 case ELF_RELOC_REL:
47 rel = (const Elf_Rel *)data;
48 where = (Elf_Addr *) (relocbase + rel->r_offset);
49 addend = *where;
50 rtype = ELF_R_TYPE(rel->r_info);
51 break;
52 case ELF_RELOC_RELA:
53 rela = (const Elf_Rela *)data;
54 where = (Elf_Addr *) (relocbase + rela->r_offset);
55 addend = rela->r_addend;
56 rtype = ELF_R_TYPE(rela->r_info);
57 break;
58 default:
59 panic("unknown reloc type %d\n", type);
60 }
61
62 switch (rtype) {
63
64 case R_386_NONE: /* none */
65 break;
66
67 case R_386_32: /* S + A */
68 if (sym == NULL)
69 return -1;
70 addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
71 if (addr == 0)
72 return -1;
73 addr += addend;
74 if (*where != addr)
75 *where = addr;
76 break;
77
78 case R_386_PC32: /* S + A - P */
79 if (sym == NULL)
80 return -1;
81 addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
82 if (addr == 0)
83 return -1;
84 addr += addend - (Elf_Addr)where;
85 if (*where != addr)
86 *where = addr;
87 break;
88
89 case R_386_COPY: /* none */
90 /*
91 * There shouldn't be copy relocations in kernel
92 * objects.
93 */
94 printf("kldload: unexpected R_COPY relocation\n");
95 return -1;
96 break;
97
98 case R_386_GLOB_DAT: /* S */
99 if (sym == NULL)
100 return -1;
101 addr = (Elf_Addr)linker_file_lookup_symbol(lf, sym, 1);
102 if (addr == 0)
103 return -1;
104 if (*where != addr)
105 *where = addr;
106 break;
107
108 case R_386_RELATIVE: /* B + A */
109 addr = relocbase + addend;
110 if (*where != addr)
111 *where = addr;
112 break;
113
114 default:
115 printf("kldload: unexpected relocation type %d\n",
116 rtype);
117 return -1;
118 }
119 return(0);
120 }
Cache object: 78fdbec975de0e01764923d3cb668f9e
|