OSDN Git Service

* config/darwin.h (SUBTARGET_OPTIONS): Add -mmacosx= option.
[pf3gnuchains/gcc-fork.git] / gcc / config / darwin.c
1 /* Functions for generic Darwin as target machine for GNU C compiler.
2    Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001, 2002, 2003, 2004
3    Free Software Foundation, Inc.
4    Contributed by Apple Computer Inc.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "regs.h"
29 #include "hard-reg-set.h"
30 #include "real.h"
31 #include "insn-config.h"
32 #include "conditions.h"
33 #include "insn-flags.h"
34 #include "output.h"
35 #include "insn-attr.h"
36 #include "flags.h"
37 #include "tree.h"
38 #include "expr.h"
39 #include "reload.h"
40 #include "function.h"
41 #include "ggc.h"
42 #include "langhooks.h"
43 #include "tm_p.h"
44 #include "errors.h"
45
46 static int machopic_data_defined_p (const char *);
47 static void update_non_lazy_ptrs (const char *);
48 static void update_stubs (const char *);
49 static const char *machopic_non_lazy_ptr_name (const char*);
50
51 /* Earliest operating system for which generated code is targeted, as string
52    and as integer.  The string form is "10.0", "10.1", etc.  The corresponding
53    numeric versions are 1000, 1010, etc.  This number is used for feature 
54    tests of the form "enable_this_feature = macosx_version_min_required >= n",
55    so 0 is a conservative default. */
56
57 const char *darwin_macosx_version_name;
58 unsigned int macosx_version_min_required = 0;
59
60 /* Parse -macosx= option. */
61
62 static struct darwin_macosx_vers {
63   const char *vers_str;
64   unsigned int vers_num;
65 } darwin_macosx_vers_tbl[] = {
66   { "10.0", 1000 },
67   { "10.1", 1010 },
68   { "10.2", 1020 },
69   { "jaguar", 1020 },
70   { "10.3", 1030 },
71   { "panther", 1030 },
72   { "10.4", 1040 },
73   { "10.5", 1050 },
74   { NULL, 0 }
75 };  
76
77 void darwin_parse_macosx_version_name (void)
78 {
79   if (darwin_macosx_version_name)
80     {
81       struct darwin_macosx_vers *v = darwin_macosx_vers_tbl;
82       while (v->vers_str
83              && strcmp (darwin_macosx_version_name, v->vers_str) != 0)
84         v++;
85
86       if (v->vers_str)
87         macosx_version_min_required = v->vers_num;
88       else
89         warning ("-macosx=%s: unrecognized version", darwin_macosx_version_name);
90     }
91 }
92
93 int
94 name_needs_quotes (const char *name)
95 {
96   int c;
97   while ((c = *name++) != '\0')
98     if (! ISIDNUM (c) && c != '.' && c != '$')
99       return 1;
100   return 0;
101 }
102
103 /*
104  * flag_pic = 1 ... generate only indirections
105  * flag_pic = 2 ... generate indirections and pure code
106  */
107
108 /* This module assumes that (const (symbol_ref "foo")) is a legal pic
109    reference, which will not be changed.  */
110
111 static GTY(()) tree machopic_defined_list;
112
113 enum machopic_addr_class
114 machopic_classify_ident (tree ident)
115 {
116   const char *name = IDENTIFIER_POINTER (ident);
117   int lprefix = (((name[0] == '*' || name[0] == '&')
118                   && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
119                  || (   name[0] == '_'
120                      && name[1] == 'O'
121                      && name[2] == 'B'
122                      && name[3] == 'J'
123                      && name[4] == 'C'
124                      && name[5] == '_'));
125   tree temp;
126
127   /* The PIC base symbol is always defined.  */
128   if (! strcmp (name, "<pic base>"))
129     return MACHOPIC_DEFINED_DATA;
130
131   if (name[0] != '!')
132     {
133       /* Here if no special encoding to be found.  */
134       if (lprefix)
135         {
136           const char *name = IDENTIFIER_POINTER (ident);
137           int len = strlen (name);
138
139           if ((len > 5 && !strcmp (name + len - 5, "$stub"))
140               || (len > 6 && !strcmp (name + len - 6, "$stub\"")))
141             return MACHOPIC_DEFINED_FUNCTION;
142           return MACHOPIC_DEFINED_DATA;
143         }
144
145       for (temp = machopic_defined_list;
146            temp != NULL_TREE;
147            temp = TREE_CHAIN (temp))
148         {
149           if (ident == TREE_VALUE (temp))
150             return MACHOPIC_DEFINED_DATA;
151         }
152
153       if (TREE_ASM_WRITTEN (ident))
154         return MACHOPIC_DEFINED_DATA;
155
156       return MACHOPIC_UNDEFINED;
157     }
158
159   else if (name[1] == 'D')
160     return MACHOPIC_DEFINED_DATA;
161
162   else if (name[1] == 'T')
163     return MACHOPIC_DEFINED_FUNCTION;
164
165   /* It is possible that someone is holding a "stale" name, which has
166      since been defined.  See if there is a "defined" name (i.e,
167      different from NAME only in having a '!D_' or a '!T_' instead of
168      a '!d_' or '!t_' prefix) in the identifier hash tables.  If so, say
169      that this identifier is defined.  */
170   else if (name[1] == 'd' || name[1] == 't')
171     {
172       char *new_name;
173       new_name = (char *)alloca (strlen (name) + 1);
174       strcpy (new_name, name);
175       new_name[1] = (name[1] == 'd') ? 'D' : 'T';
176       if (maybe_get_identifier (new_name) != NULL)
177         return  (name[1] == 'd') ? MACHOPIC_DEFINED_DATA
178                                  : MACHOPIC_DEFINED_FUNCTION;
179     }
180
181   for (temp = machopic_defined_list; temp != NULL_TREE; temp = TREE_CHAIN (temp))
182     {
183       if (ident == TREE_VALUE (temp))
184         {
185           if (name[1] == 'T')
186             return MACHOPIC_DEFINED_FUNCTION;
187           else
188             return MACHOPIC_DEFINED_DATA;
189         }
190     }
191
192   if (name[1] == 't' || name[1] == 'T')
193     {
194       if (lprefix)
195         return MACHOPIC_DEFINED_FUNCTION;
196       else
197         return MACHOPIC_UNDEFINED_FUNCTION;
198     }
199   else
200     {
201       if (lprefix)
202         return MACHOPIC_DEFINED_DATA;
203       else
204         return MACHOPIC_UNDEFINED_DATA;
205     }
206 }
207
208
209 enum machopic_addr_class
210 machopic_classify_name (const char *name)
211 {
212   return machopic_classify_ident (get_identifier (name));
213 }
214
215 int
216 machopic_ident_defined_p (tree ident)
217 {
218   switch (machopic_classify_ident (ident))
219     {
220     case MACHOPIC_UNDEFINED:
221     case MACHOPIC_UNDEFINED_DATA:
222     case MACHOPIC_UNDEFINED_FUNCTION:
223       return 0;
224     default:
225       return 1;
226     }
227 }
228
229 static int
230 machopic_data_defined_p (const char *name)
231 {
232   switch (machopic_classify_ident (get_identifier (name)))
233     {
234     case MACHOPIC_DEFINED_DATA:
235       return 1;
236     default:
237       return 0;
238     }
239 }
240
241 int
242 machopic_name_defined_p (const char *name)
243 {
244   return machopic_ident_defined_p (get_identifier (name));
245 }
246
247 void
248 machopic_define_ident (tree ident)
249 {
250   if (!machopic_ident_defined_p (ident))
251     machopic_defined_list =
252       tree_cons (NULL_TREE, ident, machopic_defined_list);
253 }
254
255 void
256 machopic_define_name (const char *name)
257 {
258   machopic_define_ident (get_identifier (name));
259 }
260
261 static GTY(()) char * function_base;
262
263 const char *
264 machopic_function_base_name (void)
265 {
266   const char *current_name;
267   /* if dynamic-no-pic is on, we should not get here */
268   if (MACHO_DYNAMIC_NO_PIC_P)
269     abort ();
270   current_name =
271     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
272
273   if (function_base == NULL)
274     function_base =
275       (char *) ggc_alloc_string ("<pic base>", sizeof ("<pic base>"));
276
277   current_function_uses_pic_offset_table = 1;
278
279   return function_base;
280 }
281
282 static GTY(()) const char * function_base_func_name;
283 static GTY(()) int current_pic_label_num;
284
285 void
286 machopic_output_function_base_name (FILE *file)
287 {
288   const char *current_name;
289
290   /* If dynamic-no-pic is on, we should not get here.  */
291   if (MACHO_DYNAMIC_NO_PIC_P)
292     abort ();
293   current_name =
294     IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (current_function_decl));
295   if (function_base_func_name != current_name)
296     {
297       ++current_pic_label_num;
298       function_base_func_name = current_name;
299     }
300   fprintf (file, "\"L%011d$pb\"", current_pic_label_num);
301 }
302
303 static GTY(()) tree machopic_non_lazy_pointers;
304
305 /* Return a non-lazy pointer name corresponding to the given name,
306    either by finding it in our list of pointer names, or by generating
307    a new one.  */
308
309 static const char *
310 machopic_non_lazy_ptr_name (const char *name)
311 {
312   const char *temp_name;
313   tree temp, ident = get_identifier (name);
314
315   for (temp = machopic_non_lazy_pointers;
316        temp != NULL_TREE;
317        temp = TREE_CHAIN (temp))
318     {
319       if (ident == TREE_VALUE (temp))
320         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
321     }
322
323   name = darwin_strip_name_encoding (name);
324
325   /* Try again, but comparing names this time.  */
326   for (temp = machopic_non_lazy_pointers;
327        temp != NULL_TREE;
328        temp = TREE_CHAIN (temp))
329     {
330       if (TREE_VALUE (temp))
331         {
332           temp_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
333           temp_name = darwin_strip_name_encoding (temp_name);
334           if (strcmp (name, temp_name) == 0)
335             return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
336         }
337     }
338
339   {
340     char *buffer;
341     int namelen = strlen (name);
342     int bufferlen = 0;
343     tree ptr_name;
344
345     buffer = alloca (namelen + strlen("$non_lazy_ptr") + 5);
346
347     strcpy (buffer, "&L");
348     bufferlen = 2;
349     if (name[0] == '*')
350       {
351         memcpy (buffer + bufferlen, name+1, namelen-1+1);
352         bufferlen += namelen-1;
353       }
354     else
355       {
356         buffer[bufferlen] = '_';
357         memcpy (buffer + bufferlen +1, name, namelen+1);
358         bufferlen += namelen +1;
359       }
360
361     memcpy (buffer + bufferlen, "$non_lazy_ptr", strlen("$non_lazy_ptr")+1);
362     bufferlen += strlen("$non_lazy_ptr");
363     ptr_name = get_identifier (buffer);
364
365     machopic_non_lazy_pointers
366       = tree_cons (ptr_name, ident, machopic_non_lazy_pointers);
367
368     TREE_USED (machopic_non_lazy_pointers) = 0;
369
370     return IDENTIFIER_POINTER (ptr_name);
371   }
372 }
373
374 static GTY(()) tree machopic_stubs;
375
376 /* Return the name of the stub corresponding to the given name,
377    generating a new stub name if necessary.  */
378
379 const char *
380 machopic_stub_name (const char *name)
381 {
382   tree temp, ident = get_identifier (name);
383   const char *tname;
384
385   for (temp = machopic_stubs;
386        temp != NULL_TREE;
387        temp = TREE_CHAIN (temp))
388     {
389       if (ident == TREE_VALUE (temp))
390         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
391       tname = IDENTIFIER_POINTER (TREE_VALUE (temp));
392       if (strcmp (name, tname) == 0)
393         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
394       /* A library call name might not be section-encoded yet, so try
395          it against a stripped name.  */
396       if (name[0] != '!'
397           && tname[0] == '!'
398           && strcmp (name, tname + 4) == 0)
399         return IDENTIFIER_POINTER (TREE_PURPOSE (temp));
400     }
401
402   name = darwin_strip_name_encoding (name);
403
404   {
405     char *buffer;
406     int bufferlen = 0;
407     int namelen = strlen (name);
408     tree ptr_name;
409     int needs_quotes = name_needs_quotes (name);
410
411     buffer = alloca (namelen + 20);
412
413     if (needs_quotes)
414       {
415         strcpy (buffer, "&\"L");
416         bufferlen = strlen("&\"L");
417       }
418     else
419       {
420         strcpy (buffer, "&L");
421         bufferlen = strlen("&L");
422       }
423     
424     if (name[0] == '*')
425       {
426         memcpy (buffer + bufferlen, name+1, namelen - 1 +1);
427         bufferlen += namelen - 1;
428       }
429     else
430       {
431         buffer[bufferlen] = '_';
432         memcpy (buffer + bufferlen +1, name, namelen+1);
433         bufferlen += namelen +1;
434       }
435
436     if (needs_quotes)
437       {
438         memcpy (buffer + bufferlen, "$stub\"", strlen("$stub\"")+1);
439         bufferlen += strlen("$stub\"");
440       }
441     else
442       {
443         memcpy (buffer + bufferlen, "$stub", strlen("$stub")+1);
444         bufferlen += strlen("$stub");
445       }
446     ptr_name = get_identifier (buffer);
447
448     machopic_stubs = tree_cons (ptr_name, ident, machopic_stubs);
449     TREE_USED (machopic_stubs) = 0;
450
451     return IDENTIFIER_POINTER (ptr_name);
452   }
453 }
454
455 void
456 machopic_validate_stub_or_non_lazy_ptr (const char *name, int validate_stub)
457 {
458   const char *real_name;
459   tree temp, ident = get_identifier (name), id2;
460
461     for (temp = (validate_stub ? machopic_stubs : machopic_non_lazy_pointers);
462          temp != NULL_TREE;
463          temp = TREE_CHAIN (temp))
464       if (ident == TREE_PURPOSE (temp))
465         {
466           /* Mark both the stub or non-lazy pointer as well as the
467              original symbol as being referenced.  */
468           TREE_USED (temp) = 1;
469           if (TREE_CODE (TREE_VALUE (temp)) == IDENTIFIER_NODE)
470             mark_referenced (TREE_VALUE (temp));
471           real_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
472           real_name = darwin_strip_name_encoding (real_name);
473           id2 = maybe_get_identifier (real_name);
474           if (id2)
475             mark_referenced (id2);
476         }
477 }
478
479 /* Transform ORIG, which may be any data source, to the corresponding
480    source using indirections.  */
481
482 rtx
483 machopic_indirect_data_reference (rtx orig, rtx reg)
484 {
485   rtx ptr_ref = orig;
486
487   if (! MACHOPIC_INDIRECT)
488     return orig;
489
490   if (GET_CODE (orig) == SYMBOL_REF)
491     {
492       const char *name = XSTR (orig, 0);
493       int defined = machopic_data_defined_p (name);
494
495       if (defined && MACHO_DYNAMIC_NO_PIC_P)
496         {
497 #if defined (TARGET_TOC)
498            emit_insn (gen_macho_high (reg, orig));
499            emit_insn (gen_macho_low (reg, reg, orig));
500 #else
501            /* some other cpu -- writeme!  */
502            abort ();
503 #endif
504            return reg;
505         }
506       else if (defined)
507         {
508 #if defined (TARGET_TOC) || defined (HAVE_lo_sum)
509           rtx pic_base = gen_rtx_SYMBOL_REF (Pmode,
510                                              machopic_function_base_name ());
511           rtx offset = gen_rtx_CONST (Pmode,
512                                       gen_rtx_MINUS (Pmode, orig, pic_base));
513 #endif
514
515 #if defined (TARGET_TOC) /* i.e., PowerPC */
516           rtx hi_sum_reg = (no_new_pseudos ? reg : gen_reg_rtx (Pmode));
517
518           if (reg == NULL)
519             abort ();
520
521           emit_insn (gen_rtx_SET (Pmode, hi_sum_reg,
522                               gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
523                                        gen_rtx_HIGH (Pmode, offset))));
524           emit_insn (gen_rtx_SET (Pmode, reg,
525                                   gen_rtx_LO_SUM (Pmode, hi_sum_reg, offset)));
526
527           orig = reg;
528 #else
529 #if defined (HAVE_lo_sum)
530           if (reg == 0) abort ();
531
532           emit_insn (gen_rtx_SET (VOIDmode, reg,
533                                   gen_rtx_HIGH (Pmode, offset)));
534           emit_insn (gen_rtx_SET (VOIDmode, reg,
535                                   gen_rtx_LO_SUM (Pmode, reg, offset)));
536           emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
537
538           orig = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, reg);
539 #endif
540 #endif
541           return orig;
542         }
543
544       ptr_ref = gen_rtx_SYMBOL_REF (Pmode,
545                                     machopic_non_lazy_ptr_name (name));
546
547       ptr_ref = gen_rtx_MEM (Pmode, ptr_ref);
548       RTX_UNCHANGING_P (ptr_ref) = 1;
549
550       return ptr_ref;
551     }
552   else if (GET_CODE (orig) == CONST)
553     {
554       rtx base, result;
555
556       /* legitimize both operands of the PLUS */
557       if (GET_CODE (XEXP (orig, 0)) == PLUS)
558         {
559           base = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 0),
560                                                    reg);
561           orig = machopic_indirect_data_reference (XEXP (XEXP (orig, 0), 1),
562                                                    (base == reg ? 0 : reg));
563         }
564       else
565         return orig;
566
567       if (MACHOPIC_PURE && GET_CODE (orig) == CONST_INT)
568         result = plus_constant (base, INTVAL (orig));
569       else
570         result = gen_rtx_PLUS (Pmode, base, orig);
571
572       if (MACHOPIC_JUST_INDIRECT && GET_CODE (base) == MEM)
573         {
574           if (reg)
575             {
576               emit_move_insn (reg, result);
577               result = reg;
578             }
579           else
580             {
581               result = force_reg (GET_MODE (result), result);
582             }
583         }
584
585       return result;
586
587     }
588   else if (GET_CODE (orig) == MEM)
589     XEXP (ptr_ref, 0) = machopic_indirect_data_reference (XEXP (orig, 0), reg);
590   /* When the target is i386, this code prevents crashes due to the
591      compiler's ignorance on how to move the PIC base register to
592      other registers.  (The reload phase sometimes introduces such
593      insns.)  */
594   else if (GET_CODE (orig) == PLUS
595            && GET_CODE (XEXP (orig, 0)) == REG
596            && REGNO (XEXP (orig, 0)) == PIC_OFFSET_TABLE_REGNUM
597 #ifdef I386
598            /* Prevent the same register from being erroneously used
599               as both the base and index registers.  */
600            && GET_CODE (XEXP (orig, 1)) == CONST
601 #endif
602            && reg)
603     {
604       emit_move_insn (reg, XEXP (orig, 0));
605       XEXP (ptr_ref, 0) = reg;
606     }
607   return ptr_ref;
608 }
609
610 /* Transform TARGET (a MEM), which is a function call target, to the
611    corresponding symbol_stub if necessary.  Return a new MEM.  */
612
613 rtx
614 machopic_indirect_call_target (rtx target)
615 {
616   if (GET_CODE (target) != MEM)
617     return target;
618
619   if (MACHOPIC_INDIRECT && GET_CODE (XEXP (target, 0)) == SYMBOL_REF)
620     {
621       enum machine_mode mode = GET_MODE (XEXP (target, 0));
622       const char *name = XSTR (XEXP (target, 0), 0);
623
624       /* If the name is already defined, we need do nothing.  */
625       if (name[0] == '!' && name[1] == 'T')
626         return target;
627
628       if (!machopic_name_defined_p (name))
629         {
630           const char *stub_name = machopic_stub_name (name);
631
632           XEXP (target, 0) = gen_rtx_SYMBOL_REF (mode, stub_name);
633           RTX_UNCHANGING_P (target) = 1;
634         }
635     }
636
637   return target;
638 }
639
640 rtx
641 machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
642 {
643   rtx pic_ref = orig;
644
645   if (! MACHOPIC_INDIRECT)
646     return orig;
647
648   /* First handle a simple SYMBOL_REF or LABEL_REF */
649   if (GET_CODE (orig) == LABEL_REF
650       || (GET_CODE (orig) == SYMBOL_REF
651           ))
652     {
653       /* addr(foo) = &func+(foo-func) */
654       rtx pic_base;
655
656       orig = machopic_indirect_data_reference (orig, reg);
657
658       if (GET_CODE (orig) == PLUS
659           && GET_CODE (XEXP (orig, 0)) == REG)
660         {
661           if (reg == 0)
662             return force_reg (mode, orig);
663
664           emit_move_insn (reg, orig);
665           return reg;
666         }
667
668       /* if dynamic-no-pic then use 0 as the pic base  */
669       if (MACHO_DYNAMIC_NO_PIC_P)
670         pic_base = CONST0_RTX (Pmode);
671       else
672       pic_base = gen_rtx_SYMBOL_REF (Pmode, machopic_function_base_name ());
673
674       if (GET_CODE (orig) == MEM)
675         {
676           if (reg == 0)
677             {
678               if (reload_in_progress)
679                 abort ();
680               else
681                 reg = gen_reg_rtx (Pmode);
682             }
683
684 #ifdef HAVE_lo_sum
685           if (MACHO_DYNAMIC_NO_PIC_P
686               && (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
687                   || GET_CODE (XEXP (orig, 0)) == LABEL_REF))
688             {
689 #if defined (TARGET_TOC)        /* ppc  */
690               rtx temp_reg = (no_new_pseudos) ? reg : gen_reg_rtx (Pmode);
691               rtx asym = XEXP (orig, 0);
692               rtx mem;
693
694               emit_insn (gen_macho_high (temp_reg, asym));
695               mem = gen_rtx_MEM (GET_MODE (orig),
696                                  gen_rtx_LO_SUM (Pmode, temp_reg, asym));
697               RTX_UNCHANGING_P (mem) = 1;
698               emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
699 #else
700               /* Some other CPU -- WriteMe! but right now there are no other platform that can use dynamic-no-pic  */
701               abort ();
702 #endif
703               pic_ref = reg;
704             }
705           else
706           if (GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
707               || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
708             {
709               rtx offset = gen_rtx_CONST (Pmode,
710                                           gen_rtx_MINUS (Pmode,
711                                                          XEXP (orig, 0),
712                                                          pic_base));
713 #if defined (TARGET_TOC) /* i.e., PowerPC */
714               /* Generating a new reg may expose opportunities for
715                  common subexpression elimination.  */
716               rtx hi_sum_reg = no_new_pseudos ? reg : gen_reg_rtx (SImode);
717               rtx mem;
718               rtx insn;
719               rtx sum;
720               
721               sum = gen_rtx_HIGH (Pmode, offset);
722               if (! MACHO_DYNAMIC_NO_PIC_P)
723                 sum = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, sum);
724
725               emit_insn (gen_rtx_SET (Pmode, hi_sum_reg, sum));
726
727               mem = gen_rtx_MEM (GET_MODE (orig),
728                                  gen_rtx_LO_SUM (Pmode, 
729                                                  hi_sum_reg, offset));
730               RTX_UNCHANGING_P (mem) = 1;
731               insn = emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
732               REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, pic_ref, 
733                                                     REG_NOTES (insn));
734
735               pic_ref = reg;
736 #else
737               emit_insn (gen_rtx_USE (VOIDmode,
738                                       gen_rtx_REG (Pmode, 
739                                                    PIC_OFFSET_TABLE_REGNUM)));
740
741               emit_insn (gen_rtx_SET (VOIDmode, reg,
742                                       gen_rtx_HIGH (Pmode,
743                                                     gen_rtx_CONST (Pmode, 
744                                                                    offset))));
745               emit_insn (gen_rtx_SET (VOIDmode, reg,
746                                   gen_rtx_LO_SUM (Pmode, reg,
747                                            gen_rtx_CONST (Pmode, offset))));
748               pic_ref = gen_rtx_PLUS (Pmode,
749                                       pic_offset_table_rtx, reg);
750 #endif
751             }
752           else
753 #endif  /* HAVE_lo_sum */
754             {
755               rtx pic = pic_offset_table_rtx;
756               if (GET_CODE (pic) != REG)
757                 {
758                   emit_move_insn (reg, pic);
759                   pic = reg;
760                 }
761 #if 0
762               emit_insn (gen_rtx_USE (VOIDmode,
763                                       gen_rtx_REG (Pmode, 
764                                                    PIC_OFFSET_TABLE_REGNUM)));
765 #endif
766
767               pic_ref = gen_rtx_PLUS (Pmode,
768                                       pic,
769                                       gen_rtx_CONST (Pmode,
770                                           gen_rtx_MINUS (Pmode,
771                                                          XEXP (orig, 0),
772                                                          pic_base)));
773             }
774
775 #if !defined (TARGET_TOC)
776           emit_move_insn (reg, pic_ref);
777           pic_ref = gen_rtx_MEM (GET_MODE (orig), reg);
778 #endif
779           RTX_UNCHANGING_P (pic_ref) = 1;
780         }
781       else
782         {
783
784 #ifdef HAVE_lo_sum
785           if (GET_CODE (orig) == SYMBOL_REF
786               || GET_CODE (orig) == LABEL_REF)
787             {
788               rtx offset = gen_rtx_CONST (Pmode,
789                                           gen_rtx_MINUS (Pmode, 
790                                                          orig, pic_base));
791 #if defined (TARGET_TOC) /* i.e., PowerPC */
792               rtx hi_sum_reg;
793
794               if (reg == 0)
795                 {
796                   if (reload_in_progress)
797                     abort ();
798                   else
799                     reg = gen_reg_rtx (SImode);
800                 }
801
802               hi_sum_reg = reg;
803
804               emit_insn (gen_rtx_SET (Pmode, hi_sum_reg,
805                                       (MACHO_DYNAMIC_NO_PIC_P)
806                                       ? gen_rtx_HIGH (Pmode, offset)
807                                       : gen_rtx_PLUS (Pmode,
808                                                       pic_offset_table_rtx,
809                                                       gen_rtx_HIGH (Pmode, 
810                                                                     offset))));
811               emit_insn (gen_rtx_SET (VOIDmode, reg,
812                                       gen_rtx_LO_SUM (Pmode,
813                                                       hi_sum_reg, offset)));
814               pic_ref = reg;
815               RTX_UNCHANGING_P (pic_ref) = 1;
816 #else
817               emit_insn (gen_rtx_SET (VOIDmode, reg,
818                                       gen_rtx_HIGH (Pmode, offset)));
819               emit_insn (gen_rtx_SET (VOIDmode, reg,
820                                       gen_rtx_LO_SUM (Pmode, reg, offset)));
821               pic_ref = gen_rtx_PLUS (Pmode,
822                                       pic_offset_table_rtx, reg);
823               RTX_UNCHANGING_P (pic_ref) = 1;
824 #endif
825             }
826           else
827 #endif  /*  HAVE_lo_sum  */
828             {
829               if (GET_CODE (orig) == REG)
830                 {
831                   return orig;
832                 }
833               else
834                 {
835                   rtx pic = pic_offset_table_rtx;
836                   if (GET_CODE (pic) != REG)
837                     {
838                       emit_move_insn (reg, pic);
839                       pic = reg;
840                     }
841 #if 0
842                   emit_insn (gen_rtx_USE (VOIDmode,
843                                           pic_offset_table_rtx));
844 #endif
845                   pic_ref = gen_rtx_PLUS (Pmode,
846                                           pic,
847                                           gen_rtx_CONST (Pmode,
848                                               gen_rtx_MINUS (Pmode,
849                                                              orig, pic_base)));
850                 }
851             }
852         }
853
854       if (GET_CODE (pic_ref) != REG)
855         {
856           if (reg != 0)
857             {
858               emit_move_insn (reg, pic_ref);
859               return reg;
860             }
861           else
862             {
863               return force_reg (mode, pic_ref);
864             }
865         }
866       else
867         {
868           return pic_ref;
869         }
870     }
871
872   else if (GET_CODE (orig) == SYMBOL_REF)
873     return orig;
874
875   else if (GET_CODE (orig) == PLUS
876            && (GET_CODE (XEXP (orig, 0)) == MEM
877                || GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
878                || GET_CODE (XEXP (orig, 0)) == LABEL_REF)
879            && XEXP (orig, 0) != pic_offset_table_rtx
880            && GET_CODE (XEXP (orig, 1)) != REG)
881
882     {
883       rtx base;
884       int is_complex = (GET_CODE (XEXP (orig, 0)) == MEM);
885
886       base = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
887       orig = machopic_legitimize_pic_address (XEXP (orig, 1),
888                                               Pmode, (base == reg ? 0 : reg));
889       if (GET_CODE (orig) == CONST_INT)
890         {
891           pic_ref = plus_constant (base, INTVAL (orig));
892           is_complex = 1;
893         }
894       else
895         pic_ref = gen_rtx_PLUS (Pmode, base, orig);
896
897       if (RTX_UNCHANGING_P (base) && RTX_UNCHANGING_P (orig))
898         RTX_UNCHANGING_P (pic_ref) = 1;
899
900       if (reg && is_complex)
901         {
902           emit_move_insn (reg, pic_ref);
903           pic_ref = reg;
904         }
905       /* Likewise, should we set special REG_NOTEs here?  */
906     }
907
908   else if (GET_CODE (orig) == CONST)
909     {
910       return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
911     }
912
913   else if (GET_CODE (orig) == MEM
914            && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
915     {
916       rtx addr = machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
917
918       addr = gen_rtx_MEM (GET_MODE (orig), addr);
919       RTX_UNCHANGING_P (addr) = RTX_UNCHANGING_P (orig);
920       emit_move_insn (reg, addr);
921       pic_ref = reg;
922     }
923
924   return pic_ref;
925 }
926
927
928 void
929 machopic_finish (FILE *asm_out_file)
930 {
931   tree temp;
932
933   for (temp = machopic_stubs;
934        temp != NULL_TREE;
935        temp = TREE_CHAIN (temp))
936     {
937       const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
938       const char *stub_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
939       char *sym;
940       char *stub;
941
942       if (! TREE_USED (temp))
943         continue;
944
945       /* If the symbol is actually defined, we don't need a stub.  */
946       if (sym_name[0] == '!' && sym_name[1] == 'T')
947         continue;
948
949       sym_name = darwin_strip_name_encoding (sym_name);
950
951       sym = alloca (strlen (sym_name) + 2);
952       if (sym_name[0] == '*' || sym_name[0] == '&')
953         strcpy (sym, sym_name + 1);
954       else if (sym_name[0] == '-' || sym_name[0] == '+')
955         strcpy (sym, sym_name);
956       else
957         sym[0] = '_', strcpy (sym + 1, sym_name);
958
959       stub = alloca (strlen (stub_name) + 2);
960       if (stub_name[0] == '*' || stub_name[0] == '&')
961         strcpy (stub, stub_name + 1);
962       else
963         stub[0] = '_', strcpy (stub + 1, stub_name);
964
965       machopic_output_stub (asm_out_file, sym, stub);
966     }
967
968   for (temp = machopic_non_lazy_pointers;
969        temp != NULL_TREE;
970        temp = TREE_CHAIN (temp))
971     {
972       const char *const sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
973       const char *const lazy_name = IDENTIFIER_POINTER (TREE_PURPOSE (temp));
974
975       if (! TREE_USED (temp))
976         continue;
977
978       if (machopic_ident_defined_p (TREE_VALUE (temp)))
979         {
980           data_section ();
981           assemble_align (GET_MODE_ALIGNMENT (Pmode));
982           assemble_label (lazy_name);
983           assemble_integer (gen_rtx_SYMBOL_REF (Pmode, sym_name),
984                             GET_MODE_SIZE (Pmode),
985                             GET_MODE_ALIGNMENT (Pmode), 1);
986         }
987       else
988         {
989           machopic_nl_symbol_ptr_section ();
990           assemble_name (asm_out_file, lazy_name);
991           fprintf (asm_out_file, ":\n");
992
993           fprintf (asm_out_file, "\t.indirect_symbol ");
994           assemble_name (asm_out_file, sym_name);
995           fprintf (asm_out_file, "\n");
996
997           assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode),
998                             GET_MODE_ALIGNMENT (Pmode), 1);
999         }
1000     }
1001 }
1002
1003 int
1004 machopic_operand_p (rtx op)
1005 {
1006   if (MACHOPIC_JUST_INDIRECT)
1007     {
1008       while (GET_CODE (op) == CONST)
1009         op = XEXP (op, 0);
1010
1011       if (GET_CODE (op) == SYMBOL_REF)
1012         return machopic_name_defined_p (XSTR (op, 0));
1013       else
1014         return 0;
1015     }
1016
1017   while (GET_CODE (op) == CONST)
1018     op = XEXP (op, 0);
1019
1020   if (GET_CODE (op) == MINUS
1021       && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1022       && GET_CODE (XEXP (op, 1)) == SYMBOL_REF
1023       && machopic_name_defined_p (XSTR (XEXP (op, 0), 0))
1024       && machopic_name_defined_p (XSTR (XEXP (op, 1), 0)))
1025       return 1;
1026
1027   return 0;
1028 }
1029
1030 /* This function records whether a given name corresponds to a defined
1031    or undefined function or variable, for machopic_classify_ident to
1032    use later.  */
1033
1034 void
1035 darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1036 {
1037   char code = '\0';
1038   int defined = 0;
1039   rtx sym_ref;
1040   const char *orig_str;
1041   char *new_str;
1042   size_t len, new_len;
1043
1044   /* Do the standard encoding things first.  */
1045   default_encode_section_info (decl, rtl, first);
1046
1047   /* With the introduction of symbol_ref flags, some of the following
1048      code has become redundant and should be removed at some point.  */
1049
1050   if ((TREE_CODE (decl) == FUNCTION_DECL
1051        || TREE_CODE (decl) == VAR_DECL)
1052       && !DECL_EXTERNAL (decl)
1053       && ((TREE_STATIC (decl)
1054            && (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
1055           || (DECL_INITIAL (decl)
1056               && DECL_INITIAL (decl) != error_mark_node)))
1057     defined = 1;
1058
1059   if (TREE_CODE (decl) == FUNCTION_DECL)
1060     code = (defined ? 'T' : 't');
1061   else if (TREE_CODE (decl) == VAR_DECL)
1062     code = (defined ? 'D' : 'd');
1063
1064   if (code == '\0')
1065     return;
1066
1067   sym_ref = XEXP (rtl, 0);
1068   orig_str = XSTR (sym_ref, 0);
1069   len = strlen (orig_str) + 1;
1070
1071   if (orig_str[0] == '!')
1072     {
1073       /* Already encoded; see if we need to change it.  */
1074       if (code == orig_str[1])
1075         return;
1076       /* Yes, tweak a copy of the name and put it in a new string.  */
1077       new_str = alloca (len);
1078       memcpy (new_str, orig_str, len);
1079       new_str[1] = code;
1080       XSTR (sym_ref, 0) = ggc_alloc_string (new_str, len);
1081     }
1082   else
1083     {
1084       /* Add the encoding.  */
1085       new_len = len + 4;
1086       new_str = alloca (new_len);
1087       new_str[0] = '!';
1088       new_str[1] = code;
1089       new_str[2] = '_';
1090       new_str[3] = '_';
1091       memcpy (new_str + 4, orig_str, len);
1092       XSTR (sym_ref, 0) = ggc_alloc_string (new_str, new_len);
1093     }
1094   /* The non-lazy pointer list may have captured references to the
1095      old encoded name, change them.  */
1096   if (TREE_CODE (decl) == VAR_DECL)
1097     update_non_lazy_ptrs (XSTR (sym_ref, 0));
1098   else
1099     update_stubs (XSTR (sym_ref, 0));
1100 }
1101
1102 /* Undo the effects of the above.  */
1103
1104 const char *
1105 darwin_strip_name_encoding (const char *str)
1106 {
1107   return str[0] == '!' ? str + 4 : str;
1108 }
1109
1110 /* Scan the list of non-lazy pointers and update any recorded names whose
1111    stripped name matches the argument.  */
1112
1113 static void
1114 update_non_lazy_ptrs (const char *name)
1115 {
1116   const char *name1, *name2;
1117   tree temp;
1118
1119   name1 = darwin_strip_name_encoding (name);
1120
1121   for (temp = machopic_non_lazy_pointers;
1122        temp != NULL_TREE;
1123        temp = TREE_CHAIN (temp))
1124     {
1125       const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1126
1127       if (*sym_name == '!')
1128         {
1129           name2 = darwin_strip_name_encoding (sym_name);
1130           if (strcmp (name1, name2) == 0)
1131             {
1132               /* FIXME: This breaks the identifier hash table.  */
1133               IDENTIFIER_NODE_CHECK (TREE_VALUE (temp))->identifier.id.str
1134                 = (unsigned char *) name;
1135               break;
1136             }
1137         }
1138     }
1139 }
1140
1141 /* Function NAME is being defined, and its label has just been output.
1142    If there's already a reference to a stub for this function, we can
1143    just emit the stub label now and we don't bother emitting the stub later.  */
1144
1145 void
1146 machopic_output_possible_stub_label (FILE *file, const char *name)
1147 {
1148   tree temp;
1149
1150   /* Ensure we're looking at a section-encoded name.  */
1151   if (name[0] != '!' || (name[1] != 't' && name[1] != 'T'))
1152     return;
1153
1154   for (temp = machopic_stubs;
1155        temp != NULL_TREE;
1156        temp = TREE_CHAIN (temp))
1157     {
1158       const char *sym_name;
1159
1160       sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1161       if (sym_name[0] == '!' && (sym_name[1] == 'T' || sym_name[1] == 't')
1162           && ! strcmp (name+2, sym_name+2))
1163         {
1164           ASM_OUTPUT_LABEL (file, IDENTIFIER_POINTER (TREE_PURPOSE (temp)));
1165           /* Avoid generating a stub for this.  */
1166           TREE_USED (temp) = 0;
1167           break;
1168         }
1169     }
1170 }
1171
1172 /* Scan the list of stubs and update any recorded names whose
1173    stripped name matches the argument.  */
1174
1175 static void
1176 update_stubs (const char *name)
1177 {
1178   const char *name1, *name2;
1179   tree temp;
1180
1181   name1 = darwin_strip_name_encoding (name);
1182
1183   for (temp = machopic_stubs;
1184        temp != NULL_TREE;
1185        temp = TREE_CHAIN (temp))
1186     {
1187       const char *sym_name = IDENTIFIER_POINTER (TREE_VALUE (temp));
1188
1189       if (*sym_name == '!')
1190         {
1191           name2 = darwin_strip_name_encoding (sym_name);
1192           if (strcmp (name1, name2) == 0)
1193             {
1194               /* FIXME: This breaks the identifier hash table.  */
1195               IDENTIFIER_NODE_CHECK (TREE_VALUE (temp))->identifier.id.str
1196                 = (unsigned char *) name;
1197               break;
1198             }
1199         }
1200     }
1201 }
1202
1203 void
1204 machopic_select_section (tree exp, int reloc,
1205                          unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
1206 {
1207   void (*base_function)(void);
1208
1209   if (decl_readonly_section_1 (exp, reloc, MACHOPIC_INDIRECT))
1210     base_function = readonly_data_section;
1211   else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
1212     base_function = const_data_section;
1213   else
1214     base_function = data_section;
1215
1216   if (TREE_CODE (exp) == STRING_CST
1217       && ((size_t) TREE_STRING_LENGTH (exp)
1218           == strlen (TREE_STRING_POINTER (exp)) + 1)
1219       && ! flag_writable_strings)
1220     cstring_section ();
1221   else if ((TREE_CODE (exp) == INTEGER_CST || TREE_CODE (exp) == REAL_CST)
1222            && flag_merge_constants)
1223     {
1224       tree size = TYPE_SIZE (TREE_TYPE (exp));
1225
1226       if (TREE_CODE (size) == INTEGER_CST &&
1227           TREE_INT_CST_LOW (size) == 4 &&
1228           TREE_INT_CST_HIGH (size) == 0)
1229         literal4_section ();
1230       else if (TREE_CODE (size) == INTEGER_CST &&
1231                TREE_INT_CST_LOW (size) == 8 &&
1232                TREE_INT_CST_HIGH (size) == 0)
1233         literal8_section ();
1234       else
1235         base_function ();
1236     }
1237   else if (TREE_CODE (exp) == CONSTRUCTOR
1238            && TREE_TYPE (exp)
1239            && TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE
1240            && TYPE_NAME (TREE_TYPE (exp)))
1241     {
1242       tree name = TYPE_NAME (TREE_TYPE (exp));
1243       if (TREE_CODE (name) == TYPE_DECL)
1244         name = DECL_NAME (name);
1245       if (!strcmp (IDENTIFIER_POINTER (name), "NSConstantString"))
1246         objc_constant_string_object_section ();
1247       else if (!strcmp (IDENTIFIER_POINTER (name), "NXConstantString"))
1248         objc_string_object_section ();
1249       else
1250         base_function ();
1251     }
1252   else if (TREE_CODE (exp) == VAR_DECL &&
1253            DECL_NAME (exp) &&
1254            TREE_CODE (DECL_NAME (exp)) == IDENTIFIER_NODE &&
1255            IDENTIFIER_POINTER (DECL_NAME (exp)) &&
1256            !strncmp (IDENTIFIER_POINTER (DECL_NAME (exp)), "_OBJC_", 6))
1257     {
1258       const char *name = IDENTIFIER_POINTER (DECL_NAME (exp));
1259
1260       if (!strncmp (name, "_OBJC_CLASS_METHODS_", 20))
1261         objc_cls_meth_section ();
1262       else if (!strncmp (name, "_OBJC_INSTANCE_METHODS_", 23))
1263         objc_inst_meth_section ();
1264       else if (!strncmp (name, "_OBJC_CATEGORY_CLASS_METHODS_", 20))
1265         objc_cat_cls_meth_section ();
1266       else if (!strncmp (name, "_OBJC_CATEGORY_INSTANCE_METHODS_", 23))
1267         objc_cat_inst_meth_section ();
1268       else if (!strncmp (name, "_OBJC_CLASS_VARIABLES_", 22))
1269         objc_class_vars_section ();
1270       else if (!strncmp (name, "_OBJC_INSTANCE_VARIABLES_", 25))
1271         objc_instance_vars_section ();
1272       else if (!strncmp (name, "_OBJC_CLASS_PROTOCOLS_", 22))
1273         objc_cat_cls_meth_section ();
1274       else if (!strncmp (name, "_OBJC_CLASS_NAME_", 17))
1275         objc_class_names_section ();
1276       else if (!strncmp (name, "_OBJC_METH_VAR_NAME_", 20))
1277         objc_meth_var_names_section ();
1278       else if (!strncmp (name, "_OBJC_METH_VAR_TYPE_", 20))
1279         objc_meth_var_types_section ();
1280       else if (!strncmp (name, "_OBJC_CLASS_REFERENCES", 22))
1281         objc_cls_refs_section ();
1282       else if (!strncmp (name, "_OBJC_CLASS_", 12))
1283         objc_class_section ();
1284       else if (!strncmp (name, "_OBJC_METACLASS_", 16))
1285         objc_meta_class_section ();
1286       else if (!strncmp (name, "_OBJC_CATEGORY_", 15))
1287         objc_category_section ();
1288       else if (!strncmp (name, "_OBJC_SELECTOR_REFERENCES", 25))
1289         objc_selector_refs_section ();
1290       else if (!strncmp (name, "_OBJC_SELECTOR_FIXUP", 20))
1291         objc_selector_fixup_section ();
1292       else if (!strncmp (name, "_OBJC_SYMBOLS", 13))
1293         objc_symbols_section ();
1294       else if (!strncmp (name, "_OBJC_MODULES", 13))
1295         objc_module_info_section ();
1296       else if (!strncmp (name, "_OBJC_IMAGE_INFO", 16))
1297         objc_image_info_section ();
1298       else if (!strncmp (name, "_OBJC_PROTOCOL_INSTANCE_METHODS_", 32))
1299         objc_cat_inst_meth_section ();
1300       else if (!strncmp (name, "_OBJC_PROTOCOL_CLASS_METHODS_", 29))
1301         objc_cat_cls_meth_section ();
1302       else if (!strncmp (name, "_OBJC_PROTOCOL_REFS_", 20))
1303         objc_cat_cls_meth_section ();
1304       else if (!strncmp (name, "_OBJC_PROTOCOL_", 15))
1305         objc_protocol_section ();
1306       else
1307         base_function ();
1308     }
1309   else
1310     base_function ();
1311 }
1312
1313 /* This can be called with address expressions as "rtx".
1314    They must go in "const".  */
1315
1316 void
1317 machopic_select_rtx_section (enum machine_mode mode, rtx x,
1318                              unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
1319 {
1320   if (GET_MODE_SIZE (mode) == 8)
1321     literal8_section ();
1322   else if (GET_MODE_SIZE (mode) == 4
1323            && (GET_CODE (x) == CONST_INT
1324                || GET_CODE (x) == CONST_DOUBLE))
1325     literal4_section ();
1326   else if (MACHOPIC_INDIRECT
1327            && (GET_CODE (x) == SYMBOL_REF
1328                || GET_CODE (x) == CONST
1329                || GET_CODE (x) == LABEL_REF))
1330     const_data_section ();
1331   else
1332     const_section ();
1333 }
1334
1335 void
1336 machopic_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
1337 {
1338   if (MACHOPIC_INDIRECT)
1339     mod_init_section ();
1340   else
1341     constructor_section ();
1342   assemble_align (POINTER_SIZE);
1343   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1344
1345   if (! MACHOPIC_INDIRECT)
1346     fprintf (asm_out_file, ".reference .constructors_used\n");
1347 }
1348
1349 void
1350 machopic_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
1351 {
1352   if (MACHOPIC_INDIRECT)
1353     mod_term_section ();
1354   else
1355     destructor_section ();
1356   assemble_align (POINTER_SIZE);
1357   assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
1358
1359   if (! MACHOPIC_INDIRECT)
1360     fprintf (asm_out_file, ".reference .destructors_used\n");
1361 }
1362
1363 void
1364 darwin_globalize_label (FILE *stream, const char *name)
1365 {
1366   if (!!strncmp (name, "_OBJC_", 6))
1367     default_globalize_label (stream, name);
1368 }
1369
1370 /* Emit an assembler directive to set visibility for a symbol.  The
1371    only supported visibilities are VISIBILITY_DEFAULT and
1372    VISIBILITY_HIDDEN; the latter corresponds to Darwin's "private
1373    extern".  There is no MACH-O equivalent of ELF's
1374    VISIBILITY_INTERNAL or VISIBILITY_PROTECTED. */
1375
1376 void 
1377 darwin_assemble_visibility (tree decl, int vis)
1378 {
1379   if (vis == VISIBILITY_DEFAULT)
1380     ;
1381   else if (vis == VISIBILITY_HIDDEN)
1382     {
1383       fputs ("\t.private_extern ", asm_out_file);
1384       assemble_name (asm_out_file,
1385                      (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
1386       fputs ("\n", asm_out_file);
1387     }
1388   else
1389     warning ("internal and protected visibility attributes not supported"
1390              "in this configuration; ignored");
1391 }
1392
1393 /* Output a difference of two labels that will be an assembly time
1394    constant if the two labels are local.  (.long lab1-lab2 will be
1395    very different if lab1 is at the boundary between two sections; it
1396    will be relocated according to the second section, not the first,
1397    so one ends up with a difference between labels in different
1398    sections, which is bad in the dwarf2 eh context for instance.)  */
1399
1400 static int darwin_dwarf_label_counter;
1401
1402 void
1403 darwin_asm_output_dwarf_delta (FILE *file, int size ATTRIBUTE_UNUSED,
1404                                const char *lab1, const char *lab2)
1405 {
1406   const char *p = lab1 + (lab1[0] == '*');
1407   int islocaldiff = (p[0] == 'L');
1408
1409   if (islocaldiff)
1410     fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
1411   else
1412     fprintf (file, "\t%s\t", ".long");
1413   assemble_name (file, lab1);
1414   fprintf (file, "-");
1415   assemble_name (file, lab2);
1416   if (islocaldiff)
1417     fprintf (file, "\n\t.long L$set$%d", darwin_dwarf_label_counter++);
1418 }
1419
1420 void
1421 darwin_file_end (void)
1422 {
1423   machopic_finish (asm_out_file);
1424   if (strcmp (lang_hooks.name, "GNU C++") == 0)
1425     {
1426       constructor_section ();
1427       destructor_section ();
1428       ASM_OUTPUT_ALIGN (asm_out_file, 1);
1429     }
1430 }
1431
1432 #include "gt-darwin.h"