public inbox for binutils@sourceware.org
 help / color / mirror / Atom feed
* [Patch macho/bfd/gas] .indirect_symbol, take 2.
@ 2012-01-09 13:00 Iain Sandoe
  2012-01-10 13:03 ` Tristan Gingold
  0 siblings, 1 reply; 5+ messages in thread
From: Iain Sandoe @ 2012-01-09 13:00 UTC (permalink / raw)
  To: binutils Development; +Cc: Tristan Gingold

Here is a different implementation of the .indirect_symbol patch.

In this we keep indirect_symbols in a linked list in the section to  
which they belong.
As of now, I can't see a reason to keep them in GAS as well.

If this is OK, then a TODO would be to populate the list when a mach-o  
file is read in -
- this is nicely symmetrical -
- and means that sections can be reordered/removed without having to  
cross-check the dysymtab.

The only thing that is less satisfactory, is that there is no way  
(AFAICS) to mark a symbol as 'referenced by an indirect' which means  
if one deletes (or wishes to delete) symbols - then one should cross- 
check the usage from the indirect tables.

tests follow as separate patch (they've all be posted before anyway).

OK?
Iain

bfd:

	* mach-o.c (bfd_mach_o_count_indirect_symbols): New.
	(bfd_mach_o_build_dysymtab_command): Populate indirect table.
	* mach-o.h (bfd_mach_o_section): Add fields for indirect symbol
	lists.

gas:

	* config/obj-macho.c (obj_mach_o_set_symbol_qualifier): Switch off
	lazy for extern/private extern.
	(obj_mach_o_indirect_symbol): New.
	(obj_mach_o_placeholder): Remove.
	(mach_o_pseudo_table): Use obj_mach_o_indirect_symbol.
	(obj_macho_frob_label): Take care not to force local symbols into
	the regular table.
	(obj_macho_frob_symbol): Likewise.  Ensure undefined and comm syms
	have their fields set.
	(obj_mach_o_frob_section): New.
	* config/obj-macho.h (obj_frob_section): Define.
	(obj_mach_o_frob_section): Declare.

  bfd/mach-o.c           |   63 +++++++++++++-
  bfd/mach-o.h           |   16 ++++
  gas/config/obj-macho.c |  214 +++++++++++++++++++++++++++++++++++++++ 
++-------
  gas/config/obj-macho.h |    3 +
  4 files changed, 262 insertions(+), 34 deletions(-)

diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index a1f6596..493116a 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -2067,6 +2067,33 @@ bfd_mach_o_build_seg_command (const char  
*segment,
    return TRUE;
  }

+/* Count the number of indirect symbols in the image.
+   Requires that the sections are in their final order.  */
+
+static unsigned int
+bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct  
*mdata)
+{
+  unsigned int i;
+  unsigned int nisyms = 0;
+
+  for (i = 0; i < mdata->nsects; ++i)
+    {
+      bfd_mach_o_section *sec = mdata->sections[i];
+
+      switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	{
+	  case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_SYMBOL_STUBS:
+	    nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+	    break;
+	  default:
+	    break;
+	}
+    }
+  return nisyms;
+}
+
  static bfd_boolean
  bfd_mach_o_build_dysymtab_command (bfd *abfd,
  				   bfd_mach_o_data_struct *mdata,
@@ -2123,9 +2150,11 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
        dsym->nundefsym = 0;
      }

+  dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd,  
mdata);
    if (dsym->nindirectsyms > 0)
      {
        unsigned i;
+      unsigned n;

        mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
        dsym->indirectsymoff = mdata->filelen;
@@ -2134,11 +2163,37 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
        dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms *  
4);
        if (dsym->indirect_syms == NULL)
          return FALSE;
-
-      /* So fill in the indices.  */
-      for (i = 0; i < dsym->nindirectsyms; ++i)
+		
+      n = 0;
+      for (i = 0; i < mdata->nsects; ++i)
  	{
-	  /* TODO: fill in the table.  */
+	  bfd_mach_o_section *sec = mdata->sections[i];
+
+	  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	    {
+	      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_SYMBOL_STUBS:
+		{
+		  bfd_mach_o_indirect_sym *isym = sec->indirectsyms;
+		  if (isym == NULL)
+		    break;
+		  /* Record the starting index in the reserved1 field.  */
+		  sec->reserved1 = n;
+		  do
+		    {
+		      dsym->indirect_syms[n] = isym->sym->symbol.udata.i;
+		      n++;
+		      /* Final safety net.  */
+		      if (n > dsym->nindirectsyms)
+		        abort ();
+		    }
+		  while ((isym = isym->next) != NULL);
+		}
+		break;
+	      default:
+		break;
+	    }
  	}
      }

diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index ca810a0..31a4095 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -63,6 +63,12 @@ typedef struct bfd_mach_o_section

    /* Corresponding bfd section.  */
    asection *bfdsection;
+
+  /* Linked list of indirect symbols for this section (only applies to
+     stub and reference sections).  */
+  struct bfd_mach_o_indirect_sym *indirectsyms;
+  /* Pointer to the last indirect, to save reversing the list.  */
+  struct bfd_mach_o_indirect_sym *lastindirectsym;

    /* Simply linked list.  */
    struct bfd_mach_o_section *next;
@@ -117,6 +123,16 @@ typedef struct bfd_mach_o_asymbol
  }
  bfd_mach_o_asymbol;

+/* An element in a list of indirect symbols the root of which
+   is "indirectsyms" in the section to which they apply.  */
+
+typedef struct bfd_mach_o_indirect_sym
+{
+  struct bfd_mach_o_indirect_sym *next;
+  struct bfd_mach_o_asymbol *sym;
+}
+bfd_mach_o_indirect_sym;
+
  /* The symbol table is sorted like this:
   (1) local.
  	(otherwise in order of generation)
diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
index 43f4fba..5d82977 100644
--- a/gas/config/obj-macho.c
+++ b/gas/config/obj-macho.c
@@ -39,6 +39,7 @@

  #include "as.h"
  #include "subsegs.h"
+#include "struc-symbol.h" /* For local symbol stuff in frob_label/ 
symbol.  */
  #include "symbols.h"
  #include "write.h"
  #include "mach-o.h"
@@ -1032,6 +1033,7 @@ obj_mach_o_set_symbol_qualifier (symbolS *sym,  
int type)

        case OBJ_MACH_O_SYM_PRIV_EXT:
  	s->n_type |= BFD_MACH_O_N_PEXT ;
+	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
  	/* We follow the system tools in marking PEXT as also global.  */
  	/* Fall through.  */

@@ -1131,13 +1133,74 @@ obj_mach_o_sym_qual (int ntype)
    demand_empty_rest_of_line ();
  }

-/* Dummy function to allow test-code to work while we are working
-   on things.  */
-
  static void
-obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
+obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
  {
-  ignore_rest_of_line ();
+  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
+  unsigned lazy = 0;
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+        lazy = LAZY;
+        /* Fall through.  */
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+        {
+          bfd_mach_o_indirect_sym *isym;
+	  char *name = input_line_pointer;
+	  char c = get_symbol_end ();
+	  symbolS *sym = symbol_find_or_make (name);
+	  unsigned int elsize =
+			bfd_mach_o_section_get_entry_size (stdoutput, sec);
+
+	  if (elsize == 0)
+	    {
+	      as_bad (_("attempt to add an indirect_symbol to a stub or"
+			" reference section with a zero-sized element at %s"),
+			name);
+	      *input_line_pointer = c;
+	      ignore_rest_of_line ();
+	      return;
+	  }
+
+	  *input_line_pointer = c;
+
+	  /* This should be allocated in bfd, since it is owned there.  */
+	  isym = (bfd_mach_o_indirect_sym *)
+			bfd_zalloc (stdoutput, sizeof (bfd_mach_o_indirect_sym));
+	  if (isym == NULL)
+	    abort ();
+
+	  isym->sym = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sym);
+	  if (sec->indirectsyms == NULL)
+	    sec->indirectsyms = isym;
+	  else
+	    sec->lastindirectsym->next = isym;
+	  sec->lastindirectsym = isym;
+	
+	  /* We put in the lazy flag, it will get reset if the symbols is  
later
+	     defined, or if the symbol becomes private_extern.  */
+	  if (isym->sym->symbol.section == bfd_und_section_ptr
+	      && ! (isym->sym->n_type & BFD_MACH_O_N_PEXT))
+	    {
+	      isym->sym->n_desc = lazy;
+	      isym->sym->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
+	    }
+	}
+        break;
+
+      default:
+	as_bad (_("an .indirect_symbol must be in a symbol pointer"
+		  " or stub section."));
+	ignore_rest_of_line ();
+	return;
+    }
+  demand_empty_rest_of_line ();
  }

  const pseudo_typeS mach_o_pseudo_table[] =
@@ -1231,7 +1294,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
    {"no_dead_strip",	obj_mach_o_sym_qual,  
OBJ_MACH_O_SYM_NO_DEAD_STRIP},
    {"weak",		obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */

-  {"indirect_symbol",	obj_mach_o_placeholder, 0},
+  {"indirect_symbol",	obj_mach_o_indirect_symbol, 0},

    /* File flags.  */
    { "subsections_via_symbols", obj_mach_o_fileprop,
@@ -1270,15 +1333,33 @@ obj_mach_o_type_for_symbol (bfd_mach_o_asymbol  
*s)

  void obj_macho_frob_label (struct symbol *sp)
  {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym  
(sp);
-  /* This is the base symbol type, that we mask in.  */
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s- 
 >symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
    int sectype = -1;

+  /* Leave local symbols alone (unless they've already been made into  
a real
+     one).  */
+
+  if (0  && sp->bsym == NULL)
+    {
+      if (((struct local_symbol *) sp)->lsy_section != reg_section)
+	return;
+      else
+	/* We have a local which has been added to the symbol table, so carry
+	   on with the checking.  */
+	sp = ((struct local_symbol *) sp)->u.lsy_sym;
+    }
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
    if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return; /* Leave alone.  */
-
+    return;
+
+  /* This is the base symbol type, that we mask in.  */
+  base_type = obj_mach_o_type_for_symbol (s);
+
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
    if (sec != NULL)
      sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;

@@ -1307,34 +1388,50 @@ void obj_macho_frob_label (struct symbol *sp)
  int
  obj_macho_frob_symbol (struct symbol *sp)
  {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym  
(sp);
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s- 
 >symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
    int sectype = -1;
-
+
+  /* Leave local symbols alone (unless they've already been made into  
a real
+     one).  */
+
+  if (0 && sp->bsym == NULL)
+    {
+      if (((struct local_symbol *) sp)->lsy_section != reg_section)
+	return 0;
+      else
+	/* We have a local which has been added to the symbol table, so carry
+	   on with the checking.  */
+	sp = ((struct local_symbol *) sp)->u.lsy_sym;
+    }
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
+  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
+    return 0;
+
+  base_type = obj_mach_o_type_for_symbol (s);
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
    if (sec != NULL)
      sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;

-  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return 0; /* Leave alone.  */
-  else if (s->symbol.section == bfd_und_section_ptr)
+  if (s->symbol.section == bfd_und_section_ptr)
      {
        /* ??? Do we really gain much from implementing this as well  
as the
  	 mach-o specific ones?  */
        if (s->symbol.flags & BSF_WEAK)
  	s->n_desc |= BFD_MACH_O_N_WEAK_REF;

-      /* Undefined references, become extern.  */
-      if (s->n_desc & REFE)
-	{
-	  s->n_desc &= ~REFE;
-	  s->n_type |= BFD_MACH_O_N_EXT;
-	}
-
-      /* So do undefined 'no_dead_strip's.  */
-      if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
-	s->n_type |= BFD_MACH_O_N_EXT;
-
+      /* Undefined syms, become extern.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
+    }
+  else if (s->symbol.section == bfd_com_section_ptr)
+    {
+      /* ... so to comm.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
      }
    else
      {
@@ -1353,6 +1450,7 @@ obj_macho_frob_symbol (struct symbol *sp)
      {
        /* Anything here that should be added that is non-standard.  */
        s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
+      s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
      }
    else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
      {
@@ -1388,6 +1486,62 @@ obj_macho_frob_symbol (struct symbol *sp)
    return 0;
  }

+void
+obj_mach_o_frob_section (asection *sec)
+{
+  bfd_vma sect_size = bfd_section_size (stdoutput, sec);
+  bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
+
+  /* Process indirect symbols to determine if we have errors there.  */
+
+  switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	{
+	  unsigned int nactual;
+	  unsigned int ncalc;
+	  bfd_mach_o_indirect_sym *isym = ms->indirectsyms;
+	  unsigned long eltsiz =
+			bfd_mach_o_section_get_entry_size (stdoutput, ms);
+
+	  /* If we somehow added indirect symbols to a section with a zero
+	     entry size, we're dead ... */
+	  if (eltsiz == 0 && isym != NULL)
+	    abort ();
+
+	  ncalc = (unsigned int) (sect_size / eltsiz);
+
+	  nactual = 0;
+	  if (isym != NULL)
+	    do
+	      {
+	        /* Count it. */
+		nactual++;
+		if (isym->sym->symbol.section == bfd_und_section_ptr)
+		  {
+		    /* If the referenced symbol is undefined, make
+		       it extern.  */
+		    isym->sym->n_type |= BFD_MACH_O_N_EXT;
+		    isym->sym->symbol.flags |= BSF_GLOBAL;
+		  }
+	      }
+	    while ((isym = isym->next) != NULL);
+
+	  if (nactual != ncalc)
+	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
+		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,
+		      (nactual == 1)?" ":"s ", sec->name, ncalc,
+		      (ncalc == 1)?"is":"are");
+	}
+	break;
+
+      default:
+	break;
+    }
+}
+
  /* Support stabs for mach-o.  */

  void
diff --git a/gas/config/obj-macho.h b/gas/config/obj-macho.h
index cbc3a4f..ceb1097 100644
--- a/gas/config/obj-macho.h
+++ b/gas/config/obj-macho.h
@@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct symbol *);
  #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
  extern int obj_macho_frob_symbol (struct symbol *);

+#define obj_frob_section(s) obj_mach_o_frob_section(s)
+void obj_mach_o_frob_section (asection *);
+
  #define EMIT_SECTION_SYMBOLS		0

  #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)	 
obj_mach_o_process_stab(W,S,T,O,D)

	

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Patch macho/bfd/gas] .indirect_symbol, take 2.
  2012-01-09 13:00 [Patch macho/bfd/gas] .indirect_symbol, take 2 Iain Sandoe
@ 2012-01-10 13:03 ` Tristan Gingold
  2012-01-12  8:37   ` [Patch macho/bfd/gas] .indirect_symbol, take 3 Iain Sandoe
  0 siblings, 1 reply; 5+ messages in thread
From: Tristan Gingold @ 2012-01-10 13:03 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: binutils Development


On Jan 9, 2012, at 2:00 PM, Iain Sandoe wrote:

> Here is a different implementation of the .indirect_symbol patch.
> 
> In this we keep indirect_symbols in a linked list in the section to which they belong.

I don't think that linked list is the best choice.  The overhead is large (at least 2x), and the list structure is useful only for creating it (i.e. for gas).  I would prefer to have an array in BFD, and the linked list in GAS.

> As of now, I can't see a reason to keep them in GAS as well.
> 
> If this is OK, then a TODO would be to populate the list when a mach-o file is read in -
> - this is nicely symmetrical -
> - and means that sections can be reordered/removed without having to cross-check the dysymtab.
> 
> The only thing that is less satisfactory, is that there is no way (AFAICS) to mark a symbol as 'referenced by an indirect' which means if one deletes (or wishes to delete) symbols - then one should cross-check the usage from the indirect tables.

Yes, this is an issue.  I need to investigate how to address that.

> tests follow as separate patch (they've all be posted before anyway).

Thanks!

> OK?

See some additional comments.

Tristan.

> Iain
> 
> bfd:
> 
> 	* mach-o.c (bfd_mach_o_count_indirect_symbols): New.
> 	(bfd_mach_o_build_dysymtab_command): Populate indirect table.
> 	* mach-o.h (bfd_mach_o_section): Add fields for indirect symbol
> 	lists.
> 
> gas:
> 
> 	* config/obj-macho.c (obj_mach_o_set_symbol_qualifier): Switch off
> 	lazy for extern/private extern.
> 	(obj_mach_o_indirect_symbol): New.
> 	(obj_mach_o_placeholder): Remove.
> 	(mach_o_pseudo_table): Use obj_mach_o_indirect_symbol.
> 	(obj_macho_frob_label): Take care not to force local symbols into
> 	the regular table.
> 	(obj_macho_frob_symbol): Likewise.  Ensure undefined and comm syms
> 	have their fields set.
> 	(obj_mach_o_frob_section): New.
> 	* config/obj-macho.h (obj_frob_section): Define.
> 	(obj_mach_o_frob_section): Declare.
> 
> bfd/mach-o.c           |   63 +++++++++++++-
> bfd/mach-o.h           |   16 ++++
> gas/config/obj-macho.c |  214 +++++++++++++++++++++++++++++++++++++++++-------
> gas/config/obj-macho.h |    3 +
> 4 files changed, 262 insertions(+), 34 deletions(-)
> 
> diff --git a/bfd/mach-o.c b/bfd/mach-o.c
> index a1f6596..493116a 100644
> --- a/bfd/mach-o.c
> +++ b/bfd/mach-o.c
> @@ -2067,6 +2067,33 @@ bfd_mach_o_build_seg_command (const char *segment,
>   return TRUE;
> }
> 
> +/* Count the number of indirect symbols in the image.
> +   Requires that the sections are in their final order.  */
> +
> +static unsigned int
> +bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct *mdata)
> +{
> +  unsigned int i;
> +  unsigned int nisyms = 0;
> +
> +  for (i = 0; i < mdata->nsects; ++i)
> +    {
> +      bfd_mach_o_section *sec = mdata->sections[i];
> +
> +      switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +	{
> +	  case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	  case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +	  case BFD_MACH_O_S_SYMBOL_STUBS:
> +	    nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
> +	    break;
> +	  default:
> +	    break;
> +	}
> +    }
> +  return nisyms;
> +}
> +

ok.

> static bfd_boolean
> bfd_mach_o_build_dysymtab_command (bfd *abfd,
> 				   bfd_mach_o_data_struct *mdata,
> @@ -2123,9 +2150,11 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
>       dsym->nundefsym = 0;
>     }
> 
> +  dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd, mdata);
>   if (dsym->nindirectsyms > 0)
>     {
>       unsigned i;
> +      unsigned n;
> 
>       mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
>       dsym->indirectsymoff = mdata->filelen;
> @@ -2134,11 +2163,37 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
>       dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms * 4);
>       if (dsym->indirect_syms == NULL)
>         return FALSE;
> -
> -      /* So fill in the indices.  */
> -      for (i = 0; i < dsym->nindirectsyms; ++i)
> +		
> +      n = 0;
> +      for (i = 0; i < mdata->nsects; ++i)
> 	{
> -	  /* TODO: fill in the table.  */
> +	  bfd_mach_o_section *sec = mdata->sections[i];
> +
> +	  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +	    {
> +	      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +	      case BFD_MACH_O_S_SYMBOL_STUBS:
> +		{
> +		  bfd_mach_o_indirect_sym *isym = sec->indirectsyms;
> +		  if (isym == NULL)
> +		    break;
> +		  /* Record the starting index in the reserved1 field.  */
> +		  sec->reserved1 = n;
> +		  do
> +		    {
> +		      dsym->indirect_syms[n] = isym->sym->symbol.udata.i;
> +		      n++;
> +		      /* Final safety net.  */
> +		      if (n > dsym->nindirectsyms)
> +		        abort ();

Use bfd_assert instead.

Note that we should take care of local and absolute symbols.

> +		    }
> +		  while ((isym = isym->next) != NULL);
> +		}
> +		break;
> +	      default:
> +		break;
> +	    }
> 	}
>     }
> 
> diff --git a/bfd/mach-o.h b/bfd/mach-o.h
> index ca810a0..31a4095 100644
> --- a/bfd/mach-o.h
> +++ b/bfd/mach-o.h
> @@ -63,6 +63,12 @@ typedef struct bfd_mach_o_section
> 
>   /* Corresponding bfd section.  */
>   asection *bfdsection;
> +
> +  /* Linked list of indirect symbols for this section (only applies to
> +     stub and reference sections).  */
> +  struct bfd_mach_o_indirect_sym *indirectsyms;
> +  /* Pointer to the last indirect, to save reversing the list.  */
> +  struct bfd_mach_o_indirect_sym *lastindirectsym;
> 
>   /* Simply linked list.  */
>   struct bfd_mach_o_section *next;
> @@ -117,6 +123,16 @@ typedef struct bfd_mach_o_asymbol
> }
> bfd_mach_o_asymbol;
> 
> +/* An element in a list of indirect symbols the root of which
> +   is "indirectsyms" in the section to which they apply.  */
> +
> +typedef struct bfd_mach_o_indirect_sym
> +{
> +  struct bfd_mach_o_indirect_sym *next;
> +  struct bfd_mach_o_asymbol *sym;
> +}
> +bfd_mach_o_indirect_sym;
> +
> /* The symbol table is sorted like this:
>  (1) local.
> 	(otherwise in order of generation)
> diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
> index 43f4fba..5d82977 100644
> --- a/gas/config/obj-macho.c
> +++ b/gas/config/obj-macho.c
> @@ -39,6 +39,7 @@
> 
> #include "as.h"
> #include "subsegs.h"
> +#include "struc-symbol.h" /* For local symbol stuff in frob_label/symbol.  */
> #include "symbols.h"
> #include "write.h"
> #include "mach-o.h"
> @@ -1032,6 +1033,7 @@ obj_mach_o_set_symbol_qualifier (symbolS *sym, int type)
> 
>       case OBJ_MACH_O_SYM_PRIV_EXT:
> 	s->n_type |= BFD_MACH_O_N_PEXT ;
> +	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
> 	/* We follow the system tools in marking PEXT as also global.  */
> 	/* Fall through.  */

Unrelated chunk ?

> 
> @@ -1131,13 +1133,74 @@ obj_mach_o_sym_qual (int ntype)
>   demand_empty_rest_of_line ();
> }
> 
> -/* Dummy function to allow test-code to work while we are working
> -   on things.  */
> -
> static void
> -obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
> +obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
> {
> -  ignore_rest_of_line ();
> +  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
> +  unsigned lazy = 0;
> +
> +#ifdef md_flush_pending_output
> +  md_flush_pending_output ();
> +#endif
> +
> +  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +    {
> +      case BFD_MACH_O_S_SYMBOL_STUBS:
> +      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +        lazy = LAZY;
> +        /* Fall through.  */
> +      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +        {
> +          bfd_mach_o_indirect_sym *isym;
> +	  char *name = input_line_pointer;
> +	  char c = get_symbol_end ();
> +	  symbolS *sym = symbol_find_or_make (name);
> +	  unsigned int elsize =
> +			bfd_mach_o_section_get_entry_size (stdoutput, sec);
> +
> +	  if (elsize == 0)
> +	    {
> +	      as_bad (_("attempt to add an indirect_symbol to a stub or"
> +			" reference section with a zero-sized element at %s"),
> +			name);
> +	      *input_line_pointer = c;
> +	      ignore_rest_of_line ();
> +	      return;
> +	  }
> +
> +	  *input_line_pointer = c;
> +
> +	  /* This should be allocated in bfd, since it is owned there.  */
> +	  isym = (bfd_mach_o_indirect_sym *)
> +			bfd_zalloc (stdoutput, sizeof (bfd_mach_o_indirect_sym));
> +	  if (isym == NULL)
> +	    abort ();
> +
> +	  isym->sym = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sym);
> +	  if (sec->indirectsyms == NULL)
> +	    sec->indirectsyms = isym;
> +	  else
> +	    sec->lastindirectsym->next = isym;
> +	  sec->lastindirectsym = isym;
> +	
> +	  /* We put in the lazy flag, it will get reset if the symbols is later
> +	     defined, or if the symbol becomes private_extern.  */
> +	  if (isym->sym->symbol.section == bfd_und_section_ptr
> +	      && ! (isym->sym->n_type & BFD_MACH_O_N_PEXT))
> +	    {
> +	      isym->sym->n_desc = lazy;
> +	      isym->sym->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
> +	    }
> +	}
> +        break;
> +
> +      default:
> +	as_bad (_("an .indirect_symbol must be in a symbol pointer"
> +		  " or stub section."));
> +	ignore_rest_of_line ();
> +	return;
> +    }
> +  demand_empty_rest_of_line ();
> }
> 
> const pseudo_typeS mach_o_pseudo_table[] =
> @@ -1231,7 +1294,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
>   {"no_dead_strip",	obj_mach_o_sym_qual, OBJ_MACH_O_SYM_NO_DEAD_STRIP},
>   {"weak",		obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */
> 
> -  {"indirect_symbol",	obj_mach_o_placeholder, 0},
> +  {"indirect_symbol",	obj_mach_o_indirect_symbol, 0},
> 
>   /* File flags.  */
>   { "subsections_via_symbols", obj_mach_o_fileprop,
> @@ -1270,15 +1333,33 @@ obj_mach_o_type_for_symbol (bfd_mach_o_asymbol *s)
> 
> void obj_macho_frob_label (struct symbol *sp)
> {
> -  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> -  /* This is the base symbol type, that we mask in.  */
> -  unsigned base_type = obj_mach_o_type_for_symbol (s);
> -  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
> +  bfd_mach_o_asymbol *s;
> +  unsigned base_type;
> +  bfd_mach_o_section *sec;
>   int sectype = -1;
> 
> +  /* Leave local symbols alone (unless they've already been made into a real
> +     one).  */
> +
> +  if (0  && sp->bsym == NULL)
> +    {
> +      if (((struct local_symbol *) sp)->lsy_section != reg_section)
> +	return;
> +      else
> +	/* We have a local which has been added to the symbol table, so carry
> +	   on with the checking.  */
> +	sp = ((struct local_symbol *) sp)->u.lsy_sym;
> +    }

Don't let 'if (0)' code.
Please, use macro accessor instead of '((struct local_symbol *) sp)->lsy_section != reg_section'.

> +
> +  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> +  /* Leave debug symbols alone.  */
>   if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> -    return; /* Leave alone.  */
> -
> +    return;
> +
> +  /* This is the base symbol type, that we mask in.  */
> +  base_type = obj_mach_o_type_for_symbol (s);
> +
> +  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
>   if (sec != NULL)
>     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
> 
> @@ -1307,34 +1388,50 @@ void obj_macho_frob_label (struct symbol *sp)
> int
> obj_macho_frob_symbol (struct symbol *sp)
> {
> -  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> -  unsigned base_type = obj_mach_o_type_for_symbol (s);
> -  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
> +  bfd_mach_o_asymbol *s;
> +  unsigned base_type;
> +  bfd_mach_o_section *sec;
>   int sectype = -1;
> -
> +
> +  /* Leave local symbols alone (unless they've already been made into a real
> +     one).  */
> +
> +  if (0 && sp->bsym == NULL)
> +    {
> +      if (((struct local_symbol *) sp)->lsy_section != reg_section)
> +	return 0;
> +      else
> +	/* We have a local which has been added to the symbol table, so carry
> +	   on with the checking.  */
> +	sp = ((struct local_symbol *) sp)->u.lsy_sym;
> +    }

Likewise.

> +
> +  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> +  /* Leave debug symbols alone.  */
> +  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> +    return 0;
> +
> +  base_type = obj_mach_o_type_for_symbol (s);
> +  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
>   if (sec != NULL)
>     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
> 
> -  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> -    return 0; /* Leave alone.  */
> -  else if (s->symbol.section == bfd_und_section_ptr)
> +  if (s->symbol.section == bfd_und_section_ptr)
>     {
>       /* ??? Do we really gain much from implementing this as well as the
> 	 mach-o specific ones?  */
>       if (s->symbol.flags & BSF_WEAK)
> 	s->n_desc |= BFD_MACH_O_N_WEAK_REF;
> 
> -      /* Undefined references, become extern.  */
> -      if (s->n_desc & REFE)
> -	{
> -	  s->n_desc &= ~REFE;
> -	  s->n_type |= BFD_MACH_O_N_EXT;
> -	}
> -
> -      /* So do undefined 'no_dead_strip's.  */
> -      if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
> -	s->n_type |= BFD_MACH_O_N_EXT;
> -
> +      /* Undefined syms, become extern.  */
> +      s->n_type |= BFD_MACH_O_N_EXT;
> +      S_SET_EXTERNAL (sp);
> +    }
> +  else if (s->symbol.section == bfd_com_section_ptr)
> +    {
> +      /* ... so to comm.  */
> +      s->n_type |= BFD_MACH_O_N_EXT;
> +      S_SET_EXTERNAL (sp);
>     }
>   else
>     {
> @@ -1353,6 +1450,7 @@ obj_macho_frob_symbol (struct symbol *sp)
>     {
>       /* Anything here that should be added that is non-standard.  */
>       s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
> +      s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
>     }
>   else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
>     {
> @@ -1388,6 +1486,62 @@ obj_macho_frob_symbol (struct symbol *sp)
>   return 0;
> }
> 
> +void
> +obj_mach_o_frob_section (asection *sec)
> +{
> +  bfd_vma sect_size = bfd_section_size (stdoutput, sec);
> +  bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
> +
> +  /* Process indirect symbols to determine if we have errors there.  */
> +
> +  switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +    {
> +      case BFD_MACH_O_S_SYMBOL_STUBS:
> +      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	{
> +	  unsigned int nactual;
> +	  unsigned int ncalc;
> +	  bfd_mach_o_indirect_sym *isym = ms->indirectsyms;
> +	  unsigned long eltsiz =
> +			bfd_mach_o_section_get_entry_size (stdoutput, ms);
> +
> +	  /* If we somehow added indirect symbols to a section with a zero
> +	     entry size, we're dead ... */
> +	  if (eltsiz == 0 && isym != NULL)
> +	    abort ();

gas_assert.

> +
> +	  ncalc = (unsigned int) (sect_size / eltsiz);
> +
> +	  nactual = 0;
> +	  if (isym != NULL)
> +	    do
> +	      {
> +	        /* Count it. */
> +		nactual++;
> +		if (isym->sym->symbol.section == bfd_und_section_ptr)
> +		  {
> +		    /* If the referenced symbol is undefined, make
> +		       it extern.  */
> +		    isym->sym->n_type |= BFD_MACH_O_N_EXT;
> +		    isym->sym->symbol.flags |= BSF_GLOBAL;
> +		  }
> +	      }
> +	    while ((isym = isym->next) != NULL);
> +
> +	  if (nactual != ncalc)
> +	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
> +		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,

"is":"are" don't make sense with other languages !

> +		      (nactual == 1)?" ":"s ", sec->name, ncalc,
> +		      (ncalc == 1)?"is":"are");
> +	}
> +	break;
> +
> +      default:
> +	break;
> +    }
> +}
> +
> /* Support stabs for mach-o.  */
> 
> void
> diff --git a/gas/config/obj-macho.h b/gas/config/obj-macho.h
> index cbc3a4f..ceb1097 100644
> --- a/gas/config/obj-macho.h
> +++ b/gas/config/obj-macho.h
> @@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct symbol *);
> #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
> extern int obj_macho_frob_symbol (struct symbol *);
> 
> +#define obj_frob_section(s) obj_mach_o_frob_section(s)
> +void obj_mach_o_frob_section (asection *);
> +
> #define EMIT_SECTION_SYMBOLS		0
> 
> #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)	obj_mach_o_process_stab(W,S,T,O,D)

Tristan.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Patch macho/bfd/gas] .indirect_symbol, take 3.
  2012-01-10 13:03 ` Tristan Gingold
