diff mbox

Fix objc/48109

Message ID 5E1A151C-9D63-463C-8E94-0A9F8BA9D217@sandoe-acoustics.co.uk
State New
Headers show

Commit Message

Iain Sandoe June 29, 2011, 5:47 p.m. UTC
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

Comments

Mike Stump June 29, 2011, 10:33 p.m. UTC | #1
On Jun 29, 2011, at 10:47 AM, Iain Sandoe wrote:
> 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.

> 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?

Ok for my parts.
Richard Biener June 30, 2011, 10:27 a.m. UTC | #2
On Wed, Jun 29, 2011 at 7:47 PM, Iain Sandoe
<developer@sandoe-acoustics.co.uk> wrote:
> 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?

Where does the target handle output of the variable?  If it is in the hook
then that hook is misnamed - it should then probably be called
assemble_variable.  Not sure if this is the most reasonable piece of
assemble_variable to split out to a hook though.

I'm not sure we want to backport this though (there isn't even a bugreport
about it?).

Thanks,
Richard.

> 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
>
>
>
>
Iain Sandoe June 30, 2011, 10:50 a.m. UTC | #3
On 30 Jun 2011, at 11:27, Richard Guenther wrote:

> On Wed, Jun 29, 2011 at 7:47 PM, Iain Sandoe
> <developer@sandoe-acoustics.co.uk> wrote:
>> 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?
>
> Where does the target handle output of the variable?  If it is in  
> the hook
> then that hook is misnamed - it should then probably be called
> assemble_variable.

It is in the hook,
hence named "handled_assemble_variable_p"
.. allowing us to test if the target has completed the work and finish  
assemble_variable () early.

Does that explain it better? - would an expanded comment help?

(I am happy to use any name generally agreed, but IMO the name should  
convey the idea that the result should be tested to determine if the  
target did the work, or it will be confusing to maintain).

> Not sure if this is the most reasonable piece of
> assemble_variable to split out to a hook though.

It is only used by darwin at present - so nothing is split out for any  
other target (the default hook is simply 'false').

Initially, I thought about simply moving the  
ASM_DECLARE_CLASS_REFERENCE and ASM_DECLARE_UNRESOLVED_REFERENCE to  
varasm.c

However, there seems to be a general move to use hooks instead of  
macros, and this seemed like a good time to make the change (and pave  
the way to remove those two macros from the tree).

If the consensus is a preference to retain the macros - I could re- 
work the patch to do that.

> I'm not sure we want to backport this though (there isn't even a  
> bugreport
> about it?).

PR48109, reported initially against 4.6.0 (before it forked);
... I guess it's also wrong code under LTO.

thanks
Iain

>
> Thanks,
> Richard.
>
>> 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
>>
>>
>>
>>
Richard Biener June 30, 2011, 10:56 a.m. UTC | #4
On Thu, Jun 30, 2011 at 12:50 PM, Iain Sandoe
<developer@sandoe-acoustics.co.uk> wrote:
>
> On 30 Jun 2011, at 11:27, Richard Guenther wrote:
>
>> On Wed, Jun 29, 2011 at 7:47 PM, Iain Sandoe
>> <developer@sandoe-acoustics.co.uk> wrote:
>>>
>>> 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?
>>
>> Where does the target handle output of the variable?  If it is in the hook
>> then that hook is misnamed - it should then probably be called
>> assemble_variable.
>
> It is in the hook,
> hence named "handled_assemble_variable_p"
> .. allowing us to test if the target has completed the work and finish
> assemble_variable () early.
>
> Does that explain it better? - would an expanded comment help?
>
> (I am happy to use any name generally agreed, but IMO the name should convey
> the idea that the result should be tested to determine if the target did the
> work, or it will be confusing to maintain).

Well, as it certainly isn't a predicate but is supposed to do the actual
work simply calling it assemble_variable is better.

>> Not sure if this is the most reasonable piece of
>> assemble_variable to split out to a hook though.
>
> It is only used by darwin at present - so nothing is split out for any other
> target (the default hook is simply 'false').

Yes, I've seen that.  Still a hook like this should be generally useful,
and you still process through some pieces of assemble_variable
while you choose to skip some other piece - it should probably be
documented which part of assemble_variable is supposed to be handled
by the hook.

I'll defer to Richard for this (and the approval).

> Initially, I thought about simply moving the ASM_DECLARE_CLASS_REFERENCE and
> ASM_DECLARE_UNRESOLVED_REFERENCE to varasm.c
>
> However, there seems to be a general move to use hooks instead of macros,
> and this seemed like a good time to make the change (and pave the way to
> remove those two macros from the tree).
>
> If the consensus is a preference to retain the macros - I could re-work the
> patch to do that.

No, a hook is definitely better.

>> I'm not sure we want to backport this though (there isn't even a bugreport
>> about it?).
>
> PR48109, reported initially against 4.6.0 (before it forked);
> ... I guess it's also wrong code under LTO.

So the ChangeLog should mention this PR.

Richard.

