/* * Create an archive descriptor. By maintaining a list of archives any * duplicate occurrences of the same archive specified by the user enable us to * pick off where the last processing finished. */ Ar_desc * ld_ar_setup(const char *name, Elf *elf, Ofl_desc *ofl) { Ar_desc * adp; size_t number; Elf_Arsym * start; /* * Unless, -z allextract is specified, get the archive symbol table * if one exists, and ignore the file with a warning message otherwise. */ if (ofl->ofl_flags1 & FLG_OF1_ALLEXRT) { start = NULL; } else if ((start = elf_getarsym(elf, &number)) == NULL) { if (elf_errno()) ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETARSYM), name); else ld_eprintf(ofl, ERR_WARNING, MSG_INTL(MSG_ELF_ARSYM), name); return (0); } /* * As this is a new archive reference establish a new descriptor. */ if ((adp = libld_malloc(sizeof (Ar_desc))) == NULL) return ((Ar_desc *)S_ERROR); adp->ad_name = name; adp->ad_elf = elf; adp->ad_start = start; if (start) { adp->ad_aux = libld_calloc(sizeof (Ar_aux), number); if (adp->ad_aux == NULL) return ((Ar_desc *)S_ERROR); } else { adp->ad_aux = NULL; } /* * Retain any command line options that are applicable to archive * extraction in case we have to rescan this archive later. */ adp->ad_flags = ofl->ofl_flags1 & MSK_OF1_ARCHIVE; ofl->ofl_arscnt++; /* * Add this new descriptor to the list of archives. */ if (aplist_append(&ofl->ofl_ars, adp, AL_CNT_OFL_LIBS) == NULL) return ((Ar_desc *)S_ERROR); else return (adp); }
/* * Construct the member's full pathname, using the format "%s(%s)". * * entry: * name - Name of archive * arname - Name of archive member * exit: * Returns pointer to constructed pathname on success, NULL on error. */ static const char * ar_member_path(const char *name, const char *arname) { size_t len; char *path; len = strlen(name) + strlen(arname) + 3; if ((path = libld_malloc(len)) == NULL) return (NULL); (void) snprintf(path, len, MSG_ORIG(MSG_FMT_ARMEM), name, arname); return (path); }
/* * Initialize new entrance and segment descriptors and add them as lists to * the output file descriptor. */ uintptr_t ld_ent_setup(Ofl_desc *ofl, Elf64_Xword segalign) { Ent_desc *enp; predef_seg_t *psegs; Sg_desc *sgp; size_t idx; /* * Initialize the elf library. */ if (elf_version(EV_CURRENT) == EV_NONE) { ld_eprintf(ofl, ERR_FATAL, MSG_ELF_LIBELF, EV_CURRENT); return (S_ERROR); } /* * Initialize internal Global Symbol Table AVL tree */ avl_create(&ofl->ofl_symavl, &ld_sym_avl_comp, sizeof (Sym_avlnode), SGSOFFSETOF(Sym_avlnode, sav_node)); /* Initialize segment AVL tree */ avl_create(&ofl->ofl_segs_avl, ofl_segs_avl_cmp, sizeof (Sg_desc), SGSOFFSETOF(Sg_desc, sg_avlnode)); /* Initialize entrance criteria AVL tree */ avl_create(&ofl->ofl_ents_avl, ofl_ents_avl_cmp, sizeof (Ent_desc), SGSOFFSETOF(Ent_desc, ec_avlnode)); /* * Allocate and initialize writable copies of both the entrance and * segment descriptors. * * Note that on non-amd64 targets, this allocates a few more * elements than are needed. For now, we are willing to overallocate * a small amount to simplify the code. */ if ((psegs = libld_malloc(sizeof (sg_desc))) == NULL) return (S_ERROR); (void) memcpy(psegs, &sg_desc, sizeof (sg_desc)); sgp = (Sg_desc *) psegs; /* * The data segment and stack permissions can differ: * * - Architectural/ABI per-platform differences * - Whether the object is built statically or dynamically * * Those segments so affected have their program header flags * set here at runtime, rather than in the sg_desc templates above. */ psegs->psg_data.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm; psegs->psg_bss.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm; psegs->psg_dynamic.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm; psegs->psg_sunwdtrace.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm; #if defined(_ELF64) psegs->psg_ldata.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm; psegs->psg_sunwdtrace.sg_phdr.p_flags |= PF_X; #endif psegs->psg_sunwstack.sg_phdr.p_flags = ld_targ.t_m.m_stack_perm; if ((ofl->ofl_flags & FLG_OF_DYNAMIC) == 0) psegs->psg_data.sg_phdr.p_flags |= PF_X; /* * Traverse the new entrance descriptor list converting the segment * pointer entries to the absolute address within the new segment * descriptor list. Add each entrance descriptor to the output file * list. */ if ((enp = libld_malloc(sizeof (ent_desc))) == NULL) return (S_ERROR); (void) memcpy(enp, ent_desc, sizeof (ent_desc)); for (idx = 0; idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++, enp++) { #if defined(_ELF64) /* Don't use the amd64 entry conditions for non-amd64 targets */ if ((enp->ec_attrmask & SHF_X86_64_LARGE) && (ld_targ.t_m.m_mach != EM_X86_64)) continue; #endif if (aplist_append(&ofl->ofl_ents, enp, AL_CNT_OFL_ENTRANCE) == NULL) return (S_ERROR); /* * The segment pointer is currently pointing at a template * segment descriptor in sg_desc. Compute its array index, * and then use that index to compute the address of the * corresponding descriptor in the writable copy. */ enp->ec_segment = &sgp[(enp->ec_segment - (Sg_desc *) &sg_desc)]; } /* * Add each segment descriptor to the segment descriptor list. The * ones with non-NULL sg_name are also entered into the AVL tree. * For each loadable segment initialize a default alignment. Note * that ld(1) and ld.so.1 initialize this differently. */ for (idx = 0; idx < predef_seg_nelts; idx++, sgp++) { Elf64_Phdr *phdr = &(sgp->sg_phdr); /* Ignore amd64 segment templates for non-amd64 targets */ switch (sgp->sg_id) { case SGID_LRODATA: case SGID_LDATA: if ((ld_targ.t_m.m_mach != EM_X86_64)) continue; } if (phdr->p_type == PT_LOAD) phdr->p_align = segalign; if ((aplist_append(&ofl->ofl_segs, sgp, AL_CNT_SEGMENTS)) == NULL) return (S_ERROR); #ifdef NDEBUG /* assert() is enabled */ /* * Enforce the segment name rule: Any segment that can * be referenced by an entrance descriptor must have * a name. Any segment that cannot, must have a NULL * name pointer. */ switch (phdr->p_type) { case PT_LOAD: case PT_NOTE: case PT_NULL: assert(sgp->sg_name != NULL); break; default: assert(sgp->sg_name == NULL); break; } #endif /* * Add named segment descriptors to the AVL tree to * provide O(logN) lookups. */ if (sgp->sg_name != NULL) avl_add(&ofl->ofl_segs_avl, sgp); } return (1); }