]> 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 63a385c49b880ec2b8b15c00c683ba2645bafab6..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 "pointer-set.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
@@ -450,7 +444,7 @@ machopic_should_output_picbase_label (void)
 /* The suffix attached to stub symbols.  */
 #define STUB_SUFFIX "$stub"
 
-typedef struct GTY (()) machopic_indirection
+typedef struct GTY ((for_user)) machopic_indirection
 {
   /* The SYMBOL_REF for the entity referenced.  */
   rtx symbol;
@@ -459,37 +453,65 @@ typedef struct GTY (()) 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_ptr_hash<machopic_indirection>
+{
+  typedef const char *compare_type;
+  static hashval_t hash (machopic_indirection *);
+  static bool equal (machopic_indirection *, const char *);
+};
+
 /* A table mapping stub names and non-lazy pointer names to
    SYMBOL_REFs for the stubbed-to and pointed-to entities.  */
 
-static GTY ((param_is (struct machopic_indirection))) htab_t
-  machopic_indirections;
+static GTY (()) hash_table<indirection_hasher> *machopic_indirections;
 
 /* Return a hash value for a SLOT in the indirections hash table.  */
 
-static hashval_t
-machopic_indirection_hash (const void *slot)
+hashval_t
+indirection_hasher::hash (machopic_indirection *p)
 {
-  const machopic_indirection *p = (const machopic_indirection *) slot;
   return htab_hash_string (p->ptr_name);
 }
 
 /* Returns true if the KEY is the same as that associated with
    SLOT.  */
 
-static int
-machopic_indirection_eq (const void *slot, const void *key)
+bool
+indirection_hasher::equal (machopic_indirection *s, const char *k)
 {
-  return strcmp (((const machopic_indirection *) slot)->ptr_name,
-                (const char *) key) == 0;
+  return strcmp (s->ptr_name, k) == 0;
 }
 
 /* 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)
@@ -498,9 +520,9 @@ machopic_indirection_name (rtx sym_ref, bool stub_p)
   const char *name = XSTR (sym_ref, 0);
   size_t namelen = strlen (name);
   machopic_indirection *p;
-  void ** slot;
   bool needs_quotes;
   const char *suffix;
+  char L_or_l = 'L';
   const char *prefix = user_label_prefix;
   const char *quote = "";
   tree id;
@@ -535,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)
@@ -545,23 +571,22 @@ 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 = htab_create_ggc (37,
-                                            machopic_indirection_hash,
-                                            machopic_indirection_eq,
-                                            /*htab_del=*/NULL);
+    machopic_indirections = hash_table<indirection_hasher>::create_ggc (37);
 
-  slot = htab_find_slot_with_hash (machopic_indirections, buffer,
-                                  htab_hash_string (buffer), INSERT);
+  machopic_indirection **slot
+    = machopic_indirections->find_slot_with_hash (buffer,
+                                                 htab_hash_string (buffer),
+                                                 INSERT);
   if (*slot)
     {
-      p = (machopic_indirection *) *slot;
+      p = *slot;
     }
   else
     {
-      p = ggc_alloc_machopic_indirection ();
+      p = ggc_alloc<machopic_indirection> ();
       p->symbol = sym_ref;
       p->ptr_name = xstrdup (buffer);
       p->stub_p = stub_p;
@@ -589,11 +614,8 @@ machopic_mcount_stub_name (void)
 void
 machopic_validate_stub_or_non_lazy_ptr (const char *name)
 {
-  machopic_indirection *p;
-
-  p = ((machopic_indirection *)
-       (htab_find_with_hash (machopic_indirections, name,
-                            htab_hash_string (name))));
+  machopic_indirection *p
+    = machopic_indirections->find_with_hash (name, htab_hash_string (name));
   if (p && ! p->used)
     {
       const char *real_name;
@@ -658,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))));
 
@@ -671,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);
@@ -696,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;
        }
 
@@ -784,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);
@@ -796,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;
 
