/* Functions for generic Darwin as target machine for GNU C compiler.
- Copyright (C) 1989-2013 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 "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 "conditions.h"
-#include "insn-flags.h"
+#include "emit-rtl.h"
+#include "cgraph.h"
+#include "lto-streamer.h"
#include "output.h"
-#include "insn-attr.h"
-#include "flags.h"
-#include "tree.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 "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
fprintf (file, "L%d$pb", current_pic_label_num);
}
+char curr_picbasename[32];
+
+const char *
+machopic_get_function_picbase (void)
+{
+ /* If dynamic-no-pic is on, we should not get here. */
+ gcc_assert (!MACHO_DYNAMIC_NO_PIC_P);
+
+ update_pic_label_number_if_needed ();
+ snprintf (curr_picbasename, 32, "L%d$pb", current_pic_label_num);
+ return (const char *) curr_picbasename;
+}
+
bool
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;
/* 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
{
- p = ggc_alloc_machopic_indirection ();
+ p = ggc_alloc<machopic_indirection> ();
p->symbol = sym_ref;
p->ptr_name = xstrdup (buffer);
p->stub_p = stub_p;
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
{
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;
return NULL_TREE;
}
+static int classes_seen;
+static int objc_metadata_seen;
+
/* Return the section required for Objective C ABI 2 metadata. */
static section *
darwin_objc2_section (tree decl ATTRIBUTE_UNUSED, tree meta, section * base)
gcc_assert (TREE_CODE (ident) == IDENTIFIER_NODE);
p = IDENTIFIER_POINTER (ident);
- /* If we are in LTO, then we don't know the state of flag_next_runtime
- or flag_objc_abi when the code was generated. We set these from the
- meta-data - which is needed to deal with const string constructors. */
+ gcc_checking_assert (flag_next_runtime == 1 && flag_objc_abi == 2);
- flag_next_runtime = 1;
- flag_objc_abi = 2;
+ objc_metadata_seen = 1;
if (base == data_section)
base = darwin_sections[objc2_metadata_section];
else if (!strncmp (p, "V2_NLCL", 7))
return darwin_sections[objc2_nonlazy_class_section];
else if (!strncmp (p, "V2_CLAB", 7))
- return darwin_sections[objc2_classlist_section];
+ {
+ classes_seen = 1;
+ return darwin_sections[objc2_classlist_section];
+ }
else if (!strncmp (p, "V2_SRFS", 7))
return darwin_sections[objc2_selector_refs_section];
else if (!strncmp (p, "V2_NLCA", 7))
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];
gcc_assert (TREE_CODE (ident) == IDENTIFIER_NODE);
p = IDENTIFIER_POINTER (ident);
- /* If we are in LTO, then we don't know the state of flag_next_runtime
- or flag_objc_abi when the code was generated. We set these from the
- meta-data - which is needed to deal with const string constructors. */
- flag_next_runtime = 1;
- if (!global_options_set.x_flag_objc_abi)
- flag_objc_abi = 1;
+ gcc_checking_assert (flag_next_runtime == 1 && flag_objc_abi < 2);
+
+ objc_metadata_seen = 1;
/* String sections first, cos there are lots of strings. */
if (!strncmp (p, "V1_STRG", 7))
return darwin_sections[objc_meth_var_types_section];
else if (!strncmp (p, "V1_CLAS", 7))
- return darwin_sections[objc_class_section];
+ {
+ classes_seen = 1;
+ return darwin_sections[objc_class_section];
+ }
else if (!strncmp (p, "V1_META", 7))
return darwin_sections[objc_meta_class_section];
else if (!strncmp (p, "V1_CATG", 7))
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_low_cst (DECL_SIZE_UNIT (decl), 1) == 0);
+ && 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) ;
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
{
if (TREE_CODE (name) == TYPE_DECL)
name = DECL_NAME (name);
- /* FIXME: This is unsatisfactory for LTO, since it relies on other
- metadata determining the source FE. */
if (!strcmp (IDENTIFIER_POINTER (name), "__builtin_ObjCString"))
{
if (flag_next_runtime)
static bool warned_objc_46 = false;
/* We shall assert that zero-sized objects are an error in ObjC
meta-data. */
- gcc_assert (tree_low_cst (DECL_SIZE_UNIT (decl), 1) != 0);
+ gcc_assert (tree_to_uhwi (DECL_SIZE_UNIT (decl)) != 0);
/* ??? This mechanism for determining the metadata section is
broken when LTO is in use, since the frontend that generated
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];
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
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);
}
machopic_define_symbol (DECL_RTL (decl));
}
- size = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+ size = tree_to_uhwi (DECL_SIZE_UNIT (decl));
#ifdef DEBUG_DARWIN_MEM_ALLOCATORS
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. */
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. */
finalize_ctors ();
if (!vec_safe_is_empty (dtors))
finalize_dtors ();
+
+ /* If we are expecting to output NeXT ObjC meta-data, (and we actually see
+ some) then we output the fix-and-continue marker (Image Info).
+ This applies to Objective C, Objective C++ and LTO with either language
+ as part of the input. */
+ if (flag_next_runtime && objc_metadata_seen)
+ {
+ unsigned int flags = 0;
+ if (flag_objc_abi >= 2)
+ {
+ flags = 16;
+ output_section_asm_op
+ (darwin_sections[objc2_image_info_section]->unnamed.data);
+ }
+ else
+ output_section_asm_op
+ (darwin_sections[objc_image_info_section]->unnamed.data);
+
+ ASM_OUTPUT_ALIGN (asm_out_file, 2);
+ fputs ("L_OBJC_ImageInfo:\n", asm_out_file);
+
+ flags |= (flag_replace_objc_classes && classes_seen) ? 1 : 0;
+ flags |= flag_objc_gc ? 2 : 0;
+
+ fprintf (asm_out_file, "\t.long\t0\n\t.long\t%u\n", flags);
+ }
+
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;
}
}
}
-static hashval_t
-cfstring_hash (const void *ptr)
+bool
+darwin_libc_has_function (enum function_class fn_class)
+{
+ if (fn_class == function_sincos)
+ return false;
+ if (fn_class == function_c99_math_complex
+ || fn_class == function_c99_misc)
+ return (TARGET_64BIT
+ || strverscmp (darwin_macosx_version_min, "10.3") >= 0);
+
+ return true;
+}
+
+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;
}
}
- *loc = desc = ggc_alloc_cleared_cfstring_descriptor ();
+ *loc = desc = ggc_cleared_alloc<cfstring_descriptor> ();
desc->literal = str;
/* isa *. */
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)
{
- *loc = ggc_alloc_cleared_cfstring_descriptor ();
+ *loc = ggc_cleared_alloc<cfstring_descriptor> ();
((struct cfstring_descriptor *)*loc)->literal = str;
}
}
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)
- return (weak)
- ? darwin_sections[text_startup_coal_section]
- : darwin_sections[text_startup_section];
+ /* 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;
- /* 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:
- 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;
- }
-}
-
-/* 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"