📄 dyn_load.c
字号:
/* * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1997 by Silicon Graphics. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to use or copy this program * for any purpose, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * * Original author: Bill Janssen * Heavily modified by Hans Boehm and others *//* * This is incredibly OS specific code for tracking down data sections in * dynamic libraries. There appears to be no way of doing this quickly * without groveling through undocumented data structures. We would argue * that this is a bug in the design of the dlopen interface. THIS CODE * MAY BREAK IN FUTURE OS RELEASES. If this matters to you, don't hesitate * to let your vendor know ... * * None of this is safe with dlclose and incremental collection. * But then not much of anything is safe in the presence of dlclose. */#if defined(__linux__) && !defined(_GNU_SOURCE) /* Can't test LINUX, since this must be define before other includes */# define _GNU_SOURCE#endif#if !defined(MACOS) && !defined(_WIN32_WCE)# include <sys/types.h>#endif#include "private/gc_priv.h"/* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */# if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \ && defined(dlopen) && !defined(GC_USE_LD_WRAP) /* To support threads in Solaris, gc.h interposes on dlopen by */ /* defining "dlopen" to be "GC_dlopen", which is implemented below. */ /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */ /* real system dlopen() in their implementation. We first remove */ /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */# undef dlopen# define GC_must_restore_redefined_dlopen# else# undef GC_must_restore_redefined_dlopen# endif#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \ && !defined(PCR)#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \ !defined(MSWIN32) && !defined(MSWINCE) && \ !(defined(ALPHA) && defined(OSF1)) && \ !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \ !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \ !(defined(FREEBSD) && defined(__ELF__)) && \ !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \ !defined(DARWIN) --> We only know how to find data segments of dynamic libraries for the --> above. Additional SVR4 variants might not be too --> hard to add.#endif#include <stdio.h>#ifdef SUNOS5DL# include <sys/elf.h># include <dlfcn.h># include <link.h>#endif#ifdef SUNOS4# include <dlfcn.h># include <link.h># include <a.out.h> /* struct link_map field overrides */# define l_next lm_next# define l_addr lm_addr# define l_name lm_name#endif#if defined(NETBSD)# include <machine/elf_machdep.h># define ELFSIZE ARCH_ELFSIZE#endif#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \ (defined(NETBSD) && defined(__ELF__)) || defined(HURD)# include <stddef.h># include <elf.h># include <link.h>#endif/* Newer versions of GNU/Linux define this macro. We * define it similarly for any ELF systems that don't. */# ifndef ElfW# if defined(FREEBSD)# if __ELF_WORD_SIZE == 32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# else# ifdef NETBSD# if ELFSIZE == 32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# else# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32# define ElfW(type) Elf32_##type# else# define ElfW(type) Elf64_##type# endif# endif# endif# endif#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)#ifdef LINT Elf32_Dyn _DYNAMIC;#endifstatic struct link_map *GC_FirstDLOpenedLinkMap(){ extern ElfW(Dyn) _DYNAMIC; ElfW(Dyn) *dp; struct r_debug *r; static struct link_map * cachedResult = 0; static ElfW(Dyn) *dynStructureAddr = 0; /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */# ifdef SUNOS53_SHARED_LIB /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */ /* up properly in dynamically linked .so's. This means we have */ /* to use its value in the set of original object files loaded */ /* at program startup. */ if( dynStructureAddr == 0 ) { void* startupSyms = dlopen(0, RTLD_LAZY); dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC"); }# else dynStructureAddr = &_DYNAMIC;# endif if( dynStructureAddr == 0) { return(0); } if( cachedResult == 0 ) { int tag; for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) { if( tag == DT_DEBUG ) { struct link_map *lm = ((struct r_debug *)(dp->d_un.d_ptr))->r_map; if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */ break; } } } return cachedResult;}#endif /* SUNOS5DL ... *//* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */# if defined(GC_must_restore_redefined_dlopen)# define dlopen GC_dlopen# endif#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)#ifdef LINT struct link_dynamic _DYNAMIC;#endifstatic struct link_map *GC_FirstDLOpenedLinkMap(){ extern struct link_dynamic _DYNAMIC; if( &_DYNAMIC == 0) { return(0); } return(_DYNAMIC.ld_un.ld_1->ld_loaded);}/* Return the address of the ld.so allocated common symbol *//* with the least address, or 0 if none. */static ptr_t GC_first_common(){ ptr_t result = 0; extern struct link_dynamic _DYNAMIC; struct rtc_symb * curr_symbol; if( &_DYNAMIC == 0) { return(0); } curr_symbol = _DYNAMIC.ldd -> ldd_cp; for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) { if (result == 0 || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) { result = (ptr_t)(curr_symbol -> rtc_sp -> n_value); } } return(result);}#endif /* SUNOS4 ... */# if defined(SUNOS4) || defined(SUNOS5DL)/* Add dynamic library data sections to the root set. */# if !defined(PCR) && !defined(GC_SOLARIS_THREADS) && defined(THREADS)# ifndef SRC_M3 --> fix mutual exclusion with dlopen# endif /* We assume M3 programs don't call dlopen for now */# endif# ifndef USE_PROC_FOR_LIBRARIESvoid GC_register_dynamic_libraries(){ struct link_map *lm = GC_FirstDLOpenedLinkMap(); for (lm = GC_FirstDLOpenedLinkMap(); lm != (struct link_map *) 0; lm = lm->l_next) {# ifdef SUNOS4 struct exec *e; e = (struct exec *) lm->lm_addr; GC_add_roots_inner( ((char *) (N_DATOFF(*e) + lm->lm_addr)), ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)), TRUE);# endif# ifdef SUNOS5DL ElfW(Ehdr) * e; ElfW(Phdr) * p; unsigned long offset; char * start; register int i; e = (ElfW(Ehdr) *) lm->l_addr; p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff)); offset = ((unsigned long)(lm->l_addr)); for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) { switch( p->p_type ) { case PT_LOAD: { if( !(p->p_flags & PF_W) ) break; start = ((char *)(p->p_vaddr)) + offset; GC_add_roots_inner( start, start + p->p_memsz, TRUE ); } break; default: break; } }# endif }# ifdef SUNOS4 { static ptr_t common_start = 0; ptr_t common_end; extern ptr_t GC_find_limit(); if (common_start == 0) common_start = GC_first_common(); if (common_start != 0) { common_end = GC_find_limit(common_start, TRUE); GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE); } }# endif}# endif /* !USE_PROC ... */# endif /* SUNOS */#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \ (defined(NETBSD) && defined(__ELF__)) || defined(HURD)#ifdef USE_PROC_FOR_LIBRARIES#include <string.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#define MAPS_BUF_SIZE (32*1024)extern ssize_t GC_repeat_read(int fd, char *buf, size_t count); /* Repeatedly read until buffer is filled, or EOF is encountered */ /* Defined in os_dep.c. */char *GC_parse_map_entry(char *buf_ptr, word *start, word *end, char *prot_buf, unsigned int *maj_dev);word GC_apply_to_maps(word (*fn)(char *)); /* From os_dep.c */word GC_register_map_entries(char *maps){ char prot_buf[5]; char *buf_ptr = maps; int count; word start, end; unsigned int maj_dev; word least_ha, greatest_ha; unsigned i; word datastart = (word)(DATASTART); /* Compute heap bounds. FIXME: Should be done by add_to_heap? */ least_ha = (word)(-1); greatest_ha = 0; for (i = 0; i < GC_n_heap_sects; ++i) { word sect_start = (word)GC_heap_sects[i].hs_start; word sect_end = sect_start + GC_heap_sects[i].hs_bytes; if (sect_start < least_ha) least_ha = sect_start; if (sect_end > greatest_ha) greatest_ha = sect_end; } if (greatest_ha < (word)GC_scratch_last_end_ptr) greatest_ha = (word)GC_scratch_last_end_ptr; for (;;) { buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev); if (buf_ptr == NULL) return 1; if (prot_buf[1] == 'w') { /* This is a writable mapping. Add it to */ /* the root set unless it is already otherwise */ /* accounted for. */ if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) { /* Stack mapping; discard */ continue; }# ifdef THREADS if (GC_segment_is_thread_stack(start, end)) continue;# endif /* We no longer exclude the main data segment. */ if (start < least_ha && end > least_ha) { end = least_ha; } if (start < greatest_ha && end > greatest_ha) { start = greatest_ha; } if (start >= least_ha && end <= greatest_ha) continue; GC_add_roots_inner((char *)start, (char *)end, TRUE); } } return 1;}void GC_register_dynamic_libraries(){ if (!GC_apply_to_maps(GC_register_map_entries)) ABORT("Failed to read /proc for library registration.");}/* We now take care of the main data segment ourselves: */GC_bool GC_register_main_static_data(){ return FALSE;} # define HAVE_REGISTER_MAIN_STATIC_DATA#endif /* USE_PROC_FOR_LIBRARIES */#if !defined(USE_PROC_FOR_LIBRARIES)/* The following is the preferred way to walk dynamic libraries *//* For glibc 2.2.4+. Unfortunately, it doesn't work for older *//* versions. Thanks to Jakub Jelinek for most of the code. */# if defined(LINUX) /* Are others OK here, too? */ \ && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \ || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) /* We have the header files for a glibc that includes dl_iterate_phdr. *//* It may still not be available in the library on the target system. *//* Thus we also treat it as a weak symbol. */#define HAVE_DL_ITERATE_PHDRstatic int GC_register_dynlib_callback(info, size, ptr) struct dl_phdr_info * info; size_t size; void * ptr;{ const ElfW(Phdr) * p; char * start; register int i; /* Make sure struct dl_phdr_info is at least as big as we need. */ if (size < offsetof (struct dl_phdr_info, dlpi_phnum) + sizeof (info->dlpi_phnum)) return -1; p = info->dlpi_phdr; for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) { switch( p->p_type ) { case PT_LOAD: { if( !(p->p_flags & PF_W) ) break; start = ((char *)(p->p_vaddr)) + info->dlpi_addr; GC_add_roots_inner(start, start + p->p_memsz, TRUE); } break; default: break; } } * (int *)ptr = 1; /* Signal that we were called */ return 0;} /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */#pragma weak dl_iterate_phdrGC_bool GC_register_dynamic_libraries_dl_iterate_phdr(){ if (dl_iterate_phdr) { int did_something = 0; dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -