]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/darwin.c
Wrap option names in gcc internal messages with %< and %>.
[thirdparty/gcc.git] / gcc / config / darwin.c
index 34dc9aa1dd93ae833233c8377ce3f29171cbcf09..f62f1c79bdd98c303f72a061f0d22067b9977112 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for generic Darwin as target machine for GNU C compiler.
-   Copyright (C) 1989-2014 Free Software Foundation, Inc.
+   Copyright (C) 1989-2019 Free Software Foundation, Inc.
    Contributed by Apple Computer Inc.
 
 This file is part of GCC.
@@ -18,49 +18,35 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define IN_TARGET_CODE 1
+
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "insn-config.h"
-#include "conditions.h"
-#include "insn-flags.h"
-#include "output.h"
-#include "insn-attr.h"
-#include "flags.h"
 #include "tree.h"
+#include "gimple.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
+#include "insn-config.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
+#include "output.h"
 #include "varasm.h"
 #include "stor-layout.h"
+#include "explow.h"
 #include "expr.h"
-#include "reload.h"
-#include "function.h"
-#include "ggc.h"
 #include "langhooks.h"
-#include "target.h"
-#include "tm_p.h"
-#include "diagnostic-core.h"
 #include "toplev.h"
-#include "hashtab.h"
-#include "df.h"
-#include "debug.h"
-#include "obstack.h"
-#include "hash-table.h"
-#include "vec.h"
-#include "basic-block.h"
-#include "tree-ssa-alias.h"
-#include "internal-fn.h"
-#include "gimple-fold.h"
-#include "tree-eh.h"
-#include "gimple-expr.h"
-#include "is-a.h"
-#include "gimple.h"
-#include "gimplify.h"
-#include "lto-streamer.h"
 #include "lto-section-names.h"
+#include "intl.h"
 
 /* Darwin supports a feature called fix-and-continue, which is used
    for rapid turn around debugging.  When code is compiled with the
@@ -115,12 +101,15 @@ int darwin_running_cxx;
 /* Some code-gen now depends on OS major version numbers (at least).  */
 int generating_for_darwin_version ;
 
+/* For older linkers we need to emit special sections (marked 'coalesced') for
+   for weak or single-definition items.  */
+static bool ld_uses_coal_sects = false;
+
 /* Section names.  */
 section * darwin_sections[NUM_DARWIN_SECTIONS];
 
 /* While we transition to using in-tests instead of ifdef'd code.  */
-#ifndef HAVE_lo_sum
-#define HAVE_lo_sum 0
+#if !HAVE_lo_sum
 #define gen_macho_high(a,b) (a)
 #define gen_macho_low(a,b,c) (a)
 #endif
@@ -239,6 +228,11 @@ darwin_init_sections (void)
   readonly_data_section = darwin_sections[const_section];
   exception_section = darwin_sections[darwin_exception_section];
   eh_frame_section = darwin_sections[darwin_eh_frame_section];
+
+  /* If our linker is new enough to coalesce weak symbols, then we
+     can just put picbase_thunks into the text section.  */
+  if (! ld_uses_coal_sects )
+    darwin_sections[picbase_thunk_section] = text_section;
 }
 
 int
@@ -459,11 +453,11 @@ typedef struct GTY ((for_user)) machopic_indirection
   /* True iff this entry is for a stub (as opposed to a non-lazy
      pointer).  */
   bool stub_p;
-  /* True iff this stub or pointer pointer has been referenced.  */
+  /* True iff this stub or pointer has been referenced.  */
   bool used;
 } machopic_indirection;
 
-struct indirection_hasher : ggc_hasher<machopic_indirection *>
+struct indirection_hasher : ggc_ptr_hash<machopic_indirection>
 {
   typedef const char *compare_type;
   static hashval_t hash (machopic_indirection *);
@@ -493,7 +487,31 @@ indirection_hasher::equal (machopic_indirection *s, const char *k)
 }
 
 /* Return the name of the non-lazy pointer (if STUB_P is false) or
-   stub (if STUB_B is true) corresponding to the given name.  */
+   stub (if STUB_B is true) corresponding to the given name.
+
+  If we have a situation like:
+
+global_weak_symbol:
+  ....
+Lnon_weak_local:
+  ....
+
+  ld64 will be unable to split this into two atoms (because the "L" makes
+  the second symbol 'invisible').  This means that legitimate direct accesses
+  to the second symbol will appear to be non-allowed direct accesses to an
+  atom of type weak, global which are not allowed.
+
+  To avoid this, we make the indirections have a leading 'l' (lower-case L)
+  which has a special meaning: linker can see this and use it to determine
+  atoms, but it is not placed into the final symbol table.
+
+  The implementation here is somewhat heavy-handed in that it will also mark
+  indirections to the __IMPORT,__pointers section the same way which is
+  really unnecessary, since ld64 _can_ split those into atoms as they are
+  fixed size.  FIXME: determine if this is a penalty worth extra code to
+  fix.
+
+*/
 
 const char *
 machopic_indirection_name (rtx sym_ref, bool stub_p)
@@ -504,6 +522,7 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   machopic_indirection *p;
   bool needs_quotes;
   const char *suffix;
+  char L_or_l = 'L';
   const char *prefix = user_label_prefix;
   const char *quote = "";
   tree id;
@@ -538,9 +557,13 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   if (stub_p)
     suffix = STUB_SUFFIX;
   else
-    suffix = NON_LAZY_POINTER_SUFFIX;
+    {
+      suffix = NON_LAZY_POINTER_SUFFIX;
+      /* Let the linker see this.  */
+      L_or_l = 'l';
+    }
 
-  buffer = XALLOCAVEC (char, strlen ("&L")
+  buffer = XALLOCAVEC (char, 2  /* strlen ("&L") or ("&l") */
                   + strlen (prefix)
                   + namelen
                   + strlen (suffix)
@@ -548,7 +571,7 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
                   + 1 /* '\0' */);
 
   /* Construct the name of the non-lazy pointer or stub.  */
-  sprintf (buffer, "&%sL%s%s%s%s", quote, prefix, name, suffix, quote);
+  sprintf (buffer, "&%s%c%s%s%s%s", quote, L_or_l, prefix, name, suffix, quote);
 
   if (!machopic_indirections)
     machopic_indirections = hash_table<indirection_hasher>::create_ggc (37);
@@ -657,10 +680,10 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
 
          gcc_assert (reg);
 
-         emit_insn (gen_rtx_SET (Pmode, hi_sum_reg,
+         emit_insn (gen_rtx_SET (hi_sum_reg,
                              gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
                                       gen_rtx_HIGH (Pmode, offset))));
-         emit_insn (gen_rtx_SET (Pmode, reg,
+         emit_insn (gen_rtx_SET (reg,
                                  gen_rtx_LO_SUM (Pmode, hi_sum_reg,
                                                  copy_rtx (offset))));
 
@@ -670,11 +693,9 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
            {
          gcc_assert (reg);
 
-         emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                 gen_rtx_HIGH (Pmode, offset)));
-         emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                 gen_rtx_LO_SUM (Pmode, reg,
-                                                 copy_rtx (offset))));
+         emit_insn (gen_rtx_SET (reg, gen_rtx_HIGH (Pmode, offset)));
+         emit_insn (gen_rtx_SET (reg, gen_rtx_LO_SUM (Pmode, reg,
+                                                      copy_rtx (offset))));
          emit_use (pic_offset_table_rtx);
 
          orig = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, reg);
@@ -695,7 +716,7 @@ machopic_indirect_data_reference (rtx orig, rtx reg)
           && reg 
           && MACHO_DYNAMIC_NO_PIC_P)
        {
-           emit_insn (gen_rtx_SET (Pmode, reg, ptr_ref));
+           emit_insn (gen_rtx_SET (reg, ptr_ref));
            ptr_ref = reg;
        }
 
@@ -783,7 +804,7 @@ machopic_indirect_call_target (rtx target)
       rtx sym_ref = XEXP (target, 0);
       const char *stub_name = machopic_indirection_name (sym_ref,
                                                         /*stub_p=*/true);
-      enum machine_mode mode = GET_MODE (sym_ref);
+      machine_mode mode = GET_MODE (sym_ref);
 
       XEXP (target, 0) = gen_rtx_SYMBOL_REF (mode, stub_name);
       SYMBOL_REF_DATA (XEXP (target, 0)) = SYMBOL_REF_DATA (sym_ref);
@@ -795,7 +816,7 @@ machopic_indirect_call_target (rtx target)
 }
 
 rtx
-machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
+machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg)
 {
   rtx pic_ref = orig;
 
@@ -804,8 +825,7 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
   /* First handle a simple SYMBOL_REF or LABEL_REF */
   if (GET_CODE (orig) == LABEL_REF
-      || (GET_CODE (orig) == SYMBOL_REF
-         ))
+      || GET_CODE (orig) == SYMBOL_REF)
     {
       /* addr(foo) = &func+(foo-func) */
       orig = machopic_indirect_data_reference (orig, reg);
@@ -844,7 +864,7 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
              mem = gen_const_mem (GET_MODE (orig),
                                   gen_rtx_LO_SUM (Pmode, temp_reg,
                                                   copy_rtx (asym)));
-             emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
+             emit_insn (gen_rtx_SET (reg, mem));
 #else
              /* Some other CPU -- WriteMe! but right now there are no other
                 platforms that can use dynamic-no-pic  */
@@ -864,31 +884,30 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
                                ? reg
                                : gen_reg_rtx (Pmode));
              rtx mem;
