OSDN Git Service

ChangeLog:
[pf3gnuchains/gcc-fork.git] / boehm-gc / dyn_load.c
1 /*
2  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
3  * Copyright (c) 1997 by Silicon Graphics.  All rights reserved.
4  *
5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
7  *
8  * Permission is hereby granted to use or copy this program
9  * for any purpose,  provided the above notices are retained on all copies.
10  * Permission to modify the code and to distribute modified code is granted,
11  * provided the above notices are retained, and a notice that the code was
12  * modified is included with the above copyright notice.
13  *
14  * Original author: Bill Janssen
15  * Heavily modified by Hans Boehm and others
16  */
17
18 /*
19  * This is incredibly OS specific code for tracking down data sections in
20  * dynamic libraries.  There appears to be no way of doing this quickly
21  * without groveling through undocumented data structures.  We would argue
22  * that this is a bug in the design of the dlopen interface.  THIS CODE
23  * MAY BREAK IN FUTURE OS RELEASES.  If this matters to you, don't hesitate
24  * to let your vendor know ...
25  *
26  * None of this is safe with dlclose and incremental collection.
27  * But then not much of anything is safe in the presence of dlclose.
28  */
29 #if (defined(__linux__) || defined(__GLIBC__)) && !defined(_GNU_SOURCE)
30     /* Can't test LINUX, since this must be define before other includes */
31 #   define _GNU_SOURCE
32 #endif
33 #if !defined(MACOS) && !defined(_WIN32_WCE)
34 #  include <sys/types.h>
35 #endif
36 #include "private/gc_priv.h"
37
38 /* BTL: avoid circular redefinition of dlopen if GC_SOLARIS_THREADS defined */
39 # if (defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)) \
40       && defined(dlopen) && !defined(GC_USE_LD_WRAP)
41     /* To support threads in Solaris, gc.h interposes on dlopen by       */
42     /* defining "dlopen" to be "GC_dlopen", which is implemented below.  */
43     /* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the   */
44     /* real system dlopen() in their implementation. We first remove     */
45     /* gc.h's dlopen definition and restore it later, after GC_dlopen(). */
46 #   undef dlopen
47 #   define GC_must_restore_redefined_dlopen
48 # else
49 #   undef GC_must_restore_redefined_dlopen
50 # endif
51
52 #if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
53     && !defined(PCR)
54 #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
55     !defined(MSWIN32) && !defined(MSWINCE) && \
56     !(defined(ALPHA) && defined(OSF1)) && \
57     !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
58     !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
59     !(defined(FREEBSD) && defined(__ELF__)) && \
60     !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
61     !defined(DARWIN)
62  --> We only know how to find data segments of dynamic libraries for the
63  --> above.  Additional SVR4 variants might not be too
64  --> hard to add.
65 #endif
66
67 #include <stdio.h>
68 #ifdef SUNOS5DL
69 #   include <sys/elf.h>
70 #   include <dlfcn.h>
71 #   include <link.h>
72 #endif
73 #ifdef SUNOS4
74 #   include <dlfcn.h>
75 #   include <link.h>
76 #   include <a.out.h>
77   /* struct link_map field overrides */
78 #   define l_next       lm_next
79 #   define l_addr       lm_addr
80 #   define l_name       lm_name
81 #endif
82
83 #if defined(NETBSD)
84 #   include <machine/elf_machdep.h>
85 #   define ELFSIZE ARCH_ELFSIZE
86 #endif
87
88 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
89     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
90     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
91 #   include <stddef.h>
92 #   include <elf.h>
93 #   include <link.h>
94 #endif
95
96 /* Newer versions of GNU/Linux define this macro.  We
97  * define it similarly for any ELF systems that don't.  */
98 #  ifndef ElfW
99 #    if defined(FREEBSD)
100 #      if __ELF_WORD_SIZE == 32
101 #        define ElfW(type) Elf32_##type
102 #      else
103 #        define ElfW(type) Elf64_##type
104 #      endif
105 #    else
106 #      ifdef NETBSD
107 #        if ELFSIZE == 32
108 #          define ElfW(type) Elf32_##type
109 #        else
110 #          define ElfW(type) Elf64_##type
111 #        endif
112 #      else
113 #        if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
114 #          define ElfW(type) Elf32_##type
115 #        else
116 #          define ElfW(type) Elf64_##type
117 #        endif
118 #      endif
119 #    endif
120 #  endif
121
122 /* An user-supplied routine that is called to dtermine if a DSO must
123    be scanned by the gc.  */
124 static int (*GC_has_static_roots)(const char *, void *, size_t);
125 /* Register the routine.  */
126 void
127 GC_register_has_static_roots_callback 
128   (int (*callback)(const char *, void *, size_t))
129 {
130   GC_has_static_roots = callback;
131 }
132
133 #if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
134
135 #ifdef LINT
136     Elf32_Dyn _DYNAMIC;
137 #endif
138
139 static struct link_map *
140 GC_FirstDLOpenedLinkMap()
141 {
142     extern ElfW(Dyn) _DYNAMIC;
143     ElfW(Dyn) *dp;
144     struct r_debug *r;
145     static struct link_map * cachedResult = 0;
146     static ElfW(Dyn) *dynStructureAddr = 0;
147                         /* BTL: added to avoid Solaris 5.3 ld.so _DYNAMIC bug */
148
149 #   ifdef SUNOS53_SHARED_LIB
150         /* BTL: Avoid the Solaris 5.3 bug that _DYNAMIC isn't being set */
151         /* up properly in dynamically linked .so's. This means we have  */
152         /* to use its value in the set of original object files loaded  */
153         /* at program startup.                                          */
154         if( dynStructureAddr == 0 ) {
155           void* startupSyms = dlopen(0, RTLD_LAZY);
156           dynStructureAddr = (ElfW(Dyn)*)dlsym(startupSyms, "_DYNAMIC");
157                 }
158 #   else
159         dynStructureAddr = &_DYNAMIC;
160 #   endif
161
162     if( dynStructureAddr == 0) {
163         return(0);
164     }
165     if( cachedResult == 0 ) {
166         int tag;
167         for( dp = ((ElfW(Dyn) *)(&_DYNAMIC)); (tag = dp->d_tag) != 0; dp++ ) {
168             if( tag == DT_DEBUG ) {
169                 struct link_map *lm
170                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
171                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
172                 break;
173             }
174         }
175     }
176     return cachedResult;
177 }
178
179 #endif /* SUNOS5DL ... */
180
181 /* BTL: added to fix circular dlopen definition if GC_SOLARIS_THREADS defined */
182 # if defined(GC_must_restore_redefined_dlopen)
183 #   define dlopen GC_dlopen
184 # endif
185
186 #if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
187
188 #ifdef LINT
189     struct link_dynamic _DYNAMIC;
190 #endif
191
192 static struct link_map *
193 GC_FirstDLOpenedLinkMap()
194 {
195     extern struct link_dynamic _DYNAMIC;
196
197     if( &_DYNAMIC == 0) {
198         return(0);
199     }
200     return(_DYNAMIC.ld_un.ld_1->ld_loaded);
201 }
202
203 /* Return the address of the ld.so allocated common symbol      */
204 /* with the least address, or 0 if none.                        */
205 static ptr_t GC_first_common()
206 {
207     ptr_t result = 0;
208     extern struct link_dynamic _DYNAMIC;
209     struct rtc_symb * curr_symbol;
210     
211     if( &_DYNAMIC == 0) {
212         return(0);
213     }
214     curr_symbol = _DYNAMIC.ldd -> ldd_cp;
215     for (; curr_symbol != 0; curr_symbol = curr_symbol -> rtc_next) {
216         if (result == 0
217             || (ptr_t)(curr_symbol -> rtc_sp -> n_value) < result) {
218             result = (ptr_t)(curr_symbol -> rtc_sp -> n_value);
219         }
220     }
221     return(result);
222 }
223
224 #endif  /* SUNOS4 ... */
225
226 # if defined(SUNOS4) || defined(SUNOS5DL)
227 /* Add dynamic library data sections to the root set.           */
228 # if !defined(PCR) && !defined(GC_SOLARIS_PTHREADS) && defined(THREADS)
229 #   ifndef SRC_M3
230         --> fix mutual exclusion with dlopen
231 #   endif  /* We assume M3 programs don't call dlopen for now */
232 # endif
233
234 # ifndef USE_PROC_FOR_LIBRARIES
235 void GC_register_dynamic_libraries()
236 {
237   struct link_map *lm = GC_FirstDLOpenedLinkMap();
238   
239
240   for (lm = GC_FirstDLOpenedLinkMap();
241        lm != (struct link_map *) 0;  lm = lm->l_next)
242     {
243 #     ifdef SUNOS4
244         struct exec *e;
245          
246         e = (struct exec *) lm->lm_addr;
247         GC_add_roots_inner(
248                     ((char *) (N_DATOFF(*e) + lm->lm_addr)),
249                     ((char *) (N_BSSADDR(*e) + e->a_bss + lm->lm_addr)),
250                     TRUE);
251 #     endif
252 #     ifdef SUNOS5DL
253         ElfW(Ehdr) * e;
254         ElfW(Phdr) * p;
255         unsigned long offset;
256         char * start;
257         register int i;
258         
259         e = (ElfW(Ehdr) *) lm->l_addr;
260         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
261         offset = ((unsigned long)(lm->l_addr));
262         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
263           switch( p->p_type ) {
264             case PT_LOAD:
265               {
266                 if( !(p->p_flags & PF_W) ) break;
267                 start = ((char *)(p->p_vaddr)) + offset;
268                 GC_add_roots_inner(
269                   start,
270                   start + p->p_memsz,
271                   TRUE
272                 );
273               }
274               break;
275             default:
276               break;
277           }
278         }
279 #     endif
280     }
281 #   ifdef SUNOS4
282       {
283         static ptr_t common_start = 0;
284         ptr_t common_end;
285         extern ptr_t GC_find_limit();
286         
287         if (common_start == 0) common_start = GC_first_common();
288         if (common_start != 0) {
289             common_end = GC_find_limit(common_start, TRUE);
290             GC_add_roots_inner((char *)common_start, (char *)common_end, TRUE);
291         }
292       }
293 #   endif
294 }
295
296 # endif /* !USE_PROC ... */
297 # endif /* SUNOS */
298
299 #if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
300     (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
301     (defined(NETBSD) && defined(__ELF__)) || defined(HURD)
302
303
304 #ifdef USE_PROC_FOR_LIBRARIES
305
306 #include <string.h>
307
308 #include <sys/stat.h>
309 #include <fcntl.h>
310 #include <unistd.h>
311
312 #define MAPS_BUF_SIZE (32*1024)
313
314 extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
315         /* Repeatedly read until buffer is filled, or EOF is encountered */
316         /* Defined in os_dep.c.                                          */
317
318 char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
319                          char *prot_buf, unsigned int *maj_dev);
320 word GC_apply_to_maps(word (*fn)(char *));
321         /* From os_dep.c        */
322
323 word GC_register_map_entries(char *maps)
324 {
325     char prot_buf[5];
326     char *buf_ptr = maps;
327     int count;
328     word start, end;
329     unsigned int maj_dev;
330     word least_ha, greatest_ha;
331     unsigned i;
332     word datastart = (word)(DATASTART);
333
334     /* Compute heap bounds. FIXME: Should be done by add_to_heap?       */
335         least_ha = (word)(-1);
336         greatest_ha = 0;
337         for (i = 0; i < GC_n_heap_sects; ++i) {
338             word sect_start = (word)GC_heap_sects[i].hs_start;
339             word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
340             if (sect_start < least_ha) least_ha = sect_start;
341             if (sect_end > greatest_ha) greatest_ha = sect_end;
342         }
343         if (greatest_ha < (word)GC_scratch_last_end_ptr)
344             greatest_ha = (word)GC_scratch_last_end_ptr; 
345
346     for (;;) {
347         buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
348         if (buf_ptr == NULL) return 1;
349         if (prot_buf[1] == 'w') {
350             /* This is a writable mapping.  Add it to           */
351             /* the root set unless it is already otherwise      */
352             /* accounted for.                                   */
353             if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
354                 /* Stack mapping; discard       */
355                 continue;
356             }
357 #           ifdef THREADS
358               if (GC_segment_is_thread_stack(start, end)) continue;
359 #           endif
360             /* We no longer exclude the main data segment.              */
361             if (start < least_ha && end > least_ha) {
362                 end = least_ha;
363             }
364             if (start < greatest_ha && end > greatest_ha) {
365                 start = greatest_ha;
366             }
367             if (start >= least_ha && end <= greatest_ha) continue;
368             GC_add_roots_inner((char *)start, (char *)end, TRUE);
369         }
370     }
371     return 1;
372 }
373
374 void GC_register_dynamic_libraries()
375 {
376    if (!GC_apply_to_maps(GC_register_map_entries))
377        ABORT("Failed to read /proc for library registration.");
378 }
379
380 /* We now take care of the main data segment ourselves: */
381 GC_bool GC_register_main_static_data()
382 {
383   return FALSE;
384 }
385
386 # define HAVE_REGISTER_MAIN_STATIC_DATA
387
388 #endif /* USE_PROC_FOR_LIBRARIES */
389
390 #if !defined(USE_PROC_FOR_LIBRARIES)
391 /* The following is the preferred way to walk dynamic libraries */
392 /* For glibc 2.2.4+.  Unfortunately, it doesn't work for older  */
393 /* versions.  Thanks to Jakub Jelinek for most of the code.     */
394
395 # if (defined(LINUX) || defined (__GLIBC__)) /* Are others OK here, too? */ \
396      && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 2) \
397          || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 2 && defined(DT_CONFIG))) 
398
399 /* We have the header files for a glibc that includes dl_iterate_phdr.  */
400 /* It may still not be available in the library on the target system.   */
401 /* Thus we also treat it as a weak symbol.                              */
402 #define HAVE_DL_ITERATE_PHDR
403 #pragma weak dl_iterate_phdr
404 #endif
405
406 # if (defined(FREEBSD) && __FreeBSD__ >= 7)
407 /* On the FreeBSD system, any target system at major version 7 shall    */
408 /* have dl_iterate_phdr; therefore, we need not make it weak as above.  */
409 #define HAVE_DL_ITERATE_PHDR
410 #endif
411
412 #if defined(HAVE_DL_ITERATE_PHDR)
413
414 static int GC_register_dynlib_callback(info, size, ptr)
415      struct dl_phdr_info * info;
416      size_t size;
417      void * ptr;
418 {
419   const ElfW(Phdr) * p;
420   char * start;
421   register int i;
422
423   /* Make sure struct dl_phdr_info is at least as big as we need.  */
424   if (size < offsetof (struct dl_phdr_info, dlpi_phnum)
425       + sizeof (info->dlpi_phnum))
426     return -1;
427
428   p = info->dlpi_phdr;
429   for( i = 0; i < (int)(info->dlpi_phnum); ((i++),(p++)) ) {
430     switch( p->p_type ) {
431       case PT_LOAD:
432         {
433           if( !(p->p_flags & PF_W) ) break;
434           start = ((char *)(p->p_vaddr)) + info->dlpi_addr;
435
436           if (GC_has_static_roots 
437               && !GC_has_static_roots(info->dlpi_name, start, p->p_memsz))
438             break;
439
440           GC_add_roots_inner(start, start + p->p_memsz, TRUE);
441         }
442       break;
443       default:
444         break;
445     }
446   }
447
448   * (int *)ptr = 1;     /* Signal that we were called */
449   return 0;
450 }     
451
452 /* Return TRUE if we succeed, FALSE if dl_iterate_phdr wasn't there. */
453
454 GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
455 {
456   if (dl_iterate_phdr) {
457     int did_something = 0;
458     dl_iterate_phdr(GC_register_dynlib_callback, &did_something);
459     if (!did_something) {
460         /* dl_iterate_phdr may forget the static data segment in        */
461         /* statically linked executables.                               */
462         GC_add_roots_inner(DATASTART, (char *)(DATAEND), TRUE);
463 #       if defined(DATASTART2)
464           GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
465 #       endif
466     }
467
468     return TRUE;
469   } else {
470     return FALSE;
471   }
472 }
473
474 /* Do we need to separately register the main static data segment? */
475 GC_bool GC_register_main_static_data()
476 {
477   return (dl_iterate_phdr == 0);
478 }
479
480 #define HAVE_REGISTER_MAIN_STATIC_DATA
481
482 # else /* !LINUX || version(glibc) < 2.2.4 */
483
484 /* Dynamic loading code for Linux running ELF. Somewhat tested on
485  * Linux/x86, untested but hopefully should work on Linux/Alpha. 
486  * This code was derived from the Solaris/ELF support. Thanks to
487  * whatever kind soul wrote that.  - Patrick Bridges */
488
489 /* This doesn't necessarily work in all cases, e.g. with preloaded
490  * dynamic libraries.                                           */
491
492 #if defined(NETBSD)
493 #  include <sys/exec_elf.h>
494 /* for compatibility with 1.4.x */
495 #  ifndef DT_DEBUG
496 #  define DT_DEBUG     21
497 #  endif
498 #  ifndef PT_LOAD
499 #  define PT_LOAD      1
500 #  endif
501 #  ifndef PF_W
502 #  define PF_W         2
503 #  endif
504 #else
505 #  include <elf.h>
506 #endif
507 #include <link.h>
508
509 # endif
510
511 #ifdef __GNUC__
512 # pragma weak _DYNAMIC
513 #endif
514 extern ElfW(Dyn) _DYNAMIC[];
515
516 static struct link_map *
517 GC_FirstDLOpenedLinkMap()
518 {
519     ElfW(Dyn) *dp;
520     static struct link_map *cachedResult = 0;
521
522     if( _DYNAMIC == 0) {
523         return(0);
524     }
525     if( cachedResult == 0 ) {
526         int tag;
527         for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
528             /* FIXME: The DT_DEBUG header is not mandated by the        */
529             /* ELF spec.  This code appears to be dependent on          */
530             /* idiosynchracies of older GNU tool chains.  If this code  */
531             /* fails for you, the real problem is probably that it is   */
532             /* being used at all.  You should be getting the            */
533             /* dl_iterate_phdr version.                                 */
534             if( tag == DT_DEBUG ) {
535                 struct link_map *lm
536                         = ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
537                 if( lm != 0 ) cachedResult = lm->l_next; /* might be NIL */
538                 break;
539             }
540         }
541     }
542     return cachedResult;
543 }
544
545
546 void GC_register_dynamic_libraries()
547 {
548   struct link_map *lm;
549   
550
551 # ifdef HAVE_DL_ITERATE_PHDR
552     if (GC_register_dynamic_libraries_dl_iterate_phdr()) {
553         return;
554     }
555 # endif
556   lm = GC_FirstDLOpenedLinkMap();
557   for (lm = GC_FirstDLOpenedLinkMap();
558        lm != (struct link_map *) 0;  lm = lm->l_next)
559     {
560         ElfW(Ehdr) * e;
561         ElfW(Phdr) * p;
562         unsigned long offset;
563         char * start;
564         register int i;
565         
566         e = (ElfW(Ehdr) *) lm->l_addr;
567         p = ((ElfW(Phdr) *)(((char *)(e)) + e->e_phoff));
568         offset = ((unsigned long)(lm->l_addr));
569         for( i = 0; i < (int)(e->e_phnum); ((i++),(p++)) ) {
570           switch( p->p_type ) {
571             case PT_LOAD:
572               {
573                 if( !(p->p_flags & PF_W) ) break;
574                 start = ((char *)(p->p_vaddr)) + offset;
575                 GC_add_roots_inner(start, start + p->p_memsz, TRUE);
576               }
577               break;
578             default:
579               break;
580           }
581         }
582     }
583 }
584
585 #endif /* !USE_PROC_FOR_LIBRARIES */
586
587 #endif /* LINUX */
588
589 #if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
590
591 #include <sys/procfs.h>
592 #include <sys/stat.h>
593 #include <fcntl.h>
594 #include <elf.h>
595 #include <errno.h>
596 #include <signal.h>  /* Only for the following test. */
597 #ifndef _sigargs
598 # define IRIX6
599 #endif
600
601 extern void * GC_roots_present();
602         /* The type is a lie, since the real type doesn't make sense here, */
603         /* and we only test for NULL.                                      */
604
605
606 /* We use /proc to track down all parts of the address space that are   */
607 /* mapped by the process, and throw out regions we know we shouldn't    */
608 /* worry about.  This may also work under other SVR4 variants.          */
609 void GC_register_dynamic_libraries()
610 {
611     static int fd = -1;
612     char buf[30];
613     static prmap_t * addr_map = 0;
614     static int current_sz = 0;  /* Number of records currently in addr_map */
615     static int needed_sz;       /* Required size of addr_map            */
616     register int i;
617     register long flags;
618     register ptr_t start;
619     register ptr_t limit;
620     ptr_t heap_start = (ptr_t)HEAP_START;
621     ptr_t heap_end = heap_start;
622
623 #   ifdef SUNOS5DL
624 #     define MA_PHYS 0
625 #   endif /* SUNOS5DL */
626
627     if (fd < 0) {
628       sprintf(buf, "/proc/%d", getpid());
629         /* The above generates a lint complaint, since pid_t varies.    */
630         /* It's unclear how to improve this.                            */
631       fd = open(buf, O_RDONLY);
632       if (fd < 0) {
633         ABORT("/proc open failed");
634       }
635     }
636     if (ioctl(fd, PIOCNMAP, &needed_sz) < 0) {
637         GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
638         ABORT("/proc PIOCNMAP ioctl failed");
639     }
640     if (needed_sz >= current_sz) {
641         current_sz = needed_sz * 2 + 1;
642                         /* Expansion, plus room for 0 record */
643         addr_map = (prmap_t *)GC_scratch_alloc((word)
644                                                 (current_sz * sizeof(prmap_t)));
645     }
646     if (ioctl(fd, PIOCMAP, addr_map) < 0) {
647         GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
648                         fd, errno, needed_sz, addr_map);
649         ABORT("/proc PIOCMAP ioctl failed");
650     };
651     if (GC_n_heap_sects > 0) {
652         heap_end = GC_heap_sects[GC_n_heap_sects-1].hs_start
653                         + GC_heap_sects[GC_n_heap_sects-1].hs_bytes;
654         if (heap_end < GC_scratch_last_end_ptr) heap_end = GC_scratch_last_end_ptr; 
655     }
656     for (i = 0; i < needed_sz; i++) {
657         flags = addr_map[i].pr_mflags;
658         if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
659                       | MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
660         if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
661             goto irrelevant;
662           /* The latter test is empirically useless in very old Irix    */
663           /* versions.  Other than the                                  */
664           /* main data and stack segments, everything appears to be     */
665           /* mapped readable, writable, executable, and shared(!!).     */
666           /* This makes no sense to me. - HB                            */
667         start = (ptr_t)(addr_map[i].pr_vaddr);
668         if (GC_roots_present(start)) goto irrelevant;
669         if (start < heap_end && start >= heap_start)
670                 goto irrelevant;
671 #       ifdef MMAP_STACKS
672           if (GC_is_thread_stack(start)) goto irrelevant;
673 #       endif /* MMAP_STACKS */
674
675         limit = start + addr_map[i].pr_size;
676         /* The following seemed to be necessary for very old versions   */
677         /* of Irix, but it has been reported to discard relevant        */
678         /* segments under Irix 6.5.                                     */
679 #       ifndef IRIX6
680           if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
681             /* Discard text segments, i.e. 0-offset mappings against    */
682             /* executable files which appear to have ELF headers.       */
683             caddr_t arg;
684             int obj;
685 #           define MAP_IRR_SZ 10
686             static ptr_t map_irr[MAP_IRR_SZ];
687                                         /* Known irrelevant map entries */
688             static int n_irr = 0;
689             struct stat buf;
690             register int i;
691             
692             for (i = 0; i < n_irr; i++) {
693                 if (map_irr[i] == start) goto irrelevant;
694             }
695             arg = (caddr_t)start;
696             obj = ioctl(fd, PIOCOPENM, &arg);
697             if (obj >= 0) {
698                 fstat(obj, &buf);
699                 close(obj);
700                 if ((buf.st_mode & 0111) != 0) {
701                     if (n_irr < MAP_IRR_SZ) {
702                         map_irr[n_irr++] = start;
703                     }
704                     goto irrelevant;
705                 }
706             }
707           }
708 #       endif /* !IRIX6 */
709         GC_add_roots_inner(start, limit, TRUE);
710       irrelevant: ;
711     }
712     /* Dont keep cached descriptor, for now.  Some kernels don't like us */
713     /* to keep a /proc file descriptor around during kill -9.            */
714         if (close(fd) < 0) ABORT("Couldnt close /proc file");
715         fd = -1;
716 }
717
718 # endif /* USE_PROC || IRIX5 */
719
720 # if defined(MSWIN32) || defined(MSWINCE)
721
722 # define WIN32_LEAN_AND_MEAN
723 # define NOSERVICE
724 # include <windows.h>
725 # include <stdlib.h>
726
727   /* We traverse the entire address space and register all segments     */
728   /* that could possibly have been written to.                          */
729   
730   extern GC_bool GC_is_heap_base (ptr_t p);
731
732 # ifdef GC_WIN32_THREADS
733     extern void GC_get_next_stack(char *start, char **lo, char **hi);
734     void GC_cond_add_roots(char *base, char * limit)
735     {
736       char * curr_base = base;
737       char * next_stack_lo;
738       char * next_stack_hi;
739    
740       if (base == limit) return;
741       for(;;) {
742           GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
743           if (next_stack_lo >= limit) break;
744           GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
745           curr_base = next_stack_hi;
746       }
747       if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
748     }
749 # else
750     void GC_cond_add_roots(char *base, char * limit)
751     {
752       char dummy;
753       char * stack_top
754          = (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
755       if (base == limit) return;
756       if (limit > stack_top && base < GC_stackbottom) {
757           /* Part of the stack; ignore it. */
758           return;
759       }
760       GC_add_roots_inner(base, limit, TRUE);
761     }
762 # endif
763
764 # ifdef MSWINCE
765   /* Do we need to separately register the main static data segment? */
766   GC_bool GC_register_main_static_data()
767   {
768     return FALSE;
769   }
770 # else /* win32 */
771   extern GC_bool GC_no_win32_dlls;
772
773   GC_bool GC_register_main_static_data()
774   {
775     return GC_no_win32_dlls;
776   }
777 # endif /* win32 */
778   
779 # define HAVE_REGISTER_MAIN_STATIC_DATA
780
781   /* The frame buffer testing code is dead in this version.     */
782   /* We leave it here temporarily in case the switch to just    */
783   /* testing for MEM_IMAGE sections causes un expected          */
784   /* problems.                                                  */
785   GC_bool GC_warn_fb = TRUE;    /* Warn about traced likely     */
786                                 /* graphics memory.             */
787   GC_bool GC_disallow_ignore_fb = FALSE;
788   int GC_ignore_fb_mb;  /* Ignore mappings bigger than the      */
789                         /* specified number of MB.              */
790   GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer  */
791                                 /* checking.            */
792   
793   /* Issue warning if tracing apparent framebuffer.             */
794   /* This limits us to one warning, and it's a back door to     */
795   /* disable that.                                              */
796  
797   /* Should [start, start+len) be treated as a frame buffer     */
798   /* and ignored?                                               */
799   /* Unfortunately, we currently are not quite sure how to tell */
800   /* this automatically, and rely largely on user input.        */
801   /* We expect that any mapping with type MEM_MAPPED (which     */
802   /* apparently excludes library data sections) can be safely   */
803   /* ignored.  But we're too chicken to do that in this         */
804   /* version.                                                   */
805   /* Based on a very limited sample, it appears that:           */
806   /*    - Frame buffer mappings appear as mappings of large     */
807   /*      length, usually a bit less than a power of two.       */
808   /*    - The definition of "a bit less" in the above cannot    */
809   /*      be made more precise.                                 */
810   /*    - Have a starting address at best 64K aligned.          */
811   /*    - Have type == MEM_MAPPED.                              */
812   static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
813   {
814     static GC_bool initialized = FALSE;
815 #   define MB (1024*1024)
816 #   define DEFAULT_FB_MB 15
817 #   define MIN_FB_MB 3
818
819     if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
820     if (!initialized) {
821       char * ignore_fb_string =  GETENV("GC_IGNORE_FB");
822
823       if (0 != ignore_fb_string) {
824         while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
825           ++ignore_fb_string;
826         if (*ignore_fb_string == '\0') {
827           GC_ignore_fb_mb = DEFAULT_FB_MB;
828         } else {
829           GC_ignore_fb_mb = atoi(ignore_fb_string);
830           if (GC_ignore_fb_mb < MIN_FB_MB) {
831             WARN("Bad GC_IGNORE_FB value.  Using %ld\n", DEFAULT_FB_MB);
832             GC_ignore_fb_mb = DEFAULT_FB_MB;
833           }
834         }
835         GC_ignore_fb = TRUE;
836       } else {
837         GC_ignore_fb_mb = DEFAULT_FB_MB;  /* For warning */
838       }
839       initialized = TRUE;
840     }
841     if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
842       if (GC_ignore_fb) {
843         return TRUE;
844       } else {
845         if (GC_warn_fb) {
846           WARN("Possible frame buffer mapping at 0x%lx: \n"
847                "\tConsider setting GC_IGNORE_FB to improve performance.\n",
848                start);
849           GC_warn_fb = FALSE;
850         }
851         return FALSE;
852       }
853     } else {
854       return FALSE;
855     }
856   }
857
858 # ifdef DEBUG_VIRTUALQUERY
859   void GC_dump_meminfo(MEMORY_BASIC_INFORMATION *buf)
860   {
861     GC_printf4("BaseAddress = %lx, AllocationBase = %lx, RegionSize = %lx(%lu)\n",
862                buf -> BaseAddress, buf -> AllocationBase, buf -> RegionSize,
863                buf -> RegionSize);
864     GC_printf4("\tAllocationProtect = %lx, State = %lx, Protect = %lx, "
865                "Type = %lx\n",
866                buf -> AllocationProtect, buf -> State, buf -> Protect,
867                buf -> Type);
868   }
869 # endif /* DEBUG_VIRTUALQUERY */
870
871   extern GC_bool GC_wnt;  /* Is Windows NT derivative.          */
872                           /* Defined and set in os_dep.c.       */
873
874   void GC_register_dynamic_libraries()
875   {
876     MEMORY_BASIC_INFORMATION buf;
877     DWORD result;
878     DWORD protect;
879     LPVOID p;
880     char * base;
881     char * limit, * new_limit;
882
883 #   ifdef MSWIN32
884       if (GC_no_win32_dlls) return;
885 #   endif
886     base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
887 #   if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
888     /* Only the first 32 MB of address space belongs to the current process */
889     while (p < (LPVOID)0x02000000) {
890         result = VirtualQuery(p, &buf, sizeof(buf));
891         if (result == 0) {
892             /* Page is free; advance to the next possible allocation base */
893             new_limit = (char *)
894                 (((DWORD) p + GC_sysinfo.dwAllocationGranularity)
895                  & ~(GC_sysinfo.dwAllocationGranularity-1));
896         } else
897 #   else
898     while (p < GC_sysinfo.lpMaximumApplicationAddress) {
899         result = VirtualQuery(p, &buf, sizeof(buf));
900 #   endif
901         {
902             if (result != sizeof(buf)) {
903                 ABORT("Weird VirtualQuery result");
904             }
905             new_limit = (char *)p + buf.RegionSize;
906             protect = buf.Protect;
907             if (buf.State == MEM_COMMIT
908                 && (protect == PAGE_EXECUTE_READWRITE
909                     || protect == PAGE_READWRITE)
910                 && !GC_is_heap_base(buf.AllocationBase)
911                 /* This used to check for
912                  * !is_frame_buffer(p, buf.RegionSize, buf.Type)
913                  * instead of just checking for MEM_IMAGE.
914                  * If something breaks, change it back. */
915                 /* There is some evidence that we cannot always
916                  * ignore MEM_PRIVATE sections under Windows ME
917                  * and predecessors.  Hence we now also check for
918                  * that case.   */
919                 && (buf.Type == MEM_IMAGE ||
920                     !GC_wnt && buf.Type == MEM_PRIVATE)) {  
921 #               ifdef DEBUG_VIRTUALQUERY
922                   GC_dump_meminfo(&buf);
923 #               endif
924                 if ((char *)p != limit) {
925                     GC_cond_add_roots(base, limit);
926                     base = p;
927                 }
928                 limit = new_limit;
929             }
930         }
931         if (p > (LPVOID)new_limit /* overflow */) break;
932         p = (LPVOID)new_limit;
933     }
934     GC_cond_add_roots(base, limit);
935   }
936
937 #endif /* MSWIN32 || MSWINCE */
938   
939 #if defined(ALPHA) && defined(OSF1)
940
941 #include <loader.h>
942
943 void GC_register_dynamic_libraries()
944 {
945   int status;
946   ldr_process_t mypid;
947
948   /* module */
949     ldr_module_t moduleid = LDR_NULL_MODULE;
950     ldr_module_info_t moduleinfo;
951     size_t moduleinfosize = sizeof(moduleinfo);
952     size_t modulereturnsize;    
953
954   /* region */
955     ldr_region_t region; 
956     ldr_region_info_t regioninfo;
957     size_t regioninfosize = sizeof(regioninfo);
958     size_t regionreturnsize;
959
960   /* Obtain id of this process */
961     mypid = ldr_my_process();
962   
963   /* For each module */
964     while (TRUE) {
965
966       /* Get the next (first) module */
967         status = ldr_next_module(mypid, &moduleid);
968
969       /* Any more modules? */
970         if (moduleid == LDR_NULL_MODULE)
971             break;    /* No more modules */
972
973       /* Check status AFTER checking moduleid because */
974       /* of a bug in the non-shared ldr_next_module stub */
975         if (status != 0 ) {
976             GC_printf1("dynamic_load: status = %ld\n", (long)status);
977             {
978                 extern char *sys_errlist[];
979                 extern int sys_nerr;
980                 extern int errno;
981                 if (errno <= sys_nerr) {
982                     GC_printf1("dynamic_load: %s\n", (long)sys_errlist[errno]);
983                } else {
984                     GC_printf1("dynamic_load: %d\n", (long)errno);
985                 }
986         }
987             ABORT("ldr_next_module failed");
988          }
989
990       /* Get the module information */
991         status = ldr_inq_module(mypid, moduleid, &moduleinfo,
992                                 moduleinfosize, &modulereturnsize); 
993         if (status != 0 )
994             ABORT("ldr_inq_module failed");
995
996       /* is module for the main program (i.e. nonshared portion)? */
997           if (moduleinfo.lmi_flags & LDR_MAIN)
998               continue;    /* skip the main module */
999
1000 #     ifdef VERBOSE
1001           GC_printf("---Module---\n");
1002           GC_printf("Module ID            = %16ld\n", moduleinfo.lmi_modid);
1003           GC_printf("Count of regions     = %16d\n", moduleinfo.lmi_nregion);
1004           GC_printf("flags for module     = %16lx\n", moduleinfo.lmi_flags); 
1005           GC_printf("pathname of module   = \"%s\"\n", moduleinfo.lmi_name);
1006 #     endif
1007
1008       /* For each region in this module */
1009         for (region = 0; region < moduleinfo.lmi_nregion; region++) {
1010
1011           /* Get the region information */
1012             status = ldr_inq_region(mypid, moduleid, region, &regioninfo,
1013                                     regioninfosize, &regionreturnsize);
1014             if (status != 0 )
1015                 ABORT("ldr_inq_region failed");
1016
1017           /* only process writable (data) regions */
1018             if (! (regioninfo.lri_prot & LDR_W))
1019                 continue;
1020
1021 #         ifdef VERBOSE
1022               GC_printf("--- Region ---\n");
1023               GC_printf("Region number    = %16ld\n",
1024                         regioninfo.lri_region_no);
1025               GC_printf("Protection flags = %016x\n",  regioninfo.lri_prot);
1026               GC_printf("Virtual address  = %16p\n",   regioninfo.lri_vaddr);
1027               GC_printf("Mapped address   = %16p\n",   regioninfo.lri_mapaddr);
1028               GC_printf("Region size      = %16ld\n",  regioninfo.lri_size);
1029               GC_printf("Region name      = \"%s\"\n", regioninfo.lri_name);
1030 #         endif
1031
1032           /* register region as a garbage collection root */
1033             GC_add_roots_inner (
1034                 (char *)regioninfo.lri_mapaddr,
1035                 (char *)regioninfo.lri_mapaddr + regioninfo.lri_size,
1036                 TRUE);
1037
1038         }
1039     }
1040 }
1041 #endif
1042
1043 #if defined(HPUX)
1044
1045 #include <errno.h>
1046 #include <dl.h>
1047
1048 extern int errno;
1049 extern char *sys_errlist[];
1050 extern int sys_nerr;
1051
1052 void GC_register_dynamic_libraries()
1053 {
1054   int status;
1055   int index = 1; /* Ordinal position in shared library search list */
1056   struct shl_descriptor *shl_desc; /* Shared library info, see dl.h */
1057
1058   /* For each dynamic library loaded */
1059     while (TRUE) {
1060
1061       /* Get info about next shared library */
1062         status = shl_get(index, &shl_desc);
1063
1064       /* Check if this is the end of the list or if some error occured */
1065         if (status != 0) {
1066 #        ifdef GC_HPUX_THREADS
1067            /* I've seen errno values of 0.  The man page is not clear   */
1068            /* as to whether errno should get set on a -1 return.        */
1069            break;
1070 #        else
1071           if (errno == EINVAL) {
1072               break; /* Moved past end of shared library list --> finished */
1073           } else {
1074               if (errno <= sys_nerr) {
1075                     GC_printf1("dynamic_load: %s\n", (long) sys_errlist[errno]);
1076               } else {
1077                     GC_printf1("dynamic_load: %d\n", (long) errno);
1078               }
1079               ABORT("shl_get failed");
1080           }
1081 #        endif
1082         }
1083
1084 #     ifdef VERBOSE
1085           GC_printf0("---Shared library---\n");
1086           GC_printf1("\tfilename        = \"%s\"\n", shl_desc->filename);
1087           GC_printf1("\tindex           = %d\n", index);
1088           GC_printf1("\thandle          = %08x\n",
1089                                         (unsigned long) shl_desc->handle);
1090           GC_printf1("\ttext seg. start = %08x\n", shl_desc->tstart);
1091           GC_printf1("\ttext seg. end   = %08x\n", shl_desc->tend);
1092           GC_printf1("\tdata seg. start = %08x\n", shl_desc->dstart);
1093           GC_printf1("\tdata seg. end   = %08x\n", shl_desc->dend);
1094           GC_printf1("\tref. count      = %lu\n", shl_desc->ref_count);
1095 #     endif
1096
1097       /* register shared library's data segment as a garbage collection root */
1098         GC_add_roots_inner((char *) shl_desc->dstart,
1099                            (char *) shl_desc->dend, TRUE);
1100
1101         index++;
1102     }
1103 }
1104 #endif /* HPUX */
1105
1106 #ifdef RS6000
1107 #pragma alloca
1108 #include <sys/ldr.h>
1109 #include <sys/errno.h>
1110 void GC_register_dynamic_libraries()
1111 {
1112         int len;
1113         char *ldibuf;
1114         int ldibuflen;
1115         struct ld_info *ldi;
1116
1117         ldibuf = alloca(ldibuflen = 8192);
1118
1119         while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
1120                 if (errno != ENOMEM) {
1121                         ABORT("loadquery failed");
1122                 }
1123                 ldibuf = alloca(ldibuflen *= 2);
1124         }
1125
1126         ldi = (struct ld_info *)ldibuf;
1127         while (ldi) {
1128                 len = ldi->ldinfo_next;
1129                 GC_add_roots_inner(
1130                                 ldi->ldinfo_dataorg,
1131                                 (ptr_t)(unsigned long)ldi->ldinfo_dataorg
1132                                 + ldi->ldinfo_datasize,
1133                                 TRUE);
1134                 ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
1135         }
1136 }
1137 #endif /* RS6000 */
1138
1139 #ifdef DARWIN
1140
1141 /* __private_extern__ hack required for pre-3.4 gcc versions.   */
1142 #ifndef __private_extern__
1143 # define __private_extern__ extern
1144 # include <mach-o/dyld.h>
1145 # undef __private_extern__
1146 #else
1147 # include <mach-o/dyld.h>
1148 #endif
1149 #include <mach-o/getsect.h>
1150
1151 /*#define DARWIN_DEBUG*/
1152
1153 const static struct { 
1154         const char *seg;
1155         const char *sect;
1156 } GC_dyld_sections[] = {
1157         { SEG_DATA, SECT_DATA },
1158         { SEG_DATA, SECT_BSS },
1159         { SEG_DATA, SECT_COMMON }
1160 };
1161     
1162 #ifdef DARWIN_DEBUG
1163 static const char *GC_dyld_name_for_hdr(const struct GC_MACH_HEADER *hdr) {
1164     unsigned long i,c;
1165     c = _dyld_image_count();
1166     for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
1167         return _dyld_get_image_name(i);
1168     return NULL;
1169 }
1170 #endif
1171         
1172 /* This should never be called by a thread holding the lock */
1173 static void GC_dyld_image_add(const struct GC_MACH_HEADER *hdr, intptr_t slide)
1174 {
1175     unsigned long start,end,i;
1176     const struct GC_MACH_SECTION *sec;
1177     if (GC_no_dls) return;
1178     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1179
1180       sec = GC_GETSECTBYNAME (hdr, GC_dyld_sections[i].seg,
1181                               GC_dyld_sections[i].sect);
1182         if(sec == NULL || sec->size == 0) continue;
1183         start = slide + sec->addr;
1184         end = start + sec->size;
1185 #       ifdef DARWIN_DEBUG
1186             GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
1187                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1188 #       endif
1189         GC_add_roots((char*)start,(char*)end);
1190     }
1191 #   ifdef DARWIN_DEBUG
1192         GC_print_static_roots();
1193 #   endif
1194 }
1195
1196 /* This should never be called by a thread holding the lock */
1197 static void GC_dyld_image_remove(const struct GC_MACH_HEADER *hdr,
1198                                  intptr_t slide) {
1199     unsigned long start,end,i;
1200     const struct GC_MACH_SECTION *sec;
1201     for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
1202       sec = GC_GETSECTBYNAME (hdr, GC_dyld_sections[i].seg,
1203                               GC_dyld_sections[i].sect);
1204         if(sec == NULL || sec->size == 0) continue;
1205         start = slide + sec->addr;
1206         end = start + sec->size;
1207 #       ifdef DARWIN_DEBUG
1208             GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
1209                 start,end,sec->size,GC_dyld_name_for_hdr(hdr));
1210 #               endif
1211         GC_remove_roots((char*)start,(char*)end);
1212     }
1213 #   ifdef DARWIN_DEBUG
1214         GC_print_static_roots();
1215 #   endif
1216 }
1217
1218 void GC_register_dynamic_libraries() {
1219     /* Currently does nothing. The callbacks are setup by GC_init_dyld() 
1220     The dyld library takes it from there. */
1221 }
1222
1223 /* The _dyld_* functions have an internal lock so no _dyld functions
1224    can be called while the world is stopped without the risk of a deadlock.
1225    Because of this we MUST setup callbacks BEFORE we ever stop the world.
1226    This should be called BEFORE any thread in created and WITHOUT the
1227    allocation lock held. */
1228    
1229 void GC_init_dyld() {
1230   static GC_bool initialized = FALSE;
1231   char *bind_fully_env = NULL;
1232   
1233   if(initialized) return;
1234   
1235 #   ifdef DARWIN_DEBUG
1236   GC_printf0("Registering dyld callbacks...\n");
1237 #   endif
1238   
1239   /* Apple's Documentation:
1240      When you call _dyld_register_func_for_add_image, the dynamic linker runtime
1241      calls the specified callback (func) once for each of the images that is
1242      currently loaded into the program. When a new image is added to the program,
1243      your callback is called again with the mach_header for the new image, and the      
1244      virtual memory slide amount of the new image. 
1245      
1246      This WILL properly register already linked libraries and libraries 
1247      linked in the future
1248   */
1249   
1250     _dyld_register_func_for_add_image(GC_dyld_image_add);
1251     _dyld_register_func_for_remove_image(GC_dyld_image_remove);
1252
1253     /* Set this early to avoid reentrancy issues. */
1254     initialized = TRUE;
1255
1256     bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
1257     
1258     if (bind_fully_env == NULL) {
1259 #   ifdef DARWIN_DEBUG
1260       GC_printf0("Forcing full bind of GC code...\n");
1261 #   endif
1262       
1263       if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
1264         GC_abort("_dyld_bind_fully_image_containing_address failed");
1265     }
1266
1267 }
1268
1269 #define HAVE_REGISTER_MAIN_STATIC_DATA
1270 GC_bool GC_register_main_static_data()
1271 {
1272   /* Already done through dyld callbacks */
1273   return FALSE;
1274 }
1275
1276 #endif /* DARWIN */
1277
1278 #else /* !DYNAMIC_LOADING */
1279
1280 #ifdef PCR
1281
1282 #   include "il/PCR_IL.h"
1283 #   include "th/PCR_ThCtl.h"
1284 #   include "mm/PCR_MM.h"
1285
1286 void GC_register_dynamic_libraries()
1287 {
1288     /* Add new static data areas of dynamically loaded modules. */
1289         {
1290           PCR_IL_LoadedFile * p = PCR_IL_GetLastLoadedFile();
1291           PCR_IL_LoadedSegment * q;
1292           
1293           /* Skip uncommited files */
1294           while (p != NIL && !(p -> lf_commitPoint)) {
1295               /* The loading of this file has not yet been committed    */
1296               /* Hence its description could be inconsistent.           */
1297               /* Furthermore, it hasn't yet been run.  Hence its data   */
1298               /* segments can't possibly reference heap allocated       */
1299               /* objects.                                               */
1300               p = p -> lf_prev;
1301           }
1302           for (; p != NIL; p = p -> lf_prev) {
1303             for (q = p -> lf_ls; q != NIL; q = q -> ls_next) {
1304               if ((q -> ls_flags & PCR_IL_SegFlags_Traced_MASK)
1305                   == PCR_IL_SegFlags_Traced_on) {
1306                 GC_add_roots_inner
1307                         ((char *)(q -> ls_addr), 
1308                          (char *)(q -> ls_addr) + q -> ls_bytes,
1309                          TRUE);
1310               }
1311             }
1312           }
1313         }
1314 }
1315
1316
1317 #else /* !PCR */
1318
1319 void GC_register_dynamic_libraries(){}
1320
1321 int GC_no_dynamic_loading;
1322
1323 #endif /* !PCR */
1324
1325 #endif /* !DYNAMIC_LOADING */
1326
1327 #ifndef HAVE_REGISTER_MAIN_STATIC_DATA
1328
1329 /* Do we need to separately register the main static data segment? */
1330 GC_bool GC_register_main_static_data()
1331 {
1332   return TRUE;
1333 }
1334 #endif /* HAVE_REGISTER_MAIN_STATIC_DATA */
1335