#include <string.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
static uintptr_t
make_mvsections(Ofl_desc *ofl)
{
Aliste idx;
Sym_desc *sdp;
Word mv_nums = 0;
Xword align_parexpn = 0;
size_t size_parexpn = 0;
for (APLIST_TRAVERSE(ofl->ofl_parsyms, idx, sdp)) {
if (sdp->sd_flags & FLG_SY_PAREXPN) {
Sym *sym = sdp->sd_sym;
Xword align_val;
if (sym->st_shndx == SHN_COMMON)
align_val = sym->st_value;
else
align_val = 8;
size_parexpn = (size_t)S_ROUND(size_parexpn,
sym->st_value) + sym->st_size;
if (align_val > align_parexpn)
align_parexpn = align_val;
} else {
mv_nums += alist_nitems(sdp->sd_move);
}
}
if (mv_nums && (ld_make_sunwmove(ofl, mv_nums) == S_ERROR))
return (S_ERROR);
if (size_parexpn) {
if (ld_make_parexpn_data(ofl, size_parexpn,
align_parexpn) == S_ERROR)
return (S_ERROR);
}
return (1);
}
static uintptr_t
append_move_desc(Ofl_desc *ofl, Sym_desc *sdp, Move *mvp, Is_desc *isp)
{
int i, cnt = mvp->m_repeat;
for (i = 0; i < cnt; i++) {
Aliste idx;
Mv_desc *omdp, nmd;
nmd.md_len = ELF_M_SIZE(mvp->m_info);
nmd.md_start = mvp->m_poffset + i *
((mvp->m_stride + 1) * nmd.md_len);
nmd.md_move = mvp;
for (ALIST_TRAVERSE(sdp->sd_move, idx, omdp)) {
Mv_desc *smdp, *lmdp;
if (nmd.md_start > omdp->md_start) {
smdp = omdp;
lmdp = &nmd;
} else {
smdp = &nmd;
lmdp = omdp;
}
if ((nmd.md_start == omdp->md_start) &&
((nmd.md_len == smdp->md_len) &&
sdp->sd_file != isp->is_file))
continue;
if ((nmd.md_start != omdp->md_start) &&
((smdp->md_start + smdp->md_len) <= lmdp->md_start))
continue;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_MOVE_OVERLAP),
sdp->sd_file->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name, demangle(sdp->sd_name),
EC_XWORD(nmd.md_start), EC_XWORD(nmd.md_len),
EC_XWORD(omdp->md_start), EC_XWORD(omdp->md_len));
sdp->sd_flags |= FLG_SY_OVERLAP;
return (1);
}
if (alist_append(&sdp->sd_move, &nmd, sizeof (Mv_desc),
AL_CNT_SDP_MOVE) == NULL)
return (S_ERROR);
}
return (1);
}
uintptr_t
ld_process_move(Ofl_desc *ofl)
{
Aliste idx;
Is_desc *isp;
int errcnt = 0;
for (APLIST_TRAVERSE(ofl->ofl_ismove, idx, isp)) {
Ifl_desc *ifile = isp->is_file;
Move *mvp;
Xword i, num;
DBG_CALL(Dbg_move_input(ofl->ofl_lml, ifile->ifl_name));
mvp = (Move *)isp->is_indata->d_buf;
if (isp->is_shdr->sh_entsize == 0) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_FIL_INVSHENTSIZE),
isp->is_file->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name, EC_XWORD(0));
return (S_ERROR);
}
num = isp->is_shdr->sh_size / isp->is_shdr->sh_entsize;
for (i = 0; i < num; i++) {
Xword ndx = ELF_M_SYM(mvp->m_info);
Sym_desc *sdp;
Sym *sym;
if ((ndx >= (Xword) isp->is_file->ifl_symscnt) ||
(ndx == 0)) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_PSYM_INVMINFO1),
isp->is_file->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name, i,
EC_XWORD(mvp->m_info));
return (S_ERROR);
}
if (mvp->m_repeat == 0) {
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_PSYM_INVMREPEAT),
isp->is_file->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name, i,
EC_XWORD(mvp->m_repeat));
return (S_ERROR);
}
sdp = isp->is_file->ifl_oldndx[ndx];
DBG_CALL(Dbg_move_entry1(ofl->ofl_lml, 1, mvp, sdp));
switch (ELF_M_SIZE(mvp->m_info)) {
case 1: case 2: case 4: case 8:
break;
default:
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_PSYM_INVMINFO2),
isp->is_file->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name, i,
EC_XWORD(mvp->m_info));
return (S_ERROR);
}
if (sdp->sd_aux &&
((sdp->sd_flags & FLG_SY_VISIBLE) == 0))
ld_sym_adjust_vis(sdp, ofl);
sym = sdp->sd_sym;
if (sdp->sd_move == NULL) {
if (aplist_append(&ofl->ofl_parsyms, sdp,
AL_CNT_OFL_PARSYMS) == NULL)
return (S_ERROR);
if ((ofl->ofl_flags & FLG_OF_REDLSYM) &&
(ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
(ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
ofl->ofl_locscnt++;
if (st_insert(ofl->ofl_strtab,
sdp->sd_name) == -1)
return (S_ERROR);
}
if ((sym->st_shndx != SHN_UNDEF) &&
(sym->st_shndx < SHN_LOPROC)) {
Is_desc *isc;
isc = ifile->ifl_isdesc[ sym->st_shndx];
isc->is_flags |= FLG_IS_RELUPD;
if (sdp->sd_osym == NULL) {
if ((sdp->sd_osym =
libld_calloc(1,
sizeof (Sym))) == NULL)
return (S_ERROR);
*(sdp->sd_osym) =
*(sdp->sd_sym);
}
}
}
if (append_move_desc(ofl, sdp, mvp, isp) == S_ERROR)
return (S_ERROR);
if (sdp->sd_flags & FLG_SY_OVERLAP)
errcnt++;
if (sdp->sd_flags & FLG_SY_PAREXPN) {
mvp++;
continue;
}
if (OFL_IS_STATIC_EXEC(ofl)) {
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
errcnt++;
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_PSYM_CANNOTEXPND),
sdp->sd_file->ifl_name,
EC_WORD(isp->is_scnndx),
isp->is_name, i,
MSG_INTL(MSG_PSYM_NOSTATIC));
} else {
sdp->sd_flags |= FLG_SY_PAREXPN;
}
} else if ((ofl->ofl_flags1 & FLG_OF1_NOPARTI) != 0) {
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_PSYM_CANNOTEXPND),
sdp->sd_file->ifl_name,
EC_WORD(isp->is_scnndx),
isp->is_name, i,
MSG_ORIG(MSG_STR_EMPTY));
} else {
sdp->sd_flags |= FLG_SY_PAREXPN;
}
} else if (((Xword)((sizeof (Move)) *
alist_nitems(sdp->sd_move)) > sym->st_size) &&
(ELF_ST_TYPE(sym->st_info) == STT_OBJECT)) {
sdp->sd_flags |= FLG_SY_PAREXPN;
}
if ((ELF_ST_BIND(sym->st_info) == STB_LOCAL) &&
(((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) ||
(ofl->ofl_flags & FLG_OF_REDLSYM))) {
Os_desc *osp = sdp->sd_isc->is_osdesc;
if (osp &&
((osp->os_flags & FLG_OS_OUTREL) == 0)) {
ofl->ofl_dynshdrcnt++;
osp->os_flags |= FLG_OS_OUTREL;
} else if ((sdp->sd_flags &
FLG_SY_PAREXPN) == 0)
ofl->ofl_flags1 |= FLG_OF1_BSSOREL;
}
mvp++;
}
}
if (errcnt != 0)
return (S_ERROR);
if (make_mvsections(ofl) == S_ERROR)
return (S_ERROR);
return (1);
}