@ 2012-01-12  8:37   ` Iain Sandoe
  2012-01-12  8:49     ` Tristan Gingold
  0 siblings, 1 reply; 5+ messages in thread
From: Iain Sandoe @ 2012-01-12  8:37 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: binutils Development


On 10 Jan 2012, at 13:03, Tristan Gingold wrote:

>> Here is a different implementation of the .indirect_symbol patch.

V3 ;-)

>> In this we keep indirect_symbols in a linked list in the section to  
>> which they belong.
>
> I don't think that linked list is the best choice.  The overhead is  
> large (at least 2x), and the list structure is useful only for  
> creating it (i.e. for gas).  I would prefer to have an array in BFD,  
> and the linked list in GAS.

well, it's a bit like a balloon - push in one place and it pops out in  
another - this version is lighter in BFD, but heavier in GAS.

>> If this is OK, then a TODO would be to populate the list when a  
>> mach-o file is read in -
>> - this is nicely symmetrical -
>> - and means that sections can be reordered/removed without having  
>> to cross-check the dysymtab.
>>
>> The only thing that is less satisfactory, is that there is no way  
>> (AFAICS) to mark a symbol as 'referenced by an indirect' which  
>> means if one deletes (or wishes to delete) symbols - then one  
>> should cross-check the usage from the indirect tables.
>
> Yes, this is an issue.  I need to investigate how to address that.

I guess we could request a bit in the symbol flags...
>
> Use bfd_assert instead.
>
> Note that we should take care of local and absolute symbols.

I think locals are now done.. I will investigate ABS as a follow-on...
>>
>>      case OBJ_MACH_O_SYM_PRIV_EXT:
>> 	s->n_type |= BFD_MACH_O_N_PEXT ;
>> +	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
>> 	/* We follow the system tools in marking PEXT as also global.  */
>> 	/* Fall through.  */
>
> Unrelated chunk ?

no, symbol stubs and lazy pointer section symbols are, by default,  
lazy but this gets cancelled if they are defined (or local).

>>
>> +	  if (nactual != ncalc)
>> +	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
>> +		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,
>
> "is":"are" don't make sense with other languages !

... and in some languages plurals are indicated by additional words ...

Does this not get handled by the translation process?

I don't especially like grammatically incorrect error/warning messages..

If it is un-handled, what is the usual solution?

====

Naturally, the changelog needs some tweaking, but I trust that we can  
do this once we're agreed on the basic patch...

OK for this version?
Iain

  bfd/mach-o.c           |   64 +++++++++++-
  bfd/mach-o.h           |   34 ++++---
  gas/config/obj-macho.c |  257 +++++++++++++++++++++++++++++++++++++++ 