@@ -805,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);
@@ -845,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  */
@@ -865,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)))));
@@ -940,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,
@@ -1007,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
@@ -1040,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)
     {
@@ -1062,11 +1073,10 @@ machopic_legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
    DATA is the FILE* for assembly output.  Called from
    htab_traverse.  */
 
-static int
-machopic_output_indirection (void **slot, void *data)
+int
+machopic_output_indirection (machopic_indirection **slot, FILE *asm_out_file)
 {
-  machopic_indirection *p = *((machopic_indirection **) slot);
-  FILE *asm_out_file = (FILE *) data;
+  machopic_indirection *p = *slot;
   rtx symbol;
   const char *sym_name;
   const char *ptr_name;
@@ -1180,9 +1190,8 @@ void
 machopic_finish (FILE *asm_out_file)
 {
   if (machopic_indirections)
-    htab_traverse_noresize (machopic_indirections,
-                           machopic_output_indirection,
-                           asm_out_file);
+    machopic_indirections
+      ->traverse_noresize<FILE *, machopic_output_indirection> (asm_out_file);
 }
 
 int
@@ -1232,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]));
@@ -1281,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 
@@ -1299,22 +1313,17 @@ darwin_mergeable_constant_section (tree exp,
     {
       tree size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
 
-      if (TREE_CODE (size) == INTEGER_CST
-         && TREE_INT_CST_LOW (size) == 4
-         && TREE_INT_CST_HIGH (size) == 0)
-        return darwin_sections[literal4_section];
-      else if (TREE_CODE (size) == INTEGER_CST
-              && TREE_INT_CST_LOW (size) == 8
-              && TREE_INT_CST_HIGH (size) == 0)
-        return darwin_sections[literal8_section];
-      else if (HAVE_GAS_LITERAL16
-              && TARGET_64BIT
-               && TREE_CODE (size) == INTEGER_CST
-               && TREE_INT_CST_LOW (size) == 16
-               && TREE_INT_CST_HIGH (size) == 0)
-        return darwin_sections[literal16_section];
-      else
-        return readonly_data_section;
+      if (TREE_CODE (size) == INTEGER_CST)
+       {
+         if (wi::to_wide (size) == 4)
+           return darwin_sections[literal4_section];
+         else if (wi::to_wide (size) == 8)
+           return darwin_sections[literal8_section];
+         else if (HAVE_GAS_LITERAL16
+                  && TARGET_64BIT
+                  && wi::to_wide (size) == 16)
+           return darwin_sections[literal16_section];
+       }
     }
 
   return readonly_data_section;
@@ -1414,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];
@@ -1513,20 +1523,22 @@ 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_ONE_ONLY (decl);
+       && DECL_COMDAT_GROUP (decl);
+
+  use_coal = (weak || one) && ld_uses_coal_sects;
 
   ro = TREE_READONLY (decl) || TREE_CONSTANT (decl) ;
 
@@ -1538,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:
@@ -1560,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];
@@ -1589,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
        {
@@ -1736,21 +1748,24 @@ 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
       && (GET_CODE (x) == CONST_INT
+         || GET_CODE (x) == CONST_WIDE_INT
          || GET_CODE (x) == CONST_DOUBLE))
     return darwin_sections[literal8_section];
   else if (GET_MODE_SIZE (mode) == 4
           && (GET_CODE (x) == CONST_INT
+              || GET_CODE (x) == CONST_WIDE_INT
               || GET_CODE (x) == CONST_DOUBLE))
     return darwin_sections[literal4_section];
   else if (HAVE_GAS_LITERAL16
           && TARGET_64BIT
           && GET_MODE_SIZE (mode) == 16
           && (GET_CODE (x) == CONST_INT
+              || GET_CODE (x) == CONST_WIDE_INT
               || GET_CODE (x) == CONST_DOUBLE
               || GET_CODE (x) == CONST_VECTOR))
     return darwin_sections[literal16_section];
@@ -1900,9 +1915,6 @@ typedef struct GTY (()) darwin_lto_section_e {
 
 static GTY (()) vec<darwin_lto_section_e, va_gc> *lto_section_names;
 
-/* Segment for LTO data.  */
-#define LTO_SEGMENT_NAME "__GNU_LTO"
-
 /* Section wrapper scheme (used here to wrap the unlimited number of LTO
    sections into three Mach-O ones).
    NOTE: These names MUST be kept in sync with those in
@@ -1915,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.  */
@@ -1923,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;
 }
@@ -1940,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.  */
 
@@ -1985,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);
 }
