#include <sys/types.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/sysconfig.h>
#include <sys/auxv.h>
#include <elf.h>
#include <link.h>
#include <string.h>
#include "alias_boot.h"
#define ALIGN(x, a) ((int)(x) & ~((int)(a) - 1))
#define ROUND(x, a) (((int)(x) + ((int)(a) - 1)) & \
~((int)(a) - 1))
#define EMPTY strings[EMPTY_S]
#define LDSO strings[LDSO_S]
#define ZERO strings[ZERO_S]
#define CLOSE (*(funcs[CLOSE_F]))
#define FSTATAT (*(funcs[FSTATAT_F]))
#define MMAP (*(funcs[MMAP_F]))
#define MUNMAP (*(funcs[MUNMAP_F]))
#define OPENAT (*(funcs[OPENAT_F]))
#define PANIC (*(funcs[PANIC_F]))
#define SYSCONFIG (*(funcs[SYSCONFIG_F]))
#include <link.h>
void *
__rtld(Elf32_Boot *ebp, const char *strings[], int (*funcs[])())
{
int i, j, p;
int page_size = 0;
const char *program_name = EMPTY;
int ldfd;
int dzfd = 0;
Elf32_Ehdr *ehdr;
Elf32_Phdr *phdr;
Elf32_Phdr *pptr;
Elf32_Phdr *lph;
Elf32_Phdr *fph = 0;
caddr_t maddr;
Elf32_Off mlen;
caddr_t faddr;
Elf32_Off foff;
Elf32_Off flen;
caddr_t addr;
caddr_t zaddr;
struct stat sb;
auxv_t *ap;
while (ebp->eb_tag != 0) {
switch (ebp->eb_tag) {
case EB_ARGV:
program_name = *((char **)ebp->eb_un.eb_ptr);
break;
case EB_AUXV:
for (ap = (auxv_t *)ebp->eb_un.eb_ptr;
ap->a_type != AT_NULL; ap++)
if (ap->a_type == AT_PAGESZ) {
page_size = ap->a_un.a_val;
break;
}
break;
}
ebp++;
}
if (page_size == 0) {
page_size = SYSCONFIG(_CONFIG_PAGESIZE);
ebp->eb_tag = EB_PAGESIZE, (ebp++)->eb_un.eb_val =
(Elf32_Word)page_size;
}
if ((ldfd = OPENAT(AT_FDCWD, LDSO, O_RDONLY)) == -1)
PANIC(program_name);
if (FSTATAT(ldfd, NULL, &sb, 0) == -1)
PANIC(program_name);
ehdr = (Elf32_Ehdr *)MMAP(0, sb.st_size, PROT_READ | PROT_EXEC,
MAP_SHARED, ldfd, 0);
if (ehdr == (Elf32_Ehdr *)-1)
PANIC(program_name);
if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
ehdr->e_ident[EI_MAG3] != ELFMAG3)
PANIC(program_name);
if (ehdr->e_ident[EI_CLASS] != ELFCLASS32 ||
ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
PANIC(program_name);
if (ehdr->e_type != ET_DYN)
PANIC(program_name);
if (ehdr->e_machine != EM_386)
PANIC(program_name);
if (ehdr->e_version > EV_CURRENT)
PANIC(program_name);
phdr = (Elf32_Phdr *)((caddr_t)ehdr + ehdr->e_phoff);
for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize))
if (pptr->p_type == PT_LOAD) {
if (fph == 0) {
fph = pptr;
} else if (pptr->p_vaddr <= lph->p_vaddr)
PANIC(program_name);
lph = pptr;
}
if (fph == 0)
PANIC(program_name);
mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
ALIGN(fph->p_vaddr, page_size), page_size);
maddr = (caddr_t)MMAP(0, mlen, PROT_READ | PROT_EXEC,
MAP_SHARED, ldfd, 0);
if (maddr == (caddr_t)-1)
PANIC(program_name);
faddr = (caddr_t)ROUND(maddr, fph->p_align);
if (faddr != maddr) {
(void) MUNMAP(maddr, mlen);
mlen = ROUND((lph->p_vaddr + lph->p_memsz) -
ALIGN(fph->p_vaddr, fph->p_align) + fph->p_align,
page_size);
maddr = (caddr_t)MMAP(0, mlen, PROT_READ | PROT_EXEC,
MAP_SHARED, ldfd, 0);
if (maddr == (caddr_t)-1)
PANIC(program_name);
faddr = (caddr_t)ROUND(maddr, fph->p_align);
}
for (p = 0, pptr = phdr; p < (int)ehdr->e_phnum; p++,
pptr = (Elf32_Phdr *)((caddr_t)pptr + ehdr->e_phentsize)) {
if ((pptr->p_type != PT_LOAD) || (pptr->p_memsz == 0))
continue;
foff = ALIGN(pptr->p_offset, page_size);
flen = pptr->p_memsz + (pptr->p_offset - foff);
addr = (caddr_t)ALIGN(faddr + pptr->p_vaddr, page_size);
if (pptr == phdr) {
ebp->eb_tag = EB_LDSO_BASE;
(ebp++)->eb_un.eb_ptr = (Elf32_Addr)addr;
}
if (addr - maddr) {
(void) MUNMAP(maddr, addr - maddr);
mlen -= addr - maddr;
}
i = 0;
if (pptr->p_flags & PF_R)
i |= PROT_READ;
if (pptr->p_flags & PF_W)
i |= PROT_WRITE;
if (pptr->p_flags & PF_X)
i |= PROT_EXEC;
if ((caddr_t)MMAP((caddr_t)addr, flen, i,
MAP_FIXED | MAP_PRIVATE, ldfd, foff) == (caddr_t)-1)
PANIC(program_name);
if (pptr->p_memsz > pptr->p_filesz) {
foff = (int)faddr + pptr->p_vaddr + pptr->p_filesz;
zaddr = (caddr_t)ROUND(foff, page_size);
for (j = 0; j < (int)(zaddr - foff); j++)
*((char *)foff + j) = 0;
j = (faddr + pptr->p_vaddr + pptr->p_memsz) - zaddr;
if (j > 0) {
if (dzfd == 0) {
dzfd = OPENAT(AT_FDCWD, ZERO, O_RDWR);
if (dzfd == -1)
PANIC(program_name);
}
if ((caddr_t)MMAP((caddr_t)zaddr, j, i,
MAP_FIXED | MAP_PRIVATE, dzfd,
0) == (caddr_t)-1)
PANIC(program_name);
}
}
maddr = addr + ROUND(flen, page_size);
mlen -= maddr - addr;
}
if (mlen > 0)
(void) MUNMAP(maddr, mlen);
(void) CLOSE(ldfd);
if (dzfd != 0)
ebp->eb_tag = EB_DEVZERO, (ebp++)->eb_un.eb_val = dzfd;
ebp->eb_tag = EB_NULL, ebp->eb_un.eb_val = 0;
return (void *) (ehdr->e_entry + faddr - 2);
}