#ifdef TOSTOOLS
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include "exec_elf.h"
#define MALLOC(x) malloc(x)
#else
#include <lib/libsa/stand.h>
#include <atari_stand.h>
#include <libkern.h>
#include <sys/exec_elf.h>
#define MALLOC(x) alloc(x)
#endif
#include "libtos.h"
#include "tosdefs.h"
#include "kparamb.h"
#include "cread.h"
#define ELFMAGIC ((ELFMAG0 << 24) | (ELFMAG1 << 16) | \
(ELFMAG2 << 8) | ELFMAG3)
int
elf_load(int fd, osdsc_t *od, char **errp, int loadsyms)
{
int i,j;
int err;
Elf32_Ehdr ehdr;
Elf32_Phdr *phdrs;
Elf32_Word ident, symsize, symstart;
long kernsize;
*errp = NULL;
lseek(fd, (off_t)0, SEEK_SET);
if (read(fd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
return -1;
memcpy(&ident, ehdr.e_ident, sizeof ident);
if (ident != ELFMAGIC)
return -1;
i = ehdr.e_phnum * sizeof(Elf32_Phdr);
err = 1;
if ((phdrs = (Elf32_Phdr *)MALLOC(i)) == NULL)
goto error;
err = 2;
if (read(fd, phdrs, i) != i)
goto error;
kernsize = 0;
for (i = 0; i < ehdr.e_phnum; i++) {
Elf32_Word sum;
sum = phdrs[i].p_vaddr + phdrs[i].p_memsz;
if ((phdrs[i].p_flags & (PF_W|PF_X)) && (sum > kernsize))
kernsize = sum;
}
symsize = 0;
symstart = 0;
if (loadsyms) {
i = ehdr.e_shnum + 1;
err = 3;
if (lseek(fd, (off_t)ehdr.e_shoff, SEEK_SET) != ehdr.e_shoff)
goto error;
while (--i) {
Elf32_Shdr shdr;
err = 4;
if (read(fd, &shdr, sizeof(shdr)) != sizeof(shdr))
goto error;
if ((shdr.sh_type == SHT_SYMTAB) || (shdr.sh_type == SHT_STRTAB))
symsize += shdr.sh_size;
}
}
if (symsize) {
symstart = kernsize;
kernsize += symsize + sizeof(ehdr) + ehdr.e_shnum*sizeof(Elf32_Shdr);
}
od->k_esym = symsize ? kernsize : 0;
od->ksize = kernsize;
od->kentry = ehdr.e_entry;
err = 5;
if ((od->kstart = (u_char *)MALLOC(od->ksize)) == NULL)
goto error;
for (i = 0; i < ehdr.e_phnum; i++) {
u_char *p;
Elf32_Phdr *php = &phdrs[i];
if (php->p_flags & (PF_W|PF_X)) {
err = 6;
if (lseek(fd, (off_t)php->p_offset, SEEK_SET) != php->p_offset)
goto error;
p = (u_char *)(od->kstart) + php->p_vaddr;
err = 7;
if (read(fd, p, php->p_filesz) != php->p_filesz)
goto error;
if (php->p_memsz > php->p_filesz)
memset(p + php->p_filesz, 0, php->p_memsz - php->p_filesz);
}
}
if (symsize) {
u_char *p, *symtab;
int nhdrs;
Elf32_Shdr *shp;
symtab = od->kstart + symstart;
p = symtab + sizeof(ehdr);
nhdrs = ehdr.e_shnum;
err = 8;
if (lseek(fd, (off_t)ehdr.e_shoff, SEEK_SET) != ehdr.e_shoff)
goto error;
err = 9;
if (read(fd, p, nhdrs * sizeof(*shp)) != nhdrs * sizeof(*shp))
goto error;
shp = (Elf32_Shdr*)p;
p += nhdrs * sizeof(*shp);
for (i = 0; i < nhdrs; i++) {
if (shp[i].sh_type == SHT_SYMTAB) {
if (shp[i].sh_offset == 0)
continue;
err = 10;
if (lseek(fd, (off_t)shp[i].sh_offset, SEEK_SET) !=
shp[i].sh_offset)
goto error;
err = 11;
if (read(fd, p, shp[i].sh_size) != shp[i].sh_size)
goto error;
shp[i].sh_offset = p - symtab;
j = shp[i].sh_link;
if (shp[j].sh_offset == 0)
continue;
p += shp[i].sh_size;
err = 12;
if (lseek(fd, (off_t)shp[j].sh_offset, SEEK_SET) !=
shp[j].sh_offset)
goto error;
err = 13;
if (read(fd, p, shp[j].sh_size) != shp[j].sh_size)
goto error;
shp[j].sh_offset = p - symtab;
break;
}
}
ehdr.e_shoff = sizeof(ehdr);
memcpy(symtab, &ehdr, sizeof(ehdr));
}
return 0;
error:
#ifdef TOSTOOLS
{
static char *errs[] = {
"Cannot malloc Elf phdr storage space",
"Cannot read Elf32_Phdrs",
"Cannot seek to e_shoff location",
"Cannot read Elf32_shdr",
"Cannot malloc kernel image space",
"Seek error while reading text segment\n",
"Read error in text segment\n",
"Error seeking to section headers",
"Error reading section headers",
"Error seeking to symbols",
"Error reading symbols",
"Error seeking to string table",
"Error reading strings"
};
*errp = errs[err];
}
#endif
return err;
}