+++------
  gas/config/obj-macho.h |    3 +
  4 files changed, 310 insertions(+), 48 deletions(-)

diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 6913b1d..9511665 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -2079,6 +2079,33 @@ bfd_mach_o_build_seg_command (const char  
*segment,
    return TRUE;
  }

+/* Count the number of indirect symbols in the image.
+   Requires that the sections are in their final order.  */
+
+static unsigned int
+bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct  
*mdata)
+{
+  unsigned int i;
+  unsigned int nisyms = 0;
+
+  for (i = 0; i < mdata->nsects; ++i)
+    {
+      bfd_mach_o_section *sec = mdata->sections[i];
+
+      switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	{
+	  case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_SYMBOL_STUBS:
+	    nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+	    break;
+	  default:
+	    break;
+	}
+    }
+  return nisyms;
+}
+
  static bfd_boolean
  bfd_mach_o_build_dysymtab_command (bfd *abfd,
  				   bfd_mach_o_data_struct *mdata,
@@ -2135,9 +2162,11 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
        dsym->nundefsym = 0;
      }

+  dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd,  
mdata);
    if (dsym->nindirectsyms > 0)
      {
        unsigned i;
+      unsigned n;

        mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
        dsym->indirectsymoff = mdata->filelen;
@@ -2146,11 +2175,38 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
        dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms *  
4);
        if (dsym->indirect_syms == NULL)
          return FALSE;
-
-      /* So fill in the indices.  */
-      for (i = 0; i < dsym->nindirectsyms; ++i)
+		
+      n = 0;
+      for (i = 0; i < mdata->nsects; ++i)
  	{
-	  /* TODO: fill in the table.  */
+	  bfd_mach_o_section *sec = mdata->sections[i];
+
+	  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	    {
+	      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_SYMBOL_STUBS:
+		{
+		  unsigned j, num;
+		  bfd_mach_o_asymbol **isyms = sec->indirect_syms;
+		
+		  num = bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+		  if (isyms == NULL || num == 0)
+		    break;
+		  /* Record the starting index in the reserved1 field.  */
+		  sec->reserved1 = n;
+		  for (j = 0; j < num; j++, n++)
+		    {
+		      if (isyms[j] == NULL)
+		        dsym->indirect_syms[n] = 0x80000000;
+		      else
+		        dsym->indirect_syms[n] = isyms[j]->symbol.udata.i;
+		    }
+		}
+		break;
+	      default:
+		break;
+	    }
  	}
      }

diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index ca810a0..7f54961 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -42,6 +42,18 @@ typedef struct bfd_mach_o_header
  }
  bfd_mach_o_header;

+typedef struct bfd_mach_o_asymbol
+{
+  /* The actual symbol which the rest of BFD works with.  */
+  asymbol symbol;
+
+  /* Mach-O symbol fields.  */
+  unsigned char n_type;
+  unsigned char n_sect;
+  unsigned short n_desc;
+}
+bfd_mach_o_asymbol;
+
  #define BFD_MACH_O_SEGNAME_SIZE 16
  #define BFD_MACH_O_SECTNAME_SIZE 16

@@ -64,6 +76,12 @@ typedef struct bfd_mach_o_section
    /* Corresponding bfd section.  */
    asection *bfdsection;

+  /* An array holding the indirect symbols for this section.
+     NULL values indicate local symbols.
+     The number of symbols is determined from the section size and  
type.  */
+
+  bfd_mach_o_asymbol **indirect_syms;
+
    /* Simply linked list.  */
    struct bfd_mach_o_section *next;
  }
@@ -105,26 +123,12 @@ typedef struct bfd_mach_o_reloc_info
  }
  bfd_mach_o_reloc_info;

-typedef struct bfd_mach_o_asymbol
-{
-  /* The actual symbol which the rest of BFD works with.  */
-  asymbol symbol;
-
-  /* Mach-O symbol fields.  */
-  unsigned char n_type;
-  unsigned char n_sect;
-  unsigned short n_desc;
-}
-bfd_mach_o_asymbol;
-
  /* The symbol table is sorted like this:
   (1) local.
  	(otherwise in order of generation)
   (2) external defined
  	(sorted by name)
- (3) external undefined
-	(sorted by name)
- (4) common
+ (3) external undefined / common
  	(sorted by name)
  */

diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
index 43f4fba..cf94de5 100644
--- a/gas/config/obj-macho.c
+++ b/gas/config/obj-macho.c
@@ -1032,6 +1032,7 @@ obj_mach_o_set_symbol_qualifier (symbolS *sym,  
int type)

        case OBJ_MACH_O_SYM_PRIV_EXT:
  	s->n_type |= BFD_MACH_O_N_PEXT ;
+	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
  	/* We follow the system tools in marking PEXT as also global.  */
  	/* Fall through.  */

@@ -1131,13 +1132,79 @@ obj_mach_o_sym_qual (int ntype)
    demand_empty_rest_of_line ();
  }

-/* Dummy function to allow test-code to work while we are working
-   on things.  */
+typedef struct obj_mach_o_indirect_sym
+{
+  symbolS *sym;
+  segT sect;
+  struct obj_mach_o_indirect_sym *next;
+} obj_mach_o_indirect_sym;
+
+/* We store in order an maintain a pointer to the last one - to save  
reversing
+   later.  */
+obj_mach_o_indirect_sym *indirect_syms;
+obj_mach_o_indirect_sym *indirect_syms_tail;

  static void
-obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
+obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
  {
-  ignore_rest_of_line ();
+  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  if (obj_mach_o_is_static)
+    as_bad (_("use of .indirect_symbols requires `-dynamic'"));
+
+  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+        {
+          obj_mach_o_indirect_sym *isym;
+	  char *name = input_line_pointer;
+	  char c = get_symbol_end ();
+	  symbolS *sym = symbol_find_or_make (name);
+	  unsigned int elsize =
+			bfd_mach_o_section_get_entry_size (stdoutput, sec);
+
+	  if (elsize == 0)
+	    {
+	      as_bad (_("attempt to add an indirect_symbol to a stub or"
+			" reference section with a zero-sized element at %s"),
+			name);
+	      *input_line_pointer = c;
+	      ignore_rest_of_line ();
+	      return;
+	  }
+	  *input_line_pointer = c;
+
+	  isym = (obj_mach_o_indirect_sym *)
+			xmalloc (sizeof (obj_mach_o_indirect_sym));
+	  if (isym == NULL)
+	    abort ();
+
+	  /* Just record the data for now, we will validate it when we
+	     compute the output.  */
+	  isym->sym = sym;
+	  isym->sect = now_seg;
+	  isym->next = NULL;
+	  if (indirect_syms == NULL)
+	    indirect_syms = isym;
+	  else
+	    indirect_syms_tail->next = isym;
+	  indirect_syms_tail = isym;
+	}
+        break;
+
+      default:
+	as_bad (_("an .indirect_symbol must be in a symbol pointer"
+		  " or stub section."));
+	ignore_rest_of_line ();
+	return;
+    }
+  demand_empty_rest_of_line ();
  }

  const pseudo_typeS mach_o_pseudo_table[] =