> thanks
> Iain
>
>>
>> Thanks,
>> Richard.
>>
>>> 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
>>>
>>>
>>>
>>>
>
>
Richard Henderson June 30, 2011, 3:12 p.m. UTC | #5
On 06/30/2011 03:56 AM, Richard Guenther wrote:
>> > It is only used by darwin at present - so nothing is split out for any other
>> > target (the default hook is simply 'false').
> Yes, I've seen that.  Still a hook like this should be generally useful,
> and you still process through some pieces of assemble_variable
> while you choose to skip some other piece - it should probably be
> documented which part of assemble_variable is supposed to be handled
> by the hook.
> 
> I'll defer to Richard for this (and the approval).
> 

I definitely want to see better documentation.  I don't know how to
review the patch at the moment.  Some background for us non-darwin
programmers would help as well; I don't know what's legal and what
isn't when it comes to these sorts of odd non-definitions.

You're changing the set of variables emitted for non-darwin here
too, as far as I can tell.  Is that actually desired?  I can't
imagine what these variables are intended to achieve, given that
they're byte sized and DECL_INITIAL = error_mark_node.

I can say that you need to watch the formatting.  There are missing
spaces after commas, and incorrect indentation.

> +  if (DECL_ATTRIBUTES (decl)
> +      && (meta = lookup_attribute ("OBJC1META", DECL_ATTRIBUTES (decl)))) 

Do not assign to variables inside if conditions.  No need to check
for DECL_ATTRIBUTES non-null before calling lookup_attribute.
Iain Sandoe June 30, 2011, 4:39 p.m. UTC | #6
Hi Richard(s),

thanks for the reviews.

before re-jigging - a couple of questions / points below.

On 30 Jun 2011, at 16:12, Richard Henderson wrote:

> On 06/30/2011 03:56 AM, Richard Guenther wrote:
>>>> It is only used by darwin at present - so nothing is split out  
>>>> for any other
>>>> target (the default hook is simply 'false').
>> Yes, I've seen that.  Still a hook like this should be generally  
>> useful,
>> and you still process through some pieces of assemble_variable
>> while you choose to skip some other piece - it should probably be
>> documented which part of assemble_variable is supposed to be handled
>> by the hook.

Yes, in order to avoid duplication of code, I placed the hook after  
all the set-up actions had been completed, but before any actual output.

Perhaps it would be better just to make the hook the first line of  
assemble_variable () and let the target take a (hopefully small) hit  
on replication of some of the actions of the varasm.c code.

Otherwise, noted about doc.

>> I'll defer to Richard for this (and the approval).

> I definitely want to see better documentation.  I don't know how to
> review the patch at the moment.  Some background for us non-darwin
> programmers would help as well; I don't know what's legal and what
> isn't when it comes to these sorts of odd non-definitions.

I guess, we new chaps assume you gurus know all... ;-) sorry...

An explanation here - as to what the hook is used for in this case.

I am not sure as to where the explanation needs to go (it doesn't seem  
appropriate for the hook, since that might be used for other purposes  
by other targets).

===

m32 Objective C (NeXT runtime) makes use of  anonymous meta-data,  
generated by the FE;
These data can be found by the runtime initialization - because they  
have a known organization and are placed in known sections.

However, because they are anonymous, there are no definitions or  
references to force the linker to include modules which only contain  
classes.

To cater for this, we have a class of symbols that are recognized by  
the darwin ld (ones beginning with ".objc_class_name_").  Satisfying  
linkage of these symbols is what ensures that appropriate modules are  
bound into the exe.

--

we arrange for the definitions to be emitted by asm like:

	.objc_class_name_MyClass = 0

.. and we arrange for the references to be generated by emitting:

	.lazy_reference .objc_class_name_MyClass

in neither case is any memory allocated for the entities represented.

In fact, one cannot allocate real memory and make a global  
objc_class_name_MyClass pointing to it - (which is essentially what  
GNU runtime does)  because, darwin's ld will recognize that it is not  
what's expected and fail (I tried that early on in seeking a solution)

The use of the hook is to allow us to generate 'real' variables for  
these items - and yet still intercept them and output the necessary asm.

That's the explanation - I think that it's present in darwin.c (in a  
shorter form) already.  I could expand on that and also replicate the  
discussion in objc-next-runtime-abi-01.c.

- would that be suitable?

> You're changing the set of variables emitted for non-darwin here
> too, as far as I can tell.  Is that actually desired?  I can't
> imagine what these variables are intended to achieve, given that
> they're byte sized and DECL_INITIAL = error_mark_node.

At present, non-NeXT targets (OK, that means non-mach-o as well,  
but..) the only real requirements are:

(a) that objc-next-runtime-abi-01.c should compile cleanly.
(b) that if someone invoked the function by some mistake elsewhere  
within ObjC, the result should be an error.

So, yes, if a non-darwin target were to call handle_next_impent () or  
handle_next_class_ref () the idea would be to cause a fail.
(perhaps there's a better way to do this - but it seemed reasonable at  
the time).

---

I'll address the other points as I re-jig.

thanks again,
Iain
diff mbox

Patch

===

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