/* * Initialize archive member */ Elf * _elf_member(int fd, Elf * ref, unsigned flags) { register Elf *elf; Member *mh; size_t base; if (ref->ed_nextoff >= ref->ed_fsz) return (0); if (ref->ed_fd == -1) /* disabled */ fd = -1; if (flags & EDF_WRITE) { _elf_seterr(EREQ_ARRDWR, 0); return (0); } if (ref->ed_fd != fd) { _elf_seterr(EREQ_ARMEMFD, 0); return (0); } if ((_elf_vm(ref, ref->ed_nextoff, sizeof (struct ar_hdr)) != OK_YES) || ((mh = _elf_armem(ref, ref->ed_ident + ref->ed_nextoff, ref->ed_fsz)) == 0)) return (0); base = ref->ed_nextoff + sizeof (struct ar_hdr); if (ref->ed_fsz - base < mh->m_hdr.ar_size) { _elf_seterr(EFMT_ARMEMSZ, 0); return (0); } if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } ++ref->ed_activ; elf->ed_parent = ref; elf->ed_fd = fd; elf->ed_myflags |= flags; elf->ed_armem = mh; elf->ed_fsz = mh->m_hdr.ar_size; elf->ed_baseoff = ref->ed_baseoff + base; elf->ed_memoff = base - mh->m_slide; elf->ed_siboff = base + elf->ed_fsz + (elf->ed_fsz & 1); ref->ed_nextoff = elf->ed_siboff; elf->ed_image = ref->ed_image; elf->ed_imagesz = ref->ed_imagesz; elf->ed_vm = ref->ed_vm; elf->ed_vmsz = ref->ed_vmsz; elf->ed_ident = ref->ed_ident + base - mh->m_slide; /* * If this member is the archive string table, * we've already altered the bytes. */ if (ref->ed_arstroff == ref->ed_nextoff) elf->ed_status = ES_COOKED; return (elf); }
Elf_Arsym * elf_getarsym(Elf *elf, size_t *ptr) { Byte *as; size_t sz; Elf_Arsym *rc; int is64; if (ptr != 0) *ptr = 0; if (elf == NULL) return (0); ELFRLOCK(elf); if (elf->ed_kind != ELF_K_AR) { ELFUNLOCK(elf); _elf_seterr(EREQ_AR, 0); return (0); } if ((as = (Byte *)elf->ed_arsym) == 0) { ELFUNLOCK(elf); return (0); } if (elf->ed_myflags & EDF_ASALLOC) { if (ptr != 0) *ptr = elf->ed_arsymsz; ELFUNLOCK(elf); /* LINTED */ return ((Elf_Arsym *)as); } is64 = (elf->ed_myflags & EDF_ARSYM64) != 0; /* * We're gonna need a write lock. */ ELFUNLOCK(elf) ELFWLOCK(elf) sz = elf->ed_arsymsz; if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) != OK_YES) { ELFUNLOCK(elf); return (0); } if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz, is64)) == 0) { ELFUNLOCK(elf); return (0); } elf->ed_myflags |= EDF_ASALLOC; if (ptr != 0) *ptr = elf->ed_arsymsz; rc = (Elf_Arsym *)elf->ed_arsym; ELFUNLOCK(elf); return (rc); }
int _elf_slide(Elf * elf) { NOTE(ASSUMING_PROTECTED(*elf)) Elf *par = elf->ed_parent; size_t sz, szof; register char *dst; register char *src = elf->ed_ident; if (par == 0 || par->ed_kind != ELF_K_AR) return (0); /* * This code relies on other code to ensure * the ar_hdr is big enough to move into. */ if (elf->ed_ident[EI_CLASS] == ELFCLASS64) szof = sizeof (Elf64); else szof = sizeof (Elf32); if ((sz = (size_t)(src - (char *)elf->ed_image) % szof) == 0) return (0); dst = src - sz; elf->ed_ident -= sz; elf->ed_memoff -= sz; elf->ed_armem->m_slide = sz; if (_elf_vm(par, elf->ed_memoff, sz + elf->ed_fsz) != OK_YES) return (-1); /* * If the archive has been mmaped in, and we're going to slide it, * and it wasn't open for write in the first place, and we've never * done the mprotect() operation before, then do it now. */ if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && ((elf->ed_myflags & EDF_MPROTECT) == 0)) { if (mprotect((char *)elf->ed_image, elf->ed_imagesz, PROT_READ|PROT_WRITE) == -1) { _elf_seterr(EIO_VM, errno); return (-1); } elf->ed_myflags |= EDF_MPROTECT; } if (memmove((void *)dst, (const void *)src, elf->ed_fsz) != (void *)dst) return (-1); else return (0); }
char * elf_rawfile(Elf * elf, size_t * ptr) { register size_t sz; char *p = 0; if (elf == 0) { if (ptr != 0) *ptr = 0; return (0); } ELFWLOCK(elf) if ((sz = elf->ed_fsz) == 0) { if (ptr != 0) *ptr = 0; ELFUNLOCK(elf) return (0); } if (elf->ed_raw != 0) p = elf->ed_raw; else if (elf->ed_status == ES_COOKED) { if ((p = _elf_read(elf->ed_fd, elf->ed_baseoff, sz)) != 0) { elf->ed_raw = p; elf->ed_myflags |= EDF_RAWALLOC; } else sz = 0; } else { p = elf->ed_raw = elf->ed_ident; elf->ed_status = ES_FROZEN; if (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES) { p = 0; sz = 0; } } if (ptr != 0) *ptr = sz; ELFUNLOCK(elf) return (p); }
Elf * _elf_config(Elf * elf) { char * base; unsigned encode; ELFRWLOCKINIT(&elf->ed_rwlock); /* * Determine if this is a ELF file. */ base = elf->ed_ident; if ((elf->ed_fsz >= EI_NIDENT) && (_elf_vm(elf, (size_t)0, (size_t)EI_NIDENT) == OK_YES) && (base[EI_MAG0] == ELFMAG0) && (base[EI_MAG1] == ELFMAG1) && (base[EI_MAG2] == ELFMAG2) && (base[EI_MAG3] == ELFMAG3)) { elf->ed_kind = ELF_K_ELF; elf->ed_class = base[EI_CLASS]; elf->ed_encode = base[EI_DATA]; if ((elf->ed_version = base[EI_VERSION]) == 0) elf->ed_version = 1; elf->ed_identsz = EI_NIDENT; /* * Allow writing only if originally specified read only. * This is only necessary if the file must be translating * from one encoding to another. */ ELFACCESSDATA(encode, _elf_encode) if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && (elf->ed_encode != encode)) { if (mprotect((char *)elf->ed_image, elf->ed_imagesz, PROT_READ|PROT_WRITE) == -1) { _elf_seterr(EIO_VM, errno); return (0); } } return (elf); }
static size_t wrt(Elf * elf, Xword outsz, unsigned fill, int update_cmd) { NOTE(ASSUMING_PROTECTED(*elf)) Elf_Data dst, src; unsigned flag; Xword hi, sz; char *image; Elf_Scn *s; Ehdr *eh = elf->ed_ehdr; unsigned ver = eh->e_version; unsigned encode; int byte; /* * If this is an ELF_C_WRIMAGE write, then we encode into the * byte order of the system we are running on rather than that of * of the object. For ld.so.1, this is the same order, but * for 'ld', it might not be in the case where we are cross * linking an object for a different target. In this later case, * the linker-host byte order is necessary so that the linker can * manipulate the resulting image. It is expected that the linker * will call elf_swap_wrimage() if necessary to convert the image * to the target byte order. */ encode = (update_cmd == ELF_C_WRIMAGE) ? _elf_sys_encoding() : eh->e_ident[EI_DATA]; /* * Two issues can cause trouble for the output file. * First, begin() with ELF_C_RDWR opens a file for both * read and write. On the write update(), the library * has to read everything it needs before truncating * the file. Second, using mmap for both read and write * is too tricky. Consequently, the library disables mmap * on the read side. Using mmap for the output saves swap * space, because that mapping is SHARED, not PRIVATE. * * If the file is write-only, there can be nothing of * interest to bother with. * * The following reads the entire file, which might be * more than necessary. Better safe than sorry. */ if ((elf->ed_myflags & EDF_READ) && (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES)) return (0); flag = elf->ed_myflags & EDF_WRALLOC; if ((image = _elf_outmap(elf->ed_fd, outsz, &flag)) == 0) return (0); if (flag == 0) elf->ed_myflags |= EDF_IMALLOC; /* * If an error occurs below, a "dirty" bit may be cleared * improperly. To save a second pass through the file, * this code sets the dirty bit on the elf descriptor * when an error happens, assuming that will "cover" any * accidents. */ /* * Hi is needed only when 'fill' is non-zero. * Fill is non-zero only when the library * calculates file/section/data buffer offsets. * The lib guarantees they increase monotonically. * That guarantees proper filling below. */ /* * Ehdr first */ src.d_buf = (Elf_Void *)eh; src.d_type = ELF_T_EHDR; src.d_size = sizeof (Ehdr); src.d_version = EV_CURRENT; dst.d_buf = (Elf_Void *)image; dst.d_size = eh->e_ehsize; dst.d_version = ver; if (elf_xlatetof(&dst, &src, encode) == 0) return (0); elf->ed_ehflags &= ~ELF_F_DIRTY; hi = eh->e_ehsize; /* * Phdr table if one exists */ if (eh->e_phnum != 0) { unsigned work; /* * Unlike other library data, phdr table is * in the user version. Change src buffer * version here, fix it after translation. */ src.d_buf = (Elf_Void *)elf->ed_phdr; src.d_type = ELF_T_PHDR; src.d_size = elf->ed_phdrsz; ELFACCESSDATA(work, _elf_work) src.d_version = work; dst.d_buf = (Elf_Void *)(image + eh->e_phoff); dst.d_size = eh->e_phnum * eh->e_phentsize; hi = (Xword)(eh->e_phoff + dst.d_size); if (elf_xlatetof(&dst, &src, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } elf->ed_phflags &= ~ELF_F_DIRTY; src.d_version = EV_CURRENT; } /* * Loop through sections */ ELFACCESSDATA(byte, _elf_byte); for (s = elf->ed_hdscn; s != 0; s = s->s_next) { register Dnode *d, *prevd; Xword off = 0; Shdr *sh = s->s_shdr; char *start = image + sh->sh_offset; char *here; /* * Just "clean" DIRTY flag for "empty" sections. Even if * NOBITS needs padding, the next thing in the * file will provide it. (And if this NOBITS is * the last thing in the file, no padding needed.) */ if ((sh->sh_type == SHT_NOBITS) || (sh->sh_type == SHT_NULL)) { d = s->s_hdnode, prevd = 0; for (; d != 0; prevd = d, d = d->db_next) d->db_uflags &= ~ELF_F_DIRTY; continue; } /* * Clear out the memory between the end of the last * section and the begining of this section. */ if (fill && (sh->sh_offset > hi)) { sz = sh->sh_offset - hi; (void) memset(start - sz, byte, sz); } for (d = s->s_hdnode, prevd = 0; d != 0; prevd = d, d = d->db_next) { d->db_uflags &= ~ELF_F_DIRTY; here = start + d->db_data.d_off; /* * Clear out the memory between the end of the * last update and the start of this data buffer. */ if (fill && (d->db_data.d_off > off)) { sz = (Xword)(d->db_data.d_off - off); (void) memset(here - sz, byte, sz); } if ((d->db_myflags & DBF_READY) == 0) { SCNLOCK(s); if (_elf_locked_getdata(s, &prevd->db_data) != &d->db_data) { elf->ed_uflags |= ELF_F_DIRTY; SCNUNLOCK(s); return (0); } SCNUNLOCK(s); } dst.d_buf = (Elf_Void *)here; dst.d_size = d->db_osz; /* * Copy the translated bits out to the destination * image. */ if (elf_xlatetof(&dst, &d->db_data, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } off = (Xword)(d->db_data.d_off + dst.d_size); } hi = sh->sh_offset + sh->sh_size; } /* * Shdr table last */ if (fill && (eh->e_shoff > hi)) { sz = eh->e_shoff - hi; (void) memset(image + hi, byte, sz); } src.d_type = ELF_T_SHDR; src.d_size = sizeof (Shdr); dst.d_buf = (Elf_Void *)(image + eh->e_shoff); dst.d_size = eh->e_shentsize; for (s = elf->ed_hdscn; s != 0; s = s->s_next) { assert((uintptr_t)dst.d_buf < ((uintptr_t)image + outsz)); s->s_shflags &= ~ELF_F_DIRTY; s->s_uflags &= ~ELF_F_DIRTY; src.d_buf = s->s_shdr; if (elf_xlatetof(&dst, &src, encode) == 0) { elf->ed_uflags |= ELF_F_DIRTY; return (0); } dst.d_buf = (char *)dst.d_buf + eh->e_shentsize; } /* * ELF_C_WRIMAGE signifyes that we build the memory image, but * that we do not actually write it to disk. This is used * by ld(1) to build up a full image of an elf file and then * to process the file before it's actually written out to * disk. This saves ld(1) the overhead of having to write * the image out to disk twice. */ if (update_cmd == ELF_C_WRIMAGE) { elf->ed_uflags &= ~ELF_F_DIRTY; elf->ed_wrimage = image; elf->ed_wrimagesz = outsz; return (outsz); } if (_elf_outsync(elf->ed_fd, image, outsz, ((elf->ed_myflags & EDF_IMALLOC) ? 0 : 1)) != 0) { elf->ed_uflags &= ~ELF_F_DIRTY; elf->ed_myflags &= ~EDF_IMALLOC; return (outsz); } elf->ed_uflags |= ELF_F_DIRTY; return (0); }
/* * Initial archive processing * An archive may have two special members. * * A symbol table, named / or /SYM64/, must be first if it is present. * Both forms use the same layout differing in the width of the * integer type used (32 or 64-bit respectively). * * A long name string table, named //, must precede all "normal" * members. This string table is used to hold the names of archive * members with names that are longer than 15 characters. It should not * be confused with the string table found at the end of the symbol * table, which is used to hold symbol names. * * This code "peeks" at headers but doesn't change them. * Later processing wants original headers. * * String table is converted, changing '/' name terminators * to nulls. The last byte in the string table, which should * be '\n', is set to nil, guaranteeing null termination. That * byte should be '\n', but this code doesn't check. * * The symbol table conversion is delayed until needed. */ void _elf_arinit(Elf * elf) { char *base = elf->ed_ident; register char *end = base + elf->ed_fsz; register struct ar_hdr *a; register char *hdr = base + SARMAG; register char *mem; int j; size_t sz = SARMAG; elf->ed_status = ES_COOKED; elf->ed_nextoff = SARMAG; for (j = 0; j < 2; ++j) { /* 2 special members */ unsigned long n; if (((end - hdr) < sizeof (struct ar_hdr)) || (_elf_vm(elf, (size_t)(SARMAG), sizeof (struct ar_hdr)) != OK_YES)) return; a = (struct ar_hdr *)hdr; mem = (char *)a + sizeof (struct ar_hdr); n = _elf_number(a->ar_size, &a->ar_size[ARSZ(ar_size)], 10); if ((end - mem < n) || (a->ar_name[0] != '/') || ((sz = n) != n)) { return; } hdr = mem + sz; if (a->ar_name[1] == ' ') { /* 32-bit symbol table */ elf->ed_arsym = mem; elf->ed_arsymsz = sz; elf->ed_arsymoff = (char *)a - base; } else if (a->ar_name[1] == '/' && a->ar_name[2] == ' ') { /* Long name string table */ int k; if (_elf_vm(elf, (size_t)(mem - elf->ed_ident), sz) != OK_YES) return; if (elf->ed_vm == 0) { char *nmem; if ((nmem = malloc(sz)) == 0) { _elf_seterr(EMEM_ARSTR, errno); return; } (void) memcpy(nmem, mem, sz); elf->ed_myflags |= EDF_ASTRALLOC; mem = nmem; } elf->ed_arstr = mem; elf->ed_arstrsz = sz; elf->ed_arstroff = (char *)a - base; for (k = 0; k < sz; k++) { if (*mem == '/') *mem = '\0'; ++mem; } *(mem - 1) = '\0'; } else if (a->ar_name[1] == 'S' && a->ar_name[2] == 'Y' && a->ar_name[3] == 'M' && a->ar_name[4] == '6' && a->ar_name[5] == '4' && a->ar_name[6] == '/' && a->ar_name[7] == ' ') { /* 64-bit symbol table */ elf->ed_arsym = mem; elf->ed_arsymsz = sz; elf->ed_arsymoff = (char *)a - base; elf->ed_myflags |= EDF_ARSYM64; } else { return; } hdr += sz & 1; } }