Skip to content

TibboddiT/dyn-loader

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

39 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Loading dynamic libraries from non libc static executable - Proof of concept

Warning: prototype quality: lots of bugs, lots of TODOs remaining.

Tested on x86_64-linux-gnu, with libraries compiled agasint glibc 2.41. Seems to also work on libraries compiled agasint musl, with a lightly patched libc.so version for now (cf. Notes).

See this thread for further information.

Usage

const std = @import("std");
const dll = @import("dll");

pub const debug = struct {
    pub const SelfInfo = dll.CustomSelfInfo;
};

pub fn main() !void {
    var gpa: std.heap.DebugAllocator(.{}) = .init;
    const allocator = gpa.allocator();
    defer if (gpa.deinit() != .ok) @panic("memory check failed");

    // `dll` is a singleton, it should be initialized early and only once, on the main thread
    try dll.init(.{ .allocator = allocator, .log_level = .warn });
    defer dll.deinit();

    const lib_c = try dll.load("libc.so.6");

    const printf_sym = try lib_c.getSymbol("printf");
    const printf_addr = printf_sym.addr;
    const printf: *const fn ([*:0]const u8, ...) callconv(.c) c_int = @ptrFromInt(printf_addr);

    _ = printf("Hello, %s!\n", "World");
}

Current limitations

  • Libraries that dlopen other libraries might not behave correctly until:
    • all dl public API functions (like dladdr) are implemented
  • Even some dl not so private functions need an implementation, mainly because C++ exception handling (sad) might call them... (for instance _dl_find_object)
  • Loading libraries should be done before having started any thread.
  • Starting threads in zig land and in library land needs to be tested.
  • Some (rare) relocation types are still missing.
  • You should not link any libc (it is part of the goal anyway).

Notes

A custom musl's libc.so is included, which is a patched version of musl 1.25. You should load it first before loading libraries compiled against musl (see the musl printf example). The library is stripped (strip --strip-unneeded lib/libc.so) as it is often the case when it is packaged for linux distros.

The patch is:

diff --git a/original/musl-1.2.5/ldso/dynlink.c b/musl-1.2.5/ldso/dynlink.c
index 324aa85..bfc5140 100644
--- a/original/musl-1.2.5/ldso/dynlink.c
+++ b/musl-1.2.5/ldso/dynlink.c
@@ -1767,6 +1767,14 @@ hidden void __dls2(unsigned char *base, size_t *sp)
        else ((stage3_func)laddr(&ldso, dls2b_def.sym->st_value))(sp, auxv);
 }
 
+extern void __pre_dls2b(size_t *auxv)
+{
+       search_vec(auxv, &__hwcap, AT_HWCAP);
+       libc.auxv = auxv;
+       libc.tls_size = sizeof builtin_tls;
+       libc.tls_align = tls_align;
+}
+
 /* Stage 2b sets up a valid thread pointer, which requires relocations
  * completed in stage 2, and on which stage 3 is permitted to depend.
  * This is done as a separate stage, with symbolic lookup as a barrier,
@@ -1775,13 +1783,11 @@ hidden void __dls2(unsigned char *base, size_t *sp)
 
 void __dls2b(size_t *sp, size_t *auxv)
 {
+       __pre_dls2b(auxv);
+
        /* Setup early thread pointer in builtin_tls for ldso/libc itself to
         * use during dynamic linking. If possible it will also serve as the
         * thread pointer at runtime. */
-       search_vec(auxv, &__hwcap, AT_HWCAP);
-       libc.auxv = auxv;
-       libc.tls_size = sizeof builtin_tls;
-       libc.tls_align = tls_align;
        if (__init_tp(__copy_tls((void *)builtin_tls)) < 0) {
                a_crash();
        }

An unpatched copy of libvulkan.so.1.4.326 from the Alpine repository is also included (renamed libvulkan.so.1).

Both are in the resources/musl directory. It is recommended that you produce those binary artifacts by yourself.

Run examples

zig build run-printf
zig build run-vulkan_version
zig build run-vulkan_version_musl
zig build run-x11_window

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages