[ld.so] Add dynamic library linking

ld.so will now go through all DT_NEEDED entries in the dynamic table and load and relocate
those shared libraries as well. Lazy linking of functions via the PLT is not yet supported,
all PLT entries are looked up ahead of time by ld.so.
This commit is contained in:
Justin C. Miller
2024-02-18 17:39:42 -08:00
parent c27f8baa31
commit c245949ea4
17 changed files with 607 additions and 203 deletions

View File

@@ -0,0 +1,7 @@
---
ccflags: [
]
ldflags: [
"-shared",
]

View File

@@ -2,7 +2,9 @@
/// \file init.h
/// Process initialization utility functions
#include <stddef.h>
#include <stdint.h>
#include <j6/types.h>
#include <util/api.h>
@@ -38,9 +40,7 @@ struct j6_arg_loader
add_header(loader);
uintptr_t loader_base;
uintptr_t image_base;
uintptr_t phdr;
size_t phdr_size;
size_t phdr_count;
uintptr_t *got;
uintptr_t entrypoint;
};
@@ -84,4 +84,4 @@ int driver_main(unsigned, const char **, const char **, const j6_init_args *);
} // extern "C"
#endif
#undef add_header
#undef add_header

View File

@@ -18,7 +18,8 @@ public:
/// Load a file into a VMA
/// \arg path Path of the file to load
/// \arg vma [out] Handle to the loaded VMA, or invalid if not found
j6_status_t load_file(char *path, j6_handle_t &vma);
/// \arg size [out] Size of the file
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
private:
j6_handle_t m_service;

View File

@@ -10,7 +10,7 @@
#include <j6/types.h>
namespace {
constexpr size_t static_arr_count = 8;
constexpr size_t static_arr_count = 32;
j6_handle_descriptor handle_array[static_arr_count];
j6_init_args init_args;
} // namespace

View File

