#include <string.h>
#include <stdio.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
Ver_desc *
ld_vers_find(const char *name, Word hash, APlist *alp)
{
Aliste idx;
Ver_desc *vdp;
for (APLIST_TRAVERSE(alp, idx, vdp)) {
if (vdp->vd_hash != hash)
continue;
if (strcmp(vdp->vd_name, name) == 0)
return (vdp);
}
return (NULL);
}
Ver_desc *
ld_vers_desc(const char *name, Word hash, APlist **alpp)
{
Ver_desc *vdp;
if ((vdp = libld_calloc(1, sizeof (Ver_desc))) == NULL)
return ((Ver_desc *)S_ERROR);
vdp->vd_name = name;
vdp->vd_hash = hash;
if (aplist_append(alpp, vdp, AL_CNT_VERDESCS) == NULL)
return ((Ver_desc *)S_ERROR);
return (vdp);
}
#define _NUM_OF_VERS_ 40
typedef struct {
Ver_desc **ver_stk;
int ver_sp;
int ver_lmt;
} Ver_Stack;
static uintptr_t
vers_visit_children(Ofl_desc *ofl, Ver_desc *vp, int flag)
{
Aliste idx;
Ver_desc *vdp;
static int err = 0;
static Ver_Stack ver_stk = {0, 0, 0};
int tmp_sp;
if (err == S_ERROR)
return (err);
if (flag == 0)
ver_stk.ver_sp = 0;
for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
Ver_desc *v;
v = ver_stk.ver_stk[tmp_sp];
if (v == vp) {
if (err == 0) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_VER_CYCLIC));
err = 1;
}
for (tmp_sp = 0; tmp_sp < ver_stk.ver_sp; tmp_sp++) {
v = ver_stk.ver_stk[tmp_sp];
if ((v->vd_flags & FLG_VER_CYCLIC) == 0) {
v->vd_flags |= FLG_VER_CYCLIC;
ld_eprintf(ofl, ERR_NONE,
MSG_INTL(MSG_VER_ADDVER),
v->vd_name);
}
}
if ((vp->vd_flags & FLG_VER_CYCLIC) == 0) {
vp->vd_flags |= FLG_VER_CYCLIC;
ld_eprintf(ofl, ERR_NONE,
MSG_INTL(MSG_VER_ADDVER), vp->vd_name);
}
return (err);
}
}
if (ver_stk.ver_sp >= ver_stk.ver_lmt) {
ver_stk.ver_lmt += _NUM_OF_VERS_;
if ((ver_stk.ver_stk = (Ver_desc **)
libld_realloc(ver_stk.ver_stk,
ver_stk.ver_lmt * sizeof (Ver_desc *))) == NULL)
return (S_ERROR);
}
ver_stk.ver_stk[(ver_stk.ver_sp)++] = vp;
for (APLIST_TRAVERSE(vp->vd_deps, idx, vdp))
if (vers_visit_children(ofl, vdp, 1) == S_ERROR)
return (S_ERROR);
(ver_stk.ver_sp)--;
return (err);
}
uintptr_t
ld_vers_check_defs(Ofl_desc *ofl)
{
Aliste idx1;
Ver_desc *vdp;
uintptr_t is_cyclic = 0;
DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, ofl->ofl_name));
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)) {
Byte cnt;
Sym *sym;
Sym_desc *sdp;
const char *name = vdp->vd_name;
uchar_t bind;
Ver_desc *_vdp __unused;
avl_index_t where;
Aliste idx2;
if (vdp->vd_ndx == 0) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(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 ((vdp->vd_flags &
(VER_FLG_BASE | VER_FLG_WEAK | FLG_VER_REFER)) == 0)
DBG_CALL(Dbg_ver_nointerface(ofl->ofl_lml,
vdp->vd_name));
ofl->ofl_verdefsz += sizeof (Verdef);
cnt = 1;
for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) {
#if defined(__lint)
vdp = _vdp;
#endif
cnt++;
}
ofl->ofl_verdefsz += (cnt * sizeof (Verdaux));
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 ((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 (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_INTL(MSG_VER_DEFINED), name,
sdp->sd_file->ifl_name);
}
} else {
if ((sym = libld_calloc(1, sizeof (Sym))) == 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);
}
static void
vers_derefer(Ifl_desc *ifl, Ver_desc *vdp, int weak)
{
Aliste idx;
Ver_desc *_vdp;
Ver_index *vip = &ifl->ifl_verndx[vdp->vd_ndx];
if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
vip->vi_flags |= VER_FLG_INFO;
for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp))
vers_derefer(ifl, _vdp, weak);
}
uintptr_t
ld_vers_check_need(Ofl_desc *ofl)
{
Aliste idx1;
Ifl_desc *ifl;
Half needndx;
Str_tbl *strtbl;
strtbl = (OFL_IS_STATIC_OBJ(ofl)) ? ofl->ofl_strtab :
ofl->ofl_dynstrtab;
needndx = (ofl->ofl_vercnt > 0) ? (ofl->ofl_vercnt + 1) : 2;
for (APLIST_TRAVERSE(ofl->ofl_sos, idx1, ifl)) {
Aliste idx2;
Ver_index *vip;
Ver_desc *vdp;
Byte cnt, need = 0;
if (!(ifl->ifl_flags & FLG_IF_NEEDED))
continue;
if (ifl->ifl_vercnt <= VER_NDX_GLOBAL)
continue;
for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
vip = &ifl->ifl_verndx[cnt];
vdp = vip->vi_desc;
if ((vip->vi_flags & (FLG_VER_REFER | VER_FLG_WEAK)) ==
(FLG_VER_REFER | VER_FLG_WEAK))
vdp->vd_flags &= ~VER_FLG_WEAK;
if (vip->vi_flags & VER_FLG_WEAK)
vip->vi_flags |= FLG_VER_REFER;
}
for (APLIST_TRAVERSE(ifl->ifl_verdesc, idx2, vdp)) {
Aliste idx3;
Ver_desc *_vdp;
int type;
vip = &ifl->ifl_verndx[vdp->vd_ndx];
if (!(vip->vi_flags & FLG_VER_REFER))
continue;
type = vdp->vd_flags & VER_FLG_WEAK;
for (APLIST_TRAVERSE(vdp->vd_deps, idx3, _vdp))
vers_derefer(ifl, _vdp, type);
}
for (cnt = 0; cnt <= ifl->ifl_vercnt; cnt++) {
vip = &ifl->ifl_verndx[cnt];
if (vip->vi_flags & FLG_VER_REFER) {
vip->vi_overndx = needndx++;
ofl->ofl_verneedsz += sizeof (Vernaux);
if (st_insert(strtbl, vip->vi_name) == -1)
return (S_ERROR);
need++;
}
}
if (need) {
ifl->ifl_flags |= FLG_IF_VERNEED;
ofl->ofl_verneedsz += sizeof (Verneed);
if (st_insert(strtbl, ifl->ifl_soname) == -1)
return (S_ERROR);
}
}
if (ofl->ofl_verneedsz == 0)
ofl->ofl_flags &= ~FLG_OF_VERNEED;
return (1);
}
static void
vers_select(Ofl_desc *ofl, Ifl_desc *ifl, Ver_desc *vdp, const char *ref)
{
Aliste idx;
Ver_desc *_vdp;
Ver_index *vip = &ifl->ifl_verndx[vdp->vd_ndx];
vip->vi_flags |= FLG_VER_AVAIL;
DBG_CALL(Dbg_ver_avail_entry(ofl->ofl_lml, vip, ref));
for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp))
vers_select(ofl, ifl, _vdp, ref);
}
static Ver_index *
vers_index(Ofl_desc *ofl, Ifl_desc *ifl, int avail)
{
Aliste idx1;
Ver_desc *vdp;
Ver_index *vip;
Sdf_desc *sdf = ifl->ifl_sdfdesc;
Word count = ifl->ifl_vercnt;
Sdv_desc *sdv;
if ((vip = libld_calloc((count + 1), sizeof (Ver_index))) == NULL)
return ((Ver_index *)S_ERROR);
for (APLIST_TRAVERSE(ifl->ifl_verdesc, idx1, vdp)) {
int ndx = vdp->vd_ndx;
vip[ndx].vi_name = vdp->vd_name;
vip[ndx].vi_desc = vdp;
if (avail || (vdp->vd_flags & VER_FLG_BASE))
vip[ndx].vi_flags |= FLG_VER_AVAIL;
if (vdp->vd_flags & VER_FLG_WEAK)
vip[ndx].vi_flags |= VER_FLG_WEAK;
if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
Aliste idx2;
for (ALIST_TRAVERSE(sdf->sdf_verneed, idx2, sdv)) {
if (strcmp(vip[ndx].vi_name, sdv->sdv_name))
continue;
vip[ndx].vi_flags |= FLG_VER_REFER;
sdv->sdv_flags |= FLG_SDV_MATCHED;
break;
}
}
}
if (sdf && (sdf->sdf_flags & FLG_SDF_ADDVER)) {
int fail = 0;
for (ALIST_TRAVERSE(sdf->sdf_verneed, idx1, sdv)) {
if (sdv->sdv_flags & FLG_SDV_MATCHED)
continue;
if (fail++ == 0) {
ld_eprintf(ofl, ERR_NONE,
MSG_INTL(MSG_VER_ADDVERS), sdf->sdf_rfile,
sdf->sdf_name);
}
ld_eprintf(ofl, ERR_NONE, MSG_INTL(MSG_VER_ADDVER),
sdv->sdv_name);
}
if (fail)
return ((Ver_index *)S_ERROR);
}
return (vip);
}
int
ld_vers_sym_process(Ofl_desc *ofl, Is_desc *isp, Ifl_desc *ifl)
{
Shdr *symshdr;
Shdr *vershdr = isp->is_shdr;
symshdr = ifl->ifl_isdesc[vershdr->sh_link]->is_shdr;
if ((symshdr->sh_size / symshdr->sh_entsize) != (vershdr->sh_size /
vershdr->sh_entsize)) {
Is_desc *sym_isp = ifl->ifl_isdesc[vershdr->sh_link];
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_ELF_VERSYM),
ifl->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name,
EC_WORD(vershdr->sh_size / vershdr->sh_entsize),
EC_WORD(sym_isp->is_scnndx), sym_isp->is_name,
EC_WORD(symshdr->sh_size / symshdr->sh_entsize));
return (1);
}
ifl->ifl_versym = (Versym *)isp->is_indata->d_buf;
return (1);
}
uintptr_t
ld_vers_def_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
{
const char *str, *file = ifl->ifl_name;
Sdf_desc *sdf = ifl->ifl_sdfdesc;
Sdv_desc *sdv;
Word num, _num;
Verdef *vdf;
int relobj;
if (isp == NULL) {
Aliste idx;
for (ALIST_TRAVERSE(sdf->sdf_vers, idx, sdv)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
sdv->sdv_name, sdv->sdv_ref);
}
return (0);
}
vdf = (Verdef *)isp->is_indata->d_buf;
if (vdf->vd_version > VER_DEF_CURRENT)
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_VER_HIGHER),
ifl->ifl_name, vdf->vd_version, VER_DEF_CURRENT);
num = isp->is_shdr->sh_info;
str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
if (ifl->ifl_ehdr->e_type == ET_REL)
relobj = 1;
else
relobj = 0;
DBG_CALL(Dbg_ver_def_title(ofl->ofl_lml, file));
for (_num = 1; _num <= num; _num++,
vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
const char *name;
Ver_desc *ivdp, *ovdp = NULL;
Word hash;
Half cnt = vdf->vd_cnt;
Half ndx = vdf->vd_ndx;
Verdaux *vdap = (Verdaux *)((uintptr_t)vdf +
vdf->vd_aux);
if (ndx > ifl->ifl_vercnt)
ifl->ifl_vercnt = ndx;
name = (char *)(str + vdap->vda_name);
hash = (Word)elf_hash(name);
if (((ivdp = ld_vers_find(name, hash,
ifl->ifl_verdesc)) == NULL) &&
((ivdp = ld_vers_desc(name, hash,
&ifl->ifl_verdesc)) == (Ver_desc *)S_ERROR))
return (S_ERROR);
ivdp->vd_ndx = ndx;
ivdp->vd_file = ifl;
ivdp->vd_flags = vdf->vd_flags;
if (relobj) {
if (!(ofl->ofl_flags & FLG_OF_RELOBJ))
ofl->ofl_flags |= FLG_OF_PROCRED;
if ((ivdp->vd_flags & VER_FLG_BASE) == 0) {
if (ofl->ofl_vercnt == 0) {
if (ld_vers_base(ofl) ==
(Ver_desc *)S_ERROR)
return (S_ERROR);
}
ofl->ofl_flags |= FLG_OF_VERDEF;
if ((ovdp = ld_vers_find(name, hash,
ofl->ofl_verdesc)) == NULL) {
if ((ovdp = ld_vers_desc(name, hash,
&ofl->ofl_verdesc)) ==
(Ver_desc *)S_ERROR)
return (S_ERROR);
ovdp->vd_ndx = (Half)++ofl->ofl_vercnt;
ovdp->vd_file = ifl;
ovdp->vd_flags = vdf->vd_flags;
}
}
ivdp->vd_ref = ovdp;
}
vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
for (cnt--; cnt; cnt--,
vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
Ver_desc *_ivdp;
name = (char *)(str + vdap->vda_name);
hash = (Word)elf_hash(name);
if (((_ivdp = ld_vers_find(name, hash,
ifl->ifl_verdesc)) == NULL) &&
((_ivdp = ld_vers_desc(name, hash,
&ifl->ifl_verdesc)) == (Ver_desc *)S_ERROR))
return (S_ERROR);
if (aplist_append(&ivdp->vd_deps, _ivdp,
AL_CNT_VERDESCS) == NULL)
return (S_ERROR);
}
DBG_CALL(Dbg_ver_desc_entry(ofl->ofl_lml, ivdp));
}
if ((ifl->ifl_verndx =
vers_index(ofl, ifl, relobj)) == (Ver_index *)S_ERROR)
return (S_ERROR);
if (relobj)
return (1);
DBG_CALL(Dbg_ver_avail_title(ofl->ofl_lml, file));
if (sdf && (sdf->sdf_flags & FLG_SDF_SELECT)) {
Aliste idx1;
for (ALIST_TRAVERSE(sdf->sdf_vers, idx1, sdv)) {
Aliste idx2;
Ver_desc *vdp;
int found = 0;
for (APLIST_TRAVERSE(ifl->ifl_verdesc, idx2, vdp)) {
if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
found++;
break;
}
}
if (found)
vers_select(ofl, ifl, vdp, sdv->sdv_ref);
else
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
sdv->sdv_name, sdv->sdv_ref);
}
} else {
Ver_index *vip;
int cnt;
for (cnt = VER_NDX_GLOBAL; cnt <= ifl->ifl_vercnt; cnt++) {
vip = &ifl->ifl_verndx[cnt];
vip->vi_flags |= FLG_VER_AVAIL;
DBG_CALL(Dbg_ver_avail_entry(ofl->ofl_lml, vip, 0));
}
}
if (ifl->ifl_flags & FLG_IF_NEEDED)
ofl->ofl_flags |= FLG_OF_VERNEED;
return (1);
}
uintptr_t
ld_vers_need_process(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
{
const char *str, *file = ifl->ifl_name;
Word num, _num;
Verneed *vnd;
vnd = (Verneed *)isp->is_indata->d_buf;
if (vnd->vn_version > VER_DEF_CURRENT) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_VER_HIGHER),
ifl->ifl_name, vnd->vn_version, VER_DEF_CURRENT);
}
num = isp->is_shdr->sh_info;
str = (char *)ifl->ifl_isdesc[isp->is_shdr->sh_link]->is_indata->d_buf;
DBG_CALL(Dbg_ver_need_title(ofl->ofl_lml, file));
for (_num = 1; _num <= num; _num++,
vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
Sdf_desc *sdf;
const char *name;
Half cnt = vnd->vn_cnt;
Vernaux *vnap = (Vernaux *)((uintptr_t)vnd +
vnd->vn_aux);
Half _cnt;
name = (char *)(str + vnd->vn_file);
if ((sdf = sdf_find(name, ofl->ofl_soneed)) == NULL) {
if ((sdf = sdf_add(name, &ofl->ofl_soneed)) ==
(Sdf_desc *)S_ERROR)
return (S_ERROR);
sdf->sdf_rfile = file;
sdf->sdf_flags |= FLG_SDF_VERIFY;
}
for (_cnt = 0; cnt; _cnt++, cnt--,
vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
Sdv_desc sdv;
sdv.sdv_name = str + vnap->vna_name;
sdv.sdv_ref = file;
sdv.sdv_flags = 0;
if (alist_append(&sdf->sdf_vers, &sdv,
sizeof (Sdv_desc), AL_CNT_SDF_VERSIONS) == NULL)
return (S_ERROR);
DBG_CALL(Dbg_ver_need_entry(ofl->ofl_lml, _cnt, name,
sdv.sdv_name));
}
}
return (1);
}
void
ld_vers_promote(Sym_desc *sdp, Word ndx, Ifl_desc *ifl, Ofl_desc *ofl)
{
Half vndx;
vndx = ifl->ifl_versym[ndx];
if (vndx == 0) {
sdp->sd_flags |= (FLG_SY_REDUCED | FLG_SY_HIDDEN);
return;
}
if (vndx == VER_NDX_ELIMINATE) {
sdp->sd_flags |= (FLG_SY_REDUCED | FLG_SY_HIDDEN | FLG_SY_ELIM);
return;
}
if (vndx == VER_NDX_GLOBAL) {
if (!SYM_IS_HIDDEN(sdp))
sdp->sd_flags |= (FLG_SY_DEFAULT | FLG_SY_EXPDEF);
if (sdp->sd_aux->sa_overndx <= VER_NDX_GLOBAL)
sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
return;
}
if ((ifl->ifl_verndx == 0) || (vndx > ifl->ifl_vercnt)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_VER_INVALNDX),
sdp->sd_name, ifl->ifl_name, vndx);
return;
}
if (!SYM_IS_HIDDEN(sdp))
sdp->sd_flags |= (FLG_SY_DEFAULT | FLG_SY_EXPDEF);
if (!(sdp->sd_flags & FLG_SY_VERSPROM)) {
Ver_index *vip;
vip = &ifl->ifl_verndx[vndx];
sdp->sd_aux->sa_overndx = vip->vi_desc->vd_ref->vd_ndx;
sdp->sd_flags |= FLG_SY_VERSPROM;
}
}
Ver_desc *
ld_vers_base(Ofl_desc *ofl)
{
Ver_desc *vdp;
const char *name;
if ((name = ofl->ofl_soname) == NULL) {
const char *str = ofl->ofl_name;
while (*str != '\0') {
if (*str++ == '/')
name = str;
}
if (name == NULL)
name = ofl->ofl_name;
}
if ((vdp = ld_vers_desc(name, (Word)elf_hash(name),
&ofl->ofl_verdesc)) == (Ver_desc *)S_ERROR)
return ((Ver_desc *)S_ERROR);
vdp->vd_ndx = ofl->ofl_vercnt = VER_NDX_GLOBAL;
vdp->vd_flags |= VER_FLG_BASE;
return (vdp);
}
int
ld_vers_verify(Ofl_desc *ofl)
{
Aliste idx1;
Sdf_desc *sdf;
char *nv;
#if defined(_ELF64)
if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_64))) == NULL)
#else
if ((nv = getenv(MSG_ORIG(MSG_LD_NOVERSION_32))) == NULL)
#endif
nv = getenv(MSG_ORIG(MSG_LD_NOVERSION));
if (nv && nv[0])
return (1);
for (APLIST_TRAVERSE(ofl->ofl_soneed, idx1, sdf)) {
Aliste idx2;
Sdv_desc *sdv;
Ifl_desc *ifl = sdf->sdf_file;
if (!(sdf->sdf_flags & FLG_SDF_VERIFY))
continue;
if ((ifl == NULL) || (ifl->ifl_verdesc == NULL))
continue;
for (ALIST_TRAVERSE(sdf->sdf_vers, idx2, sdv)) {
Aliste idx3;
Ver_desc *vdp;
int found = 0;
for (APLIST_TRAVERSE(ifl->ifl_verdesc, idx3, vdp)) {
if (strcmp(sdv->sdv_name, vdp->vd_name) == 0) {
found++;
break;
}
}
if (found) {
Ver_index *vip;
vip = &ifl->ifl_verndx[vdp->vd_ndx];
if (!(vip->vi_flags & FLG_VER_AVAIL)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_VER_UNAVAIL),
ifl->ifl_name, sdv->sdv_name,
sdv->sdv_ref);
}
} else {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_VER_NOEXIST), ifl->ifl_name,
sdv->sdv_name, sdv->sdv_ref);
}
}
}
return (1);
}