The bug arises because of the use, by the ObjC FE, of two old target
macros that emit efficient representations of class definitions and
references.
This 'works fine' (however wrong it might be conceptually), until LTO
is engaged, whereupon the definitions vanish without trace (since no
corresponding real variable is ever created).
---
The patch creates appropriate variables in the FE and tags them as
ObjC meta-data (in the same manner as is done for other objc meta-data).
We then intercept them in varasm.c with a hook that allows the target
to declare that it has completely handled the output of a variable -
allowing us to handle them in the required special manner.
FAOD, It is necessary to preserve this mechanism for emitting the
definitions and references to permit linkage with existing system
libraries.
----
If the patch is acceptable, then I would expect to follow up with a
patch to remove ASM_DECLARE_CLASS_REFERENCE and
ASM_DECLARE_UNRESOLVED_REFERENCE from the tree - since this is their
only use.
----
bootstrapped on i686-linux, i686-darwin9, x86_64-darwin10, (checked
to do the Right Thing on darwin).
Mike has already given this a 'seems reasonable' in the PR thread,
however, I need an approver for the varasm.c and target hook changes.
OK for trunk & 4.6?
Iain
===
gcc/
* target.def (handled_assemble_variable_p): New hook.
* varasm.c (assemble_variable): Allow target to handle variable output
in some special manner.
* doc/tm.texi: Regenerate.
* config/darwin.c (darwin_objc1_section): Handle class defs/refs.
(darwin_handled_assemble_variable_p): New.
* config/darwin-protos.h (darwin_handled_assemble_variable_p): New.
* config/darwin.h (TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P): New.
gcc/objc/
*objc-next-runtime-abi-01.c (handle_next_class_ref): Don't emit lazy
refs. for
cases where the class is local. Declare a real, meta-data item
tagged as
a class reference.
(handle_next_impent): Declare a real, meta-data item tagged as a
class def.
===
Index: gcc/target.def
===================================================================
--- gcc/target.def (revision 175628)
+++ gcc/target.def (working copy)
@@ -449,6 +449,13 @@ DEFHOOK
bool, (FILE *file, rtx x),
default_asm_output_addr_const_extra)
+DEFHOOK
+(handled_assemble_variable_p,
+ "Returns @code{true} iff the target has handled the assembly of the\
+ variable @var{var_decl}",
+ bool, (tree var_decl),
+ hook_bool_tree_false)
+
/* ??? The TARGET_PRINT_OPERAND* hooks are part of the asm_out struct,
even though that is not reflected in the macro name to override
their
initializers. */
Index: gcc/objc/objc-next-runtime-abi-01.c
===================================================================
--- gcc/objc/objc-next-runtime-abi-01.c (revision 175628)
+++ gcc/objc/objc-next-runtime-abi-01.c (working copy)
@@ -2267,27 +2267,51 @@ generate_objc_symtab_decl (void)
init_objc_symtab (TREE_TYPE (UOBJC_SYMBOLS_decl)));
}
-
static void
handle_next_class_ref (tree chain)
{
+ tree decl, exp;
+ struct imp_entry *impent;
const char *name = IDENTIFIER_POINTER (TREE_VALUE (chain));
char *string = (char *) alloca (strlen (name) + 30);
+ for (impent = imp_list; impent; impent = impent->next)
+ if (TREE_CODE (impent->imp_context) == CLASS_IMPLEMENTATION_TYPE
+ && IDENTIFIER_POINTER (CLASS_NAME (impent->imp_context))
+ == IDENTIFIER_POINTER (TREE_VALUE (chain)))
+ return; /* we declare this, no need for a lazy ref. */
+
sprintf (string, ".objc_class_name_%s", name);
-#ifdef ASM_DECLARE_UNRESOLVED_REFERENCE
- ASM_DECLARE_UNRESOLVED_REFERENCE (asm_out_file, string);
-#else
- return ; /* NULL build for targets other than Darwin. */
-#endif
+ decl = build_decl (UNKNOWN_LOCATION,
+ VAR_DECL, get_identifier (string), char_type_node);
+ TREE_PUBLIC (decl) = 1;
+ DECL_EXTERNAL (decl) = 1;
+ DECL_CONTEXT (decl) = NULL_TREE;
+ finish_var_decl (decl, NULL);
+
+ /* We build a variable to signal the reference. This will be
intercepted
+ and output as a lazy reference. */
+ sprintf (string, "_OBJC_class_ref_%s", name);
+ exp = build1 (ADDR_EXPR, string_type_node, decl);
+ decl = build_decl (input_location,
+ VAR_DECL, get_identifier (string), string_type_node);
+ TREE_STATIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_INITIAL (decl) = error_mark_node;
+
+ /* We must force the reference. */
+ DECL_PRESERVE_P (decl) = 1;
+ OBJCMETA (decl, objc_meta, get_identifier ("V1_CREF"));
+ DECL_CONTEXT (decl) = NULL_TREE;
+ finish_var_decl (decl, exp);
}
static void
handle_next_impent (struct imp_entry *impent)
{
char buf[BUFSIZE];
-
+ tree decl;
switch (TREE_CODE (impent->imp_context))
{
case CLASS_IMPLEMENTATION_TYPE:
@@ -2303,11 +2327,16 @@ handle_next_impent (struct imp_entry *impent)
return;
}
-#ifdef ASM_DECLARE_CLASS_REFERENCE
- ASM_DECLARE_CLASS_REFERENCE (asm_out_file, buf);
-#else
- return ; /* NULL build for targets other than Darwin. */
-#endif
+ /* We build a variable to signal that this TU contains this class
metadata. */
+ decl = build_decl (UNKNOWN_LOCATION,
+ VAR_DECL, get_identifier (buf), char_type_node);
+ TREE_PUBLIC (decl) = 1;
+ DECL_CONTEXT (decl) = NULL_TREE;
+ OBJCMETA (decl, objc_meta, get_identifier ("V1_CDEF"));
+ TREE_STATIC (decl) = 1;
+ DECL_ARTIFICIAL (decl) = 1;
+ DECL_INITIAL (decl) = error_mark_node;
+ finish_var_decl (decl, NULL);
}
static void
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c (revision 175628)
+++ gcc/varasm.c (working copy)
@@ -2009,6 +2009,10 @@ assemble_variable (tree decl, int top_level
ATTRIB
align_variable (decl, dont_output_data);
set_mem_align (decl_rtl, DECL_ALIGN (decl));
+ /* Allow the target to handle the variable output in some special
manner. */
+ if (targetm.asm_out.handled_assemble_variable_p (decl))
+ return;
+
if (TREE_PUBLIC (decl))
maybe_assemble_visibility (decl);
Index: gcc/config/darwin-protos.h
===================================================================
--- gcc/config/darwin-protos.h (revision 175628)
+++ gcc/config/darwin-protos.h (working copy)
@@ -106,6 +106,7 @@ extern void darwin_asm_output_aligned_decl_local (
extern void darwin_asm_output_aligned_decl_common (FILE *, tree,
const char *,
unsigned HOST_WIDE_INT,
unsigned int);
+extern bool darwin_handled_assemble_variable_p (tree);
extern bool darwin_binds_local_p (const_tree);
extern void darwin_cpp_builtins (struct cpp_reader *);
Index: gcc/config/darwin.c
===================================================================
--- gcc/config/darwin.c (revision 175628)
+++ gcc/config/darwin.c (working copy)
@@ -1439,6 +1439,11 @@ darwin_objc1_section (tree decl ATTRIBUTE_UNUSED,
else if (!strncmp (p, "V2_CSTR", 7))
return darwin_sections[objc_constant_string_object_section];
+ else if (!strncmp (p, "V1_CREF", 7))
+ return darwin_sections[objc_cls_refs_section];
+ else if (!strncmp (p, "V1_CDEF", 7))
+ return data_section;
+
return base;
}
@@ -2594,6 +2599,53 @@ darwin_assemble_visibility (tree decl, int vis)
"not supported in this configuration; ignored");
}
+/* For certain Objective-C metadata we handle the assembly of the
variables
+ here (it must be here, rather than in darwin-c.c, to cater for
LTO). When
+ we reference a class we emit a lazy ref, when we have class metadata
+ (local to a specific object), we emit a tag so that linkage will be
+ satisfied for the class. */
+
+bool
+darwin_handled_assemble_variable_p (tree decl)
+{
+ tree meta;
+ if (DECL_ATTRIBUTES (decl)
+ && (meta = lookup_attribute ("OBJC1META", DECL_ATTRIBUTES
(decl))))
+ {
+ const char *name;
+ rtx decl_rtl, symbol;
+
+ if (TREE_VALUE (meta) == get_identifier ("V1_CREF"))
+ {
+ tree exp = DECL_INITIAL (decl);
+ gcc_assert (exp
+ && exp != error_mark_node
+ && TREE_CODE (exp) == ADDR_EXPR);
+ exp = TREE_OPERAND (exp, 0);
+ decl_rtl = DECL_RTL (exp);
+ symbol = XEXP (decl_rtl, 0);
+ name = XSTR (symbol, 0);
+ targetm.asm_out.globalize_decl_name (asm_out_file, exp);
+ fputs ("\t.lazy_reference\t",asm_out_file);
+ assemble_name (asm_out_file, name);
+ fputs ("\n",asm_out_file);
+ return true;
+ }
+ else if (TREE_VALUE (meta) == get_identifier ("V1_CDEF"))
+ {
+ decl_rtl = DECL_RTL (decl);
+ symbol = XEXP (decl_rtl, 0);
+ name = XSTR (symbol, 0);
+ targetm.asm_out.globalize_decl_name (asm_out_file, decl);
+ fputs ("\t",asm_out_file);
+ assemble_name (asm_out_file, name);
+ fputs (" = 0\n",asm_out_file);
+ return true;
+ }
+ }
+ return false;
+}
+
/* VEC Used by darwin_asm_dwarf_section.
Maybe a hash tab would be better here - but the intention is that
this is
a very short list (fewer than 16 items) and each entry should
(ideally,
Index: gcc/config/darwin.h
===================================================================
--- gcc/config/darwin.h (revision 175628)
+++ gcc/config/darwin.h (working copy)
@@ -678,6 +678,9 @@ extern GTY(()) section * darwin_sections[NUM_DARWI
#undef TARGET_ASM_SELECT_SECTION
#define TARGET_ASM_SELECT_SECTION machopic_select_section
+#undef TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P
+#define TARGET_ASM_HANDLED_ASSEMBLE_VARIABLE_P
darwin_handled_assemble_variable_p
+
#undef TARGET_ASM_FUNCTION_SECTION
#define TARGET_ASM_FUNCTION_SECTION darwin_function_section