Updates from 0.2.1 into 0.2.1-inu-1.5
This commit is contained in:
393
gc/dyn_load.c
393
gc/dyn_load.c
@@ -26,13 +26,15 @@
|
||||
* None of this is safe with dlclose and incremental collection.
|
||||
* But then not much of anything is safe in the presence of dlclose.
|
||||
*/
|
||||
#ifndef MACOS
|
||||
#if !defined(MACOS) && !defined(_WIN32_WCE)
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include "gc_priv.h"
|
||||
#include "private/gc_priv.h"
|
||||
|
||||
/* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */
|
||||
# if defined(SOLARIS_THREADS) && defined(dlopen)
|
||||
# if (defined(LINUX_THREADS) || defined(SOLARIS_THREADS) \
|
||||
|| defined(HPUX_THREADS) || defined(IRIX_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 */
|
||||
@@ -44,11 +46,14 @@
|
||||
# undef GC_must_restore_redefined_dlopen
|
||||
# endif
|
||||
|
||||
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
|
||||
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
|
||||
&& !defined(PCR)
|
||||
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
|
||||
!defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \
|
||||
!defined(HP_PA) && !(defined(LINUX) && defined(__ELF__)) && \
|
||||
!defined(RS6000) && !defined(SCO_ELF)
|
||||
!defined(MSWIN32) && !defined(MSWINCE) && \
|
||||
!(defined(ALPHA) && defined(OSF1)) && \
|
||||
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
|
||||
!defined(RS6000) && !defined(SCO_ELF) && \
|
||||
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
|
||||
--> We only know how to find data segments of dynamic libraries for the
|
||||
--> above. Additional SVR4 variants might not be too
|
||||
--> hard to add.
|
||||
@@ -119,6 +124,11 @@ GC_FirstDLOpenedLinkMap()
|
||||
|
||||
#endif /* SUNOS5DL ... */
|
||||
|
||||
/* BTL: added to fix circular dlopen definition if 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
|
||||
@@ -167,34 +177,6 @@ static ptr_t GC_first_common()
|
||||
# endif /* We assume M3 programs don't call dlopen for now */
|
||||
# endif
|
||||
|
||||
# ifdef SOLARIS_THREADS
|
||||
/* Redefine dlopen to guarantee mutual exclusion with */
|
||||
/* GC_register_dynamic_libraries. */
|
||||
/* assumes that dlopen doesn't need to call GC_malloc */
|
||||
/* and friends. */
|
||||
# include <thread.h>
|
||||
# include <synch.h>
|
||||
|
||||
void * GC_dlopen(const char *path, int mode)
|
||||
{
|
||||
void * result;
|
||||
|
||||
# ifndef USE_PROC_FOR_LIBRARIES
|
||||
mutex_lock(&GC_allocate_ml);
|
||||
# endif
|
||||
result = dlopen(path, mode);
|
||||
# ifndef USE_PROC_FOR_LIBRARIES
|
||||
mutex_unlock(&GC_allocate_ml);
|
||||
# endif
|
||||
return(result);
|
||||
}
|
||||
# endif /* SOLARIS_THREADS */
|
||||
|
||||
/* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
|
||||
# if defined(GC_must_restore_redefined_dlopen)
|
||||
# define dlopen GC_dlopen
|
||||
# endif
|
||||
|
||||
# ifndef USE_PROC_FOR_LIBRARIES
|
||||
void GC_register_dynamic_libraries()
|
||||
{
|
||||
@@ -260,14 +242,193 @@ void GC_register_dynamic_libraries()
|
||||
# endif /* !USE_PROC ... */
|
||||
# endif /* SUNOS */
|
||||
|
||||
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF)
|
||||
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
|
||||
(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. */
|
||||
|
||||
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
|
||||
char *prot_buf, unsigned int *maj_dev);
|
||||
|
||||
void GC_register_dynamic_libraries()
|
||||
{
|
||||
int f;
|
||||
int result;
|
||||
char prot_buf[5];
|
||||
int maps_size;
|
||||
char maps_temp[32768];
|
||||
char *maps_buf;
|
||||
char *buf_ptr;
|
||||
int count;
|
||||
word start, end;
|
||||
unsigned int maj_dev, min_dev;
|
||||
word least_ha, greatest_ha;
|
||||
unsigned i;
|
||||
word datastart = (word)(DATASTART);
|
||||
|
||||
/* Read /proc/self/maps */
|
||||
/* Note that we may not allocate, and thus can't use stdio. */
|
||||
f = open("/proc/self/maps", O_RDONLY);
|
||||
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
|
||||
/* stat() doesn't work for /proc/self/maps, so we have to
|
||||
read it to find out how large it is... */
|
||||
maps_size = 0;
|
||||
do {
|
||||
result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
|
||||
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
|
||||
maps_size += result;
|
||||
} while (result == sizeof(maps_temp));
|
||||
|
||||
if (maps_size > sizeof(maps_temp)) {
|
||||
/* If larger than our buffer, close and re-read it. */
|
||||
close(f);
|
||||
f = open("/proc/self/maps", O_RDONLY);
|
||||
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
|
||||
maps_buf = alloca(maps_size);
|
||||
if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
|
||||
result = GC_repeat_read(f, maps_buf, maps_size);
|
||||
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
|
||||
} else {
|
||||
/* Otherwise use the fixed size buffer */
|
||||
maps_buf = maps_temp;
|
||||
}
|
||||
|
||||
close(f);
|
||||
maps_buf[result] = '\0';
|
||||
buf_ptr = maps_buf;
|
||||
/* Compute heap bounds. 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 = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
|
||||
if (buf_ptr == NULL) return;
|
||||
|
||||
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;
|
||||
}
|
||||
if (start <= datastart && end > datastart && maj_dev != 0) {
|
||||
/* Main data segment; discard */
|
||||
continue;
|
||||
}
|
||||
# ifdef THREADS
|
||||
if (GC_segment_is_thread_stack(start, end)) continue;
|
||||
# endif
|
||||
/* The rest of this assumes that there is no mapping */
|
||||
/* spanning the beginning of the data segment, or extending */
|
||||
/* beyond the entire heap at both ends. */
|
||||
/* Empirically these assumptions hold. */
|
||||
|
||||
if (start < (word)DATAEND && end > (word)DATAEND) {
|
||||
/* Rld may use space at the end of the main data */
|
||||
/* segment. Thus we add that in. */
|
||||
start = (word)DATAEND;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// parse_map_entry parses an entry from /proc/self/maps so we can
|
||||
// locate all writable data segments that belong to shared libraries.
|
||||
// The format of one of these entries and the fields we care about
|
||||
// is as follows:
|
||||
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
|
||||
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
|
||||
// start end prot maj_dev
|
||||
// 0 9 18 32
|
||||
//
|
||||
// The parser is called with a pointer to the entry and the return value
|
||||
// is either NULL or is advanced to the next entry(the byte after the
|
||||
// trailing '\n'.)
|
||||
//
|
||||
#define OFFSET_MAP_START 0
|
||||
#define OFFSET_MAP_END 9
|
||||
#define OFFSET_MAP_PROT 18
|
||||
#define OFFSET_MAP_MAJDEV 32
|
||||
|
||||
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
|
||||
char *prot_buf, unsigned int *maj_dev)
|
||||
{
|
||||
int i;
|
||||
unsigned int val;
|
||||
char *tok;
|
||||
|
||||
if (buf_ptr == NULL || *buf_ptr == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
|
||||
prot_buf[4] = '\0';
|
||||
|
||||
if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
|
||||
|
||||
tok = buf_ptr;
|
||||
buf_ptr[OFFSET_MAP_START+8] = '\0';
|
||||
*start = strtoul(tok, NULL, 16);
|
||||
|
||||
tok = buf_ptr+OFFSET_MAP_END;
|
||||
buf_ptr[OFFSET_MAP_END+8] = '\0';
|
||||
*end = strtoul(tok, NULL, 16);
|
||||
|
||||
buf_ptr += OFFSET_MAP_MAJDEV;
|
||||
tok = buf_ptr;
|
||||
while (*buf_ptr != ':') buf_ptr++;
|
||||
*buf_ptr++ = '\0';
|
||||
*maj_dev = strtoul(tok, NULL, 16);
|
||||
}
|
||||
|
||||
while (*buf_ptr && *buf_ptr++ != '\n');
|
||||
|
||||
return buf_ptr;
|
||||
}
|
||||
|
||||
#else /* !USE_PROC_FOR_LIBRARIES */
|
||||
|
||||
/* Dynamic loading code for Linux running ELF. Somewhat tested on
|
||||
* Linux/x86, untested but hopefully should work on Linux/Alpha.
|
||||
* This code was derived from the Solaris/ELF support. Thanks to
|
||||
* whatever kind soul wrote that. - Patrick Bridges */
|
||||
|
||||
#include <elf.h>
|
||||
#if defined(NETBSD)
|
||||
# include <sys/exec_elf.h>
|
||||
#else
|
||||
# include <elf.h>
|
||||
#endif
|
||||
#include <link.h>
|
||||
|
||||
/* Newer versions of Linux/Alpha and Linux/x86 define this macro. We
|
||||
@@ -342,21 +503,26 @@ void GC_register_dynamic_libraries()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* !USE_PROC_FOR_LIBRARIES */
|
||||
|
||||
#if defined(IRIX5) || defined(USE_PROC_FOR_LIBRARIES)
|
||||
#endif /* LINUX */
|
||||
|
||||
#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
|
||||
|
||||
#include <sys/procfs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h> /* Only for the following test. */
|
||||
#ifndef _sigargs
|
||||
# define IRIX6
|
||||
#endif
|
||||
|
||||
extern void * GC_roots_present();
|
||||
/* The type is a lie, since the real type doesn't make sense here, */
|
||||
/* and we only test for NULL. */
|
||||
|
||||
extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */
|
||||
|
||||
/* We use /proc to track down all parts of the address space that are */
|
||||
/* mapped by the process, and throw out regions we know we shouldn't */
|
||||
@@ -413,7 +579,8 @@ void GC_register_dynamic_libraries()
|
||||
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
|
||||
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
|
||||
goto irrelevant;
|
||||
/* The latter test is empirically useless. Other than the */
|
||||
/* The latter test is empirically useless in very old Irix */
|
||||
/* versions. Other than the */
|
||||
/* main data and stack segments, everything appears to be */
|
||||
/* mapped readable, writable, executable, and shared(!!). */
|
||||
/* This makes no sense to me. - HB */
|
||||
@@ -426,7 +593,11 @@ void GC_register_dynamic_libraries()
|
||||
# endif /* MMAP_STACKS */
|
||||
|
||||
limit = start + addr_map[i].pr_size;
|
||||
if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
|
||||
/* The following seemed to be necessary for very old versions */
|
||||
/* of Irix, but it has been reported to discard relevant */
|
||||
/* segments under Irix 6.5. */
|
||||
# ifndef IRIX6
|
||||
if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
|
||||
/* Discard text segments, i.e. 0-offset mappings against */
|
||||
/* executable files which appear to have ELF headers. */
|
||||
caddr_t arg;
|
||||
@@ -453,7 +624,8 @@ void GC_register_dynamic_libraries()
|
||||
goto irrelevant;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif /* !IRIX6 */
|
||||
GC_add_roots_inner(start, limit, TRUE);
|
||||
irrelevant: ;
|
||||
}
|
||||
@@ -465,7 +637,7 @@ void GC_register_dynamic_libraries()
|
||||
|
||||
# endif /* USE_PROC || IRIX5 */
|
||||
|
||||
# ifdef MSWIN32
|
||||
# if defined(MSWIN32) || defined(MSWINCE)
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# define NOSERVICE
|
||||
@@ -474,86 +646,97 @@ void GC_register_dynamic_libraries()
|
||||
|
||||
/* We traverse the entire address space and register all segments */
|
||||
/* that could possibly have been written to. */
|
||||
DWORD GC_allocation_granularity;
|
||||
|
||||
extern GC_bool GC_is_heap_base (ptr_t p);
|
||||
|
||||
# ifdef WIN32_THREADS
|
||||
extern void GC_get_next_stack(char *start, char **lo, char **hi);
|
||||
# endif
|
||||
|
||||
void GC_cond_add_roots(char *base, char * limit)
|
||||
{
|
||||
char dummy;
|
||||
char * stack_top
|
||||
= (char *) ((word)(&dummy) & ~(GC_allocation_granularity-1));
|
||||
if (base == limit) return;
|
||||
# ifdef WIN32_THREADS
|
||||
void GC_cond_add_roots(char *base, char * limit)
|
||||
{
|
||||
char * curr_base = base;
|
||||
char * next_stack_lo;
|
||||
char * next_stack_hi;
|
||||
|
||||
for(;;) {
|
||||
GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
|
||||
if (next_stack_lo >= limit) break;
|
||||
GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
|
||||
curr_base = next_stack_hi;
|
||||
}
|
||||
if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
|
||||
char * curr_base = base;
|
||||
char * next_stack_lo;
|
||||
char * next_stack_hi;
|
||||
|
||||
if (base == limit) return;
|
||||
for(;;) {
|
||||
GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
|
||||
if (next_stack_lo >= limit) break;
|
||||
GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
|
||||
curr_base = next_stack_hi;
|
||||
}
|
||||
if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
|
||||
}
|
||||
# else
|
||||
if (limit > stack_top && base < GC_stackbottom) {
|
||||
/* Part of the stack; ignore it. */
|
||||
return;
|
||||
}
|
||||
GC_add_roots_inner(base, limit, TRUE);
|
||||
# endif
|
||||
}
|
||||
|
||||
# else
|
||||
void GC_cond_add_roots(char *base, char * limit)
|
||||
{
|
||||
char dummy;
|
||||
char * stack_top
|
||||
= (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
|
||||
if (base == limit) return;
|
||||
if (limit > stack_top && base < GC_stackbottom) {
|
||||
/* Part of the stack; ignore it. */
|
||||
return;
|
||||
}
|
||||
GC_add_roots_inner(base, limit, TRUE);
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifndef MSWINCE
|
||||
extern GC_bool GC_win32s;
|
||||
# endif
|
||||
|
||||
void GC_register_dynamic_libraries()
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION buf;
|
||||
SYSTEM_INFO sysinfo;
|
||||
DWORD result;
|
||||
DWORD protect;
|
||||
LPVOID p;
|
||||
char * base;
|
||||
char * limit, * new_limit;
|
||||
|
||||
if (GC_win32s) return;
|
||||
GetSystemInfo(&sysinfo);
|
||||
base = limit = p = sysinfo.lpMinimumApplicationAddress;
|
||||
GC_allocation_granularity = sysinfo.dwAllocationGranularity;
|
||||
while (p < sysinfo.lpMaximumApplicationAddress) {
|
||||
|
||||
# ifdef MSWIN32
|
||||
if (GC_win32s) return;
|
||||
# endif
|
||||
base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
|
||||
# if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
|
||||
/* Only the first 32 MB of address space belongs to the current process */
|
||||
while (p < (LPVOID)0x02000000) {
|
||||
result = VirtualQuery(p, &buf, sizeof(buf));
|
||||
if (result != sizeof(buf)) {
|
||||
ABORT("Weird VirtualQuery result");
|
||||
}
|
||||
new_limit = (char *)p + buf.RegionSize;
|
||||
protect = buf.Protect;
|
||||
if (buf.State == MEM_COMMIT
|
||||
&& (protect == PAGE_EXECUTE_READWRITE
|
||||
|| protect == PAGE_READWRITE)
|
||||
&& !GC_is_heap_base(buf.AllocationBase)) {
|
||||
if ((char *)p == limit) {
|
||||
limit = new_limit;
|
||||
} else {
|
||||
GC_cond_add_roots(base, limit);
|
||||
base = p;
|
||||
limit = new_limit;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
/* Page is free; advance to the next possible allocation base */
|
||||
new_limit = (char *)
|
||||
(((DWORD) p + GC_sysinfo.dwAllocationGranularity)
|
||||
& ~(GC_sysinfo.dwAllocationGranularity-1));
|
||||
} else
|
||||
# else
|
||||
while (p < GC_sysinfo.lpMaximumApplicationAddress) {
|
||||
result = VirtualQuery(p, &buf, sizeof(buf));
|
||||
# endif
|
||||
{
|
||||
if (result != sizeof(buf)) {
|
||||
ABORT("Weird VirtualQuery result");
|
||||
}
|
||||
new_limit = (char *)p + buf.RegionSize;
|
||||
protect = buf.Protect;
|
||||
if (buf.State == MEM_COMMIT
|
||||
&& (protect == PAGE_EXECUTE_READWRITE
|
||||
|| protect == PAGE_READWRITE)
|
||||
&& !GC_is_heap_base(buf.AllocationBase)) {
|
||||
if ((char *)p != limit) {
|
||||
GC_cond_add_roots(base, limit);
|
||||
base = p;
|
||||
}
|
||||
limit = new_limit;
|
||||
}
|
||||
}
|
||||
if (p > (LPVOID)new_limit /* overflow */) break;
|
||||
p = (LPVOID)new_limit;
|
||||
}
|
||||
GC_cond_add_roots(base, limit);
|
||||
}
|
||||
|
||||
#endif /* MSWIN32 */
|
||||
|
||||
#endif /* MSWIN32 || MSWINCE */
|
||||
|
||||
#if defined(ALPHA) && defined(OSF1)
|
||||
|
||||
#include <loader.h>
|
||||
@@ -658,7 +841,7 @@ void GC_register_dynamic_libraries()
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HP_PA)
|
||||
#if defined(HPUX)
|
||||
|
||||
#include <errno.h>
|
||||
#include <dl.h>
|
||||
@@ -681,6 +864,11 @@ void GC_register_dynamic_libraries()
|
||||
|
||||
/* Check if this is the end of the list or if some error occured */
|
||||
if (status != 0) {
|
||||
# ifdef HPUX_THREADS
|
||||
/* I've seen errno values of 0. The man page is not clear */
|
||||
/* as to whether errno should get set on a -1 return. */
|
||||
break;
|
||||
# else
|
||||
if (errno == EINVAL) {
|
||||
break; /* Moved past end of shared library list --> finished */
|
||||
} else {
|
||||
@@ -691,6 +879,7 @@ void GC_register_dynamic_libraries()
|
||||
}
|
||||
ABORT("shl_get failed");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
# ifdef VERBOSE
|
||||
@@ -713,7 +902,7 @@ void GC_register_dynamic_libraries()
|
||||
index++;
|
||||
}
|
||||
}
|
||||
#endif /* HP_PA */
|
||||
#endif /* HPUX */
|
||||
|
||||
#ifdef RS6000
|
||||
#pragma alloca
|
||||
|
Reference in New Issue
Block a user