@@ -1231,7 +1298,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
    {"no_dead_strip",	obj_mach_o_sym_qual,  
OBJ_MACH_O_SYM_NO_DEAD_STRIP},
    {"weak",		obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */

-  {"indirect_symbol",	obj_mach_o_placeholder, 0},
+  {"indirect_symbol",	obj_mach_o_indirect_symbol, 0},

    /* File flags.  */
    { "subsections_via_symbols", obj_mach_o_fileprop,
@@ -1270,15 +1337,25 @@ obj_mach_o_type_for_symbol (bfd_mach_o_asymbol  
*s)

  void obj_macho_frob_label (struct symbol *sp)
  {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym  
(sp);
-  /* This is the base symbol type, that we mask in.  */
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s- 
 >symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
    int sectype = -1;

+  /* Leave local symbols alone.  */
+
+  if (S_IS_LOCAL (sp))
+    return;
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
    if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return; /* Leave alone.  */
-
+    return;
+
+  /* This is the base symbol type, that we mask in.  */
+  base_type = obj_mach_o_type_for_symbol (s);
+
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
    if (sec != NULL)
      sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;

@@ -1307,34 +1384,41 @@ void obj_macho_frob_label (struct symbol *sp)
  int
  obj_macho_frob_symbol (struct symbol *sp)
  {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym  
(sp);
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s- 
 >symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
    int sectype = -1;
-
+
+  /* Leave local symbols alone.  */
+  if (S_IS_LOCAL (sp))
+    return 0;
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
+  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
+    return 0;
+
+  base_type = obj_mach_o_type_for_symbol (s);
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
    if (sec != NULL)
      sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;

-  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return 0; /* Leave alone.  */
-  else if (s->symbol.section == bfd_und_section_ptr)
+  if (s->symbol.section == bfd_und_section_ptr)
      {
        /* ??? Do we really gain much from implementing this as well  
as the
  	 mach-o specific ones?  */
        if (s->symbol.flags & BSF_WEAK)
  	s->n_desc |= BFD_MACH_O_N_WEAK_REF;

-      /* Undefined references, become extern.  */
-      if (s->n_desc & REFE)
-	{
-	  s->n_desc &= ~REFE;
-	  s->n_type |= BFD_MACH_O_N_EXT;
-	}
-
-      /* So do undefined 'no_dead_strip's.  */
-      if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
-	s->n_type |= BFD_MACH_O_N_EXT;
-
+      /* Undefined syms, become extern.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
+    }
+  else if (s->symbol.section == bfd_com_section_ptr)
+    {
+      /* ... so to comm.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
      }
    else
      {
@@ -1353,6 +1437,7 @@ obj_macho_frob_symbol (struct symbol *sp)
      {
        /* Anything here that should be added that is non-standard.  */
        s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
+      s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
      }
    else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
      {
@@ -1388,6 +1473,120 @@ obj_macho_frob_symbol (struct symbol *sp)
    return 0;
  }

+static void
+obj_mach_o_set_indirect_symbols (bfd *abfd, asection *sec,
+				 void *xxx ATTRIBUTE_UNUSED)
+{
+  bfd_vma sect_size = bfd_section_size (abfd, sec);
+  bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
+  unsigned lazy = 0;
+
+  /* See if we have any indirect syms to consider.  */
+  if (indirect_syms == NULL)
+    return;
+
+  /* Process indirect symbols to determine if we have errors there.  */
+
+  switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	lazy = LAZY;
+	/* Fall through.  */
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	{
+	  unsigned int nactual = 0;
+	  unsigned int ncalc;
+	  obj_mach_o_indirect_sym *isym;
+	  obj_mach_o_indirect_sym *list = NULL;
+	  obj_mach_o_indirect_sym *list_tail = NULL;
+	  unsigned long eltsiz =
+			bfd_mach_o_section_get_entry_size (abfd, ms);
+
+	  for (isym = indirect_syms; isym != NULL; isym = isym->next)
+	    {
+	      if (isym->sect == sec)
+		{
+		  nactual++;
+		  if (list == NULL)
+		    list = isym;
+		  else
+		    list_tail->next = isym;
+		  list_tail = isym;
+		}
+	    }
+
+	  /* If none are in this section, stop here.  */
+	  if (nactual == 0)
+	    break;
+
+	  /* If we somehow added indirect symbols to a section with a zero
+	     entry size, we're dead ... */
+	  gas_assert (eltsiz != 0);
+
+	  ncalc = (unsigned int) (sect_size / eltsiz);
+	  if (nactual != ncalc)
+	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
+		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,
+		      (nactual == 1)?" ":"s ", sec->name, ncalc,
+		      (ncalc == 1)?"is":"are");
+	  else
+	    {
+	      unsigned n;
+	      bfd_mach_o_asymbol *sym;
+	      ms->indirect_syms =
+			bfd_zalloc (abfd,
+				    nactual * sizeof (bfd_mach_o_asymbol *));
+
+	      gas_assert (ms->indirect_syms != NULL);
+	
+	      for (isym = list, n = 0; isym != NULL; isym = isym->next, n++)
+		{
+		  /* Array is init to NULL & NULL signals a local symbol
+		     If the section is lazy-bound, we need to keep the
+		     reference to the symbol, since dyld can override.  */
+		  if (S_IS_LOCAL (isym->sym) && ! lazy)
+		    ;
+		  else
+		    {
+		      sym = (bfd_mach_o_asymbol *)symbol_get_bfdsym (isym->sym);
+		      if (sym == NULL)
+		        ;
+		      /* If the symbols is external ...  */
+		      else if (S_IS_EXTERNAL (isym->sym)
+			       || (sym->n_type & BFD_MACH_O_N_EXT)
+			       || ! S_IS_DEFINED (isym->sym)
+			       || lazy)
+			{
+			  sym->n_desc &= ~LAZY;
+			  /* ... and can be lazy, if not defined or hidden.  */
+			  if ((sym->n_type & BFD_MACH_O_N_TYPE)
+			       == BFD_MACH_O_N_UNDF
+			      && ! (sym->n_type & BFD_MACH_O_N_PEXT)
+			      && (sym->n_type & BFD_MACH_O_N_EXT))
+			    sym->n_desc |= lazy;
+			  ms->indirect_syms[n] = sym;
+		        }
+		    }
+		}
+	    }
+	}
+	break;
+
+      default:
+	break;
+    }
+}
+
+/* The process of relocation could alter what's externally visible,  
thus we
+   leave setting the indirect symbols until last.  */
+
+void
+obj_mach_o_frob_file_after_relocs (void)
+{
+  bfd_map_over_sections (stdoutput, obj_mach_o_set_indirect_symbols,  
(char *) 0);
+}
+
  /* Support stabs for mach-o.  */

  void
diff --git a/gas/config/obj-macho.h b/gas/config/obj-macho.h
index cbc3a4f..9f1f3db 100644
--- a/gas/config/obj-macho.h
+++ b/gas/config/obj-macho.h
@@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct symbol *);
  #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
  extern int obj_macho_frob_symbol (struct symbol *);

+#define obj_frob_file_after_relocs obj_mach_o_frob_file_after_relocs
+extern void obj_mach_o_frob_file_after_relocs (void);
+
  #define EMIT_SECTION_SYMBOLS		0

  #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)	 
obj_mach_o_process_stab(W,S,T,O,D)

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Patch macho/bfd/gas] .indirect_symbol, take 3.
  2012-01-12  8:37   ` [Patch macho/bfd/gas] .indirect_symbol, take 3 Iain Sandoe
@ 2012-01-12  8:49     ` Tristan Gingold
  2012-01-12 14:24       ` Iain Sandoe
  0 siblings, 1 reply; 5+ messages in thread
From: Tristan Gingold @ 2012-01-12  8:49 UTC (permalink / raw)
  To: Iain Sandoe; +Cc: binutils Development


On Jan 12, 2012, at 9:36 AM, Iain Sandoe wrote:

> 
> On 10 Jan 2012, at 13:03, Tristan Gingold wrote:
> 
>>> Here is a different implementation of the .indirect_symbol patch.
> 
> V3 ;-)
> 
>>> In this we keep indirect_symbols in a linked list in the section to which they belong.
>> 
>> I don't think that linked list is the best choice.  The overhead is large (at least 2x), and the list structure is useful only for creating it (i.e. for gas).  I would prefer to have an array in BFD, and the linked list in GAS.
> 
> well, it's a bit like a balloon - push in one place and it pops out in another - this version is lighter in BFD, but heavier in GAS.

Sure, but there are many binaries linked with BFD that don't need a linked list!

>>> If this is OK, then a TODO would be to populate the list when a mach-o file is read in -
>>> - this is nicely symmetrical -
>>> - and means that sections can be reordered/removed without having to cross-check the dysymtab.
>>> 
>>> The only thing that is less satisfactory, is that there is no way (AFAICS) to mark a symbol as 'referenced by an indirect' which means if one deletes (or wishes to delete) symbols - then one should cross-check the usage from the indirect tables.
>> 
>> Yes, this is an issue.  I need to investigate how to address that.
> 
> I guess we could request a bit in the symbol flags...
>> 
>> Use bfd_assert instead.
>> 
>> Note that we should take care of local and absolute symbols.
> 
> I think locals are now done.. I will investigate ABS as a follow-on…

Ok.


>>> 
>>>     case OBJ_MACH_O_SYM_PRIV_EXT:
>>> 	s->n_type |= BFD_MACH_O_N_PEXT ;
>>> +	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
>>> 	/* We follow the system tools in marking PEXT as also global.  */
>>> 	/* Fall through.  */
>> 
>> Unrelated chunk ?
> 
> no, symbol stubs and lazy pointer section symbols are, by default, lazy but this gets cancelled if they are defined (or local).

ok.

>>> 
>>> +	  if (nactual != ncalc)
>>> +	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
>>> +		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,
>> 
>> "is":"are" don't make sense with other languages !
> 
> ... and in some languages plurals are indicated by additional words ...
> 
> Does this not get handled by the translation process?
> 
> I don't especially like grammatically incorrect error/warning messages..
> 
> If it is un-handled, what is the usual solution?

The best solution is rewording, such as "too few indirect_symbols in section %s (%d instead of %d)".
You know english better than me, so you could improve my wording.

> ====
> 
> Naturally, the changelog needs some tweaking, but I trust that we can do this once we're agreed on the basic patch...
> 
> OK for this version?
> Iain
> 
> bfd/mach-o.c           |   64 +++++++++++-
> bfd/mach-o.h           |   34 ++++---
> gas/config/obj-macho.c |  257 ++++++++++++++++++++++++++++++++++++++++++------
> gas/config/obj-macho.h |    3 +
> 4 files changed, 310 insertions(+), 48 deletions(-)
> 
> diff --git a/bfd/mach-o.c b/bfd/mach-o.c
> index 6913b1d..9511665 100644
> --- a/bfd/mach-o.c
> +++ b/bfd/mach-o.c
> @@ -2079,6 +2079,33 @@ bfd_mach_o_build_seg_command (const char *segment,
>   return TRUE;
> }
> 
> +/* Count the number of indirect symbols in the image.
> +   Requires that the sections are in their final order.  */
> +
> +static unsigned int
> +bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct *mdata)
> +{
> +  unsigned int i;
> +  unsigned int nisyms = 0;
> +
> +  for (i = 0; i < mdata->nsects; ++i)
> +    {
> +      bfd_mach_o_section *sec = mdata->sections[i];
> +
> +      switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +	{
> +	  case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	  case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +	  case BFD_MACH_O_S_SYMBOL_STUBS:
> +	    nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
> +	    break;
> +	  default:
> +	    break;
> +	}
> +    }
> +  return nisyms;
> +}
> +
> static bfd_boolean
> bfd_mach_o_build_dysymtab_command (bfd *abfd,
> 				   bfd_mach_o_data_struct *mdata,
> @@ -2135,9 +2162,11 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
>       dsym->nundefsym = 0;
>     }
> 
> +  dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd, mdata);
>   if (dsym->nindirectsyms > 0)
>     {
>       unsigned i;
> +      unsigned n;
> 
>       mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
>       dsym->indirectsymoff = mdata->filelen;
> @@ -2146,11 +2175,38 @@ bfd_mach_o_build_dysymtab_command (bfd *abfd,
>       dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms * 4);
>       if (dsym->indirect_syms == NULL)
>         return FALSE;
> -
> -      /* So fill in the indices.  */
> -      for (i = 0; i < dsym->nindirectsyms; ++i)
> +		
> +      n = 0;
> +      for (i = 0; i < mdata->nsects; ++i)
> 	{
> -	  /* TODO: fill in the table.  */
> +	  bfd_mach_o_section *sec = mdata->sections[i];
> +
> +	  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +	    {
> +	      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +	      case BFD_MACH_O_S_SYMBOL_STUBS:
> +		{
> +		  unsigned j, num;
> +		  bfd_mach_o_asymbol **isyms = sec->indirect_syms;
> +		
> +		  num = bfd_mach_o_section_get_nbr_indirect (abfd, sec);
> +		  if (isyms == NULL || num == 0)
> +		    break;
> +		  /* Record the starting index in the reserved1 field.  */
> +		  sec->reserved1 = n;
> +		  for (j = 0; j < num; j++, n++)
> +		    {
> +		      if (isyms[j] == NULL)
> +		        dsym->indirect_syms[n] = 0x80000000;

We need a constant for that (ok, not your fault).

> +		      else
> +		        dsym->indirect_syms[n] = isyms[j]->symbol.udata.i;
> +		    }
> +		}
> +		break;
> +	      default:
> +		break;
> +	    }
> 	}
>     }
> 
> diff --git a/bfd/mach-o.h b/bfd/mach-o.h
> index ca810a0..7f54961 100644
> --- a/bfd/mach-o.h
> +++ b/bfd/mach-o.h
> @@ -42,6 +42,18 @@ typedef struct bfd_mach_o_header
> }
> bfd_mach_o_header;
> 
> +typedef struct bfd_mach_o_asymbol
> +{
> +  /* The actual symbol which the rest of BFD works with.  */
> +  asymbol symbol;
> +
> +  /* Mach-O symbol fields.  */
> +  unsigned char n_type;
> +  unsigned char n_sect;
> +  unsigned short n_desc;
> +}
> +bfd_mach_o_asymbol;
> +
> #define BFD_MACH_O_SEGNAME_SIZE 16
> #define BFD_MACH_O_SECTNAME_SIZE 16
> 
> @@ -64,6 +76,12 @@ typedef struct bfd_mach_o_section
>   /* Corresponding bfd section.  */
>   asection *bfdsection;
> 
> +  /* An array holding the indirect symbols for this section.
> +     NULL values indicate local symbols.
> +     The number of symbols is determined from the section size and type.  */
> +
> +  bfd_mach_o_asymbol **indirect_syms;
> +
>   /* Simply linked list.  */
>   struct bfd_mach_o_section *next;
> }
> @@ -105,26 +123,12 @@ typedef struct bfd_mach_o_reloc_info
> }
> bfd_mach_o_reloc_info;
> 
> -typedef struct bfd_mach_o_asymbol
> -{
> -  /* The actual symbol which the rest of BFD works with.  */
> -  asymbol symbol;
> -
> -  /* Mach-O symbol fields.  */
> -  unsigned char n_type;
> -  unsigned char n_sect;
> -  unsigned short n_desc;
> -}
> -bfd_mach_o_asymbol;
> -
> /* The symbol table is sorted like this:
>  (1) local.
> 	(otherwise in order of generation)
>  (2) external defined
> 	(sorted by name)
> - (3) external undefined
> -	(sorted by name)
> - (4) common
> + (3) external undefined / common
> 	(sorted by name)
> */
> 
> diff --git a/gas/config/obj-macho.c b/gas/config/obj-macho.c
> index 43f4fba..cf94de5 100644
> --- a/gas/config/obj-macho.c
> +++ b/gas/config/obj-macho.c
> @@ -1032,6 +1032,7 @@ obj_mach_o_set_symbol_qualifier (symbolS *sym, int type)
> 
>       case OBJ_MACH_O_SYM_PRIV_EXT:
> 	s->n_type |= BFD_MACH_O_N_PEXT ;
> +	s->n_desc &= ~LAZY; /* The native tool swithes this off too.  */
> 	/* We follow the system tools in marking PEXT as also global.  */
> 	/* Fall through.  */
> 
> @@ -1131,13 +1132,79 @@ obj_mach_o_sym_qual (int ntype)
>   demand_empty_rest_of_line ();
> }
> 
> -/* Dummy function to allow test-code to work while we are working
> -   on things.  */
> +typedef struct obj_mach_o_indirect_sym
> +{
> +  symbolS *sym;
> +  segT sect;
> +  struct obj_mach_o_indirect_sym *next;
> +} obj_mach_o_indirect_sym;
> +
> +/* We store in order an maintain a pointer to the last one - to save reversing
> +   later.  */
> +obj_mach_o_indirect_sym *indirect_syms;
> +obj_mach_o_indirect_sym *indirect_syms_tail;
> 
> static void
> -obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
> +obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
> {
> -  ignore_rest_of_line ();
> +  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
> +
> +#ifdef md_flush_pending_output
> +  md_flush_pending_output ();
> +#endif
> +
> +  if (obj_mach_o_is_static)
> +    as_bad (_("use of .indirect_symbols requires `-dynamic'"));
> +
> +  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +    {
> +      case BFD_MACH_O_S_SYMBOL_STUBS:
> +      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +        {
> +          obj_mach_o_indirect_sym *isym;
> +	  char *name = input_line_pointer;
> +	  char c = get_symbol_end ();
> +	  symbolS *sym = symbol_find_or_make (name);
> +	  unsigned int elsize =
> +			bfd_mach_o_section_get_entry_size (stdoutput, sec);
> +
> +	  if (elsize == 0)
> +	    {
> +	      as_bad (_("attempt to add an indirect_symbol to a stub or"
> +			" reference section with a zero-sized element at %s"),
> +			name);
> +	      *input_line_pointer = c;
> +	      ignore_rest_of_line ();
> +	      return;
> +	  }
> +	  *input_line_pointer = c;
> +
> +	  isym = (obj_mach_o_indirect_sym *)
> +			xmalloc (sizeof (obj_mach_o_indirect_sym));
> +	  if (isym == NULL)
> +	    abort ();

xmalloc can't fail.

> +
> +	  /* Just record the data for now, we will validate it when we
> +	     compute the output.  */
> +	  isym->sym = sym;
> +	  isym->sect = now_seg;
> +	  isym->next = NULL;
> +	  if (indirect_syms == NULL)
> +	    indirect_syms = isym;
> +	  else
> +	    indirect_syms_tail->next = isym;
> +	  indirect_syms_tail = isym;
> +	}
> +        break;
> +
> +      default:
> +	as_bad (_("an .indirect_symbol must be in a symbol pointer"
> +		  " or stub section."));
> +	ignore_rest_of_line ();
> +	return;
> +    }
> +  demand_empty_rest_of_line ();
> }
> 
> const pseudo_typeS mach_o_pseudo_table[] =
> @@ -1231,7 +1298,7 @@ const pseudo_typeS mach_o_pseudo_table[] =
>   {"no_dead_strip",	obj_mach_o_sym_qual, OBJ_MACH_O_SYM_NO_DEAD_STRIP},
>   {"weak",		obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */
> 
> -  {"indirect_symbol",	obj_mach_o_placeholder, 0},
> +  {"indirect_symbol",	obj_mach_o_indirect_symbol, 0},
> 
>   /* File flags.  */
>   { "subsections_via_symbols", obj_mach_o_fileprop,
> @@ -1270,15 +1337,25 @@ obj_mach_o_type_for_symbol (bfd_mach_o_asymbol *s)
> 
> void obj_macho_frob_label (struct symbol *sp)
> {
> -  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> -  /* This is the base symbol type, that we mask in.  */
> -  unsigned base_type = obj_mach_o_type_for_symbol (s);
> -  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
> +  bfd_mach_o_asymbol *s;
> +  unsigned base_type;
> +  bfd_mach_o_section *sec;
>   int sectype = -1;
> 
> +  /* Leave local symbols alone.  */
> +
> +  if (S_IS_LOCAL (sp))
> +    return;
> +
> +  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> +  /* Leave debug symbols alone.  */
>   if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> -    return; /* Leave alone.  */
> -
> +    return;
> +
> +  /* This is the base symbol type, that we mask in.  */
> +  base_type = obj_mach_o_type_for_symbol (s);
> +
> +  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
>   if (sec != NULL)
>     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
> 
> @@ -1307,34 +1384,41 @@ void obj_macho_frob_label (struct symbol *sp)
> int
> obj_macho_frob_symbol (struct symbol *sp)
> {
> -  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> -  unsigned base_type = obj_mach_o_type_for_symbol (s);
> -  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
> +  bfd_mach_o_asymbol *s;
> +  unsigned base_type;
> +  bfd_mach_o_section *sec;
>   int sectype = -1;
> -
> +
> +  /* Leave local symbols alone.  */
> +  if (S_IS_LOCAL (sp))
> +    return 0;
> +
> +  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
> +  /* Leave debug symbols alone.  */
> +  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> +    return 0;
> +
> +  base_type = obj_mach_o_type_for_symbol (s);
> +  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
>   if (sec != NULL)
>     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
> 
> -  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
> -    return 0; /* Leave alone.  */
> -  else if (s->symbol.section == bfd_und_section_ptr)
> +  if (s->symbol.section == bfd_und_section_ptr)
>     {
>       /* ??? Do we really gain much from implementing this as well as the
> 	 mach-o specific ones?  */
>       if (s->symbol.flags & BSF_WEAK)
> 	s->n_desc |= BFD_MACH_O_N_WEAK_REF;
> 
> -      /* Undefined references, become extern.  */
> -      if (s->n_desc & REFE)
> -	{
> -	  s->n_desc &= ~REFE;
> -	  s->n_type |= BFD_MACH_O_N_EXT;
> -	}
> -
> -      /* So do undefined 'no_dead_strip's.  */
> -      if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
> -	s->n_type |= BFD_MACH_O_N_EXT;
> -
> +      /* Undefined syms, become extern.  */
> +      s->n_type |= BFD_MACH_O_N_EXT;
> +      S_SET_EXTERNAL (sp);
> +    }
> +  else if (s->symbol.section == bfd_com_section_ptr)
> +    {
> +      /* ... so to comm.  */
> +      s->n_type |= BFD_MACH_O_N_EXT;
> +      S_SET_EXTERNAL (sp);
>     }
>   else
>     {
> @@ -1353,6 +1437,7 @@ obj_macho_frob_symbol (struct symbol *sp)
>     {
>       /* Anything here that should be added that is non-standard.  */
>       s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
> +      s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
>     }
>   else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
>     {
> @@ -1388,6 +1473,120 @@ obj_macho_frob_symbol (struct symbol *sp)
>   return 0;
> }
> 
> +static void
> +obj_mach_o_set_indirect_symbols (bfd *abfd, asection *sec,
> +				 void *xxx ATTRIBUTE_UNUSED)
> +{
> +  bfd_vma sect_size = bfd_section_size (abfd, sec);
> +  bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
> +  unsigned lazy = 0;
> +
> +  /* See if we have any indirect syms to consider.  */
> +  if (indirect_syms == NULL)
> +    return;
> +
> +  /* Process indirect symbols to determine if we have errors there.  */
> +
> +  switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
> +    {
> +      case BFD_MACH_O_S_SYMBOL_STUBS:
> +      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
> +	lazy = LAZY;
> +	/* Fall through.  */
> +      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
> +	{
> +	  unsigned int nactual = 0;
> +	  unsigned int ncalc;
> +	  obj_mach_o_indirect_sym *isym;
> +	  obj_mach_o_indirect_sym *list = NULL;
> +	  obj_mach_o_indirect_sym *list_tail = NULL;
> +	  unsigned long eltsiz =
> +			bfd_mach_o_section_get_entry_size (abfd, ms);
> +
> +	  for (isym = indirect_syms; isym != NULL; isym = isym->next)
> +	    {
> +	      if (isym->sect == sec)
> +		{
> +		  nactual++;
> +		  if (list == NULL)
> +		    list = isym;
> +		  else
> +		    list_tail->next = isym;
> +		  list_tail = isym;
> +		}
> +	    }
> +
> +	  /* If none are in this section, stop here.  */
> +	  if (nactual == 0)
> +	    break;
> +
> +	  /* If we somehow added indirect symbols to a section with a zero
> +	     entry size, we're dead ... */
> +	  gas_assert (eltsiz != 0);
> +
> +	  ncalc = (unsigned int) (sect_size / eltsiz);
> +	  if (nactual != ncalc)
> +	    as_bad (_("there %s %d indirect_symbol%sin section %s but"
> +		      " %d %s expected"), (nactual == 1)?"is":"are", nactual,
> +		      (nactual == 1)?" ":"s ", sec->name, ncalc,
> +		      (ncalc == 1)?"is":"are");
> +	  else
> +	    {
> +	      unsigned n;
> +	      bfd_mach_o_asymbol *sym;
> +	      ms->indirect_syms =
> +			bfd_zalloc (abfd,
> +				    nactual * sizeof (bfd_mach_o_asymbol *));
> +
> +	      gas_assert (ms->indirect_syms != NULL);

But bfd_zalloc can, so you should do an explicit check (IMHO).

> +	
> +	      for (isym = list, n = 0; isym != NULL; isym = isym->next, n++)
> +		{
> +		  /* Array is init to NULL & NULL signals a local symbol
> +		     If the section is lazy-bound, we need to keep the
> +		     reference to the symbol, since dyld can override.  */
> +		  if (S_IS_LOCAL (isym->sym) && ! lazy)
> +		    ;
> +		  else
> +		    {
> +		      sym = (bfd_mach_o_asymbol *)symbol_get_bfdsym (isym->sym);
> +		      if (sym == NULL)
> +		        ;
> +		      /* If the symbols is external ...  */
> +		      else if (S_IS_EXTERNAL (isym->sym)
> +			       || (sym->n_type & BFD_MACH_O_N_EXT)
> +			       || ! S_IS_DEFINED (isym->sym)
> +			       || lazy)
> +			{
> +			  sym->n_desc &= ~LAZY;
> +			  /* ... and can be lazy, if not defined or hidden.  */
> +			  if ((sym->n_type & BFD_MACH_O_N_TYPE)
> +			       == BFD_MACH_O_N_UNDF
> +			      && ! (sym->n_type & BFD_MACH_O_N_PEXT)
> +			      && (sym->n_type & BFD_MACH_O_N_EXT))
> +			    sym->n_desc |= lazy;
> +			  ms->indirect_syms[n] = sym;
> +		        }
> +		    }
> +		}
> +	    }
> +	}
> +	break;
> +
> +      default:
> +	break;
> +    }
> +}
> +
> +/* The process of relocation could alter what's externally visible, thus we
> +   leave setting the indirect symbols until last.  */
> +
> +void
> +obj_mach_o_frob_file_after_relocs (void)
> +{
> +  bfd_map_over_sections (stdoutput, obj_mach_o_set_indirect_symbols, (char *) 0);
> +}
> +
> /* Support stabs for mach-o.  */
> 
> void
> diff --git a/gas/config/obj-macho.h b/gas/config/obj-macho.h
> index cbc3a4f..9f1f3db 100644
> --- a/gas/config/obj-macho.h
> +++ b/gas/config/obj-macho.h
> @@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct symbol *);
> #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
> extern int obj_macho_frob_symbol (struct symbol *);
> 
> +#define obj_frob_file_after_relocs obj_mach_o_frob_file_after_relocs
> +extern void obj_mach_o_frob_file_after_relocs (void);
> +
> #define EMIT_SECTION_SYMBOLS		0
> 
> #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)	obj_mach_o_process_stab(W,S,T,O,D)
> 

Ok with the suggested change, no need to resubmit.

Thank you for your perseverance!

Tristan.


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Patch macho/bfd/gas] .indirect_symbol, take 3.
  2012-01-12  8:49     ` Tristan Gingold
@ 2012-01-12 14:24       ` Iain Sandoe
  0 siblings, 0 replies; 5+ messages in thread
From: Iain Sandoe @ 2012-01-12 14:24 UTC (permalink / raw)
  To: Tristan Gingold; +Cc: binutils Development

[-- Attachment #1: Type: text/plain, Size: 420 bytes --]

Hi Tristan,

On 12 Jan 2012, at 08:49, Tristan Gingold wrote:
>>
>> +		      if (isyms[j] == NULL)
>> +		        dsym->indirect_syms[n] = 0x80000000;

> We need a constant for that (ok, not your fault).

me being impatient .. sorry, I've taken the liberty of adding a  
constant for this and ABS to loader.h

> Ok with the suggested change, no need to resubmit.

committed as attached, with the test-cases.
thanks
Iain


[-- Attachment #2: 12011214-indirect-code.txt --]
[-- Type: text/plain, Size: 17619 bytes --]

Index: bfd/ChangeLog
===================================================================
RCS file: /cvs/src/src/bfd/ChangeLog,v
retrieving revision 1.5584
diff -u -p -r1.5584 ChangeLog
--- bfd/ChangeLog	11 Jan 2012 15:24:09 -0000	1.5584
+++ bfd/ChangeLog	12 Jan 2012 13:59:41 -0000
@@ -1,3 +1,10 @@
+2012-01-12  Iain Sandoe  <idsandoe@googlemail.com>
+
+	* mach-o.c (bfd_mach_o_count_indirect_symbols): New.
+	(bfd_mach_o_build_dysymtab_command): Populate indirect symbol table.
+	* mach-o.h (bfd_mach_o_asymbol): Move declaration to start of the
+	file. (bfd_mach_o_section): Add indirect_syms field.
+
 2012-01-11  Iain Sandoe  <idsandoe@googlemail.com>
 
 	* mach-o.c (bfd_mach_o_build_seg_command): Separate computation of
Index: bfd/mach-o.c
===================================================================
RCS file: /cvs/src/src/bfd/mach-o.c,v
retrieving revision 1.95
diff -u -p -r1.95 mach-o.c
--- bfd/mach-o.c	11 Jan 2012 15:24:10 -0000	1.95
+++ bfd/mach-o.c	12 Jan 2012 13:59:45 -0000
@@ -2079,6 +2079,33 @@ bfd_mach_o_build_seg_command (const char
   return TRUE;
 }
 
+/* Count the number of indirect symbols in the image.
+   Requires that the sections are in their final order.  */
+
+static unsigned int
+bfd_mach_o_count_indirect_symbols (bfd *abfd, bfd_mach_o_data_struct *mdata)
+{
+  unsigned int i;
+  unsigned int nisyms = 0;
+
+  for (i = 0; i < mdata->nsects; ++i)
+    {
+      bfd_mach_o_section *sec = mdata->sections[i];
+
+      switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	{
+	  case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	  case BFD_MACH_O_S_SYMBOL_STUBS:
+	    nisyms += bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+	    break;
+	  default:
+	    break;
+	}
+    }
+  return nisyms;
+}
+
 static bfd_boolean
 bfd_mach_o_build_dysymtab_command (bfd *abfd,
 				   bfd_mach_o_data_struct *mdata,
@@ -2135,9 +2162,11 @@ bfd_mach_o_build_dysymtab_command (bfd *
       dsym->nundefsym = 0;
     }
 
+  dsym->nindirectsyms = bfd_mach_o_count_indirect_symbols (abfd, mdata);
   if (dsym->nindirectsyms > 0)
     {
       unsigned i;
+      unsigned n;
 
       mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
       dsym->indirectsymoff = mdata->filelen;
@@ -2146,11 +2175,38 @@ bfd_mach_o_build_dysymtab_command (bfd *
       dsym->indirect_syms = bfd_zalloc (abfd, dsym->nindirectsyms * 4);
       if (dsym->indirect_syms == NULL)
         return FALSE;
-      
-      /* So fill in the indices.  */
-      for (i = 0; i < dsym->nindirectsyms; ++i)
+		  
+      n = 0;
+      for (i = 0; i < mdata->nsects; ++i)
 	{
-	  /* TODO: fill in the table.  */
+	  bfd_mach_o_section *sec = mdata->sections[i];
+
+	  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+	    {
+	      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	      case BFD_MACH_O_S_SYMBOL_STUBS:
+		{
+		  unsigned j, num;
+		  bfd_mach_o_asymbol **isyms = sec->indirect_syms;
+		  
+		  num = bfd_mach_o_section_get_nbr_indirect (abfd, sec);
+		  if (isyms == NULL || num == 0)
+		    break;
+		  /* Record the starting index in the reserved1 field.  */
+		  sec->reserved1 = n;
+		  for (j = 0; j < num; j++, n++)
+		    {
+		      if (isyms[j] == NULL)
+		        dsym->indirect_syms[n] = BFD_MACH_O_INDIRECT_SYM_LOCAL;
+		      else
+		        dsym->indirect_syms[n] = isyms[j]->symbol.udata.i;
+		    }
+		}
+		break;
+	      default:
+		break;
+	    }
 	}
     }
 
Index: bfd/mach-o.h
===================================================================
RCS file: /cvs/src/src/bfd/mach-o.h,v
retrieving revision 1.41
diff -u -p -r1.41 mach-o.h
--- bfd/mach-o.h	9 Jan 2012 10:47:45 -0000	1.41
+++ bfd/mach-o.h	12 Jan 2012 13:59:45 -0000
@@ -42,6 +42,18 @@ typedef struct bfd_mach_o_header
 }
 bfd_mach_o_header;
 
+typedef struct bfd_mach_o_asymbol
+{
+  /* The actual symbol which the rest of BFD works with.  */
+  asymbol symbol;
+
+  /* Mach-O symbol fields.  */
+  unsigned char n_type;
+  unsigned char n_sect;
+  unsigned short n_desc;
+}
+bfd_mach_o_asymbol;
+
 #define BFD_MACH_O_SEGNAME_SIZE 16
 #define BFD_MACH_O_SECTNAME_SIZE 16
 
@@ -64,6 +76,12 @@ typedef struct bfd_mach_o_section
   /* Corresponding bfd section.  */
   asection *bfdsection;
 
+  /* An array holding the indirect symbols for this section.
+     NULL values indicate local symbols.
+     The number of symbols is determined from the section size and type.  */
+
+  bfd_mach_o_asymbol **indirect_syms;
+
   /* Simply linked list.  */
   struct bfd_mach_o_section *next;
 }
@@ -105,26 +123,12 @@ typedef struct bfd_mach_o_reloc_info
 }
 bfd_mach_o_reloc_info;
 
-typedef struct bfd_mach_o_asymbol
-{
-  /* The actual symbol which the rest of BFD works with.  */
-  asymbol symbol;
-
-  /* Mach-O symbol fields.  */
-  unsigned char n_type;
-  unsigned char n_sect;
-  unsigned short n_desc;
-}
-bfd_mach_o_asymbol;
-
 /* The symbol table is sorted like this:
  (1) local.
 	(otherwise in order of generation)
  (2) external defined
 	(sorted by name)
- (3) external undefined
-	(sorted by name)
- (4) common
+ (3) external undefined / common
 	(sorted by name)
 */
 
Index: gas/config/obj-macho.c
===================================================================
RCS file: /cvs/src/src/gas/config/obj-macho.c,v
retrieving revision 1.10
diff -u -p -r1.10 obj-macho.c
--- gas/config/obj-macho.c	9 Jan 2012 10:47:47 -0000	1.10
+++ gas/config/obj-macho.c	12 Jan 2012 13:59:57 -0000
@@ -1032,6 +1032,7 @@ obj_mach_o_set_symbol_qualifier (symbolS
 
       case OBJ_MACH_O_SYM_PRIV_EXT:
 	s->n_type |= BFD_MACH_O_N_PEXT ;
+	s->n_desc &= ~LAZY; /* The native tool switches this off too.  */
 	/* We follow the system tools in marking PEXT as also global.  */
 	/* Fall through.  */
 
@@ -1131,13 +1132,77 @@ obj_mach_o_sym_qual (int ntype)
   demand_empty_rest_of_line ();
 }
 
-/* Dummy function to allow test-code to work while we are working
-   on things.  */
+typedef struct obj_mach_o_indirect_sym
+{
+  symbolS *sym;
+  segT sect;
+  struct obj_mach_o_indirect_sym *next;
+} obj_mach_o_indirect_sym;
+
+/* We store in order an maintain a pointer to the last one - to save reversing
+   later.  */
+obj_mach_o_indirect_sym *indirect_syms;
+obj_mach_o_indirect_sym *indirect_syms_tail;
 
 static void
-obj_mach_o_placeholder (int arg ATTRIBUTE_UNUSED)
+obj_mach_o_indirect_symbol (int arg ATTRIBUTE_UNUSED)
 {
-  ignore_rest_of_line ();
+  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (now_seg);
+
+#ifdef md_flush_pending_output
+  md_flush_pending_output ();
+#endif
+
+  if (obj_mach_o_is_static)
+    as_bad (_("use of .indirect_symbols requires `-dynamic'"));
+
+  switch (sec->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+        {
+          obj_mach_o_indirect_sym *isym;
+	  char *name = input_line_pointer;
+	  char c = get_symbol_end ();
+	  symbolS *sym = symbol_find_or_make (name);
+	  unsigned int elsize =
+			bfd_mach_o_section_get_entry_size (stdoutput, sec);
+
+	  if (elsize == 0)
+	    {
+	      as_bad (_("attempt to add an indirect_symbol to a stub or"
+			" reference section with a zero-sized element at %s"),
+			name);
+	      *input_line_pointer = c;
+	      ignore_rest_of_line ();
+	      return;
+	  }
+	  *input_line_pointer = c;
+
+	  isym = (obj_mach_o_indirect_sym *)
+			xmalloc (sizeof (obj_mach_o_indirect_sym));
+
+	  /* Just record the data for now, we will validate it when we
+	     compute the output in obj_mach_o_set_indirect_symbols.  */
+	  isym->sym = sym;
+	  isym->sect = now_seg;
+	  isym->next = NULL;
+	  if (indirect_syms == NULL)
+	    indirect_syms = isym;
+	  else
+	    indirect_syms_tail->next = isym;
+	  indirect_syms_tail = isym;
+	}
+        break;
+
+      default:
+	as_bad (_("an .indirect_symbol must be in a symbol pointer"
+		  " or stub section."));
+	ignore_rest_of_line ();
+	return;
+    }
+  demand_empty_rest_of_line ();
 }
 
 const pseudo_typeS mach_o_pseudo_table[] =
@@ -1231,7 +1296,7 @@ const pseudo_typeS mach_o_pseudo_table[]
   {"no_dead_strip",	obj_mach_o_sym_qual, OBJ_MACH_O_SYM_NO_DEAD_STRIP},
   {"weak",		obj_mach_o_sym_qual, OBJ_MACH_O_SYM_WEAK}, /* ext */
 
-  {"indirect_symbol",	obj_mach_o_placeholder, 0},
+  { "indirect_symbol",	obj_mach_o_indirect_symbol, 0},
 
   /* File flags.  */
   { "subsections_via_symbols", obj_mach_o_fileprop, 
@@ -1270,15 +1335,25 @@ obj_mach_o_type_for_symbol (bfd_mach_o_a
 
 void obj_macho_frob_label (struct symbol *sp)
 {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
-  /* This is the base symbol type, that we mask in.  */
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
   int sectype = -1;
 
+  /* Leave local symbols alone.  */
+
+  if (S_IS_LOCAL (sp))
+    return;
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
   if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return; /* Leave alone.  */
-  
+    return;
+
+  /* This is the base symbol type, that we mask in.  */
+  base_type = obj_mach_o_type_for_symbol (s);
+
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);  
   if (sec != NULL)
     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
 
@@ -1307,34 +1382,41 @@ void obj_macho_frob_label (struct symbol
 int
 obj_macho_frob_symbol (struct symbol *sp)
 {
-  bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
-  unsigned base_type = obj_mach_o_type_for_symbol (s);
-  bfd_mach_o_section *sec = bfd_mach_o_get_mach_o_section (s->symbol.section);
+  bfd_mach_o_asymbol *s;
+  unsigned base_type;
+  bfd_mach_o_section *sec;
   int sectype = -1;
-  
+
+  /* Leave local symbols alone.  */
+  if (S_IS_LOCAL (sp))
+    return 0;
+
+  s = (bfd_mach_o_asymbol *) symbol_get_bfdsym (sp);
+  /* Leave debug symbols alone.  */
+  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
+    return 0;
+
+  base_type = obj_mach_o_type_for_symbol (s);
+  sec = bfd_mach_o_get_mach_o_section (s->symbol.section);  
   if (sec != NULL)
     sectype = sec->flags & BFD_MACH_O_SECTION_TYPE_MASK;
 
-  if ((s->n_type & BFD_MACH_O_N_STAB) != 0)
-    return 0; /* Leave alone.  */
-  else if (s->symbol.section == bfd_und_section_ptr)
+  if (s->symbol.section == bfd_und_section_ptr)
     {
       /* ??? Do we really gain much from implementing this as well as the
 	 mach-o specific ones?  */
       if (s->symbol.flags & BSF_WEAK)
 	s->n_desc |= BFD_MACH_O_N_WEAK_REF;
 
-      /* Undefined references, become extern.  */
-      if (s->n_desc & REFE)
-	{
-	  s->n_desc &= ~REFE;
-	  s->n_type |= BFD_MACH_O_N_EXT;
-	}
-
-      /* So do undefined 'no_dead_strip's.  */
-      if (s->n_desc & BFD_MACH_O_N_NO_DEAD_STRIP)
-	s->n_type |= BFD_MACH_O_N_EXT;
-
+      /* Undefined syms, become extern.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
+    }
+  else if (s->symbol.section == bfd_com_section_ptr)
+    {
+      /* ... so do comm.  */
+      s->n_type |= BFD_MACH_O_N_EXT;
+      S_SET_EXTERNAL (sp);
     }
   else
     {
@@ -1353,6 +1435,7 @@ obj_macho_frob_symbol (struct symbol *sp
     {
       /* Anything here that should be added that is non-standard.  */
       s->n_desc &= ~BFD_MACH_O_REFERENCE_MASK;
+      s->symbol.udata.i = SYM_MACHO_FIELDS_NOT_VALIDATED;
     }    
   else if (s->symbol.udata.i == SYM_MACHO_FIELDS_NOT_VALIDATED)
     {
@@ -1388,6 +1471,125 @@ obj_macho_frob_symbol (struct symbol *sp
   return 0;
 }
 
+static void
+obj_mach_o_set_indirect_symbols (bfd *abfd, asection *sec,
+				 void *xxx ATTRIBUTE_UNUSED)
+{
+  bfd_vma sect_size = bfd_section_size (abfd, sec);
+  bfd_mach_o_section *ms = bfd_mach_o_get_mach_o_section (sec);
+  unsigned lazy = 0;
+
+  /* See if we have any indirect syms to consider.  */
+  if (indirect_syms == NULL)
+    return;
+
+  /* Process indirect symbols.
+     Check for errors, if OK attach them as a flat array to the section
+     for which they are defined.  */
+
+  switch (ms->flags & BFD_MACH_O_SECTION_TYPE_MASK)
+    {
+      case BFD_MACH_O_S_SYMBOL_STUBS:
+      case BFD_MACH_O_S_LAZY_SYMBOL_POINTERS:
+	lazy = LAZY;
+	/* Fall through.  */
+      case BFD_MACH_O_S_NON_LAZY_SYMBOL_POINTERS:
+	{
+	  unsigned int nactual = 0;
+	  unsigned int ncalc;
+	  obj_mach_o_indirect_sym *isym;
+	  obj_mach_o_indirect_sym *list = NULL;
+	  obj_mach_o_indirect_sym *list_tail = NULL;
+	  unsigned long eltsiz = 
+			bfd_mach_o_section_get_entry_size (abfd, ms);
+
+	  for (isym = indirect_syms; isym != NULL; isym = isym->next)
+	    {
+	      if (isym->sect == sec)
+		{
+		  nactual++;
+		  if (list == NULL)
+		    list = isym;
+		  else
+		    list_tail->next = isym;
+		  list_tail = isym;
+		}
+	    }
+
+	  /* If none are in this section, stop here.  */
+	  if (nactual == 0)
+	    break;
+
+	  /* If we somehow added indirect symbols to a section with a zero
+	     entry size, we're dead ... */
+	  gas_assert (eltsiz != 0);
+
+	  ncalc = (unsigned int) (sect_size / eltsiz);
+	  if (nactual != ncalc)
+	    as_bad (_("the number of .indirect_symbols defined in section %s"
+		      " does not match the number expected (%d defined, %d"
+		      " expected)"), sec->name, nactual, ncalc);
+	  else
+	    {
+	      unsigned n;
+	      bfd_mach_o_asymbol *sym;
+	      ms->indirect_syms =
+			bfd_zalloc (abfd,
+				    nactual * sizeof (bfd_mach_o_asymbol *));
+
+	      if (ms->indirect_syms == NULL)
+		{
+		  as_fatal (_("internal error: failed to allocate %d indirect"
+			      "symbol pointers"), nactual);
+		}
+	      
+	      for (isym = list, n = 0; isym != NULL; isym = isym->next, n++)
+		{
+		  /* Array is init to NULL & NULL signals a local symbol
+		     If the section is lazy-bound, we need to keep the
+		     reference to the symbol, since dyld can override.  */
+		  if (S_IS_LOCAL (isym->sym) && ! lazy)
+		    ;
+		  else
+		    {
+		      sym = (bfd_mach_o_asymbol *)symbol_get_bfdsym (isym->sym);
+		      if (sym == NULL)
+		        ;
+		      /* If the symbols is external ...  */
+		      else if (S_IS_EXTERNAL (isym->sym)
+			       || (sym->n_type & BFD_MACH_O_N_EXT)
+			       || ! S_IS_DEFINED (isym->sym)
+			       || lazy)
+			{
+			  sym->n_desc &= ~LAZY;
+			  /* ... it can be lazy, if not defined or hidden.  */
+			  if ((sym->n_type & BFD_MACH_O_N_TYPE) 
+			       == BFD_MACH_O_N_UNDF 
+			      && ! (sym->n_type & BFD_MACH_O_N_PEXT)
+			      && (sym->n_type & BFD_MACH_O_N_EXT))
+			    sym->n_desc |= lazy;
+			  ms->indirect_syms[n] = sym;
+		        }
+		    }
+		}
+	    }
+	}
+	break;
+
+      default:
+	break;
+    }
+}
+
+/* The process of relocation could alter what's externally visible, thus we
+   leave setting the indirect symbols until last.  */
+
+void
+obj_mach_o_frob_file_after_relocs (void)
+{
+  bfd_map_over_sections (stdoutput, obj_mach_o_set_indirect_symbols, (char *) 0);
+}
+
 /* Support stabs for mach-o.  */
 
 void
Index: gas/config/obj-macho.h
===================================================================
RCS file: /cvs/src/src/gas/config/obj-macho.h,v
retrieving revision 1.5
diff -u -p -r1.5 obj-macho.h
--- gas/config/obj-macho.h	9 Jan 2012 10:47:47 -0000	1.5
+++ gas/config/obj-macho.h	12 Jan 2012 14:00:04 -0000
@@ -62,6 +62,9 @@ extern void obj_macho_frob_label (struct
 #define obj_frob_symbol(s, punt) punt = obj_macho_frob_symbol(s)
 extern int obj_macho_frob_symbol (struct symbol *);
 
+#define obj_frob_file_after_relocs obj_mach_o_frob_file_after_relocs
+extern void obj_mach_o_frob_file_after_relocs (void);
+
 #define EMIT_SECTION_SYMBOLS		0
 
 #define OBJ_PROCESS_STAB(SEG,W,S,T,O,D)	obj_mach_o_process_stab(W,S,T,O,D)
Index: include/mach-o/ChangeLog
===================================================================
RCS file: /cvs/src/src/include/mach-o/ChangeLog,v
retrieving revision 1.7
diff -u -p -r1.7 ChangeLog
--- include/mach-o/ChangeLog	4 Jan 2012 10:37:36 -0000	1.7
+++ include/mach-o/ChangeLog	12 Jan 2012 14:00:04 -0000
@@ -1,3 +1,8 @@
+2012-01-12  Iain Sandoe  <idsandoe@googlemail.com>
+
+	* loader.h (BFD_MACH_O_INDIRECT_SYM_LOCAL): New.
+	(BFD_MACH_O_INDIRECT_SYM_ABS): New
+
 2012-01-04  Tristan Gingold  <gingold@adacore.com>
 
 	* external.h (mach_o_fvmlib_command_external): New structure.
Index: include/mach-o/loader.h
===================================================================
RCS file: /cvs/src/src/include/mach-o/loader.h,v
retrieving revision 1.5
diff -u -p -r1.5 loader.h
--- include/mach-o/loader.h	4 Jan 2012 10:25:14 -0000	1.5
+++ include/mach-o/loader.h	12 Jan 2012 14:00:04 -0000
@@ -320,6 +320,9 @@ bfd_mach_o_section_attribute;
 #define BFD_MACH_O_N_NO_DEAD_STRIP				0x20
 #define BFD_MACH_O_N_WEAK_REF					0x40
 #define BFD_MACH_O_N_WEAK_DEF					0x80
+
+#define BFD_MACH_O_INDIRECT_SYM_LOCAL			0x80000000
+#define BFD_MACH_O_INDIRECT_SYM_ABS			0x40000000
 \f
 /* Thread constants.  */
 

[-- Attachment #3: Type: text/plain, Size: 1 bytes --]



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2012-01-12 14:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-09 13:00 [Patch macho/bfd/gas] .indirect_symbol, take 2 Iain Sandoe
2012-01-10 13:03 ` Tristan Gingold
2012-01-12  8:37   ` [Patch macho/bfd/gas] .indirect_symbol, take 3 Iain Sandoe
2012-01-12  8:49     ` Tristan Gingold
2012-01-12 14:24       ` Iain Sandoe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).