char * elf_strptr(Elf * elf, size_t ndx, size_t off) { Elf_Scn * s; Elf_Data * d; char * rc; if (elf == 0) return (0); extern const char *elf_macho_str_off(size_t off); if (elf->ed_kind == ELF_K_MACHO && (ndx == SHN_MACHO || ndx == SHN_MACHO_64)) return (char *)elf_macho_str_off(off); if ((s = elf_getscn(elf, ndx)) == 0) { _elf_seterr(EREQ_STRSCN, 0); return (0); } READLOCKS(elf, s) if (elf->ed_class == ELFCLASS32) { Elf32_Shdr* sh = (Elf32_Shdr*)s->s_shdr; if ((sh == 0) || (sh->sh_type != SHT_STRTAB)) { _elf_seterr(EREQ_STRSCN, 0); READUNLOCKS(elf, s) return (0); }
size_t _elf_outsync(int fd, char *p, size_t sz, unsigned int flag) { if (flag != 0) { int err; /* * The value of MS_SYNC changed from zero to non-zero * in SunOS 5.7. This double call covers both cases. */ if ((fd = msync(p, sz, MS_SYNC)) == -1) fd = msync(p, sz, 0); if (fd == -1) err = errno; (void) munmap(p, sz); if (fd == 0) return (sz); _elf_seterr(EIO_SYNC, err); return (0); } if ((lseek(fd, 0L, SEEK_SET) == 0) && (write(fd, p, sz) == sz) && (fsync(fd) == 0)) { (void) free(p); return (sz); } _elf_seterr(EIO_WRITE, errno); return (0); }
off_t _elfxx_update(Elf * elf, Elf_Cmd cmd) { size_t sz; unsigned u; Ehdr *eh = elf->ed_ehdr; if (elf == 0) return (-1); ELFWLOCK(elf) switch (cmd) { default: _elf_seterr(EREQ_UPDATE, 0); ELFUNLOCK(elf) return (-1); case ELF_C_WRIMAGE: if ((elf->ed_myflags & EDF_WRITE) == 0) { _elf_seterr(EREQ_UPDWRT, 0); ELFUNLOCK(elf) return (-1); } break; case ELF_C_WRITE: if ((elf->ed_myflags & EDF_WRITE) == 0) { _elf_seterr(EREQ_UPDWRT, 0); ELFUNLOCK(elf) return (-1); }
char * _elf_read(int fd, off_t off, size_t fsz) { char *p; if (fsz == 0) return (0); if (fd == -1) { _elf_seterr(EREQ_NOFD, 0); return (0); } if (lseek(fd, off, 0) != off) { _elf_seterr(EIO_SEEK, errno); return (0); } if ((p = (char *)malloc(fsz)) == 0) { _elf_seterr(EMEM_DATA, errno); return (0); } if (read(fd, p, fsz) != fsz) { _elf_seterr(EIO_READ, errno); free(p); return (0); } return (p); }
/* * 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); }
char * _elf_outmap(int fd, size_t sz, unsigned int *pflag) { char *p; /* * Note: Some NFS implementations do not provide from enlarging a file * via ftruncate(), thus this may fail with ENOSUP. In this case the * fall through to the calloc() mechanism will occur. */ if ((!*pflag) && (ftruncate(fd, (off_t)sz) == 0) && (p = mmap((char *)0, sz, PROT_READ+PROT_WRITE, MAP_SHARED, fd, (off_t)0)) != (char *)-1) { *pflag = 1; return (p); } *pflag = 0; /* * If mmap fails, try calloc. Some file systems don't mmap. Note, we * use calloc rather than malloc, as ld(1) assumes that the backing * storage it is working with is zero filled. */ if ((p = (char *)calloc(1, sz)) == 0) _elf_seterr(EMEM_OUT, errno); return (p); }
/* * Handle the decision of whether the current linker can handle the * desired object size, and if not, which error to issue. * * Input is the desired size. On failure, an error has been issued * and 0 is returned. On success, 1 is returned. */ static int test_size(Lword hi) { #ifndef _LP64 /* 32-bit linker */ /* * A 32-bit libelf is limited to a 2GB output file. This limit * is due to the fact that off_t is a signed value, and that * libelf cannot support large file support: * - ABI reasons * - Memory use generally is 2x output file size anyway, * so lifting the file size limit will just send * you crashing into the 32-bit VM limit. * If the output is an ELFCLASS64 object, or an ELFCLASS32 object * under 4GB, switching to the 64-bit version of libelf will help. * However, an ELFCLASS32 object must not exceed 4GB. */ if (hi > INT_MAX) { /* Bigger than 2GB */ #ifndef _ELF64 /* ELFCLASS32 object is fundamentally too big? */ if (hi > UINT_MAX) { _elf_seterr(EFMT_FBIG_CLASS32, 0); return (0); } #endif /* _ELF64 */ /* Should switch to the 64-bit libelf? */ _elf_seterr(EFMT_FBIG_LARGEFILE, 0); return (0); } #endif /* !_LP64 */ #if defined(_LP64) && !defined(_ELF64) /* 64-bit linker, ELFCLASS32 */ /* * A 64-bit linker can produce any size output * file, but if the resulting file is ELFCLASS32, * it must not exceed 4GB. */ if (hi > UINT_MAX) { _elf_seterr(EFMT_FBIG_CLASS32, 0); return (0); } #endif return (1); }
size_t elf_rand(Elf * elf, size_t off) { if (elf == 0) return (0); ELFWLOCK(elf) if (elf->ed_kind != ELF_K_AR) { _elf_seterr(EREQ_AR, 0); ELFUNLOCK(elf) return (0); }
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); }
Dnode * _elf_dnode() { register Dnode *d; if ((d = (Dnode *)malloc(sizeof (Dnode))) == 0) { _elf_seterr(EMEM_DNODE, errno); return (0); } NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d)) *d = _elf_dnode_init; d->db_myflags = DBF_ALLOC; NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d)) return (d); }
Phdr * elf_newphdr(Elf * elf, size_t count) { Elf_Void * ph; size_t sz; Phdr * rc; unsigned work; if (elf == 0) return (0); ELFRLOCK(elf) if (elf->ed_class != ELFCLASS) { _elf_seterr(EREQ_CLASS, 0); ELFUNLOCK(elf) return (0); }
Elf * _elf_regular(int fd, unsigned flags) /* initialize regular file */ { Elf *elf; if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { _elf_seterr(EMEM_ELF, errno); return (0); } NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf)) elf->ed_fd = fd; elf->ed_myflags |= flags; if (_elf_inmap(elf) != OK_YES) { free(elf); return (0); } NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf)) return (elf); }
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); }
/* * Convert ar_hdr to Member * Converts ascii file representation to the binary memory values. */ Member * _elf_armem(Elf *elf, char *file, size_t fsz) { register struct ar_hdr *f = (struct ar_hdr *)file; register Member *m; register Memlist *l, * ol; register Memident *i; if (fsz < sizeof (struct ar_hdr)) { _elf_seterr(EFMT_ARHDRSZ, 0); return (0); } /* * Determine in this member has already been processed */ for (l = elf->ed_memlist, ol = l; l; ol = l, l = l->m_next) for (i = (Memident *)(l + 1); i < l->m_free; i++) if (i->m_offset == file) return (i->m_member); if (f->ar_fmag[0] != fmag[0] || f->ar_fmag[1] != fmag[1]) { _elf_seterr(EFMT_ARFMAG, 0); return (0); } /* * Allocate a new member structure and assign it to the next free * free memlist ident. */ if ((m = (Member *)malloc(sizeof (Member))) == 0) { _elf_seterr(EMEM_ARMEM, errno); return (0); } if ((elf->ed_memlist == 0) || (ol->m_free == ol->m_end)) { if ((l = (Memlist *)malloc(sizeof (Memlist) + (sizeof (Memident) * MEMIDENTNO))) == 0) { _elf_seterr(EMEM_ARMEM, errno); return (0); } l->m_next = 0; l->m_free = (Memident *)(l + 1); l->m_end = (Memident *)((uintptr_t)l->m_free + (sizeof (Memident) * MEMIDENTNO)); if (elf->ed_memlist == 0) elf->ed_memlist = l; else ol->m_next = l; ol = l; } ol->m_free->m_offset = file; ol->m_free->m_member = m; ol->m_free++; m->m_err = 0; (void) memcpy(m->m_name, f->ar_name, ARSZ(ar_name)); m->m_name[ARSZ(ar_name)] = '\0'; m->m_hdr.ar_name = m->m_name; (void) memcpy(m->m_raw, f->ar_name, ARSZ(ar_name)); m->m_raw[ARSZ(ar_name)] = '\0'; m->m_hdr.ar_rawname = m->m_raw; m->m_slide = 0; /* * Classify file name. * If a name error occurs, delay until getarhdr(). */ if (f->ar_name[0] != '/') { /* regular name */ register char *p; p = &m->m_name[sizeof (m->m_name)]; while (*--p != '/') if (p <= m->m_name) break; *p = '\0'; } else if (f->ar_name[1] >= '0' && f->ar_name[1] <= '9') { /* strtab */ register unsigned long j; j = _elf_number(&f->ar_name[1], &f->ar_name[ARSZ(ar_name)], 10); if (j < elf->ed_arstrsz) m->m_hdr.ar_name = elf->ed_arstr + j; else { m->m_hdr.ar_name = 0; /*LINTED*/ /* MSG_INTL(EFMT_ARSTRNM) */ m->m_err = (int)EFMT_ARSTRNM; } } else if (f->ar_name[1] == ' ') /* "/" */ m->m_name[1] = '\0'; else if (f->ar_name[1] == '/' && f->ar_name[2] == ' ') /* "//" */ m->m_name[2] = '\0'; else if (f->ar_name[1] == 'S' && f->ar_name[2] == 'Y' && f->ar_name[3] == 'M' && f->ar_name[4] == '6' && f->ar_name[5] == '4' && f->ar_name[6] == '/' && f->ar_name[7] == ' ') /* "/SYM64/" */ m->m_name[7] = '\0'; else { /* "/?" */ m->m_hdr.ar_name = 0; /*LINTED*/ /* MSG_INTL(EFMT_ARUNKNM) */ m->m_err = (int)EFMT_ARUNKNM; } m->m_hdr.ar_date = (time_t)_elf_number(f->ar_date, &f->ar_date[ARSZ(ar_date)], 10); /* LINTED */ m->m_hdr.ar_uid = (uid_t)_elf_number(f->ar_uid, &f->ar_uid[ARSZ(ar_uid)], 10); /* LINTED */ m->m_hdr.ar_gid = (gid_t)_elf_number(f->ar_gid, &f->ar_gid[ARSZ(ar_gid)], 10); /* LINTED */ m->m_hdr.ar_mode = (mode_t)_elf_number(f->ar_mode, &f->ar_mode[ARSZ(ar_mode)], 8); m->m_hdr.ar_size = (off_t)_elf_number(f->ar_size, &f->ar_size[ARSZ(ar_size)], 10); return (m); }
void _SHIM_elf_seterr(int x) { _elf_seterr( 0, x); }
static size_t _elf_upd_usr(Elf * elf) { NOTE(ASSUMING_PROTECTED(*elf)) Lword hi; Elf_Scn * s; register Lword sz; Ehdr * eh = elf->ed_ehdr; unsigned ver = eh->e_version; register char *p = (char *)eh->e_ident; /* * Ehdr and Phdr table go first */ p[EI_MAG0] = ELFMAG0; p[EI_MAG1] = ELFMAG1; p[EI_MAG2] = ELFMAG2; p[EI_MAG3] = ELFMAG3; p[EI_CLASS] = ELFCLASS; /* LINTED */ p[EI_VERSION] = (Byte)ver; hi = elf_fsize(ELF_T_EHDR, 1, ver); /* LINTED */ eh->e_ehsize = (Half)hi; /* * If phnum is zero, phoff "should" be zero too, * but the application is responsible for it. * Allow a non-zero value here and update the * hi water mark accordingly. */ if (eh->e_phnum != 0) /* LINTED */ eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); else eh->e_phentsize = 0; if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi) hi = sz; /* * Loop through sections, skipping index zero. * Compute section size before changing hi. * Allow null buffers for NOBITS. */ if ((s = elf->ed_hdscn) == 0) eh->e_shnum = 0; else { eh->e_shnum = 1; *(Shdr*)s->s_shdr = _elf_snode_init.sb_shdr; s = s->s_next; } for (; s != 0; s = s->s_next) { register Dnode *d; register Lword fsz, j; Shdr *sh = s->s_shdr; if ((s->s_myflags & SF_READY) == 0) (void) _elfxx_cookscn(s); ++eh->e_shnum; sz = 0; for (d = s->s_hdnode; d != 0; d = d->db_next) { if ((fsz = elf_fsize(d->db_data.d_type, 1, ver)) == 0) return (0); j = _elf_msize(d->db_data.d_type, ver); fsz *= (d->db_data.d_size / j); d->db_osz = (size_t)fsz; if ((sh->sh_type != SHT_NOBITS) && ((j = (d->db_data.d_off + d->db_osz)) > sz)) sz = j; } if (sh->sh_size < sz) { _elf_seterr(EFMT_SCNSZ, 0); return (0); } if ((sh->sh_type != SHT_NOBITS) && (hi < sh->sh_offset + sh->sh_size)) hi = sh->sh_offset + sh->sh_size; } /* * Shdr table last. Comment above for phnum/phoff applies here. */ if (eh->e_shnum != 0) /* LINTED */ eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); else eh->e_shentsize = 0; if ((sz = eh->e_shoff + eh->e_shentsize * eh->e_shnum) > hi) hi = sz; #ifdef TEST_SIZE if (test_size(hi) == 0) return (0); #endif return ((size_t)hi); }
static Elf_Void * arsym(Byte *off, size_t sz, size_t *e, int is64) { char *endstr = (char *)off + sz; register char *str; Byte *endoff; Elf_Void *oas; size_t eltsize = is64 ? 8 : 4; { register size_t n; if (is64) { if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (0); } } else { if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) { _elf_seterr(EFMT_ARSYMSZ, 0); return (0); } } off += eltsize; endoff = off + n * eltsize; /* * string table must be present, null terminated */ if (((str = (char *)endoff) >= endstr) || (*(endstr - 1) != '\0')) { _elf_seterr(EFMT_ARSYM, 0); return (0); } /* * overflow can occur here, but not likely */ *e = n + 1; n = sizeof (Elf_Arsym) * (n + 1); if ((oas = malloc(n)) == 0) { _elf_seterr(EMEM_ARSYM, errno); return (0); } } { register Elf_Arsym *as = (Elf_Arsym *)oas; while (off < endoff) { if (str >= endstr) { _elf_seterr(EFMT_ARSYMSTR, 0); free(oas); return (0); } if (is64) as->as_off = get8(off); else as->as_off = get4(off); as->as_name = str; as->as_hash = elf_hash(str); ++as; off += eltsize; while (*str++ != '\0') /* LINTED */ ; } as->as_name = 0; as->as_off = 0; as->as_hash = ~(unsigned long)0L; } return (oas); }
/* * 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; } }
static size_t _elf_upd_lib(Elf * elf) { NOTE(ASSUMING_PROTECTED(*elf)) Lword hi; Lword hibit; Elf_Scn * s; register Xword sz; Ehdr * eh = elf->ed_ehdr; unsigned ver = eh->e_version; register char *p = (char *)eh->e_ident; size_t scncnt; /* * Ehdr and Phdr table go first */ p[EI_MAG0] = ELFMAG0; p[EI_MAG1] = ELFMAG1; p[EI_MAG2] = ELFMAG2; p[EI_MAG3] = ELFMAG3; p[EI_CLASS] = ELFCLASS; /* LINTED */ p[EI_VERSION] = (Byte)ver; hi = elf_fsize(ELF_T_EHDR, 1, ver); /* LINTED */ eh->e_ehsize = (Half)hi; if (eh->e_phnum != 0) { /* LINTED */ eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); /* LINTED */ eh->e_phoff = (Off)hi; hi += eh->e_phentsize * eh->e_phnum; } else { eh->e_phoff = 0; eh->e_phentsize = 0; } /* * Obtain the first section header. Typically, this section has NULL * contents, however in the case of Extended ELF Sections this section * is used to hold an alternative e_shnum, e_shstrndx and e_phnum. * On initial allocation (see _elf_snode) the elements of this section * would have been zeroed. The e_shnum is initialized later, after the * section header count has been determined. The e_shstrndx and * e_phnum may have already been initialized by the caller (for example, * gelf_update_shdr() in mcs(1)). */ if ((s = elf->ed_hdscn) == 0) { eh->e_shnum = 0; scncnt = 0; } else { s = s->s_next; scncnt = 1; } /* * Loop through sections. Compute section size before changing hi. * Allow null buffers for NOBITS. */ hibit = 0; for (; s != 0; s = s->s_next) { register Dnode *d; register Lword fsz, j; Shdr *sh = s->s_shdr; scncnt++; if (sh->sh_type == SHT_NULL) { *sh = _elf_snode_init.sb_shdr; continue; } if ((s->s_myflags & SF_READY) == 0) (void) _elfxx_cookscn(s); sh->sh_addralign = 1; if ((sz = (Xword)_elf_entsz(sh->sh_type, ver)) != 0) /* LINTED */ sh->sh_entsize = (Half)sz; sz = 0; for (d = s->s_hdnode; d != 0; d = d->db_next) { if ((fsz = elf_fsize(d->db_data.d_type, 1, ver)) == 0) return (0); j = _elf_msize(d->db_data.d_type, ver); fsz *= (d->db_data.d_size / j); d->db_osz = (size_t)fsz; if ((j = d->db_data.d_align) > 1) { if (j > sh->sh_addralign) sh->sh_addralign = (Xword)j; if (sz % j != 0) sz += j - sz % j; } d->db_data.d_off = (off_t)sz; d->db_xoff = sz; sz += (Xword)fsz; } sh->sh_size = sz; /* * We want to take into account the offsets for NOBITS * sections and let the "sh_offsets" point to where * the section would 'conceptually' fit within * the file (as required by the ABI). * * But - we must also make sure that the NOBITS does * not take up any actual space in the file. We preserve * the actual offset into the file in the 'hibit' variable. * When we come to the first non-NOBITS section after a * encountering a NOBITS section the hi counter is restored * to its proper place in the file. */ if (sh->sh_type == SHT_NOBITS) { if (hibit == 0) hibit = hi; } else { if (hibit) { hi = hibit; hibit = 0; } } j = sh->sh_addralign; if ((fsz = hi % j) != 0) hi += j - fsz; /* LINTED */ sh->sh_offset = (Off)hi; hi += sz; } /* * if last section was a 'NOBITS' section then we need to * restore the 'hi' counter to point to the end of the last * non 'NOBITS' section. */ if (hibit) { hi = hibit; hibit = 0; } /* * Shdr table last */ if (scncnt != 0) { if (hi % FSZ_LONG != 0) hi += FSZ_LONG - hi % FSZ_LONG; /* LINTED */ eh->e_shoff = (Off)hi; /* * If we are using 'extended sections' then the * e_shnum is stored in the sh_size field of the * first section header. * * NOTE: we set e_shnum to '0' because it's specified * this way in the gABI, and in the hopes that * this will cause less problems to unaware * tools then if we'd set it to SHN_XINDEX (0xffff). */ if (scncnt < SHN_LORESERVE) eh->e_shnum = scncnt; else { Shdr *sh; sh = (Shdr *)elf->ed_hdscn->s_shdr; sh->sh_size = scncnt; eh->e_shnum = 0; } /* LINTED */ eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); hi += eh->e_shentsize * scncnt; } else { eh->e_shoff = 0; eh->e_shentsize = 0; } #if !(defined(_LP64) && defined(_ELF64)) if (hi > INT_MAX) { _elf_seterr(EFMT_FBIG, 0); return (0); } #endif return ((size_t)hi); }