📄 loader.c
字号:
/*****************************************************************************
CREATE USER TASKS FROM STATICALLY-LINKED ELF OR COFF OR WIN32 PE FILES
EXPORTS:
int run(task_t *task, unsigned char *image);
*****************************************************************************/
#include <string.h> /* NULL, memcmp(), memset(), memcpy() */
#include <krnl.h>
/* IMPORTS
from MAIN.C */
void kprintf(const char *fmt, ...);
/* from PAGING.C */
unsigned long alloc_page(void);
unsigned long get_page_dir(void);
/*****************************************************************************
*****************************************************************************/
/* COFF file header */
#define COFF_FILE_MAGIC 0 /* 0x014C */
#define COFF_FILE_SECT_NUM 2 /* number of sections */
#define COFF_FILE_TIMEDATE 4 /* time and date stamp */
#define COFF_FILE_SYMTAB_OFF 8 /* file offset of symbol table */
#define COFF_FILE_SYMTAB_NUM 12 /* number of symtab entries */
#define COFF_FILE_OPTHDR_SIZE 16 /* "optional" (aout) header size */
#define COFF_FILE_FLAGS 18
/* 20 bytes to here */
#define COFF_FILE_HDRLEN 20
#define COFF_AOUT_MAGIC 20 /* 0x010B */
#define COFF_AOUT_VER 22
#define COFF_AOUT_CODE_SIZE 24
#define COFF_AOUT_DATA_SIZE 28
#define COFF_AOUT_BSS_SIZE 32
#define COFF_AOUT_ENTRY 36 /* initial EIP */
#define COFF_AOUT_CODE_BASE 40
#define COFF_AOUT_DATA_BASE 44
/* 48 bytes to here */
#define AOUT_FILE_HDRLEN 48
/* COFF section header */
#define COFF_SECT_NAME 0 /* ".text", ".data", etc. */
#define COFF_SECT_PADR 8 /* physical adr */
#define COFF_SECT_VADR 12 /* virtual adr */
#define COFF_SECT_SIZE 16
#define COFF_SECT_OFF 20 /* file offset of section */
#define COFF_SECT_RELOC_OFF 24 /* file offset of relocations */
#define COFF_SECT_LINENUM_OFF 28 /* file offset of line number info */
#define COFF_SECT_RELOC_NUM 32 /* number of relocations */
#define COFF_SECT_LINENUM_NUM 34 /* number of line numbers */
#define COFF_SECT_FLAGS 36
/* 40 bytes long */
#define COFF_SECT_HDRLEN 40
static int load_coff_file(task_t *task, unsigned char *file_hdr)
{
unsigned short aout_hdr_size, i;
unsigned char *sect_hdr;
sect_t *sect;
/* VALIDATE COFF HEADER:
number of sections */
task->num_sects = read_le16(file_hdr + COFF_FILE_SECT_NUM);
if(task->num_sects > MAX_SECT)
BAD: {
kprintf("Invalid COFF file\n");
return -1;
}
/* size of a.out header */
aout_hdr_size = read_le16(file_hdr + COFF_FILE_OPTHDR_SIZE);
// if(aout_hdr_size != 28)
// goto BAD;
/* flags (F_EXEC) */
if((read_le16(file_hdr + COFF_FILE_FLAGS) & 0x0002) == 0)
goto BAD;
/* VALIDATE A.OUT HEADER: a.out magic value */
if(read_le16(file_hdr + COFF_AOUT_MAGIC) != 0x010B)
goto BAD;
/* the entry point */
task->entry_pt = read_le32(file_hdr + COFF_AOUT_ENTRY);
sect_hdr = file_hdr + COFF_FILE_HDRLEN + aout_hdr_size;
sect = task->sect + FREE_SECT;
for(i = 0; i < task->num_sects; i++)
{
/* code (STYP_TEXT) */
if(!memcmp(sect_hdr + COFF_SECT_NAME, ".text", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x20)
{
sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);
sect->exec = sect->load = 1;
sect->write = sect->zero = 0;
}
/* data (STYP_DATA) */
else if(!memcmp(sect_hdr + COFF_SECT_NAME, ".data", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x40)
{
sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);
sect->write = sect->load = 1;
sect->exec = sect->zero = 0;
}
/* BSS (STYP_BSS) */
else if(!memcmp(sect_hdr + COFF_SECT_NAME, ".bss", 5) &&
(read_le32(sect_hdr + COFF_SECT_FLAGS) & 0xE0) == 0x80)
{
sect->size = read_le32(file_hdr + COFF_AOUT_BSS_SIZE);
/* sect->size = read_le32(sect_hdr + COFF_SECT_SIZE);*/
sect->write = sect->zero = 1;
sect->exec = sect->load = 0;
}
/* anything else */
else
goto BAD;
sect->read = 1;
sect->off = read_le32(sect_hdr + COFF_SECT_OFF);
sect->adr = read_le32(sect_hdr + COFF_SECT_VADR);
sect_hdr += COFF_SECT_HDRLEN;
/* skip zero-length sections */
if(sect->size != 0)
sect++;
}
task->num_sects = sect - task->sect;
return 0;
}
/*****************************************************************************
*****************************************************************************/
#define ELF_FILE_MAGIC 0 /* "\x7F""ELF" */
#define ELF_FILE_BITNESS 4 /* 1=32-bit, 2=64-bit */
#define ELF_FILE_ENDIAN 5 /* 1=little endian, 2=big endian */
#define ELF_FILE_VER1 6 /* =1 */
/* bytes 7-15 are reserved */
#define ELF_FILE_TYPE 16 /* 1=.o, 2=executable, 3=DLL, 4=core */
#define ELF_FILE_MACHINE 18 /* 2=SPARC, 3=i386, 4=68000... */
#define ELF_FILE_VER2 20 /* =1 */
#define ELF_FILE_ENTRY 24 /* initial EIP */
#define ELF_PHTAB_OFFSET 28 /* file offset of Program Header table */
#define ELF_SHTAB_OFFSET 32 /* file offset of Section Header table */
#define ELF_FILE_FLAGS 36 /* (not used for i386?) */
#define ELF_FILE_HDRSIZE 40 /* size of this header, usu. 52 */
#define ELF_PHTAB_ENTSIZE 42 /* size of entries in PH table */
#define ELF_PHTAB_COUNT 44 /* number of entries in PH table */
#define ELF_SHTAB_ENTSIZE 46 /* size of entries in SH table */
#define ELF_SHTAB_COUNT 48 /* number of entries in SH table */
#define ELF_SHSTRTAB_INDEX 50 /* SH table entry for .shstrtab */
/* 52 bytes long */
#define ELF_PH_TYPE 0
#define ELF_PH_OFFSET 4
#define ELF_PH_VADDR 8
#define ELF_PH_PADDR 12
#define ELF_PH_FILESIZE 16
#define ELF_PH_MEMSIZE 20
#define ELF_PH_FLAGS 24
#define ELF_PH_ALIGN 28
/* 32 bytes long */
static int load_elf_file(task_t *task, unsigned char *image)
{
unsigned short phtab_ent_size, num_phtab_ents, i;
unsigned long temp;
sect_t *sect;
/* validation */
if(image[ELF_FILE_BITNESS] != 1 /* 32-bit */ ||
image[ELF_FILE_ENDIAN] != 1 /* little endian */ ||
image[ELF_FILE_VER1] != 1 /* ELF ver 1 */)
BAD: {
kprintf("Invalid ELF file\n");
return -1;
}
if(read_le16(image + ELF_FILE_TYPE) != 2 /* executable */ ||
read_le16(image + ELF_FILE_MACHINE) != 3 /* i386 */ ||
read_le32(image + ELF_FILE_VER2) != 1 /* ELF ver 1 */)
goto BAD;
/* the entry point */
task->entry_pt = read_le32(image + ELF_FILE_ENTRY);
/* go to program header table and read it */
phtab_ent_size = read_le16(image + ELF_PHTAB_ENTSIZE);
num_phtab_ents = read_le16(image + ELF_PHTAB_COUNT);
image += read_le32(image + ELF_PHTAB_OFFSET);
sect = task->sect + FREE_SECT;
for(i = 0; i < num_phtab_ents; i++)
{
temp = read_le32(image + ELF_PH_TYPE);
/* choke on DYNAMIC and the forbidden SHLIB segments */
if(temp == 2 || temp == 5)
goto BAD;
/* handle LOAD segment */
/*else*/ if(temp == 1)
{
sect->adr = read_le32(image + ELF_PH_VADDR);
sect->size = read_le32(image + ELF_PH_FILESIZE);
sect->off = read_le32(image + ELF_PH_OFFSET);
temp = read_le32(image + ELF_PH_FLAGS);
sect->read = (temp & 4) ? 1 : 0;
sect->write = (temp & 2) ? 1 : 0;
sect->exec = (temp & 1) ? 1 : 0;
sect->load = 1;
sect->zero = 0;
/* if memsize>filesize, this segment contains the BSS */
temp = read_le32(image + ELF_PH_MEMSIZE);
if(temp > sect->size)
{
sect[1].adr = sect->adr + sect->size;
sect[1].size = temp - sect->size;
sect[1].read = sect->read;
sect[1].write = sect->write;
sect[1].exec = sect->exec;
sect++;
sect->load = 0;
sect->zero = 1;
}
}
/* ignore NULL, PHDR, INTERP, and NOTE
else
nothing; */
image += phtab_ent_size;
/* skip zero-length sections */
if(sect->size != 0)
sect++;
}
task->num_sects = sect - task->sect;
return 0;
}
/*****************************************************************************
*****************************************************************************/
int run(task_t *task, unsigned char *image)
{
unsigned long foo, highest, lowest;
unsigned short i;
sect_t *sect;
regs_t *regs;
memset(task, 0, sizeof(task_t));
/* try loading as ELF. load_elf_file() and load_coff_file() will set
task->entry_pt, task->num_sects, and task->sect[] */
if(memcmp(image, "\x7F""ELF", 4) == 0)
{
if(load_elf_file(task, image) != 0)
return -1;
}
/* try loading as DJGPP COFF */
else if(read_le16(image + COFF_FILE_MAGIC) == 0x014C)
{
if(load_coff_file(task, image) != 0)
return -1;
}
/* try loading as Win32 PE */
else if(image[0] == 'M' && image[1] == 'Z')
{
foo = read_le32(image + 60);
if(!memcmp(image + foo, "PE\x00\x00", 4))
goto BAD;
if(load_coff_file(task, image + foo + 4) != 0)
return -1;
}
else
BAD: {
kprintf("run: unsupported executable file format\n");
return -1;
}
/* need 1 section left for stack */
if(task->num_sects > MAX_SECT - HEAP_SECT - 1)
{
kprintf("run: too many sections (%u) in executable file\n",
task->num_sects);
return -1;
}
/* convert file offsets to physical load addresses */
for(i = 0; i < task->num_sects; i++)
task->sect[i].off += (unsigned long)image;
/* create a new page directory */
task->page_dir = alloc_page();
if(task->page_dir == NULL)
{
MEM: kprintf("out of memory in run()\n");
return -1;
}
/* copy in current page dir */
foo = get_page_dir() & -PAGE_SIZE;
memcpy((void *)task->page_dir, (void *)foo, PAGE_SIZE);
/* create a kernel stack for the task */
foo = alloc_page();
if(foo == NULL)
goto MEM;
task->init_krnl_esp = foo + PAGE_SIZE;
/* put register values on kernel stack, to be popped by task-switch */
task->krnl_esp = task->init_krnl_esp - sizeof(regs_t);
regs = (regs_t *)task->krnl_esp;
regs->ds = regs->es = regs->fs =
regs->gs = regs->user_ss = USER_DATA_SEL;
regs->eip = task->entry_pt;
regs->cs = USER_CODE_SEL;
/* run task with interrupts enabled */
regs->eflags = 0x200;
/* find highest and lowest addresses */
lowest = -1uL;
highest = 0;
for(i = FREE_SECT; i < FREE_SECT + task->num_sects; i++)
{
sect = task->sect + i;
if(sect->adr < lowest)
lowest = sect->adr;
if(sect->adr + sect->size > highest)
highest = sect->adr + sect->size;
/* xxx - maybe check that all sections are in userland
(0x40000000 - 0xC0000000) */
}
/* create heap section */
sect = task->sect + HEAP_SECT;
sect->adr = highest;
sect->size = INIT_HEAP_SIZE;
sect->read = sect->write = 1;
sect->exec = sect->load = sect->zero = 0;
/* create stack section */
sect = task->sect + task->num_sects;
task->num_sects++;
sect->adr = USER_STACK_BASE - USER_STACK_SIZE;
sect->size = USER_STACK_SIZE;
sect->read = sect->write = 1;
sect->exec = sect->load = sect->zero = 0;
regs->user_esp = USER_STACK_BASE;
//dump_task(task);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -