ld: implement an actual program loader
This commit is contained in:
244
sys/ld/main.c
244
sys/ld/main.c
@@ -1,7 +1,10 @@
|
||||
#define MSG_IMPLEMENTATION
|
||||
#define MSG_NO_MALLOC
|
||||
|
||||
#include "elf.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <heap/heap.h>
|
||||
#include <mango/log.h>
|
||||
#include <mango/msg.h>
|
||||
@@ -10,6 +13,7 @@
|
||||
#include <mango/vm.h>
|
||||
#include <rosetta/bootstrap.h>
|
||||
#include <rosetta/fs.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -17,84 +21,204 @@
|
||||
#include <sys/remote.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char *search_paths[] = {
|
||||
"/usr/lib",
|
||||
};
|
||||
static const size_t nr_search_paths
|
||||
= sizeof search_paths / sizeof search_paths[0];
|
||||
|
||||
static void report_error(const char *name, int err, const char *msg, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
va_list arg;
|
||||
va_start(arg, msg);
|
||||
vsnprintf(buf, sizeof buf, msg, arg);
|
||||
va_end(arg);
|
||||
|
||||
kern_tracef("%s: %s: %s", name, buf, strerror(err));
|
||||
}
|
||||
|
||||
static const char *get_image_name(const char *path)
|
||||
{
|
||||
const char *last_slash = NULL;
|
||||
for (size_t i = 0; path[i]; i++) {
|
||||
if (path[i] == '/') {
|
||||
last_slash = path + i;
|
||||
}
|
||||
}
|
||||
|
||||
return last_slash ? last_slash + 1 : path;
|
||||
}
|
||||
|
||||
static int find_image(struct elf_image *img)
|
||||
{
|
||||
const char *name = img->e_leaf.l_name;
|
||||
char path[4096];
|
||||
|
||||
for (size_t i = 0; i < nr_search_paths; i++) {
|
||||
snprintf(path, sizeof path, "%s/%s", search_paths[i], name);
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
kern_tracef("found %s -> %s", name, path);
|
||||
img->e_fd = fd;
|
||||
img->e_status = ELF_IMAGE_OPEN;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
static int load_images(struct image_list *list)
|
||||
{
|
||||
int status = SUCCESS;
|
||||
struct image_list_iterator it;
|
||||
image_list_iterator_begin(&it, list);
|
||||
|
||||
while (it.it_leaf) {
|
||||
struct elf_image *image
|
||||
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
|
||||
kern_tracef(
|
||||
"image: %s [%s]",
|
||||
it.it_leaf->l_name,
|
||||
elf_image_status_to_string(image->e_status));
|
||||
|
||||
int new_dependencies = 0;
|
||||
switch (image->e_status) {
|
||||
case ELF_IMAGE_NONE:
|
||||
/* Find the image using its name */
|
||||
status = find_image(image);
|
||||
if (status != SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
case ELF_IMAGE_OPEN:
|
||||
/* parse the image */
|
||||
status = elf_image_parse(image);
|
||||
if (status != SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
case ELF_IMAGE_PARSED:
|
||||
/* load the image */
|
||||
status = elf_image_load(image);
|
||||
if (status != SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
case ELF_IMAGE_LOADED:
|
||||
/* collect dependencies */
|
||||
new_dependencies
|
||||
= elf_image_collect_dependencies(image, list);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (new_dependencies < 0) {
|
||||
return -new_dependencies;
|
||||
}
|
||||
|
||||
if (new_dependencies > 0) {
|
||||
image_list_iterator_begin(&it, list);
|
||||
} else {
|
||||
image_list_iterator_move_next(&it);
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int link_images(struct image_list *list)
|
||||
{
|
||||
int status = SUCCESS;
|
||||
struct image_list_iterator it;
|
||||
image_list_iterator_begin(&it, list);
|
||||
|
||||
kern_trace("linking all images");
|
||||
while (it.it_leaf) {
|
||||
struct elf_image *image
|
||||
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
|
||||
kern_tracef(
|
||||
"image: %s [%s]",
|
||||
it.it_leaf->l_name,
|
||||
elf_image_status_to_string(image->e_status));
|
||||
|
||||
status = elf_image_link(image);
|
||||
|
||||
image_list_iterator_move_next(&it);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int main(const struct rosetta_bootstrap *bs)
|
||||
{
|
||||
kern_logf("ld");
|
||||
kern_tracef("ld");
|
||||
|
||||
for (size_t i = 0; i < bs->bs_argc; i++) {
|
||||
kern_logf("argv[%zu]: %s", i, bs->bs_argv[i]);
|
||||
kern_tracef("argv[%zu]: %s", i, bs->bs_argv[i]);
|
||||
}
|
||||
|
||||
sys_remote_set(SYS_REMOTE_NSD, 0, 0);
|
||||
const char *path = "/usr/lib/libc.so";
|
||||
int flags = 4;
|
||||
const char *exec_path = bs->bs_argv[1];
|
||||
const char *task_name = bs->bs_argv[2];
|
||||
const char *image_name = get_image_name(exec_path);
|
||||
|
||||
kern_logf("sending msg: open(%s, %d)", path, flags);
|
||||
int fd = open(path, flags);
|
||||
struct image_list images;
|
||||
image_list_init(&images);
|
||||
|
||||
if (fd < 0) {
|
||||
kern_logf(
|
||||
"open(%s, %d) = %s (%s)",
|
||||
path,
|
||||
flags,
|
||||
strerror_code(fd),
|
||||
strerror(fd));
|
||||
struct elf_image *exec = NULL;
|
||||
int err = elf_image_open(exec_path, &exec);
|
||||
if (err != SUCCESS) {
|
||||
report_error(
|
||||
task_name,
|
||||
err,
|
||||
"error while loading %s",
|
||||
exec_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kern_logf(
|
||||
"open(%s, %d) = %s (%s)",
|
||||
path,
|
||||
flags,
|
||||
strerror_code(SUCCESS),
|
||||
strerror(SUCCESS));
|
||||
snprintf(
|
||||
exec->e_leaf.l_name,
|
||||
sizeof exec->e_leaf.l_name,
|
||||
"%s",
|
||||
image_name);
|
||||
|
||||
unsigned char buf[32] = {0};
|
||||
int nr = read(fd, buf, sizeof buf);
|
||||
|
||||
if (nr < 0) {
|
||||
kern_logf("read call failed (%s)", strerror(nr));
|
||||
image_list_put(&images, &exec->e_leaf);
|
||||
err = load_images(&images);
|
||||
if (err != SUCCESS) {
|
||||
report_error(
|
||||
task_name,
|
||||
err,
|
||||
"error while loading %s",
|
||||
exec_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
kern_logf("data: %x %c %c %c", buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
void *p
|
||||
= mmap(NULL,
|
||||
0x1000,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE,
|
||||
-1,
|
||||
0);
|
||||
if (p != MAP_FAILED) {
|
||||
memset(p, 0x0, 0x1000);
|
||||
kern_logf("mmap'd buffer at %p", p);
|
||||
} else {
|
||||
kern_logf("mmap buffer failed");
|
||||
err = link_images(&images);
|
||||
if (err != SUCCESS) {
|
||||
report_error(
|
||||
task_name,
|
||||
err,
|
||||
"error while loading %s",
|
||||
exec_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *lib
|
||||
= mmap(NULL, 0x2000, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
|
||||
if (lib != MAP_FAILED) {
|
||||
kern_logf("mmap'd %s at %p", path, lib);
|
||||
unsigned char *tmp = lib;
|
||||
kern_logf(
|
||||
"data[0]: %x %c %c %c",
|
||||
tmp[0],
|
||||
tmp[1],
|
||||
tmp[2],
|
||||
tmp[3]);
|
||||
tmp += 0x1000;
|
||||
kern_logf(
|
||||
"data[0x1000]: %02x %02x %02x %02x",
|
||||
tmp[0],
|
||||
tmp[1],
|
||||
tmp[2],
|
||||
tmp[3]);
|
||||
} else {
|
||||
kern_logf("mmap lib failed");
|
||||
struct image_list_iterator it;
|
||||
image_list_iterator_begin(&it, &images);
|
||||
|
||||
while (it.it_leaf) {
|
||||
struct elf_image *image
|
||||
= QUEUE_CONTAINER(struct elf_image, e_leaf, it.it_leaf);
|
||||
kern_tracef(
|
||||
"image: %s [%s]",
|
||||
it.it_leaf->l_name,
|
||||
elf_image_status_to_string(image->e_status));
|
||||
|
||||
image_list_iterator_move_next(&it);
|
||||
}
|
||||
|
||||
kern_logf("ld finished");
|
||||
return 0;
|
||||
kern_tracef("ld finished");
|
||||
int (*entry)(int, const char **)
|
||||
= (int (*)(int, const char **))exec->e_entry;
|
||||
return entry(bs->bs_argc - 2, bs->bs_argv + 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user