1 | /* |
---|
2 | * common.c |
---|
3 | * |
---|
4 | * Created on: Aug 11, 2008 |
---|
5 | * Author: Stefan Bucur <stefanb@zytor.com> |
---|
6 | */ |
---|
7 | |
---|
8 | #include <stdio.h> |
---|
9 | #include <elf.h> |
---|
10 | #include <string.h> |
---|
11 | #include <fs.h> |
---|
12 | |
---|
13 | #include <linux/list.h> |
---|
14 | #include <sys/module.h> |
---|
15 | |
---|
16 | #include "elfutils.h" |
---|
17 | #include "common.h" |
---|
18 | |
---|
19 | /** |
---|
20 | * The one and only list of loaded modules |
---|
21 | */ |
---|
22 | LIST_HEAD(modules_head); |
---|
23 | |
---|
24 | // User-space debugging routines |
---|
25 | #ifdef ELF_DEBUG |
---|
26 | void print_elf_ehdr(Elf_Ehdr *ehdr) { |
---|
27 | int i; |
---|
28 | |
---|
29 | fprintf(stderr, "Identification:\t"); |
---|
30 | for (i=0; i < EI_NIDENT; i++) { |
---|
31 | printf("%d ", ehdr->e_ident[i]); |
---|
32 | } |
---|
33 | fprintf(stderr, "\n"); |
---|
34 | fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type); |
---|
35 | fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine); |
---|
36 | fprintf(stderr, "Version:\t%u\n", ehdr->e_version); |
---|
37 | fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry); |
---|
38 | fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff); |
---|
39 | fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff); |
---|
40 | //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags); |
---|
41 | //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf_Ehdr)); |
---|
42 | fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum, |
---|
43 | ehdr->e_shnum); |
---|
44 | } |
---|
45 | |
---|
46 | void print_elf_symbols(struct elf_module *module) { |
---|
47 | unsigned int i; |
---|
48 | Elf_Sym *crt_sym; |
---|
49 | |
---|
50 | for (i = 1; i < module->symtable_size/module->syment_size; i++) |
---|
51 | { |
---|
52 | crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size); |
---|
53 | |
---|
54 | fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value); |
---|
55 | |
---|
56 | } |
---|
57 | } |
---|
58 | #endif //ELF_DEBUG |
---|
59 | |
---|
60 | FILE *findpath(char *name) |
---|
61 | { |
---|
62 | struct path_entry *entry; |
---|
63 | char path[FILENAME_MAX]; |
---|
64 | FILE *f; |
---|
65 | |
---|
66 | f = fopen(name, "rb"); /* for full path */ |
---|
67 | if (f) |
---|
68 | return f; |
---|
69 | |
---|
70 | list_for_each_entry(entry, &PATH, list) { |
---|
71 | bool slash = false; |
---|
72 | |
---|
73 | /* Ensure we have a '/' separator */ |
---|
74 | if (entry->str[strlen(entry->str) - 1] != '/') |
---|
75 | slash = true; |
---|
76 | |
---|
77 | snprintf(path, sizeof(path), "%s%s%s", |
---|
78 | entry->str, slash ? "/" : "", name); |
---|
79 | |
---|
80 | dprintf("findpath: trying \"%s\"\n", path); |
---|
81 | f = fopen(path, "rb"); |
---|
82 | if (f) |
---|
83 | return f; |
---|
84 | } |
---|
85 | |
---|
86 | return NULL; |
---|
87 | } |
---|
88 | |
---|
89 | /* |
---|
90 | * Image files manipulation routines |
---|
91 | */ |
---|
92 | |
---|
93 | int image_load(struct elf_module *module) |
---|
94 | { |
---|
95 | module->u.l._file = findpath(module->name); |
---|
96 | |
---|
97 | if (module->u.l._file == NULL) { |
---|
98 | dprintf("Could not open object file '%s'\n", module->name); |
---|
99 | goto error; |
---|
100 | } |
---|
101 | |
---|
102 | module->u.l._cr_offset = 0; |
---|
103 | |
---|
104 | return 0; |
---|
105 | |
---|
106 | error: |
---|
107 | if (module->u.l._file != NULL) { |
---|
108 | fclose(module->u.l._file); |
---|
109 | module->u.l._file = NULL; |
---|
110 | } |
---|
111 | |
---|
112 | return -1; |
---|
113 | } |
---|
114 | |
---|
115 | |
---|
116 | int image_unload(struct elf_module *module) { |
---|
117 | if (module->u.l._file != NULL) { |
---|
118 | fclose(module->u.l._file); |
---|
119 | module->u.l._file = NULL; |
---|
120 | |
---|
121 | } |
---|
122 | module->u.l._cr_offset = 0; |
---|
123 | |
---|
124 | return 0; |
---|
125 | } |
---|
126 | |
---|
127 | int image_read(void *buff, size_t size, struct elf_module *module) { |
---|
128 | size_t result = fread(buff, size, 1, module->u.l._file); |
---|
129 | |
---|
130 | if (result < 1) |
---|
131 | return -1; |
---|
132 | |
---|
133 | module->u.l._cr_offset += size; |
---|
134 | return 0; |
---|
135 | } |
---|
136 | |
---|
137 | int image_skip(size_t size, struct elf_module *module) { |
---|
138 | void *skip_buff = NULL; |
---|
139 | size_t result; |
---|
140 | |
---|
141 | if (size == 0) |
---|
142 | return 0; |
---|
143 | |
---|
144 | skip_buff = malloc(size); |
---|
145 | result = fread(skip_buff, size, 1, module->u.l._file); |
---|
146 | free(skip_buff); |
---|
147 | |
---|
148 | if (result < 1) |
---|
149 | return -1; |
---|
150 | |
---|
151 | module->u.l._cr_offset += size; |
---|
152 | return 0; |
---|
153 | } |
---|
154 | |
---|
155 | int image_seek(Elf_Off offset, struct elf_module *module) { |
---|
156 | if (offset < module->u.l._cr_offset) // Cannot seek backwards |
---|
157 | return -1; |
---|
158 | |
---|
159 | return image_skip(offset - module->u.l._cr_offset, module); |
---|
160 | } |
---|
161 | |
---|
162 | |
---|
163 | // Initialization of the module subsystem |
---|
164 | int modules_init(void) { |
---|
165 | return 0; |
---|
166 | } |
---|
167 | |
---|
168 | // Termination of the module subsystem |
---|
169 | void modules_term(void) { |
---|
170 | |
---|
171 | } |
---|
172 | |
---|
173 | // Allocates the structure for a new module |
---|
174 | struct elf_module *module_alloc(const char *name) { |
---|
175 | struct elf_module *result = malloc(sizeof(struct elf_module)); |
---|
176 | |
---|
177 | if (!result) { |
---|
178 | dprintf("module: Failed to alloc elf_module\n"); |
---|
179 | return NULL; |
---|
180 | } |
---|
181 | |
---|
182 | memset(result, 0, sizeof(struct elf_module)); |
---|
183 | |
---|
184 | INIT_LIST_HEAD(&result->list); |
---|
185 | INIT_LIST_HEAD(&result->required); |
---|
186 | INIT_LIST_HEAD(&result->dependants); |
---|
187 | |
---|
188 | strncpy(result->name, name, MODULE_NAME_SIZE); |
---|
189 | |
---|
190 | return result; |
---|
191 | } |
---|
192 | |
---|
193 | struct module_dep *module_dep_alloc(struct elf_module *module) { |
---|
194 | struct module_dep *result = malloc(sizeof(struct module_dep)); |
---|
195 | |
---|
196 | INIT_LIST_HEAD (&result->list); |
---|
197 | |
---|
198 | result->module = module; |
---|
199 | |
---|
200 | return result; |
---|
201 | } |
---|
202 | |
---|
203 | struct elf_module *module_find(const char *name) { |
---|
204 | struct elf_module *cr_module; |
---|
205 | |
---|
206 | for_each_module(cr_module) { |
---|
207 | if (strcmp(cr_module->name, name) == 0) |
---|
208 | return cr_module; |
---|
209 | } |
---|
210 | |
---|
211 | return NULL; |
---|
212 | } |
---|
213 | |
---|
214 | |
---|
215 | // Mouli: This is checking the header for 32bit machine |
---|
216 | // Support 64bit architecture as well. |
---|
217 | // Parts of the ELF header checked are common to both ELF32 and ELF64 |
---|
218 | // Adding simple checks for both 32bit and 64bit should work (hopefully) |
---|
219 | // |
---|
220 | // Performs verifications on ELF header to assure that the open file is a |
---|
221 | // valid SYSLINUX ELF module. |
---|
222 | int check_header_common(Elf_Ehdr *elf_hdr) { |
---|
223 | // Check the header magic |
---|
224 | if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 || |
---|
225 | elf_hdr->e_ident[EI_MAG1] != ELFMAG1 || |
---|
226 | elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || |
---|
227 | elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { |
---|
228 | |
---|
229 | dprintf("The file is not an ELF object\n"); |
---|
230 | return -1; |
---|
231 | } |
---|
232 | |
---|
233 | if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 && |
---|
234 | elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) { |
---|
235 | dprintf("Invalid ELF class code\n"); |
---|
236 | return -1; |
---|
237 | } |
---|
238 | |
---|
239 | if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { |
---|
240 | dprintf("Invalid ELF data encoding\n"); |
---|
241 | return -1; |
---|
242 | } |
---|
243 | |
---|
244 | if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || |
---|
245 | elf_hdr->e_version != MODULE_ELF_VERSION) { |
---|
246 | dprintf("Invalid ELF file version\n"); |
---|
247 | return -1; |
---|
248 | } |
---|
249 | |
---|
250 | if (elf_hdr->e_machine != EM_386 && |
---|
251 | elf_hdr->e_machine != EM_X86_64) { |
---|
252 | dprintf("Invalid ELF architecture\n"); |
---|
253 | return -1; |
---|
254 | } |
---|
255 | |
---|
256 | return 0; |
---|
257 | } |
---|
258 | |
---|
259 | |
---|
260 | |
---|
261 | int enforce_dependency(struct elf_module *req, struct elf_module *dep) { |
---|
262 | struct module_dep *crt_dep; |
---|
263 | struct module_dep *new_dep; |
---|
264 | |
---|
265 | list_for_each_entry(crt_dep, &req->dependants, list) { |
---|
266 | if (crt_dep->module == dep) { |
---|
267 | // The dependency is already enforced |
---|
268 | return 0; |
---|
269 | } |
---|
270 | } |
---|
271 | |
---|
272 | new_dep = module_dep_alloc(req); |
---|
273 | list_add(&new_dep->list, &dep->required); |
---|
274 | |
---|
275 | new_dep = module_dep_alloc(dep); |
---|
276 | list_add(&new_dep->list, &req->dependants); |
---|
277 | |
---|
278 | return 0; |
---|
279 | } |
---|
280 | |
---|
281 | int clear_dependency(struct elf_module *req, struct elf_module *dep) { |
---|
282 | struct module_dep *crt_dep = NULL; |
---|
283 | int found = 0; |
---|
284 | |
---|
285 | list_for_each_entry(crt_dep, &req->dependants, list) { |
---|
286 | if (crt_dep->module == dep) { |
---|
287 | found = 1; |
---|
288 | break; |
---|
289 | } |
---|
290 | } |
---|
291 | |
---|
292 | if (found) { |
---|
293 | list_del(&crt_dep->list); |
---|
294 | free(crt_dep); |
---|
295 | } |
---|
296 | |
---|
297 | found = 0; |
---|
298 | |
---|
299 | list_for_each_entry(crt_dep, &dep->required, list) { |
---|
300 | if (crt_dep->module == req) { |
---|
301 | found = 1; |
---|
302 | break; |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | if (found) { |
---|
307 | list_del(&crt_dep->list); |
---|
308 | free(crt_dep); |
---|
309 | } |
---|
310 | |
---|
311 | return 0; |
---|
312 | } |
---|
313 | |
---|
314 | int check_symbols(struct elf_module *module) |
---|
315 | { |
---|
316 | unsigned int i; |
---|
317 | Elf_Sym *crt_sym = NULL, *ref_sym = NULL; |
---|
318 | char *crt_name; |
---|
319 | struct elf_module *crt_module; |
---|
320 | |
---|
321 | int strong_count; |
---|
322 | int weak_count; |
---|
323 | |
---|
324 | for (i = 1; i < module->symtable_size/module->syment_size; i++) |
---|
325 | { |
---|
326 | crt_sym = symbol_get_entry(module, i); |
---|
327 | crt_name = module->str_table + crt_sym->st_name; |
---|
328 | |
---|
329 | strong_count = 0; |
---|
330 | weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK); |
---|
331 | |
---|
332 | for_each_module(crt_module) |
---|
333 | { |
---|
334 | ref_sym = module_find_symbol(crt_name, crt_module); |
---|
335 | |
---|
336 | // If we found a definition for our symbol... |
---|
337 | if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF) |
---|
338 | { |
---|
339 | switch (ELF32_ST_BIND(ref_sym->st_info)) |
---|
340 | { |
---|
341 | case STB_GLOBAL: |
---|
342 | strong_count++; |
---|
343 | break; |
---|
344 | case STB_WEAK: |
---|
345 | weak_count++; |
---|
346 | break; |
---|
347 | } |
---|
348 | } |
---|
349 | } |
---|
350 | |
---|
351 | if (crt_sym->st_shndx == SHN_UNDEF) |
---|
352 | { |
---|
353 | // We have an undefined symbol |
---|
354 | // |
---|
355 | // We use the weak_count to differentiate |
---|
356 | // between Syslinux-derivative-specific |
---|
357 | // functions. For example, unload_pxe() is |
---|
358 | // only provided by PXELINUX, so we mark it as |
---|
359 | // __weak and replace it with a reference to |
---|
360 | // undefined_symbol() on SYSLINUX, EXTLINUX, |
---|
361 | // and ISOLINUX. See perform_relocations(). |
---|
362 | if (strong_count == 0 && weak_count == 0) |
---|
363 | { |
---|
364 | dprintf("Symbol %s is undefined\n", crt_name); |
---|
365 | printf("Undef symbol FAIL: %s\n",crt_name); |
---|
366 | return -1; |
---|
367 | } |
---|
368 | } |
---|
369 | else |
---|
370 | { |
---|
371 | if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL) |
---|
372 | { |
---|
373 | // It's not an error - at relocation, the most recent symbol |
---|
374 | // will be considered |
---|
375 | dprintf("Info: Symbol %s is defined more than once\n", crt_name); |
---|
376 | } |
---|
377 | } |
---|
378 | //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value); |
---|
379 | } |
---|
380 | |
---|
381 | return 0; |
---|
382 | } |
---|
383 | |
---|
384 | int module_unloadable(struct elf_module *module) { |
---|
385 | if (!list_empty(&module->dependants)) |
---|
386 | return 0; |
---|
387 | |
---|
388 | return 1; |
---|
389 | } |
---|
390 | |
---|
391 | |
---|
392 | // Unloads the module from the system and releases all the associated memory |
---|
393 | int _module_unload(struct elf_module *module) { |
---|
394 | struct module_dep *crt_dep, *tmp; |
---|
395 | // Make sure nobody needs us |
---|
396 | if (!module_unloadable(module)) { |
---|
397 | dprintf("Module is required by other modules.\n"); |
---|
398 | return -1; |
---|
399 | } |
---|
400 | |
---|
401 | // Remove any dependency information |
---|
402 | list_for_each_entry_safe(crt_dep, tmp, &module->required, list) { |
---|
403 | clear_dependency(crt_dep->module, module); |
---|
404 | } |
---|
405 | |
---|
406 | // Remove the module from the module list |
---|
407 | list_del_init(&module->list); |
---|
408 | |
---|
409 | // Release the loaded segments or sections |
---|
410 | if (module->module_addr != NULL) { |
---|
411 | elf_free(module->module_addr); |
---|
412 | |
---|
413 | dprintf("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "", |
---|
414 | module->name); |
---|
415 | } |
---|
416 | |
---|
417 | dprintf("Unloading module %s\n", module->name); |
---|
418 | // Release the module structure |
---|
419 | free(module); |
---|
420 | |
---|
421 | return 0; |
---|
422 | } |
---|
423 | |
---|
424 | int module_unload(struct elf_module *module) { |
---|
425 | module_ctor_t *dtor; |
---|
426 | |
---|
427 | for (dtor = module->dtors; dtor && *dtor; dtor++) |
---|
428 | (*dtor) (); |
---|
429 | |
---|
430 | return _module_unload(module); |
---|
431 | } |
---|
432 | |
---|
433 | struct elf_module *unload_modules_since(const char *name) { |
---|
434 | struct elf_module *m, *mod, *begin = NULL; |
---|
435 | |
---|
436 | for_each_module(mod) { |
---|
437 | if (!strcmp(mod->name, name)) { |
---|
438 | begin = mod; |
---|
439 | break; |
---|
440 | } |
---|
441 | } |
---|
442 | |
---|
443 | if (!begin) |
---|
444 | return begin; |
---|
445 | |
---|
446 | for_each_module_safe(mod, m) { |
---|
447 | if (mod == begin) |
---|
448 | break; |
---|
449 | |
---|
450 | if (mod != begin) |
---|
451 | module_unload(mod); |
---|
452 | } |
---|
453 | |
---|
454 | return begin; |
---|
455 | } |
---|
456 | |
---|
457 | static Elf_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) { |
---|
458 | unsigned long h = elf_hash((const unsigned char*)name); |
---|
459 | Elf_Word *cr_word = module->hash_table; |
---|
460 | |
---|
461 | Elf_Word nbucket = *cr_word++; |
---|
462 | cr_word++; // Skip nchain |
---|
463 | |
---|
464 | Elf_Word *bkt = cr_word; |
---|
465 | Elf_Word *chn = cr_word + nbucket; |
---|
466 | |
---|
467 | Elf_Word crt_index = bkt[h % module->hash_table[0]]; |
---|
468 | Elf_Sym *crt_sym; |
---|
469 | |
---|
470 | |
---|
471 | while (crt_index != STN_UNDEF) { |
---|
472 | crt_sym = symbol_get_entry(module, crt_index); |
---|
473 | |
---|
474 | if (strcmp(name, module->str_table + crt_sym->st_name) == 0) |
---|
475 | return crt_sym; |
---|
476 | |
---|
477 | crt_index = chn[crt_index]; |
---|
478 | } |
---|
479 | |
---|
480 | return NULL; |
---|
481 | } |
---|
482 | |
---|
483 | static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) { |
---|
484 | unsigned long h = elf_gnu_hash((const unsigned char*)name); |
---|
485 | |
---|
486 | // Setup code (TODO: Optimize this by computing only once) |
---|
487 | Elf_Word *cr_word = module->ghash_table; |
---|
488 | Elf_Word nbucket = *cr_word++; |
---|
489 | Elf_Word symbias = *cr_word++; |
---|
490 | Elf_Word bitmask_nwords = *cr_word++; |
---|
491 | |
---|
492 | if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) { |
---|
493 | dprintf("Invalid GNU Hash structure\n"); |
---|
494 | return NULL; |
---|
495 | } |
---|
496 | |
---|
497 | Elf_Word gnu_shift = *cr_word++; |
---|
498 | |
---|
499 | Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word; |
---|
500 | cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords; |
---|
501 | |
---|
502 | Elf_Word *gnu_buckets = cr_word; |
---|
503 | cr_word += nbucket; |
---|
504 | |
---|
505 | Elf_Word *gnu_chain_zero = cr_word - symbias; |
---|
506 | |
---|
507 | // Computations |
---|
508 | Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) & |
---|
509 | (bitmask_nwords - 1)]; |
---|
510 | |
---|
511 | unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1); |
---|
512 | unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1); |
---|
513 | |
---|
514 | if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) { |
---|
515 | unsigned long rem; |
---|
516 | Elf_Word bucket; |
---|
517 | |
---|
518 | rem = h % nbucket; |
---|
519 | |
---|
520 | bucket = gnu_buckets[rem]; |
---|
521 | |
---|
522 | if (bucket != 0) { |
---|
523 | const Elf_Word* hasharr = &gnu_chain_zero[bucket]; |
---|
524 | |
---|
525 | do { |
---|
526 | if (((*hasharr ^ h ) >> 1) == 0) { |
---|
527 | Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero)); |
---|
528 | |
---|
529 | if (strcmp(name, module->str_table + crt_sym->st_name) == 0) { |
---|
530 | return crt_sym; |
---|
531 | } |
---|
532 | } |
---|
533 | } while ((*hasharr++ & 1u) == 0); |
---|
534 | } |
---|
535 | } |
---|
536 | |
---|
537 | return NULL; |
---|
538 | } |
---|
539 | |
---|
540 | static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module) |
---|
541 | { |
---|
542 | |
---|
543 | unsigned int i; |
---|
544 | Elf_Sym *crt_sym; |
---|
545 | |
---|
546 | for (i = 1; i < module->symtable_size/module->syment_size; i++) |
---|
547 | { |
---|
548 | crt_sym = symbol_get_entry(module, i); |
---|
549 | if (strcmp(name, module->str_table + crt_sym->st_name) == 0) |
---|
550 | { |
---|
551 | return crt_sym; |
---|
552 | } |
---|
553 | } |
---|
554 | |
---|
555 | return NULL; |
---|
556 | } |
---|
557 | |
---|
558 | Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) { |
---|
559 | Elf_Sym *result = NULL; |
---|
560 | |
---|
561 | if (module->ghash_table != NULL) |
---|
562 | result = module_find_symbol_gnu(name, module); |
---|
563 | |
---|
564 | if (result == NULL) |
---|
565 | { |
---|
566 | if (module->hash_table != NULL) |
---|
567 | { |
---|
568 | //printf("Attempting SYSV Symbol search\n"); |
---|
569 | result = module_find_symbol_sysv(name, module); |
---|
570 | } |
---|
571 | else |
---|
572 | { |
---|
573 | //printf("Attempting Iterative Symbol search\n"); |
---|
574 | result = module_find_symbol_iterate(name, module); |
---|
575 | } |
---|
576 | } |
---|
577 | |
---|
578 | return result; |
---|
579 | } |
---|
580 | |
---|
581 | Elf_Sym *global_find_symbol(const char *name, struct elf_module **module) { |
---|
582 | struct elf_module *crt_module; |
---|
583 | Elf_Sym *crt_sym = NULL; |
---|
584 | Elf_Sym *result = NULL; |
---|
585 | |
---|
586 | for_each_module(crt_module) { |
---|
587 | crt_sym = module_find_symbol(name, crt_module); |
---|
588 | |
---|
589 | if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) { |
---|
590 | switch (ELF32_ST_BIND(crt_sym->st_info)) { |
---|
591 | case STB_GLOBAL: |
---|
592 | if (module != NULL) { |
---|
593 | *module = crt_module; |
---|
594 | } |
---|
595 | return crt_sym; |
---|
596 | case STB_WEAK: |
---|
597 | // Consider only the first weak symbol |
---|
598 | if (result == NULL) { |
---|
599 | if (module != NULL) { |
---|
600 | *module = crt_module; |
---|
601 | } |
---|
602 | result = crt_sym; |
---|
603 | } |
---|
604 | break; |
---|
605 | } |
---|
606 | } |
---|
607 | } |
---|
608 | |
---|
609 | return result; |
---|
610 | } |
---|