#include <stdio.h>
#include <string.h>
#include <link.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
static uintptr_t
gpavl_loaded(Ofl_desc *ofl, Group_desc *gdp)
{
Isd_node isd, *isdp;
avl_tree_t *avlt;
avl_index_t where;
if ((avlt = ofl->ofl_groups) == NULL) {
if ((avlt = libld_calloc(1, sizeof (avl_tree_t))) == NULL)
return (S_ERROR);
avl_create(avlt, isdavl_compare, sizeof (Isd_node),
SGSOFFSETOF(Isd_node, isd_avl));
ofl->ofl_groups = avlt;
}
isd.isd_name = gdp->gd_name;
isd.isd_hash = sgs_str_hash(isd.isd_name);
if ((isdp = avl_find(avlt, &isd, &where)) != NULL) {
gdp->gd_oisc = isdp->isd_isp;
return (1);
}
if ((isdp = libld_calloc(1, sizeof (Isd_node))) == NULL)
return (S_ERROR);
isdp->isd_name = isd.isd_name;
isdp->isd_hash = isd.isd_hash;
isdp->isd_isp = gdp->gd_isc;
avl_insert(avlt, isdp, where);
return (0);
}
Group_desc *
ld_get_group(Ofl_desc *ofl, Is_desc *isp)
{
Ifl_desc *ifl = isp->is_file;
uint_t scnndx = isp->is_scnndx;
Group_desc *gdp;
Aliste idx;
for (ALIST_TRAVERSE(ifl->ifl_groups, idx, gdp)) {
size_t ndx;
Word *data;
if (isp->is_shdr->sh_type == SHT_GROUP) {
if (isp->is_scnndx == gdp->gd_isc->is_scnndx)
return (gdp);
continue;
}
data = gdp->gd_data;
for (ndx = 1; ndx < gdp->gd_cnt; ndx++) {
if (data[ndx] == scnndx)
return (gdp);
}
}
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_ELF_NOGROUPSECT),
ifl->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name);
return (NULL);
}
static boolean_t
is_header_gensym(const char *name)
{
const char *c = NULL;
size_t len = strlen(name);
if (len < 37)
return (B_FALSE);
if ((strncmp(name, "wm4.", 4) != 0) &&
strncmp(name, "wm8.", 4) != 0)
return (B_FALSE);
c = &name[len - 33];
if (*c++ != '.')
return (B_FALSE);
for (; *c != '\0'; c++) {
if (!(((*c >= 'a') && (*c <= 'f')) ||
((*c >= '0') && (*c <= '9')))) {
return (B_FALSE);
}
}
return (B_TRUE);
}
uintptr_t
ld_group_process(Is_desc *gisc, Ofl_desc *ofl)
{
Ifl_desc *gifl = gisc->is_file;
Shdr *sshdr, *gshdr = gisc->is_shdr;
Word *new_data = NULL;
Shdr *new_shdr = NULL;
Is_desc *isc;
Sym *sym;
const char *str;
Group_desc gd;
size_t ndx;
int gnu_stt_section;
if ((gshdr->sh_link == SHN_UNDEF) ||
(gshdr->sh_link >= gifl->ifl_shnum) ||
((isc = gifl->ifl_isdesc[gshdr->sh_link]) == NULL)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK),
gifl->ifl_name, EC_WORD(gisc->is_scnndx),
gisc->is_name, EC_XWORD(gshdr->sh_link));
return (0);
}
if (gshdr->sh_entsize == 0) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHENTSIZE),
gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
EC_XWORD(gshdr->sh_entsize));
return (0);
}
sshdr = isc->is_shdr;
sym = (Sym *)isc->is_indata->d_buf;
if ((sshdr->sh_info == SHN_UNDEF) ||
(gshdr->sh_info >= (Word)(sshdr->sh_size / sshdr->sh_entsize)) ||
((isc = gifl->ifl_isdesc[sshdr->sh_link]) == NULL)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
gifl->ifl_name, EC_WORD(gisc->is_scnndx), gisc->is_name,
EC_XWORD(gshdr->sh_info));
return (0);
}
sym += gshdr->sh_info;
str = (char *)isc->is_indata->d_buf;
str += sym->st_name;
gnu_stt_section = ((sym->st_name == 0) || (*str == '\0')) &&
(ELF_ST_TYPE(sym->st_info) == STT_SECTION);
if (gnu_stt_section)
str = gisc->is_name;
gd.gd_isc = gisc;
gd.gd_oisc = NULL;
gd.gd_name = str;
gd.gd_data = gisc->is_indata->d_buf;
gd.gd_cnt = gisc->is_indata->d_size / sizeof (Word);
if (is_header_gensym(str)) {
if ((ofl->ofl_flags1 & FLG_OF1_NRLXREL) == 0)
ofl->ofl_flags1 |= FLG_OF1_RLXREL;
DBG_CALL(Dbg_sec_gnu_comdat(ofl->ofl_lml, gisc, TRUE,
(ofl->ofl_flags1 & FLG_OF1_RLXREL) != 0));
}
for (ndx = (gd.gd_cnt - 1); ndx >= 1; ndx--) {
Word gndx = gd.gd_data[ndx];
if ((gndx == 0) || (gndx >= gifl->ifl_shnum)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_GRP_INVALNDX), gifl->ifl_name,
EC_WORD(gisc->is_scnndx), gisc->is_name, ndx, gndx);
return (0);
}
if (gifl->ifl_isdesc[gndx] == NULL) {
if (new_data == NULL) {
if ((new_data = libld_calloc(sizeof (Word),
gd.gd_cnt)) == NULL)
return (S_ERROR);
memcpy(new_data, gd.gd_data,
sizeof (Word) * gd.gd_cnt);
gisc->is_indata->d_buf = gd.gd_data = new_data;
new_shdr = libld_malloc(sizeof (Shdr));
if (new_shdr == NULL)
return (S_ERROR);
memcpy(new_shdr, gisc->is_shdr, sizeof (Shdr));
gisc->is_shdr = new_shdr;
}
if (ndx < (gd.gd_cnt - 1)) {
memmove(&gd.gd_data[ndx], &gd.gd_data[ndx + 1],
(gd.gd_cnt - (ndx + 1)) * sizeof (Word));
}
gisc->is_indata->d_size -= sizeof (Word);
gisc->is_shdr->sh_size -= sizeof (Word);
gd.gd_cnt -= 1;
continue;
}
if (gd.gd_data[0] & GRP_COMDAT)
gifl->ifl_isdesc[gndx]->is_flags |= FLG_IS_COMDAT;
}
if (gd.gd_cnt == 1)
gisc->is_flags |= FLG_IS_DISCARD;
if ((gd.gd_data[0] & GRP_COMDAT) &&
(gpavl_loaded(ofl, &gd) == S_ERROR))
return (S_ERROR);
if (alist_append(&(gifl->ifl_groups), &gd, sizeof (Group_desc),
AL_CNT_IFL_GROUPS) == NULL)
return (S_ERROR);
return (1);
}