# Loading \`libvulkan.so.1\` on Linux with \`std.ElfDynLib\`

**URL:** <https://ziggit.dev/t/loading-libvulkan-so-1-on-linux-with-std-elfdynlib/8480>\
**Category:** Brainstorming\
**Created:** [February 10, 2025, 10:01pm UTC](https://ziggit.dev/t/loading-libvulkan-so-1-on-linux-with-std-elfdynlib/8480 "2025-02-10T22:01:32Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![geemili](https://ziggit.dev/user_avatar/ziggit.dev/geemili/32/1277_2.png) [@geemili](https://ziggit.dev/u/geemili)\
**Post date:** [February 14, 2025, 2:59am UTC](https://ziggit.dev/t/loading-libvulkan-so-1-on-linux-with-std-elfdynlib/8480/3 "2025-02-14T02:59:32Z")

</div>

- [Implemented some relocations · 9f912fbcbc - geemili/dlopen-mesa-with-zig - Codeberg.org](https://codeberg.org/geemili/dlopen-mesa-with-zig/commit/9f912fbcbccd629fea10a033e7bbf9e795c6b386)

Spent some time on this today; and I got it to the point where it’s recursively loading libraries and applying relocations. I hope I’m doing the relocations correctly, I haven’t made a test program to check. Maybe I should do that.

Currently stuck at handling relocations that have to do with thread local storage:

```console
debug: needed library: 0x1c73 libc.so.6
debug: needed library: 0x869c ld-linux-x86-64.so.2
debug: ld-linux-x86-64.so.2 loaded at 0x712c95391000 - 0x712c953c9310
warning: unhandled relocation(libc.so.6)[0001]: 0x001e7c68 <- "" (0x0)	elf.R_X86_64.TPOFF64	56
warning: unhandled relocation(libc.so.6)[0002]: 0x001e7c70 <- "" (0x0)	elf.R_X86_64.TPOFF64	48
warning: unhandled relocation(libc.so.6)[0003]: 0x001e7c78 <- "" (0x0)	elf.R_X86_64.TPOFF64	72
warning: unhandled relocation(libc.so.6)[0004]: 0x001e7c80 <- "" (0x0)	elf.R_X86_64.TPOFF64	88
warning: unhandled relocation(libc.so.6)[0005]: 0x001e7c88 <- "" (0x0)	elf.R_X86_64.TPOFF64	80
warning: unhandled relocation(libc.so.6)[0006]: 0x001e7c90 <- "" (0x0)	elf.R_X86_64.TPOFF64	100
warning: unhandled relocation(libc.so.6)[0007]: 0x001e7c98 <- "" (0x0)	elf.R_X86_64.TPOFF64	120
warning: unhandled relocation(libc.so.6)[0008]: 0x001e7ca0 <- "" (0x0)	elf.R_X86_64.TPOFF64	128
warning: unhandled relocation(libc.so.6)[0009]: 0x001e7cc0 <- "" (0x0)	elf.R_X86_64.TPOFF64	24
warning: unhandled relocation(libc.so.6)[0010]: 0x001e7cd8 <- "" (0x0)	elf.R_X86_64.TPOFF64	40
warning: unhandled relocation(libc.so.6)[0011]: 0x001e7cf0 <- "" (0x0)	elf.R_X86_64.TPOFF64	16
warning: unhandled relocation(libc.so.6)[0012]: 0x001e7d78 <- "" (0x0)	elf.R_X86_64.TPOFF64	96
warning: unhandled relocation(libc.so.6)[0013]: 0x001e7ef8 <- "" (0x0)	elf.R_X86_64.TPOFF64	0
warning: unhandled relocation(libc.so.6)[0014]: 0x001e7fd8 <- "" (0x0)	elf.R_X86_64.TPOFF64	8
warning: unhandled relocation(libc.so.6)[0015]: 0x001e7ff0 <- "" (0x0)	elf.R_X86_64.TPOFF64	32
warning: unhandled relocation(libc.so.6)[0074]: 0x001e7ed0 <- "__libc_dlerror_result" (0x5f7)	elf.R_X86_64.TPOFF64	0
debug: libc.so.6 loaded at 0x712c95402000 - 0x712c955f3c78
debug: libvulkan.so.1 loaded at 0x712c9580e000 - 0x712c958971b0
debug: vkEnumerateInstanceVersion = fn (*u32) callconv(.c) vk.Result@712c958417a0
General protection exception (no address available)
???:?:?: 0x712c954a47af in ??? (???)
Unwind information for `???:0x712c954a47af` was not available, trace may be incomplete

???:?:?: 0x712c954a964c in ??? (???)
???:?:?: 0x712c9583626e in ??? (???)
???:?:?: 0x712c95842461 in ??? (???)
???:?:?: 0x712c958608f8 in ??? (???)
???:?:?: 0x712c958417f0 in ??? (???)
/home/geemili/code/dlopen-mesa-with-zig/src/main.zig:16:46: 0x1049859 in main (dlopen-mesa-with-zig)
    const result = vkEnumerateInstanceVersion(&version);
                                             ^
/home/geemili/code/zig/build-master/stage3/lib/zig/std/start.zig:656:37: 0x104277a in posixCallMainAndExit (dlopen-mesa-with-zig)
            const result = root.main() catch |err| {
                                    ^
/home/geemili/code/zig/build-master/stage3/lib/zig/std/start.zig:271:5: 0x104232d in _start (dlopen-mesa-with-zig)
    asm volatile (switch (native_arch) {
    ^

```

Running it in lldb we get some disassembly:

```console
Process 450185 stopped
* thread #1, name = 'dlopen-mesa-wit', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
    frame #0: 0x00007ffff7b847af
-> 0x7ffff7b847af: movq %rcx, %fs:(%rax)
    0x7ffff7b847b3: addq $0x60, %rcx
    0x7ffff7b847b7: movq %rcx, %rax
    0x7ffff7b847ba: leaq 0x7f0(%rcx), %rdx
(lldb) 

```

I don’t understand how thread local storage works at the moment, so I’ll have to come back to this. I probably also need to handle `.tdata` and `.tbss`.

I am wondering at this point if the system `libc.so.6` could be replaced with a theoretical `ziglibc`. `libvulkan.so.1` itself only uses a couple symbols:

```zig
     0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND 
     1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __strcat_chk@GLIBC_2.3.4 (2)
     2: 0000000000000000 0 FUNC GLOBAL DEFAULT UND getenv@GLIBC_2.2.5 (3)
     3: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __snprintf_chk@GLIBC_2.3.4 (2)
     4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dlerror@GLIBC_2.34 (4)
     5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND free@GLIBC_2.2.5 (3)
     6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND abort@GLIBC_2.2.5 (3)
     7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __errno_location@GLIBC_2.2.5 (3)
     8: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strncpy@GLIBC_2.2.5 (3)
     9: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strncmp@GLIBC_2.2.5 (3)
    10: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
    11: 0000000000000000 0 FUNC GLOBAL DEFAULT UND secure_getenv@GLIBC_2.17 (5)
    12: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __isoc23_sscanf@GLIBC_2.38 (6)
    13: 0000000000000000 0 FUNC GLOBAL DEFAULT UND qsort@GLIBC_2.2.5 (3)
    14: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fread@GLIBC_2.2.5 (3)
    15: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtod@GLIBC_2.2.5 (3)
    16: 0000000000000000 0 FUNC GLOBAL DEFAULT UND readlink@GLIBC_2.2.5 (3)
    17: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fclose@GLIBC_2.2.5 (3)
    18: 0000000000000000 0 FUNC GLOBAL DEFAULT UND opendir@GLIBC_2.2.5 (3)
    19: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strlen@GLIBC_2.2.5 (3)
    20: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __stack_chk_fail@GLIBC_2.4 (7)
    21: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strchr@GLIBC_2.2.5 (3)
    22: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_destroy@GLIBC_2.2.5 (3)
    23: 0000000000000000 0 FUNC GLOBAL DEFAULT UND snprintf@GLIBC_2.2.5 (3)
    24: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strrchr@GLIBC_2.2.5 (3)
    25: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputs@GLIBC_2.2.5 (3)
    26: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memset@GLIBC_2.2.5 (3)
    27: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strncat@GLIBC_2.2.5 (3)
    28: 0000000000000000 0 FUNC GLOBAL DEFAULT UND closedir@GLIBC_2.2.5 (3)
    29: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fputc@GLIBC_2.2.5 (3)
    30: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strcspn@GLIBC_2.2.5 (3)
    31: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strtok_r@GLIBC_2.2.5 (3)
    32: 0000000000000000 0 FUNC GLOBAL DEFAULT UND calloc@GLIBC_2.2.5 (3)
    33: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strcmp@GLIBC_2.2.5 (3)
    34: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dlopen@GLIBC_2.34 (4)
    35: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __memmove_chk@GLIBC_2.3.4 (2)
    36: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __memcpy_chk@GLIBC_2.3.4 (2)
    37: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
    38: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memcpy@GLIBC_2.14 (8)
    39: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __isoc23_strtol@GLIBC_2.38 (6)
    40: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fileno@GLIBC_2.2.5 (3)
    41: 0000000000000000 0 FUNC GLOBAL DEFAULT UND readdir@GLIBC_2.2.5 (3)
    42: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_unlock@GLIBC_2.2.5 (3)
    43: 0000000000000000 0 FUNC GLOBAL DEFAULT UND malloc@GLIBC_2.2.5 (3)
    44: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __vsnprintf_chk@GLIBC_2.3.4 (2)
    45: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __strncpy_chk@GLIBC_2.3.4 (2)
    46: 0000000000000000 0 FUNC GLOBAL DEFAULT UND realloc@GLIBC_2.2.5 (3)
    47: 0000000000000000 0 FUNC GLOBAL DEFAULT UND memmove@GLIBC_2.2.5 (3)
    48: 0000000000000000 0 FUNC GLOBAL DEFAULT UND access@GLIBC_2.2.5 (3)
    49: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fopen@GLIBC_2.2.5 (3)
    50: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dlsym@GLIBC_2.34 (4)
    51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __memset_chk@GLIBC_2.3.4 (2)
    52: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __strncat_chk@GLIBC_2.3.4 (2)
    53: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
    54: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strerror@GLIBC_2.2.5 (3)
    55: 0000000000000000 0 FUNC GLOBAL DEFAULT UND dlclose@GLIBC_2.34 (4)
    56: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_init@GLIBC_2.2.5 (3)
    57: 0000000000000000 0 FUNC GLOBAL DEFAULT UND fstat@GLIBC_2.33 (9)
    58: 0000000000000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.2.5 (3)
    59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND strstr@GLIBC_2.2.5 (3)
    60: 0000000000000000 0 FUNC GLOBAL DEFAULT UND pthread_mutex_lock@GLIBC_2.2.5 (3)
    61: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __ctype_tolower_loc@GLIBC_2.3 (10)
    62: 0000000000000000 0 OBJECT GLOBAL DEFAULT UND stderr@GLIBC_2.2.5 (3)

```

Though I guess the drivers that `libvulkan.so.1` loads would probably rely on many more symbols.

---

_[View the full topic](https://ziggit.dev/t/loading-libvulkan-so-1-on-linux-with-std-elfdynlib/8480)._
