/* 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.
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
/* 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
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
/* 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;
/* 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)
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;
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)
+ 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
{
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;
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))));
{
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);
&& 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;
}
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);
}
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;
/* 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);
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 */
? 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)))));
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,
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
}
/* 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)
{
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;
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
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]));
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
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];
}
}
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];
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))
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:
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];
case SECCAT_BSS:
case SECCAT_SBSS:
case SECCAT_TBSS:
- if (weak || one)
+ if (use_coal)
base_section = darwin_sections[data_coal_section];
else
{
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
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. */
{
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;
}
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. */
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);
}
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. */
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. */
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
{
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);
{
/* 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;
}
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
{
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);
}
{
/* 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;
}
{
/* 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;
}
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
}
}
- fprintf (asm_out_file, "\t.section %s\n", name);
if (!found)
{
dwarf_sect_used_entry e;
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');
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++);
}
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. */
}
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]);
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);
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;
/* 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
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
&& !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;
}
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;
/* 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)
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;
}
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;
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)
darwin_build_constant_cfstring (tree str)
{
struct cfstring_descriptor *desc, key;
- void **loc;
tree addr;
if (!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)
{
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;
}
}
darwin_cfstring_p (tree str)
{
struct cfstring_descriptor key;
- void **loc;
if (!str)
return false;
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;
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)
{
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)
/* 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,
/* 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"