diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-deps.c | 241 | ||||
-rw-r--r-- | elf/dl-load.c | 47 | ||||
-rw-r--r-- | elf/dl-lookup.c | 11 | ||||
-rw-r--r-- | elf/dl-runtime.c | 26 | ||||
-rw-r--r-- | elf/dl-version.c | 15 | ||||
-rw-r--r-- | elf/elf.h | 7 | ||||
-rw-r--r-- | elf/rtld.c | 139 |
7 files changed, 273 insertions, 213 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 3fbb3db..38db767 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -28,6 +28,10 @@ is signaled by the AUXTAG entry in l_info. */ #define AUXTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM \ + DT_EXTRATAGIDX (DT_AUXILIARY)) +/* Whether an shared object references one or more auxiliary objects + is signaled by the AUXTAG entry in l_info. */ +#define FILTERTAG (DT_NUM + DT_PROCNUM + DT_VERSIONTAGNUM \ + + DT_EXTRATAGIDX (DT_FILTER)) /* When loading auxiliary objects we must ignore errors. It's ok if @@ -138,7 +142,7 @@ _dl_map_object_deps (struct link_map *map, { struct link_map *l = runp->map; - if (l->l_info[AUXTAG] || l->l_info[DT_NEEDED]) + if (l->l_info[AUXTAG] || l->l_info[FILTERTAG] || l->l_info[DT_NEEDED]) { const char *strtab = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr); @@ -190,119 +194,87 @@ _dl_map_object_deps (struct link_map *map, dep->l_reserved = 1; } } - else if (d->d_tag == DT_AUXILIARY) + else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER) { char *errstring; const char *objname; + struct list *newp; - /* Store the tag in the argument structure. */ - args.d = d; - - if (_dl_catch_error (&errstring, &objname, openaux, &args)) + if (d->d_tag == DT_AUXILIARY) { - /* We are not interested in the error message. */ - assert (errstring != NULL); - free (errstring); + /* Store the tag in the argument structure. */ + args.d = d; + + /* We must be prepared that the addressed shared + object is not available. */ + if (_dl_catch_error (&errstring, &objname, openaux, &args)) + { + /* We are not interested in the error message. */ + assert (errstring != NULL); + free (errstring); + + /* Simply ignore this error and continue the work. */ + continue; + } } else + /* For filter objects the dependency must be available. */ + args.aux = _dl_map_object (l, strtab + d->d_un.d_val, + (l->l_type == lt_executable + ? lt_library : l->l_type), + trace_mode); + + /* The auxiliary object is actually available. + Incorporate the map in all the lists. */ + + /* Allocate new entry. This always has to be done. */ + newp = alloca (sizeof (struct list)); + + /* Copy the content of the current entry over. */ + memcpy (newp, orig, sizeof (*newp)); + + /* Initialize new entry. */ + orig->done = 0; + orig->map = args.aux; + orig->dup = newp; + + /* We must handle two situations here: the map is new, + so we must add it in all three lists. If the map + is already known, we have two further possibilities: + - if the object is before the current map in the + search list, we do nothing. It is already found + early + - if the object is after the current one, we must + move it just before the current map to make sure + the symbols are found early enough + */ + if (args.aux->l_reserved) { - /* The auxiliary object is actually available. - Incorporate the map in all the lists. */ - - /* Allocate new entry. This always has to be done. */ - struct list *newp = alloca (sizeof (struct list)); - - /* Copy the content of the current entry over. */ - memcpy (newp, orig, sizeof (*newp)); - - /* Initialize new entry. */ - orig->done = 0; - orig->map = args.aux; - orig->dup = newp; - - /* We must handle two situations here: the map is new, - so we must add it in all three lists. If the map - is already known, we have two further possibilities: - - if the object is before the current map in the - search list, we do nothing. It is already found - early - - if the object is after the current one, we must - move it just before the current map to make sure - the symbols are found early enough - */ - if (args.aux->l_reserved) - { - /* The object is already somewhere in the - list. Locate it first. */ - struct list *late; - - /* This object is already in the search list - we are building. Don't add a duplicate - pointer. Release the reference just added - by _dl_map_object. */ - --args.aux->l_opencount; - - for (late = orig; late->unique; late = late->unique) - if (late->unique->map == args.aux) - break; - - if (late->unique) - { - /* The object is somewhere behind the current - position in the search path. We have to - move it to this earlier position. */ - orig->unique = newp; - - /* Now remove the later entry from the unique - list. */ - late->unique = late->unique->unique; - - /* We must move the earlier in the chain. */ - if (args.aux->l_prev) - args.aux->l_prev->l_next = args.aux->l_next; - if (args.aux->l_next) - args.aux->l_next->l_prev = args.aux->l_prev; - - args.aux->l_prev = newp->map->l_prev; - newp->map->l_prev = args.aux; - if (args.aux->l_prev != NULL) - args.aux->l_prev->l_next = args.aux; - args.aux->l_next = newp->map; - } - else - { - /* The object must be somewhere earlier in - the list. That's good, we only have to - insert an entry for the duplicate list. */ - orig->unique = NULL; /* Never used. */ - - /* Now we have a problem. The element pointing - to ORIG in the unique list must point to - NEWP now. This is the only place where we - need this backreference and this situation - is really not that frequent. So we don't - use a double-linked list but instead search - for the preceding element. */ - late = head; - while (late->unique != orig) - late = late->unique; - late->unique = newp; - } - } - else + /* The object is already somewhere in the list. + Locate it first. */ + struct list *late; + + /* This object is already in the search list we + are building. Don't add a duplicate pointer. + Release the reference just added by + _dl_map_object. */ + --args.aux->l_opencount; + + for (late = orig; late->unique; late = late->unique) + if (late->unique->map == args.aux) + break; + + if (late->unique) { - /* This is easy. We just add the symbol right - here. */ + /* The object is somewhere behind the current + position in the search path. We have to + move it to this earlier position. */ orig->unique = newp; - ++nlist; - /* Set the mark bit that says it's already in - the list. */ - args.aux->l_reserved = 1; - - /* The only problem is that in the double linked - list of all objects we don't have this new - object at the correct place. Correct this - here. */ + + /* Now remove the later entry from the unique list. */ + late->unique = late->unique->unique; + + /* We must move the earlier in the chain. */ if (args.aux->l_prev) args.aux->l_prev->l_next = args.aux->l_next; if (args.aux->l_next) @@ -314,19 +286,60 @@ _dl_map_object_deps (struct link_map *map, args.aux->l_prev->l_next = args.aux; args.aux->l_next = newp->map; } + else + { + /* The object must be somewhere earlier in the + list. That's good, we only have to insert + an entry for the duplicate list. */ + orig->unique = NULL; /* Never used. */ + + /* Now we have a problem. The element + pointing to ORIG in the unique list must + point to NEWP now. This is the only place + where we need this backreference and this + situation is really not that frequent. So + we don't use a double-linked list but + instead search for the preceding element. */ + late = head; + while (late->unique != orig) + late = late->unique; + late->unique = newp; + } + } + else + { + /* This is easy. We just add the symbol right here. */ + orig->unique = newp; + ++nlist; + /* Set the mark bit that says it's already in the list. */ + args.aux->l_reserved = 1; + + /* The only problem is that in the double linked + list of all objects we don't have this new + object at the correct place. Correct this here. */ + if (args.aux->l_prev) + args.aux->l_prev->l_next = args.aux->l_next; + if (args.aux->l_next) + args.aux->l_next->l_prev = args.aux->l_prev; + + args.aux->l_prev = newp->map->l_prev; + newp->map->l_prev = args.aux; + if (args.aux->l_prev != NULL) + args.aux->l_prev->l_next = args.aux; + args.aux->l_next = newp->map; + } - /* Move the tail pointers if necessary. */ - if (orig == utail) - utail = newp; - if (orig == dtail) - dtail = newp; + /* Move the tail pointers if necessary. */ + if (orig == utail) + utail = newp; + if (orig == dtail) + dtail = newp; - /* Move on the insert point. */ - orig = newp; + /* Move on the insert point. */ + orig = newp; - /* We always add an entry to the duplicate list. */ - ++nduplist; - } + /* We always add an entry to the duplicate list. */ + ++nduplist; } } else diff --git a/elf/dl-load.c b/elf/dl-load.c index ce3bd9f..9a6aae6 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -406,6 +406,9 @@ _dl_init_paths (void) { fake_path_list = (struct r_search_path_elem **) malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); + if (fake_path_list == NULL) + _dl_signal_error (ENOMEM, NULL, + "cannot create cache for search path"); (void) fillin_rpath (local_strdup (llp), fake_path_list, ":;", __libc_enable_secure ? trusted_dirs : NULL); @@ -901,23 +904,33 @@ _dl_map_object (struct link_map *loader, const char *name, int type, /* Look for this name among those already loaded. */ for (l = _dl_loaded; l; l = l->l_next) - if (l->l_opencount > 0 && _dl_name_match_p (name, l) || - /* If the requested name matches the soname of a loaded object, - use that object. */ - (l->l_info[DT_SONAME] && - ! strcmp (name, (const char *) (l->l_addr + - l->l_info[DT_STRTAB]->d_un.d_ptr + - l->l_info[DT_SONAME]->d_un.d_val)))) - { - /* The object is already loaded. - Just bump its reference count and return it. */ - const char *soname = (const char *) (l->l_addr + - l->l_info[DT_STRTAB]->d_un.d_ptr + - l->l_info[DT_SONAME]->d_un.d_val); - add_name_to_object (l, local_strdup (soname)); - ++l->l_opencount; - return l; - } + { + /* If the requested name matches the soname of a loaded object, + use that object. Elide this check for names that have not + yet been opened. */ + if (l->l_opencount <= 0) + continue; + if (!_dl_name_match_p (name, l)) + { + const char *soname; + + if (l->l_info[DT_SONAME] == NULL) + continue; + + soname = (const char *) (l->l_addr + + l->l_info[DT_STRTAB]->d_un.d_ptr + + l->l_info[DT_SONAME]->d_un.d_val); + if (strcmp (name, soname) != 0) + continue; + + /* We have a match on a new name -- cache it. */ + add_name_to_object (l, local_strdup (soname)); + } + + /* We have a match -- bump the reference count and return it. */ + ++l->l_opencount; + return l; + } if (strchr (name, '/') == NULL) { diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index 4cc1f2d..c3a67ff 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -93,6 +93,10 @@ do_lookup (const char *undef_name, unsigned long int hash, map->l_type == lt_executable) continue; + /* Skip objects without symbol tables. */ + if (map->l_info[DT_SYMTAB] == NULL) + continue; + symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr); strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr); if (map->l_nversions > 0 && map->l_info[VERSTAG (DT_VERSYM)] != NULL) @@ -364,8 +368,13 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name, void _dl_setup_hash (struct link_map *map) { - ElfW(Symndx) *hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr); + ElfW(Symndx) *hash; ElfW(Symndx) nchain; + + if (!map->l_info[DT_HASH]) + return; + hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr); + map->l_nbuckets = *hash++; nchain = *hash++; map->l_buckets = hash; diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c index 8ee1838..46c0e1b 100644 --- a/elf/dl-runtime.c +++ b/elf/dl-runtime.c @@ -87,6 +87,10 @@ _dl_object_relocation_scope (struct link_map *l) # define VERSYMIDX(sym) (DT_NUM + DT_PROCNUM + DT_VERSIONTAGIDX (sym)) #endif +#ifndef ELF_FIXUP_RETURN_VALUE +#define ELF_FIXUP_RETURN_VALUE(map, result) (result) +#endif + /* We need to define the function as a local symbol so that the reference in the trampoline code will be a local PC-relative call. Tell the compiler not to worry that the function appears not to be called. */ @@ -120,6 +124,7 @@ fixup ( const PLTREL *const reloc = (const void *) (l->l_addr + l->l_info[DT_JMPREL]->d_un.d_ptr + reloc_offset); + ElfW(Addr) *const rel_addr = (ElfW(Addr) *)(l->l_addr + reloc->r_offset); /* Set up the scope to find symbols referenced by this object. */ struct link_map **scope = _dl_object_relocation_scope (l); @@ -144,21 +149,17 @@ fixup ( elf_machine_relplt (l, reloc, &symtab[ELFW(R_SYM) (reloc->r_info)], &l->l_versions[ndx], - (void *) (l->l_addr + reloc->r_offset)); + (void *) rel_addr); } else elf_machine_relplt (l, reloc, &symtab[ELFW(R_SYM) (reloc->r_info)], - NULL, (void *) (l->l_addr + reloc->r_offset)); + NULL, (void *) rel_addr); } *_dl_global_scope_end = NULL; /* Return the address that was written by the relocation. */ -#ifdef ELF_FIXUP_RETURNS_ADDRESS - return (ElfW(Addr))(l->l_addr + reloc->r_offset); -#else - return *(ElfW(Addr) *) (l->l_addr + reloc->r_offset); -#endif + return ELF_FIXUP_RETURN_VALUE(l, *rel_addr); } @@ -219,17 +220,10 @@ profile_fixup ( } *_dl_global_scope_end = NULL; - - /* Return the address that was written by the relocation. */ -#ifdef ELF_FIXUP_RETURNS_ADDRESS (*mcount_fct) (retaddr, result); - return &result; /* XXX This cannot work. What to do??? --drepper */ -#else - (*mcount_fct) (retaddr, result); - - return result; -#endif + /* Return the address that was written by the relocation. */ + return ELF_FIXUP_RETURN_VALUE(l, result); } #endif diff --git a/elf/dl-version.c b/elf/dl-version.c index 0675b1c..b5515c8 100644 --- a/elf/dl-version.c +++ b/elf/dl-version.c @@ -155,16 +155,23 @@ int _dl_check_map_versions (struct link_map *map, int verbose) { int result = 0; - const char *strtab = (const char *) (map->l_addr - + map->l_info[DT_STRTAB]->d_un.d_ptr); + const char *strtab; /* Pointer to section with needed versions. */ - ElfW(Dyn) *dyn = map->l_info[VERSTAG (DT_VERNEED)]; + ElfW(Dyn) *dyn; /* Pointer to dynamic section with definitions. */ - ElfW(Dyn) *def = map->l_info[VERSTAG (DT_VERDEF)]; + ElfW(Dyn) *def; /* We need to find out which is the highest version index used in a dependecy. */ unsigned int ndx_high = 0; + /* If we don't have a string table, we must be ok. */ + if (map->l_info[DT_STRTAB] == NULL) + return 0; + strtab = (const char *) (map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr); + + dyn = map->l_info[VERSTAG (DT_VERNEED)]; + def = map->l_info[VERSTAG (DT_VERDEF)]; + if (dyn != NULL) { /* This file requires special versions from its dependencies. */ @@ -783,6 +783,13 @@ typedef struct #define DT_SPARC_PLTFMT 0x70000001 /* .plt format version/type */ #define DT_SPARC_NUM 2 +/* Bits present in AT_HWCAP, primarily for Sparc32. */ + +#define HWCAP_SPARC_FLUSH 1 /* The cpu supports flush insn. */ +#define HWCAP_SPARC_STBAR 2 +#define HWCAP_SPARC_SWAP 4 +#define HWCAP_SPARC_MULDIV 8 + /* MIPS R3000 specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ @@ -53,13 +53,13 @@ static void print_unresolved (int errcode, const char *objname, static void print_missing_version (int errcode, const char *objname, const char *errsting); - int _dl_argc; char **_dl_argv; const char *_dl_rpath; int _dl_verbose; const char *_dl_platform; size_t _dl_platformlen; +unsigned long _dl_hwcap; struct r_search_path *_dl_search_paths; const char *_dl_profile; const char *_dl_profile_output; @@ -80,6 +80,7 @@ static void dl_main (const ElfW(Phdr) *phdr, struct link_map _dl_rtld_map; struct libname_list _dl_rtld_libname; +struct libname_list _dl_rtld_libname2; #ifdef RTLD_START RTLD_START @@ -119,19 +120,22 @@ _dl_start (void *arg) the operating system's program loader where to find the program header table in core. */ - /* Transfer data about ourselves to the permanent link_map structure. */ _dl_rtld_map.l_addr = bootstrap_map.l_addr; _dl_rtld_map.l_ld = bootstrap_map.l_ld; + _dl_rtld_map.l_opencount = 1; memcpy (_dl_rtld_map.l_info, bootstrap_map.l_info, sizeof _dl_rtld_map.l_info); _dl_setup_hash (&_dl_rtld_map); /* Cache the DT_RPATH stored in ld.so itself; this will be the default search path. */ - _dl_rpath = (void *) (_dl_rtld_map.l_addr + - _dl_rtld_map.l_info[DT_STRTAB]->d_un.d_ptr + - _dl_rtld_map.l_info[DT_RPATH]->d_un.d_val); + if (_dl_rtld_map.l_info[DT_STRTAB] && _dl_rtld_map.l_info[DT_RPATH]) + { + _dl_rpath = (void *) (_dl_rtld_map.l_addr + + _dl_rtld_map.l_info[DT_STRTAB]->d_un.d_ptr + + _dl_rtld_map.l_info[DT_RPATH]->d_un.d_val); + } /* Call the OS-dependent function to set up life so we can do things like file access. It will call `dl_main' (below) to do all the real work @@ -416,6 +420,23 @@ of this helper program; chances are you did not intend to run this program.\n", _dl_rtld_libname.name = (const char *) main_map->l_addr + ph->p_vaddr; _dl_rtld_libname.next = NULL; _dl_rtld_map.l_libname = &_dl_rtld_libname; + + /* Ordinarilly, we would get additional names for the loader from + our DT_SONAME. This can't happen if we were actually linked as + a static executable (detect this case when we have no DYNAMIC). + If so, assume the filename component of the interpreter path to + be our SONAME, and add it to our name list. */ + if (_dl_rtld_map.l_ld == NULL) + { + char *p = strrchr (_dl_rtld_libname.name, '/'); + if (p) + { + _dl_rtld_libname2.name = p+1; + _dl_rtld_libname2.next = NULL; + _dl_rtld_libname.next = &_dl_rtld_libname2; + } + } + has_interp = 1; break; } @@ -696,74 +717,70 @@ of this helper program; chances are you did not intend to run this program.\n", for (map = _dl_loaded; map != NULL; map = map->l_next) { - const char *strtab = - (const char *) (map->l_addr - + map->l_info[DT_STRTAB]->d_un.d_ptr); + const char *strtab; ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG]; + ElfW(Verneed) *ent; + + if (dyn == NULL) + continue; + + strtab = (const char *) + (map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr); + ent = (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); - if (dyn != NULL) + if (first) { - ElfW(Verneed) *ent = - (ElfW(Verneed) *) (map->l_addr + dyn->d_un.d_ptr); + _dl_sysdep_message ("\n\tVersion information:\n", NULL); + first = 0; + } - if (first) - { - _dl_sysdep_message ("\n\tVersion information:\n", - NULL); - first = 0; - } + _dl_sysdep_message ("\t", (map->l_name[0] + ? map->l_name : _dl_argv[0]), + ":\n", NULL); + + while (1) + { + ElfW(Vernaux) *aux; + struct link_map *needed; - _dl_sysdep_message ("\t", (map->l_name[0] - ? map->l_name - : _dl_argv[0]), ":\n", - NULL); + needed = find_needed (strtab + ent->vn_file); + aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); while (1) { - ElfW(Vernaux) *aux; - struct link_map *needed; - - needed = find_needed (strtab + ent->vn_file); - aux = (ElfW(Vernaux) *) ((char *) ent + ent->vn_aux); - - while (1) - { - const char *fname = NULL; - - _dl_sysdep_message ("\t\t", - strtab + ent->vn_file, - " (", strtab + aux->vna_name, - ") ", - (aux->vna_flags - & VER_FLG_WEAK - ? "[WEAK] " : ""), - "=> ", NULL); - - if (needed != NULL - && match_version (strtab + aux->vna_name, - needed)) - fname = needed->l_name; - - _dl_sysdep_message (fname ?: "not found", "\n", - NULL); - - if (aux->vna_next == 0) - /* No more symbols. */ - break; - - /* Next symbol. */ - aux = (ElfW(Vernaux) *) ((char *) aux - + aux->vna_next); - } + const char *fname = NULL; + + _dl_sysdep_message ("\t\t", + strtab + ent->vn_file, + " (", strtab + aux->vna_name, + ") ", + (aux->vna_flags + & VER_FLG_WEAK + ? "[WEAK] " : ""), + "=> ", NULL); + + if (needed != NULL + && match_version (strtab+aux->vna_name, needed)) + fname = needed->l_name; + + _dl_sysdep_message (fname ?: "not found", "\n", + NULL); - if (ent->vn_next == 0) - /* No more dependencies. */ + if (aux->vna_next == 0) + /* No more symbols. */ break; - /* Next dependency. */ - ent = (ElfW(Verneed) *) ((char *) ent - + ent->vn_next); + /* Next symbol. */ + aux = (ElfW(Vernaux) *) ((char *) aux + + aux->vna_next); } + + if (ent->vn_next == 0) + /* No more dependencies. */ + break; + + /* Next dependency. */ + ent = (ElfW(Verneed) *) ((char *) ent + ent->vn_next); } } } |