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