| @@ -1,1080 +1,1081 @@ | | | @@ -1,1080 +1,1081 @@ |
1 | /* $NetBSD: subr_kobj.c,v 1.76 2023/01/29 17:20:48 skrll Exp $ */ | | 1 | /* $NetBSD: subr_kobj.c,v 1.77 2023/04/17 08:14:51 skrll Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software developed for The NetBSD Foundation | | 7 | * This code is derived from software developed for The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 1998-2000 Doug Rabson | | 33 | * Copyright (c) 1998-2000 Doug Rabson |
34 | * Copyright (c) 2004 Peter Wemm | | 34 | * Copyright (c) 2004 Peter Wemm |
35 | * All rights reserved. | | 35 | * All rights reserved. |
36 | * | | 36 | * |
37 | * Redistribution and use in source and binary forms, with or without | | 37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions | | 38 | * modification, are permitted provided that the following conditions |
39 | * are met: | | 39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright | | 40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. | | 41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright | | 42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the | | 43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. | | 44 | * documentation and/or other materials provided with the distribution. |
45 | * | | 45 | * |
46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | | 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | | 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
56 | * SUCH DAMAGE. | | 56 | * SUCH DAMAGE. |
57 | */ | | 57 | */ |
58 | | | 58 | |
59 | /* | | 59 | /* |
60 | * Kernel loader for ELF objects. | | 60 | * Kernel loader for ELF objects. |
61 | * | | 61 | * |
62 | * TODO: adjust kmem_alloc() calls to avoid needless fragmentation. | | 62 | * TODO: adjust kmem_alloc() calls to avoid needless fragmentation. |
63 | */ | | 63 | */ |
64 | | | 64 | |
65 | #include <sys/cdefs.h> | | 65 | #include <sys/cdefs.h> |
66 | __KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.76 2023/01/29 17:20:48 skrll Exp $"); | | 66 | __KERNEL_RCSID(0, "$NetBSD: subr_kobj.c,v 1.77 2023/04/17 08:14:51 skrll Exp $"); |
67 | | | 67 | |
68 | #ifdef _KERNEL_OPT | | 68 | #ifdef _KERNEL_OPT |
69 | #include "opt_modular.h" | | 69 | #include "opt_modular.h" |
70 | #endif | | 70 | #endif |
71 | | | 71 | |
72 | #include <sys/kobj_impl.h> | | 72 | #include <sys/kobj_impl.h> |
73 | | | 73 | |
74 | #ifdef MODULAR | | 74 | #ifdef MODULAR |
75 | | | 75 | |
76 | #include <sys/param.h> | | 76 | #include <sys/param.h> |
| | | 77 | |
77 | #include <sys/kernel.h> | | 78 | #include <sys/kernel.h> |
78 | #include <sys/kmem.h> | | 79 | #include <sys/kmem.h> |
79 | #include <sys/proc.h> | | | |
80 | #include <sys/ksyms.h> | | 80 | #include <sys/ksyms.h> |
81 | #include <sys/module.h> | | 81 | #include <sys/module.h> |
| | | 82 | #include <sys/proc.h> |
82 | | | 83 | |
83 | #include <uvm/uvm_extern.h> | | 84 | #include <uvm/uvm_extern.h> |
84 | | | 85 | |
85 | #define kobj_error(_kobj, ...) \ | | 86 | #define kobj_error(_kobj, ...) \ |
86 | kobj_out(__func__, __LINE__, _kobj, __VA_ARGS__) | | 87 | kobj_out(__func__, __LINE__, _kobj, __VA_ARGS__) |
87 | | | 88 | |
88 | static int kobj_relocate(kobj_t, bool); | | 89 | static int kobj_relocate(kobj_t, bool); |
89 | static int kobj_checksyms(kobj_t, bool); | | 90 | static int kobj_checksyms(kobj_t, bool); |
90 | static void kobj_out(const char *, int, kobj_t, const char *, ...) | | 91 | static void kobj_out(const char *, int, kobj_t, const char *, ...) |
91 | __printflike(4, 5); | | 92 | __printflike(4, 5); |
92 | static void kobj_jettison(kobj_t); | | 93 | static void kobj_jettison(kobj_t); |
93 | static void kobj_free(kobj_t, void *, size_t); | | 94 | static void kobj_free(kobj_t, void *, size_t); |
94 | static void kobj_close(kobj_t); | | 95 | static void kobj_close(kobj_t); |
95 | static int kobj_read_mem(kobj_t, void **, size_t, off_t, bool); | | 96 | static int kobj_read_mem(kobj_t, void **, size_t, off_t, bool); |
96 | static void kobj_close_mem(kobj_t); | | 97 | static void kobj_close_mem(kobj_t); |
97 | | | 98 | |
98 | /* | | 99 | /* |
99 | * kobj_load_mem: | | 100 | * kobj_load_mem: |
100 | * | | 101 | * |
101 | * Load an object already resident in memory. If size is not -1, | | 102 | * Load an object already resident in memory. If size is not -1, |
102 | * the complete size of the object is known. | | 103 | * the complete size of the object is known. |
103 | */ | | 104 | */ |
104 | int | | 105 | int |
105 | kobj_load_mem(kobj_t *kop, const char *name, void *base, ssize_t size) | | 106 | kobj_load_mem(kobj_t *kop, const char *name, void *base, ssize_t size) |
106 | { | | 107 | { |
107 | kobj_t ko; | | 108 | kobj_t ko; |
108 | | | 109 | |
109 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); | | 110 | ko = kmem_zalloc(sizeof(*ko), KM_SLEEP); |
110 | ko->ko_type = KT_MEMORY; | | 111 | ko->ko_type = KT_MEMORY; |
111 | kobj_setname(ko, name); | | 112 | kobj_setname(ko, name); |
112 | ko->ko_source = base; | | 113 | ko->ko_source = base; |
113 | ko->ko_memsize = size; | | 114 | ko->ko_memsize = size; |
114 | ko->ko_read = kobj_read_mem; | | 115 | ko->ko_read = kobj_read_mem; |
115 | ko->ko_close = kobj_close_mem; | | 116 | ko->ko_close = kobj_close_mem; |
116 | | | 117 | |
117 | *kop = ko; | | 118 | *kop = ko; |
118 | return kobj_load(ko); | | 119 | return kobj_load(ko); |
119 | } | | 120 | } |
120 | | | 121 | |
121 | /* | | 122 | /* |
122 | * kobj_close: | | 123 | * kobj_close: |
123 | * | | 124 | * |
124 | * Close an open ELF object. | | 125 | * Close an open ELF object. |
125 | */ | | 126 | */ |
126 | static void | | 127 | static void |
127 | kobj_close(kobj_t ko) | | 128 | kobj_close(kobj_t ko) |
128 | { | | 129 | { |
129 | | | 130 | |
130 | if (ko->ko_source == NULL) { | | 131 | if (ko->ko_source == NULL) { |
131 | return; | | 132 | return; |
132 | } | | 133 | } |
133 | | | 134 | |
134 | ko->ko_close(ko); | | 135 | ko->ko_close(ko); |
135 | ko->ko_source = NULL; | | 136 | ko->ko_source = NULL; |
136 | } | | 137 | } |
137 | | | 138 | |
138 | static void | | 139 | static void |
139 | kobj_close_mem(kobj_t ko) | | 140 | kobj_close_mem(kobj_t ko) |
140 | { | | 141 | { |
141 | | | 142 | |
142 | return; | | 143 | return; |
143 | } | | 144 | } |
144 | | | 145 | |
145 | /* | | 146 | /* |
146 | * kobj_load: | | 147 | * kobj_load: |
147 | * | | 148 | * |
148 | * Load an ELF object and prepare to link into the running kernel | | 149 | * Load an ELF object and prepare to link into the running kernel |
149 | * image. | | 150 | * image. |
150 | */ | | 151 | */ |
151 | int | | 152 | int |
152 | kobj_load(kobj_t ko) | | 153 | kobj_load(kobj_t ko) |
153 | { | | 154 | { |
154 | Elf_Ehdr *hdr; | | 155 | Elf_Ehdr *hdr; |
155 | Elf_Shdr *shdr; | | 156 | Elf_Shdr *shdr; |
156 | Elf_Sym *es; | | 157 | Elf_Sym *es; |
157 | vaddr_t map_text_base; | | 158 | vaddr_t map_text_base; |
158 | vaddr_t map_data_base; | | 159 | vaddr_t map_data_base; |
159 | vaddr_t map_rodata_base; | | 160 | vaddr_t map_rodata_base; |
160 | size_t map_text_size; | | 161 | size_t map_text_size; |
161 | size_t map_data_size; | | 162 | size_t map_data_size; |
162 | size_t map_rodata_size; | | 163 | size_t map_rodata_size; |
163 | int error; | | 164 | int error; |
164 | int symtabindex; | | 165 | int symtabindex; |
165 | int symstrindex; | | 166 | int symstrindex; |
166 | int nsym; | | 167 | int nsym; |
167 | int pb, rl, ra; | | 168 | int pb, rl, ra; |
168 | int alignmask; | | 169 | int alignmask; |
169 | int i, j; | | 170 | int i, j; |
170 | void *addr; | | 171 | void *addr; |
171 | | | 172 | |
172 | KASSERT(ko->ko_type != KT_UNSET); | | 173 | KASSERT(ko->ko_type != KT_UNSET); |
173 | KASSERT(ko->ko_source != NULL); | | 174 | KASSERT(ko->ko_source != NULL); |
174 | | | 175 | |
175 | shdr = NULL; | | 176 | shdr = NULL; |
176 | error = 0; | | 177 | error = 0; |
177 | hdr = NULL; | | 178 | hdr = NULL; |
178 | | | 179 | |
179 | /* | | 180 | /* |
180 | * Read the elf header from the file. | | 181 | * Read the elf header from the file. |
181 | */ | | 182 | */ |
182 | error = ko->ko_read(ko, (void **)&hdr, sizeof(*hdr), 0, true); | | 183 | error = ko->ko_read(ko, (void **)&hdr, sizeof(*hdr), 0, true); |
183 | if (error != 0) { | | 184 | if (error != 0) { |
184 | kobj_error(ko, "read failed %d", error); | | 185 | kobj_error(ko, "read failed %d", error); |
185 | goto out; | | 186 | goto out; |
186 | } | | 187 | } |
187 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) { | | 188 | if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0) { |
188 | kobj_error(ko, "not an ELF object"); | | 189 | kobj_error(ko, "not an ELF object"); |
189 | error = ENOEXEC; | | 190 | error = ENOEXEC; |
190 | goto out; | | 191 | goto out; |
191 | } | | 192 | } |
192 | | | 193 | |
193 | if (hdr->e_ident[EI_VERSION] != EV_CURRENT || | | 194 | if (hdr->e_ident[EI_VERSION] != EV_CURRENT || |
194 | hdr->e_version != EV_CURRENT) { | | 195 | hdr->e_version != EV_CURRENT) { |
195 | kobj_error(ko, "unsupported file version %d", | | 196 | kobj_error(ko, "unsupported file version %d", |
196 | hdr->e_ident[EI_VERSION]); | | 197 | hdr->e_ident[EI_VERSION]); |
197 | error = ENOEXEC; | | 198 | error = ENOEXEC; |
198 | goto out; | | 199 | goto out; |
199 | } | | 200 | } |
200 | if (hdr->e_type != ET_REL) { | | 201 | if (hdr->e_type != ET_REL) { |
201 | kobj_error(ko, "unsupported file type %d", hdr->e_type); | | 202 | kobj_error(ko, "unsupported file type %d", hdr->e_type); |
202 | error = ENOEXEC; | | 203 | error = ENOEXEC; |
203 | goto out; | | 204 | goto out; |
204 | } | | 205 | } |
205 | switch (hdr->e_machine) { | | 206 | switch (hdr->e_machine) { |
206 | #if ELFSIZE == 32 | | 207 | #if ELFSIZE == 32 |
207 | ELF32_MACHDEP_ID_CASES | | 208 | ELF32_MACHDEP_ID_CASES |
208 | #elif ELFSIZE == 64 | | 209 | #elif ELFSIZE == 64 |
209 | ELF64_MACHDEP_ID_CASES | | 210 | ELF64_MACHDEP_ID_CASES |
210 | #else | | 211 | #else |
211 | #error not defined | | 212 | #error not defined |
212 | #endif | | 213 | #endif |
213 | default: | | 214 | default: |
214 | kobj_error(ko, "unsupported machine %d", hdr->e_machine); | | 215 | kobj_error(ko, "unsupported machine %d", hdr->e_machine); |
215 | error = ENOEXEC; | | 216 | error = ENOEXEC; |
216 | goto out; | | 217 | goto out; |
217 | } | | 218 | } |
218 | | | 219 | |
219 | ko->ko_nprogtab = 0; | | 220 | ko->ko_nprogtab = 0; |
220 | ko->ko_shdr = 0; | | 221 | ko->ko_shdr = 0; |
221 | ko->ko_nrel = 0; | | 222 | ko->ko_nrel = 0; |
222 | ko->ko_nrela = 0; | | 223 | ko->ko_nrela = 0; |
223 | | | 224 | |
224 | /* | | 225 | /* |
225 | * Allocate and read in the section header. | | 226 | * Allocate and read in the section header. |
226 | */ | | 227 | */ |
227 | if (hdr->e_shnum == 0 || hdr->e_shnum > ELF_MAXSHNUM || | | 228 | if (hdr->e_shnum == 0 || hdr->e_shnum > ELF_MAXSHNUM || |
228 | hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { | | 229 | hdr->e_shoff == 0 || hdr->e_shentsize != sizeof(Elf_Shdr)) { |
229 | kobj_error(ko, "bad sizes"); | | 230 | kobj_error(ko, "bad sizes"); |
230 | error = ENOEXEC; | | 231 | error = ENOEXEC; |
231 | goto out; | | 232 | goto out; |
232 | } | | 233 | } |
233 | ko->ko_shdrsz = hdr->e_shnum * sizeof(Elf_Shdr); | | 234 | ko->ko_shdrsz = hdr->e_shnum * sizeof(Elf_Shdr); |
234 | error = ko->ko_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff, | | 235 | error = ko->ko_read(ko, (void **)&shdr, ko->ko_shdrsz, hdr->e_shoff, |
235 | true); | | 236 | true); |
236 | if (error != 0) { | | 237 | if (error != 0) { |
237 | kobj_error(ko, "read failed %d", error); | | 238 | kobj_error(ko, "read failed %d", error); |
238 | goto out; | | 239 | goto out; |
239 | } | | 240 | } |
240 | ko->ko_shdr = shdr; | | 241 | ko->ko_shdr = shdr; |
241 | | | 242 | |
242 | /* | | 243 | /* |
243 | * Scan the section header for information and table sizing. | | 244 | * Scan the section header for information and table sizing. |
244 | */ | | 245 | */ |
245 | nsym = 0; | | 246 | nsym = 0; |
246 | symtabindex = symstrindex = -1; | | 247 | symtabindex = symstrindex = -1; |
247 | for (i = 0; i < hdr->e_shnum; i++) { | | 248 | for (i = 0; i < hdr->e_shnum; i++) { |
248 | switch (shdr[i].sh_type) { | | 249 | switch (shdr[i].sh_type) { |
249 | case SHT_PROGBITS: | | 250 | case SHT_PROGBITS: |
250 | case SHT_NOBITS: | | 251 | case SHT_NOBITS: |
251 | ko->ko_nprogtab++; | | 252 | ko->ko_nprogtab++; |
252 | break; | | 253 | break; |
253 | case SHT_SYMTAB: | | 254 | case SHT_SYMTAB: |
254 | nsym++; | | 255 | nsym++; |
255 | symtabindex = i; | | 256 | symtabindex = i; |
256 | symstrindex = shdr[i].sh_link; | | 257 | symstrindex = shdr[i].sh_link; |
257 | break; | | 258 | break; |
258 | case SHT_REL: | | 259 | case SHT_REL: |
259 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) | | 260 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) |
260 | continue; | | 261 | continue; |
261 | ko->ko_nrel++; | | 262 | ko->ko_nrel++; |
262 | break; | | 263 | break; |
263 | case SHT_RELA: | | 264 | case SHT_RELA: |
264 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) | | 265 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) |
265 | continue; | | 266 | continue; |
266 | ko->ko_nrela++; | | 267 | ko->ko_nrela++; |
267 | break; | | 268 | break; |
268 | case SHT_STRTAB: | | 269 | case SHT_STRTAB: |
269 | break; | | 270 | break; |
270 | } | | 271 | } |
271 | } | | 272 | } |
272 | if (ko->ko_nprogtab == 0) { | | 273 | if (ko->ko_nprogtab == 0) { |
273 | kobj_error(ko, "file has no contents"); | | 274 | kobj_error(ko, "file has no contents"); |
274 | error = ENOEXEC; | | 275 | error = ENOEXEC; |
275 | goto out; | | 276 | goto out; |
276 | } | | 277 | } |
277 | if (nsym != 1) { | | 278 | if (nsym != 1) { |
278 | /* Only allow one symbol table for now */ | | 279 | /* Only allow one symbol table for now */ |
279 | kobj_error(ko, "file has no valid symbol table"); | | 280 | kobj_error(ko, "file has no valid symbol table"); |
280 | error = ENOEXEC; | | 281 | error = ENOEXEC; |
281 | goto out; | | 282 | goto out; |
282 | } | | 283 | } |
283 | KASSERT(symtabindex != -1); | | 284 | KASSERT(symtabindex != -1); |
284 | KASSERT(symstrindex != -1); | | 285 | KASSERT(symstrindex != -1); |
285 | | | 286 | |
286 | if (symstrindex == SHN_UNDEF || symstrindex >= hdr->e_shnum || | | 287 | if (symstrindex == SHN_UNDEF || symstrindex >= hdr->e_shnum || |
287 | shdr[symstrindex].sh_type != SHT_STRTAB) { | | 288 | shdr[symstrindex].sh_type != SHT_STRTAB) { |
288 | kobj_error(ko, "file has invalid symbol strings"); | | 289 | kobj_error(ko, "file has invalid symbol strings"); |
289 | error = ENOEXEC; | | 290 | error = ENOEXEC; |
290 | goto out; | | 291 | goto out; |
291 | } | | 292 | } |
292 | | | 293 | |
293 | /* | | 294 | /* |
294 | * Allocate space for tracking the load chunks. | | 295 | * Allocate space for tracking the load chunks. |
295 | */ | | 296 | */ |
296 | if (ko->ko_nprogtab != 0) { | | 297 | if (ko->ko_nprogtab != 0) { |
297 | ko->ko_progtab = kmem_zalloc(ko->ko_nprogtab * | | 298 | ko->ko_progtab = kmem_zalloc(ko->ko_nprogtab * |
298 | sizeof(*ko->ko_progtab), KM_SLEEP); | | 299 | sizeof(*ko->ko_progtab), KM_SLEEP); |
299 | if (ko->ko_progtab == NULL) { | | 300 | if (ko->ko_progtab == NULL) { |
300 | error = ENOMEM; | | 301 | error = ENOMEM; |
301 | kobj_error(ko, "out of memory"); | | 302 | kobj_error(ko, "out of memory"); |
302 | goto out; | | 303 | goto out; |
303 | } | | 304 | } |
304 | } | | 305 | } |
305 | if (ko->ko_nrel != 0) { | | 306 | if (ko->ko_nrel != 0) { |
306 | ko->ko_reltab = kmem_zalloc(ko->ko_nrel * | | 307 | ko->ko_reltab = kmem_zalloc(ko->ko_nrel * |
307 | sizeof(*ko->ko_reltab), KM_SLEEP); | | 308 | sizeof(*ko->ko_reltab), KM_SLEEP); |
308 | if (ko->ko_reltab == NULL) { | | 309 | if (ko->ko_reltab == NULL) { |
309 | error = ENOMEM; | | 310 | error = ENOMEM; |
310 | kobj_error(ko, "out of memory"); | | 311 | kobj_error(ko, "out of memory"); |
311 | goto out; | | 312 | goto out; |
312 | } | | 313 | } |
313 | } | | 314 | } |
314 | if (ko->ko_nrela != 0) { | | 315 | if (ko->ko_nrela != 0) { |
315 | ko->ko_relatab = kmem_zalloc(ko->ko_nrela * | | 316 | ko->ko_relatab = kmem_zalloc(ko->ko_nrela * |
316 | sizeof(*ko->ko_relatab), KM_SLEEP); | | 317 | sizeof(*ko->ko_relatab), KM_SLEEP); |
317 | if (ko->ko_relatab == NULL) { | | 318 | if (ko->ko_relatab == NULL) { |
318 | error = ENOMEM; | | 319 | error = ENOMEM; |
319 | kobj_error(ko, "out of memory"); | | 320 | kobj_error(ko, "out of memory"); |
320 | goto out; | | 321 | goto out; |
321 | } | | 322 | } |
322 | } | | 323 | } |
323 | | | 324 | |
324 | /* | | 325 | /* |
325 | * Allocate space for and load the symbol table. | | 326 | * Allocate space for and load the symbol table. |
326 | */ | | 327 | */ |
327 | ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); | | 328 | ko->ko_symcnt = shdr[symtabindex].sh_size / sizeof(Elf_Sym); |
328 | if (ko->ko_symcnt == 0) { | | 329 | if (ko->ko_symcnt == 0) { |
329 | kobj_error(ko, "no symbol table"); | | 330 | kobj_error(ko, "no symbol table"); |
330 | error = ENOEXEC; | | 331 | error = ENOEXEC; |
331 | goto out; | | 332 | goto out; |
332 | } | | 333 | } |
333 | error = ko->ko_read(ko, (void **)&ko->ko_symtab, | | 334 | error = ko->ko_read(ko, (void **)&ko->ko_symtab, |
334 | ko->ko_symcnt * sizeof(Elf_Sym), | | 335 | ko->ko_symcnt * sizeof(Elf_Sym), |
335 | shdr[symtabindex].sh_offset, true); | | 336 | shdr[symtabindex].sh_offset, true); |
336 | if (error != 0) { | | 337 | if (error != 0) { |
337 | kobj_error(ko, "read failed %d", error); | | 338 | kobj_error(ko, "read failed %d", error); |
338 | goto out; | | 339 | goto out; |
339 | } | | 340 | } |
340 | | | 341 | |
341 | /* | | 342 | /* |
342 | * Allocate space for and load the symbol strings. | | 343 | * Allocate space for and load the symbol strings. |
343 | */ | | 344 | */ |
344 | ko->ko_strtabsz = shdr[symstrindex].sh_size; | | 345 | ko->ko_strtabsz = shdr[symstrindex].sh_size; |
345 | if (ko->ko_strtabsz == 0) { | | 346 | if (ko->ko_strtabsz == 0) { |
346 | kobj_error(ko, "no symbol strings"); | | 347 | kobj_error(ko, "no symbol strings"); |
347 | error = ENOEXEC; | | 348 | error = ENOEXEC; |
348 | goto out; | | 349 | goto out; |
349 | } | | 350 | } |
350 | error = ko->ko_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz, | | 351 | error = ko->ko_read(ko, (void *)&ko->ko_strtab, ko->ko_strtabsz, |
351 | shdr[symstrindex].sh_offset, true); | | 352 | shdr[symstrindex].sh_offset, true); |
352 | if (error != 0) { | | 353 | if (error != 0) { |
353 | kobj_error(ko, "read failed %d", error); | | 354 | kobj_error(ko, "read failed %d", error); |
354 | goto out; | | 355 | goto out; |
355 | } | | 356 | } |
356 | | | 357 | |
357 | /* | | 358 | /* |
358 | * Adjust module symbol namespace, if necessary (e.g. with rump) | | 359 | * Adjust module symbol namespace, if necessary (e.g. with rump) |
359 | */ | | 360 | */ |
360 | error = kobj_renamespace(ko->ko_symtab, ko->ko_symcnt, | | 361 | error = kobj_renamespace(ko->ko_symtab, ko->ko_symcnt, |
361 | &ko->ko_strtab, &ko->ko_strtabsz); | | 362 | &ko->ko_strtab, &ko->ko_strtabsz); |
362 | if (error != 0) { | | 363 | if (error != 0) { |
363 | kobj_error(ko, "renamespace failed %d", error); | | 364 | kobj_error(ko, "renamespace failed %d", error); |
364 | goto out; | | 365 | goto out; |
365 | } | | 366 | } |
366 | | | 367 | |
367 | /* | | 368 | /* |
368 | * Do we have a string table for the section names? | | 369 | * Do we have a string table for the section names? |
369 | */ | | 370 | */ |
370 | if (hdr->e_shstrndx != SHN_UNDEF) { | | 371 | if (hdr->e_shstrndx != SHN_UNDEF) { |
371 | if (hdr->e_shstrndx >= hdr->e_shnum) { | | 372 | if (hdr->e_shstrndx >= hdr->e_shnum) { |
372 | kobj_error(ko, "bad shstrndx"); | | 373 | kobj_error(ko, "bad shstrndx"); |
373 | error = ENOEXEC; | | 374 | error = ENOEXEC; |
374 | goto out; | | 375 | goto out; |
375 | } | | 376 | } |
376 | if (shdr[hdr->e_shstrndx].sh_size != 0 && | | 377 | if (shdr[hdr->e_shstrndx].sh_size != 0 && |
377 | shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { | | 378 | shdr[hdr->e_shstrndx].sh_type == SHT_STRTAB) { |
378 | ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size; | | 379 | ko->ko_shstrtabsz = shdr[hdr->e_shstrndx].sh_size; |
379 | error = ko->ko_read(ko, (void **)&ko->ko_shstrtab, | | 380 | error = ko->ko_read(ko, (void **)&ko->ko_shstrtab, |
380 | shdr[hdr->e_shstrndx].sh_size, | | 381 | shdr[hdr->e_shstrndx].sh_size, |
381 | shdr[hdr->e_shstrndx].sh_offset, true); | | 382 | shdr[hdr->e_shstrndx].sh_offset, true); |
382 | if (error != 0) { | | 383 | if (error != 0) { |
383 | kobj_error(ko, "read failed %d", error); | | 384 | kobj_error(ko, "read failed %d", error); |
384 | goto out; | | 385 | goto out; |
385 | } | | 386 | } |
386 | } | | 387 | } |
387 | } | | 388 | } |
388 | | | 389 | |
389 | /* | | 390 | /* |
390 | * Size up code/data(progbits) and bss(nobits). | | 391 | * Size up code/data(progbits) and bss(nobits). |
391 | */ | | 392 | */ |
392 | alignmask = 0; | | 393 | alignmask = 0; |
393 | map_text_size = 0; | | 394 | map_text_size = 0; |
394 | map_data_size = 0; | | 395 | map_data_size = 0; |
395 | map_rodata_size = 0; | | 396 | map_rodata_size = 0; |
396 | for (i = 0; i < hdr->e_shnum; i++) { | | 397 | for (i = 0; i < hdr->e_shnum; i++) { |
397 | if (shdr[i].sh_type != SHT_PROGBITS && | | 398 | if (shdr[i].sh_type != SHT_PROGBITS && |
398 | shdr[i].sh_type != SHT_NOBITS) | | 399 | shdr[i].sh_type != SHT_NOBITS) |
399 | continue; | | 400 | continue; |
400 | alignmask = shdr[i].sh_addralign - 1; | | 401 | alignmask = shdr[i].sh_addralign - 1; |
401 | if ((shdr[i].sh_flags & SHF_EXECINSTR)) { | | 402 | if ((shdr[i].sh_flags & SHF_EXECINSTR)) { |
402 | map_text_size += alignmask; | | 403 | map_text_size += alignmask; |
403 | map_text_size &= ~alignmask; | | 404 | map_text_size &= ~alignmask; |
404 | map_text_size += shdr[i].sh_size; | | 405 | map_text_size += shdr[i].sh_size; |
405 | } else if (!(shdr[i].sh_flags & SHF_WRITE)) { | | 406 | } else if (!(shdr[i].sh_flags & SHF_WRITE)) { |
406 | map_rodata_size += alignmask; | | 407 | map_rodata_size += alignmask; |
407 | map_rodata_size &= ~alignmask; | | 408 | map_rodata_size &= ~alignmask; |
408 | map_rodata_size += shdr[i].sh_size; | | 409 | map_rodata_size += shdr[i].sh_size; |
409 | } else { | | 410 | } else { |
410 | map_data_size += alignmask; | | 411 | map_data_size += alignmask; |
411 | map_data_size &= ~alignmask; | | 412 | map_data_size &= ~alignmask; |
412 | map_data_size += shdr[i].sh_size; | | 413 | map_data_size += shdr[i].sh_size; |
413 | } | | 414 | } |
414 | } | | 415 | } |
415 | | | 416 | |
416 | if (map_text_size == 0) { | | 417 | if (map_text_size == 0) { |
417 | kobj_error(ko, "no text"); | | 418 | kobj_error(ko, "no text"); |
418 | error = ENOEXEC; | | 419 | error = ENOEXEC; |
419 | goto out; | | 420 | goto out; |
420 | } | | 421 | } |
421 | | | 422 | |
422 | if (map_data_size != 0) { | | 423 | if (map_data_size != 0) { |
423 | map_data_base = uvm_km_alloc(module_map, round_page(map_data_size), | | 424 | map_data_base = uvm_km_alloc(module_map, round_page(map_data_size), |
424 | 0, UVM_KMF_WIRED); | | 425 | 0, UVM_KMF_WIRED); |
425 | if (map_data_base == 0) { | | 426 | if (map_data_base == 0) { |
426 | kobj_error(ko, "out of memory"); | | 427 | kobj_error(ko, "out of memory"); |
427 | error = ENOMEM; | | 428 | error = ENOMEM; |
428 | goto out; | | 429 | goto out; |
429 | } | | 430 | } |
430 | ko->ko_data_address = map_data_base; | | 431 | ko->ko_data_address = map_data_base; |
431 | ko->ko_data_size = map_data_size; | | 432 | ko->ko_data_size = map_data_size; |
432 | } else { | | 433 | } else { |
433 | map_data_base = 0; | | 434 | map_data_base = 0; |
434 | ko->ko_data_address = 0; | | 435 | ko->ko_data_address = 0; |
435 | ko->ko_data_size = 0; | | 436 | ko->ko_data_size = 0; |
436 | } | | 437 | } |
437 | | | 438 | |
438 | if (map_rodata_size != 0) { | | 439 | if (map_rodata_size != 0) { |
439 | map_rodata_base = uvm_km_alloc(module_map, round_page(map_rodata_size), | | 440 | map_rodata_base = uvm_km_alloc(module_map, round_page(map_rodata_size), |
440 | 0, UVM_KMF_WIRED); | | 441 | 0, UVM_KMF_WIRED); |
441 | if (map_rodata_base == 0) { | | 442 | if (map_rodata_base == 0) { |
442 | kobj_error(ko, "out of memory"); | | 443 | kobj_error(ko, "out of memory"); |
443 | error = ENOMEM; | | 444 | error = ENOMEM; |
444 | goto out; | | 445 | goto out; |
445 | } | | 446 | } |
446 | ko->ko_rodata_address = map_rodata_base; | | 447 | ko->ko_rodata_address = map_rodata_base; |
447 | ko->ko_rodata_size = map_rodata_size; | | 448 | ko->ko_rodata_size = map_rodata_size; |
448 | } else { | | 449 | } else { |
449 | map_rodata_base = 0; | | 450 | map_rodata_base = 0; |
450 | ko->ko_rodata_address = 0; | | 451 | ko->ko_rodata_address = 0; |
451 | ko->ko_rodata_size = 0; | | 452 | ko->ko_rodata_size = 0; |
452 | } | | 453 | } |
453 | | | 454 | |
454 | map_text_base = uvm_km_alloc(module_map, round_page(map_text_size), | | 455 | map_text_base = uvm_km_alloc(module_map, round_page(map_text_size), |
455 | 0, UVM_KMF_WIRED | UVM_KMF_EXEC); | | 456 | 0, UVM_KMF_WIRED | UVM_KMF_EXEC); |
456 | if (map_text_base == 0) { | | 457 | if (map_text_base == 0) { |
457 | kobj_error(ko, "out of memory"); | | 458 | kobj_error(ko, "out of memory"); |
458 | error = ENOMEM; | | 459 | error = ENOMEM; |
459 | goto out; | | 460 | goto out; |
460 | } | | 461 | } |
461 | ko->ko_text_address = map_text_base; | | 462 | ko->ko_text_address = map_text_base; |
462 | ko->ko_text_size = map_text_size; | | 463 | ko->ko_text_size = map_text_size; |
463 | | | 464 | |
464 | /* | | 465 | /* |
465 | * Now load code/data(progbits), zero bss(nobits), allocate space | | 466 | * Now load code/data(progbits), zero bss(nobits), allocate space |
466 | * for and load relocs | | 467 | * for and load relocs |
467 | */ | | 468 | */ |
468 | pb = 0; | | 469 | pb = 0; |
469 | rl = 0; | | 470 | rl = 0; |
470 | ra = 0; | | 471 | ra = 0; |
471 | alignmask = 0; | | 472 | alignmask = 0; |
472 | for (i = 0; i < hdr->e_shnum; i++) { | | 473 | for (i = 0; i < hdr->e_shnum; i++) { |
473 | switch (shdr[i].sh_type) { | | 474 | switch (shdr[i].sh_type) { |
474 | case SHT_PROGBITS: | | 475 | case SHT_PROGBITS: |
475 | case SHT_NOBITS: | | 476 | case SHT_NOBITS: |
476 | alignmask = shdr[i].sh_addralign - 1; | | 477 | alignmask = shdr[i].sh_addralign - 1; |
477 | if ((shdr[i].sh_flags & SHF_EXECINSTR)) { | | 478 | if ((shdr[i].sh_flags & SHF_EXECINSTR)) { |
478 | map_text_base += alignmask; | | 479 | map_text_base += alignmask; |
479 | map_text_base &= ~alignmask; | | 480 | map_text_base &= ~alignmask; |
480 | addr = (void *)map_text_base; | | 481 | addr = (void *)map_text_base; |
481 | map_text_base += shdr[i].sh_size; | | 482 | map_text_base += shdr[i].sh_size; |
482 | } else if (!(shdr[i].sh_flags & SHF_WRITE)) { | | 483 | } else if (!(shdr[i].sh_flags & SHF_WRITE)) { |
483 | map_rodata_base += alignmask; | | 484 | map_rodata_base += alignmask; |
484 | map_rodata_base &= ~alignmask; | | 485 | map_rodata_base &= ~alignmask; |
485 | addr = (void *)map_rodata_base; | | 486 | addr = (void *)map_rodata_base; |
486 | map_rodata_base += shdr[i].sh_size; | | 487 | map_rodata_base += shdr[i].sh_size; |
487 | } else { | | 488 | } else { |
488 | map_data_base += alignmask; | | 489 | map_data_base += alignmask; |
489 | map_data_base &= ~alignmask; | | 490 | map_data_base &= ~alignmask; |
490 | addr = (void *)map_data_base; | | 491 | addr = (void *)map_data_base; |
491 | map_data_base += shdr[i].sh_size; | | 492 | map_data_base += shdr[i].sh_size; |
492 | } | | 493 | } |
493 | | | 494 | |
494 | ko->ko_progtab[pb].addr = addr; | | 495 | ko->ko_progtab[pb].addr = addr; |
495 | if (shdr[i].sh_type == SHT_PROGBITS) { | | 496 | if (shdr[i].sh_type == SHT_PROGBITS) { |
496 | ko->ko_progtab[pb].name = "<<PROGBITS>>"; | | 497 | ko->ko_progtab[pb].name = "<<PROGBITS>>"; |
497 | error = ko->ko_read(ko, &addr, | | 498 | error = ko->ko_read(ko, &addr, |
498 | shdr[i].sh_size, shdr[i].sh_offset, false); | | 499 | shdr[i].sh_size, shdr[i].sh_offset, false); |
499 | if (error != 0) { | | 500 | if (error != 0) { |
500 | kobj_error(ko, "read failed %d", error); | | 501 | kobj_error(ko, "read failed %d", error); |
501 | goto out; | | 502 | goto out; |
502 | } | | 503 | } |
503 | } else { /* SHT_NOBITS */ | | 504 | } else { /* SHT_NOBITS */ |
504 | ko->ko_progtab[pb].name = "<<NOBITS>>"; | | 505 | ko->ko_progtab[pb].name = "<<NOBITS>>"; |
505 | memset(addr, 0, shdr[i].sh_size); | | 506 | memset(addr, 0, shdr[i].sh_size); |
506 | } | | 507 | } |
507 | | | 508 | |
508 | ko->ko_progtab[pb].size = shdr[i].sh_size; | | 509 | ko->ko_progtab[pb].size = shdr[i].sh_size; |
509 | ko->ko_progtab[pb].sec = i; | | 510 | ko->ko_progtab[pb].sec = i; |
510 | if (ko->ko_shstrtab != NULL && shdr[i].sh_name != 0) { | | 511 | if (ko->ko_shstrtab != NULL && shdr[i].sh_name != 0) { |
511 | ko->ko_progtab[pb].name = | | 512 | ko->ko_progtab[pb].name = |
512 | ko->ko_shstrtab + shdr[i].sh_name; | | 513 | ko->ko_shstrtab + shdr[i].sh_name; |
513 | } | | 514 | } |
514 | | | 515 | |
515 | /* Update all symbol values with the offset. */ | | 516 | /* Update all symbol values with the offset. */ |
516 | for (j = 0; j < ko->ko_symcnt; j++) { | | 517 | for (j = 0; j < ko->ko_symcnt; j++) { |
517 | es = &ko->ko_symtab[j]; | | 518 | es = &ko->ko_symtab[j]; |
518 | if (es->st_shndx != i) { | | 519 | if (es->st_shndx != i) { |
519 | continue; | | 520 | continue; |
520 | } | | 521 | } |
521 | es->st_value += (Elf_Addr)addr; | | 522 | es->st_value += (Elf_Addr)addr; |
522 | } | | 523 | } |
523 | pb++; | | 524 | pb++; |
524 | break; | | 525 | break; |
525 | case SHT_REL: | | 526 | case SHT_REL: |
526 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) | | 527 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) |
527 | break; | | 528 | break; |
528 | ko->ko_reltab[rl].size = shdr[i].sh_size; | | 529 | ko->ko_reltab[rl].size = shdr[i].sh_size; |
529 | ko->ko_reltab[rl].size -= | | 530 | ko->ko_reltab[rl].size -= |
530 | shdr[i].sh_size % sizeof(Elf_Rel); | | 531 | shdr[i].sh_size % sizeof(Elf_Rel); |
531 | if (ko->ko_reltab[rl].size != 0) { | | 532 | if (ko->ko_reltab[rl].size != 0) { |
532 | ko->ko_reltab[rl].nrel = | | 533 | ko->ko_reltab[rl].nrel = |
533 | shdr[i].sh_size / sizeof(Elf_Rel); | | 534 | shdr[i].sh_size / sizeof(Elf_Rel); |
534 | ko->ko_reltab[rl].sec = shdr[i].sh_info; | | 535 | ko->ko_reltab[rl].sec = shdr[i].sh_info; |
535 | error = ko->ko_read(ko, | | 536 | error = ko->ko_read(ko, |
536 | (void **)&ko->ko_reltab[rl].rel, | | 537 | (void **)&ko->ko_reltab[rl].rel, |
537 | ko->ko_reltab[rl].size, | | 538 | ko->ko_reltab[rl].size, |
538 | shdr[i].sh_offset, true); | | 539 | shdr[i].sh_offset, true); |
539 | if (error != 0) { | | 540 | if (error != 0) { |
540 | kobj_error(ko, "read failed %d", | | 541 | kobj_error(ko, "read failed %d", |
541 | error); | | 542 | error); |
542 | goto out; | | 543 | goto out; |
543 | } | | 544 | } |
544 | } | | 545 | } |
545 | rl++; | | 546 | rl++; |
546 | break; | | 547 | break; |
547 | case SHT_RELA: | | 548 | case SHT_RELA: |
548 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) | | 549 | if (shdr[shdr[i].sh_info].sh_type != SHT_PROGBITS) |
549 | break; | | 550 | break; |
550 | ko->ko_relatab[ra].size = shdr[i].sh_size; | | 551 | ko->ko_relatab[ra].size = shdr[i].sh_size; |
551 | ko->ko_relatab[ra].size -= | | 552 | ko->ko_relatab[ra].size -= |
552 | shdr[i].sh_size % sizeof(Elf_Rela); | | 553 | shdr[i].sh_size % sizeof(Elf_Rela); |
553 | if (ko->ko_relatab[ra].size != 0) { | | 554 | if (ko->ko_relatab[ra].size != 0) { |
554 | ko->ko_relatab[ra].nrela = | | 555 | ko->ko_relatab[ra].nrela = |
555 | shdr[i].sh_size / sizeof(Elf_Rela); | | 556 | shdr[i].sh_size / sizeof(Elf_Rela); |
556 | ko->ko_relatab[ra].sec = shdr[i].sh_info; | | 557 | ko->ko_relatab[ra].sec = shdr[i].sh_info; |
557 | error = ko->ko_read(ko, | | 558 | error = ko->ko_read(ko, |
558 | (void **)&ko->ko_relatab[ra].rela, | | 559 | (void **)&ko->ko_relatab[ra].rela, |
559 | shdr[i].sh_size, | | 560 | shdr[i].sh_size, |
560 | shdr[i].sh_offset, true); | | 561 | shdr[i].sh_offset, true); |
561 | if (error != 0) { | | 562 | if (error != 0) { |
562 | kobj_error(ko, "read failed %d", error); | | 563 | kobj_error(ko, "read failed %d", error); |
563 | goto out; | | 564 | goto out; |
564 | } | | 565 | } |
565 | } | | 566 | } |
566 | ra++; | | 567 | ra++; |
567 | break; | | 568 | break; |
568 | default: | | 569 | default: |
569 | break; | | 570 | break; |
570 | } | | 571 | } |
571 | } | | 572 | } |
572 | if (pb != ko->ko_nprogtab) { | | 573 | if (pb != ko->ko_nprogtab) { |
573 | panic("%s:%d: %s: lost progbits", __func__, __LINE__, | | 574 | panic("%s:%d: %s: lost progbits", __func__, __LINE__, |
574 | ko->ko_name); | | 575 | ko->ko_name); |
575 | } | | 576 | } |
576 | if (rl != ko->ko_nrel) { | | 577 | if (rl != ko->ko_nrel) { |
577 | panic("%s:%d: %s: lost rel", __func__, __LINE__, | | 578 | panic("%s:%d: %s: lost rel", __func__, __LINE__, |
578 | ko->ko_name); | | 579 | ko->ko_name); |
579 | } | | 580 | } |
580 | if (ra != ko->ko_nrela) { | | 581 | if (ra != ko->ko_nrela) { |
581 | panic("%s:%d: %s: lost rela", __func__, __LINE__, | | 582 | panic("%s:%d: %s: lost rela", __func__, __LINE__, |
582 | ko->ko_name); | | 583 | ko->ko_name); |
583 | } | | 584 | } |
584 | if (map_text_base != ko->ko_text_address + map_text_size) { | | 585 | if (map_text_base != ko->ko_text_address + map_text_size) { |
585 | panic("%s:%d: %s: map_text_base 0x%lx != address %lx " | | 586 | panic("%s:%d: %s: map_text_base 0x%lx != address %lx " |
586 | "+ map_text_size %ld (0x%lx)\n", | | 587 | "+ map_text_size %ld (0x%lx)\n", |
587 | __func__, __LINE__, ko->ko_name, (long)map_text_base, | | 588 | __func__, __LINE__, ko->ko_name, (long)map_text_base, |
588 | (long)ko->ko_text_address, (long)map_text_size, | | 589 | (long)ko->ko_text_address, (long)map_text_size, |
589 | (long)ko->ko_text_address + map_text_size); | | 590 | (long)ko->ko_text_address + map_text_size); |
590 | } | | 591 | } |
591 | if (map_data_base != ko->ko_data_address + map_data_size) { | | 592 | if (map_data_base != ko->ko_data_address + map_data_size) { |
592 | panic("%s:%d: %s: map_data_base 0x%lx != address %lx " | | 593 | panic("%s:%d: %s: map_data_base 0x%lx != address %lx " |
593 | "+ map_data_size %ld (0x%lx)\n", | | 594 | "+ map_data_size %ld (0x%lx)\n", |
594 | __func__, __LINE__, ko->ko_name, (long)map_data_base, | | 595 | __func__, __LINE__, ko->ko_name, (long)map_data_base, |
595 | (long)ko->ko_data_address, (long)map_data_size, | | 596 | (long)ko->ko_data_address, (long)map_data_size, |
596 | (long)ko->ko_data_address + map_data_size); | | 597 | (long)ko->ko_data_address + map_data_size); |
597 | } | | 598 | } |
598 | if (map_rodata_base != ko->ko_rodata_address + map_rodata_size) { | | 599 | if (map_rodata_base != ko->ko_rodata_address + map_rodata_size) { |
599 | panic("%s:%d: %s: map_rodata_base 0x%lx != address %lx " | | 600 | panic("%s:%d: %s: map_rodata_base 0x%lx != address %lx " |
600 | "+ map_rodata_size %ld (0x%lx)\n", | | 601 | "+ map_rodata_size %ld (0x%lx)\n", |
601 | __func__, __LINE__, ko->ko_name, (long)map_rodata_base, | | 602 | __func__, __LINE__, ko->ko_name, (long)map_rodata_base, |
602 | (long)ko->ko_rodata_address, (long)map_rodata_size, | | 603 | (long)ko->ko_rodata_address, (long)map_rodata_size, |
603 | (long)ko->ko_rodata_address + map_rodata_size); | | 604 | (long)ko->ko_rodata_address + map_rodata_size); |
604 | } | | 605 | } |
605 | | | 606 | |
606 | /* | | 607 | /* |
607 | * Perform local relocations only. Relocations relating to global | | 608 | * Perform local relocations only. Relocations relating to global |
608 | * symbols will be done by kobj_affix(). | | 609 | * symbols will be done by kobj_affix(). |
609 | */ | | 610 | */ |
610 | error = kobj_checksyms(ko, false); | | 611 | error = kobj_checksyms(ko, false); |
611 | if (error) | | 612 | if (error) |
612 | goto out; | | 613 | goto out; |
613 | | | 614 | |
614 | error = kobj_relocate(ko, true); | | 615 | error = kobj_relocate(ko, true); |
615 | if (error) | | 616 | if (error) |
616 | goto out; | | 617 | goto out; |
617 | out: | | 618 | out: |
618 | if (hdr != NULL) { | | 619 | if (hdr != NULL) { |
619 | kobj_free(ko, hdr, sizeof(*hdr)); | | 620 | kobj_free(ko, hdr, sizeof(*hdr)); |
620 | } | | 621 | } |
621 | kobj_close(ko); | | 622 | kobj_close(ko); |
622 | if (error != 0) { | | 623 | if (error != 0) { |
623 | kobj_unload(ko); | | 624 | kobj_unload(ko); |
624 | } | | 625 | } |
625 | | | 626 | |
626 | return error; | | 627 | return error; |
627 | } | | 628 | } |
628 | | | 629 | |
629 | static void | | 630 | static void |
630 | kobj_unload_notify(kobj_t ko, vaddr_t addr, size_t size, const char *note) | | 631 | kobj_unload_notify(kobj_t ko, vaddr_t addr, size_t size, const char *note) |
631 | { | | 632 | { |
632 | if (addr == 0) | | 633 | if (addr == 0) |
633 | return; | | 634 | return; |
634 | | | 635 | |
635 | int error = kobj_machdep(ko, (void *)addr, size, false); | | 636 | int error = kobj_machdep(ko, (void *)addr, size, false); |
636 | if (error) | | 637 | if (error) |
637 | kobj_error(ko, "machine dependent deinit failed (%s) %d", | | 638 | kobj_error(ko, "machine dependent deinit failed (%s) %d", |
638 | note, error); | | 639 | note, error); |
639 | } | | 640 | } |
640 | | | 641 | |
641 | #define KOBJ_SEGMENT_NOTIFY(ko, what) \ | | 642 | #define KOBJ_SEGMENT_NOTIFY(ko, what) \ |
642 | kobj_unload_notify(ko, (ko)->ko_ ## what ## _address, \ | | 643 | kobj_unload_notify(ko, (ko)->ko_ ## what ## _address, \ |
643 | (ko)->ko_ ## what ## _size, # what); | | 644 | (ko)->ko_ ## what ## _size, # what); |
644 | | | 645 | |
645 | #define KOBJ_SEGMENT_FREE(ko, what) \ | | 646 | #define KOBJ_SEGMENT_FREE(ko, what) \ |
646 | do \ | | 647 | do \ |
647 | if ((ko)->ko_ ## what ## _address != 0) \ | | 648 | if ((ko)->ko_ ## what ## _address != 0) \ |
648 | uvm_km_free(module_map, (ko)->ko_ ## what ## _address, \ | | 649 | uvm_km_free(module_map, (ko)->ko_ ## what ## _address, \ |
649 | round_page((ko)->ko_ ## what ## _size), UVM_KMF_WIRED); \ | | 650 | round_page((ko)->ko_ ## what ## _size), UVM_KMF_WIRED); \ |
650 | while (/*CONSTCOND*/ 0) | | 651 | while (/*CONSTCOND*/ 0) |
651 | | | 652 | |
652 | /* | | 653 | /* |
653 | * kobj_unload: | | 654 | * kobj_unload: |
654 | * | | 655 | * |
655 | * Unload an object previously loaded by kobj_load(). | | 656 | * Unload an object previously loaded by kobj_load(). |
656 | */ | | 657 | */ |
657 | void | | 658 | void |
658 | kobj_unload(kobj_t ko) | | 659 | kobj_unload(kobj_t ko) |
659 | { | | 660 | { |
660 | kobj_close(ko); | | 661 | kobj_close(ko); |
661 | kobj_jettison(ko); | | 662 | kobj_jettison(ko); |
662 | | | 663 | |
663 | | | 664 | |
664 | /* | | 665 | /* |
665 | * Notify MD code that a module has been unloaded. | | 666 | * Notify MD code that a module has been unloaded. |
666 | */ | | 667 | */ |
667 | if (ko->ko_loaded) { | | 668 | if (ko->ko_loaded) { |
668 | KOBJ_SEGMENT_NOTIFY(ko, text); | | 669 | KOBJ_SEGMENT_NOTIFY(ko, text); |
669 | KOBJ_SEGMENT_NOTIFY(ko, data); | | 670 | KOBJ_SEGMENT_NOTIFY(ko, data); |
670 | KOBJ_SEGMENT_NOTIFY(ko, rodata); | | 671 | KOBJ_SEGMENT_NOTIFY(ko, rodata); |
671 | } | | 672 | } |
672 | | | 673 | |
673 | KOBJ_SEGMENT_FREE(ko, text); | | 674 | KOBJ_SEGMENT_FREE(ko, text); |
674 | KOBJ_SEGMENT_FREE(ko, data); | | 675 | KOBJ_SEGMENT_FREE(ko, data); |
675 | KOBJ_SEGMENT_FREE(ko, rodata); | | 676 | KOBJ_SEGMENT_FREE(ko, rodata); |
676 | | | 677 | |
677 | if (ko->ko_ksyms == true) { | | 678 | if (ko->ko_ksyms == true) { |
678 | ksyms_modunload(ko->ko_name); | | 679 | ksyms_modunload(ko->ko_name); |
679 | } | | 680 | } |
680 | if (ko->ko_symtab != NULL) { | | 681 | if (ko->ko_symtab != NULL) { |
681 | kobj_free(ko, ko->ko_symtab, ko->ko_symcnt * sizeof(Elf_Sym)); | | 682 | kobj_free(ko, ko->ko_symtab, ko->ko_symcnt * sizeof(Elf_Sym)); |
682 | } | | 683 | } |
683 | if (ko->ko_strtab != NULL) { | | 684 | if (ko->ko_strtab != NULL) { |
684 | kobj_free(ko, ko->ko_strtab, ko->ko_strtabsz); | | 685 | kobj_free(ko, ko->ko_strtab, ko->ko_strtabsz); |
685 | } | | 686 | } |
686 | if (ko->ko_progtab != NULL) { | | 687 | if (ko->ko_progtab != NULL) { |
687 | kobj_free(ko, ko->ko_progtab, ko->ko_nprogtab * | | 688 | kobj_free(ko, ko->ko_progtab, ko->ko_nprogtab * |
688 | sizeof(*ko->ko_progtab)); | | 689 | sizeof(*ko->ko_progtab)); |
689 | ko->ko_progtab = NULL; | | 690 | ko->ko_progtab = NULL; |
690 | } | | 691 | } |
691 | if (ko->ko_shstrtab) { | | 692 | if (ko->ko_shstrtab) { |
692 | kobj_free(ko, ko->ko_shstrtab, ko->ko_shstrtabsz); | | 693 | kobj_free(ko, ko->ko_shstrtab, ko->ko_shstrtabsz); |
693 | ko->ko_shstrtab = NULL; | | 694 | ko->ko_shstrtab = NULL; |
694 | } | | 695 | } |
695 | | | 696 | |
696 | kmem_free(ko, sizeof(*ko)); | | 697 | kmem_free(ko, sizeof(*ko)); |
697 | } | | 698 | } |
698 | | | 699 | |
699 | /* | | 700 | /* |
700 | * kobj_stat: | | 701 | * kobj_stat: |
701 | * | | 702 | * |
702 | * Return size and load address of an object. | | 703 | * Return size and load address of an object. |
703 | */ | | 704 | */ |
704 | int | | 705 | int |
705 | kobj_stat(kobj_t ko, vaddr_t *address, size_t *size) | | 706 | kobj_stat(kobj_t ko, vaddr_t *address, size_t *size) |
706 | { | | 707 | { |
707 | | | 708 | |
708 | if (address != NULL) { | | 709 | if (address != NULL) { |
709 | *address = ko->ko_text_address; | | 710 | *address = ko->ko_text_address; |
710 | } | | 711 | } |
711 | if (size != NULL) { | | 712 | if (size != NULL) { |
712 | *size = ko->ko_text_size; | | 713 | *size = ko->ko_text_size; |
713 | } | | 714 | } |
714 | return 0; | | 715 | return 0; |
715 | } | | 716 | } |
716 | | | 717 | |
717 | /* | | 718 | /* |
718 | * kobj_affix: | | 719 | * kobj_affix: |
719 | * | | 720 | * |
720 | * Set an object's name and perform global relocs. May only be | | 721 | * Set an object's name and perform global relocs. May only be |
721 | * called after the module and any requisite modules are loaded. | | 722 | * called after the module and any requisite modules are loaded. |
722 | */ | | 723 | */ |
723 | int | | 724 | int |
724 | kobj_affix(kobj_t ko, const char *name) | | 725 | kobj_affix(kobj_t ko, const char *name) |
725 | { | | 726 | { |
726 | int error; | | 727 | int error; |
727 | | | 728 | |
728 | KASSERT(ko->ko_ksyms == false); | | 729 | KASSERT(ko->ko_ksyms == false); |
729 | KASSERT(ko->ko_loaded == false); | | 730 | KASSERT(ko->ko_loaded == false); |
730 | | | 731 | |
731 | kobj_setname(ko, name); | | 732 | kobj_setname(ko, name); |
732 | | | 733 | |
733 | /* Cache addresses of undefined symbols. */ | | 734 | /* Cache addresses of undefined symbols. */ |
734 | error = kobj_checksyms(ko, true); | | 735 | error = kobj_checksyms(ko, true); |
735 | if (error) | | 736 | if (error) |
736 | goto out; | | 737 | goto out; |
737 | | | 738 | |
738 | /* Now do global relocations. */ | | 739 | /* Now do global relocations. */ |
739 | error = kobj_relocate(ko, false); | | 740 | error = kobj_relocate(ko, false); |
740 | if (error) | | 741 | if (error) |
741 | goto out; | | 742 | goto out; |
742 | | | 743 | |
743 | /* | | 744 | /* |
744 | * Now that we know the name, register the symbol table. | | 745 | * Now that we know the name, register the symbol table. |
745 | * Do after global relocations because ksyms will pack | | 746 | * Do after global relocations because ksyms will pack |
746 | * the table. | | 747 | * the table. |
747 | */ | | 748 | */ |
748 | ksyms_modload(ko->ko_name, ko->ko_symtab, | | 749 | ksyms_modload(ko->ko_name, ko->ko_symtab, |
749 | ko->ko_symcnt * sizeof(Elf_Sym), ko->ko_strtab, ko->ko_strtabsz); | | 750 | ko->ko_symcnt * sizeof(Elf_Sym), ko->ko_strtab, ko->ko_strtabsz); |
750 | ko->ko_ksyms = true; | | 751 | ko->ko_ksyms = true; |
751 | | | 752 | |
752 | /* Jettison unneeded memory post-link. */ | | 753 | /* Jettison unneeded memory post-link. */ |
753 | kobj_jettison(ko); | | 754 | kobj_jettison(ko); |
754 | | | 755 | |
755 | /* | | 756 | /* |
756 | * Notify MD code that a module has been loaded. | | 757 | * Notify MD code that a module has been loaded. |
757 | * | | 758 | * |
758 | * Most architectures use this opportunity to flush their caches. | | 759 | * Most architectures use this opportunity to flush their caches. |
759 | */ | | 760 | */ |
760 | if (ko->ko_text_address != 0) { | | 761 | if (ko->ko_text_address != 0) { |
761 | error = kobj_machdep(ko, (void *)ko->ko_text_address, | | 762 | error = kobj_machdep(ko, (void *)ko->ko_text_address, |
762 | ko->ko_text_size, true); | | 763 | ko->ko_text_size, true); |
763 | if (error) { | | 764 | if (error) { |
764 | kobj_error(ko, "machine dependent init failed (text)" | | 765 | kobj_error(ko, "machine dependent init failed (text)" |
765 | " %d", error); | | 766 | " %d", error); |
766 | goto out; | | 767 | goto out; |
767 | } | | 768 | } |
768 | } | | 769 | } |
769 | | | 770 | |
770 | if (ko->ko_data_address != 0) { | | 771 | if (ko->ko_data_address != 0) { |
771 | error = kobj_machdep(ko, (void *)ko->ko_data_address, | | 772 | error = kobj_machdep(ko, (void *)ko->ko_data_address, |
772 | ko->ko_data_size, true); | | 773 | ko->ko_data_size, true); |
773 | if (error) { | | 774 | if (error) { |
774 | kobj_error(ko, "machine dependent init failed (data)" | | 775 | kobj_error(ko, "machine dependent init failed (data)" |
775 | " %d", error); | | 776 | " %d", error); |
776 | goto out; | | 777 | goto out; |
777 | } | | 778 | } |
778 | } | | 779 | } |
779 | | | 780 | |
780 | if (ko->ko_rodata_address != 0) { | | 781 | if (ko->ko_rodata_address != 0) { |
781 | error = kobj_machdep(ko, (void *)ko->ko_rodata_address, | | 782 | error = kobj_machdep(ko, (void *)ko->ko_rodata_address, |
782 | ko->ko_rodata_size, true); | | 783 | ko->ko_rodata_size, true); |
783 | if (error) { | | 784 | if (error) { |
784 | kobj_error(ko, "machine dependent init failed (rodata)" | | 785 | kobj_error(ko, "machine dependent init failed (rodata)" |
785 | " %d", error); | | 786 | " %d", error); |
786 | goto out; | | 787 | goto out; |
787 | } | | 788 | } |
788 | } | | 789 | } |
789 | | | 790 | |
790 | ko->ko_loaded = true; | | 791 | ko->ko_loaded = true; |
791 | | | 792 | |
792 | /* Change the memory protections, when needed. */ | | 793 | /* Change the memory protections, when needed. */ |
793 | if (ko->ko_text_address != 0) { | | 794 | if (ko->ko_text_address != 0) { |
794 | uvm_km_protect(module_map, ko->ko_text_address, | | 795 | uvm_km_protect(module_map, ko->ko_text_address, |
795 | ko->ko_text_size, VM_PROT_READ|VM_PROT_EXECUTE); | | 796 | ko->ko_text_size, VM_PROT_READ|VM_PROT_EXECUTE); |
796 | } | | 797 | } |
797 | if (ko->ko_rodata_address != 0) { | | 798 | if (ko->ko_rodata_address != 0) { |
798 | uvm_km_protect(module_map, ko->ko_rodata_address, | | 799 | uvm_km_protect(module_map, ko->ko_rodata_address, |
799 | ko->ko_rodata_size, VM_PROT_READ); | | 800 | ko->ko_rodata_size, VM_PROT_READ); |
800 | } | | 801 | } |
801 | | | 802 | |
802 | /* Success! */ | | 803 | /* Success! */ |
803 | error = 0; | | 804 | error = 0; |
804 | | | 805 | |
805 | out: if (error) { | | 806 | out: if (error) { |
806 | /* If there was an error, destroy the whole object. */ | | 807 | /* If there was an error, destroy the whole object. */ |
807 | kobj_unload(ko); | | 808 | kobj_unload(ko); |
808 | } | | 809 | } |
809 | return error; | | 810 | return error; |
810 | } | | 811 | } |
811 | | | 812 | |
812 | /* | | 813 | /* |
813 | * kobj_find_section: | | 814 | * kobj_find_section: |
814 | * | | 815 | * |
815 | * Given a section name, search the loaded object and return | | 816 | * Given a section name, search the loaded object and return |
816 | * virtual address if present and loaded. | | 817 | * virtual address if present and loaded. |
817 | */ | | 818 | */ |
818 | int | | 819 | int |
819 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) | | 820 | kobj_find_section(kobj_t ko, const char *name, void **addr, size_t *size) |
820 | { | | 821 | { |
821 | int i; | | 822 | int i; |
822 | | | 823 | |
823 | KASSERT(ko->ko_progtab != NULL); | | 824 | KASSERT(ko->ko_progtab != NULL); |
824 | | | 825 | |
825 | for (i = 0; i < ko->ko_nprogtab; i++) { | | 826 | for (i = 0; i < ko->ko_nprogtab; i++) { |
826 | if (strcmp(ko->ko_progtab[i].name, name) == 0) { | | 827 | if (strcmp(ko->ko_progtab[i].name, name) == 0) { |
827 | if (addr != NULL) { | | 828 | if (addr != NULL) { |
828 | *addr = ko->ko_progtab[i].addr; | | 829 | *addr = ko->ko_progtab[i].addr; |
829 | } | | 830 | } |
830 | if (size != NULL) { | | 831 | if (size != NULL) { |
831 | *size = ko->ko_progtab[i].size; | | 832 | *size = ko->ko_progtab[i].size; |
832 | } | | 833 | } |
833 | return 0; | | 834 | return 0; |
834 | } | | 835 | } |
835 | } | | 836 | } |
836 | | | 837 | |
837 | return ENOENT; | | 838 | return ENOENT; |
838 | } | | 839 | } |
839 | | | 840 | |
840 | /* | | 841 | /* |
841 | * kobj_jettison: | | 842 | * kobj_jettison: |
842 | * | | 843 | * |
843 | * Release object data not needed after performing relocations. | | 844 | * Release object data not needed after performing relocations. |
844 | */ | | 845 | */ |
845 | static void | | 846 | static void |
846 | kobj_jettison(kobj_t ko) | | 847 | kobj_jettison(kobj_t ko) |
847 | { | | 848 | { |
848 | int i; | | 849 | int i; |
849 | | | 850 | |
850 | if (ko->ko_reltab != NULL) { | | 851 | if (ko->ko_reltab != NULL) { |
851 | for (i = 0; i < ko->ko_nrel; i++) { | | 852 | for (i = 0; i < ko->ko_nrel; i++) { |
852 | if (ko->ko_reltab[i].rel) { | | 853 | if (ko->ko_reltab[i].rel) { |
853 | kobj_free(ko, ko->ko_reltab[i].rel, | | 854 | kobj_free(ko, ko->ko_reltab[i].rel, |
854 | ko->ko_reltab[i].size); | | 855 | ko->ko_reltab[i].size); |
855 | } | | 856 | } |
856 | } | | 857 | } |
857 | kobj_free(ko, ko->ko_reltab, ko->ko_nrel * | | 858 | kobj_free(ko, ko->ko_reltab, ko->ko_nrel * |
858 | sizeof(*ko->ko_reltab)); | | 859 | sizeof(*ko->ko_reltab)); |
859 | ko->ko_reltab = NULL; | | 860 | ko->ko_reltab = NULL; |
860 | ko->ko_nrel = 0; | | 861 | ko->ko_nrel = 0; |
861 | } | | 862 | } |
862 | if (ko->ko_relatab != NULL) { | | 863 | if (ko->ko_relatab != NULL) { |
863 | for (i = 0; i < ko->ko_nrela; i++) { | | 864 | for (i = 0; i < ko->ko_nrela; i++) { |
864 | if (ko->ko_relatab[i].rela) { | | 865 | if (ko->ko_relatab[i].rela) { |
865 | kobj_free(ko, ko->ko_relatab[i].rela, | | 866 | kobj_free(ko, ko->ko_relatab[i].rela, |
866 | ko->ko_relatab[i].size); | | 867 | ko->ko_relatab[i].size); |
867 | } | | 868 | } |
868 | } | | 869 | } |
869 | kobj_free(ko, ko->ko_relatab, ko->ko_nrela * | | 870 | kobj_free(ko, ko->ko_relatab, ko->ko_nrela * |
870 | sizeof(*ko->ko_relatab)); | | 871 | sizeof(*ko->ko_relatab)); |
871 | ko->ko_relatab = NULL; | | 872 | ko->ko_relatab = NULL; |
872 | ko->ko_nrela = 0; | | 873 | ko->ko_nrela = 0; |
873 | } | | 874 | } |
874 | if (ko->ko_shdr != NULL) { | | 875 | if (ko->ko_shdr != NULL) { |
875 | kobj_free(ko, ko->ko_shdr, ko->ko_shdrsz); | | 876 | kobj_free(ko, ko->ko_shdr, ko->ko_shdrsz); |
876 | ko->ko_shdr = NULL; | | 877 | ko->ko_shdr = NULL; |
877 | } | | 878 | } |
878 | } | | 879 | } |
879 | | | 880 | |
880 | /* | | 881 | /* |
881 | * kobj_sym_lookup: | | 882 | * kobj_sym_lookup: |
882 | * | | 883 | * |
883 | * Symbol lookup function to be used when the symbol index | | 884 | * Symbol lookup function to be used when the symbol index |
884 | * is known (ie during relocation). | | 885 | * is known (ie during relocation). |
885 | */ | | 886 | */ |
886 | int | | 887 | int |
887 | kobj_sym_lookup(kobj_t ko, uintptr_t symidx, Elf_Addr *val) | | 888 | kobj_sym_lookup(kobj_t ko, uintptr_t symidx, Elf_Addr *val) |
888 | { | | 889 | { |
889 | const Elf_Sym *sym; | | 890 | const Elf_Sym *sym; |
890 | const char *symbol; | | 891 | const char *symbol; |
891 | | | 892 | |
892 | sym = ko->ko_symtab + symidx; | | 893 | sym = ko->ko_symtab + symidx; |
893 | | | 894 | |
894 | if (symidx == SHN_ABS || symidx == 0) { | | 895 | if (symidx == SHN_ABS || symidx == 0) { |
895 | *val = (uintptr_t)sym->st_value; | | 896 | *val = (uintptr_t)sym->st_value; |
896 | return 0; | | 897 | return 0; |
897 | } else if (symidx >= ko->ko_symcnt) { | | 898 | } else if (symidx >= ko->ko_symcnt) { |
898 | /* | | 899 | /* |
899 | * Don't even try to lookup the symbol if the index is | | 900 | * Don't even try to lookup the symbol if the index is |
900 | * bogus. | | 901 | * bogus. |
901 | */ | | 902 | */ |
902 | kobj_error(ko, "symbol index %ju out of range", | | 903 | kobj_error(ko, "symbol index %ju out of range", |
903 | (uintmax_t)symidx); | | 904 | (uintmax_t)symidx); |
904 | return EINVAL; | | 905 | return EINVAL; |
905 | } | | 906 | } |
906 | | | 907 | |
907 | /* Quick answer if there is a definition included. */ | | 908 | /* Quick answer if there is a definition included. */ |
908 | if (sym->st_shndx != SHN_UNDEF) { | | 909 | if (sym->st_shndx != SHN_UNDEF) { |
909 | *val = (uintptr_t)sym->st_value; | | 910 | *val = (uintptr_t)sym->st_value; |
910 | return 0; | | 911 | return 0; |
911 | } | | 912 | } |
912 | | | 913 | |
913 | /* If we get here, then it is undefined and needs a lookup. */ | | 914 | /* If we get here, then it is undefined and needs a lookup. */ |
914 | switch (ELF_ST_BIND(sym->st_info)) { | | 915 | switch (ELF_ST_BIND(sym->st_info)) { |
915 | case STB_LOCAL: | | 916 | case STB_LOCAL: |
916 | /* Local, but undefined? huh? */ | | 917 | /* Local, but undefined? huh? */ |
917 | kobj_error(ko, "local symbol @%ju undefined", | | 918 | kobj_error(ko, "local symbol @%ju undefined", |
918 | (uintmax_t)symidx); | | 919 | (uintmax_t)symidx); |
919 | return EINVAL; | | 920 | return EINVAL; |
920 | | | 921 | |
921 | case STB_GLOBAL: | | 922 | case STB_GLOBAL: |
922 | /* Relative to Data or Function name */ | | 923 | /* Relative to Data or Function name */ |
923 | symbol = ko->ko_strtab + sym->st_name; | | 924 | symbol = ko->ko_strtab + sym->st_name; |
924 | | | 925 | |
925 | /* Force a lookup failure if the symbol name is bogus. */ | | 926 | /* Force a lookup failure if the symbol name is bogus. */ |
926 | if (*symbol == 0) { | | 927 | if (*symbol == 0) { |
927 | kobj_error(ko, "bad symbol @%ju name", | | 928 | kobj_error(ko, "bad symbol @%ju name", |
928 | (uintmax_t)symidx); | | 929 | (uintmax_t)symidx); |
929 | return EINVAL; | | 930 | return EINVAL; |
930 | } | | 931 | } |
931 | if (sym->st_value == 0) { | | 932 | if (sym->st_value == 0) { |
932 | kobj_error(ko, "%s @%ju: bad value", symbol, | | 933 | kobj_error(ko, "%s @%ju: bad value", symbol, |
933 | (uintmax_t)symidx); | | 934 | (uintmax_t)symidx); |
934 | return EINVAL; | | 935 | return EINVAL; |
935 | } | | 936 | } |
936 | | | 937 | |
937 | *val = (uintptr_t)sym->st_value; | | 938 | *val = (uintptr_t)sym->st_value; |
938 | return 0; | | 939 | return 0; |
939 | | | 940 | |
940 | case STB_WEAK: | | 941 | case STB_WEAK: |
941 | kobj_error(ko, "weak symbol @%ju not supported", | | 942 | kobj_error(ko, "weak symbol @%ju not supported", |
942 | (uintmax_t)symidx); | | 943 | (uintmax_t)symidx); |
943 | return EINVAL; | | 944 | return EINVAL; |
944 | | | 945 | |
945 | default: | | 946 | default: |
946 | kobj_error(ko, "bad binding %#x for symbol @%ju", | | 947 | kobj_error(ko, "bad binding %#x for symbol @%ju", |
947 | ELF_ST_BIND(sym->st_info), (uintmax_t)symidx); | | 948 | ELF_ST_BIND(sym->st_info), (uintmax_t)symidx); |
948 | return EINVAL; | | 949 | return EINVAL; |
949 | } | | 950 | } |
950 | } | | 951 | } |
951 | | | 952 | |
952 | /* | | 953 | /* |
953 | * kobj_findbase: | | 954 | * kobj_findbase: |
954 | * | | 955 | * |
955 | * Return base address of the given section. | | 956 | * Return base address of the given section. |
956 | */ | | 957 | */ |
957 | static uintptr_t | | 958 | static uintptr_t |
958 | kobj_findbase(kobj_t ko, int sec) | | 959 | kobj_findbase(kobj_t ko, int sec) |
959 | { | | 960 | { |
960 | int i; | | 961 | int i; |
961 | | | 962 | |
962 | for (i = 0; i < ko->ko_nprogtab; i++) { | | 963 | for (i = 0; i < ko->ko_nprogtab; i++) { |
963 | if (sec == ko->ko_progtab[i].sec) { | | 964 | if (sec == ko->ko_progtab[i].sec) { |
964 | return (uintptr_t)ko->ko_progtab[i].addr; | | 965 | return (uintptr_t)ko->ko_progtab[i].addr; |
965 | } | | 966 | } |
966 | } | | 967 | } |
967 | return 0; | | 968 | return 0; |
968 | } | | 969 | } |
969 | | | 970 | |
970 | /* | | 971 | /* |
971 | * kobj_checksyms: | | 972 | * kobj_checksyms: |
972 | * | | 973 | * |
973 | * Scan symbol table for duplicates or resolve references to | | 974 | * Scan symbol table for duplicates or resolve references to |
974 | * external symbols. | | 975 | * external symbols. |
975 | */ | | 976 | */ |
976 | static int | | 977 | static int |
977 | kobj_checksyms(kobj_t ko, bool undefined) | | 978 | kobj_checksyms(kobj_t ko, bool undefined) |
978 | { | | 979 | { |
979 | unsigned long rval; | | 980 | unsigned long rval; |
980 | Elf_Sym *sym, *ksym, *ms; | | 981 | Elf_Sym *sym, *ksym, *ms; |
981 | const char *name; | | 982 | const char *name; |
982 | int error; | | 983 | int error; |
983 | | | 984 | |
984 | error = 0; | | 985 | error = 0; |
985 | | | 986 | |
986 | for (ms = (sym = ko->ko_symtab) + ko->ko_symcnt; sym < ms; sym++) { | | 987 | for (ms = (sym = ko->ko_symtab) + ko->ko_symcnt; sym < ms; sym++) { |
987 | /* Check validity of the symbol. */ | | 988 | /* Check validity of the symbol. */ |
988 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL || | | 989 | if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL || |
989 | sym->st_name == 0) | | 990 | sym->st_name == 0) |
990 | continue; | | 991 | continue; |
991 | if (undefined != (sym->st_shndx == SHN_UNDEF)) { | | 992 | if (undefined != (sym->st_shndx == SHN_UNDEF)) { |
992 | continue; | | 993 | continue; |
993 | } | | 994 | } |
994 | | | 995 | |
995 | /* | | 996 | /* |
996 | * Look it up. Don't need to lock, as it is known that | | 997 | * Look it up. Don't need to lock, as it is known that |
997 | * the symbol tables aren't going to change (we hold | | 998 | * the symbol tables aren't going to change (we hold |
998 | * module_lock). | | 999 | * module_lock). |
999 | */ | | 1000 | */ |
1000 | name = ko->ko_strtab + sym->st_name; | | 1001 | name = ko->ko_strtab + sym->st_name; |
1001 | if (ksyms_getval_unlocked(NULL, name, &ksym, &rval, | | 1002 | if (ksyms_getval_unlocked(NULL, name, &ksym, &rval, |
1002 | KSYMS_EXTERN) != 0) { | | 1003 | KSYMS_EXTERN) != 0) { |
1003 | if (undefined) { | | 1004 | if (undefined) { |
1004 | kobj_error(ko, "symbol `%s' not found", | | 1005 | kobj_error(ko, "symbol `%s' not found", |
1005 | name); | | 1006 | name); |
1006 | error = ENOEXEC; | | 1007 | error = ENOEXEC; |
1007 | } | | 1008 | } |
1008 | continue; | | 1009 | continue; |
1009 | } | | 1010 | } |
1010 | | | 1011 | |
1011 | /* Save values of undefined globals. */ | | 1012 | /* Save values of undefined globals. */ |
1012 | if (undefined) { | | 1013 | if (undefined) { |
1013 | if (ksym->st_shndx == SHN_ABS) { | | 1014 | if (ksym->st_shndx == SHN_ABS) { |
1014 | sym->st_shndx = SHN_ABS; | | 1015 | sym->st_shndx = SHN_ABS; |
1015 | } | | 1016 | } |
1016 | sym->st_value = (Elf_Addr)rval; | | 1017 | sym->st_value = (Elf_Addr)rval; |
1017 | continue; | | 1018 | continue; |
1018 | } | | 1019 | } |
1019 | | | 1020 | |
1020 | /* Check (and complain) about differing values. */ | | 1021 | /* Check (and complain) about differing values. */ |
1021 | if (sym->st_value == rval) { | | 1022 | if (sym->st_value == rval) { |
1022 | continue; | | 1023 | continue; |
1023 | } | | 1024 | } |
1024 | if (strcmp(name, "_bss_start") == 0 || | | 1025 | if (strcmp(name, "_bss_start") == 0 || |
1025 | strcmp(name, "__bss_start") == 0 || | | 1026 | strcmp(name, "__bss_start") == 0 || |
1026 | strcmp(name, "_bss_end__") == 0 || | | 1027 | strcmp(name, "_bss_end__") == 0 || |
1027 | strcmp(name, "__bss_end__") == 0 || | | 1028 | strcmp(name, "__bss_end__") == 0 || |
1028 | strcmp(name, "_edata") == 0 || | | 1029 | strcmp(name, "_edata") == 0 || |
1029 | strcmp(name, "_end") == 0 || | | 1030 | strcmp(name, "_end") == 0 || |
1030 | strcmp(name, "__end") == 0 || | | 1031 | strcmp(name, "__end") == 0 || |
1031 | strcmp(name, "__end__") == 0 || | | 1032 | strcmp(name, "__end__") == 0 || |
1032 | strncmp(name, "__start_link_set_", 17) == 0 || | | 1033 | strncmp(name, "__start_link_set_", 17) == 0 || |
1033 | strncmp(name, "__stop_link_set_", 16) == 0) { | | 1034 | strncmp(name, "__stop_link_set_", 16) == 0) { |
1034 | continue; | | 1035 | continue; |
1035 | } | | 1036 | } |
1036 | kobj_error(ko, "global symbol `%s' redefined", | | 1037 | kobj_error(ko, "global symbol `%s' redefined", |
1037 | name); | | 1038 | name); |
1038 | error = ENOEXEC; | | 1039 | error = ENOEXEC; |
1039 | } | | 1040 | } |
1040 | | | 1041 | |
1041 | return error; | | 1042 | return error; |
1042 | } | | 1043 | } |
1043 | | | 1044 | |
1044 | /* | | 1045 | /* |
1045 | * kobj_relocate: | | 1046 | * kobj_relocate: |
1046 | * | | 1047 | * |
1047 | * Resolve relocations for the loaded object. | | 1048 | * Resolve relocations for the loaded object. |
1048 | */ | | 1049 | */ |
1049 | static int | | 1050 | static int |
1050 | kobj_relocate(kobj_t ko, bool local) | | 1051 | kobj_relocate(kobj_t ko, bool local) |
1051 | { | | 1052 | { |
1052 | const Elf_Rel *rellim; | | 1053 | const Elf_Rel *rellim; |
1053 | const Elf_Rel *rel; | | 1054 | const Elf_Rel *rel; |
1054 | const Elf_Rela *relalim; | | 1055 | const Elf_Rela *relalim; |
1055 | const Elf_Rela *rela; | | 1056 | const Elf_Rela *rela; |
1056 | const Elf_Sym *sym; | | 1057 | const Elf_Sym *sym; |
1057 | uintptr_t base; | | 1058 | uintptr_t base; |
1058 | int i, error; | | 1059 | int i, error; |
1059 | uintptr_t symidx; | | 1060 | uintptr_t symidx; |
1060 | | | 1061 | |
1061 | /* | | 1062 | /* |
1062 | * Perform relocations without addend if there are any. | | 1063 | * Perform relocations without addend if there are any. |
1063 | */ | | 1064 | */ |
1064 | for (i = 0; i < ko->ko_nrel; i++) { | | 1065 | for (i = 0; i < ko->ko_nrel; i++) { |
1065 | rel = ko->ko_reltab[i].rel; | | 1066 | rel = ko->ko_reltab[i].rel; |
1066 | if (rel == NULL) { | | 1067 | if (rel == NULL) { |
1067 | continue; | | 1068 | continue; |
1068 | } | | 1069 | } |
1069 | rellim = rel + ko->ko_reltab[i].nrel; | | 1070 | rellim = rel + ko->ko_reltab[i].nrel; |
1070 | base = kobj_findbase(ko, ko->ko_reltab[i].sec); | | 1071 | base = kobj_findbase(ko, ko->ko_reltab[i].sec); |
1071 | if (base == 0) { | | 1072 | if (base == 0) { |
1072 | panic("%s:%d: %s: lost base for e_reltab[%d] sec %d", | | 1073 | panic("%s:%d: %s: lost base for e_reltab[%d] sec %d", |
1073 | __func__, __LINE__, ko->ko_name, i, | | 1074 | __func__, __LINE__, ko->ko_name, i, |
1074 | ko->ko_reltab[i].sec); | | 1075 | ko->ko_reltab[i].sec); |
1075 | } | | 1076 | } |
1076 | for (; rel < rellim; rel++) { | | 1077 | for (; rel < rellim; rel++) { |
1077 | symidx = ELF_R_SYM(rel->r_info); | | 1078 | symidx = ELF_R_SYM(rel->r_info); |
1078 | if (symidx >= ko->ko_symcnt) { | | 1079 | if (symidx >= ko->ko_symcnt) { |
1079 | continue; | | 1080 | continue; |
1080 | } | | 1081 | } |