@@ -2231,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.  */
@@ -2284,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.  */
@@ -2372,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 
     {
@@ -2393,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);
@@ -2510,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;
     } 
 
@@ -2544,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 
     {
@@ -2565,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);
 }
@@ -2624,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;
     } 
 
@@ -2694,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;
     } 
 
@@ -2763,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
@@ -2793,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;
@@ -2815,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');
@@ -2829,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++);
 }
@@ -2840,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.  */
@@ -2902,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]);
@@ -2920,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);
@@ -3021,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;
@@ -3075,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
@@ -3109,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
@@ -3134,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;
     }
@@ -3155,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;
@@ -3259,17 +3328,20 @@ static enum built_in_function darwin_builtin_cfstring;
 /* Store all constructed constant CFStrings in a hash table so that
    they get uniqued properly.  */
 
-typedef struct GTY (()) cfstring_descriptor {
+typedef struct GTY ((for_user)) cfstring_descriptor {
   /* The string literal.  */
   tree literal;
   /* The resulting constant CFString.  */
   tree constructor;
 } cfstring_descriptor;
 
-static GTY ((param_is (struct cfstring_descriptor))) htab_t cfstring_htab;
+struct cfstring_hasher : ggc_ptr_hash<cfstring_descriptor>
+{
+  static hashval_t hash (cfstring_descriptor *);
+  static bool equal (cfstring_descriptor *, cfstring_descriptor *);
+};
 
-static hashval_t cfstring_hash (const void *);
-static int cfstring_eq (const void *, const void *);
+static GTY (()) hash_table<cfstring_hasher> *cfstring_htab;
 
 static tree
 add_builtin_field_decl (tree type, const char *name, tree **chain)
@@ -3352,7 +3424,7 @@ darwin_init_cfstring_builtins (unsigned builtin_cfstring)
   rest_of_decl_compilation (cfstring_class_reference, 0, 0);
   
   /* Initialize the hash table used to hold the constant CFString objects.  */
-  cfstring_htab = htab_create_ggc (31, cfstring_hash, cfstring_eq, NULL);
+  cfstring_htab = hash_table<cfstring_hasher>::create_ggc (31);
 
   return cfstring_type_node;
 }
@@ -3426,10 +3498,10 @@ darwin_libc_has_function (enum function_class fn_class)
   return true;
 }
 
-static hashval_t
-cfstring_hash (const void *ptr)
+hashval_t
+cfstring_hasher::hash (cfstring_descriptor *ptr)
 {
-  tree str = ((const struct cfstring_descriptor *)ptr)->literal;
+  tree str = ptr->literal;
   const unsigned char *p = (const unsigned char *) TREE_STRING_POINTER (str);
   int i, len = TREE_STRING_LENGTH (str);
   hashval_t h = len;
@@ -3440,11 +3512,11 @@ cfstring_hash (const void *ptr)
   return h;
 }
 
-static int
-cfstring_eq (const void *ptr1, const void *ptr2)
+bool
+cfstring_hasher::equal (cfstring_descriptor *ptr1, cfstring_descriptor *ptr2)
 {
-  tree str1 = ((const struct cfstring_descriptor *)ptr1)->literal;
-  tree str2 = ((const struct cfstring_descriptor *)ptr2)->literal;
+  tree str1 = ptr1->literal;
+  tree str2 = ptr2->literal;
   int len1 = TREE_STRING_LENGTH (str1);
 
   return (len1 == TREE_STRING_LENGTH (str2)
@@ -3456,7 +3528,6 @@ tree
 darwin_build_constant_cfstring (tree str)
 {
   struct cfstring_descriptor *desc, key;
-  void **loc;
   tree addr;
 
   if (!str)
@@ -3478,8 +3549,8 @@ darwin_build_constant_cfstring (tree str)
 
   /* Perhaps we already constructed a constant CFString just like this one? */
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, INSERT);
-  desc = (struct cfstring_descriptor *) *loc;
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, INSERT);
+  desc = *loc;
 
   if (!desc)
     {
@@ -3495,13 +3566,14 @@ 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;
              }
        }
 
-      *loc = desc = ggc_alloc_cleared_cfstring_descriptor ();
+      *loc = desc = ggc_cleared_alloc<cfstring_descriptor> ();
       desc->literal = str;
 
       /* isa *. */
