diff --git a/assets/build/target.user.shared.yaml b/assets/build/target.user.shared.yaml new file mode 100644 index 0000000..666830b --- /dev/null +++ b/assets/build/target.user.shared.yaml @@ -0,0 +1,7 @@ +--- +ccflags: [ +] + +ldflags: [ + "-shared", +] diff --git a/src/libraries/j6/include/j6/init.h b/src/libraries/j6/include/j6/init.h index a257263..b5dcef1 100644 --- a/src/libraries/j6/include/j6/init.h +++ b/src/libraries/j6/include/j6/init.h @@ -2,7 +2,9 @@ /// \file init.h /// Process initialization utility functions +#include #include + #include #include @@ -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 \ No newline at end of file +#undef add_header diff --git a/src/libraries/j6/include/j6/protocols/vfs.hh b/src/libraries/j6/include/j6/protocols/vfs.hh index e02e799..4699234 100644 --- a/src/libraries/j6/include/j6/protocols/vfs.hh +++ b/src/libraries/j6/include/j6/protocols/vfs.hh @@ -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; diff --git a/src/libraries/j6/init.cpp b/src/libraries/j6/init.cpp index c89f557..1befef1 100644 --- a/src/libraries/j6/init.cpp +++ b/src/libraries/j6/init.cpp @@ -10,7 +10,7 @@ #include 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 diff --git a/src/libraries/j6/protocols/vfs.cpp b/src/libraries/j6/protocols/vfs.cpp index 6b17ec3..fd87a3c 100644 --- a/src/libraries/j6/protocols/vfs.cpp +++ b/src/libraries/j6/protocols/vfs.cpp @@ -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(data); // contains a status diff --git a/src/libraries/libc/__j6libc/increase_core.cpp b/src/libraries/libc/__j6libc/increase_core.cpp index f23cb8c..991c548 100644 --- a/src/libraries/libc/__j6libc/increase_core.cpp +++ b/src/libraries/libc/__j6libc/increase_core.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include 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; diff --git a/src/libraries/util/util.module b/src/libraries/util/util.module index a1049a9..9a002ab 100644 --- a/src/libraries/util/util.module +++ b/src/libraries/util/util.module @@ -2,6 +2,7 @@ module("util", kind = "lib", + static = True, sources = [ "cdb.cpp", "bip_buffer.cpp", diff --git a/src/user/ld.so/image.cpp b/src/user/ld.so/image.cpp new file mode 100644 index 0000000..7e598f3 --- /dev/null +++ b/src/user/ld.so/image.cpp @@ -0,0 +1,369 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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(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(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(start); + uint8_t *dest = reinterpret_cast(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(dyn.value + base); + break; + + case dyn_type::strtab: + strtab.pointer = reinterpret_cast(dyn.value + base); + break; + + case dyn_type::symtab: + dynsym = reinterpret_cast(dyn.value + base); + break; + + case dyn_type::rela: + dynrel.pointer = reinterpret_cast(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(dyn.value + base); + break; + + case dyn_type::gnu_hash: + gnu_hash = reinterpret_cast(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( + &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 &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(rel.address + base) = sym_addr; + break; + + case reloc::relative: + *reinterpret_cast(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(this); + got[2] = reinterpret_cast(&_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; +} diff --git a/src/user/ld.so/image.h b/src/user/ld.so/image.h new file mode 100644 index 0000000..e1d04fb --- /dev/null +++ b/src/user/ld.so/image.h @@ -0,0 +1,67 @@ +#pragma once +/// \file image.h +/// Definition of a class representing a loaded ELF image + +#include +#include +#include +#include + +#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 jmprel; + util::counted 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(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 &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 +{ + /// 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); +}; diff --git a/src/user/ld.so/ld.so.module b/src/user/ld.so/ld.so.module index fe79419..5942274 100644 --- a/src/user/ld.so/ld.so.module +++ b/src/user/ld.so/ld.so.module @@ -8,8 +8,8 @@ ldso = module("ld.so", deps = [ "libc", "util", "elf" ], description = "Dynamic Linker", sources = [ + "image.cpp", "main.cpp", - "relocate.cpp", "start.s", ]) diff --git a/src/user/ld.so/main.cpp b/src/user/ld.so/main.cpp index 01c3b8e..3dda4ec 100644 --- a/src/user/ld.so/main.cpp +++ b/src/user/ld.so/main.cpp @@ -3,32 +3,16 @@ #include #include +#include #include #include -#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(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(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(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; -} \ No newline at end of file +} diff --git a/src/user/ld.so/relocate.cpp b/src/user/ld.so/relocate.cpp deleted file mode 100644 index 8bf1c03..0000000 --- a/src/user/ld.so/relocate.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include -#include -#include -#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(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 -{ -public: - string_table(const char *start, size_t size) : - util::counted {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 T off(uintptr_t p, uintptr_t base) { return reinterpret_cast(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(values.strtab + base), - values.strsz, - }; - - symbol *symtab = off(values.symtab, base); - gnu_hash_table *hashtab = off(values.hash, base); - - uintptr_t *jmprel = off(values.jmprel, base); - uintptr_t *plt = off(values.pltgot, base); - - size_t nrela = values.relacount; - for (size_t i = 0; i < values.relacount; ++i) { - rela *rel = off(values.rela + i * values.relaent, base); - switch (rel->type) - { - case reloc::relative: - *reinterpret_cast(rel->address + base) = base + rel->offset; - break; - - default: - j6::syslog("Unknown relocation type %d", rel->type); - exit(126); - break; - } - } -} \ No newline at end of file diff --git a/src/user/ld.so/relocate.h b/src/user/ld.so/relocate.h index 30d9003..d169523 100644 --- a/src/user/ld.so/relocate.h +++ b/src/user/ld.so/relocate.h @@ -2,6 +2,31 @@ /// \file relocate.h /// Image relocation services +#include #include -void relocate_image(uintptr_t base, uintptr_t dyn_section); \ No newline at end of file +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; +}; diff --git a/src/user/ld.so/start.s b/src/user/ld.so/start.s index bbc2c77..73fdbd5 100644 --- a/src/user/ld.so/start.s +++ b/src/user/ld.so/start.s @@ -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: \ No newline at end of file +.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: diff --git a/src/user/ld.so/symbols.h b/src/user/ld.so/symbols.h new file mode 100644 index 0000000..f4b90e9 --- /dev/null +++ b/src/user/ld.so/symbols.h @@ -0,0 +1,36 @@ +#pragma once +/// \file symbols.h +/// Symbol lookup routines and related data structures + +#include +#include + +class string_table : + public util::counted +{ +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]; +}; diff --git a/src/user/srv.init/initfs.cpp b/src/user/srv.init/initfs.cpp index 4bd3a28..9f6ca50 100644 --- a/src/user/srv.init/initfs.cpp +++ b/src/user/srv.init/initfs.cpp @@ -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 diff --git a/src/user/srv.init/loader.cpp b/src/user/srv.init/loader.cpp index 0cb0770..e0c06b6 100644 --- a/src/user/srv.init/loader.cpp +++ b/src/user/srv.init/loader.cpp @@ -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(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(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(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;