/* * Read the archive symbol table. For each symbol in the table, determine * whether that symbol satisfies an unresolved reference, tentative reference, * or a reference that expects hidden or protected visibility. If so, the * corresponding object from the archive is processed. The archive symbol * table is searched until we go through a complete pass without satisfying any * unresolved symbols * * entry: * name - Name of archive * fd - Open file descriptor for archive * adp - Archive descriptor * ofl - output descriptor * found - Address of variable to set to TRUE if any objects are extracted * rej - Rejection descriptor to pass to ld_process_ifl(). * * exit: * Returns FALSE on fatal error. On success, *found will be TRUE * if any object was extracted, rej will be set if any object * was rejected, and TRUE is returned. */ static Boolean ar_extract_bysym(const char *name, int fd, Ar_desc *adp, Ofl_desc *ofl, Boolean *found, Rej_desc *rej) { Elf_Arsym * arsym; Elf * arelf; Ar_aux * aup; Sym_desc * sdp; const char *arname, *arpath; Boolean again = FALSE; uintptr_t err; /* * An archive without a symbol table should not reach this function, * because it can only get past ld_ar_setup() in the case where * the archive is first seen under the influence of '-z allextract'. * That will cause the entire archive to be extracted, and any * subsequent reference to the archive will be ignored by * ld_process_archive(). */ if (adp->ad_start == NULL) { assert(adp->ad_start != NULL); return (TRUE); } /* * Loop through archive symbol table until we make a complete pass * without satisfying an unresolved reference. For each archive * symbol, see if there is a symbol with the same name in ld's * symbol table. If so, and if that symbol is still unresolved or * tentative, process the corresponding archive member. */ do { DBG_CALL(Dbg_file_ar(ofl->ofl_lml, name, again)); DBG_CALL(Dbg_syms_ar_title(ofl->ofl_lml, name, again)); again = FALSE; for (arsym = adp->ad_start, aup = adp->ad_aux; arsym->as_name; ++arsym, ++aup) { Ar_mem *amp; Sym *sym; Boolean visible = TRUE; Boolean vers; Ifl_desc *ifl; /* * If the auxiliary members value indicates that this * member has been processed then this symbol will have * been added to the output file image already or the * object was rejected in which case we don't want to * process it again. */ if (aup->au_mem == FLG_ARMEM_PROC) continue; /* * If the auxiliary symbol element is non-zero lookup * the symbol from the internal symbol table. */ if ((sdp = aup->au_syms) == NULL) { if ((sdp = ld_sym_find(arsym->as_name, /* LINTED */ (Word)arsym->as_hash, NULL, ofl)) == NULL) { DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml, name, arsym)); continue; } aup->au_syms = sdp; } /* * With '-z allextract', all members will be extracted. * * This archive member is a candidate for extraction if * the internal symbol originates from an explicit file, * and represents an undefined or tentative symbol. * * By default, weak references do not cause archive * extraction, however the -zweakextract flag overrides * this default. * * If this symbol has already been bound to a versioned * shared object, but the shared objects version is not * available, then a definition of this symbol from * within the archive is a better candidate. Similarly, * if this symbol has been bound to a shared object, but * the original reference expected hidden or protected * visibility, then a definition of this symbol from * within the archive is a better candidate. */ vers = TRUE; ifl = sdp->sd_file; sym = sdp->sd_sym; if (sdp->sd_ref == REF_DYN_NEED) { uchar_t vis; if (ifl->ifl_vercnt) { Word vndx; Ver_index *vip; vndx = sdp->sd_aux->sa_dverndx; vip = &ifl->ifl_verndx[vndx]; if (!(vip->vi_flags & FLG_VER_AVAIL)) vers = FALSE; } vis = ELF_ST_VISIBILITY(sym->st_other); visible = sym_vis[vis]; } if (((ifl->ifl_flags & FLG_IF_NEEDED) == 0) || (visible && vers && (sym->st_shndx != SHN_UNDEF) && (sym->st_shndx != SHN_COMMON)) || ((ELF_ST_BIND(sym->st_info) == STB_WEAK) && (!(ofl->ofl_flags1 & FLG_OF1_WEAKEXT)))) { DBG_CALL(Dbg_syms_ar_skip(ofl->ofl_lml, name, arsym)); continue; } /* * Determine if we have already extracted this member, * and if so reuse the Ar_mem information. */ if ((amp = aup->au_mem) != 0) { arelf = amp->am_elf; arname = amp->am_name; arpath = amp->am_path; } else { /* * Set up a new elf descriptor for this member. */ if (elf_rand(adp->ad_elf, arsym->as_off) != arsym->as_off) { ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_ARMEM), name, EC_WORD(arsym->as_off), demangle(arsym->as_name)); return (FALSE); } if ((arelf = elf_begin(fd, ELF_C_READ, adp->ad_elf)) == NULL) { ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN), name); return (FALSE); } /* Get member filename */ if ((arname = ar_member_name(name, arelf, ofl)) == NULL) return (FALSE); /* Construct the member's full pathname */ if ((arpath = ar_member_path(name, arname)) == NULL) return (S_ERROR); /* * Determine whether the support libraries wish * to process this open. See comments in * ld_process_open(). */ ld_sup_open(ofl, &arpath, &arname, &fd, (FLG_IF_EXTRACT | FLG_IF_NEEDED), &arelf, adp->ad_elf, arsym->as_off, elf_kind(arelf)); if (arelf == NULL) { /* Ignore this archive member */ aup->au_mem = FLG_ARMEM_PROC; continue; } } /* * The symbol for which this archive member is being * processed may provide a better alternative to the * symbol that is presently known. Two cases are * covered: * * i. The present symbol represents tentative data. * The archive member may provide a data * definition symbol. * ii. The present symbol represents a reference that * has seen a definition within a shared object * dependency, but the reference expects to be * reduced to hidden or protected visibility. */ if ((sym->st_shndx == SHN_COMMON) || (visible == FALSE)) { /* * If we don't already have a member structure * allocate one. */ if (!amp) { if ((amp = libld_calloc(sizeof (Ar_mem), 1)) == NULL) return (FALSE); amp->am_elf = arelf; amp->am_name = arname; amp->am_path = arpath; } DBG_CALL(Dbg_syms_ar_checking(ofl->ofl_lml, name, arname, arsym)); if ((err = process_member(amp, arsym->as_name, sdp, ofl)) == S_ERROR) return (FALSE); /* * If it turns out that we don't need this * member simply initialize all other auxiliary * entries that match this offset with this * members address. In this way we can resuse * this information if we recurse back to this * symbol. */ if (err == 0) { if (aup->au_mem == NULL) ld_ar_member(adp, arsym, aup, amp); continue; } } /* * Process the archive member. Retain any error for * return to the caller. */ DBG_CALL(Dbg_syms_ar_resolve(ofl->ofl_lml, name, arname, arsym)); switch (ar_input(fd, adp, ofl, arelf, arpath, rej)) { case S_ERROR: return (FALSE); case 0: /* * Mark the member as extracted so that we * don't try and process it again on a rescan. */ ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC); continue; } /* * Note that this archive has contributed something * during this specific operation, and also signal * the need to rescan the archive. */ *found = again = TRUE; ld_ar_member(adp, arsym, aup, FLG_ARMEM_PROC); } } while (again); return (TRUE); }
/* * Enter a mapfile defined symbol into the given version * * entry: * mf - Mapfile descriptor * ms - Information related to symbol being added to version * * exit: * On success, returns true. On failure that requires an immediate * halt, returns false. * * On failure that requires eventual halt, but for which it would * be OK to continue parsing in hopes of flushing out additional * problems, increments mv->mv_errcnt, and returns true. */ bool ld_map_sym_enter(Mapfile *mf, ld_map_ver_t *mv, ld_map_sym_t *ms) { Ofl_desc *ofl = mf->mf_ofl; Elf64_Word hash; avl_index_t where; Elf64_Sym *sym; Sym_desc *sdp; const char *conflict; /* * Add the new symbol. It should be noted that all * symbols added by the mapfile start out with global * scope, thus they will fall through the normal symbol * resolution process. Elf64_Symbols defined as locals will * be reduced in scope after all input file processing. */ /* LINTED */ hash = (Elf64_Word)elf_hash(ms->ms_name); //DBG_CALL(Dbg_map_version(ofl->ofl_lml, mv->mv_name, ms->ms_name, // mv->mv_scope)); /* * Make sure that any parent or external declarations fall back to * references. */ if (ms->ms_sdflags & (FLG_SY_PARENT | FLG_SY_EXTERN)) { /* * Turn it into a reference by setting the section index * to UNDEF. */ ms->ms_shndx = SHN_UNDEF; /* * It is wrong to specify size or value for an external symbol. */ if (ms->ms_value_set || (ms->ms_size != 0)) { mf_fatal0(mf, (MSG_MAP_NOEXVLSZ)); mv->mv_errcnt++; return (true); } } if ((sdp = ld_sym_find(ms->ms_name, hash, &where, ofl)) == NULL) { if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL) return (false); sym->st_shndx = (Elf64_Half)ms->ms_shndx; sym->st_value = ms->ms_value; sym->st_size = ms->ms_size; sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type); if ((sdp = ld_sym_enter(ms->ms_name, sym, hash, ld_map_ifl(mf), ofl, 0, ms->ms_shndx, ms->ms_sdflags, &where)) == (Sym_desc *)S_ERROR) return (false); sdp->sd_flags &= ~FLG_SY_CLEAN; /* * Identify any references. FLG_SY_MAPREF is * turned off once a relocatable object with * the same symbol is found, thus the existence * of FLG_SY_MAPREF at symbol validation is * used to flag undefined/misspelled entries. */ if (sym->st_shndx == SHN_UNDEF) sdp->sd_flags |= (FLG_SY_MAPREF | FLG_SY_GLOBREF); } else { conflict = NULL; sym = sdp->sd_sym; /* * If this symbol already exists, make sure this * definition doesn't conflict with the former. * Provided it doesn't, multiple definitions * from different mapfiles can augment each * other. */ if (sym->st_value) { if (ms->ms_value && (sym->st_value != ms->ms_value)) conflict = (MSG_MAP_DIFF_SYMVAL); } else { sym->st_value = ms->ms_value; } if (sym->st_size) { if (ms->ms_size && (sym->st_size != ms->ms_size)) conflict = (MSG_MAP_DIFF_SYMSZ); } else { sym->st_size = ms->ms_size; } if (ELF_ST_TYPE(sym->st_info) != STT_NOTYPE) { if ((ms->ms_type != STT_NOTYPE) && (ELF_ST_TYPE(sym->st_info) != ms->ms_type)) conflict = (MSG_MAP_DIFF_SYMTYP); } else { sym->st_info = ELF_ST_INFO(STB_GLOBAL, ms->ms_type); } if (sym->st_shndx != SHN_UNDEF) { if ((ms->ms_shndx != SHN_UNDEF) && (sym->st_shndx != ms->ms_shndx)) conflict = (MSG_MAP_DIFF_SYMNDX); } else { sym->st_shndx = sdp->sd_shndx = ms->ms_shndx; } if ((sdp->sd_flags & MSK_SY_GLOBAL) && (sdp->sd_aux->sa_overndx != VER_NDX_GLOBAL) && (mv->mv_vdp->vd_ndx != VER_NDX_GLOBAL) && (sdp->sd_aux->sa_overndx != mv->mv_vdp->vd_ndx)) { conflict = (MSG_MAP_DIFF_SYMVER); } if (conflict) { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(ms->ms_name), sdp->sd_file->ifl_name, conflict); mv->mv_errcnt++; return (true); } /* * If this mapfile entry supplies a definition, * indicate that the symbol is now used. */ if (ms->ms_shndx != SHN_UNDEF) sdp->sd_flags |= FLG_SY_MAPUSED; } /* * A symbol declaration that defines a size but no * value is processed as a request to create an * associated backing section. The intent behind this * functionality is to provide OBJT definitions within * filters that are not ABS. ABS symbols don't allow * copy-relocations to be established to filter OBJT * definitions. */ if ((ms->ms_shndx == SHN_ABS) && ms->ms_size && !ms->ms_value_set) { /* Create backing section if not there */ if (sdp->sd_isc == NULL) { Is_desc *isp; if (ms->ms_type == STT_OBJECT) { if ((isp = ld_make_data(ofl, ms->ms_size)) == (Is_desc *)S_ERROR) return (false); } else { if ((isp = ld_make_text(ofl, ms->ms_size)) == (Is_desc *)S_ERROR) return (false); } sdp->sd_isc = isp; isp->is_file = ld_map_ifl(mf); } /* * Now that backing storage has been created, * associate the symbol descriptor. Remove the * symbols special section tag so that it will * be assigned the correct section index as part * of update symbol processing. */ sdp->sd_flags &= ~FLG_SY_SPECSEC; ms->ms_sdflags &= ~FLG_SY_SPECSEC; } /* * Indicate the new symbols scope. Although the * symbols st_other field will eventually be updated as * part of writing out the final symbol, update the * st_other field here to trigger better diagnostics * during symbol validation (for example, undefined * references that are defined symbolic in a mapfile). */ if (mv->mv_scope == FLG_SCOPE_HIDD) { /* * This symbol needs to be reduced to local. */ if (ofl->ofl_flags & FLG_OF_REDLSYM) { sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM); sdp->sd_sym->st_other = STV_ELIMINATE; } else { sdp->sd_flags |= FLG_SY_HIDDEN; sdp->sd_sym->st_other = STV_HIDDEN; } } else if (mv->mv_scope == FLG_SCOPE_ELIM) { /* * This symbol needs to be eliminated. Note, * the symbol is also tagged as local to trigger * any necessary relocation processing prior * to the symbol being eliminated. */ sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM); sdp->sd_sym->st_other = STV_ELIMINATE; } else { /* * This symbol is explicitly defined to remain * global. */ sdp->sd_flags |= ms->ms_sdflags; /* * Qualify any global scope. */ if (mv->mv_scope == FLG_SCOPE_SNGL) { sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR); sdp->sd_sym->st_other = STV_SINGLETON; } else if (mv->mv_scope == FLG_SCOPE_PROT) { sdp->sd_flags |= FLG_SY_PROTECT; sdp->sd_sym->st_other = STV_PROTECTED; } else if (mv->mv_scope == FLG_SCOPE_EXPT) { sdp->sd_flags |= FLG_SY_EXPORT; sdp->sd_sym->st_other = STV_EXPORTED; } else sdp->sd_flags |= FLG_SY_DEFAULT; /* * Record the present version index for later * potential versioning. */ if ((sdp->sd_aux->sa_overndx == 0) || (sdp->sd_aux->sa_overndx == VER_NDX_GLOBAL)) sdp->sd_aux->sa_overndx = mv->mv_vdp->vd_ndx; mv->mv_vdp->vd_flags |= FLG_VER_REFER; } conflict = NULL; /* * Carry out some validity checks to ensure incompatible * symbol characteristics have not been defined. * These checks are carried out after symbols are added * or resolved, to catch single instance, and * multi-instance definition inconsistencies. */ if ((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_ELIM)) && ((mv->mv_scope != FLG_SCOPE_HIDD) && (mv->mv_scope != FLG_SCOPE_ELIM))) { conflict = (MSG_MAP_DIFF_SYMLCL); } else if ((sdp->sd_flags & (FLG_SY_SINGLE | FLG_SY_EXPORT)) && ((mv->mv_scope != FLG_SCOPE_DFLT) && (mv->mv_scope != FLG_SCOPE_EXPT) && (mv->mv_scope != FLG_SCOPE_SNGL))) { conflict = (MSG_MAP_DIFF_SYMGLOB); } else if ((sdp->sd_flags & FLG_SY_PROTECT) && ((mv->mv_scope != FLG_SCOPE_DFLT) && (mv->mv_scope != FLG_SCOPE_PROT))) { conflict = (MSG_MAP_DIFF_SYMPROT); } else if ((sdp->sd_flags & FLG_SY_NDIR) && (mv->mv_scope == FLG_SCOPE_PROT)) { conflict = (MSG_MAP_DIFF_PROTNDIR); } else if ((sdp->sd_flags & FLG_SY_DIR) && (mv->mv_scope == FLG_SCOPE_SNGL)) { conflict = (MSG_MAP_DIFF_SNGLDIR); } if (conflict) { /* * Select the conflict message from either a * single instance or multi-instance definition. */ if (sdp->sd_file->ifl_name == mf->mf_name) { mf_fatal(mf, (MSG_MAP_SYMDEF2), demangle(ms->ms_name), conflict); } else { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(ms->ms_name), sdp->sd_file->ifl_name, conflict); } mv->mv_errcnt++; return (true); } /* * Indicate that this symbol has been explicitly * contributed from a mapfile. */ sdp->sd_flags |= (FLG_SY_MAPFILE | FLG_SY_EXPDEF); /* * If we've encountered a symbol definition simulate * that an input file has been processed - this allows * things like filters to be created purely from a * mapfile. */ if (ms->ms_type != STT_NOTYPE) ofl->ofl_objscnt++; //DBG_CALL(Dbg_map_symbol(ofl, sdp)); /* * If this symbol has an associated filtee, record the * filtee string and associate the string index with the * symbol. This is used later to associate the syminfo * information with the necessary .dynamic entry. */ if (ms->ms_filtee) { Dfltr_desc * dftp; Sfltr_desc sft; size_t idx, _idx, nitems; /* * Make sure we don't duplicate any filtee * strings, and create a new descriptor if * necessary. */ idx = nitems = alist_nitems(ofl->ofl_dtsfltrs); for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, _idx, dftp)) { if ((ms->ms_dft_flag != dftp->dft_flag) || (strcmp(dftp->dft_str, ms->ms_filtee))) continue; idx = _idx; break; } if (idx == nitems) { Dfltr_desc dft; dft.dft_str = ms->ms_filtee; dft.dft_flag = ms->ms_dft_flag; dft.dft_ndx = 0; /* * The following append puts the new * item at the offset contained in * idx, because we know idx contains * the index of the next available slot. */ if (alist_append(&ofl->ofl_dtsfltrs, &dft, sizeof (Dfltr_desc), AL_CNT_OFL_DTSFLTRS) == NULL) return (false); } /* * Create a new filter descriptor for this * symbol. */ sft.sft_sdp = sdp; sft.sft_idx = idx; if (alist_append(&ofl->ofl_symfltrs, &sft, sizeof (Sfltr_desc), AL_CNT_OFL_SYMFLTRS) == NULL) return (false); }
/* * Add a size symbol to a segment * * entry: * mf - Mapfile descriptor * sgp - Segment descriptor * eq_tol - Type of assignment: TK_EQUAL, or TK_PLUSEQ * symname - Name of symbol. Must be in stable static storage * that can be retained. * * exit: * On success, the symbol has been added and true is returned. * Otherwise an error is reported and false is returned. */ bool ld_map_seg_size_symbol(Mapfile *mf, Sg_desc *sgp, Token eq_tok, const char *symname) { Elf64_Sym *sym; /* New symbol pointer */ Sym_desc *sdp; /* New symbol node pointer */ Ifl_desc *ifl; /* Dummy input file structure */ avl_index_t where; Ofl_desc *ofl = mf->mf_ofl; /* * We don't allow resetting the list of size symbols, so if the * operator is TK_EQUAL and the list is not empty, issue an error. * * If we want to lift this restriction, we would have to save the * size symbols and enter them from ld_map_post_process(). Doing that * well would require a significant overhead in saved error reporting * state, and interactions with the same symbols created by symbol * directives. As size symbols are of little practical use, and are * maintained primarily for backward compatibility with SysV, we have * decided not to do that, but to create the symbols as the mapfiles * are processed, and to disallow later attempts to remove them. */ if ((eq_tok == TK_EQUAL) && (aplist_nitems(sgp->sg_sizesym) > 0)) { mf_fatal(mf, (MSG_MAP_SEGSIZE), sgp->sg_name); return (false); } /* * Make sure we have a pseudo file descriptor to associate to the * symbol. */ if ((ifl = ld_map_ifl(mf)) == NULL) return (false); /* * Make sure the symbol doesn't already exist. It is possible that the * symbol has been scoped or versioned, in which case it does exist * but we can freely update it here. */ if ((sdp = ld_sym_find(symname, SYM_NOHASH, &where, ofl)) == NULL) { Elf64_Word hval; if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL) return (false); sym->st_shndx = SHN_ABS; sym->st_size = 0; sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); //DBG_CALL(Dbg_map_size_new(ofl->ofl_lml, symname, // sgp->sg_name, mf->mf_lineno)); /* LINTED */ hval = (Elf64_Word)elf_hash(symname); if ((sdp = ld_sym_enter(symname, sym, hval, ifl, ofl, 0, SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_GLOBREF), &where)) == (Sym_desc *)S_ERROR) return (false); sdp->sd_flags &= ~FLG_SY_CLEAN; //DBG_CALL(Dbg_map_symbol(ofl, sdp)); } else { sym = sdp->sd_sym; if (sym->st_shndx == SHN_UNDEF) { sdp->sd_shndx = sym->st_shndx = SHN_ABS; sdp->sd_flags |= FLG_SY_SPECSEC; sym->st_size = 0; sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT); sdp->sd_flags &= ~FLG_SY_MAPREF; //DBG_CALL(Dbg_map_size_old(ofl, sdp, // sgp->sg_name, mf->mf_lineno)); } else { mf_fatal(mf, (MSG_MAP_SYMDEF1), demangle(sdp->sd_name), sdp->sd_file->ifl_name, (MSG_MAP_DIFF_SYMMUL)); return (false); } } /* * Assign the symbol to the segment. */ if (aplist_append(&sgp->sg_sizesym, sdp, AL_CNT_SG_SIZESYM) == NULL) return (false); return (true); }
uintptr_t ld_vers_check_defs(Ofl_desc *ofl) { size_t idx1; Ver_desc *vdp; uintptr_t is_cyclic = 0; //DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, ofl->ofl_name)); /* * First check if there are any cyclic dependency */ for (APLIST_TRAVERSE(ofl->ofl_verdesc, idx1, vdp)) if ((is_cyclic = vers_visit_children(ofl, vdp, 0)) == S_ERROR) return (S_ERROR); if (is_cyclic) ofl->ofl_flags |= FLG_OF_FATAL; for (APLIST_TRAVERSE(ofl->ofl_verdesc, idx1, vdp)) { uint8_t cnt; Elf64_Sym *sym; Sym_desc *sdp; const char *name = vdp->vd_name; unsigned char bind; Ver_desc *_vdp; avl_index_t where; size_t idx2; if (vdp->vd_ndx == 0) { ld_eprintf(ofl, ERR_FATAL, (MSG_VER_UNDEF), name, vdp->vd_ref->vd_name, vdp->vd_ref->vd_file->ifl_name); continue; } //DBG_CALL(Dbg_ver_desc_entry(ofl->ofl_lml, vdp)); /* * If a version definition contains no symbols this is possibly * a mapfile error. */ #if 0 if ((vdp->vd_flags & (VER_FLG_BASE | VER_FLG_WEAK | FLG_VER_REFER)) == 0) DBG_CALL(Dbg_ver_nointerface(ofl->ofl_lml, vdp->vd_name)); #endif /* * Update the version entry count to account for this new * version descriptor (the count is the size in bytes). */ ofl->ofl_verdefsz += sizeof (Elf64_Verdef); /* * Traverse this versions dependency list to determine what * additional version dependencies we must account for against * this descriptor. */ cnt = 1; for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) { #if defined(__lint) /* get lint to think `_vdp' is used... */ vdp = _vdp; #endif cnt++; } ofl->ofl_verdefsz += (cnt * sizeof (Elf64_Verdaux)); /* * Except for the base version descriptor, generate an absolute * symbol to reflect this version. */ if (vdp->vd_flags & VER_FLG_BASE) continue; if (vdp->vd_flags & VER_FLG_WEAK) bind = STB_WEAK; else bind = STB_GLOBAL; if (sdp = ld_sym_find(name, vdp->vd_hash, &where, ofl)) { /* * If the symbol already exists and is undefined or was * defined in a shared library, convert it to an * absolute. */ if ((sdp->sd_sym->st_shndx == SHN_UNDEF) || (sdp->sd_ref != REF_REL_NEED)) { sdp->sd_shndx = sdp->sd_sym->st_shndx = SHN_ABS; sdp->sd_sym->st_info = ELF_ST_INFO(bind, STT_OBJECT); sdp->sd_ref = REF_REL_NEED; sdp->sd_flags |= (FLG_SY_SPECSEC | FLG_SY_DEFAULT | FLG_SY_EXPDEF); sdp->sd_aux->sa_overndx = vdp->vd_ndx; /* * If the reference originated from a mapfile * insure we mark the symbol as used. */ if (sdp->sd_flags & FLG_SY_MAPREF) sdp->sd_flags |= FLG_SY_MAPUSED; } else if ((sdp->sd_flags & FLG_SY_SPECSEC) && (sdp->sd_sym->st_shndx != SHN_ABS) && (sdp->sd_ref == REF_REL_NEED)) { ld_eprintf(ofl, ERR_WARNING, (MSG_VER_DEFINED), name, sdp->sd_file->ifl_name); } } else { /* * If the symbol does not exist create it. */ if ((sym = libld_calloc(sizeof (Elf64_Sym), 1)) == NULL) return (S_ERROR); sym->st_shndx = SHN_ABS; sym->st_info = ELF_ST_INFO(bind, STT_OBJECT); //DBG_CALL(Dbg_ver_symbol(ofl->ofl_lml, name)); if ((sdp = ld_sym_enter(name, sym, vdp->vd_hash, vdp->vd_file, ofl, 0, SHN_ABS, (FLG_SY_SPECSEC | FLG_SY_DEFAULT | FLG_SY_EXPDEF), &where)) == (Sym_desc *)S_ERROR) return (S_ERROR); sdp->sd_ref = REF_REL_NEED; sdp->sd_aux->sa_overndx = vdp->vd_ndx; } } return (1); }