📄 eshlibld.c
字号:
#endif struct shliblist anon_objs; struct shliblist *libs;} locals ={#ifdef RELOC_DEBUG NULL,#endif { { " Anonymous objects", NULL}, NULL, &(locals.anon_objs.first_obj) }, &locals.anon_objs};#endif/* FUNCTIONS *//* Calculate the hash of a string, "return" value of last expression. Hash function stolen from bfd 2.6 - the one in ld-so-1.9.9 sucked; the gas 2.6 variant was slightly worse when resolving sash at one time - YMMV. */static inline unsigned longcalc_hash(const char *s){ unsigned long _hash = 0; unsigned int _len = 0; unsigned int _c; const char *_name = (s); while ((_c = *_name++) != '\0') { _hash += _c + (_c << 17); _hash ^= _hash >> 2; ++_len; } _hash += _len + (_len << 17); _hash ^= _hash >> 2; return _hash % N_HASHTABLE_ENTRIES;}/* Add a symbol to the hash table, when there already is one with the same hash, and obeying order if the existing or "added" symbol is weak (later weaks are ignored, strong symbol overrides any weak). */static int /* inline hurts here - 2.7.2 */hash_add_extended(struct symhashentry *entp, struct symlist *slist, struct symtype *symp, struct progenv *penv){ /* If there was a simple hash-entry, we will need to add *two* new extended ones. */ if (entp->sym != NULL) { struct extended_hashentry *newent; if (strcmp(entp->sym->index + entp->slist->strings, symp->index + slist->strings) == 0) { if (! SYM_IS_WEAK(entp->sym->symtyperaw) || SYM_IS_WEAK(symp->symtyperaw)) return 1; /* It seems we got a strong definition that overrides an earlier weak definition. Then just replace it. */ D_(printk("Strong %s in %s overrides weak %s in %s\n", symp->index + slist->strings, slist->name, entp->sym->index + entp->slist->strings, entp->slist->name)); entp->sym = symp; entp->slist = slist; return 1; } newent = sym_malloc(2*sizeof *newent, "exthash"); if (newent == NULL) { penv->env_flags |= PROG_FATAL_ERROR; return 0; } penv->exthash_next[0] = newent; newent[0].next = newent+1; newent[1].next = NULL; newent[0].this.slist = entp->slist; newent[0].this.sym = entp->sym; newent[1].this.slist = slist; newent[1].this.sym = symp; /* Note that what's in newent[1].next_alloc is irrelevant, since it is not linked into the "allocate" list. */ newent[0].next_alloc = NULL; entp->slist = (struct symlist *) newent; entp->sym = NULL; penv->exthash_next = &(newent[0].next_alloc); return 1; } else { /* There's already an "extended" list. Walk it and check that the same symbol is not there. */ struct extended_hashentry *newent; struct extended_hashentry *eentp; D_(printk("YAE for %s in %s\n", symp->index + slist->strings, slist->name)); for (eentp = (struct extended_hashentry *) entp->slist; eentp->next != NULL; eentp = eentp->next) if (strcmp(eentp->this.sym->index + eentp->this.slist->strings, symp->index + slist->strings) == 0) { if (! SYM_IS_WEAK(eentp->this.sym->symtyperaw) || SYM_IS_WEAK(symp->symtyperaw)) return 1; D_(printk("E Strong %s in %s overrides weak %s in %s\n", symp->index + slist->strings, slist->name, eentp->this.sym->index + eentp->this.slist->strings, eentp->this.slist->name)); eentp->this.sym = symp; eentp->this.slist = slist; return 1; } newent = sym_malloc(sizeof (*newent), "exthashn"); if (newent == NULL) { penv->env_flags |= PROG_FATAL_ERROR; return 0; } eentp->next = newent; newent->this.sym = symp; newent->this.slist = slist; newent->next = NULL; newent->next_alloc = NULL; penv->exthash_next[0] = newent; penv->exthash_next = &(newent->next_alloc); return 1; }}/* Check if a symbol is in the hashtable in an extended (linked list) entry. */static inline struct extended_hashentry *hash_check_extended(struct extended_hashentry *entp, struct symlist *slist, struct symtype *symp){ for (; entp != NULL; entp = entp->next) if (strcmp(entp->this.sym->index + entp->this.slist->strings, symp->index + slist->strings) == 0) return entp; return NULL;}/* When the special symbol that says that all symbols in the program should be exported is encountered, we mark that in the program flags. */static intmark_prog_sym_export(struct symtype *symp, struct symlist *slist __attribute__ ((unused)), struct progenv *penv){ /* This is also some kind of dynlink "provide" mechanism; the program_symbols_symbol gets the value of a "struct shliblist **", which when followed, gives a "struct shliblist *" to its symbols. (We can't put in the "struct shliblist *", as it's not allocated and cannot be allocated yet). This is definitely virtual-memory-unfriendly. */ if ((symp->symtyperaw & 0x1e) != TEXT_SYM && (symp->symtyperaw & 0x1f) != WEAK_T_SYM) return 0; penv->dlibsyms = (struct shlib_obj ***) (symp->value + slist->text); penv->env_flags |= EXPORT_PROGRAM_SYMBOLS_FLAG; return 1;}/* When the special symbol is seen that says that this object can be exported, despite that it has writable data, we mark that in the object flags. */static intmark_cheated(struct symtype *symp __attribute__ ((unused)), struct symlist *slist, struct progenv *penv __attribute__ ((unused))){ slist->flags |= SYML_DEP_CHEAT_SAME; return 1;}/* When the special symbol that means a system call is seen - and it is undefined, we define it to refer to the actual system call. If we would not, the symbol in crt0.o would be found, so the object would refer to stuff in the "main" program object, and therefore cannot be shared. This way, we can have the same crt0.o for static and dynamic linking (which is somewhat necessary since we "compare" the link map to that of a static link). */static intset_system_call(struct symtype *symp, struct symlist *slist __attribute__ ((unused)), struct progenv *penv __attribute__ ((unused))){ extern void system_call(void); /* For unknown symbols with this name, set to kernel entry. */ if ((symp->symtyperaw & 0x1f) == (1 | UNKNOWN_SYM)) { symp->symtyperaw = ABS_SYM;#ifdef __KERNEL__ symp->value = (unsigned long) system_call;#else symp->value = (unsigned long) JIR_SIM_MAGIC;#endif } return 1;}/* When a ctor is found in a library object, the object is marked so we can collect the list later. */static intadd_global_lib_ctor(struct symtype *symp, struct symlist *slist, struct progenv *penv __attribute__ ((unused))){ /* An object with a ctor or dtor must *not* be shared. FIXME: We *could* do that, if we care to manage which ctor or dtor to run *when*; the object usecount and all that. I don't currently see the win, only the headache and multitude of bug hideouts. */ /* We don't allow libraries with more than one ctor. */ if (slist->ctor || ! SYM_IS_KNOWN(symp->symtyperaw) || ((symp->symtyperaw & 0x1f) != WEAK_T_SYM && (symp->symtyperaw & 0x1e) != TEXT_SYM)) { DB(printk("?strange ctor lib symbol 0x%lx at %d\n", symp->symtyperaw, __LINE__)); return 0; } slist->flags |= SYML_DEP_BAD; penv->n_ctors++; slist->ctor = symp; return 1;}/* Just as add_global_lib_ctor, but only works if the object is marked as preloaded. */static intadd_preload_main(struct symtype *symp, struct symlist *slist, struct progenv *penv __attribute__ ((unused))){ if ((slist->flags & (SYML_IS_PRELOAD | SYML_WAS_PRELOAD))) { if ( /* We demand that the symbol is text or weak text for general sanity. And it has to be a symbol *definition* (known symbol), not a symbol *reference*. */ ! SYM_IS_KNOWN(symp->symtyperaw) || (((symp->symtyperaw & 0x1f) != WEAK_T_SYM) && ((symp->symtyperaw & 0x1e) != TEXT_SYM))) { DB(printk("?strange ctor lib list symbol 0x%lx at %d\n", symp->symtyperaw, __LINE__)); /* It was supposed to work in this context, so it was *bad*. Unfortunately, since this is a preload, nobody will notice; all symbols will get values. */ return 0; } } else { /* Not in a preload, just ignore the special meaning. */ return 1; } slist->flags |= SYML_DEP_BAD; slist->ctor = symp; return 1;}/* Add a dtor from a library, similar to a ctor. */static intadd_global_lib_dtor(struct symtype *symp, struct symlist *slist, struct progenv *penv __attribute__ ((unused))){ /* An object with a ctor or dtor must *not* be shared. FIXME: We *could* do that, if we care to manage which ctor or dtor to run *when*; the object usecount and all that. I don't currently see the win, only the headache and multitude of bug hideouts. */ /* We don't allow libraries with more than one dtor. */ if (slist->dtor != NULL || ! SYM_IS_KNOWN(symp->symtyperaw) || ((symp->symtyperaw & 0x1f) != WEAK_T_SYM && (symp->symtyperaw & 0x1e) != TEXT_SYM)) { DB(printk("?strange dtor lib symbol 0x%lx at %d\n", symp->symtyperaw, __LINE__)); return 0; } slist->flags |= SYML_DEP_BAD; slist->dtor = symp; penv->n_dtors++; return 1;}/* This symbol works the other way around; the symbol points to what-to-patch with the list pointer *if* there are ctors or dtors in libraries. Must only be one per program. */static intset_global_lib_ctor_list(struct symtype *symp, struct symlist *slist, struct progenv *penv){ /* We demand that the symbol is text or weak text for general sanity; we should have strict control over it since we write the only library function where it is used. */ if (penv->ctor_listp != NULL || ! SYM_IS_KNOWN(symp->symtyperaw) || (((symp->symtyperaw & 0x1f) != WEAK_T_SYM) && ((symp->symtyperaw & 0x1e) != TEXT_SYM))) { DB(printk("?strange ctor lib list symbol 0x%lx at %d\n", symp->symtyperaw, __LINE__)); return 0; } /* An object using a ctor or dtor list must *not* be shared. */ slist->flags |= SYML_DEP_BAD; penv->ctor_listp = (void ***) (symp->value + slist->text); return 1;}/* Same as above, but for the dtor list. */static intset_global_lib_dtor_list(struct symtype *symp, struct symlist *slist, struct progenv *penv){ /* An object using a ctor or dtor list must *not* be shared. FIXME: The ctor and dtor lists come in no sane order, compared to the remotely sane order imposed when linking statically. */ /* We demand that the symbol is text or weak text for general sanity; we should have strict control over it since we write the only library function where it is used. */ if (penv->dtor_listp != NULL || ! SYM_IS_KNOWN(symp->symtyperaw) || (((symp->symtyperaw & 0x1f) != WEAK_T_SYM) && ((symp->symtyperaw & 0x1e) != TEXT_SYM))) { DB(printk("?strange dtor lib list symbol 0x%lx at %d\n", symp->symtyperaw, __LINE__)); return 0; } /* An object using a ctor or dtor list must *not* be shared. */ slist->flags |= SYML_DEP_BAD; penv->dtor_listp = (void ***) (symp->value + slist->text); return 1;}/* Go through the symbol table for this object, add the symbols to the symbol table, check the special_symbol_handling list and perform the actions mentioned there. Not done for the main program object. Returns 0 if there are any invalid constructs present. */static inthandle_special_symbols(struct symlist *slist, struct progenv *penv){ /* Go through all symbols in this slist and do dirty things with the special ones as specified in "specials": for example libdl marking, cheat marking, ctor/dtor marking. */ struct symtype *symp; struct symtype *symbase; struct symtype *symend; char *strings; int symslen; for (symp = symbase = slist->syms, symslen = slist->symslen, strings = slist->strings, symend = (struct symtype *) ((unsigned char *) symbase + symslen); symp < symend; symp++) { unsigned int i; assert(symp->index < slist->stringlen); /* Only valid (non-debug) symbols. */ if (symp->index) { if (SYM_IS_GLOBAL(symp->symtyperaw) || SYM_IS_KNOWN(symp->symtyperaw)) {#if 0 if (slist->flags & SYML_IS_SHLIB) printk("Checking if %s in %s (%d) is special\n", strings + symp->index, slist->name, symp->symtyperaw&0x1f);#endif for (i = 0; i < sizeof (specials) / sizeof (specials[0]); i++) if ((specials[i].symbol[0] == strings[symp->index]) && (specials[i].symbol[1] == strings[symp->index + 1]) /* Note that we only test a prefix here, so they better be unique, or the ambiguous ones tested in the action function. */ && (strncmp(specials[i].symbol, strings + symp->index, specials[i].symbol_length) == 0) && (specials[i].func(symp, slist, penv) == 0)) { penv->env_flags |= PROG_FATAL_ERROR; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -