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