]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
fix(elf): skip SHN_UNDEF symbols in GLOB_DAT/32 relocations
authorTulio A M Mendes <[email protected]>
Thu, 16 Apr 2026 05:36:15 +0000 (02:36 -0300)
committerTulio A M Mendes <[email protected]>
Thu, 16 Apr 2026 05:36:15 +0000 (02:36 -0300)
The kernel's elf32_process_relocations incorrectly resolved R_386_GLOB_DAT
relocations for SHN_UNDEF symbols (st_shndx == 0) by setting the GOT
entry to base_offset. For libc.so loaded at 0x11000000, this meant
symbols like __init_array_start, __fini_array_end, and _init were
resolved to 0x11000000 (the ELF header), causing __libc_init_array
to execute garbage code at the ELF header and crash with SIGSEGV
at eip=0x11000012.

Now, SHN_UNDEF symbols are set to 0 in the GOT, leaving them for
the dynamic linker to resolve. Defined symbols (st_shndx != 0)
continue to be resolved as sym->st_value + base_offset.

Also removed debug kprintf from elf32_load_needed_libs.

src/arch/x86/elf.c

index 484560cf7a9b072fd5401ecdd4d8be18c8e4e18b..e3bd091978bdb743502dcf73af23b8b6eb9e4eac 100644 (file)
@@ -216,7 +216,11 @@ static void elf32_process_relocations(const uint8_t* file, uint32_t file_len,
                 if (symtab_addr && sym_idx) { \
                     const elf32_sym_t* sym = &((const elf32_sym_t*) \
                         (symtab_addr + base_offset))[sym_idx]; \
-                    *target = sym->st_value + (uint32_t)base_offset; \
+                    if (sym->st_shndx != 0) { \
+                        *target = sym->st_value + (uint32_t)base_offset; \
+                    } else { \
+                        *target = 0; /* SHN_UNDEF: leave for ld.so */ \
+                    } \
                 } \
                 break; \
             } \
@@ -225,7 +229,9 @@ static void elf32_process_relocations(const uint8_t* file, uint32_t file_len,
                 if (symtab_addr && sym_idx) { \
                     const elf32_sym_t* sym = &((const elf32_sym_t*) \
                         (symtab_addr + base_offset))[sym_idx]; \
-                    *target += sym->st_value + (uint32_t)base_offset; \
+                    if (sym->st_shndx != 0) { \
+                        *target += sym->st_value + (uint32_t)base_offset; \
+                    } \
                 } \
                 break; \
             } \
@@ -331,7 +337,6 @@ static int elf32_load_needed_libs(const uint8_t* file, uint32_t file_len,
         uintptr_t seg_end = 0;
         int rc = elf32_load_shared_lib_at(path, as, lib_base, &seg_end);
         if (rc == 0) {
-            /* shared lib loaded silently */
             lib_base = (seg_end + 0xFFFU) & ~(uintptr_t)0xFFFU;
             loaded++;
         } else {
@@ -530,11 +535,14 @@ int elf32_load_user_from_initrd(const char* filename, uintptr_t* entry_out, uint
         g_pending_auxv_count = 7;
     }
 
-    /* Map vDSO shared page read-only into user address space */
+    /* Map vDSO shared page read-only into user address space.
+     * Bump refcount so vmm_as_destroy properly decrements instead of
+     * freeing the shared kernel page. */
     {
         extern uintptr_t vdso_get_phys(void);
         uintptr_t vp = vdso_get_phys();
         if (vp) {
+            pmm_incref(vp);
             vmm_map_page((uint64_t)vp, (uint64_t)0x007FE000U,
                          VMM_FLAG_PRESENT | VMM_FLAG_USER);
         }