/* Functions for generic Darwin as target machine for GNU C compiler.
- Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1989, 1990, 1991, 1992, 1993, 2000, 2001, 2002, 2003, 2004,
+ 2005
Free Software Foundation, Inc.
Contributed by Apple Computer Inc.
#include "function.h"
#include "ggc.h"
#include "langhooks.h"
+#include "target.h"
#include "tm_p.h"
#include "errors.h"
#include "hashtab.h"
+/* Darwin supports a feature called fix-and-continue, which is used
+ for rapid turn around debugging. When code is compiled with the
+ -mfix-and-continue flag, two changes are made to the generated code
+ that allow the system to do things that it would normally not be
+ able to do easily. These changes allow gdb to load in
+ recompilation of a translation unit that has been changed into a
+ running program and replace existing functions and methods of that
+ translation unit with with versions of those functions and methods
+ from the newly compiled translation unit. The new functions access
+ the existing static data from the old translation unit, if the data
+ existed in the unit to be replaced, and from the new translation
+ unit, for new data.
+
+ The changes are to insert 5 nops at the beginning of all functions
+ and to use indirection to get at static duration data. The 5 nops
+ are required by consumers of the generated code. Currently, gdb
+ uses this to patch in a jump to the overriding function, this
+ allows all uses of the old name to forward to the replacement,
+ including existing function pointers and virtual methods. See
+ rs6000_emit_prologue for the code that handles the nop insertions.
+
+ The added indirection allows gdb to redirect accesses to static
+ duration data from the newly loaded translation unit to the
+ existing data, if any. @code{static} data is special and is
+ handled by setting the second word in the .non_lazy_symbol_pointer
+ data structure to the address of the data. See indirect_data for
+ the code that handles the extra indirection, and
+ machopic_output_indirection and its use of MACHO_SYMBOL_STATIC for
+ the code that handles @code{static} data indirection. */
+
+
/* Nonzero if the user passes the -mone-byte-bool switch, which forces
sizeof(bool) to be 1. */
const char *darwin_one_byte_bool = 0;
return 0;
}
-/*
- * flag_pic = 1 ... generate only indirections
- * flag_pic = 2 ... generate indirections and pure code
- */
-
+/* Return true if SYM_REF can be used without an indirection. */
static int
machopic_symbol_defined_p (rtx sym_ref)
{
- return ((SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_DEFINED)
- /* Local symbols must always be defined. */
- || SYMBOL_REF_LOCAL_P (sym_ref));
+ if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_DEFINED)
+ return true;
+
+ /* If a symbol references local and is not an extern to this
+ file, then the symbol might be able to declared as defined. */
+ if (SYMBOL_REF_LOCAL_P (sym_ref) && ! SYMBOL_REF_EXTERNAL_P (sym_ref))
+ {
+ /* If the symbol references a variable and the variable is a
+ common symbol, then this symbol is not defined. */
+ if (SYMBOL_REF_FLAGS (sym_ref) & MACHO_SYMBOL_FLAG_VARIABLE)
+ {
+ tree decl = SYMBOL_REF_DECL (sym_ref);
+ if (!decl)
+ return true;
+ if (DECL_COMMON (decl))
+ return false;
+ }
+ return true;
+ }
+ return false;
}
/* This module assumes that (const (symbol_ref "foo")) is a legal pic
? MACHOPIC_UNDEFINED_FUNCTION : MACHOPIC_UNDEFINED_DATA);
}
+#ifndef TARGET_FIX_AND_CONTINUE
+#define TARGET_FIX_AND_CONTINUE 0
+#endif
+
+/* Indicate when fix-and-continue style code generation is being used
+ and when a reference to data should be indirected so that it can be
+ rebound in a new translation unit to reference the original instance
+ of that data. Symbol names that are for code generation local to
+ the translation unit are bound to the new translation unit;
+ currently this means symbols that begin with L or _OBJC_;
+ otherwise, we indicate that an indirect reference should be made to
+ permit the runtime to rebind new instances of the translation unit
+ to the original instance of the data. */
+
+static int
+indirect_data (rtx sym_ref)
+{
+ int lprefix;
+ const char *name;
+
+ /* If we aren't generating fix-and-continue code, don't do anything special. */
+ if (TARGET_FIX_AND_CONTINUE == 0)
+ return 0;
+
+ /* Otherwise, all symbol except symbols that begin with L or _OBJC_
+ are indirected. Symbols that begin with L and _OBJC_ are always
+ bound to the current translation unit as they are used for
+ generated local data of the translation unit. */
+
+ name = XSTR (sym_ref, 0);
+
+ lprefix = (((name[0] == '*' || name[0] == '&')
+ && (name[1] == 'L' || (name[1] == '"' && name[2] == 'L')))
+ || (strncmp (name, "_OBJC_", 6) == 0));
+
+ return ! lprefix;
+}
+
+
static int
machopic_data_defined_p (rtx sym_ref)
{
+ if (indirect_data (sym_ref))
+ return 0;
+
switch (machopic_classify_symbol (sym_ref))
{
case MACHOPIC_DEFINED_DATA:
+ case MACHOPIC_DEFINED_FUNCTION:
return 1;
default:
return 0;
{
/* The SYMBOL_REF for the entity referenced. */
rtx symbol;
- /* The IDENTIFIER_NODE giving the name of the stub or non-lazy
- pointer. */
- tree ptr_name;
+ /* The name of the stub or non-lazy pointer. */
+ const char * ptr_name;
/* True iff this entry is for a stub (as opposed to a non-lazy
pointer). */
bool stub_p;
machopic_indirection_hash (const void *slot)
{
const machopic_indirection *p = (const machopic_indirection *) slot;
- return IDENTIFIER_HASH_VALUE (p->ptr_name);
+ return htab_hash_string (p->ptr_name);
}
/* Returns true if the KEY is the same as that associated with
static int
machopic_indirection_eq (const void *slot, const void *key)
{
- return ((const machopic_indirection *) slot)->ptr_name == (tree) key;
+ return strcmp (((const machopic_indirection *) slot)->ptr_name, key) == 0;
}
/* Return the name of the non-lazy pointer (if STUB_P is false) or
{
char *buffer;
const char *name = XSTR (sym_ref, 0);
- int namelen = strlen (name);
- tree ptr_name;
+ size_t namelen = strlen (name);
machopic_indirection *p;
+ void ** slot;
/* Construct the name of the non-lazy pointer or stub. */
if (stub_p)
user_label_prefix, name);
}
- /* See if we already have it. */
- ptr_name = maybe_get_identifier (buffer);
- /* If not, create a mapping from the non-lazy pointer to the
- SYMBOL_REF. */
- if (!ptr_name)
+ if (!machopic_indirections)
+ machopic_indirections = htab_create_ggc (37,
+ machopic_indirection_hash,
+ machopic_indirection_eq,
+ /*htab_del=*/NULL);
+
+ slot = htab_find_slot_with_hash (machopic_indirections, buffer,
+ htab_hash_string (buffer), INSERT);
+ if (*slot)
+ {
+ p = (machopic_indirection *) *slot;
+ }
+ else
{
- void **slot;
- ptr_name = get_identifier (buffer);
p = (machopic_indirection *) ggc_alloc (sizeof (machopic_indirection));
p->symbol = sym_ref;
- p->ptr_name = ptr_name;
+ p->ptr_name = xstrdup (buffer);
p->stub_p = stub_p;
- p->used = 0;
- if (!machopic_indirections)
- machopic_indirections
- = htab_create_ggc (37,
- machopic_indirection_hash,
- machopic_indirection_eq,
- /*htab_del=*/NULL);
- slot = htab_find_slot_with_hash (machopic_indirections, ptr_name,
- IDENTIFIER_HASH_VALUE (ptr_name),
- INSERT);
- *((machopic_indirection **) slot) = p;
+ p->used = false;
+ *slot = p;
}
- return IDENTIFIER_POINTER (ptr_name);
+ return p->ptr_name;
}
/* Return the name of the stub for the mcount function. */
const char*
machopic_mcount_stub_name (void)
{
- return "&L*mcount$stub";
+ rtx symbol = gen_rtx_SYMBOL_REF (Pmode, "*mcount");
+ return machopic_indirection_name (symbol, /*stub_p=*/true);
}
/* If NAME is the name of a stub or a non-lazy pointer , mark the stub
void
machopic_validate_stub_or_non_lazy_ptr (const char *name)
{
- tree ident = get_identifier (name);
-
machopic_indirection *p;
p = ((machopic_indirection *)
- (htab_find_with_hash (machopic_indirections, ident,
- IDENTIFIER_HASH_VALUE (ident))));
- if (p)
+ (htab_find_with_hash (machopic_indirections, name,
+ htab_hash_string (name))));
+ if (p && ! p->used)
{
- p->used = 1;
- mark_referenced (ident);
- mark_referenced (get_identifier (XSTR (p->symbol, 0)));
+ const char *real_name;
+ tree id;
+
+ p->used = true;
+
+ /* Do what output_addr_const will do when we actually call it. */
+ if (SYMBOL_REF_DECL (p->symbol))
+ mark_decl_referenced (SYMBOL_REF_DECL (p->symbol));
+
+ real_name = targetm.strip_name_encoding (XSTR (p->symbol, 0));
+
+ id = maybe_get_identifier (real_name);
+ if (id)
+ mark_referenced (id);
}
}
if (defined && MACHO_DYNAMIC_NO_PIC_P)
{
#if defined (TARGET_TOC)
- emit_insn (GET_MODE (orig) == DImode
- ? gen_macho_high_di (reg, orig)
- : gen_macho_high (reg, orig));
- emit_insn (GET_MODE (orig) == DImode
- ? gen_macho_low_di (reg, reg, orig)
- : gen_macho_low (reg, reg, orig));
+ emit_insn (gen_macho_high (reg, orig));
+ emit_insn (gen_macho_low (reg, reg, orig));
#else
/* some other cpu -- writeme! */
abort ();
return orig;
}
- ptr_ref = (gen_rtx_SYMBOL_REF
+ ptr_ref = (gen_rtx_SYMBOL_REF
(Pmode,
machopic_indirection_name (orig, /*stub_p=*/false)));
SYMBOL_REF_DECL (ptr_ref) = SYMBOL_REF_DECL (orig);
ptr_ref = gen_const_mem (Pmode, ptr_ref);
+ machopic_define_symbol (ptr_ref);
return ptr_ref;
}
rtx asym = XEXP (orig, 0);
rtx mem;
- emit_insn (mode == DImode
- ? gen_macho_high_di (temp_reg, asym)
- : gen_macho_high (temp_reg, asym));
+ emit_insn (gen_macho_high (temp_reg, asym));
mem = gen_const_mem (GET_MODE (orig),
gen_rtx_LO_SUM (Pmode, temp_reg, asym));
emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
else
#endif /* HAVE_lo_sum */
{
- if (GET_CODE (orig) == REG)
+ if (REG_P (orig)
+ || GET_CODE (orig) == SUBREG)
{
return orig;
}
symbol = p->symbol;
sym_name = XSTR (symbol, 0);
- ptr_name = IDENTIFIER_POINTER (p->ptr_name);
+ ptr_name = p->ptr_name;
if (p->stub_p)
{
else
sprintf (stub, "%s%s", user_label_prefix, ptr_name);
- machopic_output_stub (asm_out_file, sym, stub);
+ machopic_output_stub (asm_out_file, sym, stub);
}
- else if (machopic_symbol_defined_p (symbol))
+ else if (! indirect_data (symbol)
+ && (machopic_symbol_defined_p (symbol)
+ || SYMBOL_REF_LOCAL_P (symbol)))
{
data_section ();
assemble_align (GET_MODE_ALIGNMENT (Pmode));
}
else
{
+ rtx init = const0_rtx;
+
machopic_nl_symbol_ptr_section ();
assemble_name (asm_out_file, ptr_name);
fprintf (asm_out_file, ":\n");
assemble_name (asm_out_file, sym_name);
fprintf (asm_out_file, "\n");
- assemble_integer (const0_rtx, GET_MODE_SIZE (Pmode),
+ /* Variables that are marked with MACHO_SYMBOL_STATIC need to
+ have their symbol name instead of 0 in the second entry of
+ the non-lazy symbol pointer data structure when they are
+ defined. This allows the runtime to rebind newer instances
+ of the translation unit with the original instance of the
+ data. */
+
+ if ((SYMBOL_REF_FLAGS (symbol) & MACHO_SYMBOL_STATIC)
+ && machopic_symbol_defined_p (symbol))
+ init = gen_rtx_SYMBOL_REF (Pmode, sym_name);
+
+ assemble_integer (init, GET_MODE_SIZE (Pmode),
GET_MODE_ALIGNMENT (Pmode), 1);
}
machopic_finish (FILE *asm_out_file)
{
if (machopic_indirections)
- htab_traverse_noresize (machopic_indirections,
+ htab_traverse_noresize (machopic_indirections,
machopic_output_indirection,
asm_out_file);
}
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_VARIABLE;
if (!DECL_EXTERNAL (decl)
- && (!TREE_PUBLIC (decl) || (!DECL_ONE_ONLY (decl) && !DECL_WEAK (decl)))
+ && (!TREE_PUBLIC (decl) || !DECL_WEAK (decl))
&& ((TREE_STATIC (decl)
&& (!DECL_COMMON (decl) || !TREE_PUBLIC (decl)))
|| (!DECL_COMMON (decl) && DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node)))
SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_FLAG_DEFINED;
-}
-void
-darwin_make_decl_one_only (tree decl)
-{
- static const char *text_section = "__TEXT,__textcoal_nt,coalesced,no_toc";
- static const char *data_section = "__DATA,__datacoal_nt,coalesced,no_toc";
-
- const char *sec = TREE_CODE (decl) == FUNCTION_DECL
- ? text_section
- : data_section;
- TREE_PUBLIC (decl) = 1;
- DECL_ONE_ONLY (decl) = 1;
- DECL_SECTION_NAME (decl) = build_string (strlen (sec), sec);
+ if (TREE_CODE (decl) == VAR_DECL
+ && indirect_data (sym_ref)
+ && ! TREE_PUBLIC (decl))
+ SYMBOL_REF_FLAGS (sym_ref) |= MACHO_SYMBOL_STATIC;
}
void
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
void (*base_function)(void);
-
- if (decl_readonly_section_1 (exp, reloc, MACHOPIC_INDIRECT))
- base_function = readonly_data_section;
+ bool weak_p = DECL_P (exp) && DECL_WEAK (exp);
+ static void (* const base_funs[][2])(void) = {
+ { text_section, text_coal_section },
+ { unlikely_text_section, text_unlikely_coal_section },
+ { readonly_data_section, const_coal_section },
+ { const_data_section, const_data_coal_section },
+ { data_section, data_coal_section }
+ };
+
+ if (reloc == 0
+ && (last_text_section == in_text_unlikely
+ || last_text_section == in_text_unlikely_coal))
+ reloc = 1;
+
+ if (TREE_CODE (exp) == FUNCTION_DECL)
+ base_function = base_funs[reloc][weak_p];
+ else if (decl_readonly_section_1 (exp, reloc, MACHOPIC_INDIRECT))
+ base_function = base_funs[2][weak_p];
else if (TREE_READONLY (exp) || TREE_CONSTANT (exp))
- base_function = const_data_section;
+ base_function = base_funs[3][weak_p];
else
- base_function = data_section;
+ base_function = base_funs[4][weak_p];
if (TREE_CODE (exp) == STRING_CST
&& ((size_t) TREE_STRING_LENGTH (exp)
else if ((TREE_CODE (exp) == INTEGER_CST || TREE_CODE (exp) == REAL_CST)
&& flag_merge_constants)
{
- tree size = TYPE_SIZE (TREE_TYPE (exp));
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (exp));
if (TREE_CODE (size) == INTEGER_CST &&
TREE_INT_CST_LOW (size) == 4 &&
else
base_function ();
}
+ /* ::operator new and ::operator delete must be coalesced, even
+ if not weak. There are 8 variants that we look for. */
+ else if (TREE_CODE (exp) == FUNCTION_DECL
+ && ! DECL_ONE_ONLY (exp))
+ {
+ const char * name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (exp));
+ if (name[0] == '_' && name[1] == 'Z'
+ && ((name[2] == 'n' && (name[3] == 'a' || name[3] == 'w')
+ && name[4] == 'm')
+ || (name[2] == 'd' && (name[3] == 'a' || name[3] == 'l')
+ && name[4] == 'P' && name[5] == 'v')))
+ {
+ bool delete_p = name[2] == 'd';
+ if (name[5 + delete_p] == 0
+ || strcmp (name + 5 + delete_p, "KSt9nothrow_t") == 0)
+ base_funs[reloc][1] ();
+ else
+ base_function ();
+ }
+ else
+ base_function ();
+ }
else
base_function ();
}
machopic_select_rtx_section (enum machine_mode mode, rtx x,
unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
{
- if (GET_MODE_SIZE (mode) == 8)
+ if (GET_MODE_SIZE (mode) == 8
+ && (GET_CODE (x) == CONST_INT
+ || GET_CODE (x) == CONST_DOUBLE))
literal8_section ();
else if (GET_MODE_SIZE (mode) == 4
&& (GET_CODE (x) == CONST_INT
}
void
-darwin_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
+darwin_asm_named_section (const char *name,
+ unsigned int flags ATTRIBUTE_UNUSED,
+ tree decl ATTRIBUTE_UNUSED)
{
- fprintf (asm_out_file, ".section %s\n", name);
+ fprintf (asm_out_file, "\t.section %s\n", name);
}
-unsigned int
-darwin_section_type_flags (tree decl, const char *name, int reloc)
-{
- unsigned int flags = default_section_type_flags (decl, name, reloc);
-
- /* Weak or linkonce variables live in a writable section. */
- if (decl != 0 && TREE_CODE (decl) != FUNCTION_DECL
- && (DECL_WEAK (decl) || DECL_ONE_ONLY (decl)))
- flags |= SECTION_WRITE;
-
- return flags;
-}
-
void
-darwin_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
+darwin_unique_section (tree decl ATTRIBUTE_UNUSED, int reloc ATTRIBUTE_UNUSED)
{
- /* Darwin does not use unique sections. However, the target's
- unique_section hook is called for linkonce symbols. We need
- to set an appropriate section for such symbols. */
- if (DECL_ONE_ONLY (decl) && !DECL_SECTION_NAME (decl))
- darwin_make_decl_one_only (decl);
+ /* Darwin does not use unique sections. */
}
-#define HAVE_DEAD_STRIP 0
+/* Handle a "weak_import" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+darwin_handle_weak_import_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags),
+ bool * no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL && TREE_CODE (*node) != VAR_DECL)
+ {
+ warning ("%qs attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+ else
+ declare_weak (*node);
+
+ return NULL_TREE;
+}
static void
no_dead_strip (FILE *file, const char *lab)
{
- if (HAVE_DEAD_STRIP)
- fprintf (file, ".no_dead_strip %s\n", lab);
+ fprintf (file, ".no_dead_strip %s\n", lab);
}
/* Emit a label for an FDE, making it global and/or weak if appropriate.
strcat(lab, "\"");
if (TREE_PUBLIC (decl))
- fprintf (file, "%s %s\n",
+ fprintf (file, "\t%s %s\n",
(DECL_VISIBILITY (decl) != VISIBILITY_HIDDEN
? ".globl"
: ".private_extern"),
lab);
- if (DECL_ONE_ONLY (decl) && TREE_PUBLIC (decl))
- fprintf (file, ".weak_definition %s\n", lab);
+ if (DECL_WEAK (decl))
+ fprintf (file, "\t.weak_definition %s\n", lab);
if (empty)
{
fputs ("\n", asm_out_file);
}
else
- warning ("internal and protected visibility attributes not supported"
+ warning ("internal and protected visibility attributes not supported "
"in this configuration; ignored");
}
static int darwin_dwarf_label_counter;
void
-darwin_asm_output_dwarf_delta (FILE *file, int size ATTRIBUTE_UNUSED,
+darwin_asm_output_dwarf_delta (FILE *file, int size,
const char *lab1, const char *lab2)
{
int islocaldiff = (lab1[0] == '*' && lab1[1] == 'L'
&& lab2[0] == '*' && lab2[1] == 'L');
+ const char *directive = (size == 8 ? ".quad" : ".long");
if (islocaldiff)
fprintf (file, "\t.set L$set$%d,", darwin_dwarf_label_counter);
else
- fprintf (file, "\t%s\t", ".long");
- assemble_name (file, lab1);
+ fprintf (file, "\t%s\t", directive);
+ assemble_name_raw (file, lab1);
fprintf (file, "-");
- assemble_name (file, lab2);
+ assemble_name_raw (file, lab2);
if (islocaldiff)
- fprintf (file, "\n\t.long L$set$%d", darwin_dwarf_label_counter++);
+ fprintf (file, "\n\t%s L$set$%d", directive, darwin_dwarf_label_counter++);
}
void
fprintf (asm_out_file, "\t.subsections_via_symbols\n");
}
+/* True, iff we're generating fast turn around debugging code. When
+ true, we arrange for function prologues to start with 4 nops so
+ that gdb may insert code to redirect them, and for data to accessed
+ indirectly. The runtime uses this indirection to forward
+ references for data to the original instance of that data. */
+
+int darwin_fix_and_continue;
+const char *darwin_fix_and_continue_switch;
+
#include "gt-darwin.h"