#include <lib/libsa/arc4.h>
int ELFNAME(exec)(int, Elf_Ehdr *, uint64_t *, int);
int
ELFNAME(exec)(int fd, Elf_Ehdr *elf, uint64_t *marks, int flags)
{
Elf_Shdr *shp;
Elf_Phdr *phdr;
Elf_Off off;
int i;
size_t sz;
int first;
int havesyms;
paddr_t minp = ~0, maxp = 0, pos = 0;
paddr_t offset = marks[MARK_START], shpp, elfp;
sz = elf->e_phnum * sizeof(Elf_Phdr);
phdr = ALLOC(sz);
if (lseek(fd, (off_t)elf->e_phoff, SEEK_SET) == -1) {
WARN(("lseek phdr"));
FREE(phdr, sz);
return 1;
}
if (read(fd, phdr, sz) != sz) {
WARN(("read program headers"));
FREE(phdr, sz);
return 1;
}
for (first = 1, i = 0; i < elf->e_phnum; i++) {
if (phdr[i].p_type == PT_OPENBSD_RANDOMIZE) {
if (flags & LOAD_RANDOM) {
extern struct rc4_ctx randomctx;
rc4_getbytes(&randomctx,
(void *)LOADADDR(phdr[i].p_paddr),
phdr[i].p_filesz);
}
if (flags & (LOAD_RANDOM | COUNT_RANDOM)) {
marks[MARK_RANDOM] = LOADADDR(phdr[i].p_paddr);
marks[MARK_ERANDOM] =
marks[MARK_RANDOM] + phdr[i].p_filesz;
}
continue;
}
if (phdr[i].p_type != PT_LOAD ||
(phdr[i].p_flags & (PF_W|PF_R|PF_X)) == 0)
continue;
#ifdef CHECK_PHDR
if (CHECK_PHDR(ELFSIZE, &phdr[i])) {
FREE(phdr, sz);
return 1;
}
#endif
#define IS_TEXT(p) (p.p_flags & PF_X)
#define IS_DATA(p) ((p.p_flags & PF_X) == 0)
#define IS_BSS(p) (p.p_filesz < p.p_memsz)
if ((IS_TEXT(phdr[i]) && (flags & LOAD_TEXT)) ||
(IS_DATA(phdr[i]) && (flags & LOAD_DATA))) {
PROGRESS(("%s%lu", first ? "" : "+",
(u_long)phdr[i].p_filesz));
if (lseek(fd, (off_t)phdr[i].p_offset, SEEK_SET) == -1) {
WARN(("lseek text"));
FREE(phdr, sz);
return 1;
}
if (READ(fd, phdr[i].p_paddr, phdr[i].p_filesz) !=
phdr[i].p_filesz) {
WARN(("read text"));
FREE(phdr, sz);
return 1;
}
first = 0;
}
if ((IS_TEXT(phdr[i]) && (flags & (LOAD_TEXT | COUNT_TEXT))) ||
(IS_DATA(phdr[i]) && (flags & (LOAD_DATA | COUNT_TEXT)))) {
pos = phdr[i].p_paddr;
if (minp > pos)
minp = pos;
pos += phdr[i].p_filesz;
if (maxp < pos)
maxp = pos;
}
if (IS_BSS(phdr[i]) && (flags & LOAD_BSS)) {
PROGRESS(("+%lu",
(u_long)(phdr[i].p_memsz - phdr[i].p_filesz)));
BZERO((phdr[i].p_paddr + phdr[i].p_filesz),
phdr[i].p_memsz - phdr[i].p_filesz);
}
if (IS_BSS(phdr[i]) && (flags & (LOAD_BSS|COUNT_BSS))) {
pos += phdr[i].p_memsz - phdr[i].p_filesz;
if (maxp < pos)
maxp = pos;
}
}
FREE(phdr, sz);
elfp = maxp = roundup(maxp, sizeof(Elf_Addr));
if (flags & (LOAD_HDR | COUNT_HDR))
maxp += sizeof(Elf_Ehdr);
if (flags & (LOAD_SYM | COUNT_SYM)) {
if (lseek(fd, (off_t)elf->e_shoff, SEEK_SET) == -1) {
WARN(("lseek section headers"));
return 1;
}
sz = elf->e_shnum * sizeof(Elf_Shdr);
shp = ALLOC(sz);
if (read(fd, shp, sz) != sz) {
WARN(("read section headers"));
FREE(shp, sz);
return 1;
}
shpp = maxp;
maxp += roundup(sz, sizeof(Elf_Addr));
size_t shstrsz = shp[elf->e_shstrndx].sh_size;
char *shstr = ALLOC(shstrsz);
if (lseek(fd, (off_t)shp[elf->e_shstrndx].sh_offset, SEEK_SET) == -1) {
WARN(("lseek section header string table"));
FREE(shstr, shstrsz);
FREE(shp, sz);
return 1;
}
if (read(fd, shstr, shstrsz) != shstrsz) {
WARN(("read section header string table"));
FREE(shstr, shstrsz);
FREE(shp, sz);
return 1;
}
off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
for (havesyms = i = 0; i < elf->e_shnum; i++)
if (shp[i].sh_type == SHT_SYMTAB)
havesyms = 1;
for (first = 1, i = 0; i < elf->e_shnum; i++) {
if (shp[i].sh_type == SHT_SYMTAB ||
shp[i].sh_type == SHT_STRTAB ||
!strcmp(shstr + shp[i].sh_name, ".debug_line") ||
!strcmp(shstr + shp[i].sh_name, ELF_CTF)) {
if (havesyms && (flags & LOAD_SYM)) {
PROGRESS(("%s%ld", first ? " [" : "+",
(u_long)shp[i].sh_size));
if (lseek(fd, (off_t)shp[i].sh_offset,
SEEK_SET) == -1) {
WARN(("lseek symbols"));
FREE(shstr, shstrsz);
FREE(shp, sz);
return 1;
}
if (READ(fd, maxp, shp[i].sh_size) !=
shp[i].sh_size) {
WARN(("read symbols"));
FREE(shstr, shstrsz);
FREE(shp, sz);
return 1;
}
}
maxp += roundup(shp[i].sh_size,
sizeof(Elf_Addr));
shp[i].sh_offset = off;
shp[i].sh_flags |= SHF_ALLOC;
off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
first = 0;
}
}
if (flags & LOAD_SYM) {
BCOPY(shp, shpp, sz);
if (havesyms && first == 0)
PROGRESS(("]"));
}
FREE(shstr, shstrsz);
FREE(shp, sz);
}
if (flags & LOAD_HDR) {
elf->e_phoff = 0;
elf->e_shoff = sizeof(Elf_Ehdr);
elf->e_phentsize = 0;
elf->e_phnum = 0;
BCOPY(elf, elfp, sizeof(*elf));
}
marks[MARK_START] = LOADADDR(minp);
marks[MARK_ENTRY] = LOADADDR(elf->e_entry);
marks[MARK_VENTRY] = elf->e_entry;
marks[MARK_NSYM] = 1;
marks[MARK_SYM] = LOADADDR(elfp);
marks[MARK_END] = LOADADDR(maxp);
return 0;
}