diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 35dc7e1eaa..5bfd4e2a43 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -1317,6 +1317,36 @@ static void call_tls_callbacks( HMODULE module, UINT reason ) } } +#if defined(__FreeBSD__) +/* The PT_LOAD segments are sorted in increasing order, and the first + * starts at the beginning of the ELF file. By parsing the file, we can + * find that first PT_LOAD segment, from which we can find the base + * address it wanted, and knowing mapbase where the binary was actually + * loaded, use them to work out the relocbase offset. */ +static BOOL mapbase_to_relocbase(const caddr_t mapbase, caddr_t *relocbase) +{ + const Elf_Phdr *prog_header; + Elf_Half i; +#ifdef _WIN64 + const Elf64_Ehdr *elf_header = (Elf64_Ehdr*) mapbase; +#else + const Elf32_Ehdr *elf_header = (Elf32_Ehdr*) mapbase; +#endif + + prog_header = (const Elf_Phdr*) ((const caddr_t)elf_header + elf_header->e_phoff); + for (i = 0; i < elf_header->e_phnum; i++) + { + if (prog_header->p_type == PT_LOAD) + { + const caddr_t desired_base = (caddr_t) ((prog_header->p_vaddr / prog_header->p_align) * prog_header->p_align); + *relocbase = (caddr_t) (mapbase - desired_base); + return TRUE; + } + prog_header++; + } + return FALSE; +} +#endif /************************************************************************* * call_constructors @@ -1338,14 +1368,27 @@ static void call_constructors( WINE_MODREF *wm ) if (dlinfo( wm->so_handle, RTLD_DI_LINKMAP, &map ) == -1) return; for (dyn = map->l_ld; dyn->d_tag; dyn++) { -#define GET_PTR(base,ptr) ((ptr) > (base) ? (ptr) : (base) + (ptr)) + /* The offset between addresses wanted by the binary ELF file on disk, + * and the addresses they actually got in memory. 0 when no relocation occurred. + * How it's worked out depends on the system's dlinfo() implementation. */ + caddr_t relocbase; + +#if defined(__FreeBSD__) + if (!mapbase_to_relocbase(map->l_addr, &relocbase)) + { + ERR("conversion of mapbase to relocbase failed, skipping initializers!!!\n"); + return; + } +#else + /* GNU, NetBSD */ + relocbase = (caddr_t)map->l_addr; +#endif switch (dyn->d_tag) { - case 0x60009990: init_array = (void *)GET_PTR( map->l_addr, dyn->d_un.d_ptr ); break; + case 0x60009990: init_array = (void *)(relocbase + dyn->d_un.d_val); break; case 0x60009991: init_arraysz = dyn->d_un.d_val; break; - case 0x60009992: init_func = (void *)GET_PTR( map->l_addr, dyn->d_un.d_ptr ); break; + case 0x60009992: init_func = (void *)(relocbase + dyn->d_un.d_val); break; } -#undef GET_PTR } TRACE( "%s: got init_func %p init_array %p %lu\n", debugstr_us( &wm->ldr.BaseDllName ),