⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 loader.c

📁 一个类linux的dos下开发的操作系统.
💻 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 + -