📄 eshlibld.c
字号:
"base" pointer from the objects to the library). Luckily, this is not a priority operation; objects that are shared should normally remain shared. */ for (nextshlibpp = &(locals.libs); *nextshlibpp != NULL && *nextshlibpp != obj->base_lib; nextshlibpp = (struct shliblist **) &(nextshlibpp[0]->common.next)) ; if (*nextshlibpp == obj->base_lib) { D_(printk("Found %s (%p)\n", obj->base_lib->common.name, obj->base_lib)); for (nextobjpp = &(nextshlibpp[0]->first_obj); *nextobjpp != NULL && *nextobjpp != obj DB(&& ++i < 500); nextobjpp = ((struct shlib_obj **) &(nextobjpp[0]->common.next))) { D_(printk("Frowning on %s (%p)\n", nextobjpp[0]->common.name, nextobjpp[0])); } DB( /* If the linked list gets trashed. */ if (i == 500) { printk("Too many iterations\n"); fatal_never_tried(); /* Not been here yet. */ }); if (*nextobjpp == obj) { /* Found it. */ struct shlib_obj **depobjp; /* If we actually delete an object, we have to recalculate nextshlibpp and nextobjpp, since they may have gone, perhaps by being depended on through lots of levels. */ int obj_deleted = 0; D_(printk("obj %s found in %s\n", obj->common.name, obj->base_lib->common.name)); /* About to unlink this object. First, go through all objects depended-on and decrease usecount (and possibly free them). Check for usecount == 0 before that, so we properly avoid recursing for circular dependencies. FIXME: There's no check for max recursion here, although it should be "pretty safe" since we got this level of dependencies in the first place, and since this function would have a pretty small stack-frame. */ for (depobjp = obj->shdeps.shdeps; *depobjp != NULL; depobjp++) { D_(printk("Bye to %s #%d\n", depobjp[0]->common.name, depobjp[0]->usecount)); if (depobjp[0]->usecount && --depobjp[0]->usecount == 0) { obj_deleted = 1; shlibobj_free(depobjp); } } /* Maybe recalculate. */ if (obj_deleted) { /* Recalculate nextshlibpp. */ D_(printk("Recalculate ->next lib %p obj %p ... ", nextshlibpp, nextobjpp)); for (nextshlibpp = &(locals.libs); *nextshlibpp != NULL && *nextshlibpp != obj->base_lib; nextshlibpp = (struct shliblist **) &(nextshlibpp[0]->common.next)) ; if (*nextshlibpp == obj->base_lib) { /* Recalculate nextobjpp. */ for (nextobjpp = &(nextshlibpp[0] ->first_obj); *nextobjpp != NULL && *nextobjpp != obj DB(&& ++i < 500) ; nextobjpp = ((struct shlib_obj **) &(nextobjpp[0] ->common.next))) { D_(printk("ReFrowning on" " %s (%p)\n", nextobjpp[0] ->common.name, nextobjpp[0])); } DB( /* If the linked list gets trashed. */ if (i == 500) { printk("Too many iterations\n"); /* Not been here yet. */ fatal_never_tried(); }); if (*nextobjpp != obj) { debug_fatal("Cannot find" " obj %s again\n", obj->common.name); } D_(printk("%p %p\n", nextshlibpp, nextobjpp)); } else { debug_fatal("Cannot find base %s again\n", obj->base_lib->common.name); } } /* If it was the last object, we need to change the "last_next" pointer for this library. */ if (obj->base_lib->last_next == (struct shlib_obj **) &(obj->common.next)) { D_(printk("Was last object, new last is %s\n", (nextshlibpp[0]->first_obj == obj ? "(gone)" : (((struct shlib_obj *) ((char *) nextobjpp - ((unsigned int) (&((struct shlib_obj *)0) ->common.next)))) ->common.name)))); obj->base_lib->last_next = nextobjpp; } *nextobjpp = ((struct shlib_obj *) obj->common.next); /* Did we just remove the only member? */ if (nextshlibpp[0]->first_obj == NULL && *nextshlibpp != &locals.anon_objs) { struct shliblist *shlib = *nextshlibpp; D_(printk("Shlib %s gone, next is %s\n", nextshlibpp[0]->common.name, (shlib->common.next ? shlib->common.next->name : "(gone)"))); *nextshlibpp = ((struct shliblist *) shlib->common.next); /* Free the shliblist. There's nothing hanging in there. */ sym_free(shlib, "last in lib"); } /* Now free the object. Each of the segments needs to be freed too. Note that we use some flavor of kfree here (when __KERNEL__). This is possible since the originally mmapped area was "forgotten" through a call to the [special] do_mforgetmap function. */ if (obj->text_data) { D_(printk("Will free text etc. at %p\n", obj->text_data)); sym_free ((void *) obj->text_data, "text+data(+bss)"); } if (obj->bss) { D_(printk("Will free bss at %p\n", obj->bss)); sym_free ((void *) obj->bss, "bss"); } D_(printk("Object goes at %p\n", obj)); sym_free(obj, "object"); } else { DB(printk("obj %s not found in %s!\n", obj->common.name, obj->base_lib->common.name)); fatal_never_tried(); /* Not been here yet. */ } } else { DB(printk("lib %s not found!\n", obj->base_lib->common.name)); fatal_never_tried(); /* Not been here yet. */ }}/* For the shared objects mentioned in the argument, mark that this was the end of their use by this process. */voidshlibmod_exit(struct shlibdep **shdeps){ struct shlib_obj **objp; if (*shdeps == NULL) return; /* Go through the list of dependencies, and decrease every use-count by one. For those that became 0, perform free-actions. */ for (objp = (struct shlib_obj **) *shdeps; *objp != NULL; objp++) { D_(printk("Exiting use of %s of %s from %d\n", objp[0]->common.name, (objp[0]->base_lib != NULL ? objp[0]->base_lib->common.name : "(preload)"), objp[0]->usecount)); if (--(objp[0]->usecount) == 0) shlibobj_free(objp); } sym_free(*shdeps, "deps"); *shdeps = NULL;}/* For the shared objects mentioned in the argument, say that this process forked and duplicate them (copy and update use count). Return 0 if fail, nonzero for success. */intshlibmod_fork(struct shlibdep **shdeps){ /* We fake it a little here; there is no actual use of any struct shlibdep. */ struct shlib_obj **mydeps = (struct shlib_obj **) *shdeps; struct shlib_obj **objp; struct shlib_obj **tmpobjp; int chunklen;#ifdef RELOC_DEBUG /* We need to clear the debug struct for this task. There is a slight problem in that we do not find it at "current", but rather at "p", which is not attached here, and really is only needed for debug purposes. It can be found by counting back from "shdeps", so we will do that rather than adding function parameters, structure members, or code at the call point. */ struct task_struct *new_current /* No "offsetof()" available, I guess. */ = (struct task_struct *) ((char *) shdeps - ((unsigned int) (&((struct task_struct *)0) ->shlib_deps))); struct task_struct *old_current = current; memset(&(new_current->shlib_dbg), 0, sizeof(new_current->shlib_dbg));#endif if (mydeps == NULL) return 1; /* Go through the list of dependencies, and increase every use count by one. Copy the list itself and store in *shdeps. */ for (objp = mydeps, chunklen = sizeof (*objp); *objp != NULL; objp++) { chunklen += sizeof(*objp); D_(printk("Forking use of %s of %s from %d\n", objp[0]->common.name, (objp[0]->base_lib != NULL ? objp[0]->base_lib->common.name : "(preload)"), objp[0]->usecount)); objp[0]->usecount++; }#ifdef RELOC_DEBUG /* The debug-allocation machinery will use "current". To avoid more ugly hackery, let's just temporarily set it. (No, we don't have SMP, I just kept the guts of the macro since I could not use straight "current"; it's not an lvalue - probably because someone don't want people to assign to it by mistake ;-). */ current_set[smp_processor_id()] = new_current; tmpobjp = sym_malloc(chunklen, "Fork"); current_set[smp_processor_id()] = old_current;#else tmpobjp = sym_malloc(chunklen, "Fork");#endif if (tmpobjp == NULL) { /* If we fail, count down all we updated. */ printk("Failed to allocate room for forking shared libraries");#ifdef RELOC_DEBUG current_set[smp_processor_id()] = new_current; shlibmod_exit(shdeps); current_set[smp_processor_id()] = old_current;#else shlibmod_exit(shdeps);#endif return 0; } memcpy(tmpobjp, mydeps, chunklen); *shdeps = (struct shlibdep *) tmpobjp; return 1;}/* If the dependencies of the shared object are no other than those mentioned in the program (that is, they are a subset of the program objects), return 1, else return 0. */static intmatches_mentioned_dependencies(struct shlib_obj *obj, struct progenv *penv){ struct shlibdep shdeps = obj->shdeps; struct shlib_obj **objp; /* Check for general (dis)allowance. */ if (! /* If dependency (direct or indirect) on bss or data, then euid is >= 0, set to the euid of the process exporting the library. */ (obj->euid < 0 /* So check if we allow this all-around. */ || (penv->env_flags & ALLOW_WRITE_DATA_FLAG) /* Or just for same euid. */ || ((penv->env_flags & ALLOW_WRITE_DATA_SAME_UID_FLAG) && (obj->euid == penv->euid || obj->euid == 0)))) { D_(printk("%s depends on writable data, not allowed for sharing\n", obj->common.name)); return 0; } /* Empty dependencies are good. */ if (shdeps.shdeps == NULL || shdeps.shdeps[0] == NULL) { D_(printk("%s has no dependencies. (Sharing ok).\n", obj->common.name)); return 1; } for (objp = shdeps.shdeps; *objp != NULL; objp++) { struct shlib_obj *depobj = *objp; struct symlist *slistp; /* For non-contained objects, ->libindex is -1, so starting with that makes it right when comparing for "the right lib". */ int i = -1; /* Check if the library is mentioned. */ if (depobj->base_lib != &locals.anon_objs) { int nlibs = penv->nlibs; /* maybe FIXME: There's a weak spot here. We can't check that the path is right for a depended-on library that has not been looked up yet (as in decided-the-right-path for). In this case we have to depend on the choice of Good Names for the libraries, and not only depending on paths to separate them (which would be very unwise anyway, for other reasons too). So if the library is not determined (the meat is not loaded), we'll just check the basename. */ for (i = 0; i < nlibs; i++) { struct libspec *libspc = penv->libs + i; D_(printk(" Checking if %s is %s\n", depobj->base_lib->common.name + 1, libspc->path)); if (strcmp(libspc->path, depobj->base_lib->common.name + 1) == 0) { D_(printk(" %s is straight %s\n", depobj->base_lib->common.name + 1, libspc->path)); break; } else { /* If there was no match with the path, then check if the library is loaded (the path is determined), or if we should try just the basename and see if it fits. */ if (libspc->shlib == (struct shliblist *) NULL) { /* Then the path is unchecked. Check the basenames. */ char *shlibbase = strrchr(depobj-> base_lib-> common.name, '/'); if (shlibbase == NULL) shlibbase = depobj-> base_lib-> common.name; else /* Skip the '/'. */ shlibbase++; if (strcmp(shlibbase, penv->libnames[i]) == 0) { D_(printk("Unchecked %s" "is mentioned\n", shlibbase)); break; } } } } /* If we get here, we either found the correct library name, or ran out of places to look. */ if (i == nlibs) {#if defined(RELOC_DEBUG) || defined(MINIMAL_RELOC_DEBUG) printk("Th
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -