Loading `libvulkan.so.1` on Linux with `std.ElfDynLib` Part 2
2025-02-13This was originally a topic on Ziggit.
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:
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:
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:
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.