#define ELF_TARGET_AMD64
#define ELF_TARGET_SPARC
#include <string.h>
#include <stdio.h>
#include <alloca.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
#define IS_PLT(X) RELTAB_IS_PLT(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOT_RELATIVE(X) \
RELTAB_IS_GOT_RELATIVE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOT_PC(X) RELTAB_IS_GOT_PC(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOTPCREL(X) RELTAB_IS_GOTPCREL(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOT_BASED(X) RELTAB_IS_GOT_BASED(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOT_OPINS(X) RELTAB_IS_GOT_OPINS(X, ld_targ.t_mr.mr_reloc_table)
#define IS_GOT_REQUIRED(X) \
RELTAB_IS_GOT_REQUIRED(X, ld_targ.t_mr.mr_reloc_table)
#define IS_PC_RELATIVE(X) RELTAB_IS_PC_RELATIVE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_ADD_RELATIVE(X) \
RELTAB_IS_ADD_RELATIVE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_REGISTER(X) RELTAB_IS_REGISTER(X, ld_targ.t_mr.mr_reloc_table)
#define IS_NOTSUP(X) RELTAB_IS_NOTSUP(X, ld_targ.t_mr.mr_reloc_table)
#define IS_SEG_RELATIVE(X) \
RELTAB_IS_SEG_RELATIVE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_EXTOFFSET(X) RELTAB_IS_EXTOFFSET(X, ld_targ.t_mr.mr_reloc_table)
#define IS_SEC_RELATIVE(X) \
RELTAB_IS_SEC_RELATIVE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_TLS_INS(X) RELTAB_IS_TLS_INS(X, ld_targ.t_mr.mr_reloc_table)
#define IS_TLS_GD(X) RELTAB_IS_TLS_GD(X, ld_targ.t_mr.mr_reloc_table)
#define IS_TLS_LD(X) RELTAB_IS_TLS_LD(X, ld_targ.t_mr.mr_reloc_table)
#define IS_TLS_IE(X) RELTAB_IS_TLS_IE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_TLS_LE(X) RELTAB_IS_TLS_LE(X, ld_targ.t_mr.mr_reloc_table)
#define IS_LOCALBND(X) RELTAB_IS_LOCALBND(X, ld_targ.t_mr.mr_reloc_table)
#define IS_SIZE(X) RELTAB_IS_SIZE(X, ld_targ.t_mr.mr_reloc_table)
typedef struct copy_rel {
Sym_desc *c_sdp;
Addr c_val;
} Copy_rel;
static void
is_disp_copied(Ofl_desc *ofl, Copy_rel *crp)
{
Ifl_desc *ifl = crp->c_sdp->sd_file;
Sym_desc *sdp = crp->c_sdp;
Addr symaddr = crp->c_val;
Is_desc *irel;
Aliste idx;
Conv_inv_buf_t inv_buf;
if ((ifl->ifl_flags & FLG_IF_DISPDONE) &&
(ofl->ofl_flags & FLG_OF_VERBOSE))
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_DISPREL2),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
ld_targ.t_m.m_r_copy, 0, &inv_buf),
ifl->ifl_name, demangle(sdp->sd_name));
if ((ifl->ifl_flags & FLG_IF_DISPPEND) == 0)
return;
for (APLIST_TRAVERSE(ifl->ifl_relsect, idx, irel)) {
Sym_desc *rsdp;
Is_desc *trel;
Rel *rend, *reloc;
Xword rsize, entsize;
trel = ifl->ifl_isdesc[irel->is_shdr->sh_info];
rsize = irel->is_shdr->sh_size;
entsize = irel->is_shdr->sh_entsize;
reloc = (Rel *)irel->is_indata->d_buf;
if ((entsize == 0) || (entsize > rsize)) {
if (irel->is_shdr->sh_type == SHT_RELA)
entsize = sizeof (Rela);
else
entsize = sizeof (Rel);
}
for (rend = (Rel *)((uintptr_t)reloc + (uintptr_t)rsize);
reloc < rend;
reloc = (Rel *)((uintptr_t)reloc + (uintptr_t)entsize)) {
const char *str;
Word rstndx;
if (IS_PC_RELATIVE(ELF_R_TYPE(reloc->r_info,
ld_targ.t_m.m_mach)) == 0)
continue;
rstndx = (Word) ELF_R_SYM(reloc->r_info);
rsdp = ifl->ifl_oldndx[rstndx];
if (rsdp == sdp) {
if ((str = demangle(rsdp->sd_name)) !=
rsdp->sd_name) {
char *_str = alloca(strlen(str) + 1);
(void) strcpy(_str, str);
str = (const char *)_str;
}
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_REL_DISPREL1),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
(uint_t)ELF_R_TYPE(reloc->r_info,
ld_targ.t_m.m_mach),
0, &inv_buf), ifl->ifl_name, str,
MSG_INTL(MSG_STR_UNKNOWN),
EC_XWORD(reloc->r_offset),
demangle(sdp->sd_name));
}
if ((sdp->sd_isc != trel) ||
(reloc->r_offset < symaddr) ||
(reloc->r_offset >=
(symaddr + sdp->sd_sym->st_size)))
continue;
if ((str = demangle(sdp->sd_name)) != sdp->sd_name) {
char *_str = alloca(strlen(str) + 1);
(void) strcpy(_str, str);
str = (const char *)_str;
}
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_DISPREL1),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
(uint_t)ELF_R_TYPE(reloc->r_info,
ld_targ.t_m.m_mach), 0, &inv_buf),
ifl->ifl_name, demangle(rsdp->sd_name), str,
EC_XWORD(reloc->r_offset), str);
}
}
}
static int
disp_bsearch(const void *key, const void *array)
{
Addr kvalue, avalue;
Ssv_desc *ssvp = (Ssv_desc *)array;
kvalue = *((Addr *)key);
avalue = ssvp->ssv_value;
if (avalue > kvalue)
return (-1);
if ((avalue < kvalue) &&
((avalue + ssvp->ssv_sdp->sd_sym->st_size) <= kvalue))
return (1);
return (0);
}
static Sym_desc *
disp_scansyms(Ifl_desc * ifl, Rel_desc *rld, Boolean rlocal, int inspect,
Ofl_desc *ofl)
{
Sym_desc *tsdp, *rsdp;
Sym *rsym, *tsym;
Ssv_desc *ssvp;
uchar_t rtype, ttype;
Addr value;
value = rld->rel_roffset;
if (rld->rel_isdesc->is_shdr)
value += rld->rel_isdesc->is_shdr->sh_offset;
if ((ssvp = bsearch((void *)&value, (void *)ifl->ifl_sortsyms,
ifl->ifl_sortcnt, sizeof (Ssv_desc), &disp_bsearch)) != 0)
tsdp = ssvp->ssv_sdp;
else
tsdp = 0;
if (inspect)
return (tsdp);
rsdp = rld->rel_sym;
rsym = rsdp->sd_sym;
rtype = ELF_ST_TYPE(rsym->st_info);
if (tsdp == 0) {
if ((rlocal == TRUE) ||
((rtype != STT_OBJECT) && (rtype != STT_SECTION)))
return (tsdp);
} else {
if ((rlocal == TRUE) && (SYM_IS_HIDDEN(tsdp) ||
(ELF_ST_BIND(tsdp->sd_sym->st_info) != STB_GLOBAL) ||
((ofl->ofl_flags & (FLG_OF_AUTOLCL | FLG_OF_AUTOELM)) &&
((tsdp->sd_flags & MSK_SY_NOAUTO) == 0))))
return (tsdp);
tsym = tsdp->sd_sym;
ttype = ELF_ST_TYPE(tsym->st_info);
if ((rlocal == TRUE) && (ttype != STT_OBJECT) &&
(ttype != STT_SECTION))
return (tsdp);
if ((rtype != STT_OBJECT) && (rtype != STT_SECTION) &&
(ttype != STT_OBJECT) && (ttype != STT_SECTION))
return (tsdp);
}
value = rsym->st_value;
if ((rld->rel_flags & FLG_REL_RELA) == FLG_REL_RELA)
value += rld->rel_raddend;
if ((rld->rel_roffset >= value) &&
(rld->rel_roffset < (value + rsym->st_size)))
return (tsdp);
rld->rel_flags |= FLG_REL_DISP;
return (tsdp);
}
void
ld_disp_errmsg(const char *msg, Rel_desc *rsp, Ofl_desc *ofl)
{
Sym_desc *sdp;
const char *str;
Ifl_desc *ifl = rsp->rel_isdesc->is_file;
Conv_inv_buf_t inv_buf;
if ((sdp = disp_scansyms(ifl, rsp, 0, 1, ofl)) != 0)
str = demangle(sdp->sd_name);
else
str = MSG_INTL(MSG_STR_UNKNOWN);
ld_eprintf(ofl, ERR_WARNING, msg,
conv_reloc_type(ifl->ifl_ehdr->e_machine, rsp->rel_rtype,
0, &inv_buf), ifl->ifl_name, ld_reloc_sym_name(rsp), str,
EC_OFF(rsp->rel_roffset));
}
static int
disp_qsort(const void * s1, const void * s2)
{
Ssv_desc *ssvp1 = ((Ssv_desc *)s1);
Ssv_desc *ssvp2 = ((Ssv_desc *)s2);
Addr val1 = ssvp1->ssv_value;
Addr val2 = ssvp2->ssv_value;
if (val1 > val2)
return (1);
if (val1 < val2)
return (-1);
return (0);
}
static uintptr_t
disp_inspect(Ofl_desc *ofl, Rel_desc *rld, Boolean rlocal)
{
Is_desc *isp = rld->rel_isdesc;
Ifl_desc *ifl = rld->rel_isdesc->is_file;
if (ifl->ifl_sortsyms == 0) {
Word ondx, nndx;
if ((ifl->ifl_sortsyms = libld_malloc((ifl->ifl_symscnt + 1) *
sizeof (Ssv_desc))) == 0)
return (S_ERROR);
for (ondx = 0, nndx = 0; ondx < ifl->ifl_symscnt; ondx++) {
Sym_desc *sdp;
Addr value;
if (((sdp = ifl->ifl_oldndx[ondx]) == 0) ||
(sdp->sd_sym->st_shndx == SHN_UNDEF) ||
(sdp->sd_sym->st_shndx >= SHN_LORESERVE) ||
(sdp->sd_ref != REF_REL_NEED) ||
(sdp->sd_file != ifl) ||
(sdp->sd_sym->st_size == 0))
continue;
if (sdp->sd_isc && (ondx >= ifl->ifl_locscnt))
sdp->sd_isc->is_flags |= FLG_IS_GDATADEF;
value = sdp->sd_sym->st_value;
if (sdp->sd_isc && sdp->sd_isc->is_shdr)
value += sdp->sd_isc->is_shdr->sh_offset;
ifl->ifl_sortsyms[nndx].ssv_value = value;
ifl->ifl_sortsyms[nndx].ssv_sdp = sdp;
nndx++;
}
if ((ifl->ifl_sortcnt = nndx) != 0)
qsort(ifl->ifl_sortsyms, nndx, sizeof (Ssv_desc),
&disp_qsort);
}
if ((rlocal == FALSE) && ((isp->is_flags & FLG_IS_GDATADEF) == 0))
return (1);
if (ifl->ifl_sortcnt)
(void) disp_scansyms(ifl, rld, rlocal, 0, ofl);
return (1);
}
static Rel_cachebuf *
ld_add_rel_cache(Ofl_desc *ofl, Rel_cache *rcp)
{
Rel_cachebuf *rcbp;
size_t nelts, size, alloc_cnt;
alloc_cnt = aplist_nitems(rcp->rc_list);
if (rcp->rc_list &&
((rcbp = rcp->rc_list->apl_data[alloc_cnt - 1]) != NULL) &&
(rcbp->rc_free < rcbp->rc_end))
return (rcbp);
nelts = REL_CACHEBUF_ALLOC;
if ((alloc_cnt == 0) && (ofl->ofl_relocincnt > REL_CACHEBUF_ALLOC)) {
Boolean is_rel = (ofl->ofl_flags & FLG_OF_RELOBJ) != 0;
if (((rcp == &ofl->ofl_actrels) && !is_rel) ||
((rcp == &ofl->ofl_outrels) && is_rel))
nelts = ofl->ofl_relocincnt;
}
size = sizeof (Rel_cachebuf) + ((nelts - 1) * sizeof (Rel_desc));
if (((rcbp = libld_malloc(size)) == NULL) ||
(aplist_append(&rcp->rc_list, rcbp, AL_CNT_OFL_RELS) == NULL))
return (NULL);
rcbp->rc_free = rcbp->rc_arr;
rcbp->rc_end = rcbp->rc_arr + nelts;
return (rcbp);
}
static Boolean
ld_add_rel_aux(Ofl_desc *ofl, Rel_desc *rdesc)
{
Rel_aux_cachebuf *racp = NULL;
size_t size;
if (ofl->ofl_relaux) {
racp = ofl->ofl_relaux->apl_data[
ofl->ofl_relaux->apl_nitems - 1];
if (racp && (racp->rac_free >= racp->rac_end))
racp = NULL;
}
if (racp == NULL) {
size = sizeof (Rel_aux_cachebuf) +
((RELAUX_CACHEBUF_ALLOC - 1) * sizeof (Rel_aux));
if (((racp = libld_malloc(size)) == NULL) ||
(aplist_append(&ofl->ofl_relaux, racp, AL_CNT_OFL_RELS) ==
NULL))
return (FALSE);
racp->rac_free = racp->rac_arr;
racp->rac_end = racp->rac_arr + RELAUX_CACHEBUF_ALLOC;
}
rdesc->rel_aux = racp->rac_free++;
return (TRUE);
}
Rel_desc *
ld_reloc_enter(Ofl_desc *ofl, Rel_cache *rcp, Rel_desc *rdesc, Word flags)
{
Rel_desc *arsp;
Rel_aux *auxp;
Rel_cachebuf *rcbp;
rcbp = ld_add_rel_cache(ofl, rcp);
if (rcbp == NULL)
return (NULL);
arsp = rcbp->rc_free;
if (rdesc->rel_aux != NULL) {
if (!ld_add_rel_aux(ofl, arsp))
return (NULL);
auxp = arsp->rel_aux;
}
*arsp = *rdesc;
if (rdesc->rel_aux != NULL) {
arsp->rel_aux = auxp;
*auxp = *rdesc->rel_aux;
}
arsp->rel_flags |= flags;
rcbp->rc_free++;
rcp->rc_cnt++;
return (arsp);
}
static void
ld_init_rel_aux(Rel_desc *rdesc)
{
Rel_aux *rap = rdesc->rel_aux;
rap->ra_osdesc = (rdesc->rel_isdesc == NULL) ? NULL :
rdesc->rel_isdesc->is_osdesc;
rap->ra_usym = rdesc->rel_sym;
rap->ra_move = NULL;
rap->ra_typedata = 0;
}
#define PROCESS_NULL_REL_AUX(_isdefault_predicate) \
if (rdesc->rel_aux == NULL) { \
\
if (_isdefault_predicate) \
return (TRUE); \
\
if (!ld_add_rel_aux(ofl, rdesc)) \
return (FALSE); \
\
ld_init_rel_aux(rdesc); \
}
Boolean
ld_reloc_set_aux_osdesc(Ofl_desc *ofl, Rel_desc *rdesc, Os_desc *osp)
{
PROCESS_NULL_REL_AUX(RELAUX_ISDEFAULT_OSDESC(rdesc, osp))
rdesc->rel_aux->ra_osdesc = osp;
return (TRUE);
}
Boolean
ld_reloc_set_aux_usym(Ofl_desc *ofl, Rel_desc *rdesc, Sym_desc *sdp)
{
PROCESS_NULL_REL_AUX(RELAUX_ISDEFAULT_USYM(rdesc, sdp))
rdesc->rel_aux->ra_usym = sdp;
return (TRUE);
}
#undef PROCESS_NULL_REL_AUX
const char *
ld_reloc_sym_name(Rel_desc *rsp)
{
Sym_desc *sdp = rsp->rel_sym;
if (sdp != NULL) {
if (sdp->sd_name && *sdp->sd_name)
return (demangle(sdp->sd_name));
if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) &&
(sdp->sd_isc != NULL) && (sdp->sd_isc->is_sym_name != NULL))
return (demangle(sdp->sd_isc->is_sym_name));
} else {
if (IS_REGISTER(rsp->rel_rtype))
return (MSG_ORIG(MSG_STR_EMPTY));
}
return (MSG_INTL(MSG_STR_UNKNOWN));
}
uintptr_t
ld_add_actrel(Word flags, Rel_desc *rsp, Ofl_desc *ofl)
{
Rel_desc *arsp;
if ((arsp = ld_reloc_enter(ofl, &ofl->ofl_actrels, rsp, flags)) == NULL)
return (S_ERROR);
if (IS_GOT_REQUIRED(arsp->rel_rtype))
ofl->ofl_flags |= FLG_OF_BLDGOT;
if (arsp->rel_flags & FLG_REL_DISP) {
ofl->ofl_dtflags_1 |= DF_1_DISPRELDNE;
if (ofl->ofl_flags & FLG_OF_VERBOSE)
ld_disp_errmsg(MSG_INTL(MSG_REL_DISPREL3), arsp, ofl);
}
DBG_CALL(Dbg_reloc_ars_entry(ofl->ofl_lml, ELF_DBG_LD,
arsp->rel_isdesc->is_shdr->sh_type, ld_targ.t_m.m_mach, arsp));
return (1);
}
Word
ld_bswap_Word(Word v)
{
return (BSWAP_WORD(v));
}
Xword
ld_bswap_Xword(Xword v)
{
return (BSWAP_XWORD(v));
}
uintptr_t
ld_reloc_GOT_relative(Boolean local, Rel_desc *rsp, Ofl_desc *ofl)
{
Sym_desc *sdp = rsp->rel_sym;
ofl_flag_t flags = ofl->ofl_flags;
Gotndx *gnp;
if ((gnp = (*ld_targ.t_mr.mr_find_got_ndx)(sdp->sd_GOTndxs,
GOT_REF_GENERIC, ofl, rsp)) == 0) {
Word rtype = rsp->rel_rtype;
if ((*ld_targ.t_mr.mr_assign_got_ndx)(&(sdp->sd_GOTndxs), NULL,
GOT_REF_GENERIC, ofl, rsp, sdp) == S_ERROR)
return (S_ERROR);
if (local == TRUE) {
if ((flags & FLG_OF_SHAROBJ) &&
(((sdp->sd_flags & FLG_SY_SPECSEC) == 0) ||
((sdp->sd_sym->st_shndx != SHN_ABS)) ||
(sdp->sd_aux && sdp->sd_aux->sa_symspec))) {
if (ld_add_actrel((FLG_REL_GOT | FLG_REL_GOTCL),
rsp, ofl) == S_ERROR)
return (S_ERROR);
rsp->rel_rtype = ld_targ.t_m.m_r_relative;
if ((*ld_targ.t_mr.mr_add_outrel)
((FLG_REL_GOT | FLG_REL_ADVAL),
rsp, ofl) == S_ERROR)
return (S_ERROR);
rsp->rel_rtype = rtype;
} else {
if (ld_add_actrel(FLG_REL_GOT, rsp,
ofl) == S_ERROR)
return (S_ERROR);
}
} else {
rsp->rel_rtype = ld_targ.t_m.m_r_glob_dat;
if ((*ld_targ.t_mr.mr_add_outrel)(FLG_REL_GOT,
rsp, ofl) == S_ERROR)
return (S_ERROR);
rsp->rel_rtype = rtype;
}
} else {
if ((*ld_targ.t_mr.mr_assign_got_ndx)(&(sdp->sd_GOTndxs), gnp,
GOT_REF_GENERIC, ofl, rsp, sdp) == S_ERROR)
return (S_ERROR);
}
return (ld_add_actrel(0, rsp, ofl));
}
uintptr_t
ld_reloc_plt(Rel_desc *rsp, Ofl_desc *ofl)
{
Sym_desc *sdp = rsp->rel_sym;
switch (ld_targ.t_m.m_mach) {
case EM_AMD64:
if ((ofl->ofl_flags & FLG_OF_EXEC) &&
(strcmp(sdp->sd_name, MSG_ORIG(MSG_SYM_TLSGETADDR_U)) ==
0))
return (ld_add_actrel(FLG_REL_TLSFIX, rsp, ofl));
break;
case EM_386:
if ((ofl->ofl_flags & FLG_OF_EXEC) &&
(strcmp(sdp->sd_name, MSG_ORIG(MSG_SYM_TLSGETADDR_UU)) ==
0))
return (ld_add_actrel(FLG_REL_TLSFIX, rsp, ofl));
break;
}
if (sdp->sd_aux->sa_PLTndx == 0) {
Word ortype = rsp->rel_rtype;
(*ld_targ.t_mr.mr_assign_plt_ndx)(sdp, ofl);
if (sdp->sd_file) {
if (sdp->sd_file->ifl_flags & FLG_IF_LAZYLD)
sdp->sd_flags |= FLG_SY_LAZYLD;
if (sdp->sd_file->ifl_flags & FLG_IF_DEFERRED)
sdp->sd_flags |= FLG_SY_DEFERRED;
}
rsp->rel_rtype = ld_targ.t_m.m_r_jmp_slot;
if ((*ld_targ.t_mr.mr_add_outrel)(FLG_REL_PLT, rsp, ofl) ==
S_ERROR)
return (S_ERROR);
rsp->rel_rtype = ortype;
}
if ((ofl->ofl_flags & FLG_OF_SHAROBJ) &&
IS_ADD_RELATIVE(rsp->rel_rtype)) {
Word ortype = rsp->rel_rtype;
rsp->rel_rtype = ld_targ.t_m.m_r_relative;
if ((*ld_targ.t_mr.mr_add_outrel)(FLG_REL_ADVAL, rsp, ofl) ==
S_ERROR)
return (S_ERROR);
rsp->rel_rtype = ortype;
return (1);
} else
return (ld_add_actrel(0, rsp, ofl));
}
static Word
nlpo2(Word val)
{
val--;
val |= (val >> 1);
val |= (val >> 2);
val |= (val >> 4);
val |= (val >> 8);
val |= (val >> 16);
return (++val);
}
static uintptr_t
reloc_exec(Rel_desc *rsp, Ofl_desc *ofl)
{
Sym_desc *_sdp, *sdp = rsp->rel_sym;
Sym_aux *sap = sdp->sd_aux;
Sym *sym = sdp->sd_sym;
Addr stval;
if (ELF_ST_TYPE(sym->st_info) == STT_FUNC)
return (ld_reloc_plt(rsp, ofl));
if ((sdp->sd_flags & FLG_SY_SPECSEC) && (sym->st_shndx == SHN_ABS)) {
if ((ofl->ofl_flags1 & FLG_OF1_ABSEXEC) == 0)
return ((*ld_targ.t_mr.mr_add_outrel)(0, rsp, ofl));
sdp->sd_ref = REF_REL_NEED;
return (ld_add_actrel(0, rsp, ofl));
}
if ((ELF_ST_TYPE(sym->st_info) == STT_OBJECT) &&
(RELAUX_GET_OSDESC(rsp)->os_shdr->sh_flags & SHF_WRITE)) {
if (sdp->sd_flags & FLG_SY_MVTOCOMM)
return (ld_add_actrel(0, rsp, ofl));
else
return ((*ld_targ.t_mr.mr_add_outrel)(0, rsp, ofl));
}
if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) {
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_UNEXPSYM),
conv_sym_info_type(sdp->sd_file->ifl_ehdr->e_machine,
ELF_ST_TYPE(sym->st_info), 0, &inv_buf),
rsp->rel_isdesc->is_file->ifl_name,
ld_reloc_sym_name(rsp), sdp->sd_file->ifl_name);
return ((*ld_targ.t_mr.mr_add_outrel)(0, rsp, ofl));
}
if (sap->sa_linkndx) {
_sdp = sdp->sd_file->ifl_oldndx[sap->sa_linkndx];
if (_sdp->sd_ref < sdp->sd_ref) {
_sdp->sd_ref = sdp->sd_ref;
_sdp->sd_flags |= FLG_SY_REFRSD;
if (ELF_ST_BIND(_sdp->sd_sym->st_info) == STB_GLOBAL)
_sdp->sd_flags |= FLG_SY_GLOBREF;
} else if (_sdp->sd_ref > sdp->sd_ref) {
sdp->sd_ref = _sdp->sd_ref;
sdp->sd_flags |= FLG_SY_REFRSD;
if (ELF_ST_BIND(sym->st_info) == STB_GLOBAL)
sdp->sd_flags |= FLG_SY_GLOBREF;
}
if (((ELF_ST_BIND(sdp->sd_sym->st_info) == STB_WEAK) ||
(sdp->sd_flags & FLG_SY_WEAKDEF)) &&
!ld_reloc_set_aux_usym(ofl, rsp, _sdp))
return (S_ERROR);
} else
_sdp = 0;
if (!(RELAUX_GET_USYM(rsp)->sd_flags & FLG_SY_MVTOCOMM)) {
Word rtype = rsp->rel_rtype, w2align;
Copy_rel cr;
DBG_CALL(Dbg_syms_copy_reloc(ofl, sdp, 0));
sdp->sd_flags |=
(FLG_SY_MVTOCOMM | FLG_SY_DEFAULT | FLG_SY_EXPDEF);
sdp->sd_flags &= ~MSK_SY_LOCAL;
sdp->sd_sym->st_other &= ~MSK_SYM_VISIBILITY;
if (_sdp) {
_sdp->sd_flags |= (FLG_SY_MVTOCOMM |
FLG_SY_DEFAULT | FLG_SY_EXPDEF);
_sdp->sd_flags &= ~MSK_SY_LOCAL;
_sdp->sd_sym->st_other &= ~MSK_SYM_VISIBILITY;
if (!(_sdp->sd_aux->sa_rfile))
_sdp->sd_aux->sa_rfile = sdp->sd_aux->sa_rfile;
}
_sdp = RELAUX_GET_USYM(rsp);
stval = _sdp->sd_sym->st_value;
if (ld_sym_copy(_sdp) == S_ERROR)
return (S_ERROR);
_sdp->sd_shndx = _sdp->sd_sym->st_shndx = SHN_COMMON;
_sdp->sd_flags |= FLG_SY_SPECSEC;
w2align = ld_targ.t_m.m_word_align * 2;
if (_sdp->sd_sym->st_size < w2align)
_sdp->sd_sym->st_value = ld_targ.t_m.m_word_align;
else {
Shdr *shdr;
Word isalign;
if (_sdp->sd_isc &&
((shdr = _sdp->sd_isc->is_shdr) != NULL) &&
((isalign = shdr->sh_addralign) != 0))
_sdp->sd_sym->st_value = nlpo2(isalign);
else
_sdp->sd_sym->st_value = w2align;
}
cr.c_sdp = _sdp;
cr.c_val = stval;
if (alist_append(&ofl->ofl_copyrels, &cr, sizeof (Copy_rel),
AL_CNT_OFL_COPYRELS) == NULL)
return (S_ERROR);
rsp->rel_rtype = ld_targ.t_m.m_r_copy;
if ((*ld_targ.t_mr.mr_add_outrel)(FLG_REL_BSS, rsp, ofl) ==
S_ERROR)
return (S_ERROR);
rsp->rel_rtype = rtype;
if (_sdp->sd_flags & FLG_SY_PROT) {
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_COPY),
conv_reloc_type(_sdp->sd_file->ifl_ehdr->e_machine,
ld_targ.t_m.m_r_copy, 0, &inv_buf),
_sdp->sd_file->ifl_name, _sdp->sd_name);
}
DBG_CALL(Dbg_syms_copy_reloc(ofl, _sdp,
_sdp->sd_sym->st_value));
}
return (ld_add_actrel(0, rsp, ofl));
}
static uintptr_t
reloc_generic(Rel_desc *rsp, Ofl_desc *ofl)
{
Ifl_desc *ifl = rsp->rel_isdesc->is_file;
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_UNEXPREL),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rsp->rel_rtype,
0, &inv_buf), ifl->ifl_name, ld_reloc_sym_name(rsp));
if (ofl->ofl_flags & FLG_OF_SHAROBJ)
return ((*ld_targ.t_mr.mr_add_outrel)(0, rsp, ofl));
return (ld_add_actrel(0, rsp, ofl));
}
static uintptr_t
reloc_relobj(Boolean local, Rel_desc *rsp, Ofl_desc *ofl)
{
Word rtype = rsp->rel_rtype;
Sym_desc *sdp = rsp->rel_sym;
Is_desc *isp = rsp->rel_isdesc;
Word oflags = 0;
if (local && !IS_GOT_RELATIVE(rtype) &&
!IS_GOT_BASED(rtype) && !IS_GOT_PC(rtype) &&
IS_PC_RELATIVE(rtype) &&
((sdp->sd_isc) && (sdp->sd_isc->is_osdesc == isp->is_osdesc)))
return (ld_add_actrel(0, rsp, ofl));
if (local && (((ofl->ofl_flags & FLG_OF_REDLSYM) &&
(ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL)) ||
((sdp->sd_flags & FLG_SY_ELIM) &&
(ofl->ofl_flags & FLG_OF_PROCRED)))) {
if (IS_GOT_RELATIVE(rsp->rel_rtype)) {
Ifl_desc *ifl = rsp->rel_isdesc->is_file;
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_PICREDLOC),
ld_reloc_sym_name(rsp), ifl->ifl_name,
conv_reloc_type(ifl->ifl_ehdr->e_machine,
rsp->rel_rtype, 0, &inv_buf));
return (S_ERROR);
}
if ((rsp->rel_flags & FLG_REL_RELA) == FLG_REL_RELA)
oflags = FLG_REL_SCNNDX | FLG_REL_ADVAL;
else
oflags = FLG_REL_SCNNDX;
}
if ((rsp->rel_flags & FLG_REL_RELA) == 0) {
if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) ||
(oflags == FLG_REL_SCNNDX))
if (ld_add_actrel(0, rsp, ofl) == S_ERROR)
return (S_ERROR);
}
return ((*ld_targ.t_mr.mr_add_outrel)(oflags, rsp, ofl));
}
static uintptr_t
reloc_TLS(Boolean local, Rel_desc *rsp, Ofl_desc *ofl)
{
Word rtype = rsp->rel_rtype;
ofl_flag_t flags = ofl->ofl_flags;
Ifl_desc *ifl = rsp->rel_isdesc->is_file;
Half mach = ifl->ifl_ehdr->e_machine;
Sym_desc *sdp = rsp->rel_sym;
unsigned char type;
Conv_inv_buf_t inv_buf1, inv_buf2;
if (OFL_IS_STATIC_EXEC(ofl)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_TLSSTAT),
conv_reloc_type(mach, rtype, 0, &inv_buf1), ifl->ifl_name,
ld_reloc_sym_name(rsp));
return (S_ERROR);
}
if ((type = ELF_ST_TYPE(sdp->sd_sym->st_info)) != STT_TLS) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_TLSBADSYM),
conv_reloc_type(mach, rtype, 0, &inv_buf1), ifl->ifl_name,
ld_reloc_sym_name(rsp),
conv_sym_info_type(mach, type, 0, &inv_buf2));
return (S_ERROR);
}
if (!local && (IS_TLS_LD(rtype) ||
((flags & FLG_OF_EXEC) && IS_TLS_LE(rtype)))) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_TLSBND),
conv_reloc_type(mach, rtype, 0, &inv_buf1), ifl->ifl_name,
ld_reloc_sym_name(rsp), sdp->sd_file->ifl_name);
return (S_ERROR);
}
if ((flags & FLG_OF_EXEC) == 0) {
if (IS_TLS_LE(rtype)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_TLSLE),
conv_reloc_type(mach, rtype, 0, &inv_buf1),
ifl->ifl_name, ld_reloc_sym_name(rsp));
return (S_ERROR);
} else if ((IS_TLS_IE(rtype)) &&
(flags & FLG_OF_VERBOSE)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_TLSIE),
conv_reloc_type(mach, rtype, 0, &inv_buf1),
ifl->ifl_name, ld_reloc_sym_name(rsp));
}
}
return ((*ld_targ.t_mr.mr_reloc_TLS)(local, rsp, ofl));
}
uintptr_t
ld_process_sym_reloc(Ofl_desc *ofl, Rel_desc *reld, Rel *reloc, Is_desc *isp,
const char *isname, Word isscnndx)
{
Word rtype = reld->rel_rtype;
ofl_flag_t flags = ofl->ofl_flags;
Sym_desc *sdp = reld->rel_sym;
Sym_aux *sap;
Boolean local;
Conv_inv_buf_t inv_buf;
DBG_CALL(Dbg_reloc_in(ofl->ofl_lml, ELF_DBG_LD, ld_targ.t_m.m_mach,
ld_targ.t_m.m_rel_sht_type, (void *)reloc, isname, isscnndx,
ld_reloc_sym_name(reld)));
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;
}
if (!ld_reloc_set_aux_usym(ofl, reld, sdp))
return (S_ERROR);
sap = sdp->sd_aux;
if (sap && sap->sa_linkndx &&
((ELF_ST_BIND(sdp->sd_sym->st_info) == STB_WEAK) ||
(sdp->sd_flags & FLG_SY_WEAKDEF)) &&
(!(sdp->sd_flags & FLG_SY_MVTOCOMM))) {
Sym_desc *_sdp;
_sdp = sdp->sd_file->ifl_oldndx[sap->sa_linkndx];
if ((_sdp->sd_ref != REF_DYN_SEEN) &&
!ld_reloc_set_aux_usym(ofl, reld, _sdp))
return (S_ERROR);
}
local = FALSE;
if (ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL) {
local = TRUE;
} else if (!(reld->rel_flags & FLG_REL_LOAD)) {
local = TRUE;
} else if (sdp->sd_sym->st_shndx != SHN_UNDEF) {
if (reld->rel_isdesc &&
reld->rel_isdesc->is_shdr->sh_type == SHT_SUNW_dof) {
local = TRUE;
} else if (!(flags & FLG_OF_RELOBJ) &&
(IS_LOCALBND(rtype) || IS_SEG_RELATIVE(rtype))) {
local = TRUE;
} else if ((sdp->sd_ref == REF_REL_NEED) &&
((sdp->sd_flags & FLG_SY_CAP) == 0)) {
if ((sdp->sd_flags &
(FLG_SY_HIDDEN | FLG_SY_PROTECT)))
local = TRUE;
else if ((flags & FLG_OF_EXEC) ||
((flags & FLG_OF_SYMBOLIC) &&
((sdp->sd_flags & FLG_SY_NDIR) == 0))) {
local = TRUE;
}
}
}
if ((ofl->ofl_flags & FLG_OF_SHAROBJ) &&
IS_PC_RELATIVE(rtype) &&
(IS_GOT_PC(rtype) == 0) &&
(IS_PLT(rtype) == 0)) {
if (disp_inspect(ofl, reld, local) == S_ERROR)
return (S_ERROR);
}
if (!local && !(flags & FLG_OF_RELOBJ) &&
IS_GOT_BASED(rtype)) {
Ifl_desc *ifl = reld->rel_isdesc->is_file;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_BADGOTBASED),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, demangle(sdp->sd_name));
return (S_ERROR);
}
if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_TLS) &&
(IS_TLS_INS(rtype) == 0)) {
if (RELAUX_GET_OSDESC(reld)->os_shdr->sh_flags & SHF_ALLOC) {
Ifl_desc *ifl = reld->rel_isdesc->is_file;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_BADTLS),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
rtype, 0, &inv_buf), ifl->ifl_name,
demangle(sdp->sd_name));
return (S_ERROR);
}
}
if (IS_REGISTER(rtype)) {
if (ld_targ.t_mr.mr_reloc_register == NULL) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_NOREG));
return (S_ERROR);
}
return ((*ld_targ.t_mr.mr_reloc_register)(reld, isp, ofl));
}
if (flags & FLG_OF_RELOBJ)
return (reloc_relobj(local, reld, ofl));
if (IS_TLS_INS(rtype))
return (reloc_TLS(local, reld, ofl));
if (IS_GOT_OPINS(rtype)) {
if (ld_targ.t_mr.mr_reloc_GOTOP == NULL) {
assert(0);
return (S_ERROR);
}
return ((*ld_targ.t_mr.mr_reloc_GOTOP)(local, reld, ofl));
}
if (IS_GOT_RELATIVE(rtype))
return (ld_reloc_GOT_relative(local, reld, ofl));
if (local)
return ((*ld_targ.t_mr.mr_reloc_local)(reld, ofl));
if ((IS_PLT(rtype) || ((sdp->sd_flags & FLG_SY_CAP) &&
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_FUNC))) &&
((flags & FLG_OF_BFLAG) == 0))
return (ld_reloc_plt(reld, ofl));
if ((sdp->sd_ref == REF_REL_NEED) ||
(flags & FLG_OF_BFLAG) || (flags & FLG_OF_SHAROBJ) ||
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_NOTYPE))
return ((*ld_targ.t_mr.mr_add_outrel)(0, reld, ofl));
if (sdp->sd_ref == REF_DYN_NEED)
return (reloc_exec(reld, ofl));
return (reloc_generic(reld, ofl));
}
static Sym_desc *
sloppy_comdat_reloc(Ofl_desc *ofl, Rel_desc *reld, Sym_desc *sdp,
Rlxrel_rej *reject)
{
Is_desc *rep_isp;
Sym *sym, *rep_sym;
Is_desc *isp;
Ifl_desc *ifl;
Conv_inv_buf_t inv_buf;
Word scnndx, symscnt;
Sym_desc **oldndx, *rep_sdp;
const char *is_name;
is_name = reld->rel_isdesc->is_name;
if (((is_name[1] == 'e') &&
(strcmp(is_name, MSG_ORIG(MSG_SCN_EHFRAME)) == 0)) ||
((is_name[1] == 'g') &&
(strcmp(is_name, MSG_ORIG(MSG_SCN_GCC_X_TBL)) == 0))) {
*reject = RLXREL_REJ_TARGET;
return (NULL);
}
if (sdp == ofl->ofl_sr_cache.sr_osdp) {
*reject = ofl->ofl_sr_cache.sr_rej;
return (ofl->ofl_sr_cache.sr_rsdp);
}
ofl->ofl_sr_cache.sr_osdp = sdp;
sym = sdp->sd_sym;
isp = sdp->sd_isc;
ifl = sdp->sd_file;
if (((rep_isp = isp->is_comdatkeep) == NULL) ||
((rep_isp->is_flags & FLG_IS_DISCARD) != 0) ||
((rep_isp->is_flags & FLG_IS_COMDAT) == 0) ||
(isp->is_indata->d_size != rep_isp->is_indata->d_size) ||
(isp->is_shdr->sh_type != rep_isp->is_shdr->sh_type) ||
((isp->is_shdr->sh_flags & SHF_GROUP) !=
(rep_isp->is_shdr->sh_flags & SHF_GROUP))) {
*reject = ofl->ofl_sr_cache.sr_rej = RLXREL_REJ_SECTION;
return (ofl->ofl_sr_cache.sr_rsdp = NULL);
}
scnndx = rep_isp->is_scnndx;
oldndx = rep_isp->is_file->ifl_oldndx;
symscnt = rep_isp->is_file->ifl_symscnt;
while (symscnt--) {
rep_sdp = *oldndx++;
if ((rep_sdp == NULL) || (rep_sdp->sd_flags & FLG_SY_ISDISC) ||
((rep_sym = rep_sdp->sd_sym)->st_shndx != scnndx) ||
((sym->st_name == 0) != (rep_sym->st_name == 0)) ||
((sym->st_name != 0) &&
(strcmp(sdp->sd_name, rep_sdp->sd_name) != 0)) ||
(sym->st_info != rep_sym->st_info) ||
(sym->st_value != rep_sym->st_value) ||
(sym->st_size != rep_sym->st_size) ||
(sym->st_other != rep_sym->st_other))
continue;
if (ofl->ofl_flags & FLG_OF_VERBOSE) {
if (sym->st_name != 0) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_REL_SLOPCDATNAM),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
reld->rel_rtype, 0, &inv_buf),
ifl->ifl_name,
EC_WORD(reld->rel_isdesc->is_scnndx),
reld->rel_isdesc->is_name,
rep_sdp->sd_name,
EC_WORD(isp->is_scnndx), isp->is_name,
rep_sdp->sd_file->ifl_name);
} else {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_REL_SLOPCDATNONAM),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
reld->rel_rtype, 0, &inv_buf),
ifl->ifl_name,
EC_WORD(reld->rel_isdesc->is_scnndx),
reld->rel_isdesc->is_name,
EC_WORD(isp->is_scnndx), isp->is_name,
rep_sdp->sd_file->ifl_name);
}
}
DBG_CALL(Dbg_reloc_sloppycomdat(ofl->ofl_lml, rep_sdp));
*reject = ofl->ofl_sr_cache.sr_rej = RLXREL_REJ_NONE;
return (ofl->ofl_sr_cache.sr_rsdp = rep_sdp);
}
*reject = ofl->ofl_sr_cache.sr_rej = RLXREL_REJ_SYMBOL;
return (ofl->ofl_sr_cache.sr_rsdp = NULL);
}
static uintptr_t
process_reld(Ofl_desc *ofl, Is_desc *isp, Rel_desc *reld, Word rsndx,
Rel *reloc)
{
Ifl_desc *ifl = isp->is_file;
Word rtype = reld->rel_rtype;
Sym_desc *sdp;
Conv_inv_buf_t inv_buf;
if (rtype >= ld_targ.t_m.m_r_num) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_INVALRELT),
ifl->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name,
rtype);
return (S_ERROR);
}
ofl->ofl_entrelscnt++;
if (IS_REGISTER(rtype) && (rsndx == 0)) {
reld->rel_sym = NULL;
DBG_CALL(Dbg_reloc_in(ofl->ofl_lml, ELF_DBG_LD,
ld_targ.t_m.m_mach, isp->is_shdr->sh_type,
(void *)reloc, isp->is_name, isp->is_scnndx,
ld_reloc_sym_name(reld)));
if (ld_targ.t_mr.mr_reloc_register == NULL) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_NOREG));
return (S_ERROR);
}
return ((*ld_targ.t_mr.mr_reloc_register)(reld, isp, ofl));
}
sdp = reld->rel_sym = ifl->ifl_oldndx[rsndx];
if ((sdp != NULL) &&
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) &&
(sdp->sd_isc != NULL) && (sdp->sd_isc->is_name != NULL) &&
(sdp->sd_isc->is_sym_name == NULL) &&
(ld_stt_section_sym_name(sdp->sd_isc) == NULL))
return (S_ERROR);
if (rtype == ld_targ.t_m.m_r_none) {
DBG_CALL(Dbg_reloc_in(ofl->ofl_lml, ELF_DBG_LD,
ld_targ.t_m.m_mach, ld_targ.t_m.m_rel_sht_type,
(void *)reloc, isp->is_name, isp->is_scnndx,
ld_reloc_sym_name(reld)));
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_REL_NULL),
ifl->ifl_name, EC_WORD(isp->is_scnndx), isp->is_name);
return (1);
}
if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) &&
IS_NOTSUP(rtype)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_NOTSUP),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name);
return (S_ERROR);
}
if (sdp == NULL) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_NOSYMBOL),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name, EC_XWORD(reloc->r_offset));
return (S_ERROR);
}
if (sdp->sd_flags & FLG_SY_IGNORE)
return (1);
if (sdp->sd_flags & FLG_SY_ISDISC) {
Sym_desc *nsdp = NULL;
Rlxrel_rej reject;
if (ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL) {
if ((ofl->ofl_flags1 & FLG_OF1_RLXREL) &&
sdp->sd_isc->is_osdesc &&
(sdp->sd_isc->is_flags & FLG_IS_COMDAT) &&
((nsdp = sloppy_comdat_reloc(ofl, reld,
sdp, &reject)) == NULL)) {
Shdr *is_shdr = reld->rel_isdesc->is_shdr;
if (((ofl->ofl_flags & FLG_OF_VERBOSE) != 0) ||
((is_shdr->sh_flags & SHF_ALLOC) &&
(reject != RLXREL_REJ_TARGET)))
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_REL_SLOPCDATNOSYM),
conv_reloc_type(
ifl->ifl_ehdr->e_machine,
reld->rel_rtype, 0, &inv_buf),
ifl->ifl_name,
EC_WORD(isp->is_scnndx),
isp->is_name,
ld_reloc_sym_name(reld),
EC_WORD(sdp->sd_isc->is_scnndx),
sdp->sd_isc->is_name);
return (1);
}
} else if ((sdp != NULL) && sdp->sd_name && *sdp->sd_name)
nsdp = ld_sym_find(sdp->sd_name, SYM_NOHASH, NULL, ofl);
if (nsdp == NULL) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_SYMDISC),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
reld->rel_rtype, 0, &inv_buf), ifl->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name,
ld_reloc_sym_name(reld),
EC_WORD(sdp->sd_isc->is_scnndx),
sdp->sd_isc->is_name);
return (S_ERROR);
}
ifl->ifl_oldndx[rsndx] = sdp = nsdp;
if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) &&
(sdp->sd_isc != NULL) && (sdp->sd_isc->is_name != NULL) &&
(sdp->sd_isc->is_sym_name == NULL) &&
(ld_stt_section_sym_name(sdp->sd_isc) == NULL))
return (S_ERROR);
}
if (sdp->sd_aux && ((sdp->sd_flags & FLG_SY_VISIBLE) == 0))
ld_sym_adjust_vis(sdp, ofl);
if ((sdp->sd_isc == 0) &&
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION))
return (1);
if (sdp->sd_isc && (sdp->sd_isc->is_osdesc == 0) &&
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_RELINVSEC),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name, EC_WORD(sdp->sd_isc->is_scnndx),
sdp->sd_isc->is_name);
return (1);
}
if ((sdp->sd_flags & FLG_SY_INVALID) || (rsndx == 0) ||
(rsndx >= ifl->ifl_symscnt)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_UNKNWSYM),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name, ld_reloc_sym_name(reld),
EC_XWORD(reloc->r_offset), EC_WORD(rsndx));
return (S_ERROR);
}
if (IS_SIZE(rtype) &&
(ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_UNSUPSIZE),
conv_reloc_type(ifl->ifl_ehdr->e_machine, rtype,
0, &inv_buf), ifl->ifl_name, EC_WORD(isp->is_scnndx),
isp->is_name);
return (S_ERROR);
}
reld->rel_sym = sdp;
if (reld->rel_aux)
reld->rel_aux->ra_usym = sdp;
return (ld_process_sym_reloc(ofl, reld, reloc, isp, isp->is_name,
isp->is_scnndx));
}
static uintptr_t
reloc_section(Ofl_desc *ofl, Is_desc *isect, Is_desc *rsect, Os_desc *osect)
{
Rel *rend;
Rel *reloc;
Xword rsize;
Xword entsize;
Rel_desc reld;
Rel_aux rel_aux;
Shdr * shdr;
Word flags = 0;
uintptr_t ret = 1;
shdr = rsect->is_shdr;
rsize = shdr->sh_size;
reloc = (Rel *)rsect->is_indata->d_buf;
if (((entsize = shdr->sh_entsize) == 0) || (entsize > rsize)) {
if (shdr->sh_type == SHT_RELA)
entsize = sizeof (Rela);
else
entsize = sizeof (Rel);
}
reld.rel_isdesc = isect;
reld.rel_aux = &rel_aux;
ld_init_rel_aux(&reld);
rel_aux.ra_osdesc = osect;
if ((ofl->ofl_flags & FLG_OF_RELOBJ) ||
(osect && (osect->os_sgdesc->sg_phdr.p_type == PT_LOAD)))
flags |= FLG_REL_LOAD;
if (shdr->sh_info == 0)
flags |= FLG_REL_NOINFO;
DBG_CALL(Dbg_reloc_proc(ofl->ofl_lml, osect, isect, rsect));
for (rend = (Rel *)((uintptr_t)reloc + (uintptr_t)rsize);
reloc < rend;
reloc = (Rel *)((uintptr_t)reloc + (uintptr_t)entsize)) {
Word rsndx;
reld.rel_flags = flags;
rsndx = (*ld_targ.t_mr.mr_init_rel)(&reld,
&rel_aux.ra_typedata, (void *)reloc);
reld.rel_aux =
(RELAUX_ISDEFAULT_OSDESC(&reld, rel_aux.ra_osdesc) &&
RELAUX_ISDEFAULT_TYPEDATA(&reld, rel_aux.ra_typedata)) ?
NULL : &rel_aux;
if (process_reld(ofl, rsect, &reld, rsndx, reloc) == S_ERROR)
ret = S_ERROR;
}
return (ret);
}
static uintptr_t
reloc_segments(int wr_flag, Ofl_desc *ofl)
{
Aliste idx1;
Sg_desc *sgp;
Is_desc *isp;
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Os_desc *osp;
Aliste idx2;
if ((sgp->sg_phdr.p_flags & PF_W) != wr_flag)
continue;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
Is_desc *risp;
Aliste idx3;
osp->os_szoutrels = 0;
for (APLIST_TRAVERSE(osp->os_relisdescs, idx3, risp)) {
Word indx;
indx = risp->is_shdr->sh_info;
isp = risp->is_file->ifl_isdesc[indx];
if (isp->is_flags & FLG_IS_DISCARD)
continue;
if (reloc_section(ofl, isp, risp, osp) ==
S_ERROR)
return (S_ERROR);
}
if (osp->os_szoutrels &&
(sgp->sg_phdr.p_type == PT_LOAD) &&
((sgp->sg_phdr.p_flags & PF_W) == 0)) {
ofl->ofl_flags |= FLG_OF_TEXTREL;
ofl->ofl_dtflags |= DF_TEXTREL;
}
}
}
return (1);
}
static Move *
get_move_entry(Is_desc *rsect, Xword roffset)
{
Ifl_desc *ifile = rsect->is_file;
Shdr *rshdr = rsect->is_shdr;
Is_desc *misp;
Shdr *mshdr;
Xword midx;
Move *mvp;
misp = ifile->ifl_isdesc[rshdr->sh_info];
mshdr = misp->is_shdr;
if (mshdr->sh_entsize == 0)
return (NULL);
midx = roffset / mshdr->sh_entsize;
if ((midx * mshdr->sh_entsize) >= mshdr->sh_size)
return (NULL);
mvp = (Move *)misp->is_indata->d_buf;
mvp += midx;
return (mvp);
}
static uintptr_t
process_movereloc(Ofl_desc *ofl, Is_desc *rsect)
{
Ifl_desc *file = rsect->is_file;
Rel *rend, *reloc;
Xword rsize, entsize;
Rel_desc reld;
Rel_aux rel_aux;
rsize = rsect->is_shdr->sh_size;
reloc = (Rel *)rsect->is_indata->d_buf;
entsize = rsect->is_shdr->sh_entsize;
if ((entsize == 0) ||
(entsize > rsect->is_shdr->sh_size)) {
if (rsect->is_shdr->sh_type == SHT_RELA)
entsize = sizeof (Rela);
else
entsize = sizeof (Rel);
}
reld.rel_aux = &rel_aux;
ld_init_rel_aux(&reld);
for (rend = (Rel *)((uintptr_t)reloc + (uintptr_t)rsize);
reloc < rend;
reloc = (Rel *)((uintptr_t)reloc + (uintptr_t)entsize)) {
Sym_desc *psdp;
Move *mvp;
Word rsndx;
reld.rel_flags = FLG_REL_LOAD;
rsndx = (*ld_targ.t_mr.mr_init_rel)(&reld,
&rel_aux.ra_typedata, (void *)reloc);
if (((mvp = get_move_entry(rsect, reloc->r_offset)) == NULL) ||
((rel_aux.ra_move =
libld_malloc(sizeof (Mv_reloc))) == NULL))
return (S_ERROR);
psdp = file->ifl_oldndx[ELF_M_SYM(mvp->m_info)];
rel_aux.ra_move->mr_move = mvp;
rel_aux.ra_move->mr_sym = psdp;
if (psdp->sd_flags & FLG_SY_PAREXPN) {
int _num, num = mvp->m_repeat;
rel_aux.ra_osdesc = ofl->ofl_isparexpn->is_osdesc;
reld.rel_isdesc = ofl->ofl_isparexpn;
reld.rel_roffset = mvp->m_poffset;
for (_num = 0; _num < num; _num++) {
reld.rel_roffset +=
(_num * ELF_M_SIZE(mvp->m_info));
if (process_reld(ofl,
rsect, &reld, rsndx, reloc) == S_ERROR)
return (S_ERROR);
}
} else {
reld.rel_flags |= FLG_REL_MOVETAB;
rel_aux.ra_osdesc = ofl->ofl_osmove;
reld.rel_isdesc = ld_os_first_isdesc(ofl->ofl_osmove);
if (process_reld(ofl,
rsect, &reld, rsndx, reloc) == S_ERROR)
return (S_ERROR);
}
}
return (1);
}
static uintptr_t
reloc_movesections(Ofl_desc *ofl)
{
Aliste idx;
Is_desc *risp;
uintptr_t ret = 1;
for (APLIST_TRAVERSE(ofl->ofl_ismoverel, idx, risp)) {
if (process_movereloc(ofl, risp) == S_ERROR)
ret = S_ERROR;
}
return (ret);
}
uintptr_t
ld_reloc_init(Ofl_desc *ofl)
{
Aliste idx;
Is_desc *isp;
Sym_desc *sdp;
DBG_CALL(Dbg_basic_collect(ofl->ofl_lml));
if (ld_sym_spec(ofl) == S_ERROR)
return (S_ERROR);
ofl->ofl_gotcnt = ld_targ.t_m.m_got_xnumber;
if (reloc_segments(0, ofl) == S_ERROR)
return (S_ERROR);
if (reloc_segments(PF_W, ofl) == S_ERROR)
return (S_ERROR);
for (APLIST_TRAVERSE(ofl->ofl_extrarels, idx, isp)) {
if (reloc_section(ofl, NULL, isp, NULL) == S_ERROR)
return (S_ERROR);
}
if (reloc_movesections(ofl) == S_ERROR)
return (S_ERROR);
if (ofl->ofl_copyrels) {
Copy_rel *crp;
for (ALIST_TRAVERSE(ofl->ofl_copyrels, idx, crp)) {
if (crp->c_sdp->sd_file->ifl_flags &
(FLG_IF_DISPPEND | FLG_IF_DISPDONE))
is_disp_copied(ofl, crp);
}
}
if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) &&
((ofl->ofl_flags & FLG_OF_BLDGOT) ||
((((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_GOFTBL),
SYM_NOHASH, NULL, ofl)) != NULL) ||
((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_GOFTBL_U),
SYM_NOHASH, NULL, ofl)) != NULL)) &&
(sdp->sd_ref != REF_DYN_SEEN)))) {
if (ld_make_got(ofl) == S_ERROR)
return (S_ERROR);
if ((ld_targ.t_mr.mr_allocate_got != NULL) &&
((*ld_targ.t_mr.mr_allocate_got)(ofl) == S_ERROR))
return (S_ERROR);
}
return (1);
}
static int
reloc_compare(Reloc_list *i, Reloc_list *j)
{
if (i->rl_key1 > j->rl_key1)
return (1);
if (i->rl_key1 < j->rl_key1)
return (-1);
if ((uintptr_t)i->rl_key2 > (uintptr_t)j->rl_key2)
return (1);
if ((uintptr_t)i->rl_key2 < (uintptr_t)j->rl_key2)
return (-1);
if (i->rl_key3 > j->rl_key3)
return (1);
if (i->rl_key3 < j->rl_key3)
return (-1);
return (0);
}
static uintptr_t
do_sorted_outrelocs(Ofl_desc *ofl)
{
Rel_desc *orsp;
Rel_cachebuf *rcbp;
Aliste idx;
Reloc_list *sorted_list;
Word index = 0;
int debug = 0;
uintptr_t error = 1;
Boolean remain_seen = FALSE;
if ((sorted_list = libld_malloc((size_t)(sizeof (Reloc_list) *
ofl->ofl_reloccnt))) == NULL)
return (S_ERROR);
REL_CACHE_TRAVERSE(&ofl->ofl_outrels, idx, rcbp, orsp) {
if (debug == 0) {
DBG_CALL(Dbg_reloc_dooutrel(ofl->ofl_lml,
ld_targ.t_m.m_rel_sht_type));
debug = 1;
}
if (orsp->rel_flags & FLG_REL_PLT) {
if ((*ld_targ.t_mr.mr_perform_outreloc)
(orsp, ofl, &remain_seen) == S_ERROR)
error = S_ERROR;
continue;
}
if ((orsp->rel_rtype == ld_targ.t_m.m_r_relative) ||
(orsp->rel_rtype == ld_targ.t_m.m_r_register)) {
sorted_list[index].rl_key1 = 0;
sorted_list[index].rl_key2 =
(Sym_desc *)(uintptr_t)orsp->rel_rtype;
} else {
sorted_list[index].rl_key1 =
orsp->rel_sym->sd_file->ifl_neededndx;
sorted_list[index].rl_key2 = orsp->rel_sym;
}
if (orsp->rel_flags & FLG_REL_GOT) {
sorted_list[index].rl_key3 =
(*ld_targ.t_mr.mr_calc_got_offset)(orsp, ofl);
} else {
if (orsp->rel_rtype == ld_targ.t_m.m_r_register) {
sorted_list[index].rl_key3 = 0;
} else {
sorted_list[index].rl_key3 = orsp->rel_roffset +
(Xword)_elf_getxoff(orsp->
rel_isdesc->is_indata) +
orsp->rel_isdesc->is_osdesc->
os_shdr->sh_addr;
}
}
sorted_list[index++].rl_rsp = orsp;
}
qsort(sorted_list, (size_t)ofl->ofl_reloccnt, sizeof (Reloc_list),
(int (*)(const void *, const void *))reloc_compare);
for (index = 0; index < ofl->ofl_reloccnt; index++) {
if ((*ld_targ.t_mr.mr_perform_outreloc)
(sorted_list[index].rl_rsp, ofl, &remain_seen) == S_ERROR)
error = S_ERROR;
}
if (remain_seen && OFL_GUIDANCE(ofl, FLG_OFG_NO_TEXT))
ld_eprintf(ofl, ERR_GUIDANCE, MSG_INTL(MSG_GUIDE_TEXT));
return (error);
}
uintptr_t
ld_reloc_process(Ofl_desc *ofl)
{
Sg_desc *sgp;
Os_desc *osp;
Word ndx = 0;
ofl_flag_t flags = ofl->ofl_flags;
Shdr *shdr;
DBG_CALL(Dbg_basic_relocate(ofl->ofl_lml));
if (OFL_ALLOW_DYNSYM(ofl))
ndx = (Word)elf_ndxscn(ofl->ofl_osdynsym->os_scn);
else if (!(flags & FLG_OF_STRIP) || (flags & FLG_OF_RELOBJ))
ndx = (Word)elf_ndxscn(ofl->ofl_ossymtab->os_scn);
ofl->ofl_relocpltsz = 0;
ofl->ofl_relocgotsz = 0;
ofl->ofl_relocbsssz = 0;
if (do_sorted_outrelocs(ofl) == S_ERROR)
return (S_ERROR);
if ((*ld_targ.t_mr.mr_do_activerelocs)(ofl) == S_ERROR)
return (S_ERROR);
if ((flags & FLG_OF_COMREL) == 0) {
Aliste idx1;
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Os_desc *osp;
Aliste idx2;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
if (osp->os_relosdesc == 0)
continue;
shdr = osp->os_relosdesc->os_shdr;
shdr->sh_link = ndx;
shdr->sh_info = (Word)elf_ndxscn(osp->os_scn);
}
}
if ((osp = ofl->ofl_osrel) != NULL) {
shdr = osp->os_shdr;
shdr->sh_link = ndx;
shdr->sh_info = 0;
}
} else {
if ((osp = ofl->ofl_osrelhead) != NULL) {
shdr = osp->os_shdr;
shdr->sh_link = ndx;
shdr->sh_info = 0;
}
if (((osp = ofl->ofl_osplt) != NULL) && osp->os_relosdesc) {
shdr = osp->os_relosdesc->os_shdr;
shdr->sh_link = ndx;
shdr->sh_info = (Word)elf_ndxscn(osp->os_scn);
}
}
if ((flags & (FLG_OF_PURETXT | FLG_OF_TEXTREL)) ==
(FLG_OF_PURETXT | FLG_OF_TEXTREL)) {
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_REMAIN_3));
return (S_ERROR);
}
if (flags & FLG_OF_DYNAMIC) {
if ((*ld_targ.t_mr.mr_fillin_gotplt)(ofl) == S_ERROR)
return (S_ERROR);
}
if ((osp = ofl->ofl_osgot) != NULL)
DBG_CALL(Dbg_got_display(ofl, osp->os_shdr->sh_addr, 1,
ld_targ.t_m.m_got_xnumber, ld_targ.t_m.m_got_entsize));
return (1);
}
void
ld_reloc_remain_entry(Rel_desc *orsp, Os_desc *osp, Ofl_desc *ofl,
Boolean *remain_seen)
{
if (ofl->ofl_flags1 & FLG_OF1_TEXTOFF)
return;
if ((orsp->rel_rtype == ld_targ.t_m.m_r_register) || (!osp) ||
(osp->os_sgdesc->sg_phdr.p_type != PT_LOAD) ||
(osp->os_sgdesc->sg_phdr.p_flags & PF_W))
return;
if (((ofl->ofl_flags & FLG_OF_PURETXT) == 0) &&
(ELF_ST_BIND(orsp->rel_sym->sd_sym->st_info) == STB_WEAK) &&
(orsp->rel_sym->sd_sym->st_shndx == SHN_UNDEF))
return;
if (*remain_seen == FALSE) {
const char *str1 = (ofl->ofl_flags & FLG_OF_PURETXT) ?
MSG_INTL(MSG_REL_RMN_ITM_11) : MSG_INTL(MSG_REL_RMN_ITM_13);
ld_eprintf(ofl, ERR_NONE, MSG_INTL(MSG_REL_REMAIN_FMT_1), str1,
MSG_INTL(MSG_REL_RMN_ITM_31), MSG_INTL(MSG_REL_RMN_ITM_12),
MSG_INTL(MSG_REL_RMN_ITM_2), MSG_INTL(MSG_REL_RMN_ITM_32));
*remain_seen = TRUE;
}
ld_eprintf(ofl, ERR_NONE, MSG_INTL(MSG_REL_REMAIN_2),
ld_reloc_sym_name(orsp), EC_OFF(orsp->rel_roffset),
orsp->rel_isdesc->is_file->ifl_name);
}
uintptr_t
ld_assign_got_TLS(Boolean local, Rel_desc *rsp, Ofl_desc *ofl, Sym_desc *sdp,
Gotndx *gnp, Gotref gref, Word rflag, Word ortype, Word rtype1, Word rtype2)
{
Word rflags;
if ((*ld_targ.t_mr.mr_assign_got_ndx)(&(sdp->sd_GOTndxs), gnp,
gref, ofl, rsp, sdp) == S_ERROR)
return (S_ERROR);
rflags = FLG_REL_GOT | rflag;
if (local)
rflags |= FLG_REL_SCNNDX;
rsp->rel_rtype = rtype1;
if ((*ld_targ.t_mr.mr_add_outrel)(rflags, rsp, ofl) == S_ERROR)
return (S_ERROR);
if (local && (gref == GOT_REF_TLSIE)) {
if (ld_add_actrel(rflags, rsp, ofl) == S_ERROR)
return (S_ERROR);
}
if (rtype2) {
rflags = FLG_REL_GOT | rflag;
rsp->rel_rtype = rtype2;
if (local) {
if (ld_add_actrel(rflags, rsp, ofl) == S_ERROR)
return (S_ERROR);
} else {
if ((*ld_targ.t_mr.mr_add_outrel)(rflags, rsp, ofl) ==
S_ERROR)
return (S_ERROR);
}
}
rsp->rel_rtype = ortype;
return (1);
}
static void
newroffset_for_move(Sym_desc *sdp, Move *mvp, Xword offset1, Xword *offset2)
{
Mv_desc *mdp;
Aliste idx;
for (ALIST_TRAVERSE(sdp->sd_move, idx, mdp)) {
if (mdp->md_move == mvp) {
*offset2 = (Xword)((mdp->md_oidx - 1) * sizeof (Move) +
offset1 % sizeof (Move));
return;
}
}
}
void
ld_adj_movereloc(Ofl_desc *ofl, Rel_desc *arsp)
{
Move *move = arsp->rel_aux->ra_move->mr_move;
Sym_desc *psdp = arsp->rel_aux->ra_move->mr_sym;
Xword newoffset;
if (arsp->rel_flags & FLG_REL_MOVETAB) {
newroffset_for_move(psdp, move, arsp->rel_roffset,
&newoffset);
DBG_CALL(Dbg_move_adjmovereloc(ofl->ofl_lml, arsp->rel_roffset,
newoffset, psdp->sd_name));
arsp->rel_roffset = newoffset;
} else {
arsp->rel_roffset += psdp->sd_sym->st_value -
ofl->ofl_isparexpn->is_osdesc->os_shdr->sh_addr;
DBG_CALL(Dbg_move_adjexpandreloc(ofl->ofl_lml,
arsp->rel_roffset, psdp->sd_name));
}
}
Sym_desc *
ld_am_I_partial(Rel_desc *reld, Xword val)
{
Ifl_desc *ifile = reld->rel_sym->sd_isc->is_file;
int nlocs = ifile->ifl_locscnt, i;
for (i = 1; i < nlocs; i++) {
Sym *osym;
Sym_desc *symd = ifile->ifl_oldndx[i];
if ((osym = symd->sd_osym) == 0)
continue;
if ((symd->sd_flags & FLG_SY_PAREXPN) == 0)
continue;
if ((osym->st_value <= val) &&
(osym->st_value + osym->st_size > val))
return (symd);
}
return (NULL);
}
int
ld_swap_reloc_data(Ofl_desc *ofl, Rel_desc *rsp)
{
if ((ofl->ofl_flags1 & FLG_OF1_ENCDIFF) != 0) {
switch (RELAUX_GET_OSDESC(rsp)->os_shdr->sh_type) {
case SHT_PROGBITS:
return (1);
case SHT_SPARC_GOTDATA:
if (ld_targ.t_m.m_mach ==
LD_TARG_BYCLASS(EM_SPARC, EM_SPARCV9))
return (1);
break;
case SHT_AMD64_UNWIND:
if (ld_targ.t_m.m_mach == EM_AMD64)
return (1);
break;
}
}
return (0);
}
int
ld_reloc_targval_get(Ofl_desc *ofl, Rel_desc *rsp, uchar_t *data, Xword *value)
{
const Rel_entry *rep;
rep = &ld_targ.t_mr.mr_reloc_table[rsp->rel_rtype];
switch (rep->re_fsize) {
case 1:
*value = (Xword) *((uchar_t *)data);
break;
case 2:
{
Half v;
uchar_t *v_bytes = (uchar_t *)&v;
if (OFL_SWAP_RELOC_DATA(ofl, rsp)) {
UL_ASSIGN_BSWAP_HALF(v_bytes, data);
} else {
UL_ASSIGN_HALF(v_bytes, data);
}
*value = (Xword) v;
}
break;
case 4:
{
Word v;
uchar_t *v_bytes = (uchar_t *)&v;
if (OFL_SWAP_RELOC_DATA(ofl, rsp)) {
UL_ASSIGN_BSWAP_WORD(v_bytes, data);
} else {
UL_ASSIGN_WORD(v_bytes, data);
}
*value = (Xword) v;
}
break;
default:
{
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_UNSUPSZ),
conv_reloc_type(ld_targ.t_m.m_mach, rsp->rel_rtype,
0, &inv_buf), rsp->rel_isdesc->is_file->ifl_name,
ld_reloc_sym_name(rsp), (int)rep->re_fsize);
}
return (0);
}
return (1);
}
int
ld_reloc_targval_set(Ofl_desc *ofl, Rel_desc *rsp, uchar_t *data, Xword value)
{
const Rel_entry *rep;
rep = &ld_targ.t_mr.mr_reloc_table[rsp->rel_rtype];
switch (rep->re_fsize) {
case 1:
*((uchar_t *)data) = (uchar_t)value;
break;
case 2:
{
Half v = (Half)value;
uchar_t *v_bytes = (uchar_t *)&v;
if (OFL_SWAP_RELOC_DATA(ofl, rsp)) {
UL_ASSIGN_BSWAP_HALF(data, v_bytes);
} else {
UL_ASSIGN_HALF(data, v_bytes);
}
}
break;
case 4:
{
Word v = (Word)value;
uchar_t *v_bytes = (uchar_t *)&v;
if (OFL_SWAP_RELOC_DATA(ofl, rsp)) {
UL_ASSIGN_BSWAP_WORD(data, v_bytes);
} else {
UL_ASSIGN_WORD(data, v_bytes);
}
}
break;
default:
{
Conv_inv_buf_t inv_buf;
ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_REL_UNSUPSZ),
conv_reloc_type(ld_targ.t_m.m_mach, rsp->rel_rtype,
0, &inv_buf), rsp->rel_isdesc->is_file->ifl_name,
ld_reloc_sym_name(rsp), (int)rep->re_fsize);
}
return (0);
}
return (1);
}