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



Reply via email to