#define ELF_TARGET_AMD64
#include <sys/debug.h>
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include <link.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
inline static void
remove_local(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym)
{
Sym *sym = sdp->sd_sym;
uchar_t type = ELF_ST_TYPE(sym->st_info);
int err;
if ((ofl->ofl_flags & FLG_OF_REDLSYM) == 0) {
ofl->ofl_locscnt--;
err = st_delstring(ofl->ofl_strtab, sdp->sd_name);
assert(err != -1);
if (allow_ldynsym && ldynsym_symtype[type]) {
ofl->ofl_dynlocscnt--;
err = st_delstring(ofl->ofl_dynstrtab, sdp->sd_name);
assert(err != -1);
DYNSORT_COUNT(sdp, sym, type, --);
}
}
sdp->sd_flags |= FLG_SY_ISDISC;
}
inline static void
remove_scoped(Ofl_desc *ofl, Sym_desc *sdp, int allow_ldynsym)
{
Sym *sym = sdp->sd_sym;
uchar_t type = ELF_ST_TYPE(sym->st_info);
int err;
ofl->ofl_scopecnt--;
ofl->ofl_elimcnt++;
err = st_delstring(ofl->ofl_strtab, sdp->sd_name);
assert(err != -1);
if (allow_ldynsym && ldynsym_symtype[type]) {
ofl->ofl_dynscopecnt--;
err = st_delstring(ofl->ofl_dynstrtab, sdp->sd_name);
assert(err != -1);
DYNSORT_COUNT(sdp, sym, type, --);
}
sdp->sd_flags |= FLG_SY_ELIM;
}
inline static void
ignore_sym(Ofl_desc *ofl, Ifl_desc *ifl, Sym_desc *sdp, int allow_ldynsym)
{
Os_desc *osp;
Is_desc *isp = sdp->sd_isc;
uchar_t bind = ELF_ST_BIND(sdp->sd_sym->st_info);
if (bind == STB_LOCAL) {
uchar_t type = ELF_ST_TYPE(sdp->sd_sym->st_info);
if (type == STT_SECTION)
return;
if (((ifl->ifl_flags & FLG_IF_FILEREF) == 0) &&
((type == STT_FILE) || ((isp == NULL) &&
((sdp->sd_flags & FLG_SY_UPREQD) == 0)))) {
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
if (ifl->ifl_flags & FLG_IF_IGNORE)
remove_local(ofl, sdp, allow_ldynsym);
return;
}
} else {
if (!SYM_IS_HIDDEN(sdp))
return;
if ((isp == NULL) && ((sdp->sd_flags & FLG_SY_UPREQD) == 0)) {
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
if (ifl->ifl_flags & FLG_IF_IGNORE)
remove_scoped(ofl, sdp, allow_ldynsym);
return;
}
}
if (isp && ((isp->is_flags & FLG_IS_SECTREF) == 0) &&
((osp = isp->is_osdesc) != 0) &&
(osp->os_sgdesc->sg_phdr.p_type == PT_LOAD)) {
DBG_CALL(Dbg_syms_discarded(ofl->ofl_lml, sdp));
if (ifl->ifl_flags & FLG_IF_IGNORE) {
if (bind == STB_LOCAL)
remove_local(ofl, sdp, allow_ldynsym);
else
remove_scoped(ofl, sdp, allow_ldynsym);
}
}
}
static Boolean
isdesc_discarded(Is_desc *isp)
{
Ifl_desc *ifl = isp->is_file;
Os_desc *osp = isp->is_osdesc;
Word ptype = osp->os_sgdesc->sg_phdr.p_type;
if (isp->is_flags & FLG_IS_DISCARD)
return (TRUE);
if (ifl &&
(((ifl->ifl_flags & FLG_IF_FILEREF) == 0) ||
((ptype == PT_LOAD) &&
((isp->is_flags & FLG_IS_SECTREF) == 0) &&
(isp->is_shdr->sh_size > 0))) &&
(ifl->ifl_flags & FLG_IF_IGNORE))
return (TRUE);
return (FALSE);
}
static void
adjust_os_count(Ofl_desc *ofl)
{
Sg_desc *sgp;
Is_desc *isp;
Os_desc *osp;
Aliste idx1;
if ((ofl->ofl_flags & FLG_OF_ADJOSCNT) == 0)
return;
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Aliste idx2;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
Aliste idx3;
int keep = 0, os_isdescs_idx;
OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx3, isp) {
if (!isdesc_discarded(isp)) {
keep = 1;
break;
}
}
if (keep == 0) {
int err;
ofl->ofl_shdrcnt--;
err = st_delstring(ofl->ofl_shdrsttab,
osp->os_name);
assert(err != -1);
}
}
}
}
static uintptr_t
ignore_section_processing(Ofl_desc *ofl)
{
Sg_desc *sgp;
Is_desc *isp;
Os_desc *osp;
Ifl_desc *ifl;
Rel_cachebuf *rcbp;
Rel_desc *rsp;
int allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
Aliste idx1;
for (APLIST_TRAVERSE(ofl->ofl_objs, idx1, ifl)) {
uint_t num, discard;
if ((ifl->ifl_flags & FLG_IF_FILEREF) == 0)
DBG_CALL(Dbg_unused_file(ofl->ofl_lml,
ifl->ifl_name, 0, 0));
if (((ofl->ofl_flags1 & FLG_OF1_IGNPRC) == 0) ||
((ifl->ifl_flags & FLG_IF_IGNORE) == 0))
continue;
discard = 0;
if (ifl->ifl_flags & FLG_IF_FILEREF) {
for (num = 1; num < ifl->ifl_shnum; num++) {
if (((isp = ifl->ifl_isdesc[num]) != NULL) &&
((isp->is_flags & FLG_IS_SECTREF) == 0) &&
((osp = isp->is_osdesc) != NULL) &&
((sgp = osp->os_sgdesc) != NULL) &&
(sgp->sg_phdr.p_type == PT_LOAD)) {
discard++;
break;
}
}
}
if ((discard == 0) && (ifl->ifl_flags & FLG_IF_FILEREF))
continue;
for (num = 1; num < ifl->ifl_symscnt; num++) {
Sym_desc *sdp;
sdp = ifl->ifl_oldndx[num];
if ((sdp->sd_file != ifl) ||
(sdp->sd_flags &
(FLG_SY_ISDISC | FLG_SY_INVALID | FLG_SY_ELIM)))
continue;
ignore_sym(ofl, ifl, sdp, allow_ldynsym);
}
}
if ((ofl->ofl_flags1 & FLG_OF1_IGNPRC) == 0)
return (1);
REL_CACHE_TRAVERSE(&ofl->ofl_outrels, idx1, rcbp, rsp) {
Is_desc *isc = rsp->rel_isdesc;
uint_t flags, entsize;
Shdr *shdr;
if ((isc == NULL) || ((isc->is_flags & (FLG_IS_SECTREF))) ||
((ifl = isc->is_file) == NULL) ||
((ifl->ifl_flags & FLG_IF_IGNORE) == 0) ||
((shdr = isc->is_shdr) == NULL) ||
((shdr->sh_flags & SHF_ALLOC) == 0))
continue;
flags = rsp->rel_flags;
if (flags & (FLG_REL_GOT | FLG_REL_BSS |
FLG_REL_NOINFO | FLG_REL_PLT))
continue;
osp = RELAUX_GET_OSDESC(rsp);
if (rsp->rel_flags & FLG_REL_RELA)
entsize = sizeof (Rela);
else
entsize = sizeof (Rel);
assert(osp->os_szoutrels > 0);
osp->os_szoutrels -= entsize;
if (!(flags & FLG_REL_PLT))
ofl->ofl_reloccntsub++;
if (rsp->rel_rtype == ld_targ.t_m.m_r_relative)
ofl->ofl_relocrelcnt--;
}
ofl->ofl_flags |= FLG_OF_ADJOSCNT;
return (1);
}
static uintptr_t
new_section(Ofl_desc *ofl, Word shtype, const char *shname, Xword entcnt,
Is_desc **ret_isec, Shdr **ret_shdr, Elf_Data **ret_data)
{
typedef struct sec_info {
Word d_type;
Word align;
Word sh_flags;
Word sh_entsize;
} SEC_INFO_T;
const SEC_INFO_T *sec_info;
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
#define SET_SEC_INFO(d_type, d_align, sh_flags, sh_entsize) \
{ \
static const SEC_INFO_T info_s = { d_type, d_align, sh_flags, \
sh_entsize}; \
sec_info = &info_s; \
}
#define SET_SEC_INFO_WORD_ALIGN(d_type, sh_flags, sh_entsize) \
{ \
static SEC_INFO_T info_s = { d_type, 0, sh_flags, \
sh_entsize}; \
info_s.align = ld_targ.t_m.m_word_align; \
sec_info = &info_s; \
}
switch (shtype) {
case SHT_PROGBITS:
SET_SEC_INFO_WORD_ALIGN(ELF_T_BYTE, SHF_ALLOC, 0)
break;
case SHT_SYMTAB:
SET_SEC_INFO_WORD_ALIGN(ELF_T_SYM, 0, sizeof (Sym))
break;
case SHT_DYNSYM:
SET_SEC_INFO_WORD_ALIGN(ELF_T_SYM, SHF_ALLOC, sizeof (Sym))
break;
case SHT_SUNW_LDYNSYM:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_SYM, SHF_ALLOC, sizeof (Sym))
break;
case SHT_STRTAB:
SET_SEC_INFO(ELF_T_BYTE, 1, SHF_STRINGS, 0)
break;
case SHT_RELA:
SET_SEC_INFO_WORD_ALIGN(ELF_T_RELA, 0, sizeof (Rela))
break;
case SHT_REL:
SET_SEC_INFO_WORD_ALIGN(ELF_T_REL, 0, sizeof (Rel))
break;
case SHT_HASH:
SET_SEC_INFO_WORD_ALIGN(ELF_T_WORD, SHF_ALLOC, sizeof (Word))
break;
case SHT_SUNW_symsort:
case SHT_SUNW_tlssort:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_WORD, SHF_ALLOC, sizeof (Word))
break;
case SHT_DYNAMIC:
SET_SEC_INFO_WORD_ALIGN(ELF_T_DYN, 0, sizeof (Dyn))
break;
case SHT_NOBITS:
SET_SEC_INFO(ELF_T_BYTE, 0, SHF_ALLOC | SHF_WRITE, 0)
break;
case SHT_INIT_ARRAY:
case SHT_FINI_ARRAY:
case SHT_PREINIT_ARRAY:
SET_SEC_INFO(ELF_T_ADDR, sizeof (Addr), SHF_ALLOC | SHF_WRITE,
sizeof (Addr))
break;
case SHT_SYMTAB_SHNDX:
SET_SEC_INFO_WORD_ALIGN(ELF_T_WORD, 0, sizeof (Word));
break;
case SHT_SUNW_cap:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_CAP, SHF_ALLOC, sizeof (Cap));
break;
case SHT_SUNW_capchain:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_WORD, SHF_ALLOC,
sizeof (Capchain));
break;
case SHT_SUNW_capinfo:
ofl->ofl_flags |= FLG_OF_OSABI;
#if _ELF64
SET_SEC_INFO(ELF_T_XWORD, sizeof (Xword), SHF_ALLOC,
sizeof (Capinfo));
#else
SET_SEC_INFO(ELF_T_WORD, sizeof (Word), SHF_ALLOC,
sizeof (Capinfo));
#endif
break;
case SHT_SUNW_move:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO(ELF_T_BYTE, sizeof (Lword),
SHF_ALLOC | SHF_WRITE, sizeof (Move));
break;
case SHT_SUNW_syminfo:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_BYTE,
SHF_ALLOC | SHF_INFO_LINK, sizeof (Syminfo));
break;
case SHT_SUNW_verneed:
case SHT_SUNW_verdef:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_BYTE, SHF_ALLOC, 0);
break;
case SHT_SUNW_versym:
ofl->ofl_flags |= FLG_OF_OSABI;
SET_SEC_INFO_WORD_ALIGN(ELF_T_BYTE, SHF_ALLOC,
sizeof (Versym));
break;
default:
assert(0);
return (S_ERROR);
}
#undef SET_SEC_INFO
#undef SET_SEC_INFO_WORD_ALIGN
size = entcnt * sec_info->sh_entsize;
if ((data = libld_calloc(1, sizeof (Elf_Data))) == NULL)
return (S_ERROR);
data->d_type = sec_info->d_type;
data->d_size = size;
data->d_align = sec_info->align;
data->d_version = ofl->ofl_dehdr->e_version;
if ((shdr = libld_calloc(1, sizeof (Shdr))) == NULL)
return (S_ERROR);
shdr->sh_type = shtype;
shdr->sh_size = size;
shdr->sh_flags = sec_info->sh_flags;
shdr->sh_addralign = sec_info->align;
shdr->sh_entsize = sec_info->sh_entsize;
if ((isec = libld_calloc(1, sizeof (Is_desc))) == NULL)
return (S_ERROR);
isec->is_name = shname;
isec->is_shdr = shdr;
isec->is_indata = data;
*ret_isec = isec;
*ret_shdr = shdr;
*ret_data = data;
return (1);
}
static uintptr_t
new_section_from_template(Ofl_desc *ofl, Is_desc *tmpl_isp, size_t size,
Is_desc **ret_isec, Shdr **ret_shdr, Elf_Data **ret_data)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if ((data = libld_calloc(1, sizeof (Elf_Data))) == NULL)
return (S_ERROR);
data->d_type = tmpl_isp->is_indata->d_type;
data->d_size = size;
data->d_align = tmpl_isp->is_shdr->sh_addralign;
data->d_version = ofl->ofl_dehdr->e_version;
if ((shdr = libld_malloc(sizeof (Shdr))) == NULL)
return (S_ERROR);
*shdr = *tmpl_isp->is_shdr;
shdr->sh_addr = 0;
shdr->sh_offset = 0;
shdr->sh_size = size;
if ((isec = libld_calloc(1, sizeof (Is_desc))) == NULL)
return (S_ERROR);
isec->is_name = tmpl_isp->is_name;
isec->is_shdr = shdr;
isec->is_indata = data;
*ret_isec = isec;
*ret_shdr = shdr;
*ret_data = data;
return (1);
}
uintptr_t
ld_make_bss(Ofl_desc *ofl, Xword size, Xword align, uint_t ident)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Os_desc *osp;
Xword rsize = (Xword)ofl->ofl_relocbsssz;
if (new_section(ofl, SHT_NOBITS, NULL, 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = (size_t)size;
data->d_align = (size_t)align;
shdr->sh_size = size;
shdr->sh_addralign = align;
if (ident == ld_targ.t_id.id_tlsbss) {
isec->is_name = MSG_ORIG(MSG_SCN_TBSS);
ofl->ofl_istlsbss = isec;
shdr->sh_flags |= SHF_TLS;
} else if (ident == ld_targ.t_id.id_bss) {
isec->is_name = MSG_ORIG(MSG_SCN_BSS);
ofl->ofl_isbss = isec;
#if defined(_ELF64)
} else if ((ld_targ.t_m.m_mach == EM_AMD64) &&
(ident == ld_targ.t_id.id_lbss)) {
isec->is_name = MSG_ORIG(MSG_SCN_LBSS);
ofl->ofl_islbss = isec;
shdr->sh_flags |= SHF_AMD64_LARGE;
#endif
}
if ((osp = ld_place_section(ofl, isec, NULL, ident, NULL)) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
if (!(osp->os_flags & FLG_OS_OUTREL)) {
ofl_flag_t flagtotest;
if (ident == ld_targ.t_id.id_tlsbss)
flagtotest = FLG_OF1_TLSOREL;
else
flagtotest = FLG_OF1_BSSOREL;
if (ofl->ofl_flags1 & flagtotest) {
ofl->ofl_dynshdrcnt++;
osp->os_flags |= FLG_OS_OUTREL;
}
}
osp->os_szoutrels = rsize;
return (1);
}
static uintptr_t
make_array(Ofl_desc *ofl, Word shtype, const char *sectname, APlist *alp)
{
uint_t entcount;
Aliste idx;
Elf_Data *data;
Is_desc *isec;
Shdr *shdr;
Sym_desc *sdp;
Rel_desc reld;
Rela reloc;
Os_desc *osp;
uintptr_t ret = 1;
if (alp == NULL)
return (1);
entcount = 0;
for (APLIST_TRAVERSE(alp, idx, sdp))
entcount++;
if (new_section(ofl, shtype, sectname, entcount, &isec, &shdr, &data) ==
S_ERROR)
return (S_ERROR);
if ((data->d_buf = libld_calloc(entcount, sizeof (Addr))) == NULL)
return (S_ERROR);
if (ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_array, NULL) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
osp = isec->is_osdesc;
if ((ofl->ofl_osinitarray == NULL) && (shtype == SHT_INIT_ARRAY))
ofl->ofl_osinitarray = osp;
if ((ofl->ofl_ospreinitarray == NULL) && (shtype == SHT_PREINIT_ARRAY))
ofl->ofl_ospreinitarray = osp;
else if ((ofl->ofl_osfiniarray == NULL) && (shtype == SHT_FINI_ARRAY))
ofl->ofl_osfiniarray = osp;
reld.rel_isdesc = isec;
reld.rel_aux = NULL;
reld.rel_flags = FLG_REL_LOAD;
reld.rel_rtype = ld_targ.t_m.m_r_arrayaddr;
reld.rel_roffset = 0;
reld.rel_raddend = 0;
reloc.r_offset = 0;
reloc.r_info = ELF_R_INFO(0, ld_targ.t_m.m_r_arrayaddr);
reloc.r_addend = 0;
DBG_CALL(Dbg_reloc_generate(ofl->ofl_lml, osp,
ld_targ.t_m.m_rel_sht_type));
for (APLIST_TRAVERSE(alp, idx, sdp)) {
reld.rel_sym = sdp;
if (ld_process_sym_reloc(ofl, &reld, (Rel *)&reloc, isec,
MSG_INTL(MSG_STR_COMMAND), 0) == S_ERROR) {
ret = S_ERROR;
continue;
}
reld.rel_roffset += (Xword)sizeof (Addr);
reloc.r_offset = reld.rel_roffset;
}
return (ret);
}
static uintptr_t
make_comment(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_COMMENT), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_buf = (void *)ofl->ofl_sgsid;
data->d_size = strlen(ofl->ofl_sgsid) + 1;
data->d_align = 1;
shdr->sh_size = (Xword)data->d_size;
shdr->sh_flags = 0;
shdr->sh_addralign = 1;
return ((uintptr_t)ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_note, NULL));
}
static uintptr_t
make_dynamic(Ofl_desc *ofl)
{
Shdr *shdr;
Os_desc *osp;
Elf_Data *data;
Is_desc *isec;
size_t cnt = 0;
Aliste idx;
Ifl_desc *ifl;
Sym_desc *sdp;
size_t size;
Str_tbl *strtbl;
ofl_flag_t flags = ofl->ofl_flags;
int not_relobj = !(flags & FLG_OF_RELOBJ);
int unused = 0;
if (OFL_IS_STATIC_OBJ(ofl))
strtbl = ofl->ofl_strtab;
else
strtbl = ofl->ofl_dynstrtab;
if (new_section(ofl, SHT_DYNAMIC, MSG_ORIG(MSG_SCN_DYNAMIC), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if (not_relobj)
shdr->sh_flags |= SHF_ALLOC;
if (ofl->ofl_osinterp)
shdr->sh_flags |= SHF_WRITE;
osp = ofl->ofl_osdynamic =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynamic, NULL);
for (APLIST_TRAVERSE(ofl->ofl_sos, idx, ifl)) {
if (!(ifl->ifl_flags & (FLG_IF_NEEDED | FLG_IF_NEEDSTR)))
continue;
if ((ifl->ifl_flags & FLG_IF_NEEDSTR) ||
((ifl->ifl_flags & FLG_IF_DEPREQD) == 0)) {
if (unused++ == 0)
DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
DBG_CALL(Dbg_unused_file(ofl->ofl_lml, ifl->ifl_soname,
(ifl->ifl_flags & FLG_IF_NEEDSTR), 0));
if (OFL_GUIDANCE(ofl, FLG_OFG_NO_UNUSED) &&
((ifl->ifl_flags & FLG_IF_IGNORE) == 0))
ld_eprintf(ofl, ERR_GUIDANCE,
MSG_INTL(MSG_GUIDE_UNUSED),
ifl->ifl_soname);
if (ifl->ifl_flags & FLG_IF_NEEDSTR)
ifl->ifl_flags |= FLG_IF_DEPREQD;
else if (ifl->ifl_flags & FLG_IF_IGNORE)
continue;
}
if ((ifl->ifl_flags & MSK_IF_POSFLAG1) && not_relobj)
cnt++;
if (st_insert(strtbl, ifl->ifl_soname) == -1)
return (S_ERROR);
cnt++;
if (strstr(ifl->ifl_soname, MSG_ORIG(MSG_STR_ORIGIN))) {
ofl->ofl_dtflags_1 |= DF_1_ORIGIN;
ofl->ofl_dtflags |= DF_ORIGIN;
}
}
if (unused)
DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
if (not_relobj) {
cnt += alist_nitems(ofl->ofl_dtsfltrs);
if (((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_INIT_U),
SYM_NOHASH, NULL, ofl)) != NULL) &&
(sdp->sd_ref == REF_REL_NEED) &&
(sdp->sd_sym->st_shndx != SHN_UNDEF)) {
sdp->sd_flags |= FLG_SY_UPREQD;
cnt++;
}
if (((sdp = ld_sym_find(MSG_ORIG(MSG_SYM_FINI_U),
SYM_NOHASH, NULL, ofl)) != NULL) &&
(sdp->sd_ref == REF_REL_NEED) &&
(sdp->sd_sym->st_shndx != SHN_UNDEF)) {
sdp->sd_flags |= FLG_SY_UPREQD;
cnt++;
}
if (ofl->ofl_soname) {
cnt++;
if (st_insert(strtbl, ofl->ofl_soname) == -1)
return (S_ERROR);
}
if (ofl->ofl_filtees) {
cnt++;
if (st_insert(strtbl, ofl->ofl_filtees) == -1)
return (S_ERROR);
if (strstr(ofl->ofl_filtees,
MSG_ORIG(MSG_STR_ORIGIN))) {
ofl->ofl_dtflags_1 |= DF_1_ORIGIN;
ofl->ofl_dtflags |= DF_ORIGIN;
}
}
}
if (ofl->ofl_rpath) {
cnt += 2;
if (st_insert(strtbl, ofl->ofl_rpath) == -1)
return (S_ERROR);
if (strstr(ofl->ofl_rpath, MSG_ORIG(MSG_STR_ORIGIN))) {
ofl->ofl_dtflags_1 |= DF_1_ORIGIN;
ofl->ofl_dtflags |= DF_ORIGIN;
}
}
if (not_relobj) {
Aliste idx;
Sg_desc *sgp;
if (ofl->ofl_config) {
cnt++;
if (st_insert(strtbl, ofl->ofl_config) == -1)
return (S_ERROR);
if (strstr(ofl->ofl_config, MSG_ORIG(MSG_STR_ORIGIN))) {
ofl->ofl_dtflags_1 |= DF_1_ORIGIN;
ofl->ofl_dtflags |= DF_ORIGIN;
}
}
if (ofl->ofl_depaudit) {
cnt++;
if (st_insert(strtbl, ofl->ofl_depaudit) == -1)
return (S_ERROR);
}
if (ofl->ofl_audit) {
cnt++;
if (st_insert(strtbl, ofl->ofl_audit) == -1)
return (S_ERROR);
}
cnt += 6;
if (OFL_ALLOW_LDYNSYM(ofl))
cnt += 2;
if ((ofl->ofl_dynsymsortcnt > 0) ||
(ofl->ofl_dyntlssortcnt > 0))
cnt++;
if (ofl->ofl_dynsymsortcnt > 0)
cnt += 2;
if (ofl->ofl_dyntlssortcnt > 0)
cnt += 2;
if ((flags & (FLG_OF_VERDEF | FLG_OF_NOVERSEC)) ==
FLG_OF_VERDEF)
cnt += 2;
if ((flags & (FLG_OF_VERNEED | FLG_OF_NOVERSEC)) ==
FLG_OF_VERNEED)
cnt += 2;
if ((flags & FLG_OF_COMREL) && ofl->ofl_relocrelcnt)
cnt++;
if (flags & FLG_OF_TEXTREL)
cnt++;
if (ofl->ofl_osfiniarray)
cnt += 2;
if (ofl->ofl_osinitarray)
cnt += 2;
if (ofl->ofl_ospreinitarray)
cnt += 2;
if (ofl->ofl_pltcnt)
cnt += 3;
if (ofl->ofl_pltpad)
cnt += 2;
if (ofl->ofl_relocsz)
cnt += 3;
if (flags & FLG_OF_SYMINFO)
cnt += 3;
if (ofl->ofl_osmove)
cnt += 3;
cnt += ofl->ofl_regsymcnt;
for (APLIST_TRAVERSE(ofl->ofl_rtldinfo, idx, sdp))
cnt++;
if (((sgp = osp->os_sgdesc) != NULL) &&
(sgp->sg_phdr.p_flags & PF_W) && ofl->ofl_osinterp)
cnt++;
if (ofl->ofl_oscap)
cnt++;
if (ofl->ofl_oscapinfo)
cnt++;
if (ofl->ofl_oscapchain)
cnt += 3;
if (flags & FLG_OF_SYMBOLIC)
cnt++;
if (ofl->ofl_aslr != 0)
cnt++;
}
if (ofl->ofl_flags & FLG_OF_KMOD)
cnt++;
(*ld_targ.t_mr.mr_mach_make_dynamic)(ofl, &cnt);
cnt += 4 + DYNAMIC_EXTRA_ELTS;
cnt++;
size = cnt * (size_t)shdr->sh_entsize;
shdr->sh_size = (Xword)size;
data->d_size = size;
ofl->ofl_flags |= FLG_OF_OSABI;
return ((uintptr_t)ofl->ofl_osdynamic);
}
uintptr_t
ld_make_got(Ofl_desc *ofl)
{
Elf_Data *data;
Shdr *shdr;
Is_desc *isec;
size_t size = (size_t)ofl->ofl_gotcnt * ld_targ.t_m.m_got_entsize;
size_t rsize = (size_t)ofl->ofl_relocgotsz;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_GOT), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = size;
shdr->sh_flags |= SHF_WRITE;
shdr->sh_size = (Xword)size;
shdr->sh_entsize = ld_targ.t_m.m_got_entsize;
ofl->ofl_osgot = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_got, NULL);
if (ofl->ofl_osgot == (Os_desc *)S_ERROR)
return (S_ERROR);
ofl->ofl_osgot->os_szoutrels = (Xword)rsize;
return (1);
}
static uintptr_t
make_interp(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
const char *iname = ofl->ofl_interp;
size_t size;
if (ofl->ofl_flags1 & FLG_OF1_NOINTRP)
return (1);
if (((ofl->ofl_flags & (FLG_OF_DYNAMIC | FLG_OF_EXEC |
FLG_OF_RELOBJ)) != (FLG_OF_DYNAMIC | FLG_OF_EXEC)) && !iname)
return (1);
if (iname == NULL)
iname = ofl->ofl_interp = ld_targ.t_m.m_def_interp;
size = strlen(iname) + 1;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_INTERP), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
data->d_align = shdr->sh_addralign = 1;
ofl->ofl_osinterp =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_interp, NULL);
return ((uintptr_t)ofl->ofl_osinterp);
}
static Os_desc *
make_sym_sec(Ofl_desc *ofl, const char *sectname, Word stype, int ident)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (new_section(ofl, stype, sectname, 0, &isec, &shdr, &data) ==
S_ERROR)
return ((Os_desc *)S_ERROR);
return (ld_place_section(ofl, isec, NULL, ident, NULL));
}
inline static int
is_cap_redundant(Objcapset *ocapset, Objcapset *scapset)
{
Alist *oalp, *salp;
elfcap_mask_t omsk, smsk;
oalp = ocapset->oc_plat.cl_val;
salp = scapset->oc_plat.cl_val;
if (oalp && ((salp == NULL) || cap_names_match(oalp, salp)))
return (1);
if (salp && (oalp == NULL))
return (0);
oalp = ocapset->oc_plat.cl_val;
salp = scapset->oc_plat.cl_val;
if (oalp && ((salp == NULL) || cap_names_match(oalp, salp)))
return (1);
if (salp && (oalp == NULL))
return (0);
omsk = ocapset->oc_hw_3.cm_val;
smsk = scapset->oc_hw_3.cm_val;
if ((omsk > smsk) || (omsk && (omsk == smsk)))
return (1);
if (omsk < smsk)
return (0);
omsk = ocapset->oc_hw_2.cm_val;
smsk = scapset->oc_hw_2.cm_val;
if ((omsk > smsk) || (omsk && (omsk == smsk)))
return (1);
if (omsk < smsk)
return (0);
omsk = ocapset->oc_hw_1.cm_val;
smsk = scapset->oc_hw_1.cm_val;
if ((omsk > smsk) || (omsk && (omsk == smsk)))
return (1);
return (0);
}
static void
capmask_value(Lm_list *lml, Word type, Capmask *capmask, int *title)
{
if ((capmask->cm_val & capmask->cm_exc) == 0)
return;
DBG_CALL(Dbg_cap_post_title(lml, title));
DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_CURRENT, type,
capmask->cm_val, ld_targ.t_m.m_mach));
DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_EXCLUDE, type,
capmask->cm_exc, ld_targ.t_m.m_mach));
capmask->cm_val &= ~capmask->cm_exc;
DBG_CALL(Dbg_cap_val_entry(lml, DBG_STATE_RESOLVED, type,
capmask->cm_val, ld_targ.t_m.m_mach));
}
static void
capstr_value(Lm_list *lml, Word type, Caplist *caplist, int *title)
{
Aliste idx1, idx2;
char *estr;
Capstr *capstr;
Boolean found = FALSE;
for (APLIST_TRAVERSE(caplist->cl_exc, idx1, estr)) {
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
if (strcmp(estr, capstr->cs_str) == 0) {
found = TRUE;
break;
}
}
}
if (found == FALSE)
return;
if (DBG_ENABLED) {
Dbg_cap_post_title(lml, title);
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
Dbg_cap_ptr_entry(lml, DBG_STATE_CURRENT, type,
capstr->cs_str);
}
}
for (APLIST_TRAVERSE(caplist->cl_exc, idx1, estr)) {
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
if (strcmp(estr, capstr->cs_str) == 0) {
DBG_CALL(Dbg_cap_ptr_entry(lml,
DBG_STATE_EXCLUDE, type, capstr->cs_str));
alist_delete(caplist->cl_val, &idx2);
break;
}
}
}
if (DBG_ENABLED) {
for (ALIST_TRAVERSE(caplist->cl_val, idx2, capstr)) {
Dbg_cap_ptr_entry(lml, DBG_STATE_RESOLVED, type,
capstr->cs_str);
}
}
}
#define CAP_UPDATE(cap, capndx, tag, val) \
cap->c_tag = tag; \
cap->c_un.c_val = val; \
cap++, capndx++;
static uintptr_t
make_cap(Ofl_desc *ofl, Word shtype, const char *shname, int ident)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Cap *cap;
size_t size = 0;
Word capndx = 0;
Str_tbl *strtbl;
Objcapset *ocapset = &ofl->ofl_ocapset;
Aliste idx1;
Capstr *capstr;
int title = 0;
if (OFL_IS_STATIC_OBJ(ofl))
strtbl = ofl->ofl_strtab;
else
strtbl = ofl->ofl_dynstrtab;
if ((ofl->ofl_flags & FLG_OF_OTOSCAP) && (ofl->ofl_capsymcnt == 0))
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_CAP_NOSYMSFOUND));
if ((ofl->ofl_flags & FLG_OF_OTOSCAP) && ofl->ofl_capsymcnt &&
(ofl->ofl_capfamilies == NULL)) {
ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_CAP_NOSYMSFOUND));
ld_cap_move_symtoobj(ofl);
ofl->ofl_capsymcnt = 0;
ofl->ofl_capgroups = NULL;
ofl->ofl_flags &= ~FLG_OF_OTOSCAP;
}
capstr_value(ofl->ofl_lml, CA_SUNW_PLAT, &ocapset->oc_plat, &title);
capstr_value(ofl->ofl_lml, CA_SUNW_MACH, &ocapset->oc_mach, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_HW_3, &ocapset->oc_hw_3, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_HW_2, &ocapset->oc_hw_2, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_HW_1, &ocapset->oc_hw_1, &title);
capmask_value(ofl->ofl_lml, CA_SUNW_SF_1, &ocapset->oc_sf_1, &title);
size += alist_nitems(ocapset->oc_plat.cl_val);
size += alist_nitems(ocapset->oc_mach.cl_val);
if (ocapset->oc_hw_3.cm_val)
size++;
if (ocapset->oc_hw_2.cm_val)
size++;
if (ocapset->oc_hw_1.cm_val)
size++;
if (ocapset->oc_sf_1.cm_val)
size++;
if (ocapset->oc_id.cs_str) {
if (size)
size++;
else
ocapset->oc_id.cs_str = NULL;
}
if (size)
size++;
if (ofl->ofl_capsymcnt) {
if (size == 0)
size++;
size += ofl->ofl_capsymcnt;
}
if (size == 0)
return (0);
if (new_section(ofl, shtype, shname, size, &isec,
&shdr, &data) == S_ERROR)
return (S_ERROR);
if ((data->d_buf = libld_malloc(shdr->sh_size)) == NULL)
return (S_ERROR);
cap = (Cap *)data->d_buf;
if (ocapset->oc_id.cs_str) {
ofl->ofl_flags |= FLG_OF_CAPSTRS;
if (st_insert(strtbl, ocapset->oc_id.cs_str) == -1)
return (S_ERROR);
ocapset->oc_id.cs_ndx = capndx;
CAP_UPDATE(cap, capndx, CA_SUNW_ID, 0);
}
if (ocapset->oc_plat.cl_val) {
ofl->ofl_flags |= (FLG_OF_PTCAP | FLG_OF_CAPSTRS);
for (ALIST_TRAVERSE(ocapset->oc_plat.cl_val, idx1, capstr)) {
if (st_insert(strtbl, capstr->cs_str) == -1)
return (S_ERROR);
capstr->cs_ndx = capndx;
CAP_UPDATE(cap, capndx, CA_SUNW_PLAT, 0);
}
}
if (ocapset->oc_mach.cl_val) {
ofl->ofl_flags |= (FLG_OF_PTCAP | FLG_OF_CAPSTRS);
for (ALIST_TRAVERSE(ocapset->oc_mach.cl_val, idx1, capstr)) {
if (st_insert(strtbl, capstr->cs_str) == -1)
return (S_ERROR);
capstr->cs_ndx = capndx;
CAP_UPDATE(cap, capndx, CA_SUNW_MACH, 0);
}
}
if (ocapset->oc_hw_3.cm_val) {
ofl->ofl_flags |= FLG_OF_PTCAP;
CAP_UPDATE(cap, capndx, CA_SUNW_HW_3, ocapset->oc_hw_3.cm_val);
}
if (ocapset->oc_hw_2.cm_val) {
ofl->ofl_flags |= FLG_OF_PTCAP;
CAP_UPDATE(cap, capndx, CA_SUNW_HW_2, ocapset->oc_hw_2.cm_val);
}
if (ocapset->oc_hw_1.cm_val) {
ofl->ofl_flags |= FLG_OF_PTCAP;
CAP_UPDATE(cap, capndx, CA_SUNW_HW_1, ocapset->oc_hw_1.cm_val);
}
if (ocapset->oc_sf_1.cm_val) {
ofl->ofl_flags |= FLG_OF_PTCAP;
CAP_UPDATE(cap, capndx, CA_SUNW_SF_1, ocapset->oc_sf_1.cm_val);
}
CAP_UPDATE(cap, capndx, CA_SUNW_NULL, 0);
if (ofl->ofl_capgroups) {
Cap_group *cgp;
for (APLIST_TRAVERSE(ofl->ofl_capgroups, idx1, cgp)) {
Objcapset *scapset = &cgp->cg_set;
Aliste idx2;
Is_desc *isp;
cgp->cg_ndx = capndx;
if (scapset->oc_id.cs_str) {
ofl->ofl_flags |= FLG_OF_CAPSTRS;
if (st_insert(strtbl,
scapset->oc_id.cs_str) == -1)
return (S_ERROR);
scapset->oc_id.cs_ndx = capndx;
CAP_UPDATE(cap, capndx, CA_SUNW_ID, 0);
}
if (scapset->oc_plat.cl_val) {
ofl->ofl_flags |= FLG_OF_CAPSTRS;
for (ALIST_TRAVERSE(scapset->oc_plat.cl_val,
idx2, capstr)) {
if (st_insert(strtbl,
capstr->cs_str) == -1)
return (S_ERROR);
capstr->cs_ndx = capndx;
CAP_UPDATE(cap, capndx,
CA_SUNW_PLAT, 0);
}
}
if (scapset->oc_mach.cl_val) {
ofl->ofl_flags |= FLG_OF_CAPSTRS;
for (ALIST_TRAVERSE(scapset->oc_mach.cl_val,
idx2, capstr)) {
if (st_insert(strtbl,
capstr->cs_str) == -1)
return (S_ERROR);
capstr->cs_ndx = capndx;
CAP_UPDATE(cap, capndx,
CA_SUNW_MACH, 0);
}
}
if (scapset->oc_hw_3.cm_val) {
CAP_UPDATE(cap, capndx, CA_SUNW_HW_3,
scapset->oc_hw_3.cm_val);
}
if (scapset->oc_hw_2.cm_val) {
CAP_UPDATE(cap, capndx, CA_SUNW_HW_2,
scapset->oc_hw_2.cm_val);
}
if (scapset->oc_hw_1.cm_val) {
CAP_UPDATE(cap, capndx, CA_SUNW_HW_1,
scapset->oc_hw_1.cm_val);
}
if (scapset->oc_sf_1.cm_val) {
CAP_UPDATE(cap, capndx, CA_SUNW_SF_1,
scapset->oc_sf_1.cm_val);
}
CAP_UPDATE(cap, capndx, CA_SUNW_NULL, 0);
if (((ofl->ofl_flags & FLG_OF_PTCAP) == 0) ||
(is_cap_redundant(ocapset, scapset) == 0))
continue;
for (APLIST_TRAVERSE(cgp->cg_secs, idx2, isp)) {
ld_eprintf(ofl, ERR_WARNING,
MSG_INTL(MSG_CAP_REDUNDANT),
isp->is_file->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name);
}
}
}
if (ofl->ofl_flags & FLG_OF_CAPSTRS)
shdr->sh_flags |= SHF_INFO_LINK;
if ((ofl->ofl_oscap = ld_place_section(ofl, isec,
NULL, ident, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
if (ofl->ofl_capfamilies) {
if ((ofl->ofl_oscapinfo = make_sym_sec(ofl,
MSG_ORIG(MSG_SCN_SUNWCAPINFO), SHT_SUNW_capinfo,
ld_targ.t_id.id_capinfo)) == (Os_desc *)S_ERROR)
return (S_ERROR);
if (ofl->ofl_capchaincnt &&
((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)) {
if (new_section(ofl, SHT_SUNW_capchain,
MSG_ORIG(MSG_SCN_SUNWCAPCHAIN),
ofl->ofl_capchaincnt, &isec, &shdr,
&data) == S_ERROR)
return (S_ERROR);
ofl->ofl_oscapchain = ld_place_section(ofl, isec,
NULL, ld_targ.t_id.id_capchain, NULL);
if (ofl->ofl_oscapchain == (Os_desc *)S_ERROR)
return (S_ERROR);
}
}
return (1);
}
#undef CAP_UPDATE
static uintptr_t
make_plt(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size = ld_targ.t_m.m_plt_reservsz +
(((size_t)ofl->ofl_pltcnt + (size_t)ofl->ofl_pltpad) *
ld_targ.t_m.m_plt_entsize);
size_t rsize = (size_t)ofl->ofl_relocpltsz;
if (ld_targ.t_m.m_mach == LD_TARG_BYCLASS(EM_SPARC, EM_SPARCV9))
size += sizeof (Word);
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_PLT), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = size;
data->d_align = ld_targ.t_m.m_plt_align;
shdr->sh_flags = ld_targ.t_m.m_plt_shf_flags;
shdr->sh_size = (Xword)size;
shdr->sh_addralign = ld_targ.t_m.m_plt_align;
shdr->sh_entsize = ld_targ.t_m.m_plt_entsize;
ofl->ofl_osplt = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_plt, NULL);
if (ofl->ofl_osplt == (Os_desc *)S_ERROR)
return (S_ERROR);
ofl->ofl_osplt->os_szoutrels = (Xword)rsize;
return (1);
}
static uintptr_t
make_hash(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
Word nsyms = ofl->ofl_globcnt;
size_t cnt;
if (new_section(ofl, SHT_HASH, MSG_ORIG(MSG_SCN_HASH), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
ofl->ofl_oshash =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_hash, NULL);
if (ofl->ofl_oshash == (Os_desc *)S_ERROR)
return (S_ERROR);
ofl->ofl_hashbkts = findprime(nsyms);
cnt = 2 + ofl->ofl_hashbkts + DYNSYM_ALL_CNT(ofl);
size = cnt * shdr->sh_entsize;
if ((data->d_buf = libld_calloc(size, 1)) == NULL)
return (S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
return (1);
}
static uintptr_t
make_symtab(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Is_desc *xisec = 0;
size_t size;
Word symcnt;
if (new_section(ofl, SHT_SYMTAB, MSG_ORIG(MSG_SCN_SYMTAB), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if ((ofl->ofl_ossymtab = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_symtab, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
if ((ofl->ofl_shdrcnt + 1) >= SHN_LORESERVE) {
Shdr *xshdr;
Elf_Data *xdata;
if (new_section(ofl, SHT_SYMTAB_SHNDX,
MSG_ORIG(MSG_SCN_SYMTAB_SHNDX), 0, &xisec,
&xshdr, &xdata) == S_ERROR)
return (S_ERROR);
if ((ofl->ofl_ossymshndx = ld_place_section(ofl, xisec, NULL,
ld_targ.t_id.id_symtab_ndx, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
symcnt = (size_t)(1 + SYMTAB_ALL_CNT(ofl));
size = symcnt * shdr->sh_entsize;
data->d_size = size;
shdr->sh_size = (Xword)size;
if (xisec) {
size_t xsize = symcnt * sizeof (Word);
xisec->is_indata->d_size = xsize;
xisec->is_shdr->sh_size = (Xword)xsize;
}
return (1);
}
static uintptr_t
make_dynsym(Ofl_desc *ofl)
{
Shdr *shdr, *lshdr;
Elf_Data *data, *ldata;
Is_desc *isec, *lisec;
size_t size;
Xword cnt;
int allow_ldynsym;
allow_ldynsym = OFL_ALLOW_LDYNSYM(ofl);
if (allow_ldynsym && new_section(ofl, SHT_SUNW_LDYNSYM,
MSG_ORIG(MSG_SCN_LDYNSYM), 0, &lisec, &lshdr, &ldata) == S_ERROR)
return (S_ERROR);
if (new_section(ofl, SHT_DYNSYM, MSG_ORIG(MSG_SCN_DYNSYM), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if (allow_ldynsym &&
((ofl->ofl_osldynsym = ld_place_section(ofl, lisec, NULL,
ld_targ.t_id.id_ldynsym, NULL)) == (Os_desc *)S_ERROR))
return (S_ERROR);
ofl->ofl_osdynsym =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynsym, NULL);
if (ofl->ofl_osdynsym == (Os_desc *)S_ERROR)
return (S_ERROR);
cnt = DYNSYM_ALL_CNT(ofl);
size = (size_t)cnt * shdr->sh_entsize;
data->d_size = size;
shdr->sh_size = (Xword)size;
if (allow_ldynsym) {
cnt = 1 + ofl->ofl_dynlocscnt + ofl->ofl_dynscopecnt;
size = (size_t)cnt * shdr->sh_entsize;
ldata->d_size = size;
lshdr->sh_size = (Xword)size;
}
return (1);
}
static uintptr_t
make_dynsort(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (!OFL_ALLOW_LDYNSYM(ofl))
return (1);
if (ofl->ofl_dynsymsortcnt > 0) {
if (new_section(ofl, SHT_SUNW_symsort,
MSG_ORIG(MSG_SCN_DYNSYMSORT), ofl->ofl_dynsymsortcnt,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if ((ofl->ofl_osdynsymsort = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
if (ofl->ofl_dyntlssortcnt > 0) {
if (new_section(ofl, SHT_SUNW_tlssort,
MSG_ORIG(MSG_SCN_DYNTLSSORT),
ofl->ofl_dyntlssortcnt, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if ((ofl->ofl_osdyntlssort = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsort, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
return (1);
}
static uintptr_t
make_dyn_shndx(Ofl_desc *ofl, const char *shname, Os_desc *symtab,
Os_desc **ret_os)
{
Is_desc *isec;
Is_desc *dynsymisp;
Shdr *shdr, *dynshdr;
Elf_Data *data;
dynsymisp = ld_os_first_isdesc(symtab);
dynshdr = dynsymisp->is_shdr;
if (new_section(ofl, SHT_SYMTAB_SHNDX, shname,
(dynshdr->sh_size / dynshdr->sh_entsize),
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if ((*ret_os = ld_place_section(ofl, isec, NULL,
ld_targ.t_id.id_dynsym_ndx, NULL)) == (Os_desc *)S_ERROR)
return (S_ERROR);
assert(*ret_os);
return (1);
}
static uintptr_t
make_dynsym_shndx(Ofl_desc *ofl)
{
if (OFL_ALLOW_LDYNSYM(ofl)) {
if (make_dyn_shndx(ofl, MSG_ORIG(MSG_SCN_LDYNSYM_SHNDX),
ofl->ofl_osldynsym, &ofl->ofl_osldynshndx) == S_ERROR)
return (S_ERROR);
}
if (make_dyn_shndx(ofl, MSG_ORIG(MSG_SCN_DYNSYM_SHNDX),
ofl->ofl_osdynsym, &ofl->ofl_osdynshndx) == S_ERROR)
return (S_ERROR);
return (1);
}
static uintptr_t
make_shstrtab(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_SHSTRTAB),
0, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
ofl->ofl_osshstrtab =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_note, NULL);
if (ofl->ofl_osshstrtab == (Os_desc *)S_ERROR)
return (S_ERROR);
size = st_getstrtab_sz(ofl->ofl_shdrsttab);
assert(size > 0);
data->d_size = size;
shdr->sh_size = (Xword)size;
return (1);
}
static uintptr_t
make_strtab(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
if (st_insert(ofl->ofl_strtab, ofl->ofl_name) == -1)
return (S_ERROR);
size = st_getstrtab_sz(ofl->ofl_strtab);
assert(size > 0);
if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_STRTAB),
0, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
ofl->ofl_osstrtab =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_strtab, NULL);
return ((uintptr_t)ofl->ofl_osstrtab);
}
static uintptr_t
make_dynstr(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
if (OFL_ALLOW_LDYNSYM(ofl)) {
if (st_insert(ofl->ofl_dynstrtab, ofl->ofl_name) == -1)
return (S_ERROR);
ofl->ofl_dynscopecnt++;
}
if (ofl->ofl_regsyms) {
int ndx;
for (ndx = 0; ndx < ofl->ofl_regsymsno; ndx++) {
Sym_desc *sdp;
if ((sdp = ofl->ofl_regsyms[ndx]) == NULL)
continue;
if (!SYM_IS_HIDDEN(sdp) &&
(ELF_ST_BIND(sdp->sd_sym->st_info) != STB_LOCAL))
continue;
if (sdp->sd_sym->st_name == 0)
continue;
if (st_insert(ofl->ofl_dynstrtab, sdp->sd_name) == -1)
return (S_ERROR);
}
}
if (ofl->ofl_dtsfltrs != NULL) {
Dfltr_desc *dftp;
Aliste idx;
for (ALIST_TRAVERSE(ofl->ofl_dtsfltrs, idx, dftp))
if (st_insert(ofl->ofl_dynstrtab, dftp->dft_str) == -1)
return (S_ERROR);
}
size = st_getstrtab_sz(ofl->ofl_dynstrtab);
assert(size > 0);
if (new_section(ofl, SHT_STRTAB, MSG_ORIG(MSG_SCN_DYNSTR),
0, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if (!(ofl->ofl_flags & FLG_OF_RELOBJ))
shdr->sh_flags |= SHF_ALLOC;
data->d_size = size + DYNSTR_EXTRA_PAD;
shdr->sh_size = (Xword)size;
ofl->ofl_osdynstr =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_dynstr, NULL);
return ((uintptr_t)ofl->ofl_osdynstr);
}
static uintptr_t
make_reloc(Ofl_desc *ofl, Os_desc *osp)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
size_t size;
Xword sh_flags;
char *sectname;
Os_desc *rosp;
Word relsize;
const char *rel_prefix;
if (ld_targ.t_m.m_rel_sht_type == SHT_REL) {
relsize = sizeof (Rel);
rel_prefix = MSG_ORIG(MSG_SCN_REL);
} else {
relsize = sizeof (Rela);
rel_prefix = MSG_ORIG(MSG_SCN_RELA);
}
if (osp) {
size = osp->os_szoutrels;
sh_flags = osp->os_shdr->sh_flags;
if ((sectname = libld_malloc(strlen(rel_prefix) +
strlen(osp->os_name) + 1)) == 0)
return (S_ERROR);
(void) strcpy(sectname, rel_prefix);
(void) strcat(sectname, osp->os_name);
} else if (ofl->ofl_flags & FLG_OF_COMREL) {
size = (ofl->ofl_reloccnt - ofl->ofl_reloccntsub) * relsize;
sh_flags = SHF_ALLOC;
sectname = (char *)MSG_ORIG(MSG_SCN_SUNWRELOC);
} else {
size = ofl->ofl_relocrelsz;
sh_flags = SHF_ALLOC;
sectname = (char *)rel_prefix;
}
ofl->ofl_relocsz += (Xword)size;
if (new_section(ofl, ld_targ.t_m.m_rel_sht_type, sectname, 0, &isec,
&shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
if (OFL_ALLOW_DYNSYM(ofl) && (sh_flags & SHF_ALLOC))
shdr->sh_flags = SHF_ALLOC;
if (osp) {
shdr->sh_flags |= SHF_INFO_LINK;
}
rosp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_rel, NULL);
if (rosp == (Os_desc *)S_ERROR)
return (S_ERROR);
if (osp) {
Aliste idx;
Is_desc *risp;
for (APLIST_TRAVERSE(osp->os_relisdescs, idx, risp)) {
risp->is_osdesc = rosp;
if (risp->is_shdr->sh_flags & SHF_GROUP) {
rosp->os_shdr->sh_flags |= SHF_GROUP;
break;
}
}
osp->os_relosdesc = rosp;
} else
ofl->ofl_osrel = rosp;
if (ofl->ofl_osrelhead == (Os_desc *)0)
ofl->ofl_osrelhead = rosp;
return (1);
}
static uintptr_t
make_verneed(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (new_section(ofl, SHT_SUNW_verneed, MSG_ORIG(MSG_SCN_SUNWVERSION),
0, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = ofl->ofl_verneedsz;
shdr->sh_size = (Xword)ofl->ofl_verneedsz;
ofl->ofl_osverneed =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
return ((uintptr_t)ofl->ofl_osverneed);
}
static uintptr_t
make_verdef(Ofl_desc *ofl)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Ver_desc *vdp;
Str_tbl *strtab;
vdp = (Ver_desc *)ofl->ofl_verdesc->apl_data[0];
if (OFL_IS_STATIC_OBJ(ofl))
strtab = ofl->ofl_strtab;
else
strtab = ofl->ofl_dynstrtab;
if (st_insert(strtab, vdp->vd_name) == -1)
return (S_ERROR);
if (new_section(ofl, SHT_SUNW_verdef, MSG_ORIG(MSG_SCN_SUNWVERSION),
0, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
data->d_size = ofl->ofl_verdefsz;
shdr->sh_size = (Xword)ofl->ofl_verdefsz;
ofl->ofl_osverdef =
ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_version, NULL);
return ((uintptr_t)ofl->ofl_osverdef);
}
uintptr_t
ld_make_parexpn_data(Ofl_desc *ofl, size_t size, Xword align)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Os_desc *osp;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_DATA), 0,
&isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
shdr->sh_flags |= SHF_WRITE;
data->d_size = size;
shdr->sh_size = (Xword)size;
if (align != 0) {
data->d_align = align;
shdr->sh_addralign = align;
}
if ((data->d_buf = libld_calloc(size, 1)) == NULL)
return (S_ERROR);
ofl->ofl_isparexpn = isec;
osp = ld_place_section(ofl, isec, NULL, ld_targ.t_id.id_data, NULL);
if (osp == (Os_desc *)S_ERROR)
return (S_ERROR);
if (!(osp->os_flags & FLG_OS_OUTREL)) {
ofl->ofl_dynshdrcnt++;
osp->os_flags |= FLG_OS_OUTREL;
}
return (1);
}
uintptr_t
ld_make_sunwmove(Ofl_desc *ofl, int mv_nums)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
Aliste idx;
Sym_desc *sdp;
int cnt = 1;
if (new_section(ofl, SHT_SUNW_move, MSG_ORIG(MSG_SCN_SUNWMOVE),
mv_nums, &isec, &shdr, &data) == S_ERROR)
return (S_ERROR);
if ((data->d_buf = libld_calloc(data->d_size, 1)) == NULL)
return (S_ERROR);
for (APLIST_TRAVERSE(ofl->ofl_parsyms, idx, sdp)) {
Aliste idx2;
Mv_desc *mdp;
if (sdp->sd_flags & FLG_SY_PAREXPN)
continue;
for (ALIST_TRAVERSE(sdp->sd_move, idx2, mdp))
mdp->md_oidx = cnt++;
}
if ((ofl->ofl_osmove = ld_place_section(ofl, isec, NULL, 0, NULL)) ==
(Os_desc *)S_ERROR)
return (S_ERROR);
return (1);
}
static const char *
strmerge_get_reloc_str(Ofl_desc *ofl, Rel_desc *rsp)
{
Sym_desc *sdp = rsp->rel_sym;
Xword str_off;
if (ELF_ST_TYPE(sdp->sd_sym->st_info) != STT_SECTION) {
str_off = sdp->sd_sym->st_value;
} else if ((rsp->rel_flags & FLG_REL_RELA) == FLG_REL_RELA) {
str_off = rsp->rel_raddend;
} else {
uchar_t *addr = (uchar_t *)((uintptr_t)rsp->rel_roffset +
(uintptr_t)rsp->rel_isdesc->is_indata->d_buf);
if (ld_reloc_targval_get(ofl, rsp, addr, &str_off) == 0)
return (0);
}
return (str_off + (char *)sdp->sd_isc->is_indata->d_buf);
}
static uintptr_t
ld_gather_strmerge(Ofl_desc *ofl, Rel_cache *cache)
{
Rel_cachebuf *rbcp;
Rel_desc *rsp;
Sym_desc *last_sdp = NULL;
Aliste idx1;
REL_CACHE_TRAVERSE(cache, idx1, rbcp, rsp) {
Sym_desc *sdp = rsp->rel_sym;
Os_desc *osp;
const char *name;
if ((sdp->sd_isc == NULL) || ((sdp->sd_isc->is_flags &
(FLG_IS_DISCARD | FLG_IS_INSTRMRG)) != FLG_IS_INSTRMRG))
continue;
osp = sdp->sd_isc->is_osdesc;
if (last_sdp != sdp) {
if (aplist_append(&osp->os_mstrsyms, sdp,
AL_CNT_STRMRGSYM) == NULL)
return (S_ERROR);
last_sdp = sdp;
}
if ((osp->os_mstrtab == NULL) &&
(osp->os_mstrtab = st_new(FLG_STNEW_COMPRESS)) == NULL)
return (S_ERROR);
name = strmerge_get_reloc_str(ofl, rsp);
if (st_insert(osp->os_mstrtab, name) == -1)
return (S_ERROR);
if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) &&
(aplist_append(&osp->os_mstrrels, rsp,
AL_CNT_STRMRGREL) == NULL)) {
return (S_ERROR);
}
}
return (0);
}
static uintptr_t
ld_strmerge_sec(Ofl_desc *ofl, Os_desc *osp)
{
Is_desc *isp = NULL;
Sym_desc *sdp;
Rel_desc *rsp;
Is_desc *mstrsec = NULL;
Shdr *mstr_shdr = NULL;
Elf_Data *mstr_data = NULL;
size_t data_size;
Aliste idx;
uintptr_t ret = 0;
Boolean placed = FALSE;
for (APLIST_TRAVERSE(osp->os_mstrisdescs, idx, isp)) {
const char *str, *end;
if (isdesc_discarded(isp))
continue;
if (isp->is_shdr->sh_size == 0)
continue;
if ((osp->os_mstrtab == NULL) &&
(osp->os_mstrtab = st_new(FLG_STNEW_COMPRESS)) == NULL) {
ret = S_ERROR;
goto out;
}
end = isp->is_indata->d_buf + isp->is_indata->d_size;
for (str = isp->is_indata->d_buf; str < end;
str += strlen(str) + 1) {
if (st_insert(osp->os_mstrtab, str) != 0) {
ret = S_ERROR;
goto out;
}
}
}
IMPLY(osp->os_mstrtab != NULL, isp != NULL);
if (osp->os_mstrtab == NULL) {
ret = 0;
goto out;
}
data_size = st_getstrtab_sz(osp->os_mstrtab);
if (new_section_from_template(ofl, isp, data_size,
&mstrsec, &mstr_shdr, &mstr_data) == S_ERROR) {
ret = S_ERROR;
goto out;
}
mstrsec->is_flags |= FLG_IS_GNSTRMRG;
if ((mstr_data->d_buf = libld_malloc(data_size)) == NULL) {
ret = S_ERROR;
goto out;
}
if ((st_setstrbuf(osp->os_mstrtab, mstr_data->d_buf,
data_size) == -1)) {
ret = S_ERROR;
goto out;
}
st_setallstrings(osp->os_mstrtab);
if (ld_place_section(ofl, mstrsec, NULL, osp->os_identndx, NULL) ==
(Os_desc *)S_ERROR) {
ret = S_ERROR;
goto out;
}
placed = TRUE;
for (APLIST_TRAVERSE(osp->os_mstrrels, idx, rsp)) {
const char *name;
size_t stoff;
name = strmerge_get_reloc_str(ofl, rsp);
stoff = st_findstring(osp->os_mstrtab, name);
VERIFY3S(stoff, !=, -1);
if ((rsp->rel_flags & FLG_REL_RELA) == 0) {
rsp->rel_flags |= FLG_REL_NADDEND;
}
rsp->rel_raddend = (Sxword)stoff;
if (ld_stt_section_sym_name(mstrsec) == NULL) {
ret = S_ERROR;
goto out;
}
}
for (APLIST_TRAVERSE(osp->os_mstrsyms, idx, sdp)) {
if ((sdp->sd_isc->is_flags & FLG_IS_INSTRMRG) == 0)
continue;
if (ELF_ST_TYPE(sdp->sd_sym->st_info) != STT_SECTION) {
const char *name;
size_t stoff;
name = sdp->sd_sym->st_value +
(char *)sdp->sd_isc->is_indata->d_buf;
stoff = st_findstring(osp->os_mstrtab, name);
VERIFY3S(stoff, !=, -1);
if (ld_sym_copy(sdp) == S_ERROR) {
ret = S_ERROR;
goto out;
}
sdp->sd_sym->st_value = (Word)stoff;
}
sdp->sd_isc = mstrsec;
}
data_size = 0;
for (APLIST_TRAVERSE(osp->os_mstrisdescs, idx, isp)) {
if (isp->is_flags & (FLG_IS_DISCARD | FLG_IS_GNSTRMRG))
continue;
data_size += isp->is_indata->d_size;
isp->is_flags |= FLG_IS_DISCARD;
DBG_CALL(Dbg_sec_discarded(ofl->ofl_lml, isp, mstrsec));
}
DBG_CALL(Dbg_sec_genstr_compress(ofl->ofl_lml, osp->os_name, data_size,
mstr_data->d_size));
out:
if ((ret == S_ERROR) && !placed) {
libld_free(mstrsec);
if (mstr_data != NULL)
libld_free(mstr_data->d_buf);
libld_free(mstr_data);
libld_free(mstr_shdr);
}
libld_free(osp->os_mstrsyms);
osp->os_mstrsyms = NULL;
libld_free(osp->os_mstrrels);
osp->os_mstrrels = NULL;
if (osp->os_mstrtab != NULL) {
st_destroy(osp->os_mstrtab);
osp->os_mstrtab = NULL;
}
return (ret);
}
static uintptr_t
ld_make_strmerge(Ofl_desc *ofl)
{
Sg_desc *sgp;
Aliste idx1;
if (ld_gather_strmerge(ofl, &ofl->ofl_actrels) == S_ERROR)
return (S_ERROR);
if (ld_gather_strmerge(ofl, &ofl->ofl_outrels) == S_ERROR)
return (S_ERROR);
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Os_desc *osp;
Aliste idx2;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
if (ld_strmerge_sec(ofl, osp) == S_ERROR)
return (S_ERROR);
}
}
return (0);
}
inline static void
update_data_size(Os_desc *osp, ulong_t cnt)
{
Is_desc *isec = ld_os_first_isdesc(osp);
Elf_Data *data = isec->is_indata;
Shdr *shdr = osp->os_shdr;
size_t size = cnt * shdr->sh_entsize;
shdr->sh_size = (Xword)size;
data->d_size = size;
}
uintptr_t
ld_make_sections(Ofl_desc *ofl)
{
ofl_flag_t flags = ofl->ofl_flags;
Sg_desc *sgp;
if (flags & FLG_OF_ADDVERS)
if (make_comment(ofl) == S_ERROR)
return (S_ERROR);
if (make_interp(ofl) == S_ERROR)
return (S_ERROR);
if (make_cap(ofl, SHT_SUNW_cap, MSG_ORIG(MSG_SCN_SUNWCAP),
ld_targ.t_id.id_cap) == S_ERROR)
return (S_ERROR);
if (make_array(ofl, SHT_INIT_ARRAY, MSG_ORIG(MSG_SCN_INITARRAY),
ofl->ofl_initarray) == S_ERROR)
return (S_ERROR);
if (make_array(ofl, SHT_FINI_ARRAY, MSG_ORIG(MSG_SCN_FINIARRAY),
ofl->ofl_finiarray) == S_ERROR)
return (S_ERROR);
if (make_array(ofl, SHT_PREINIT_ARRAY, MSG_ORIG(MSG_SCN_PREINITARRAY),
ofl->ofl_preiarray) == S_ERROR)
return (S_ERROR);
if ((ofl->ofl_pltcnt) || (ofl->ofl_pltpad))
if (make_plt(ofl) == S_ERROR)
return (S_ERROR);
if (DBG_ENABLED || (ofl->ofl_flags1 & FLG_OF1_IGNPRC)) {
if (ignore_section_processing(ofl) == S_ERROR)
return (S_ERROR);
}
if (ofl->ofl_flags & FLG_OF_ADJOSCNT)
adjust_os_count(ofl);
if ((ofl->ofl_flags1 & FLG_OF1_NCSTTAB) == 0) {
if (ld_make_strmerge(ofl) == S_ERROR)
return (S_ERROR);
}
if (!(flags & FLG_OF_NOVERSEC)) {
if ((flags & FLG_OF_VERNEED) &&
(make_verneed(ofl) == S_ERROR))
return (S_ERROR);
if ((flags & FLG_OF_VERDEF) &&
(make_verdef(ofl) == S_ERROR))
return (S_ERROR);
if ((flags & (FLG_OF_VERNEED | FLG_OF_VERDEF)) &&
((ofl->ofl_osversym = make_sym_sec(ofl,
MSG_ORIG(MSG_SCN_SUNWVERSYM), SHT_SUNW_versym,
ld_targ.t_id.id_version)) == (Os_desc*)S_ERROR))
return (S_ERROR);
}
if (flags & FLG_OF_SYMINFO) {
if ((ofl->ofl_ossyminfo = make_sym_sec(ofl,
MSG_ORIG(MSG_SCN_SUNWSYMINFO), SHT_SUNW_syminfo,
ld_targ.t_id.id_syminfo)) == (Os_desc *)S_ERROR)
return (S_ERROR);
}
if (flags & FLG_OF_COMREL) {
if (ofl->ofl_reloccnt) {
if (make_reloc(ofl, NULL) == S_ERROR)
return (S_ERROR);
}
} else {
Aliste idx1;
for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
Os_desc *osp, *posp = 0;
Aliste idx2;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
if ((osp != posp) && osp->os_szoutrels &&
(osp != ofl->ofl_osplt)) {
if (make_reloc(ofl, osp) == S_ERROR)
return (S_ERROR);
}
posp = osp;
}
}
if (ofl->ofl_relocrelsz) {
if (make_reloc(ofl, NULL) == S_ERROR)
return (S_ERROR);
}
}
if (ofl->ofl_osplt && ofl->ofl_relocpltsz) {
if (make_reloc(ofl, ofl->ofl_osplt) == S_ERROR)
return (S_ERROR);
}
if (flags & FLG_OF_DYNAMIC) {
if (make_dynamic(ofl) == S_ERROR)
return (S_ERROR);
if (!(flags & FLG_OF_RELOBJ)) {
if (make_hash(ofl) == S_ERROR)
return (S_ERROR);
if (make_dynstr(ofl) == S_ERROR)
return (S_ERROR);
if (make_dynsym(ofl) == S_ERROR)
return (S_ERROR);
if (ld_unwind_make_hdr(ofl) == S_ERROR)
return (S_ERROR);
if (make_dynsort(ofl) == S_ERROR)
return (S_ERROR);
}
}
if (!(flags & FLG_OF_STRIP) || (flags & FLG_OF_RELOBJ) ||
((flags & FLG_OF_STATIC) && ofl->ofl_osversym)) {
if (ofl->ofl_osdynsym &&
((ofl->ofl_shdrcnt + 3) >= SHN_LORESERVE)) {
if (make_dynsym_shndx(ofl) == S_ERROR)
return (S_ERROR);
}
if (make_strtab(ofl) == S_ERROR)
return (S_ERROR);
if (make_symtab(ofl) == S_ERROR)
return (S_ERROR);
} else {
if (ofl->ofl_osdynsym &&
((ofl->ofl_shdrcnt + 1) >= SHN_LORESERVE)) {
if (make_dynsym_shndx(ofl) == S_ERROR)
return (S_ERROR);
}
}
if (make_shstrtab(ofl) == S_ERROR)
return (S_ERROR);
if (ofl->ofl_osversym || ofl->ofl_ossyminfo) {
ulong_t cnt;
Is_desc *isp;
Os_desc *osp;
if (OFL_IS_STATIC_OBJ(ofl))
osp = ofl->ofl_ossymtab;
else
osp = ofl->ofl_osdynsym;
isp = ld_os_first_isdesc(osp);
cnt = (isp->is_shdr->sh_size / isp->is_shdr->sh_entsize);
if (ofl->ofl_osversym)
update_data_size(ofl->ofl_osversym, cnt);
if (ofl->ofl_ossyminfo)
update_data_size(ofl->ofl_ossyminfo, cnt);
}
if (ofl->ofl_oscapinfo) {
ulong_t cnt;
if (OFL_IS_STATIC_OBJ(ofl))
cnt = SYMTAB_ALL_CNT(ofl);
else
cnt = DYNSYM_ALL_CNT(ofl);
update_data_size(ofl->ofl_oscapinfo, cnt);
}
return (1);
}
Is_desc *
ld_make_data(Ofl_desc *ofl, size_t size)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_DATA), 0,
&isec, &shdr, &data) == S_ERROR)
return ((Is_desc *)S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
shdr->sh_flags |= SHF_WRITE;
if (aplist_append(&ofl->ofl_mapdata, isec, AL_CNT_OFL_MAPSECS) == NULL)
return ((Is_desc *)S_ERROR);
return (isec);
}
Is_desc *
ld_make_text(Ofl_desc *ofl, size_t size)
{
Shdr *shdr;
Elf_Data *data;
Is_desc *isec;
if (size < ld_targ.t_nf.nf_size)
size = ld_targ.t_nf.nf_size;
if (new_section(ofl, SHT_PROGBITS, MSG_ORIG(MSG_SCN_TEXT), 0,
&isec, &shdr, &data) == S_ERROR)
return ((Is_desc *)S_ERROR);
data->d_size = size;
shdr->sh_size = (Xword)size;
shdr->sh_flags |= SHF_EXECINSTR;
if ((data->d_buf = libld_calloc(size, 1)) == NULL)
return ((Is_desc *)S_ERROR);
(void) memcpy(data->d_buf, ld_targ.t_nf.nf_template,
ld_targ.t_nf.nf_size);
if ((ld_targ.t_ff.ff_execfill != NULL) && (size > ld_targ.t_nf.nf_size))
ld_targ.t_ff.ff_execfill(data->d_buf, ld_targ.t_nf.nf_size,
size - ld_targ.t_nf.nf_size);
if (aplist_append(&ofl->ofl_maptext, isec, AL_CNT_OFL_MAPSECS) == NULL)
return ((Is_desc *)S_ERROR);
return (isec);
}
void
ld_comdat_validate(Ofl_desc *ofl, Ifl_desc *ifl)
{
int i;
for (i = 0; i < ifl->ifl_shnum; i++) {
Is_desc *isp = ifl->ifl_isdesc[i];
int types = 0;
char buf[1024] = "";
Group_desc *gr = NULL;
if ((isp == NULL) || (isp->is_flags & FLG_IS_COMDAT) == 0)
continue;
if (isp->is_shdr->sh_type == SHT_SUNW_COMDAT) {
types++;
(void) strlcpy(buf, MSG_ORIG(MSG_STR_SUNW_COMDAT),
sizeof (buf));
}
if (strncmp(MSG_ORIG(MSG_SCN_GNU_LINKONCE), isp->is_name,
MSG_SCN_GNU_LINKONCE_SIZE) == 0) {
types++;
if (types > 1)
(void) strlcat(buf, ", ", sizeof (buf));
(void) strlcat(buf, MSG_ORIG(MSG_SCN_GNU_LINKONCE),
sizeof (buf));
}
if ((isp->is_shdr->sh_flags & SHF_GROUP) &&
((gr = ld_get_group(ofl, isp)) != NULL) &&
(gr->gd_data[0] & GRP_COMDAT)) {
types++;
if (types > 1)
(void) strlcat(buf, ", ", sizeof (buf));
(void) strlcat(buf, MSG_ORIG(MSG_STR_GROUP),
sizeof (buf));
}
if (types > 1)
ld_eprintf(ofl, ERR_FATAL,
MSG_INTL(MSG_SCN_MULTICOMDAT), ifl->ifl_name,
EC_WORD(isp->is_scnndx), isp->is_name, buf);
}
}