OSDN Git Service

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