From fbaa14ed8d5c576db36f9f2e212b7ca7a0628868 Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Thu, 16 Apr 2026 02:36:15 -0300 Subject: [PATCH] fix(elf): skip SHN_UNDEF symbols in GLOB_DAT/32 relocations 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 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/arch/x86/elf.c b/src/arch/x86/elf.c index 484560cf..e3bd0919 100644 --- a/src/arch/x86/elf.c +++ b/src/arch/x86/elf.c @@ -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); } -- 2.43.0