2021-10-11 19:38:01 -03:00

320 lines
6.3 KiB
C
Executable File

/* Copyright (c) 1988 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#pragma ident "@(#)begin.c 1.8 94/08/01 SMI" /* SVr4.0 1.13 */
/*LINTLIBRARY*/
#ifdef __STDC__
#pragma weak elf_begin = _elf_begin
#pragma weak elf_memory = _elf_memory
#endif
#include "syn.h"
#include <ar.h>
#include <stdlib.h>
#include <memory.h>
#include "libelf.h"
#include "decl.h"
#include "member.h"
#include "error.h"
#include "foreign.h"
#ifdef MMAP_IS_AVAIL
#include <sys/mman.h>
#endif
static Elf *member _((int, Elf *, unsigned));
static Elf *regular _((int, unsigned));
static const Elf elf_init = { 0 };
static const char armag[] = ARMAG;
Elf *
elf_begin(fd, cmd, ref)
int fd;
Elf_Cmd cmd;
Elf *ref;
{
register Elf *elf;
register char *base;
int (*const *f) _((Elf *));
unsigned flags = 0;
if (_elf_work == EV_NONE) /* version() not called yet */
{
_elf_err = ESEQ_VER;
return 0;
}
switch (cmd)
{
default:
_elf_err = EREQ_BEGIN;
return 0;
case ELF_C_NULL:
return 0;
case ELF_C_WRITE:
if ((elf = (Elf *)malloc(sizeof(Elf))) == 0)
{
_elf_err = EMEM_ELF;
return 0;
}
*elf = elf_init;
elf->ed_fd = fd;
elf->ed_activ = 1;
elf->ed_myflags |= EDF_WRITE;
return elf;
case ELF_C_RDWR:
flags = EDF_WRITE | EDF_READ;
break;
case ELF_C_READ:
flags = EDF_READ;
break;
}
/* A null ref asks for a new file
* Non-null ref bumps the activation count
* or gets next archive member
*/
if (ref == 0)
{
if ((elf = regular(fd, flags)) == 0)
return 0;
}
else
{
if ((ref->ed_myflags & flags) != flags)
{
_elf_err = EREQ_RDWR;
return 0;
}
if (ref->ed_kind != ELF_K_AR) /* new activation */
{
++ref->ed_activ;
return ref;
}
if ((elf = member(fd, ref, flags)) == 0)
return 0;
}
elf->ed_activ = 1;
/* ELF?
*/
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;
#ifdef MMAP_IS_AVAIL
/*
* Allow writing only if originally specified read only.
* This is only necessary if the file must be translating
* from one encoding to another.
*/
if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) &&
(elf->ed_encode != _elf_encode)) {
if (mprotect((char *)elf->ed_image, elf->ed_imagesz,
PROT_READ|PROT_WRITE) == -1) {
_elf_err = EIO_VM;
return (0);
}
}
#endif
return elf;
}
/* Archive?
*/
if (elf->ed_fsz >= SARMAG
&& _elf_vm(elf, (size_t)0, (size_t)SARMAG) == OK_YES
&& memcmp(base, armag, SARMAG) == 0)
{
_elf_arinit(elf);
elf->ed_kind = ELF_K_AR;
elf->ed_identsz = SARMAG;
return elf;
}
if (elf->ed_fsz > 0)
{
/* Foreign file conversion?
*/
for (f = _elf_foreign; *f; ++f)
{
int j = (**f)(elf);
if (j > (int)ELF_K_NONE)
{
elf->ed_kind = (Elf_Kind)j;
return elf;
}
if (j == (int)ELF_K_NONE)
continue;
(void)elf_end(elf); /* error leg?? */
return 0;
}
}
/* Return a few ident bytes, but not so many that
* getident() must read a large file. 512 is arbitrary.
*/
elf->ed_kind = ELF_K_NONE;
if ((elf->ed_identsz = elf->ed_fsz) > 512)
elf->ed_identsz = 512;
return elf;
}
static Elf *
member(fd, ref, flags) /* initialize archive member */
int fd;
register 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_err = EREQ_ARRDWR;
return 0;
}
if (ref->ed_fd != fd)
{
_elf_err = EREQ_ARMEMFD;
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_err = EFMT_ARMEMSZ;
return 0;
}
if ((elf = (Elf *)malloc(sizeof(Elf))) == 0)
{
_elf_err = EMEM_ELF;
return 0;
}
*elf = elf_init;
++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;
}
static Elf *
regular(fd, flags) /* initialize regular file */
int fd;
unsigned flags;
{
Elf *elf;
if ((elf = (Elf *)malloc(sizeof(Elf))) == 0)
{
_elf_err = EMEM_ELF;
return 0;
}
*elf = elf_init;
elf->ed_fd = fd;
elf->ed_myflags |= flags;
if (_elf_inmap(elf) != OK_YES)
{
free(elf);
return 0;
}
return elf;
}
/*
* Special routine for ld(1) implimentation. ld(1) generates an initial
* image in memory and calls upon this routine to represent that image
* with an elf descriptor. This allows processing on the image to be
* performed using the standard elf library calls.
*/
Elf *
elf_memory(image, sz)
char *image;
size_t sz;
{
Elf *elf;
if (_elf_work == EV_NONE) /* version() not called yet */
{
_elf_err = ESEQ_VER;
return 0;
}
if ((elf = (Elf *)malloc(sizeof(Elf))) == 0)
{
_elf_err = EMEM_ELF;
return 0;
}
*elf = elf_init;
elf->ed_fd = -1;
elf->ed_myflags |= EDF_WRITE | EDF_READ;
elf->ed_image = elf->ed_ident = image;
elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz;
elf->ed_kind = ELF_K_ELF;
elf->ed_class = image[EI_CLASS];
elf->ed_encode = image[EI_DATA];
if ((elf->ed_version = image[EI_VERSION]) == 0)
elf->ed_version = 1;
elf->ed_identsz = EI_NIDENT;
return elf;
}