@@ -3555,7 +3627,6 @@ bool
 darwin_cfstring_p (tree str)
 {
   struct cfstring_descriptor key;
-  void **loc;
 
   if (!str)
     return false;
@@ -3569,7 +3640,7 @@ darwin_cfstring_p (tree str)
     return false;
 
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, NO_INSERT);
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, NO_INSERT);
   
   if (loc)
     return true;
@@ -3581,14 +3652,13 @@ void
 darwin_enter_string_into_cfstring_table (tree str)
 {
   struct cfstring_descriptor key;
-  void **loc;
 
   key.literal = str;
-  loc = htab_find_slot (cfstring_htab, &key, INSERT);
+  cfstring_descriptor **loc = cfstring_htab->find_slot (&key, INSERT);
 
   if (!*loc)
     {
-      *loc = ggc_alloc_cleared_cfstring_descriptor ();
+      *loc = ggc_cleared_alloc<cfstring_descriptor> ();
       ((struct cfstring_descriptor *)*loc)->literal = str;
     }
 }
@@ -3600,85 +3670,48 @@ 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_TREE)
+  if (decl && DECL_SECTION_NAME (decl) != NULL)
     return get_named_section (decl, NULL, 0);
 
-  /* Default when there is no function re-ordering.  */
-  if (!flag_reorder_functions)
-    return (weak)
-           ? darwin_sections[text_coal_section]
-           : text_section;
+  /* We always put unlikely executed stuff in the cold section.  */
+  if (freq == NODE_FREQUENCY_UNLIKELY_EXECUTED)
+    return (use_coal) ? darwin_sections[text_cold_coal_section]
+                     : darwin_sections[text_cold_section];
 
-  /* Startup code should go to startup subsection unless it is
-     unlikely executed (this happens especially with function splitting
-     where we can split away unnecessary parts of static constructors).  */
-  if (startup && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
-  {
-    /* If we do have a profile or(and) LTO phase is executed, we do not need
-       these ELF section.  */
-    if (!in_lto_p || !flag_profile_values)
-      return (weak)
-             ? darwin_sections[text_startup_coal_section]
-             : darwin_sections[text_startup_section];
-    else
-      return text_section;
-  }
-
-  /* Similarly for exit.  */
-  if (exit && freq != NODE_FREQUENCY_UNLIKELY_EXECUTED)
-    return (weak)
-           ? darwin_sections[text_exit_coal_section]
-           : darwin_sections[text_exit_section];
-
-  /* Group cold functions together, similarly for hot code.  */
-  switch (freq)
-    {
-      case NODE_FREQUENCY_UNLIKELY_EXECUTED:
-       return (weak)
-               ? darwin_sections[text_cold_coal_section]
-               : darwin_sections[text_cold_section];
-       break;
-      case NODE_FREQUENCY_HOT:
-      {
-        /* If we do have a profile or(and) LTO phase is executed, we do not need
-           these ELF section.  */
-        if (!in_lto_p || !flag_profile_values)
-          return (weak)
-                  ? darwin_sections[text_hot_coal_section]
-                  : darwin_sections[text_hot_section];
-        break;
-      }
-      default:
-       return (weak)
-               ? darwin_sections[text_coal_section]
-               : text_section;
-       break;
-    }
-}
+  /* If we have LTO *and* feedback information, then let LTO handle
+     the function ordering, it makes a better job (for normal, hot,
+     startup and exit - hence the bailout for cold above).  */
+  if (in_lto_p && flag_profile_values)
+    goto default_function_sections;
 
-/* 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).  */
+  /* Non-cold startup code should go to startup subsection.  */
+  if (startup)
+    return (use_coal) ? darwin_sections[text_startup_coal_section]
+                     : darwin_sections[text_startup_section];
 
-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);
+  /* Similarly for exit.  */
+  if (exit)
+    return (use_coal) ? darwin_sections[text_exit_coal_section]
+                     : darwin_sections[text_exit_section];
+
+  /* Place hot code.  */
+  if (freq == NODE_FREQUENCY_HOT)
+    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 (use_coal) ? darwin_sections[text_coal_section]
+                   : text_section;
 }
 
 #include "gt-darwin.h"