@@ -15,7 +15,7 @@ client::client(j6_handle_t vfs_mb) :
inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; }
j6_status_t
client::load_file(char *path, j6_handle_t &vma)
client::load_file(char *path, j6_handle_t &vma, size_t &size)
{
if (!path)
return j6_err_invalid_arg;
@@ -43,8 +43,16 @@ client::load_file(char *path, j6_handle_t &vma)
if (s != j6_status_ok)
return s;
if (tag == j6_proto_vfs_file)
if (tag == j6_proto_vfs_file) {
size = 0;
// Get the size into `size`
s = j6_vma_resize(vma, &size);
if (s != j6_status_ok)
return s;
return j6_status_ok; // handle is already in `vma`
}
else if (tag == j6_proto_base_status)
return *reinterpret_cast<j6_status_t*>(data); // contains a status

View File

@@ -1,6 +1,7 @@
#include <stddef.h>
#include <stdint.h>
#include <j6/errors.h>
#include <j6/flags.h>
#include <j6/syscalls.h>
namespace __j6libc {
@@ -21,7 +22,7 @@ void * increase_core(intptr_t i)
if (i < 0)
return (void*)-1;
j6_status_t result = j6_vma_create_map(&core_handle, i, &core_base, 1);
j6_status_t result = j6_vma_create_map(&core_handle, i, &core_base, j6_vm_flag_write);
if (result != j6_status_ok)
return (void*)-1;

View File

@@ -2,6 +2,7 @@
module("util",
kind = "lib",
static = True,
sources = [
"cdb.cpp",
"bip_buffer.cpp",

369
src/user/ld.so/image.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include <stdlib.h>
#include <elf/file.h>
#include <j6/errors.h>
#include <j6/flags.h>
#include <j6/memutils.h>
#include <j6/protocols/vfs.hh>
#include <j6/syscalls.h>
#include <j6/syslog.hh>
#include <util/format.h>
#include "image.h"
#include "j6/types.h"
#include "relocate.h"
#include "symbols.h"
extern "C" void _ldso_plt_lookup();
extern image_list all_images;
// Can't use strcmp because it's from another library, and
// this needs to be used as part of relocation or symbol lookup
static inline bool
str_equal(const char *a, const char *b)
{
if (!a || !b)
return a == b;
size_t i = 0;
while(a[i] && b[i] && a[i] == b[i]) ++i;
return a[i] == b[i];
}
static inline uint32_t
gnu_hash_func(const char *s)
{
uint32_t h = 5381;
while (s && *s)
h = (h<<5) + h + *s++;
return h;
}
inline image_list::item_type *
new_image(const char *name)
{
// Use malloc() instead of new to simplify linkage
image_list::item_type *i = reinterpret_cast<image_list::item_type*>(malloc(sizeof(*i)));
i->base = 0;
i->name = name;
i->got = nullptr;
return i;
}
static uintptr_t
load_image(image_list::item_type &img, j6::proto::vfs::client &vfs)
{
uintptr_t eop = 0; // end of program
char path [1024];
util::format({path, sizeof(path)}, "/jsix/lib/%s", img.name);
size_t file_size = 0;
j6_handle_t vma = j6_handle_invalid;
j6_status_t r = vfs.load_file(path, vma, file_size);
if (r != j6_status_ok) {
j6::syslog("Error %d opening %s", r, path);
return 0;
}
uintptr_t file_addr = 0;
r = j6_vma_map(vma, 0, &file_addr, 0);
if (r != j6_status_ok) {
j6::syslog("Error %d opening %s", r, path);
return 0;
}
elf::file file { util::const_buffer::from(file_addr, file_size) };
if (!file.valid(elf::filetype::shared)) {
j6::syslog("Error opening %s: Not an ELF shared object", path);
return 0;
}
for (auto &seg : file.segments()) {
if (seg.type == elf::segment_type::dynamic) {
const dyn_entry *table =
reinterpret_cast<const dyn_entry*>(img.base + seg.vaddr);
img.read_dyn_table(table);
}
if (seg.type != elf::segment_type::load)
continue;
// TODO: way to remap VMA as read-only if there's no write flag on
// the segment
unsigned long flags = j6_vm_flag_exact | j6_vm_flag_write;
if (seg.flags && elf::segment_flags::exec)
flags |= j6_vm_flag_exec;
uintptr_t start = file.base() + seg.offset;
size_t prologue = seg.vaddr & 0xfff;
size_t epilogue = seg.mem_size - seg.file_size;
uintptr_t addr = (img.base + seg.vaddr) & ~0xfffull;
j6_handle_t sub_vma = j6_handle_invalid;
j6_status_t res = j6_vma_create_map(&sub_vma, seg.mem_size+prologue, &addr, flags);
if (res != j6_status_ok) {
j6::syslog(" ** error loading ELF '%s': creating sub vma: %lx", path, res);
return 0;
}
uint8_t *src = reinterpret_cast<uint8_t *>(start);
uint8_t *dest = reinterpret_cast<uint8_t *>(addr);
memset(dest, 0, prologue);
memcpy(dest+prologue, src, seg.file_size);
memset(dest+prologue+seg.file_size, 0, epilogue);
// end of segment
uintptr_t eos = addr + seg.vaddr + seg.mem_size + prologue;
if (eos > eop)
eop = eos;
}
j6_vma_unmap(vma, 0);
return eop;
}
void
image::read_dyn_table(dyn_entry const *table)
{
size_t dynrel_size = 0;
size_t sizeof_rela = sizeof(rela);
size_t jmprel_size = 0;
size_t soname_index = 0;
bool parsing = true;
while (parsing) {
const dyn_entry &dyn = *table++;
switch (dyn.tag) {
case dyn_type::null:
parsing = false;
break;
case dyn_type::pltrelsz:
jmprel_size = dyn.value;
break;
case dyn_type::pltgot:
got = reinterpret_cast<uintptr_t*>(dyn.value + base);
break;
case dyn_type::strtab:
strtab.pointer = reinterpret_cast<char const*>(dyn.value + base);
break;
case dyn_type::symtab:
dynsym = reinterpret_cast<const symbol*>(dyn.value + base);
break;
case dyn_type::rela:
dynrel.pointer = reinterpret_cast<rela const*>(dyn.value + base);
break;
case dyn_type::relasz:
dynrel_size = dyn.value;
break;
case dyn_type::relaent:
sizeof_rela = dyn.value;
break;
case dyn_type::strsz:
strtab.count = dyn.value;
break;
case dyn_type::jmprel:
jmprel.pointer = reinterpret_cast<rela const*>(dyn.value + base);
break;
case dyn_type::gnu_hash:
gnu_hash = reinterpret_cast<const gnu_hash_table*>(dyn.value + base);
break;
case dyn_type::soname:
soname_index = dyn.value;
break;
default:
break;
}
}
if (dynrel_size && sizeof_rela)
dynrel.count = dynrel_size / sizeof_rela;
if (jmprel_size && sizeof_rela)
jmprel.count = jmprel_size / sizeof_rela;
if (soname_index && strtab)
name = string(soname_index);
}
uintptr_t
image::lookup(const char *name) const
{
if (!gnu_hash || !dynsym || !strtab.pointer)
return 0;
// Convenience references
const gnu_hash_table &gh = *gnu_hash;
uint32_t h = gnu_hash_func(name);
// Check bloom filter
static constexpr uint64_t bloom_bits = 6;
static constexpr uint64_t mask = (1ull << bloom_bits) - 1;
uint64_t bloom_index = (h >> bloom_bits) % gh.bloom_count;
uint64_t bloom = gh.bloom[bloom_index];
uint64_t test = (1ull << (h & mask)) | (1ull << ((h >> gh.bloom_shift) & mask));
if ((bloom & test) != test)
return 0;
const uint32_t *buckets = reinterpret_cast<const uint32_t*>(
&gh.bloom[gh.bloom_count]);
const uint32_t *chains = &buckets[gh.bucket_count];
uint32_t i = buckets[h % gh.bucket_count];
if (i < gh.start_symbol)
return 0;
while (true) {
const symbol &sym = dynsym[i];
const char *sym_name = strtab.lookup(sym.name);
uint32_t sym_hash = chains[i - gh.start_symbol];
// Low bit is used to mark end-of-chain
if ((h|1) == (sym_hash|1) && str_equal(name, sym_name))
return base + sym.address;
if (sym_hash & 1)
break;
++i;
}
return 0;
}
void
add_needed_entries(image &img, image_list &open, image_list &closed)
{
dyn_entry const *dyn = img.dyn_table();
while (dyn->tag != dyn_type::null) {
if (dyn->tag == dyn_type::needed) {
const char *name = img.string(dyn->value);
if (!open.find_image(name) && !closed.find_image(name))
open.push_back(new_image(name));
}
++dyn;
}
}
void
image_list::load(j6_handle_t vfs_mb, uintptr_t addr)
{
image_list open;
j6::proto::vfs::client vfs {vfs_mb};
for (auto *img : *this)
add_needed_entries(*img, open, *this);
while (!open.empty()) {
image_list::item_type *img = open.pop_front();
img->base = addr;
// Load the file
addr = load_image(*img, vfs);
if (!img->got) {
j6::syslog("Error opening %s: Could not find GOT", img->name);
return;
}
j6::syslog("Loaded %s at base address 0x%x", img->name, img->base);
addr = (addr & ~0xffffull) + 0x10000;
// Find the DT_NEEDED entries
add_needed_entries(*img, open, *this);
push_back(img);
}
for (auto *img : *this)
img->relocate(*this);
}
void
image::parse_rela_table(const util::counted<const rela> &table, image_list &ctx)
{
for (size_t i = 0; i < table.count; ++i) {
const rela &rel = table[i];
const symbol *sym_obj = dynsym ? &dynsym[rel.symbol] : nullptr;
const char *sym_name = sym_obj ? string(sym_obj->name) : nullptr;
uintptr_t sym_addr = sym_name && *sym_name ? ctx.resolve(sym_name) : 0;
switch (rel.type)
{
case reloc::glob_dat:
case reloc::jump_slot:
*reinterpret_cast<uint64_t*>(rel.address + base) = sym_addr;
break;
case reloc::relative:
*reinterpret_cast<uint64_t*>(rel.address + base) = base + rel.offset;
break;
default:
j6::syslog("Unknown rela relocation type %d in %s", rel.type, name);
exit(126);
break;
}
}
}
void
image::relocate(image_list &ctx)
{
if (relocated)
return;
parse_rela_table(dynrel, ctx);
parse_rela_table(jmprel, ctx);
got[1] = reinterpret_cast<uintptr_t>(this);
got[2] = reinterpret_cast<uintptr_t>(&_ldso_plt_lookup);
relocated = true;
}
image_list::item_type *
image_list::find_image(const char *name)
{
for (auto *i : *this) {
if (str_equal(i->name, name))
return i;
}
return nullptr;
}
uintptr_t
image_list::resolve(const char *name)
{
for (auto *img : *this) {
uintptr_t addr = img->lookup(name);
if (addr) return addr;
}
return 0;
}
extern "C" uintptr_t
ldso_plt_lookup(const image *img, unsigned jmprel_index)
{
const rela &rel = img->jmprel[jmprel_index];
const symbol &sym = img->dynsym[rel.symbol];
const char *name = img->string(sym.name);
uintptr_t addr = all_images.resolve(name);
return addr;
}

67
src/user/ld.so/image.h Normal file
View File

@@ -0,0 +1,67 @@
#pragma once
/// \file image.h
/// Definition of a class representing a loaded ELF image
#include <stdint.h>
#include <j6/types.h>
#include <util/counted.h>
#include <util/linked_list.h>
#include "symbols.h"
struct dyn_entry;
struct string_table;
struct rela;
struct image_list;
struct image
{
uintptr_t base;
const char *name;
uintptr_t *got;
string_table strtab;
util::counted<rela const> jmprel;
util::counted<rela const> dynrel;
symbol const *dynsym = nullptr;
gnu_hash_table const *gnu_hash = nullptr;
bool relocated = false;
/// Look up a string table entry in this image's string table.
const char * string(unsigned index) const {
if (index > strtab.count) return nullptr;
return strtab.pointer + index;
}
/// Get the address of the DYNAMIC table
inline const dyn_entry *dyn_table() const {
return reinterpret_cast<const dyn_entry*>(got[0] + base);
}
void read_dyn_table(dyn_entry const *table = nullptr);
/// Do all relocation on this image
void relocate(image_list &ctx);
/// Do the relocations from a single table
void parse_rela_table(const util::counted<const rela> &table, image_list &ctx);
/// Look up a symbol in this image's symbol table, and return an address
/// if it is defined, or otherwise 0.
uintptr_t lookup(const char *name) const;
};
struct image_list :
public util::linked_list<image>
{
/// Resolve a symbol name to an address, respecting library load order
uintptr_t resolve(const char *symbol);
/// Recursively load images and return an image_list
void load(j6_handle_t vfs_mb, uintptr_t addr);
/// Find an image with the given name in the list, or return null.
item_type * find_image(const char *name);
};

View File

@@ -8,8 +8,8 @@ ldso = module("ld.so",
deps = [ "libc", "util", "elf" ],
description = "Dynamic Linker",
sources = [
"image.cpp",
"main.cpp",
"relocate.cpp",
"start.s",
])

View File

@@ -3,32 +3,16 @@
#include <elf/headers.h>
#include <j6/init.h>
#include <j6/protocols/vfs.hh>
#include <j6/syslog.hh>
#include <util/pointers.h>
#include "relocate.h"
uintptr_t
locate_dyn_section(uintptr_t base, uintptr_t phdr, size_t phdr_size, size_t phdr_count)
{
if (!phdr || !phdr_count)
return 0;
#include "image.h"
const elf::segment_header *ph_base =
reinterpret_cast<const elf::segment_header*>(phdr + base);
for (size_t i = 0; i < phdr_count; ++i) {
const elf::segment_header *ph =
util::offset_pointer(ph_base, i*phdr_size);
if (ph->type == elf::segment_type::dynamic)
return ph->vaddr;
}
return 0;
}
image_list all_images;
extern "C" uintptr_t
ldso_init(j6_arg_header *stack_args, uintptr_t const *got)
ldso_init(j6_arg_header *stack_args, uintptr_t *got)
{
j6_arg_loader *arg_loader = nullptr;
j6_arg_handles *arg_handles = nullptr;
@@ -57,14 +41,37 @@ ldso_init(j6_arg_header *stack_args, uintptr_t const *got)
exit(127);
}
relocate_image(arg_loader->loader_base, got[0]);
j6_handle_t vfs = j6_handle_invalid;
if (arg_handles) {
for (size_t i = 0; i < arg_handles->nhandles; ++i) {
j6_arg_handle_entry &ent = arg_handles->handles[i];
if (ent.proto == j6::proto::vfs::id) {
vfs = ent.handle;
break;
}
}
}
uintptr_t dyn_section = locate_dyn_section(
arg_loader->image_base,
arg_loader->phdr,
arg_loader->phdr_size,
arg_loader->phdr_count);
relocate_image(arg_loader->image_base, dyn_section);
// First relocate ld.so itself. It cannot have any dependencies
image_list::item_type ldso_image;
ldso_image.base = arg_loader->loader_base;
ldso_image.got = got;
ldso_image.read_dyn_table(
reinterpret_cast<const dyn_entry*>(got[0] + arg_loader->loader_base));
image_list just_ldso;
just_ldso.push_back(&ldso_image);
ldso_image.relocate(just_ldso);
image_list::item_type target_image;
target_image.base = arg_loader->image_base;
target_image.got = arg_loader->got;
target_image.read_dyn_table(
reinterpret_cast<const dyn_entry*>(arg_loader->got[0] + arg_loader->image_base));
all_images.push_back(&target_image);
all_images.load(vfs, 0xb00'0000);
return arg_loader->entrypoint + arg_loader->image_base;
}
}

View File

@@ -1,155 +0,0 @@
#include <stdlib.h>
#include <j6/syslog.hh>
#include <util/counted.h>
#include "relocate.h"
enum class dyn_type : uint64_t {
null, needed, pltrelsz, pltgot, hash, strtab, symtab, rela, relasz, relaent,
strsz, syment, init, fini, soname, rpath, symbolic, rel, relsz, relent, pltrel,
debug, textrel, jmprel, bind_now, init_array, fini_array, init_arraysz, fini_arraysz,
gnu_hash = 0x6ffffef5, relacount = 0x6ffffff9,
};
struct dyn_entry {
dyn_type tag;
uintptr_t value;
};
struct dyn_values {
uintptr_t pltrelsz;
uintptr_t pltgot;
uintptr_t hash;
uintptr_t pltrel;
uintptr_t strtab;
uintptr_t symtab;
uintptr_t rela;
uintptr_t relasz;
uintptr_t relaent;
uintptr_t strsz;
uintptr_t syment;
uintptr_t jmprel;
uintptr_t relacount;
};
#define read_dyn_value(name) \
case dyn_type::name: \
values.name = dyn.value; \
break;
void
read_dynamic_values(uintptr_t base, uintptr_t dyn_section, dyn_values &values)
{
const dyn_entry *dyns = reinterpret_cast<const dyn_entry*>(dyn_section + base);
unsigned i = 0;
while (true) {
const dyn_entry &dyn = dyns[i++];
switch (dyn.tag) {
case dyn_type::null:
return;
read_dyn_value(pltrelsz);
read_dyn_value(pltgot);
read_dyn_value(pltrel);
read_dyn_value(strtab);
read_dyn_value(symtab);
read_dyn_value(rela);
read_dyn_value(relasz);
read_dyn_value(relaent);
read_dyn_value(strsz);
read_dyn_value(syment);
read_dyn_value(jmprel);
read_dyn_value(relacount);
case dyn_type::gnu_hash:
values.hash = dyn.value;
break;
default:
break;
}
}
}
#undef read_dyn_value(name)
class string_table :
private util::counted<const char>
{
public:
string_table(const char *start, size_t size) :
util::counted<const char> {start, size} {}
const char *lookup(size_t offset) {
if (offset > count) return nullptr;
return pointer + offset;
}
};
struct symbol
{
uint32_t name;
uint8_t type : 4;
uint8_t binding : 4;
uint8_t _reserved0;
uint16_t section;
uintptr_t address;
size_t size;
};
struct gnu_hash_table
{
uint32_t bucket_count;
uint32_t start_symbol;
uint32_t bloom_count;
uint32_t bloom_shift;
uint64_t bloom [0];
};
enum class reloc : uint32_t {
relative = 8,
};
struct rela
{
uintptr_t address;
reloc type;
uint32_t symbol;
ptrdiff_t offset;
};
template <typename T> T off(uintptr_t p, uintptr_t base) { return reinterpret_cast<T>(p ? p + base : 0); }
void
relocate_image(uintptr_t base, uintptr_t dyn_section)
{
dyn_values values = {0};
read_dynamic_values(base, dyn_section, values);
string_table strtab {
reinterpret_cast<const char *>(values.strtab + base),
values.strsz,
};
symbol *symtab = off<symbol *>(values.symtab, base);
gnu_hash_table *hashtab = off<gnu_hash_table *>(values.hash, base);
uintptr_t *jmprel = off<uintptr_t *>(values.jmprel, base);
uintptr_t *plt = off<uintptr_t *>(values.pltgot, base);
size_t nrela = values.relacount;
for (size_t i = 0; i < values.relacount; ++i) {
rela *rel = off<rela*>(values.rela + i * values.relaent, base);
switch (rel->type)
{
case reloc::relative:
*reinterpret_cast<uint64_t*>(rel->address + base) = base + rel->offset;
break;
default:
j6::syslog("Unknown relocation type %d", rel->type);
exit(126);
break;
}
}
}

View File

@@ -2,6 +2,31 @@
/// \file relocate.h
/// Image relocation services
#include <stddef.h>
#include <stdint.h>
void relocate_image(uintptr_t base, uintptr_t dyn_section);
enum class dyn_type : uint64_t {
null, needed, pltrelsz, pltgot, hash, strtab, symtab, rela, relasz, relaent,
strsz, syment, init, fini, soname, rpath, symbolic, rel, relsz, relent, pltrel,
debug, textrel, jmprel, bind_now, init_array, fini_array, init_arraysz, fini_arraysz,
gnu_hash = 0x6ffffef5, relacount = 0x6ffffff9,
};
struct dyn_entry {
dyn_type tag;
uintptr_t value;
};
enum class reloc : uint32_t {
glob_dat = 6,
jump_slot = 7,
relative = 8,
};
struct rela
{
uintptr_t address;
reloc type;
uint32_t symbol;
ptrdiff_t offset;
};

View File

@@ -1,4 +1,5 @@
extern ldso_init
extern ldso_plt_lookup
extern _GLOBAL_OFFSET_TABLE_
global _ldso_start:function hidden (_ldso_start.end - _ldso_start)
@@ -30,4 +31,34 @@ _ldso_start:
pop rdi
jmp rax
.end:
.end:
global _ldso_plt_lookup:function hidden (_ldso_plt_lookup.end - _ldso_plt_lookup)
_ldso_plt_lookup:
pop rax ; image struct address
pop r11 ; jmprel entry index
; Save off anything that might be a function arg
push rdi
push rsi
push rdx
push rcx
push r8
push r9
mov rdi, rax
mov rsi, r11
call ldso_plt_lookup
; The function's address is now in rax
; Put the function call params back
pop r9
pop r8
pop rcx
pop rdx
pop rsi
pop rdi
jmp rax
.end:

36
src/user/ld.so/symbols.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
/// \file symbols.h
/// Symbol lookup routines and related data structures
#include <stdint.h>
#include <util/counted.h>
class string_table :
public util::counted<char const>
{
public:
const char *lookup(size_t offset) const {
if (offset > count) return nullptr;
return pointer + offset;
}
};
struct symbol
{
uint32_t name;
uint8_t type : 4;
uint8_t binding : 4;
uint8_t _reserved0;
uint16_t section;
uintptr_t address;
size_t size;
};
struct gnu_hash_table
{
uint32_t bucket_count;
uint32_t start_symbol;
uint32_t bloom_count;
uint32_t bloom_shift;
uint64_t bloom [0];
};

View File

@@ -26,7 +26,7 @@ handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
fs.load_inode_data(in, dest);
j6_vma_unmap(vma, 0);
return j6_err_nyi;
return j6_status_ok;
}
void

View File

@@ -65,7 +65,7 @@ stack_push(uint8_t *&stack, size_t extra)
uintptr_t
load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const char *path)
{
uintptr_t eop = 0;
uintptr_t eop = 0; // end of program
for (auto &seg : file.segments()) {
if (seg.type != elf::segment_type::load)
@@ -96,6 +96,7 @@ load_program_into(j6_handle_t proc, elf::file &file, uintptr_t image_base, const
memcpy(dest+prologue, src, seg.file_size);
memset(dest+prologue+seg.file_size, 0, epilogue);
// end of segment
uintptr_t eos = image_base + seg.vaddr + seg.mem_size + prologue;
if (eos > eop)
eop = eos;
@@ -219,12 +220,16 @@ load_program(
j6_arg_loader *loader_arg = stack_push<j6_arg_loader>(stack, 0);
const elf::file_header *h = program_elf.header();
loader_arg->image_base = program_image_base;
loader_arg->phdr = h->ph_offset;
loader_arg->phdr_count = h->ph_num;
loader_arg->entrypoint = entrypoint;
const elf::section_header *got_section = program_elf.get_section_by_name(".got.plt");
if (got_section)
loader_arg->got = reinterpret_cast<uintptr_t*>(program_image_base + got_section->addr);
// The dynamic linker will offset the entrypoint, don't do it here.
loader_arg->entrypoint = program_elf.entrypoint();
j6_arg_handles *handles_arg = stack_push<j6_arg_handles>(stack, 2 * sizeof(j6_arg_handle_entry));
handles_arg->nhandles = 1;
handles_arg->nhandles = 2;
handles_arg->handles[0].handle = slp;
handles_arg->handles[0].proto = j6::proto::sl::id;
handles_arg->handles[1].handle = vfs;
@@ -268,8 +273,9 @@ load_program(
}
j6_handle_t thread = j6_handle_invalid;
ptrdiff_t stack_consumed = stack_orig - stack;
res = j6_thread_create(&thread, proc, stack_top - stack_consumed, entrypoint, program_image_base, 0);
uintptr_t target_stack = stack_top - (stack_orig - stack);
target_stack &= ~0xfull; // Align to 16-byte stack
res = j6_thread_create(&thread, proc, target_stack, entrypoint, program_image_base, 0);
if (res != j6_status_ok) {
j6::syslog(" ** error loading program '%s': creating thread: %lx", path, res);
return false;