-             rtx insn;
              rtx sum;
 
              sum = gen_rtx_HIGH (Pmode, offset);
              if (! MACHO_DYNAMIC_NO_PIC_P)
                sum = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, sum);
 
-             emit_insn (gen_rtx_SET (Pmode, hi_sum_reg, sum));
+             emit_insn (gen_rtx_SET (hi_sum_reg, sum));
 
              mem = gen_const_mem (GET_MODE (orig),
                                  gen_rtx_LO_SUM (Pmode,
                                                  hi_sum_reg,
                                                  copy_rtx (offset)));
-             insn = emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
+             rtx_insn *insn = emit_insn (gen_rtx_SET (reg, mem));
              set_unique_reg_note (insn, REG_EQUAL, pic_ref);
 
              pic_ref = reg;
 #else
              emit_use (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM));
 
-             emit_insn (gen_rtx_SET (VOIDmode, reg,
+             emit_insn (gen_rtx_SET (reg,
                                      gen_rtx_HIGH (Pmode,
                                                    gen_rtx_CONST (Pmode,
                                                                   offset))));
-             emit_insn (gen_rtx_SET (VOIDmode, reg,
+             emit_insn (gen_rtx_SET (reg,
                                  gen_rtx_LO_SUM (Pmode, reg,
                                           gen_rtx_CONST (Pmode,
                                                          copy_rtx (offset)))));
@@ -939,22 +958,21 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
              hi_sum_reg = reg;
 
-             emit_insn (gen_rtx_SET (Pmode, hi_sum_reg,
+             emit_insn (gen_rtx_SET (hi_sum_reg,
                                      (MACHO_DYNAMIC_NO_PIC_P)
                                      ? gen_rtx_HIGH (Pmode, offset)
                                      : gen_rtx_PLUS (Pmode,
                                                      pic_offset_table_rtx,
                                                      gen_rtx_HIGH (Pmode,
                                                                    offset))));
-             emit_insn (gen_rtx_SET (VOIDmode, reg,
+             emit_insn (gen_rtx_SET (reg,
                                      gen_rtx_LO_SUM (Pmode,
                                                      hi_sum_reg,
                                                      copy_rtx (offset))));
              pic_ref = reg;
 #else
-             emit_insn (gen_rtx_SET (VOIDmode, reg,
-                                     gen_rtx_HIGH (Pmode, offset)));
-             emit_insn (gen_rtx_SET (VOIDmode, reg,
+             emit_insn (gen_rtx_SET (reg, gen_rtx_HIGH (Pmode, offset)));
+             emit_insn (gen_rtx_SET (reg,
                                      gen_rtx_LO_SUM (Pmode, reg,
                                                      copy_rtx (offset))));
              pic_ref = gen_rtx_PLUS (Pmode,
@@ -1006,10 +1024,6 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
           return pic_ref;
         }
     }
-
-  else if (GET_CODE (orig) == SYMBOL_REF)
-    return orig;
-
   else if (GET_CODE (orig) == PLUS
           && (GET_CODE (XEXP (orig, 0)) == MEM
               || GET_CODE (XEXP (orig, 0)) == SYMBOL_REF
@@ -1039,12 +1053,10 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
        }
       /* Likewise, should we set special REG_NOTEs here?  */
     }
-
   else if (GET_CODE (orig) == CONST)
     {
       return machopic_legitimize_pic_address (XEXP (orig, 0), Pmode, reg);
     }
-
   else if (GET_CODE (orig) == MEM
           && GET_CODE (XEXP (orig, 0)) == SYMBOL_REF)
     {
@@ -1229,15 +1241,20 @@ darwin_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
 void
 darwin_mark_decl_preserved (const char *name)
 {
+  /* Actually we shouldn't mark any local symbol this way, but for now
+     this only happens with ObjC meta-data.  */
+  if (darwin_label_is_anonymous_local_objc_name (name))
+    return;
+
   fprintf (asm_out_file, "\t.no_dead_strip ");
   assemble_name (asm_out_file, name);
   fputc ('\n', asm_out_file);
 }
 
 static section *
-darwin_rodata_section (int weak, bool zsize)
+darwin_rodata_section (int use_coal, bool zsize)
 {
-  return (weak
+  return (use_coal
          ? darwin_sections[const_coal_section]
          : (zsize ? darwin_sections[zobj_const_section]
                   : darwin_sections[const_section]));
@@ -1278,7 +1295,7 @@ darwin_mergeable_constant_section (tree exp,
                                   unsigned HOST_WIDE_INT align,
                                   bool zsize)
 {
-  enum machine_mode mode = DECL_MODE (exp);
+  machine_mode mode = DECL_MODE (exp);
   unsigned int modesize = GET_MODE_BITSIZE (mode);
 
   if (DARWIN_SECTION_ANCHORS 
@@ -1298,13 +1315,13 @@ darwin_mergeable_constant_section (tree exp,
 
       if (TREE_CODE (size) == INTEGER_CST)
        {
-         if (wi::eq_p (size, 4))
+         if (wi::to_wide (size) == 4)
            return darwin_sections[literal4_section];
-         else if (wi::eq_p (size, 8))
+         else if (wi::to_wide (size) == 8)
            return darwin_sections[literal8_section];
          else if (HAVE_GAS_LITERAL16
                   && TARGET_64BIT
-                  && wi::eq_p (size, 16))
+                  && wi::to_wide (size) == 16)
            return darwin_sections[literal16_section];
        }
     }
@@ -1406,7 +1423,8 @@ darwin_objc2_section (tree decl ATTRIBUTE_UNUSED, tree meta, section * base)
     return darwin_sections[objc2_image_info_section];
 
   else if (!strncmp (p, "V2_EHTY", 7))
-    return darwin_sections[data_coal_section];
+    return ld_uses_coal_sects ? darwin_sections[data_coal_section]
+                              : data_section;
 
   else if (!strncmp (p, "V2_CSTR", 7))
     return darwin_sections[objc2_constant_string_object_section];
@@ -1505,21 +1523,23 @@ machopic_select_section (tree decl,
                         int reloc,
                         unsigned HOST_WIDE_INT align)
 {
-  bool zsize, one, weak, ro;
+  bool zsize, one, weak, use_coal, ro;
   section *base_section = NULL;
 
   weak = (DECL_P (decl)
          && DECL_WEAK (decl)
          && !lookup_attribute ("weak_import", DECL_ATTRIBUTES (decl)));
 
-  zsize = (DECL_P (decl) 
+  zsize = (DECL_P (decl)
           && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == CONST_DECL) 
           && tree_to_uhwi (DECL_SIZE_UNIT (decl)) == 0);
 
-  one = DECL_P (decl) 
+  one = DECL_P (decl)
        && TREE_CODE (decl) == VAR_DECL 
        && DECL_COMDAT_GROUP (decl);
 
+  use_coal = (weak || one) && ld_uses_coal_sects;
+
   ro = TREE_READONLY (decl) || TREE_CONSTANT (decl) ;
 
   switch (categorize_decl_for_section (decl, reloc))
@@ -1530,7 +1550,7 @@ machopic_select_section (tree decl,
 
     case SECCAT_RODATA:
     case SECCAT_SRODATA:
-      base_section = darwin_rodata_section (weak, zsize);
+      base_section = darwin_rodata_section (use_coal, zsize);
       break;
 
     case SECCAT_RODATA_MERGE_STR:
@@ -1552,7 +1572,7 @@ machopic_select_section (tree decl,
     case SECCAT_DATA_REL_RO_LOCAL:
     case SECCAT_SDATA:
     case SECCAT_TDATA:
-      if (weak || one)
+      if (use_coal)
        {
          if (ro)
            base_section = darwin_sections[const_data_coal_section];
@@ -1581,7 +1601,7 @@ machopic_select_section (tree decl,
     case SECCAT_BSS:
     case SECCAT_SBSS:
     case SECCAT_TBSS:
-      if (weak || one) 
+      if (use_coal)
        base_section = darwin_sections[data_coal_section];
       else
        {
@@ -1728,7 +1748,7 @@ machopic_select_section (tree decl,
    They must go in "const".  */
 
 section *
-machopic_select_rtx_section (enum machine_mode mode, rtx x,
+machopic_select_rtx_section (machine_mode mode, rtx x,
                             unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   if (GET_MODE_SIZE (mode) == 8
@@ -1907,6 +1927,7 @@ static GTY (()) vec<darwin_lto_section_e, va_gc> *lto_section_names;
    in darwin_end_file.  */
 static FILE *lto_asm_out_file, *saved_asm_out_file;
 static char *lto_asm_out_name;
+static enum debug_info_levels saved_debug_info_level;
 
 /* Prepare asm_out_file for LTO output.  For darwin, this means hiding
    asm_out_file and switching to an alternative output file.  */
@@ -1915,11 +1936,14 @@ darwin_asm_lto_start (void)
 {
   gcc_assert (! saved_asm_out_file);
   saved_asm_out_file = asm_out_file;
+  saved_debug_info_level = debug_info_level;
+  debug_info_level = DINFO_LEVEL_NONE;
   if (! lto_asm_out_name)
     lto_asm_out_name = make_temp_file (".lto.s");
   lto_asm_out_file = fopen (lto_asm_out_name, "a");
   if (lto_asm_out_file == NULL)
-    fatal_error ("failed to open temporary file %s for LTO output",
+    fatal_error (input_location,
+                "failed to open temporary file %s for LTO output",
                 lto_asm_out_name);
   asm_out_file = lto_asm_out_file;
 }
@@ -1932,10 +1956,12 @@ darwin_asm_lto_end (void)
   fclose (lto_asm_out_file);
   asm_out_file = saved_asm_out_file;
   saved_asm_out_file = NULL;
+  debug_info_level = saved_debug_info_level;
 }
 
 static void
-darwin_asm_dwarf_section (const char *name, unsigned int flags, tree decl);
+darwin_asm_dwarf_section (const char *name, unsigned int flags,
+                         tree decl, bool is_for_lto);
 
 /*  Called for the TARGET_ASM_NAMED_SECTION hook.  */
 
@@ -1977,7 +2003,9 @@ darwin_asm_named_section (const char *name,
       vec_safe_push (lto_section_names, e);
    }
   else if (strncmp (name, "__DWARF,", 8) == 0)
-    darwin_asm_dwarf_section (name, flags, decl);
+    darwin_asm_dwarf_section (name, flags, decl, false);
+  else if (strncmp (name, "__GNU_DWARF_LTO,", 16) == 0)
+    darwin_asm_dwarf_section (name, flags, decl, true);
   else
     fprintf (asm_out_file, "\t.section %s\n", name);
 }
@@ -2223,7 +2251,7 @@ fprintf (file, "# dadon: %s %s (%llu, %u) local %d weak %d"
 
       ASM_OUTPUT_LABEL (file, xname);
       size = 1;
-      fprintf (file, "\t.space\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+      fprintf (file, "\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
 
       /* Check that we've correctly picked up the zero-sized item and placed it
          properly.  */
@@ -2276,14 +2304,18 @@ darwin_asm_declare_constant_name (FILE *file, const char *name,
 static void
 darwin_emit_weak_or_comdat (FILE *fp, tree decl, const char *name,
                                  unsigned HOST_WIDE_INT size, 
+                                 bool use_coal,
                                  unsigned int align)
 {
-  /* Since the sections used here are coalesed, they will not be eligible
-     for section anchors, and therefore we don't need to break that out.  */
+  /* Since the sections used here are coalesced, they will not be eligible
+     for section anchors, and therefore we don't need to break that out.
+     CHECKME: for modern linker on PowerPC.  */
  if (TREE_READONLY (decl) || TREE_CONSTANT (decl))
-    switch_to_section (darwin_sections[const_data_coal_section]);
+    switch_to_section (use_coal ? darwin_sections[const_data_coal_section]
+                               : darwin_sections[const_data_section]);
   else
-    switch_to_section (darwin_sections[data_coal_section]);
+    switch_to_section (use_coal ? darwin_sections[data_coal_section]
+                               : data_section);
 
   /* To be consistent, we'll allow darwin_asm_declare_object_name to assemble
      the align info for zero-sized items... but do it here otherwise.  */
@@ -2364,7 +2396,7 @@ darwin_emit_local_bss (FILE *fp, tree decl, const char *name,
        fprintf (fp, "\t.align\t%u\n", l2align);
 
       assemble_name (fp, name);        
-      fprintf (fp, ":\n\t.space\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+      fprintf (fp, ":\n\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
     }
   else 
     {
@@ -2385,10 +2417,10 @@ darwin_emit_local_bss (FILE *fp, tree decl, const char *name,
        size = 1;
 
       if (l2align)
-       fprintf (fp, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",
+       fprintf (fp, "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n",
                 size, (unsigned) l2align);
       else
-       fprintf (fp, ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+       fprintf (fp, "," HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
     }
 
   (*targetm.encode_section_info) (decl, DECL_RTL (decl), false);
@@ -2502,7 +2534,7 @@ fprintf (fp, "# albss: %s (%lld,%d) ro %d cst %d stat %d com %d"
     {
       /* Weak or COMDAT objects are put in mergeable sections.  */
       darwin_emit_weak_or_comdat (fp, decl, name, size, 
-                                       DECL_ALIGN (decl));
+                                 ld_uses_coal_sects, DECL_ALIGN (decl));
       return;
     } 
 
@@ -2536,7 +2568,7 @@ fprintf (fp, "# albss: %s (%lld,%d) ro %d cst %d stat %d com %d"
        fprintf (fp, "\t.align\t%u\n", l2align);
 
       assemble_name (fp, name);
-      fprintf (fp, ":\n\t.space\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+      fprintf (fp, ":\n\t.space\t" HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
     }
   else 
     {
@@ -2557,9 +2589,9 @@ fprintf (fp, "# albss: %s (%lld,%d) ro %d cst %d stat %d com %d"
        size = 1;
 
       if (l2align)
-       fprintf (fp, ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", size, l2align);
+       fprintf (fp, "," HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", size, l2align);
       else
-       fprintf (fp, ","HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+       fprintf (fp, "," HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
     }
   (* targetm.encode_section_info) (decl, DECL_RTL (decl), false);
 }
@@ -2616,7 +2648,7 @@ fprintf (fp, "# adcom: %s (%lld,%d) ro %d cst %d stat %d com %d pub %d"
     {
       /* Weak or COMDAT objects are put in mergable sections.  */
       darwin_emit_weak_or_comdat (fp, decl, name, size, 
-                                       DECL_ALIGN (decl));
+                                 ld_uses_coal_sects, DECL_ALIGN (decl));
       return;
     } 
 
@@ -2686,7 +2718,7 @@ fprintf (fp, "# adloc: %s (%lld,%d) ro %d cst %d stat %d one %d pub %d"
     {
       /* Weak or COMDAT objects are put in mergable sections.  */
       darwin_emit_weak_or_comdat (fp, decl, name, size, 
-                                       DECL_ALIGN (decl));
+                                 ld_uses_coal_sects, DECL_ALIGN (decl));
       return;
     } 
 
@@ -2755,19 +2787,37 @@ static GTY (()) vec<dwarf_sect_used_entry, va_gc> *dwarf_sect_names_table;
 
 static void
 darwin_asm_dwarf_section (const char *name, unsigned int flags,
-                         tree ARG_UNUSED (decl))
+                         tree ARG_UNUSED (decl), bool is_for_lto)
 {
   unsigned i;
-  int namelen;
-  const char * sname;
+  int namelen, extra = 0;
+  const char *sect, *lto_add = "";
+  char sname[64];
   dwarf_sect_used_entry *ref;
   bool found = false;
-  gcc_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
-                   == (SECTION_DEBUG | SECTION_NAMED));
-  /* We know that the name starts with __DWARF,  */
-  sname = name + 8;
-  namelen = strchr (sname, ',') - sname;
-  gcc_assert (namelen);
+
+  gcc_checking_assert ((flags & (SECTION_DEBUG | SECTION_NAMED))
+                       == (SECTION_DEBUG | SECTION_NAMED));
+
+  /* We know that the name starts with __DWARF, or __GNU_DAWRF_LTO  */
+  sect = strchr (name, ',') + 1;
+  namelen = strchr (sect, ',') - sect;
+  gcc_checking_assert (namelen);
+
+  /* The section switch is output as written...  */
+  fprintf (asm_out_file, "\t.section %s\n", name);
+
+  /* ... but the string we keep to make section start labels needs
+     adjustment for lto cases.  */
+  if (is_for_lto)
+    {
+      lto_add = "_lto";
+      extra = 4;
+    }
+
+  snprintf (sname, 64, "%.*s%.*s", namelen, sect, extra, lto_add);
+  namelen += extra;
+
   if (dwarf_sect_names_table == NULL)
     vec_alloc (dwarf_sect_names_table, 16);
   else
@@ -2785,7 +2835,6 @@ darwin_asm_dwarf_section (const char *name, unsigned int flags,
          }
       }
 
-  fprintf (asm_out_file, "\t.section %s\n", name);
   if (!found)
     {
       dwarf_sect_used_entry e;
@@ -2807,7 +2856,8 @@ static int darwin_dwarf_label_counter;
 
 void
 darwin_asm_output_dwarf_delta (FILE *file, int size,
-                              const char *lab1, const char *lab2)
+                              const char *lab1, const char *lab2,
+                              HOST_WIDE_INT offset)
 {
   int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
                     && lab2[0] == '*' && lab2[1] == 'L');
@@ -2821,6 +2871,8 @@ darwin_asm_output_dwarf_delta (FILE *file, int size,
   assemble_name_raw (file, lab1);
   fprintf (file, "-");
   assemble_name_raw (file, lab2);
+  if (offset != 0)
+    fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
   if (islocaldiff)
     fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
 }
@@ -2832,18 +2884,28 @@ darwin_asm_output_dwarf_delta (FILE *file, int size,
 
 void
 darwin_asm_output_dwarf_offset (FILE *file, int size, const char * lab,
-                               section *base)
+                               HOST_WIDE_INT offset, section *base)
 {
   char sname[64];
-  int namelen;
+  int namelen, extra = 0;
+  bool is_for_lto;
+  const char *lto_add = "";
 
-  gcc_assert (base->common.flags & SECTION_NAMED);
-  gcc_assert (strncmp (base->named.name, "__DWARF,", 8) == 0);
-  gcc_assert (strchr (base->named.name + 8, ','));
+  gcc_checking_assert (base->common.flags & SECTION_NAMED);
+  is_for_lto = strncmp (base->named.name, "__GNU_DWARF_LTO,", 16) == 0;
+  gcc_checking_assert (is_for_lto
+                      || strncmp (base->named.name, "__DWARF,", 8) == 0);
+  const char *name = strchr (base->named.name, ',') + 1;
+  gcc_checking_assert (name);
 
-  namelen = strchr (base->named.name + 8, ',') - (base->named.name + 8);
-  sprintf (sname, "*Lsection%.*s", namelen, base->named.name + 8);
-  darwin_asm_output_dwarf_delta (file, size, lab, sname);
+  namelen = strchr (name, ',') - (name);
+  if (is_for_lto)
+    {
+      lto_add = "_lto";
+      extra = 4;
+    }
+  snprintf (sname, 64, "*Lsection%.*s%.*s", namelen, name, extra, lto_add);
+  darwin_asm_output_dwarf_delta (file, size, lab, sname, offset);
 }
 
 /* Called from the within the TARGET_ASM_FILE_START for each target.  */
@@ -2894,7 +2956,7 @@ darwin_file_end (void)
      }
 
   machopic_finish (asm_out_file);
-  if (strcmp (lang_hooks.name, "GNU C++") == 0)
+  if (lang_GNU_CXX ())
     {
       switch_to_section (darwin_sections[constructor_section]);
       switch_to_section (darwin_sections[destructor_section]);
@@ -2912,7 +2974,8 @@ darwin_file_end (void)
 
       lto_asm_out_file = fopen (lto_asm_out_name, "r");
       if (lto_asm_out_file == NULL)
-       fatal_error ("failed to open temporary file %s with LTO output",
+       fatal_error (input_location,
+                    "failed to open temporary file %s with LTO output",
                     lto_asm_out_name);
       fseek (lto_asm_out_file, 0, SEEK_END);
       n = ftell (lto_asm_out_file);
@@ -3013,23 +3076,23 @@ darwin_asm_output_anchor (rtx symbol)
           SYMBOL_REF_BLOCK_OFFSET (symbol));
 }
 
-/* Disable section anchoring on any section containing a zero-sized 
+/* Disable section anchoring on any section containing a zero-sized
    object.  */
 bool
 darwin_use_anchors_for_symbol_p (const_rtx symbol)
 {
-  if (DARWIN_SECTION_ANCHORS && flag_section_anchors) 
+  if (DARWIN_SECTION_ANCHORS && flag_section_anchors)
     {
       section *sect;
       /* If the section contains a zero-sized object it's ineligible.  */
       sect = SYMBOL_REF_BLOCK (symbol)->sect;
       /* This should have the effect of disabling anchors for vars that follow
-         any zero-sized one, in a given section.  */     
+         any zero-sized one, in a given section.  */
       if (sect->common.flags & SECTION_NO_ANCHOR)
        return false;
 
-        /* Also check the normal reasons for suppressing.  */
-        return default_use_anchors_for_symbol_p (symbol);
+      /* Also check the normal reasons for suppressing.  */
+      return default_use_anchors_for_symbol_p (symbol);
     }
   else
     return false;
@@ -3067,6 +3130,12 @@ darwin_override_options (void)
       /* Earlier versions are not specifically accounted, until required.  */
     }
 
+  /* Older Darwin ld could not coalesce weak entities without them being
+     placed in special sections.  */
+  if (darwin_target_linker
+      && (strverscmp (darwin_target_linker, MIN_LD64_NO_COAL_SECTS) < 0))
+    ld_uses_coal_sects = true;
+
   /* In principle, this should be c-family only.  However, we really need to
      set sensible defaults for LTO as well, since the section selection stuff
      should check for correctness re. the ABI.  TODO: check and provide the
@@ -3101,6 +3170,14 @@ darwin_override_options (void)
   if (!global_options_set.x_dwarf_version)
     dwarf_version = 2;
 
+  if (global_options_set.x_dwarf_split_debug_info)
+    {
+      inform (input_location,
+             "%<-gsplit-dwarf%> is not supported on this platform, ignored");
+      dwarf_split_debug_info = 0;
+      global_options_set.x_dwarf_split_debug_info = 0;
+    }
+
   /* Do not allow unwind tables to be generated by default for m32.  
      fnon-call-exceptions will override this, regardless of what we do.  */
   if (generating_for_darwin_version < 10
@@ -3126,8 +3203,8 @@ darwin_override_options (void)
               && !global_options_set.x_flag_asynchronous_unwind_tables)))
     {
       inform (input_location,
-             "-freorder-blocks-and-partition does not work with exceptions "
-             "on this architecture");
+             "%<-freorder-blocks-and-partition%> does not work with "
+             "exceptions on this architecture");
       flag_reorder_blocks_and_partition = 0;
       flag_reorder_blocks = 1;
     }
@@ -3147,7 +3224,7 @@ darwin_override_options (void)
   if (flag_mkernel || flag_apple_kext)
     {
       /* -mkernel implies -fapple-kext for C++ */
-      if (strcmp (lang_hooks.name, "GNU C++") == 0)
+      if (lang_GNU_CXX ())
        flag_apple_kext = 1;
 
       flag_no_common = 1;
@@ -3258,7 +3335,7 @@ typedef struct GTY ((for_user)) cfstring_descriptor {
   tree constructor;
 } cfstring_descriptor;
 
-struct cfstring_hasher : ggc_hasher<cfstring_descriptor *>
+struct cfstring_hasher : ggc_ptr_hash<cfstring_descriptor>
 {
   static hashval_t hash (cfstring_descriptor *);
   static bool equal (cfstring_descriptor *, cfstring_descriptor *);
@@ -3489,8 +3566,9 @@ darwin_build_constant_cfstring (tree str)
          for (l = 0; l < length; l++)
            if (!s[l] || !isascii (s[l]))
              {
-               warning (darwin_warn_nonportable_cfstrings, "%s in CFString literal",
-                        s[l] ? "non-ASCII character" : "embedded NUL");
+               warning (darwin_warn_nonportable_cfstrings,
+                        s[l] ? G_("non-ASCII character in CFString literal")
+                             : G_("embedded NUL in CFString literal"));
                break;
              }
        }
@@ -3592,12 +3670,13 @@ darwin_function_section (tree decl, enum node_frequency freq,
                          bool startup, bool exit)
 {
   /* Decide if we need to put this in a coalescable section.  */
-  bool weak = (decl 
+  bool weak = (decl
               && DECL_WEAK (decl)
               && (!DECL_ATTRIBUTES (decl)
                   || !lookup_attribute ("weak_import", 
                                          DECL_ATTRIBUTES (decl))));
 
+  bool use_coal = weak && ld_uses_coal_sects;
   /* If there is a specified section name, we should not be trying to
      override.  */
   if (decl && DECL_SECTION_NAME (decl) != NULL)
@@ -3605,8 +3684,8 @@ darwin_function_section (tree decl, enum node_frequency freq,
 
   /* We always put unlikely executed stuff in the cold section.  */
   if (freq == NODE_FREQUENCY_UNLIKELY_EXECUTED)
-    return (weak) ? darwin_sections[text_cold_coal_section]
-                 : darwin_sections[text_cold_section];
+    return (use_coal) ? darwin_sections[text_cold_coal_section]
+                     : darwin_sections[text_cold_section];
 
   /* If we have LTO *and* feedback information, then let LTO handle
      the function ordering, it makes a better job (for normal, hot,
@@ -3616,40 +3695,23 @@ darwin_function_section (tree decl, enum node_frequency freq,
 
   /* Non-cold startup code should go to startup subsection.  */
   if (startup)
-    return (weak) ? darwin_sections[text_startup_coal_section]
-                 : darwin_sections[text_startup_section];
+    return (use_coal) ? darwin_sections[text_startup_coal_section]
+                     : darwin_sections[text_startup_section];
 
   /* Similarly for exit.  */
   if (exit)
-    return (weak) ? darwin_sections[text_exit_coal_section]
-                 : darwin_sections[text_exit_section];
+    return (use_coal) ? darwin_sections[text_exit_coal_section]
+                     : darwin_sections[text_exit_section];
 
   /* Place hot code.  */
   if (freq == NODE_FREQUENCY_HOT)
-    return (weak) ? darwin_sections[text_hot_coal_section]
-                 : darwin_sections[text_hot_section];
+    return (use_coal) ? darwin_sections[text_hot_coal_section]
+                     : darwin_sections[text_hot_section];
 
   /* Otherwise, default to the 'normal' non-reordered sections.  */
 default_function_sections:
-  return (weak) ? darwin_sections[text_coal_section]
-               : text_section;
-}
-
-/* When a function is partitioned between sections, we need to insert a label
-   at the start of each new chunk - so that it may become a valid 'atom' for
-   eh and debug purposes.  Without this the linker will emit warnings if one 
-   tries to add line location information (since the switched fragment will 
-   be anonymous).  */
-
-void
-darwin_function_switched_text_sections (FILE *fp, tree decl, bool new_is_cold)
-{
-  char buf[128];
-  snprintf (buf, 128, "%s%s",new_is_cold?"__cold_sect_of_":"__hot_sect_of_",
-           IDENTIFIER_POINTER (DECL_NAME (decl)));
-  /* Make sure we pick up all the relevant quotes etc.  */
-  assemble_name_raw (fp, (const char *) buf);
-  fputs (":\n", fp);
+  return (use_coal) ? darwin_sections[text_coal_section]
+                   : text_section;
 }
 
 #include "gt-darwin.h"