#define ELF_TARGET_AMD64
#include <sys/ctype.h>
#include <stdio.h>
#include <string.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
int
ld_sym_avl_comp(const void *elem1, const void *elem2)
{
Sym_avlnode *sav1 = (Sym_avlnode *)elem1;
Sym_avlnode *sav2 = (Sym_avlnode *)elem2;
int res;
res = sav1->sav_hash - sav2->sav_hash;
if (res < 0)
return (-1);
if (res > 0)
return (1);
res = strcmp(sav1->sav_name, sav2->sav_name);
if (res == 0)
return (0);
if (res > 0)
return (1);
return (-1);
}
inline static const char *
string(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, size_t strsize,
int symndx, Word shndx, Word symsecndx, const char *symsecname,
const char *strsecname, sd_flag_t *flags)
{
Word name = sym->st_name;
if (name) {
if ((ifl->ifl_flags & FLG_IF_HSTRTAB) == 0) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_NOSTRTABLE),
ifl->ifl_name, EC_WORD(symsecndx), symsecname,
symndx, EC_XWORD(name));
return (NULL);
}
if (name >= (Word)strsize) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_FIL_EXCSTRTABLE), ifl->ifl_name,
EC_WORD(symsecndx), symsecname, symndx,
EC_XWORD(name), strsecname, EC_XWORD(strsize));
return (NULL);
}
}
if (ld_targ.t_ms.ms_is_regsym != NULL) {
const char *regname = (*ld_targ.t_ms.ms_is_regsym)(ofl, ifl,
sym, strs, symndx, shndx, symsecname, flags);
if (regname == (const char *)S_ERROR) {
return (NULL);
}
if (regname)
return (regname);
}
if ((name == 0) && (ELF_ST_BIND(sym->st_info) != STB_LOCAL)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_FIL_NONAMESYM),
ifl->ifl_name, EC_WORD(symsecndx), symsecname, symndx,
EC_XWORD(name));
}
return (strs + name);
}
static const char *
demangle_symname(const char *name, const char *symtab_name, Word symndx)
{
#define INIT_BUFSIZE 256
static char *buf;
static size_t bufsize = 0;
size_t len;
int use_name;
use_name = (name != NULL) && (*name != '\0');
if (use_name) {
name = demangle(name);
len = strlen(name) + 2;
} else {
name = MSG_ORIG(MSG_STR_EMPTY);
len = strlen(symtab_name) + 2 + CONV_INV_BUFSIZE;
}
len++;
if (len > bufsize) {
size_t new_bufsize = bufsize;
char *new_buf;
if (new_bufsize == 0)
new_bufsize = INIT_BUFSIZE;
while (len > new_bufsize)
new_bufsize *= 2;
if ((new_buf = libld_malloc(new_bufsize)) == NULL)
return (name);
buf = new_buf;
bufsize = new_bufsize;
}
if (use_name) {
(void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SYMNAM), name);
} else {
(void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_NULLSYMNAM),
symtab_name, EC_WORD(symndx));
}
return (buf);
#undef INIT_BUFSIZE
}
uintptr_t
ld_sym_nodirect(Is_desc *isp, Ifl_desc *ifl, Ofl_desc *ofl)
{
Shdr *sifshdr, *symshdr;
Syminfo *sifdata;
Sym *symdata;
char *strdata;
ulong_t cnt, _cnt;
sifshdr = isp->is_shdr;
sifdata = (Syminfo *)isp->is_indata->d_buf;
cnt = sifshdr->sh_size / sifshdr->sh_entsize;
if ((sifshdr->sh_link == 0) || (sifshdr->sh_link >= ifl->ifl_shnum)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
ifl->ifl_name, isp->is_name, EC_XWORD(sifshdr->sh_link));
return (0);
}
symshdr = ifl->ifl_isdesc[sifshdr->sh_link]->is_shdr;
symdata = ifl->ifl_isdesc[sifshdr->sh_link]->is_indata->d_buf;
strdata = ifl->ifl_isdesc[symshdr->sh_link]->is_indata->d_buf;
for (_cnt = 1, sifdata++; _cnt < cnt; _cnt++, sifdata++) {
Sym *sym;
char *str;
Sym_desc *sdp;
if ((sifdata->si_flags & SYMINFO_FLG_NOEXTDIRECT) == 0)
continue;
sym = (Sym *)(symdata + _cnt);
str = (char *)(strdata + sym->st_name);
if ((sdp = ld_sym_find(str, SYM_NOHASH, NULL, ofl)) != NULL) {
if (ifl != sdp->sd_file)
continue;
sdp->sd_flags &= ~FLG_SY_DIR;
sdp->sd_flags |= FLG_SY_NDIR;
}
}
return (0);
}
uintptr_t
ld_sym_copy(Sym_desc *sdp)
{
Sym *nsym;
if (sdp->sd_flags & FLG_SY_CLEAN) {
if ((nsym = libld_malloc(sizeof (Sym))) == NULL)
return (S_ERROR);
*nsym = *(sdp->sd_sym);
sdp->sd_sym = nsym;
sdp->sd_flags &= ~FLG_SY_CLEAN;
}
return (1);
}
Sym_desc *
ld_sym_find(const char *name, Word hash, avl_index_t *where, Ofl_desc *ofl)
{
Sym_avlnode qsav, *sav;
if (hash == SYM_NOHASH)
hash = (Word)elf_hash((const char *)name);
qsav.sav_hash = hash;
qsav.sav_name = name;
sav = avl_find(&ofl->ofl_symavl, &qsav, where);
if (sav == NULL)
return (NULL);
return (sav->sav_sdp);
}
static inline Boolean
is_gcc_localalias(Sym_desc *sdp)
{
char *p;
if (ELF_ST_BIND(sdp->sd_sym->st_info) != STB_LOCAL)
return (FALSE);
if ((p = strstr(sdp->sd_name, MSG_ORIG(MSG_SYM_LOCALALIAS))) != NULL) {
p += MSG_SYM_LOCALALIAS_SIZE;
switch (*p++) {
case '\0':
return (TRUE);
case '.':
if (*p == '\0')
return (FALSE);
while (ISDIGIT(*p))
p++;
if (*p != '\0')
return (FALSE);
return (TRUE);
}
}
return (FALSE);
}
Sym_desc *
ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
Ofl_desc *ofl, Word ndx, Word shndx, sd_flag_t sdflags, avl_index_t *where)
{
Sym_desc *sdp;
Sym_aux *sap;
Sym_avlnode *savl;
char *_name;
Sym *nsym;
Half etype;
uchar_t vis;
avl_index_t _where;
if (ifl)
etype = ifl->ifl_ehdr->e_type;
else
etype = ET_NONE;
ofl->ofl_entercnt++;
if ((savl = libld_calloc(1, S_DROUND(sizeof (Sym_avlnode)) +
S_DROUND(sizeof (Sym_desc)) +
S_DROUND(sizeof (Sym_aux)))) == NULL)
return ((Sym_desc *)S_ERROR);
sdp = (Sym_desc *)((uintptr_t)savl +
S_DROUND(sizeof (Sym_avlnode)));
sap = (Sym_aux *)((uintptr_t)sdp +
S_DROUND(sizeof (Sym_desc)));
savl->sav_sdp = sdp;
sdp->sd_file = ifl;
sdp->sd_aux = sap;
savl->sav_hash = sap->sa_hash = hash;
sdp->sd_sym = nsym = &sap->sa_sym;
*nsym = *osym;
sdp->sd_shndx = shndx;
sdp->sd_flags |= sdflags;
if ((_name = libld_malloc(strlen(name) + 1)) == NULL)
return ((Sym_desc *)S_ERROR);
savl->sav_name = sdp->sd_name = (const char *)strcpy(_name, name);
if (where == 0) {
Sym_avlnode *_savl;
where = &_where;
_savl = avl_find(&ofl->ofl_symavl, savl, where);
assert(_savl == NULL);
}
avl_insert(&ofl->ofl_symavl, savl, *where);
if ((sdflags & FLG_SY_SPECSEC) || (nsym->st_shndx == SHN_UNDEF))
sdp->sd_isc = NULL;
else {
sdp->sd_isc = ifl->ifl_isdesc[shndx];
if ((etype == ET_REL) && (sdp->sd_isc == NULL)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYM_INVSEC),
name, ifl->ifl_name, EC_XWORD(shndx));
return (sdp);
}
}
if (sdflags & FLG_SY_SPECSEC) {
if (nsym->st_shndx == SHN_COMMON)
sdp->sd_flags |= FLG_SY_TENTSYM;
#if defined(_ELF64)
else if ((ld_targ.t_m.m_mach == EM_AMD64) &&
(nsym->st_shndx == SHN_X86_64_LCOMMON))
sdp->sd_flags |= FLG_SY_TENTSYM;
#endif
}
vis = ELF_ST_VISIBILITY(nsym->st_other);
if ((etype == ET_NONE) || (etype == ET_REL)) {
switch (vis) {
case STV_DEFAULT:
sdp->sd_flags |= FLG_SY_DEFAULT;
break;
case STV_INTERNAL:
case STV_HIDDEN:
sdp->sd_flags |= FLG_SY_HIDDEN;
break;
case STV_PROTECTED:
sdp->sd_flags |= FLG_SY_PROTECT;
break;
case STV_EXPORTED:
sdp->sd_flags |= FLG_SY_EXPORT;
break;
case STV_SINGLETON:
sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR);
ofl->ofl_flags1 |= (FLG_OF1_NDIRECT | FLG_OF1_NGLBDIR);
break;
case STV_ELIMINATE:
sdp->sd_flags |= (FLG_SY_HIDDEN | FLG_SY_ELIM);
break;
default:
assert(vis <= STV_ELIMINATE);
}
sdp->sd_ref = REF_REL_NEED;
if ((ofl->ofl_flags1 & FLG_OF1_ALNODIR) &&
((sdp->sd_flags & (FLG_SY_PROTECT | FLG_SY_DIR)) == 0) &&
(nsym->st_shndx != SHN_UNDEF)) {
sdp->sd_flags |= FLG_SY_NDIR;
}
} else {
sdp->sd_ref = REF_DYN_SEEN;
if (vis == STV_PROTECTED)
sdp->sd_flags |= FLG_SY_PROT;
if ((vis == STV_SINGLETON) && (nsym->st_shndx != SHN_UNDEF))
sdp->sd_flags |= (FLG_SY_SINGLE | FLG_SY_NDIR);
if (sdp->sd_isc &&
(sdp->sd_isc->is_shdr->sh_type == SHT_NOBITS))
sdp->sd_flags |= FLG_SY_TENTSYM;
}
if (nsym->st_shndx == SHN_SUNW_IGNORE) {
sdp->sd_shndx = shndx = SHN_UNDEF;
sdp->sd_flags |= (FLG_SY_REDUCED |
FLG_SY_HIDDEN | FLG_SY_IGNORE | FLG_SY_ELIM);
}
if ((etype == ET_REL) &&
(ELF_ST_BIND(nsym->st_info) == STB_GLOBAL) &&
((nsym->st_shndx == SHN_UNDEF) || ((sdflags & FLG_SY_SPECSEC) &&
#if defined(_ELF64)
((nsym->st_shndx == SHN_COMMON) ||
((ld_targ.t_m.m_mach == EM_AMD64) &&
(nsym->st_shndx == SHN_X86_64_LCOMMON))))))
#else
(nsym->st_shndx == SHN_COMMON))))
#endif
sdp->sd_flags |= FLG_SY_GLOBREF;
if (nsym->st_shndx == SHN_UNDEF) {
sap->sa_rfile = ifl->ifl_name;
} else {
if (sdp->sd_ref == REF_DYN_SEEN) {
if (ifl->ifl_vercnt) {
Ver_index *vip;
Half vndx = ifl->ifl_versym[ndx];
sap->sa_dverndx = vndx;
vip = &ifl->ifl_verndx[vndx];
if (!(vip->vi_flags & FLG_VER_AVAIL)) {
sdp->sd_flags |= FLG_SY_NOTAVAIL;
sap->sa_vfile = ifl->ifl_name;
}
}
if (!(ifl->ifl_flags & FLG_IF_NEEDED))
sdp->sd_flags |= FLG_SY_NOTAVAIL;
} else if (etype == ET_REL) {
if (ifl->ifl_versym)
ld_vers_promote(sdp, ndx, ifl, ofl);
}
if ((ofl->ofl_flags & FLG_OF_GENMAP) &&
((sdflags & FLG_SY_SPECSEC) == 0))
if (aplist_append(&sap->sa_dfiles, ifl->ifl_name,
AL_CNT_SDP_DFILES) == NULL)
return ((Sym_desc *)S_ERROR);
}
if ((ifl == NULL) || ((ifl->ifl_flags & FLG_IF_MAPFILE) == 0))
DBG_CALL(Dbg_syms_entered(ofl, nsym, sdp));
return (sdp);
}
static uintptr_t
sym_add_spec(const char *name, const char *uname, Word sdaux_id,
sd_flag_t sdflags_u, sd_flag_t sdflags, Ofl_desc *ofl)
{
Sym_desc *sdp;
Sym_desc *usdp;
Sym *sym;
Word hash;
avl_index_t where;
hash = (Word)elf_hash(uname);
if (usdp = ld_sym_find(uname, hash, &where, ofl)) {
if ((usdp->sd_shndx == SHN_UNDEF) ||
(usdp->sd_ref != REF_REL_NEED)) {
usdp->sd_ref = REF_REL_NEED;
usdp->sd_shndx = usdp->sd_sym->st_shndx = SHN_ABS;
usdp->sd_flags |= FLG_SY_SPECSEC | sdflags_u;
usdp->sd_sym->st_info =
ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
usdp->sd_isc = NULL;
usdp->sd_sym->st_size = 0;
usdp->sd_sym->st_value = 0;
usdp->sd_aux->sa_symspec = (Half)sdaux_id;
if (!SYM_IS_HIDDEN(usdp) &&
(sdflags & FLG_SY_DEFAULT)) {
usdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
if (sdaux_id == SDAUX_ID_GOT) {
usdp->sd_flags &= ~FLG_SY_NDIR;
usdp->sd_flags |= FLG_SY_PROTECT;
usdp->sd_sym->st_other = STV_PROTECTED;
} else if (
((usdp->sd_flags & FLG_SY_DIR) == 0) &&
((ofl->ofl_flags & FLG_OF_SYMBOLIC) == 0)) {
usdp->sd_flags |= FLG_SY_NDIR;
}
}
usdp->sd_flags |= sdflags;
if (usdp->sd_flags & FLG_SY_MAPREF)
usdp->sd_flags |= FLG_SY_MAPUSED;
DBG_CALL(Dbg_syms_updated(ofl, usdp, uname));
} else {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_RESERVE),
uname, usdp->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(STB_GLOBAL, STT_OBJECT);
sym->st_size = 0;
sym->st_value = 0;
DBG_CALL(Dbg_syms_created(ofl->ofl_lml, uname));
if ((usdp = ld_sym_enter(uname, sym, hash, (Ifl_desc *)NULL,
ofl, 0, SHN_ABS, (FLG_SY_SPECSEC | sdflags_u), &where)) ==
(Sym_desc *)S_ERROR)
return (S_ERROR);
usdp->sd_ref = REF_REL_NEED;
usdp->sd_aux->sa_symspec = (Half)sdaux_id;
usdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
if (sdaux_id == SDAUX_ID_GOT) {
usdp->sd_flags |= FLG_SY_PROTECT;
usdp->sd_sym->st_other = STV_PROTECTED;
} else if ((sdflags & FLG_SY_DEFAULT) &&
((ofl->ofl_flags & FLG_OF_SYMBOLIC) == 0)) {
usdp->sd_flags |= FLG_SY_NDIR;
}
usdp->sd_flags |= sdflags;
}
if (name && (sdp = ld_sym_find(name, SYM_NOHASH, NULL, ofl)) &&
(sdp->sd_sym->st_shndx == SHN_UNDEF)) {
uchar_t bind;
sdp->sd_ref = REF_REL_NEED;
sdp->sd_shndx = sdp->sd_sym->st_shndx = SHN_ABS;
sdp->sd_flags |= FLG_SY_SPECSEC;
sdp->sd_isc = NULL;
sdp->sd_sym->st_size = 0;
sdp->sd_sym->st_value = 0;
sdp->sd_aux->sa_symspec = (Half)sdaux_id;
if (usdp->sd_aux->sa_symspec) {
usdp->sd_aux->sa_linkndx = 0;
sdp->sd_aux->sa_linkndx = 0;
bind = STB_WEAK;
} else
bind = STB_GLOBAL;
sdp->sd_sym->st_info = ELF_ST_INFO(bind, STT_OBJECT);
if (!SYM_IS_HIDDEN(sdp) &&
(sdflags & FLG_SY_DEFAULT)) {
sdp->sd_aux->sa_overndx = VER_NDX_GLOBAL;
if (sdaux_id == SDAUX_ID_GOT) {
sdp->sd_flags &= ~FLG_SY_NDIR;
sdp->sd_flags |= FLG_SY_PROTECT;
sdp->sd_sym->st_other = STV_PROTECTED;
} else if (((sdp->sd_flags & FLG_SY_DIR) == 0) &&
((ofl->ofl_flags & FLG_OF_SYMBOLIC) == 0)) {
sdp->sd_flags |= FLG_SY_NDIR;
}
}
sdp->sd_flags |= sdflags;
if (sdp->sd_flags & FLG_SY_MAPREF)
sdp->sd_flags |= FLG_SY_MAPUSED;
DBG_CALL(Dbg_syms_updated(ofl, sdp, name));
}
return (1);
}
typedef enum {
UNDEF, NOVERSION, IMPLICIT, NOTAVAIL,
BNDLOCAL
} Type;
static const Msg format[] = {
MSG_SYM_UND_UNDEF,
MSG_SYM_UND_NOVER,
MSG_SYM_UND_IMPL,
MSG_SYM_UND_NOTA,
MSG_SYM_UND_BNDLOCAL
};
static void
sym_undef_entry(Ofl_desc *ofl, Sym_desc *sdp, Type type, ofl_flag_t ofl_flag,
ofl_flag_t *undef_state)
{
const char *name1, *name2, *name3;
Ifl_desc *ifl = sdp->sd_file;
Sym_aux *sap = sdp->sd_aux;
if (*undef_state == 0)
ld_eprintf(ofl, ERR_NONE, MSG_INTL(MSG_SYM_FMT_UNDEF),
MSG_INTL(MSG_SYM_UNDEF_ITM_11),
MSG_INTL(MSG_SYM_UNDEF_ITM_21),
MSG_INTL(MSG_SYM_UNDEF_ITM_12),
MSG_INTL(MSG_SYM_UNDEF_ITM_22));
ofl->ofl_flags |= ofl_flag;
*undef_state |= ofl_flag ? ofl_flag : ~(FLG_OF_FATAL | FLG_OF_WARN);
switch (type) {
case UNDEF:
case BNDLOCAL:
name1 = sap->sa_rfile;
break;
case NOVERSION:
name1 = ifl->ifl_name;
break;
case IMPLICIT:
name1 = sap->sa_rfile;
name2 = ifl->ifl_name;
break;
case NOTAVAIL:
name1 = sap->sa_rfile;
name2 = sap->sa_vfile;
name3 = ifl->ifl_verndx[sap->sa_dverndx].vi_name;
break;
default:
return;
}
ld_eprintf(ofl, ERR_NONE, MSG_INTL(format[type]),
demangle(sdp->sd_name), name1, name2, name3);
}
static void
sym_add_bounds(Ofl_desc *ofl, Os_desc *osp, Word bound)
{
Sym_desc *bsdp;
char symn[1024];
size_t nsz;
switch (bound) {
case SDAUX_ID_SECBOUND_START:
nsz = snprintf(symn, sizeof (symn), "%s%s",
MSG_ORIG(MSG_SYM_SECBOUND_START), osp->os_name);
if (nsz >= sizeof (symn))
return;
break;
case SDAUX_ID_SECBOUND_STOP:
nsz = snprintf(symn, sizeof (symn), "%s%s",
MSG_ORIG(MSG_SYM_SECBOUND_STOP), osp->os_name);
if (nsz >= sizeof (symn))
return;
break;
default:
assert(0);
}
if ((bsdp = ld_sym_find(symn, SYM_NOHASH, NULL, ofl)) != NULL) {
if ((bsdp->sd_shndx != SHN_UNDEF) &&
(bsdp->sd_ref == REF_REL_NEED)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_RESERVE),
symn, bsdp->sd_file->ifl_name);
return;
}
DBG_CALL(Dbg_syms_updated(ofl, bsdp, symn));
bsdp->sd_aux->sa_symspec = bound;
bsdp->sd_aux->sa_boundsec = osp;
bsdp->sd_flags |= FLG_SY_SPECSEC;
bsdp->sd_ref = REF_REL_NEED;
bsdp->sd_sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
bsdp->sd_sym->st_other = STV_PROTECTED;
bsdp->sd_isc = NULL;
bsdp->sd_sym->st_size = 0;
bsdp->sd_sym->st_value = 0;
bsdp->sd_shndx = bsdp->sd_sym->st_shndx = SHN_ABS;
}
}
static Boolean
is_cname(const char *name)
{
if (strlen(name) == strspn(name,
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"_"))
return (TRUE);
else
return (FALSE);
}
uintptr_t
ld_sym_spec(Ofl_desc *ofl)
{
Sym_desc *sdp;
Sg_desc *sgp;
DBG_CALL(Dbg_syms_spec_title(ofl->ofl_lml));
if (!(ofl->ofl_flags & FLG_OF_RELOBJ) ||
(ofl->ofl_flags & FLG_OF_KMOD)) {
Aliste idx1;
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Os_desc *osp;
Aliste idx2;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
if (is_cname(osp->os_name)) {
sym_add_bounds(ofl, osp,
SDAUX_ID_SECBOUND_START);
sym_add_bounds(ofl, osp,
SDAUX_ID_SECBOUND_STOP);
}
}
}
}
if (ofl->ofl_flags & FLG_OF_RELOBJ)
return (1);
if (sym_add_spec(MSG_ORIG(MSG_SYM_ETEXT), MSG_ORIG(MSG_SYM_ETEXT_U),
SDAUX_ID_ETEXT, 0, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
ofl) == S_ERROR)
return (S_ERROR);
if (sym_add_spec(MSG_ORIG(MSG_SYM_EDATA), MSG_ORIG(MSG_SYM_EDATA_U),
SDAUX_ID_EDATA, 0, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
ofl) == S_ERROR)
return (S_ERROR);
if (sym_add_spec(MSG_ORIG(MSG_SYM_END), MSG_ORIG(MSG_SYM_END_U),
SDAUX_ID_END, FLG_SY_DYNSORT, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
ofl) == S_ERROR)
return (S_ERROR);
if (sym_add_spec(MSG_ORIG(MSG_SYM_L_END), MSG_ORIG(MSG_SYM_L_END_U),
SDAUX_ID_END, 0, FLG_SY_HIDDEN, ofl) == S_ERROR)
return (S_ERROR);
if (sym_add_spec(MSG_ORIG(MSG_SYM_L_START), MSG_ORIG(MSG_SYM_L_START_U),
SDAUX_ID_START, 0, FLG_SY_HIDDEN, ofl) == S_ERROR)
return (S_ERROR);
if (sym_add_spec(MSG_ORIG(MSG_SYM_DYNAMIC), MSG_ORIG(MSG_SYM_DYNAMIC_U),
SDAUX_ID_DYN, FLG_SY_DYNSORT, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
ofl) == S_ERROR)
return (S_ERROR);
if (OFL_ALLOW_DYNSYM(ofl))
if (sym_add_spec(MSG_ORIG(MSG_SYM_PLKTBL),
MSG_ORIG(MSG_SYM_PLKTBL_U), SDAUX_ID_PLT,
FLG_SY_DYNSORT, (FLG_SY_DEFAULT | FLG_SY_EXPDEF),
ofl) == S_ERROR)
return (S_ERROR);
if (((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_GOFTBL_U),
SYM_NOHASH, NULL, ofl)) != NULL) && (sdp->sd_ref != REF_DYN_SEEN)) {
if (sym_add_spec(MSG_ORIG(MSG_SYM_GOFTBL),
MSG_ORIG(MSG_SYM_GOFTBL_U), SDAUX_ID_GOT, FLG_SY_DYNSORT,
(FLG_SY_DEFAULT | FLG_SY_EXPDEF), ofl) == S_ERROR)
return (S_ERROR);
}
return (1);
}
static int
sym_cap_vis(const char *name, Word hash, Sym *sym, Ofl_desc *ofl)
{
Sym_desc *sdp;
uchar_t vis;
avl_index_t where;
sd_flag_t sdflags = 0;
vis = ELF_ST_VISIBILITY(sym->st_other);
switch (vis) {
case STV_EXPORTED:
sdflags |= FLG_SY_EXPORT;
break;
case STV_SINGLETON:
sdflags |= FLG_SY_SINGLE;
break;
case STV_HIDDEN:
sdflags |= FLG_SY_HIDDEN;
break;
}
if ((sdp = ld_sym_find(name, hash, &where, ofl)) != NULL)
sdflags |= sdp->sd_flags;
if ((ofl->ofl_flags & (FLG_OF_AUTOLCL | FLG_OF_AUTOELM)) &&
((sdflags & MSK_SY_NOAUTO) == 0))
sdflags |= FLG_SY_HIDDEN;
return ((sdflags & FLG_SY_HIDDEN) == 0);
}
void
ld_sym_adjust_vis(Sym_desc *sdp, Ofl_desc *ofl)
{
ofl_flag_t oflags = ofl->ofl_flags;
Sym *sym = sdp->sd_sym;
if ((sdp->sd_ref == REF_REL_NEED) &&
(sdp->sd_sym->st_shndx != SHN_UNDEF)) {
if ((oflags & (FLG_OF_AUTOLCL | FLG_OF_AUTOELM)) &&
((sdp->sd_flags & MSK_SY_NOAUTO) == 0)) {
if ((sdp->sd_flags & FLG_SY_HIDDEN) == 0) {
sdp->sd_flags |=
(FLG_SY_REDUCED | FLG_SY_HIDDEN);
}
if (oflags & (FLG_OF_REDLSYM | FLG_OF_AUTOELM)) {
sdp->sd_flags |= FLG_SY_ELIM;
sym->st_other = STV_ELIMINATE |
(sym->st_other & ~MSK_SYM_VISIBILITY);
} else if (ELF_ST_VISIBILITY(sym->st_other) !=
STV_INTERNAL)
sym->st_other = STV_HIDDEN |
(sym->st_other & ~MSK_SYM_VISIBILITY);
}
if ((oflags & FLG_OF_SYMBOLIC) &&
((sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_NDIR)) == 0)) {
sdp->sd_flags |= FLG_SY_PROTECT;
if (ELF_ST_VISIBILITY(sym->st_other) == STV_DEFAULT)
sym->st_other = STV_PROTECTED |
(sym->st_other & ~MSK_SYM_VISIBILITY);
}
}
sdp->sd_flags |= FLG_SY_VISIBLE;
}
inline static int
ensure_sym_local(Ofl_desc *ofl, Sym_desc *sdp, const char *str)
{
if (sdp->sd_sym->st_shndx == SHN_UNDEF) {
if (str) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYM_UNDEF),
str, demangle((char *)sdp->sd_name));
}
return (1);
}
if (sdp->sd_ref != REF_REL_NEED) {
if (str) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYM_EXTERN),
str, demangle((char *)sdp->sd_name),
sdp->sd_file->ifl_name);
}
return (1);
}
sdp->sd_flags |= FLG_SY_UPREQD;
if (sdp->sd_isc) {
sdp->sd_isc->is_flags |= FLG_IS_SECTREF;
sdp->sd_isc->is_file->ifl_flags |= FLG_IF_FILEREF;
}
return (0);
}
static int
ensure_array_local(Ofl_desc *ofl, APlist *apl, const char *str)
{
Aliste idx;
Sym_desc *sdp;
int ret = 0;
for (APLIST_TRAVERSE(apl, idx, sdp))
ret += ensure_sym_local(ofl, sdp, str);
return (ret);
}
uintptr_t
ld_sym_validate(Ofl_desc *ofl)
{
Sym_avlnode *sav;
Sym_desc *sdp;
Sym *sym;
ofl_flag_t oflags = ofl->ofl_flags;
ofl_flag_t undef = 0, needed = 0, verdesc = 0;
Xword bssalign = 0, tlsalign = 0;
Boolean need_bss, need_tlsbss;
Xword bsssize = 0, tlssize = 0;
#if defined(_ELF64)
Xword lbssalign = 0, lbsssize = 0;
Boolean need_lbss;
#endif
int ret, allow_ldynsym;
uchar_t type;
ofl_flag_t undef_state = 0;
DBG_CALL(Dbg_basic_validate(ofl->ofl_lml));
need_bss = need_tlsbss = FALSE;
#if defined(_ELF64)
need_lbss = FALSE;
#endif
if (oflags & FLG_OF_NOUNDEF) {
undef = FLG_OF_FATAL;
} else if (oflags & FLG_OF_SHAROBJ) {
if ((oflags & FLG_OF_SYMBOLIC) ||
OFL_GUIDANCE(ofl, FLG_OFG_NO_DEFS))
undef = FLG_OF_WARN;
}
if ((oflags & FLG_OF_NOUNDEF) || !(oflags & FLG_OF_SHAROBJ))
needed = FLG_OF_FATAL;
else if ((oflags & FLG_OF_SHAROBJ) &&
OFL_GUIDANCE(ofl, FLG_OFG_NO_DEFS))
needed = FLG_OF_WARN;
if ((oflags & FLG_OF_VERDEF) && (ofl->ofl_vercnt > VER_NDX_GLOBAL))
verdesc = FLG_OF_FATAL;
allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
if (allow_ldynsym) {
static const char *special[] = {
MSG_ORIG(MSG_SYM_INIT_U),
MSG_ORIG(MSG_SYM_FINI_U),
MSG_ORIG(MSG_SYM_START),
NULL
};
int i;
for (i = 0; special[i] != NULL; i++) {
if (((sdp = ld_sym_find(special[i],
SYM_NOHASH, NULL, ofl)) != NULL) &&
(sdp->sd_sym->st_size == 0)) {
if (ld_sym_copy(sdp) == S_ERROR)
return (S_ERROR);
sdp->sd_flags |= FLG_SY_DYNSORT;
}
}
}
for (sav = avl_first(&ofl->ofl_symavl); sav;
sav = AVL_NEXT(&ofl->ofl_symavl, sav)) {
Is_desc *isp;
int undeferr = 0;
uchar_t vis;
sdp = sav->sav_sdp;
if (!(oflags & FLG_OF_NOUNDEF) &&
!OFL_GUIDANCE(ofl, FLG_OFG_NO_DEFS) &&
(sdp->sd_ref == REF_DYN_SEEN))
continue;
if ((sdp->sd_flags & (FLG_SY_EXTERN | FLG_SY_PARENT)) &&
((sdp->sd_flags & FLG_SY_MAPUSED) == 0)) {
sdp->sd_flags |= FLG_SY_INVALID;
continue;
}
sym = sdp->sd_sym;
type = ELF_ST_TYPE(sym->st_info);
if ((type == STT_TLS) && (sym->st_size != 0) &&
(sym->st_shndx != SHN_UNDEF) &&
(sym->st_shndx != SHN_COMMON)) {
Is_desc *isp = sdp->sd_isc;
Ifl_desc *ifl = sdp->sd_file;
if ((isp == NULL) || (isp->is_shdr == NULL) ||
((isp->is_shdr->sh_flags & SHF_TLS) == 0)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_SYM_TLS),
demangle(sdp->sd_name), ifl->ifl_name);
continue;
}
}
if ((sdp->sd_flags & FLG_SY_VISIBLE) == 0)
ld_sym_adjust_vis(sdp, ofl);
if ((sdp->sd_flags & FLG_SY_REDUCED) &&
(oflags & FLG_OF_PROCRED)) {
DBG_CALL(Dbg_syms_reduce(ofl, DBG_SYM_REDUCE_GLOBAL,
sdp, 0, 0));
}
if ((vis = ELF_ST_VISIBILITY(sym->st_other)) == STV_SINGLETON)
ofl->ofl_dtflags_1 |= DF_1_SINGLETON;
if (((oflags & FLG_OF_RELOBJ) == 0) &&
(sym->st_shndx == SHN_UNDEF) &&
(ELF_ST_BIND(sym->st_info) != STB_WEAK)) {
if (vis && (vis != STV_SINGLETON)) {
sym_undef_entry(ofl, sdp, BNDLOCAL,
FLG_OF_FATAL, &undef_state);
continue;
}
}
if (((isp = sdp->sd_isc) != 0) && isp->is_shdr &&
((isp->is_shdr->sh_flags & SHF_ALLOC) == 0)) {
sdp->sd_flags |= (FLG_SY_REDUCED | FLG_SY_HIDDEN);
}
if (sdp->sd_flags & FLG_SY_IGNORE)
sdp->sd_shndx = SHN_SUNW_IGNORE;
if (undef) {
if (!(sdp->sd_flags & FLG_SY_REGSYM) &&
((sym->st_shndx == SHN_UNDEF) &&
((ELF_ST_BIND(sym->st_info) != STB_WEAK) &&
((sdp->sd_flags &
(FLG_SY_PARENT | FLG_SY_EXTERN)) == 0)) ||
((sdp->sd_flags &
(FLG_SY_MAPREF | FLG_SY_MAPUSED | FLG_SY_HIDDEN |
FLG_SY_PROTECT)) == FLG_SY_MAPREF))) {
sym_undef_entry(ofl, sdp, UNDEF, undef,
&undef_state);
undeferr = 1;
}
} else {
if ((sdp->sd_flags &
(FLG_SY_MAPREF | FLG_SY_MAPUSED)) ==
FLG_SY_MAPREF) {
sym_undef_entry(ofl, sdp, UNDEF, FLG_OF_WARN,
&undef_state);
undeferr = 1;
}
}
if ((sdp->sd_ref == REF_DYN_NEED) &&
(!(sdp->sd_flags & FLG_SY_REFRSD))) {
sdp->sd_file->ifl_flags |= FLG_IF_DEPREQD;
if (sdp->sd_flags & FLG_SY_NDIR)
ofl->ofl_flags1 |= FLG_OF1_NGLBDIR;
if (sdp->sd_file->ifl_vercnt) {
int vndx;
Ver_index *vip;
vndx = sdp->sd_aux->sa_dverndx;
vip = &sdp->sd_file->ifl_verndx[vndx];
if (vip->vi_flags & FLG_VER_AVAIL) {
vip->vi_flags |= FLG_VER_REFER;
} else {
sym_undef_entry(ofl, sdp, NOTAVAIL,
FLG_OF_FATAL, &undef_state);
continue;
}
}
}
if (needed && !undeferr && (sdp->sd_flags & FLG_SY_GLOBREF) &&
(sdp->sd_ref == REF_DYN_NEED) &&
(sdp->sd_flags & FLG_SY_NOTAVAIL)) {
sym_undef_entry(ofl, sdp, IMPLICIT, needed,
&undef_state);
if (needed == FLG_OF_FATAL)
continue;
}
if ((sdp->sd_ref == REF_DYN_NEED) &&
(sdp->sd_flags & (FLG_SY_HIDDEN | FLG_SY_PROTECT))) {
sym_undef_entry(ofl, sdp, BNDLOCAL, FLG_OF_FATAL,
&undef_state);
continue;
}
if (verdesc && (sdp->sd_ref == REF_REL_NEED)) {
if (sym->st_shndx == SHN_UNDEF) {
if (sdp->sd_aux && sdp->sd_aux->sa_overndx)
sdp->sd_aux->sa_overndx = 0;
} else {
if (!SYM_IS_HIDDEN(sdp) && sdp->sd_aux &&
(sdp->sd_aux->sa_overndx == 0)) {
sym_undef_entry(ofl, sdp, NOVERSION,
verdesc, &undef_state);
continue;
}
}
}
if (sdp->sd_ref == REF_DYN_SEEN)
continue;
if ((sym->st_shndx == SHN_COMMON) &&
(((oflags & FLG_OF_RELOBJ) == 0) ||
ld_sym_reducable(ofl, sdp))) {
if ((sdp->sd_move == NULL) ||
((sdp->sd_flags & FLG_SY_PAREXPN) == 0)) {
if (type != STT_TLS) {
need_bss = TRUE;
bsssize = (Xword)S_ROUND(bsssize,
sym->st_value) + sym->st_size;
if (sym->st_value > bssalign)
bssalign = sym->st_value;
} else {
need_tlsbss = TRUE;
tlssize = (Xword)S_ROUND(tlssize,
sym->st_value) + sym->st_size;
if (sym->st_value > tlsalign)
tlsalign = sym->st_value;
}
}
}
#if defined(_ELF64)
if ((ld_targ.t_m.m_mach == EM_AMD64) &&
(sym->st_shndx == SHN_X86_64_LCOMMON)) {
need_lbss = TRUE;
lbsssize = (Xword)S_ROUND(lbsssize, sym->st_value) +
sym->st_size;
if (sym->st_value > lbssalign)
lbssalign = sym->st_value;
}
#endif
if (((isp = sdp->sd_isc) != 0) &&
(sdp->sd_flags & FLG_SY_CMDREF)) {
isp->is_flags |= FLG_IS_SECTREF;
isp->is_file->ifl_flags |= FLG_IF_FILEREF;
}
if (ld_sym_reducable(ofl, sdp)) {
if (sdp->sd_flags & FLG_SY_ELIM) {
ofl->ofl_elimcnt++;
} else {
ofl->ofl_scopecnt++;
if ((((sdp->sd_flags & FLG_SY_REGSYM) == 0) ||
sym->st_name) && (st_insert(ofl->ofl_strtab,
sdp->sd_name) == -1))
return (S_ERROR);
if (allow_ldynsym && ldynsym_symtype[type] &&
((sym->st_name != 0) ||
(type == STT_FILE))) {
ofl->ofl_dynscopecnt++;
if (st_insert(ofl->ofl_dynstrtab,
sdp->sd_name) == -1)
return (S_ERROR);
DYNSORT_COUNT(sdp, sym, type, ++);
}
}
} else {
ofl->ofl_globcnt++;
if (allow_ldynsym)
DYNSORT_COUNT(sdp, sym, type, ++);
if (((ofl->ofl_dtflags_1 & DF_1_DIRECT) || (isp &&
(isp->is_file->ifl_flags & FLG_IF_DIRECT))) &&
((sdp->sd_flags & FLG_SY_NDIR) == 0))
sdp->sd_flags |= FLG_SY_DIR;
if (((sdp->sd_flags & FLG_SY_REGSYM) == 0) ||
sym->st_name) {
if (st_insert(ofl->ofl_strtab,
sdp->sd_name) == -1)
return (S_ERROR);
if (!(ofl->ofl_flags & FLG_OF_RELOBJ) &&
(st_insert(ofl->ofl_dynstrtab,
sdp->sd_name) == -1))
return (S_ERROR);
}
if (isp) {
isp->is_flags |= FLG_IS_SECTREF;
isp->is_file->ifl_flags |= FLG_IF_FILEREF;
}
}
}
if (!((oflags & FLG_OF_SHAROBJ) && OFL_GUIDANCE(ofl, FLG_OFG_NO_DEFS) &&
(undef_state & (FLG_OF_FATAL | FLG_OF_WARN))))
ofl->ofl_guideflags |= FLG_OFG_NO_DEFS;
if (ofl->ofl_flags & FLG_OF_FATAL)
return (1);
if (ofl->ofl_regsyms) {
int ndx;
for (ndx = 0; ndx < ofl->ofl_regsymsno; ndx++) {
if ((sdp = ofl->ofl_regsyms[ndx]) == NULL)
continue;
if (sdp->sd_ref != REF_REL_NEED) {
ofl->ofl_regsyms[ndx] = NULL;
continue;
}
ofl->ofl_regsymcnt++;
if (sdp->sd_sym->st_name == 0)
sdp->sd_name = MSG_ORIG(MSG_STR_EMPTY);
if (SYM_IS_HIDDEN(sdp) ||
(ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL))
ofl->ofl_lregsymcnt++;
}
}
if (need_bss) {
if (ld_make_bss(ofl, bsssize, bssalign,
ld_targ.t_id.id_bss) == S_ERROR)
return (S_ERROR);
}
if (need_tlsbss) {
if (ld_make_bss(ofl, tlssize, tlsalign,
ld_targ.t_id.id_tlsbss) == S_ERROR)
return (S_ERROR);
}
#if defined(_ELF64)
if ((ld_targ.t_m.m_mach == EM_AMD64) &&
need_lbss && !(oflags & FLG_OF_RELOBJ)) {
if (ld_make_bss(ofl, lbsssize, lbssalign,
ld_targ.t_id.id_lbss) == S_ERROR)
return (S_ERROR);
}
#endif
ret = 0;
if (ofl->ofl_entry) {
if ((sdp = ld_sym_find(ofl->ofl_entry, SYM_NOHASH,
NULL, ofl)) == NULL) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_ARG_NOENTRY),
ofl->ofl_entry);
ret++;
} else if (ensure_sym_local(ofl, sdp,
MSG_INTL(MSG_SYM_ENTRY)) != 0) {
ret++;
} else {
ofl->ofl_entry = (void *)sdp;
}
} else if (((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_START),
SYM_NOHASH, NULL, ofl)) != NULL) && (ensure_sym_local(ofl,
sdp, 0) == 0)) {
ofl->ofl_entry = (void *)sdp;
} else if (((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_MAIN),
SYM_NOHASH, NULL, ofl)) != NULL) && (ensure_sym_local(ofl,
sdp, 0) == 0)) {
ofl->ofl_entry = (void *)sdp;
}
if ((sdp = ofl->ofl_dtracesym) != 0)
ret += ensure_sym_local(ofl, sdp, MSG_ORIG(MSG_STR_DTRACE));
if (ofl->ofl_initarray) {
ret += ensure_array_local(ofl, ofl->ofl_initarray,
MSG_ORIG(MSG_SYM_INITARRAY));
}
if (ofl->ofl_finiarray) {
ret += ensure_array_local(ofl, ofl->ofl_finiarray,
MSG_ORIG(MSG_SYM_FINIARRAY));
}
if (ofl->ofl_preiarray) {
ret += ensure_array_local(ofl, ofl->ofl_preiarray,
MSG_ORIG(MSG_SYM_PREINITARRAY));
}
if (ret)
return (S_ERROR);
if ((oflags & (FLG_OF_VERNEED | FLG_OF_NOVERSEC)) == FLG_OF_VERNEED)
return (ld_vers_check_need(ofl));
else
return (1);
}
static int
compare(const void *sdpp1, const void *sdpp2)
{
Sym_desc *sdp1 = *((Sym_desc **)sdpp1);
Sym_desc *sdp2 = *((Sym_desc **)sdpp2);
Sym *sym1, *sym2;
uchar_t bind1, bind2;
if (sdp1 == NULL)
return (-1);
if (sdp2 == NULL)
return (1);
sym1 = sdp1->sd_sym;
sym2 = sdp2->sd_sym;
if (sym1->st_shndx > sym2->st_shndx)
return (1);
if (sym1->st_shndx < sym2->st_shndx)
return (-1);
if (sym1->st_value > sym2->st_value)
return (1);
if (sym1->st_value < sym2->st_value)
return (-1);
bind1 = ELF_ST_BIND(sym1->st_info);
bind2 = ELF_ST_BIND(sym2->st_info);
if (bind1 > bind2)
return (-1);
if (bind1 < bind2)
return (1);
return (0);
}
static void
issue_badaddr_msg(Ifl_desc *ifl, Ofl_desc *ofl, Sym_desc *sdp,
Sym *sym, Word shndx)
{
Error err;
const char *msg;
if ((sdp->sd_isc->is_shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) ==
SHF_ALLOC) {
msg = MSG_INTL(MSG_SYM_BADADDR_ROTXT);
err = ERR_WARNING;
} else {
msg = MSG_INTL(MSG_SYM_BADADDR);
err = ERR_FATAL;
}
ld_eprintf(ofl, err, msg, demangle(sdp->sd_name),
ifl->ifl_name, shndx, sdp->sd_isc->is_name,
EC_XWORD(sdp->sd_isc->is_shdr->sh_size),
EC_XWORD(sym->st_value), EC_XWORD(sym->st_size));
}
typedef struct {
Sym_desc *c_nsdp;
Sym_desc *c_osdp;
Cap_group *c_group;
Word c_ndx;
} Cap_pair;
uintptr_t
ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
{
#define SYM_LOC_BADADDR(_sdp, _sym, _type) \
(_sym->st_size && dynsymsort_symtype[_type] && \
(_sym->st_shndx != SHN_UNDEF) && \
((_sym->st_shndx < SHN_LORESERVE) || \
(_sym->st_shndx == SHN_XINDEX)) && \
_sdp->sd_isc && _sdp->sd_isc->is_shdr && \
((_sym->st_value + _sym->st_size) > _sdp->sd_isc->is_shdr->sh_size))
Conv_inv_buf_t inv_buf;
Sym *sym = (Sym *)isc->is_indata->d_buf;
Word *symshndx = NULL;
Shdr *shdr = isc->is_shdr;
Sym_desc *sdp;
size_t strsize;
char *strs;
uchar_t type, bind;
Word ndx, hash, local, total;
uchar_t osabi = ifl->ifl_ehdr->e_ident[EI_OSABI];
Half mach = ifl->ifl_ehdr->e_machine;
Half etype = ifl->ifl_ehdr->e_type;
const char *symsecname, *strsecname;
Word symsecndx;
avl_index_t where;
int test_gnu_hidden_bit, weak;
Cap_desc *cdp = NULL;
Alist *cappairs = NULL;
if (ifl->ifl_symscnt)
return (1);
if (isc->is_symshndx)
symshndx = isc->is_symshndx->is_indata->d_buf;
DBG_CALL(Dbg_syms_process(ofl->ofl_lml, ifl));
symsecndx = isc->is_scnndx;
if (isc->is_name)
symsecname = isc->is_name;
else
symsecname = MSG_ORIG(MSG_STR_EMPTY);
if (ifl->ifl_flags & FLG_IF_HSTRTAB) {
ndx = shdr->sh_link;
if ((ndx == 0) || (ndx >= ifl->ifl_shnum)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_FIL_INVSHLINK), ifl->ifl_name,
EC_WORD(symsecndx), symsecname, EC_XWORD(ndx));
return (S_ERROR);
}
strsize = ifl->ifl_isdesc[ndx]->is_shdr->sh_size;
strs = ifl->ifl_isdesc[ndx]->is_indata->d_buf;
if (ifl->ifl_isdesc[ndx]->is_name)
strsecname = ifl->ifl_isdesc[ndx]->is_name;
else
strsecname = MSG_ORIG(MSG_STR_EMPTY);
} else {
strsize = 0;
strs = (char *)MSG_ORIG(MSG_STR_EMPTY);
strsecname = MSG_ORIG(MSG_STR_EMPTY);
}
total = (Word)(shdr->sh_size / shdr->sh_entsize);
local = shdr->sh_info;
if ((ifl->ifl_oldndx = libld_malloc((size_t)(total *
sizeof (Sym_desc *)))) == NULL)
return (S_ERROR);
if ((etype == ET_REL) && (local != 0)) {
if ((ifl->ifl_locs =
libld_calloc(local, sizeof (Sym_desc))) == NULL)
return (S_ERROR);
ifl->ifl_locscnt = local;
}
ifl->ifl_symscnt = total;
if (local != 0) {
int allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
Sym_desc *last_file_sdp = NULL;
int last_file_ndx = 0;
for (sym++, ndx = 1; ndx < local; sym++, ndx++) {
sd_flag_t sdflags = FLG_SY_CLEAN;
Word shndx;
const char *name;
Sym_desc *rsdp;
int shndx_bad = 0;
int symtab_enter = 1;
if (symshndx && (sym->st_shndx == SHN_XINDEX)) {
shndx = symshndx[ndx];
} else if ((shndx = sym->st_shndx) >= SHN_LORESERVE) {
sdflags |= FLG_SY_SPECSEC;
} else if (shndx > ifl->ifl_shnum) {
shndx_bad = 1;
}
if ((name = string(ofl, ifl, sym, strs, strsize, ndx,
shndx, symsecndx, symsecname, strsecname,
&sdflags)) == NULL)
continue;
if (shndx_bad) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, symsecname, ndx),
ifl->ifl_name,
conv_sym_shndx(osabi, mach, sym->st_shndx,
CONV_FMT_DECIMAL, &inv_buf));
continue;
}
rsdp = sdp = NULL;
if (sdflags & FLG_SY_REGSYM) {
rsdp = (*ld_targ.t_ms.ms_reg_find)(sym, ofl);
if (rsdp != 0) {
(void) (*ld_targ.t_ms.ms_reg_check)
(rsdp, sym, name, ifl, ofl);
continue;
}
if (etype == ET_DYN) {
if ((sdp = libld_calloc(
sizeof (Sym_desc), 1)) == NULL)
return (S_ERROR);
sdp->sd_ref = REF_DYN_SEEN;
symtab_enter = 0;
}
} else if (etype == ET_DYN) {
continue;
}
if (sdp == NULL) {
sdp = &(ifl->ifl_locs[ndx]);
sdp->sd_ref = REF_REL_NEED;
sdp->sd_symndx = ndx;
}
if (rsdp == NULL) {
sdp->sd_name = name;
sdp->sd_sym = sym;
sdp->sd_shndx = shndx;
sdp->sd_flags = sdflags;
sdp->sd_file = ifl;
ifl->ifl_oldndx[ndx] = sdp;
}
DBG_CALL(Dbg_syms_entry(ofl->ofl_lml, ndx, sdp));
if (sym->st_shndx == SHN_SUNW_IGNORE) {
sdp->sd_shndx = shndx = SHN_UNDEF;
sdp->sd_flags |= (FLG_SY_IGNORE | FLG_SY_ELIM);
}
if (sdp->sd_flags & FLG_SY_REGSYM) {
DBG_CALL(Dbg_syms_entered(ofl, sym, sdp));
if ((rsdp == NULL) &&
((*ld_targ.t_ms.ms_reg_enter)(sdp, ofl) ==
0))
return (S_ERROR);
}
if ((sym->st_shndx != SHN_UNDEF) &&
((sdp->sd_flags & FLG_SY_SPECSEC) == 0))
sdp->sd_isc = ifl->ifl_isdesc[shndx];
if (sdp->sd_isc &&
(sdp->sd_isc->is_flags & FLG_IS_DISCARD)) {
sdp->sd_flags |= FLG_SY_ISDISC;
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
continue;
}
if ((type = ELF_ST_TYPE(sym->st_info)) == STT_SECTION) {
if (sym->st_shndx == SHN_UNDEF) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, symsecname,
ndx), ifl->ifl_name,
conv_sym_shndx(osabi, mach,
sym->st_shndx, CONV_FMT_DECIMAL,
&inv_buf));
}
continue;
}
if (etype == ET_REL) {
if (SYM_LOC_BADADDR(sdp, sym, type)) {
issue_badaddr_msg(ifl, ofl, sdp,
sym, shndx);
if (ofl->ofl_flags & FLG_OF_FATAL)
continue;
}
if (type == STT_FILE) {
int toss = (last_file_sdp != NULL) &&
((ndx - 1) == last_file_ndx) &&
(sym->st_name ==
last_file_sdp->sd_sym->st_name);
last_file_sdp = sdp;
last_file_ndx = ndx;
if (toss) {
sdp->sd_flags |= FLG_SY_INVALID;
DBG_CALL(Dbg_syms_dup_discarded(
ofl->ofl_lml, ndx, sdp));
continue;
}
}
}
if ((etype == ET_REL) && is_gcc_localalias(sdp))
sdp->sd_flags |= FLG_SY_NODYNSORT;
if ((sym->st_size != 0) && ((type == STT_TLS) &&
(sym->st_shndx != SHN_COMMON))) {
Is_desc *isp = sdp->sd_isc;
if ((isp == NULL) || (isp->is_shdr == NULL) ||
((isp->is_shdr->sh_flags & SHF_TLS) == 0)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_SYM_TLS),
demangle(sdp->sd_name),
ifl->ifl_name);
continue;
}
}
if (((sdp->sd_flags & FLG_SY_SPECSEC) &&
((sym->st_shndx == SHN_COMMON)) ||
((type == STT_FILE) &&
(sym->st_shndx != SHN_ABS))) ||
(sdp->sd_isc && (sdp->sd_isc->is_osdesc == NULL))) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, symsecname, ndx),
ifl->ifl_name,
conv_sym_shndx(osabi, mach, sym->st_shndx,
CONV_FMT_DECIMAL, &inv_buf));
sdp->sd_isc = NULL;
sdp->sd_flags |= FLG_SY_INVALID;
continue;
}
if (!(ofl->ofl_flags & FLG_OF_REDLSYM) &&
symtab_enter) {
ofl->ofl_locscnt++;
if ((((sdp->sd_flags & FLG_SY_REGSYM) == 0) ||
sym->st_name) && (st_insert(ofl->ofl_strtab,
sdp->sd_name) == -1))
return (S_ERROR);
if (allow_ldynsym && ldynsym_symtype[type] &&
((sym->st_name != 0) ||
(type == STT_FILE))) {
ofl->ofl_dynlocscnt++;
if (st_insert(ofl->ofl_dynstrtab,
sdp->sd_name) == -1)
return (S_ERROR);
DYNSORT_COUNT(sdp, sym, type, ++);
}
}
}
}
test_gnu_hidden_bit = ((ifl->ifl_flags & FLG_IF_GNUVER) != 0) &&
(ifl->ifl_versym != NULL);
if ((etype == ET_REL) && (ifl->ifl_flags & FLG_IF_OTOSCAP))
cdp = ifl->ifl_caps;
sym = (Sym *)isc->is_indata->d_buf;
sym += local;
weak = 0;
for (ndx = (int)local; ndx < total; sym++, ndx++) {
const char *name;
sd_flag_t sdflags = 0;
Word shndx;
int shndx_bad = 0;
Sym *nsym = sym;
Cap_pair *cpp = NULL;
uchar_t ntype;
if (symshndx && (nsym->st_shndx == SHN_XINDEX)) {
shndx = symshndx[ndx];
} else if ((shndx = nsym->st_shndx) >= SHN_LORESERVE) {
sdflags |= FLG_SY_SPECSEC;
} else if (shndx > ifl->ifl_shnum) {
shndx_bad = 1;
}
if ((name = string(ofl, ifl, nsym, strs, strsize, ndx, shndx,
symsecndx, symsecname, strsecname, &sdflags)) == NULL)
continue;
if (shndx_bad) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, symsecname, ndx),
ifl->ifl_name,
conv_sym_shndx(osabi, mach, nsym->st_shndx,
CONV_FMT_DECIMAL, &inv_buf));
continue;
}
if (test_gnu_hidden_bit &&
((ifl->ifl_versym[ndx] & 0x8000) != 0))
continue;
if (name[0] && (etype == ET_DYN) && (nsym->st_size == 0) &&
(ELF_ST_TYPE(nsym->st_info) == STT_OBJECT) &&
(name[0] == '_') && ((name[1] == 'e') ||
(name[1] == 'D') || (name[1] == 'P')) &&
((strcmp(name, MSG_ORIG(MSG_SYM_ETEXT_U)) == 0) ||
(strcmp(name, MSG_ORIG(MSG_SYM_EDATA_U)) == 0) ||
(strcmp(name, MSG_ORIG(MSG_SYM_END_U)) == 0) ||
(strcmp(name, MSG_ORIG(MSG_SYM_DYNAMIC_U)) == 0) ||
(strcmp(name, MSG_ORIG(MSG_SYM_PLKTBL_U)) == 0))) {
ifl->ifl_oldndx[ndx] = 0;
continue;
}
if (ofl->ofl_wrap && name[0] && (shndx == SHN_UNDEF)) {
WrapSymNode wsn, *wsnp;
wsn.wsn_name = name;
if ((*name == '_') &&
(strncmp(name, MSG_ORIG(MSG_STR_UU_REAL_U),
MSG_STR_UU_REAL_U_SIZE) == 0))
wsn.wsn_name += MSG_STR_UU_REAL_U_SIZE;
if ((wsnp = avl_find(ofl->ofl_wrap, &wsn, 0)) != NULL) {
const char *old_name = name;
name = (wsn.wsn_name == name) ?
wsnp->wsn_wrapname : wsn.wsn_name;
DBG_CALL(Dbg_syms_wrap(ofl->ofl_lml, ndx,
old_name, name));
}
}
bind = ELF_ST_BIND(nsym->st_info);
if ((bind != STB_GLOBAL) && (bind != STB_WEAK)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_SYM_NONGLOB),
demangle_symname(name, symsecname, ndx),
ifl->ifl_name,
conv_sym_info_bind(bind, 0, &inv_buf));
continue;
}
if (bind == STB_WEAK)
weak++;
if (((sdflags & FLG_SY_SPECSEC) == 0) &&
(nsym->st_shndx != SHN_UNDEF)) {
Is_desc *isp;
if (shndx >= ifl->ifl_shnum) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, symsecname, ndx),
ifl->ifl_name,
conv_sym_shndx(osabi, mach, nsym->st_shndx,
CONV_FMT_DECIMAL, &inv_buf));
continue;
}
isp = ifl->ifl_isdesc[shndx];
if ((isp != NULL) &&
(isp->is_flags & FLG_IS_DISCARD) &&
(isp->is_flags & FLG_IS_COMDAT)) {
Sym *rsym;
if ((rsym = libld_malloc(sizeof (Sym))) == NULL)
return (S_ERROR);
*rsym = *nsym;
rsym->st_shndx = shndx = SHN_UNDEF;
rsym->st_value = 0x0;
rsym->st_size = 0x0;
nsym = rsym;
sdflags |= FLG_SY_ISDISC;
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
} else if ((isp != NULL) &&
(isp->is_flags & FLG_IS_DISCARD)) {
if ((sdp =
libld_calloc(1, sizeof (Sym_desc))) == NULL)
return (S_ERROR);
sdp->sd_name = name;
sdp->sd_sym = nsym;
sdp->sd_file = ifl;
sdp->sd_isc = isp;
sdp->sd_flags = FLG_SY_ISDISC;
ifl->ifl_oldndx[ndx] = sdp;
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
continue;
}
}
hash = (Word)elf_hash(name);
ntype = ELF_ST_TYPE(nsym->st_info);
if (cdp && (nsym->st_shndx != SHN_UNDEF) &&
((sdflags & FLG_SY_SPECSEC) == 0) &&
((ntype == STT_FUNC) || (ntype == STT_OBJECT))) {
if (sym_cap_vis(name, hash, sym, ofl) &&
((cpp = alist_append(&cappairs, NULL,
sizeof (Cap_pair), AL_CNT_CAP_PAIRS)) == NULL))
return (S_ERROR);
}
if (cpp) {
Sym *rsym;
DBG_CALL(Dbg_syms_cap_convert(ofl, ndx, name, nsym));
if ((cpp->c_osdp =
libld_malloc(sizeof (Sym_desc))) == NULL)
return (S_ERROR);
cpp->c_osdp->sd_name = name;
cpp->c_osdp->sd_sym = nsym;
cpp->c_osdp->sd_shndx = shndx;
cpp->c_osdp->sd_file = ifl;
cpp->c_osdp->sd_isc = ifl->ifl_isdesc[shndx];
cpp->c_osdp->sd_ref = REF_REL_NEED;
cpp->c_group = cdp->ca_groups->apl_data[0];
cpp->c_ndx = ndx;
if ((rsym = libld_malloc(sizeof (Sym))) == NULL)
return (S_ERROR);
*rsym = *nsym;
rsym->st_info = ELF_ST_INFO(STB_GLOBAL, ntype);
rsym->st_shndx = shndx = SHN_UNDEF;
rsym->st_value = 0;
rsym->st_size = 0;
sdflags |= FLG_SY_CAP;
nsym = rsym;
}
if ((sdp = ld_sym_find(name, hash, &where, ofl)) == NULL) {
DBG_CALL(Dbg_syms_global(ofl->ofl_lml, ndx, name));
if ((sdp = ld_sym_enter(name, nsym, hash, ifl, ofl, ndx,
shndx, sdflags, &where)) == (Sym_desc *)S_ERROR)
return (S_ERROR);
} else if (ld_sym_resolve(sdp, nsym, ifl, ofl, ndx, shndx,
sdflags) == S_ERROR) {
return (S_ERROR);
}
if (cpp)
cpp->c_nsdp = sdp;
if ((etype == ET_DYN) && (nsym->st_shndx != SHN_UNDEF) &&
((sdp->sd_flags & FLG_SY_SOFOUND) == 0))
sdp->sd_flags |= FLG_SY_SOFOUND;
if (sdp->sd_file == ifl)
sdp->sd_symndx = ndx;
ifl->ifl_oldndx[ndx] = sdp;
if (sdp->sd_flags & FLG_SY_REGSYM) {
Sym_desc *rsdp;
rsdp = (*ld_targ.t_ms.ms_reg_find)(sdp->sd_sym, ofl);
if (rsdp == NULL) {
if ((*ld_targ.t_ms.ms_reg_enter)(sdp, ofl) == 0)
return (S_ERROR);
} else if (rsdp != sdp) {
(void) (*ld_targ.t_ms.ms_reg_check)(rsdp,
sdp->sd_sym, sdp->sd_name, ifl, ofl);
}
}
if ((etype == ET_REL) && (sdp->sd_file == ifl)) {
Sym *tsym = sdp->sd_sym;
if (SYM_LOC_BADADDR(sdp, tsym,
ELF_ST_TYPE(tsym->st_info))) {
issue_badaddr_msg(ifl, ofl, sdp,
tsym, tsym->st_shndx);
continue;
}
}
}
DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
if (weak && (OFL_ALLOW_LDYNSYM(ofl) || (etype == ET_DYN)) &&
(total > local)) {
static Sym_desc **sort;
static size_t osize = 0;
size_t nsize = (total - local) * sizeof (Sym_desc *);
if ((osize == 0) || (nsize > osize)) {
if ((sort = libld_malloc(nsize)) == NULL)
return (S_ERROR);
osize = nsize;
}
(void) memcpy((void *)sort, &ifl->ifl_oldndx[local], nsize);
qsort(sort, (total - local), sizeof (Sym_desc *), compare);
for (ndx = 0; ndx < (total - local); ndx++) {
Sym_desc *wsdp = sort[ndx];
Sym *wsym;
int sndx;
if ((wsdp == NULL) || (wsdp->sd_file != ifl))
continue;
wsym = wsdp->sd_sym;
if ((wsym->st_shndx == SHN_UNDEF) ||
(wsdp->sd_flags & FLG_SY_SPECSEC) ||
(ELF_ST_BIND(wsym->st_info) != STB_WEAK))
continue;
for (sndx = ndx + 1; sndx < (total - local); sndx++) {
Sym_desc *ssdp = sort[sndx];
Sym *ssym;
sd_flag_t w_dynbits, s_dynbits;
if ((ssdp == NULL) || (ssdp->sd_file != ifl))
continue;
ssym = ssdp->sd_sym;
if (ssym->st_shndx == SHN_UNDEF)
continue;
if ((ssym->st_shndx != wsym->st_shndx) ||
(ssym->st_value != wsym->st_value))
break;
if ((ssym->st_size != wsym->st_size) ||
(ssdp->sd_flags & FLG_SY_SPECSEC) ||
(ELF_ST_BIND(ssym->st_info) == STB_WEAK))
continue;
if (etype == ET_DYN) {
ssdp->sd_aux->sa_linkndx =
(Word)wsdp->sd_symndx;
wsdp->sd_aux->sa_linkndx =
(Word)ssdp->sd_symndx;
}
w_dynbits = wsdp->sd_flags &
(FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
s_dynbits = ssdp->sd_flags &
(FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
if (!(w_dynbits && s_dynbits)) {
if (s_dynbits) {
if (s_dynbits == FLG_SY_DYNSORT)
wsdp->sd_flags |=
FLG_SY_NODYNSORT;
} else if (w_dynbits !=
FLG_SY_NODYNSORT) {
ssdp->sd_flags |=
FLG_SY_NODYNSORT;
}
}
break;
}
}
}
if (cappairs) {
Aliste idx1;
Cap_pair *cpp1;
for (ALIST_TRAVERSE(cappairs, idx1, cpp1)) {
Sym_desc *sdp1 = cpp1->c_osdp;
Sym *sym1 = sdp1->sd_sym;
uchar_t bind1 = ELF_ST_BIND(sym1->st_info);
Aliste idx2;
Cap_pair *cpp2;
if (bind1 != STB_WEAK)
continue;
for (ALIST_TRAVERSE(cappairs, idx2, cpp2)) {
Sym_desc *sdp2 = cpp2->c_osdp;
Sym *sym2 = sdp2->sd_sym;
uchar_t bind2 =
ELF_ST_BIND(sym2->st_info);
if ((cpp1 == cpp2) ||
(cpp1->c_group != cpp2->c_group) ||
(sym1->st_value != sym2->st_value) ||
(bind2 == STB_WEAK))
continue;
if (ld_cap_add_family(ofl, cpp2->c_nsdp,
cpp1->c_nsdp, NULL, NULL) == S_ERROR)
return (S_ERROR);
free((void *)cpp1->c_osdp);
(void) alist_delete(cappairs, &idx1);
}
}
DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
for (ALIST_TRAVERSE(cappairs, idx1, cpp1)) {
Sym_desc *osdp = cpp1->c_osdp;
Objcapset *capset;
size_t nsize, tsize;
const char *oname;
char *cname, *idstr;
Sym *csym;
if ((osdp->sd_flags & FLG_SY_CAP) != 0)
continue;
capset = &cpp1->c_group->cg_set;
oname = osdp->sd_name;
idstr = capset->oc_id.cs_str;
nsize = strlen(oname);
tsize = nsize + 1 + strlen(idstr) + 1;
if ((cname = libld_malloc(tsize)) == NULL)
return (S_ERROR);
(void) strcpy(cname, oname);
cname[nsize++] = '%';
(void) strcpy(&cname[nsize], idstr);
if ((csym = libld_malloc(sizeof (Sym))) == NULL)
return (S_ERROR);
*csym = *osdp->sd_sym;
csym->st_info = ELF_ST_INFO(STB_LOCAL,
ELF_ST_TYPE(osdp->sd_sym->st_info));
osdp->sd_name = cname;
osdp->sd_sym = csym;
osdp->sd_flags = FLG_SY_CAP;
ofl->ofl_caploclcnt++;
if (st_insert(ofl->ofl_strtab, cname) == -1)
return (S_ERROR);
DBG_CALL(Dbg_syms_cap_local(ofl, cpp1->c_ndx,
cname, csym, osdp));
if (ld_cap_add_family(ofl, cpp1->c_nsdp, osdp,
cpp1->c_group, &ifl->ifl_caps->ca_syms) == S_ERROR)
return (S_ERROR);
}
}
return (1);
#undef SYM_LOC_BADADDR
}
Sym_desc *
ld_sym_add_u(const char *name, Ofl_desc *ofl, Msg mid)
{
Sym *sym;
Ifl_desc *ifl = NULL, *_ifl;
Sym_desc *sdp;
Word hash;
Aliste idx;
avl_index_t where;
const char *reference = MSG_INTL(mid);
hash = (Word)elf_hash(name);
if ((sdp = ld_sym_find(name, hash, &where, ofl)) != NULL) {
if ((sdp->sd_sym->st_shndx == SHN_UNDEF) &&
(sdp->sd_file->ifl_name == reference))
return (sdp);
}
for (APLIST_TRAVERSE(ofl->ofl_objs, idx, _ifl))
if (strcmp(_ifl->ifl_name, reference) == 0) {
ifl = _ifl;
break;
}
if (ifl == NULL) {
if ((ifl = libld_calloc(1, sizeof (Ifl_desc))) == NULL)
return ((Sym_desc *)S_ERROR);
ifl->ifl_name = reference;
ifl->ifl_flags = FLG_IF_NEEDED | FLG_IF_FILEREF;
if ((ifl->ifl_ehdr = libld_calloc(1, sizeof (Ehdr))) == NULL)
return ((Sym_desc *)S_ERROR);
ifl->ifl_ehdr->e_type = ET_REL;
if (aplist_append(&ofl->ofl_objs, ifl, AL_CNT_OFL_OBJS) == NULL)
return ((Sym_desc *)S_ERROR);
}
if ((sym = libld_calloc(1, sizeof (Sym))) == NULL)
return ((Sym_desc *)S_ERROR);
sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
sym->st_shndx = SHN_UNDEF;
DBG_CALL(Dbg_syms_process(ofl->ofl_lml, ifl));
if (sdp == NULL) {
DBG_CALL(Dbg_syms_global(ofl->ofl_lml, 0, name));
if ((sdp = ld_sym_enter(name, sym, hash, ifl, ofl, 0, SHN_UNDEF,
0, &where)) == (Sym_desc *)S_ERROR)
return ((Sym_desc *)S_ERROR);
} else if (ld_sym_resolve(sdp, sym, ifl, ofl, 0,
SHN_UNDEF, 0) == S_ERROR)
return ((Sym_desc *)S_ERROR);
sdp->sd_flags &= ~FLG_SY_CLEAN;
sdp->sd_flags |= FLG_SY_CMDREF;
return (sdp);
}
const char *
ld_stt_section_sym_name(Is_desc *isp)
{
const char *fmt;
char *str;
size_t len;
if ((isp == NULL) || (isp->is_name == NULL))
return (NULL);
if (isp->is_sym_name == NULL) {
fmt = (isp->is_flags & FLG_IS_GNSTRMRG) ?
MSG_INTL(MSG_STR_SECTION_MSTR) : MSG_INTL(MSG_STR_SECTION);
len = strlen(fmt) + strlen(isp->is_name) + 1;
if ((str = libld_malloc(len)) == NULL)
return (NULL);
(void) snprintf(str, len, fmt, isp->is_name);
isp->is_sym_name = str;
}
return (isp->is_sym_name);
}
Boolean
ld_sym_reducable(Ofl_desc *ofl, Sym_desc *sdp)
{
Is_desc *isc = sdp->sd_isc;
if (((ofl->ofl_flags & FLG_OF_RELOBJ) != 0) &&
(isc != NULL) &&
((isc->is_flags & FLG_IS_COMDAT) != 0)) {
return (FALSE);
} else {
return (SYM_IS_HIDDEN(sdp) &&
(ofl->ofl_flags & FLG_OF_PROCRED));
}
}