[elf] Separate exec and system

This commit is contained in:
Kevin Lange 2011-04-15 17:33:19 -05:00
parent 3e3c7fb544
commit 7cf04ad13e
4 changed files with 84 additions and 59 deletions

View File

@ -35,69 +35,79 @@ exec(
int argc, /* Argument count (ie, /bin/echo hello world = 3) */
char ** argv /* Argument strings (including executable path) */
) {
/* This is technically system(), so we're forking */
int child = fork();
if (child == 0) {
/* Open the file */
fs_node_t * file = kopen(path,0);
if (!file) {
/* Command not found */
kexit(127);
}
/* Read in the binary contents */
Elf32_Header * header = (Elf32_Header *)malloc(file->length + 100);
read_fs(file, 0, file->length, (uint8_t *)header);
/* Open the file */
fs_node_t * file = kopen(path,0);
if (!file) {
/* Command not found */
kexit(127);
}
/* Read in the binary contents */
Elf32_Header * header = (Elf32_Header *)malloc(file->length + 100);
read_fs(file, 0, file->length, (uint8_t *)header);
/* Alright, we've read the binary, time to load the loadable sections */
/* Verify the magic */
if ( header->e_ident[0] != ELFMAG0 ||
header->e_ident[1] != ELFMAG1 ||
header->e_ident[2] != ELFMAG2 ||
header->e_ident[3] != ELFMAG3) {
/* What? This isn't an ELF... */
kprintf("Fatal: Not a valid ELF executable.\n");
free(header);
close_fs(file);
kexit(127);
}
/* Load the loadable segments from the binary */
for (uintptr_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
/* read a section header */
Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)header + (header->e_shoff + x));
if (shdr->sh_addr) {
/* If this is a loadable section, load it up. */
if (shdr->sh_addr < current_task->entry) {
/* If this is the lowest entry point, store it for memory reasons */
current_task->entry = shdr->sh_addr;
}
if (shdr->sh_addr + shdr->sh_size - current_task->entry > current_task->image_size) {
/* We also store the total size of the memory region used by the application */
current_task->image_size = shdr->sh_addr + shdr->sh_size - current_task->entry;
}
for (uintptr_t i = 0; i < shdr->sh_size; i += 0x1000) {
/* This doesn't care if we already allocated this page */
alloc_frame(get_page(shdr->sh_addr + i, 1, current_directory), 0, 1);
}
/* Copy the section into memory */
memcpy((void *)(shdr->sh_addr), (void *)((uintptr_t)header + shdr->sh_offset), shdr->sh_size);
}
}
/* Store the entry point to the code segment */
uintptr_t entry = (uintptr_t)header->e_entry;
/* Free the space we used for the ELF headers and files */
/* Alright, we've read the binary, time to load the loadable sections */
/* Verify the magic */
if ( header->e_ident[0] != ELFMAG0 ||
header->e_ident[1] != ELFMAG1 ||
header->e_ident[2] != ELFMAG2 ||
header->e_ident[3] != ELFMAG3) {
/* What? This isn't an ELF... */
kprintf("Fatal: Not a valid ELF executable.\n");
free(header);
close_fs(file);
kexit(127);
}
/* Go go go */
enter_user_jmp(entry, argc, argv);
/* Load the loadable segments from the binary */
for (uintptr_t x = 0; x < header->e_shentsize * header->e_shnum; x += header->e_shentsize) {
/* read a section header */
Elf32_Shdr * shdr = (Elf32_Shdr *)((uintptr_t)header + (header->e_shoff + x));
if (shdr->sh_addr) {
/* If this is a loadable section, load it up. */
if (shdr->sh_addr < current_task->entry) {
/* If this is the lowest entry point, store it for memory reasons */
current_task->entry = shdr->sh_addr;
}
if (shdr->sh_addr + shdr->sh_size - current_task->entry > current_task->image_size) {
/* We also store the total size of the memory region used by the application */
current_task->image_size = shdr->sh_addr + shdr->sh_size - current_task->entry;
}
for (uintptr_t i = 0; i < shdr->sh_size; i += 0x1000) {
/* This doesn't care if we already allocated this page */
alloc_frame(get_page(shdr->sh_addr + i, 1, current_directory), 0, 1);
}
/* Copy the section into memory */
memcpy((void *)(shdr->sh_addr), (void *)((uintptr_t)header + shdr->sh_offset), shdr->sh_size);
}
}
/* Store the entry point to the code segment */
uintptr_t entry = (uintptr_t)header->e_entry;
/* Free the space we used for the ELF headers and files */
free(header);
close_fs(file);
/* Go go go */
enter_user_jmp(entry, argc, argv);
/* We should never reach this code */
return -1;
}
int
system(
char * path, /* Path to the executable to run */
int argc, /* Argument count (ie, /bin/echo hello world = 3) */
char ** argv /* Argument strings (including executable path) */
) {
int child = fork();
if (child == 0) {
exec(path,argc,argv);
kexit(0x5ADFACE);
return -1;
} else {
/* We are emulating system(), so we need to wait for the child
/* We are system(), so we need to wait for the child
* application to exit before we can continue. */
/* Get the child task. */
task_t * volatile child_task = gettask(child);
@ -112,8 +122,6 @@ exec(
/* Grab the child's return value */
return child_task->retval;
}
/* Something went terribly wrong. */
return -1;
}
/*

View File

@ -213,7 +213,7 @@ start_shell() {
if (tokenid < 2) {
continue;
}
int ret = exec(argv[1],tokenid - 1, &argv[1]);
int ret = system(argv[1],tokenid - 1, &argv[1]);
kprintf("Returned %d\n", ret);
} else if (!strcmp(cmd, "boredom")) {
int x = 30;
@ -263,7 +263,7 @@ start_shell() {
kprintf("Unrecognized command: %s\n", cmd);
} else {
close_fs(chd);
exec(filename, tokenid, argv);
system(filename, tokenid, argv);
}
free(filename);
}

View File

@ -283,6 +283,7 @@ void enable_fpu();
/* ELF */
int exec( char *, int, char **);
int system( char *, int, char **);
/* Sytem Calls */
void syscalls_install();

View File

@ -157,5 +157,21 @@ int main(struct multiboot *mboot, uint32_t mboot_mag, uintptr_t esp)
start_shell();
fork();
if (getpid() == 0) {
char * args[] = {
"/bin/yes",
"\033[1;32mA\033[0m"
};
exec("/bin/yes",2,args);
} else {
char * args[] = {
"/bin/yes",
"\033[1;31mB\033[0m"
};
exec("/bin/yes",2,args);
}
return 0;
}