[ld.so] Add a minimal dynamic linker

This commit includes a number of changes to enable loading of PIE
executables:

- The loader in srv.init checks for a `PT_INTERP` segment in the program
  its loading, and if it exists, loads the specified interpreter and
  passes control to it instead of the program itself.
- Added ld.so the dynamic linker executable and set it as the
  interpreter for all user-target programs.
- Program initial stack changed again to now contain a number of
  possible tagged structures, including a new one for ld.so's arguments,
  and for passing handles tagged with protocol ids.
- Added a stub for a new VFS protocol. Unused so far, but srv.init will
  need to serve VFS requests from ld.so once I transition libraries to
  shared libs for user-target programs. (Right now all executables are
  PIE but statically linked, so they only need internal relocations.)
- Added 16 and 8 bit variants of `util::bitset`. This ended up not being
  used, but could be useful.
This commit is contained in:
Justin C. Miller
2023-08-12 22:55:37 -07:00
parent 3cfd0cf86b
commit c4bb60299e
21 changed files with 903 additions and 136 deletions

View File

@@ -7,6 +7,7 @@
#include <j6/init.h>
#include <j6/syscalls.h>
#include <j6/syslog.hh>
#include <j6/thread.hh>
#include <j6/types.h>
#include <bootproto/acpi.h>
@@ -14,6 +15,7 @@
#include <bootproto/devices/framebuffer.h>
#include "acpi.h"
#include "initfs.h"
#include "j6romfs.h"
#include "loader.h"
#include "modules.h"
@@ -22,30 +24,7 @@
using bootproto::module;
using bootproto::module_type;
void
load_driver(
j6romfs::fs &initrd,
const j6romfs::inode *dir,
const char *name,
j6_handle_t sys,
j6_handle_t slp,
const module *arg = nullptr)
{
const j6romfs::inode *in = initrd.lookup_inode_in_dir(dir, name);
if (in->type != j6romfs::inode_type::file)
return;
j6::syslog("Loading driver: %s", name);
uint8_t *data = new uint8_t [in->size];
util::buffer program {data, in->size};
initrd.load_inode_data(in, program);
load_program(name, program, sys, slp, arg);
delete [] data;
}
constexpr uintptr_t stack_top = 0xf80000000;
int
driver_main(unsigned argc, const char **argv, const char **env, const j6_init_args *initp)
@@ -58,6 +37,9 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
j6_handle_t sys = j6_handle_invalid;
j6_handle_t sys_child = j6_handle_invalid;
j6_handle_t vfs_mb = j6_handle_invalid;
j6_handle_t vfs_mb_child = j6_handle_invalid;
j6_log("srv.init starting");
sys = j6_find_first_handle(j6_object_type_system);
@@ -82,6 +64,16 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
if (s != j6_status_ok)
return s;
s = j6_mailbox_create(&vfs_mb);
if (s != j6_status_ok)
return s;
s = j6_handle_clone(vfs_mb, &vfs_mb_child,
j6_cap_mailbox_send |
j6_cap_object_clone);
if (s != j6_status_ok)
return s;
uintptr_t modules_addr = initp->args[0];
std::vector<const module*> mods;
@@ -130,19 +122,17 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
// have driver_source objects..
j6romfs::fs initrd {initrd_buf};
j6::thread vfs_thread {[=, &initrd](){ initfs_start(initrd, vfs_mb); }, stack_top};
j6_status_t result = vfs_thread.start();
load_acpi(sys, acpi_module);
const j6romfs::inode *driver_dir = initrd.lookup_inode("/jsix/drivers");
if (!driver_dir) {
j6_log("Could not load drivers directory");
return 1;
}
load_program("/jsix/drivers/drv.uart.elf", initrd, sys_child, slp_mb_child, vfs_mb_child);
load_driver(initrd, driver_dir, "drv.uart.elf", sys_child, slp_mb_child);
for (const module *m : devices) {
switch (m->type_id) {
case bootproto::devices::type_id_uefi_fb:
load_driver(initrd, driver_dir, "drv.uefi_fb.elf", sys_child, slp_mb_child, m);
load_program("/jsix/drivers/drv.uefi_fb.elf", initrd, sys_child, slp_mb_child, vfs_mb_child, m);
break;
default:
@@ -155,16 +145,10 @@ driver_main(unsigned argc, const char **argv, const char **env, const j6_init_ar
if (in->type != j6romfs::inode_type::file)
return;
j6::syslog("Loading service: %s", name);
uint8_t *data = new uint8_t [in->size];
util::buffer program {data, in->size};
initrd.load_inode_data(in, program);
load_program(name, program, sys_child, slp_mb_child);
delete [] data;
});
char path [128];
sprintf(path, "/jsix/services/%s", name);
load_program(path, initrd, sys_child, slp_mb_child, vfs_mb_child);
});
service_locator_start(slp_mb);
return 0;