add dysymtab write support to bfd/mach-o.
authorIain Sandoe <iain@codesourcery.com>
Tue, 3 Jan 2012 10:54:01 +0000 (10:54 +0000)
committerIain Sandoe <iain@codesourcery.com>
Tue, 3 Jan 2012 10:54:01 +0000 (10:54 +0000)
bfd:

* mach-o.c (bfd_mach_o_write_symtab): Fill in the string table index
as the value of an indirect symbol.  Keep the string table index in
non-indirect syms for reference.
(bfd_mach_o_write_dysymtab): New.
(bfd_mach_o_primary_symbol_sort_key): New.
(bfd_mach_o_cf_symbols): New.
(bfd_mach_o_sort_symbol_table): New.
(bfd_mach_o_mangle_symbols): Return early if no symbols.  Sort symbols.
If we are emitting a dysymtab, process indirect symbols and count the
number of each other kind.
(bfd_mach_o_mangle_sections): New.
(bfd_mach_o_write_contents): Split out some pre-requisite code into
the command builder. Write dysymtab if the command is present.
(bfd_mach_o_count_sections_for_seg): New.
(bfd_mach_o_build_seg_command): New.
(bfd_mach_o_build_dysymtab_command): New.
(bfd_mach_o_build_commands): Reorganize to support the fact that some
commands are optional and should not be emitted if there are no
sections or symbols.
(bfd_mach_o_set_section_contents): Amend comment.
* mach-o.h: Amend and add to comments.
(mach_o_data_struct): Add fields for dysymtab symbols counts and a
pointer to the indirects, when present.
(bfd_mach_o_should_emit_dysymtab): New macro.
(IS_MACHO_INDIRECT): Likewise.

gas/testsuite:

* gas/mach-o/dysymtab-1-64.d: New.
* gas/mach-o/dysymtab-1.d: New.
* gas/mach-o/symbols-1-64.d: New.
* gas/mach-o/symbols-1.d: New.
* gas/mach-o/symbols-base-64.s: New.
* gas/mach-o/symbols-base.s: New.

bfd/ChangeLog
bfd/mach-o.c
bfd/mach-o.h
gas/testsuite/ChangeLog
gas/testsuite/gas/mach-o/dysymtab-1-64.d [new file with mode: 0644]
gas/testsuite/gas/mach-o/dysymtab-1.d [new file with mode: 0644]
gas/testsuite/gas/mach-o/symbols-1-64.d [new file with mode: 0644]
gas/testsuite/gas/mach-o/symbols-1.d [new file with mode: 0644]
gas/testsuite/gas/mach-o/symbols-base-64.s [new file with mode: 0644]
gas/testsuite/gas/mach-o/symbols-base.s [new file with mode: 0644]

index 9af9565..7406ddd 100644 (file)
@@ -1,3 +1,31 @@
+2012-01-03  Iain Sandoe  <idsandoe@googlemail.com>
+
+       * mach-o.c (bfd_mach_o_write_symtab): Fill in the string table index
+       as the value of an indirect symbol.  Keep the string table index in
+       non-indirect syms for reference.
+       (bfd_mach_o_write_dysymtab): New.
+       (bfd_mach_o_primary_symbol_sort_key): New.
+       (bfd_mach_o_cf_symbols): New.
+       (bfd_mach_o_sort_symbol_table): New.
+       (bfd_mach_o_mangle_symbols): Return early if no symbols.  Sort symbols.
+       If we are emitting a dysymtab, process indirect symbols and count the
+       number of each other kind.
+       (bfd_mach_o_mangle_sections): New.
+       (bfd_mach_o_write_contents): Split out some pre-requisite code into
+       the command builder. Write dysymtab if the command is present.
+       (bfd_mach_o_count_sections_for_seg): New.
+       (bfd_mach_o_build_seg_command): New.
+       (bfd_mach_o_build_dysymtab_command): New.
+       (bfd_mach_o_build_commands): Reorganize to support the fact that some
+       commands are optional and should not be emitted if there are no
+       sections or symbols.
+       (bfd_mach_o_set_section_contents): Amend comment.
+       * mach-o.h: Amend and add to comments. 
+       (mach_o_data_struct): Add fields for dysymtab symbols counts and a
+       pointer to the indirects, when present.
+       (bfd_mach_o_should_emit_dysymtab): New macro.
+       (IS_MACHO_INDIRECT): Likewise.
+
 2011-12-24  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        * elf32-rl78.c (rl78_elf_relocate_section, rl78_dump_symtab)
index cc68d89..b2c4dff 100644 (file)
@@ -1,6 +1,6 @@
 /* Mach-O support for BFD.
    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-   2009, 2010, 2011
+   2009, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -29,6 +29,8 @@
 #include "mach-o/reloc.h"
 #include "mach-o/external.h"
 #include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
 
 #define bfd_mach_o_object_p bfd_mach_o_gen_object_p
 #define bfd_mach_o_core_p bfd_mach_o_gen_core_p
@@ -1351,13 +1353,34 @@ bfd_mach_o_write_symtab (bfd *abfd, bfd_mach_o_load_command *command)
       bfd_size_type str_index;
       bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
 
-      /* Compute name index.  */
-      /* An index of 0 always means the empty string.  */
+      /* For a bare indirect symbol, the system tools expect that the symbol
+        value will be the string table offset for its referenced counterpart.
+        
+        Normally, indirect syms will not be written this way, but rather as
+        part of the dysymtab command.
+        
+        In either case, correct operation depends on the symbol table being
+        sorted such that the indirect symbols are at the end (since the 
+        string table index is filled in below).  */
+
+      if (IS_MACHO_INDIRECT (s->n_type))
+       /* A pointer to the referenced symbol will be stored in the udata
+          field.  Use that to find the string index.  */
+       s->symbol.value = 
+           ((bfd_mach_o_asymbol *)s->symbol.udata.p)->symbol.udata.i;
+     
       if (s->symbol.name == 0 || s->symbol.name[0] == '\0')
+       /* An index of 0 always means the empty string.  */
         str_index = 0;
       else
         {
           str_index = _bfd_stringtab_add (strtab, s->symbol.name, TRUE, FALSE);
+          /* Record the string index.  This can be looked up by an indirect sym
+            which retains a pointer to its referenced counterpart, until it is
+            actually output.  */
+         if (IS_MACHO_INDIRECT (s->n_type))
+           s->symbol.udata.i = str_index;
+
           if (str_index == (bfd_size_type) -1)
             goto err;
         }
@@ -1420,15 +1443,316 @@ bfd_mach_o_write_symtab (bfd *abfd, bfd_mach_o_load_command *command)
   return FALSE;
 }
 
-/* Process the symbols and generate Mach-O specific fields.
-   Number them.  */
+/* Write a dysymtab command.
+   TODO: Possibly coalesce writes of smaller objects.  */
+
+static bfd_boolean
+bfd_mach_o_write_dysymtab (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  bfd_mach_o_dysymtab_command *cmd = &command->command.dysymtab;
+
+  BFD_ASSERT (command->type == BFD_MACH_O_LC_DYSYMTAB);
+
+  if (cmd->nmodtab != 0)
+    {
+      unsigned int i;
+
+      if (bfd_seek (abfd, cmd->modtaboff, SEEK_SET) != 0)
+       return FALSE;
+
+      for (i = 0; i < cmd->nmodtab; i++)
+       {
+         bfd_mach_o_dylib_module *module = &cmd->dylib_module[i];
+         unsigned int iinit;
+         unsigned int ninit;
+
+         iinit = module->iinit & 0xffff;
+         iinit |= ((module->iterm & 0xffff) << 16);
+
+         ninit = module->ninit & 0xffff;
+         ninit |= ((module->nterm & 0xffff) << 16);
+
+         if (bfd_mach_o_wide_p (abfd))
+           {
+             struct mach_o_dylib_module_64_external w;
+
+             bfd_h_put_32 (abfd, module->module_name_idx, &w.module_name);
+             bfd_h_put_32 (abfd, module->iextdefsym, &w.iextdefsym);
+             bfd_h_put_32 (abfd, module->nextdefsym, &w.nextdefsym);
+             bfd_h_put_32 (abfd, module->irefsym, &w.irefsym);
+             bfd_h_put_32 (abfd, module->nrefsym, &w.nrefsym);
+             bfd_h_put_32 (abfd, module->ilocalsym, &w.ilocalsym);
+             bfd_h_put_32 (abfd, module->nlocalsym, &w.nlocalsym);
+             bfd_h_put_32 (abfd, module->iextrel, &w.iextrel);
+             bfd_h_put_32 (abfd, module->nextrel, &w.nextrel);
+             bfd_h_put_32 (abfd, iinit, &w.iinit_iterm);
+             bfd_h_put_32 (abfd, ninit, &w.ninit_nterm);
+             bfd_h_put_64 (abfd, module->objc_module_info_addr,
+                           &w.objc_module_info_addr);
+             bfd_h_put_32 (abfd, module->objc_module_info_size,
+                           &w.objc_module_info_size);
+
+             if (bfd_bwrite ((void *) &w, sizeof (w), abfd) != sizeof (w))
+               return FALSE;
+           }
+         else
+           {
+             struct mach_o_dylib_module_external n;
+
+             bfd_h_put_32 (abfd, module->module_name_idx, &n.module_name);
+             bfd_h_put_32 (abfd, module->iextdefsym, &n.iextdefsym);
+             bfd_h_put_32 (abfd, module->nextdefsym, &n.nextdefsym);
+             bfd_h_put_32 (abfd, module->irefsym, &n.irefsym);
+             bfd_h_put_32 (abfd, module->nrefsym, &n.nrefsym);
+             bfd_h_put_32 (abfd, module->ilocalsym, &n.ilocalsym);
+             bfd_h_put_32 (abfd, module->nlocalsym, &n.nlocalsym);
+             bfd_h_put_32 (abfd, module->iextrel, &n.iextrel);
+             bfd_h_put_32 (abfd, module->nextrel, &n.nextrel);
+             bfd_h_put_32 (abfd, iinit, &n.iinit_iterm);
+             bfd_h_put_32 (abfd, ninit, &n.ninit_nterm);
+             bfd_h_put_32 (abfd, module->objc_module_info_addr,
+                           &n.objc_module_info_addr);
+             bfd_h_put_32 (abfd, module->objc_module_info_size,
+                           &n.objc_module_info_size);
+
+             if (bfd_bwrite ((void *) &n, sizeof (n), abfd) != sizeof (n))
+               return FALSE;
+           }
+       }
+    }
+
+  if (cmd->ntoc != 0)
+    {
+      unsigned int i;
+
+      if (bfd_seek (abfd, cmd->tocoff, SEEK_SET) != 0)
+       return FALSE;
+
+      for (i = 0; i < cmd->ntoc; i++)
+       {
+         struct mach_o_dylib_table_of_contents_external raw;
+         bfd_mach_o_dylib_table_of_content *toc = &cmd->dylib_toc[i];
+
+         bfd_h_put_32 (abfd, toc->symbol_index, &raw.symbol_index);
+         bfd_h_put_32 (abfd, toc->module_index, &raw.module_index);
+
+         if (bfd_bwrite (&raw, sizeof (raw), abfd) != sizeof (raw))
+           return FALSE;
+       }
+    }
+  
+  if (cmd->nindirectsyms > 0)
+    {
+      unsigned int i;
+
+      if (bfd_seek (abfd, cmd->indirectsymoff, SEEK_SET) != 0)
+       return FALSE;
+
+      for (i = 0; i < cmd->nindirectsyms; ++i)
+       {
+         unsigned char raw[4];
+
+         bfd_h_put_32 (abfd, cmd->indirect_syms[i], &raw);
+         if (bfd_bwrite (raw, sizeof (raw), abfd) != sizeof (raw))
+           return FALSE;
+       }    
+    }
+
+  if (cmd->nextrefsyms != 0)
+    {
+      unsigned int i;
+
+      if (bfd_seek (abfd, cmd->extrefsymoff, SEEK_SET) != 0)
+       return FALSE;
+
+      for (i = 0; i < cmd->nextrefsyms; i++)
+       {
+         unsigned long v;
+         unsigned char raw[4];
+         bfd_mach_o_dylib_reference *ref = &cmd->ext_refs[i];
+
+         /* Fields isym and flags are written as bit-fields, thus we need
+            a specific processing for endianness.  */
+
+         if (bfd_big_endian (abfd))
+           {
+             v = ((ref->isym & 0xffffff) << 8);
+             v |= ref->flags & 0xff;
+           }
+         else
+           {
+             v = ref->isym  & 0xffffff;
+             v |= ((ref->flags & 0xff) << 24);
+           }
+
+         bfd_h_put_32 (abfd, v, raw);
+         if (bfd_bwrite (raw, sizeof (raw), abfd) != sizeof (raw))
+           return FALSE;
+       }
+    }
+
+  /* The command.  */
+  if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0)
+    return FALSE;
+  else
+    {
+      struct mach_o_dysymtab_command_external raw;
+
+      bfd_h_put_32 (abfd, cmd->ilocalsym, &raw.ilocalsym);
+      bfd_h_put_32 (abfd, cmd->nlocalsym, &raw.nlocalsym);
+      bfd_h_put_32 (abfd, cmd->iextdefsym, &raw.iextdefsym);
+      bfd_h_put_32 (abfd, cmd->nextdefsym, &raw.nextdefsym);
+      bfd_h_put_32 (abfd, cmd->iundefsym, &raw.iundefsym);
+      bfd_h_put_32 (abfd, cmd->nundefsym, &raw.nundefsym);
+      bfd_h_put_32 (abfd, cmd->tocoff, &raw.tocoff);
+      bfd_h_put_32 (abfd, cmd->ntoc, &raw.ntoc);
+      bfd_h_put_32 (abfd, cmd->modtaboff, &raw.modtaboff);
+      bfd_h_put_32 (abfd, cmd->nmodtab, &raw.nmodtab);
+      bfd_h_put_32 (abfd, cmd->extrefsymoff, &raw.extrefsymoff);
+      bfd_h_put_32 (abfd, cmd->nextrefsyms, &raw.nextrefsyms);
+      bfd_h_put_32 (abfd, cmd->indirectsymoff, &raw.indirectsymoff);
+      bfd_h_put_32 (abfd, cmd->nindirectsyms, &raw.nindirectsyms);
+      bfd_h_put_32 (abfd, cmd->extreloff, &raw.extreloff);
+      bfd_h_put_32 (abfd, cmd->nextrel, &raw.nextrel);
+      bfd_h_put_32 (abfd, cmd->locreloff, &raw.locreloff);
+      bfd_h_put_32 (abfd, cmd->nlocrel, &raw.nlocrel);
+
+      if (bfd_bwrite (&raw, sizeof (raw), abfd) != sizeof (raw))
+       return FALSE;
+    }
+
+  return TRUE;
+}
+
+static unsigned
+bfd_mach_o_primary_symbol_sort_key (unsigned type, unsigned ext)
+{
+  /* TODO: Determine the correct ordering of stabs symbols.  */
+  /* We make indirect symbols a local/synthetic.  */
+  if (type == BFD_MACH_O_N_INDR)
+    return 3;
+
+  /* Local (we should never see an undefined local AFAICT).  */
+  if (! ext)
+    return 0;
+
+  /* Common symbols look like undefined externs.  */
+  if (type == BFD_MACH_O_N_UNDF)
+    return 2;
+
+  /* A defined symbol that's not indirect or extern.  */
+  return 1;
+}
+
+static int
+bfd_mach_o_cf_symbols (const void *a, const void *b)
+{
+  bfd_mach_o_asymbol *sa = *(bfd_mach_o_asymbol **) a;
+  bfd_mach_o_asymbol *sb = *(bfd_mach_o_asymbol **) b;
+  unsigned int soa, sob;
+
+  soa = bfd_mach_o_primary_symbol_sort_key 
+                       (sa->n_type & BFD_MACH_O_N_TYPE,
+                        sa->n_type & (BFD_MACH_O_N_PEXT | BFD_MACH_O_N_EXT));
+  sob = bfd_mach_o_primary_symbol_sort_key
+                       (sb->n_type & BFD_MACH_O_N_TYPE,
+                        sb->n_type & (BFD_MACH_O_N_PEXT | BFD_MACH_O_N_EXT));
+  if (soa < sob)
+    return -1;
+
+  if (soa > sob)
+    return 1;
+
+  /* If it's local, just preserve the input order.  */
+  if (soa == 0)
+    {
+      if (sa->symbol.udata.i < sb->symbol.udata.i)
+        return -1;
+      if (sa->symbol.udata.i > sb->symbol.udata.i)
+        return  1;
+      return 0;
+    }
+
+  /* Unless it's an indirect the second sort key is name.  */
+  if (soa < 3)
+    return strcmp (sa->symbol.name, sb->symbol.name);
+
+  /* Here be indirect symbols, which have different sort rules.  */
+
+  /* Next sort key for indirect, is the section index.  */
+  if (sa->n_sect < sb->n_sect)
+    return -1;
+
+  if (sa->n_sect > sb->n_sect)
+    return  1;
+
+  /* Last sort key is the order of definition - which should be in line with
+     the value, since a stub size of 0 is meaninglesss.  */
+
+  if (sa->symbol.value < sb->symbol.value)
+    return -1;
+
+  if (sa->symbol.value > sb->symbol.value)
+    return 1;
+
+  /* In the final analysis, this is probably an error ... but leave it alone
+     for now.  */
+  return 0;
+}
+
+/* When this is finished, return the number of non-indirect symbols.  */
+
+static unsigned int
+bfd_mach_o_sort_symbol_table (asymbol **symbols, unsigned int nin)
+{
+  qsort (symbols, (size_t) nin, sizeof (void *), bfd_mach_o_cf_symbols);
+  
+  /* Find the last non-indirect symbol.  
+     There must be at least one non-indirect symbol otherwise there's
+     nothing for the indirect(s) to refer to.  */
+  do
+    { 
+      bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[nin - 1];
+      if (IS_MACHO_INDIRECT (s->n_type))
+       nin--;
+      else
+       break;
+    } while (nin - 1 > 0);
+  return nin;
+}
+
+/* Process the symbols.
+
+   This should be OK for single-module files - but it is not likely to work
+   for multi-module shared libraries.
+
+   (a) If the application has not filled in the relevant mach-o fields, make
+       an estimate.
+
+   (b) Order them, like this:
+       (  i) local.
+               (unsorted)
+       ( ii) external defined
+               (by name)
+       (iii) external undefined
+               (by name)
+       ( iv) common
+               (by name)
+       (  v) indirect 
+               (by section)
+                       (by position within section).
+
+   (c) Indirect symbols are moved to the end of the list.  */
 
 static bfd_boolean
-bfd_mach_o_mangle_symbols (bfd *abfd)
+bfd_mach_o_mangle_symbols (bfd *abfd, bfd_mach_o_data_struct *mdata)
 {
   unsigned long i;
   asymbol **symbols = bfd_get_outsymbols (abfd);
 
+  if (symbols == NULL || bfd_get_symcount (abfd) == 0)
+    return TRUE;
+
   for (i = 0; i < bfd_get_symcount (abfd); i++)
     {
       bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
@@ -1445,6 +1769,8 @@ bfd_mach_o_mangle_symbols (bfd *abfd)
               s->n_type = BFD_MACH_O_N_UNDF;
               if (s->symbol.flags & BSF_WEAK)
                 s->n_desc |= BFD_MACH_O_N_WEAK_REF;
+              /* mach-o automatically makes undefined symbols extern.  */
+             s->n_type |= BFD_MACH_O_N_EXT;
             }
           else if (s->symbol.section == bfd_com_section_ptr)
             s->n_type = BFD_MACH_O_N_UNDF | BFD_MACH_O_N_EXT;
@@ -1455,15 +1781,116 @@ bfd_mach_o_mangle_symbols (bfd *abfd)
             s->n_type |= BFD_MACH_O_N_EXT;
         }
 
-      /* Compute section index.  */
+      /* Put the section index in, where required.  */
       if (s->symbol.section != bfd_abs_section_ptr
           && s->symbol.section != bfd_und_section_ptr
           && s->symbol.section != bfd_com_section_ptr)
         s->n_sect = s->symbol.section->target_index;
 
-      /* Number symbols.  */
-      s->symbol.udata.i = i;
+      /* Unless we're looking at an indirect sym, note the input ordering.
+        We use this to keep local symbols ordered as per the input.  */
+      if (IS_MACHO_INDIRECT (s->n_type))
+       s->symbol.udata.i = i;
+    }
+
+  /* Sort the symbols and determine how many will remain in the main symbol
+     table, and how many will be emitted as indirect (assuming that we will
+     be emitting a dysymtab).  Renumber the sorted symbols so that the right
+     index will be found during indirection.  */
+  i = bfd_mach_o_sort_symbol_table (symbols, bfd_get_symcount (abfd));
+  if (bfd_mach_o_should_emit_dysymtab ())
+    {
+      /* Point at the first indirect symbol.  */
+      if (i < bfd_get_symcount (abfd))
+       {
+         mdata->indirect_syms = &symbols[i];
+         mdata->nindirect = bfd_get_symcount (abfd) - i;
+         /* This is, essentially, local to the output section of mach-o,
+            and therefore should be safe.  */
+         abfd->symcount = i;
+       }
+
+      /* Now setup the counts for each type of symbol.  */
+      for (i = 0; i < bfd_get_symcount (abfd); ++i)
+       {
+         bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
+         s->symbol.udata.i = i;  /* renumber.  */
+         if (s->n_type & (BFD_MACH_O_N_EXT | BFD_MACH_O_N_PEXT))
+           break;
+       }
+      mdata->nlocal = i;
+      for (; i < bfd_get_symcount (abfd); ++i)
+       {
+         bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
+         s->symbol.udata.i = i;  /* renumber.  */
+         if ((s->n_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_UNDF)
+           break;
+       }
+      mdata->ndefext = i - mdata->nlocal;
+      mdata->nundefext = bfd_get_symcount (abfd) 
+                        - mdata->ndefext 
+                        - mdata->nlocal;
+      for (; i < bfd_get_symcount (abfd); ++i)
+       {
+         bfd_mach_o_asymbol *s = (bfd_mach_o_asymbol *)symbols[i];
+         s->symbol.udata.i = i;  /* renumber.  */
+       }
+    }
+
+  return TRUE;
+}
+
+/* We build a flat table of sections, which can be re-ordered if necessary.
+   Fill in the section number and other mach-o-specific data.  */
+
+static bfd_boolean
+bfd_mach_o_mangle_sections (bfd *abfd, bfd_mach_o_data_struct *mdata)
+{
+  asection *sec;
+  unsigned target_index;
+  unsigned nsect;
+
+  nsect = bfd_count_sections (abfd);
+  
+  /* Don't do it if it's already set - assume the application knows what it's
+     doing.  */
+  if (mdata->nsects == nsect
+      && (mdata->nsects == 0 || mdata->sections != NULL))
+    return TRUE;
+
+  mdata->nsects = nsect;
+  mdata->sections = bfd_alloc (abfd, 
+                              mdata->nsects * sizeof (bfd_mach_o_section *));
+  if (mdata->sections == NULL)
+    return FALSE;
+
+  /* We need to check that this can be done...  */
+  if (nsect > 255)
+    (*_bfd_error_handler) (_("mach-o: there are too many sections (%d)"
+                            " maximum is 255,\n"), nsect);
+
+  /* Create Mach-O sections.
+     Section type, attribute and align should have been set when the 
+     section was created - either read in or specified.  */
+  target_index = 0;
+  for (sec = abfd->sections; sec; sec = sec->next)
+    {
+      unsigned bfd_align = bfd_get_section_alignment (abfd, sec);
+      bfd_mach_o_section *msect = bfd_mach_o_get_mach_o_section (sec);
+
+      mdata->sections[target_index] = msect;
+
+      msect->addr = bfd_get_section_vma (abfd, sec);
+      msect->size = bfd_get_section_size (sec);
+
+      /* Use the largest alignment set, in case it was bumped after the 
+        section was created.  */
+      msect->align = msect->align > bfd_align ? msect->align : bfd_align;
+
+      msect->offset = 0;
+      sec->target_index = ++target_index;
     }
+
   return TRUE;
 }
 
@@ -1473,27 +1900,14 @@ bfd_mach_o_write_contents (bfd *abfd)
   unsigned int i;
   bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
 
+  /* Make the commands, if not already present.  */
   if (mdata->header.ncmds == 0)
     if (!bfd_mach_o_build_commands (abfd))
       return FALSE;
 
-  /* Now write header information.  */
-  if (mdata->header.filetype == 0)
-    {
-      if (abfd->flags & EXEC_P)
-        mdata->header.filetype = BFD_MACH_O_MH_EXECUTE;
-      else if (abfd->flags & DYNAMIC)
-        mdata->header.filetype = BFD_MACH_O_MH_DYLIB;
-      else
-        mdata->header.filetype = BFD_MACH_O_MH_OBJECT;
-    }
   if (!bfd_mach_o_write_header (abfd, &mdata->header))
     return FALSE;
 
-  /* Assign a number to each symbols.  */
-  if (!bfd_mach_o_mangle_symbols (abfd))
-    return FALSE;
-
   for (i = 0; i < mdata->header.ncmds; i++)
     {
       struct mach_o_load_command_external raw;
@@ -1523,6 +1937,10 @@ bfd_mach_o_write_contents (bfd *abfd)
          if (!bfd_mach_o_write_symtab (abfd, cur))
            return FALSE;
          break;
+       case BFD_MACH_O_LC_DYSYMTAB:
+         if (!bfd_mach_o_write_dysymtab (abfd, cur))
+           return FALSE;
+         break;
        case BFD_MACH_O_LC_SYMSEG:
          break;
        case BFD_MACH_O_LC_THREAD:
@@ -1535,7 +1953,6 @@ bfd_mach_o_write_contents (bfd *abfd)
        case BFD_MACH_O_LC_IDENT:
        case BFD_MACH_O_LC_FVMFILE:
        case BFD_MACH_O_LC_PREPAGE:
-       case BFD_MACH_O_LC_DYSYMTAB:
        case BFD_MACH_O_LC_LOAD_DYLIB:
        case BFD_MACH_O_LC_LOAD_WEAK_DYLIB:
        case BFD_MACH_O_LC_ID_DYLIB:
@@ -1591,7 +2008,171 @@ bfd_mach_o_set_section_flags_from_bfd (bfd *abfd ATTRIBUTE_UNUSED, asection *sec
     s->flags = BFD_MACH_O_S_REGULAR;
 }
 
-/* Build Mach-O load commands from the sections.  */
+/* Count the number of sections in the list for the segment named.
+
+   The special case of NULL or "" for the segment name is valid for
+   an MH_OBJECT file and means 'all sections available'.  
+   
+   Requires that the sections table in mdata be filled in.  
+
+   Returns the number of sections (0 is valid).
+   Any number > 255 signals an invalid section count, although we will,
+   perhaps, allow the file to be written (in line with Darwin tools up
+   to XCode 4). 
+   
+   A section count of (unsigned long) -1 signals a definite error.  */
+
+static unsigned long
+bfd_mach_o_count_sections_for_seg (const char *segment,
+                                  bfd_mach_o_data_struct *mdata)
+{
+  unsigned i,j;
+  if (mdata == NULL || mdata->sections == NULL)
+    return (unsigned long) -1;
+
+  /* The MH_OBJECT case, all sections are considered; Although nsects is
+     is an unsigned long, the maximum valid section count is 255 and this
+     will have been checked already by mangle_sections.  */
+  if (segment == NULL || segment[0] == '\0')
+    return mdata->nsects;
+
+  /* Count the number of sections we see in this segment.  */
+  j = 0;
+  for (i = 0; i < mdata->nsects; ++i)
+    {
+      bfd_mach_o_section *s = mdata->sections[i];
+      if (strncmp (segment, s->segname, BFD_MACH_O_SEGNAME_SIZE) == 0)
+        j++;
+    }
+  return j;
+}
+
+static bfd_boolean
+bfd_mach_o_build_seg_command (const char *segment,
+                             bfd_mach_o_data_struct *mdata,
+                             bfd_mach_o_segment_command *seg)
+{
+  unsigned i;
+  int is_mho = (segment == NULL || segment[0] == '\0');
+
+  /* Fill segment command.  */
+  if (is_mho)
+    memset (seg->segname, 0, sizeof (seg->segname));
+  else
+    strncpy (seg->segname, segment, sizeof (seg->segname));
+
+  /* TODO: fix this up for non-MH_OBJECT cases.  */
+  seg->vmaddr = 0;
+
+  seg->fileoff = mdata->filelen;
+  seg->filesize = 0;
+  seg->maxprot = BFD_MACH_O_PROT_READ | BFD_MACH_O_PROT_WRITE
+                | BFD_MACH_O_PROT_EXECUTE;
+  seg->initprot = seg->maxprot;
+  seg->flags = 0;
+  seg->sect_head = NULL;
+  seg->sect_tail = NULL;
+
+  /*  Append sections to the segment.  */
+
+  for (i = 0; i < mdata->nsects; ++i)
+    {
+      bfd_mach_o_section *s = mdata->sections[i];
+      asection *sec = s->bfdsection;
+
+      /* If we're not making an MH_OBJECT, check whether this section is from
+        our segment, and skip if not.  Otherwise, just add all sections.  */
+      if (! is_mho 
+         && strncmp (segment, s->segname, BFD_MACH_O_SEGNAME_SIZE) != 0)
+       continue;
+
+      bfd_mach_o_append_section_to_segment (seg, sec);
+
+      if (s->size == 0)
+         s->offset = 0;
+      else
+       {
+          mdata->filelen = FILE_ALIGN (mdata->filelen, s->align);
+          s->offset = mdata->filelen;
+        }
+
+      sec->filepos = s->offset;
+
+      mdata->filelen += s->size;
+    }
+
+  seg->filesize = mdata->filelen - seg->fileoff;
+  seg->vmsize = seg->filesize;
+
+  return TRUE;
+}
+
+static bfd_boolean
+bfd_mach_o_build_dysymtab_command (bfd *abfd,
+                                  bfd_mach_o_data_struct *mdata,
+                                  bfd_mach_o_load_command *cmd)
+{
+  bfd_mach_o_dysymtab_command *dsym = &cmd->command.dysymtab;
+
+  /* TODO:
+     We are not going to try and fill these in yet and, moreover, we are
+     going to bail if they are already set.  */
+  if (dsym->nmodtab != 0
+      || dsym->ntoc != 0
+      || dsym->nextrefsyms != 0)
+    {
+      (*_bfd_error_handler) (_("sorry: modtab, toc and extrefsyms are not yet"
+                               " implemented for dysymtab commands."));
+      return FALSE;
+    }
+
+  dsym->ilocalsym = 0;
+  dsym->nlocalsym = mdata->nlocal;
+  dsym->iextdefsym = dsym->nlocalsym;
+  dsym->nextdefsym = mdata->ndefext;
+  dsym->iundefsym = dsym->nextdefsym + dsym->iextdefsym;
+  dsym->nundefsym = mdata->nundefext;
+
+  if (mdata->nindirect > 0)
+    {
+      unsigned i, sect;
+
+      mdata->filelen = FILE_ALIGN (mdata->filelen, 2);
+      dsym->indirectsymoff = mdata->filelen;
+      mdata->filelen += mdata->nindirect * 4;
+      
+      dsym->indirect_syms = bfd_zalloc (abfd, mdata->nindirect * 4);
+      if (dsym->indirect_syms == NULL)
+        return FALSE;
+      dsym->nindirectsyms = mdata->nindirect;
+      
+      /* So fill in the indices, and point the section reserved1 fields
+        at the right one.  */
+      sect = (unsigned) -1;
+      for (i = 0; i < mdata->nindirect; ++i)
+       {
+         bfd_mach_o_asymbol *s = 
+                       (bfd_mach_o_asymbol *) mdata->indirect_syms[i];
+         /* Lookup the index of the referenced symbol.  */
+         dsym->indirect_syms[i] = 
+               ((bfd_mach_o_asymbol *) s->symbol.udata.p)->symbol.udata.i;
+         if (s->n_sect != sect)
+           {
+             /* Mach-o sections are 1-based, but the section table
+                is 0-based.  */
+             bfd_mach_o_section *sc = mdata->sections[s->n_sect-1];
+             sc->reserved1 = i;
+             sect = s->n_sect;
+           }
+       }
+    }
+
+  return TRUE;
+}
+
+/* Build Mach-O load commands (currently assuming an MH_OBJECT file).
+   TODO: Other file formats, rebuilding symtab/dysymtab commands for strip
+   and copy functionality.  */
 
 bfd_boolean
 bfd_mach_o_build_commands (bfd *abfd)
@@ -1599,102 +2180,148 @@ bfd_mach_o_build_commands (bfd *abfd)
   bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
   unsigned int wide = mach_o_wide_p (&mdata->header);
   bfd_mach_o_segment_command *seg;
-  asection *sec;
   bfd_mach_o_load_command *cmd;
   bfd_mach_o_load_command *symtab_cmd;
-  int target_index;
+  unsigned symcind;
 
-  /* Return now if commands are already built.  */
+  /* Return now if commands are already present.  */
   if (mdata->header.ncmds)
     return FALSE;
 
-  /* Very simple version: a command (segment) to contain all the sections and
-     a command for the symbol table.  */
-  mdata->header.ncmds = 2;
-  mdata->commands = bfd_alloc (abfd, mdata->header.ncmds
-                               * sizeof (bfd_mach_o_load_command));
-  if (mdata->commands == NULL)
-    return FALSE;
-  cmd = &mdata->commands[0];
-  seg = &cmd->command.segment;
-
-  seg->nsects = bfd_count_sections (abfd);
+  /* Fill in the file type, if not already set.  */
 
-  /* Set segment command.  */
-  if (wide)
+  if (mdata->header.filetype == 0)
     {
-      cmd->type = BFD_MACH_O_LC_SEGMENT_64;
-      cmd->offset = BFD_MACH_O_HEADER_64_SIZE;
-      cmd->len = BFD_MACH_O_LC_SEGMENT_64_SIZE
-        + BFD_MACH_O_SECTION_64_SIZE * seg->nsects;
+      if (abfd->flags & EXEC_P)
+        mdata->header.filetype = BFD_MACH_O_MH_EXECUTE;
+      else if (abfd->flags & DYNAMIC)
+        mdata->header.filetype = BFD_MACH_O_MH_DYLIB;
+      else
+        mdata->header.filetype = BFD_MACH_O_MH_OBJECT;
     }
-  else
+
+  /* If hasn't already been done, flatten sections list, and sort
+     if/when required.  Must be done before the symbol table is adjusted,
+     since that depends on properly numbered sections.  */
+  if (mdata->nsects == 0 || mdata->sections == NULL)
+    if (! bfd_mach_o_mangle_sections (abfd, mdata))
+      return FALSE;
+
+  /* Order the symbol table, fill-in/check mach-o specific fields and
+     partition out any indirect symbols.  */
+  if (!bfd_mach_o_mangle_symbols (abfd, mdata))
+    return FALSE;
+
+  /* It's valid to have a file with only absolute symbols...  */
+  if (mdata->nsects > 0)
     {
-      cmd->type = BFD_MACH_O_LC_SEGMENT;
-      cmd->offset = BFD_MACH_O_HEADER_SIZE;
-      cmd->len = BFD_MACH_O_LC_SEGMENT_SIZE
-        + BFD_MACH_O_SECTION_SIZE * seg->nsects;
+      mdata->header.ncmds = 1;
+      symcind = 1;
     }
-  cmd->type_required = FALSE;
-  mdata->header.sizeofcmds = cmd->len;
-  mdata->filelen = cmd->offset + cmd->len;
+  else
+    symcind = 0;
 
-  /* Set symtab command.  */
-  symtab_cmd = &mdata->commands[1];
-  
-  symtab_cmd->type = BFD_MACH_O_LC_SYMTAB;
-  symtab_cmd->offset = cmd->offset + cmd->len;
-  symtab_cmd->len = 6 * 4;
-  symtab_cmd->type_required = FALSE;
-  
-  mdata->header.sizeofcmds += symtab_cmd->len;
-  mdata->filelen += symtab_cmd->len;
+  /* It's OK to have a file with only section statements.  */
+  if (bfd_get_symcount (abfd) > 0)
+    mdata->header.ncmds += 1;
 
-  /* Fill segment command.  */
-  memset (seg->segname, 0, sizeof (seg->segname));
-  seg->vmaddr = 0;
-  seg->fileoff = mdata->filelen;
-  seg->filesize = 0;
-  seg->maxprot = BFD_MACH_O_PROT_READ | BFD_MACH_O_PROT_WRITE
-    | BFD_MACH_O_PROT_EXECUTE;
-  seg->initprot = seg->maxprot;
-  seg->flags = 0;
-  seg->sect_head = NULL;
-  seg->sect_tail = NULL;
+  /* Very simple version (only really applicable to MH_OBJECTs):
+       a command (segment) to contain all the sections,
+       a command for the symbol table
+       a n (optional) command for the dysymtab.  
 
-  /* Create Mach-O sections.
-     Section type, attribute and align should have been set when the 
-     section was created - either read in or specified.  */
-  target_index = 0;
-  for (sec = abfd->sections; sec; sec = sec->next)
-    {
-      unsigned bfd_align = bfd_get_section_alignment (abfd, sec);
-      bfd_mach_o_section *msect = bfd_mach_o_get_mach_o_section (sec);
+     ??? maybe we should assert that this is an MH_OBJECT?  */
 
-      bfd_mach_o_append_section_to_segment (seg, sec);
+  if (bfd_mach_o_should_emit_dysymtab ()
+      && bfd_get_symcount (abfd) > 0)
+    mdata->header.ncmds += 1;
 
-      msect->addr = bfd_get_section_vma (abfd, sec);
-      msect->size = bfd_get_section_size (sec);
-      /* Use the largest alignment set, in case it was bumped after the 
-        section was created.  */
-      msect->align = msect->align > bfd_align ? msect->align : bfd_align;
+  /* A bit weird, but looks like no content;
+     as -n empty.s -o empty.o  */
+  if (mdata->header.ncmds == 0)
+    return TRUE;
 
-      if (msect->size != 0)
-        {
-          mdata->filelen = FILE_ALIGN (mdata->filelen, msect->align);
-          msect->offset = mdata->filelen;
-        }
+  mdata->commands = bfd_zalloc (abfd, mdata->header.ncmds
+                                * sizeof (bfd_mach_o_load_command));
+  if (mdata->commands == NULL)
+    return FALSE;
+
+  if (mdata->nsects > 0)
+    {  
+      cmd = &mdata->commands[0];
+      seg = &cmd->command.segment;
+
+      /* Count the segctions in the special blank segment used for MH_OBJECT.  */
+      seg->nsects = bfd_mach_o_count_sections_for_seg (NULL, mdata);
+      if (seg->nsects == (unsigned long) -1)
+       return FALSE;
+
+      /* Init segment command.  */
+      if (wide)
+       {
+         cmd->type = BFD_MACH_O_LC_SEGMENT_64;
+         cmd->offset = BFD_MACH_O_HEADER_64_SIZE;
+         cmd->len = BFD_MACH_O_LC_SEGMENT_64_SIZE
+                       + BFD_MACH_O_SECTION_64_SIZE * seg->nsects;
+       }
       else
-        msect->offset = 0;
+       {
+         cmd->type = BFD_MACH_O_LC_SEGMENT;
+         cmd->offset = BFD_MACH_O_HEADER_SIZE;
+         cmd->len = BFD_MACH_O_LC_SEGMENT_SIZE
+                       + BFD_MACH_O_SECTION_SIZE * seg->nsects;
+       }
+      cmd->type_required = FALSE;
+      mdata->header.sizeofcmds = cmd->len;
+      mdata->filelen = cmd->offset + cmd->len;
+    }
 
-      sec->filepos = msect->offset;
-      sec->target_index = ++target_index;
+  if (bfd_get_symcount (abfd) > 0)
+    {
+      /* Init symtab command.  */
+      symtab_cmd = &mdata->commands[symcind];
+  
+      symtab_cmd->type = BFD_MACH_O_LC_SYMTAB;
+      if (symcind > 0)
+        symtab_cmd->offset = mdata->commands[0].offset 
+                            + mdata->commands[0].len;
+      else
+        symtab_cmd->offset = 0;
+      symtab_cmd->len = 6 * 4;
+      symtab_cmd->type_required = FALSE;
+  
+      mdata->header.sizeofcmds += symtab_cmd->len;
+      mdata->filelen += symtab_cmd->len;
+    }
 
-      mdata->filelen += msect->size;
+  /* If required, setup symtab command.  */
+  if (bfd_mach_o_should_emit_dysymtab ()
+      && bfd_get_symcount (abfd) > 0)
+    {
+      cmd = &mdata->commands[symcind+1];
+      cmd->type = BFD_MACH_O_LC_DYSYMTAB;
+      cmd->offset = symtab_cmd->offset + symtab_cmd->len;
+      cmd->type_required = FALSE;
+      cmd->len = 18 * 4 + BFD_MACH_O_LC_SIZE;
+
+      mdata->header.sizeofcmds += cmd->len;
+      mdata->filelen += cmd->len;
     }
-  seg->filesize = mdata->filelen - seg->fileoff;
-  seg->vmsize = seg->filesize;
 
+  /* So, now we have sized the commands and the filelen set to that.
+     Now we can build the segment command and set the section file offsets.  */
+  if (mdata->nsects > 0
+      && ! bfd_mach_o_build_seg_command (NULL, mdata, seg))
+    return FALSE;
+
+  /* If we're doing a dysymtab, cmd points to its load command.  */
+  if (bfd_mach_o_should_emit_dysymtab ()
+      && bfd_get_symcount (abfd) > 0
+      && ! bfd_mach_o_build_dysymtab_command (abfd, mdata, 
+                                             &mdata->commands[symcind+1]))
+    return FALSE;
+
+  /* The symtab command is filled in when the symtab is written.  */
   return TRUE;
 }
 
@@ -1709,8 +2336,8 @@ bfd_mach_o_set_section_contents (bfd *abfd,
 {
   file_ptr pos;
 
-  /* This must be done first, because bfd_set_section_contents is
-     going to set output_has_begun to TRUE.  */
+  /* Trying to write the first section contents will trigger the creation of
+     the load commands if they are not already present.  */
   if (! abfd->output_has_begun && ! bfd_mach_o_build_commands (abfd))
     return FALSE;
 
index 89dce1a..24a1645 100644 (file)
@@ -1,6 +1,6 @@
 /* Mach-O support for BFD.
-   Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2011
-   Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2009, 2011,
+   2012 Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
@@ -109,13 +109,24 @@ typedef struct bfd_mach_o_asymbol
   /* The actual symbol which the rest of BFD works with.  */
   asymbol symbol;
 
-  /* Fields from Mach-O 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
+       (sorted by name)
+*/
+
 typedef struct bfd_mach_o_symtab_command
 {
   unsigned int symoff;
@@ -507,7 +518,7 @@ typedef struct mach_o_data_struct
   unsigned long nsects;
   bfd_mach_o_section **sections;
 
-  /* Used while writting: current length of the output file.  This is used
+  /* Used while writing: current length of the output file.  This is used
      to allocate space in the file.  */
   ufile_ptr filelen;
 
@@ -517,6 +528,18 @@ typedef struct mach_o_data_struct
   bfd_mach_o_symtab_command *symtab;
   bfd_mach_o_dysymtab_command *dysymtab;
 
+  /* Base values used for building the dysymtab for a single-module object.  */  
+  unsigned long nlocal;
+  unsigned long ndefext;
+  unsigned long nundefext;
+
+  /* If this is non-zero, then the pointer below is populated.  */
+  unsigned long nindirect;
+  /* A set of synthetic symbols representing the 'indirect' ones in the file.
+     These should be sorted (a) by the section they represent and (b) by the
+     order that they appear within each section.  */
+  asymbol **indirect_syms;
+
   /* A place to stash dwarf2 info for this bfd.  */
   void *dwarf2_find_line_info;
 
@@ -600,6 +623,10 @@ unsigned int bfd_mach_o_section_get_entry_size (bfd *, bfd_mach_o_section *);
 bfd_boolean bfd_mach_o_read_symtab_symbols (bfd *);
 bfd_boolean bfd_mach_o_read_symtab_strtab (bfd *abfd);
 
+/* A placeholder in case we need to suppress emitting the dysymtab for some
+   reason (e.g. compatibility with older system versions).  */
+#define bfd_mach_o_should_emit_dysymtab(x) TRUE
+
 extern const bfd_mach_o_xlat_name bfd_mach_o_section_attribute_name[];
 extern const bfd_mach_o_xlat_name bfd_mach_o_section_type_name[];
 
@@ -640,4 +667,8 @@ typedef struct bfd_mach_o_backend_data
 }
 bfd_mach_o_backend_data;
 
+/* Symbol type tests.  */
+
+#define IS_MACHO_INDIRECT(x) (((x) & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_INDR)
+
 #endif /* _BFD_MACH_O_H_ */
index 80f9a73..624ee9f 100644 (file)
@@ -1,3 +1,12 @@
+2012-01-03  Iain Sandoe  <idsandoe@googlemail.com>
+
+       * gas/mach-o/dysymtab-1-64.d: New.
+       * gas/mach-o/dysymtab-1.d: New.
+       * gas/mach-o/symbols-1-64.d: New.
+       * gas/mach-o/symbols-1.d: New.
+       * gas/mach-o/symbols-base-64.s: New.
+       * gas/mach-o/symbols-base.s: New.
+
 2011-12-29  Iain Sandoe  <idsandoe@googlemail.com>
 
        * gas/mach-o/sections-1.d: Amend to recognize that bss is not emitted
diff --git a/gas/testsuite/gas/mach-o/dysymtab-1-64.d b/gas/testsuite/gas/mach-o/dysymtab-1-64.d
new file mode 100644 (file)
index 0000000..2b2b419
--- /dev/null
@@ -0,0 +1,15 @@
+#objdump: -P dysymtab
+#target: x86_64-*-darwin* powerpc64-*-darwin*
+#source: symbols-base-64.s
+.*: +file format mach-o.*
+#...
+Load command dysymtab:
+              local symbols: idx:          0  num: 6.*\(nxtidx: 6\)
+           external symbols: idx:          6  num: 18.*\(nxtidx: 24\)
+          undefined symbols: idx:         24  num: 21.*\(nxtidx: 45\)
+           table of content: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+               module table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+   external reference table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+      indirect symbol table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+  external relocation table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+     local relocation table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
diff --git a/gas/testsuite/gas/mach-o/dysymtab-1.d b/gas/testsuite/gas/mach-o/dysymtab-1.d
new file mode 100644 (file)
index 0000000..48db498
--- /dev/null
@@ -0,0 +1,15 @@
+#objdump: -P dysymtab
+#target: i?86-*-darwin* powerpc-*-darwin*
+#source: symbols-base.s
+.*: +file format mach-o.*
+#...
+Load command dysymtab:
+              local symbols: idx:          0  num: 6.*\(nxtidx: 6\)
+           external symbols: idx:          6  num: 18.*\(nxtidx: 24\)
+          undefined symbols: idx:         24  num: 21.*\(nxtidx: 45\)
+           table of content: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+               module table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+   external reference table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+      indirect symbol table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+  external relocation table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
+     local relocation table: off: 0x00000000  num: 0.*\(endoff: 0x00000000\)
diff --git a/gas/testsuite/gas/mach-o/symbols-1-64.d b/gas/testsuite/gas/mach-o/symbols-1-64.d
new file mode 100644 (file)
index 0000000..9d23ee1
--- /dev/null
@@ -0,0 +1,70 @@
+#as: -L
+#objdump: -t
+#target: x86_64-*-darwin* powerpc64-*-darwin*
+#source: symbols-base-64.s
+.*: +file format mach-o.*
+#...
+SYMBOL TABLE:
+0000000000000000 l.*0e SECT   01 0000 \[.text\] Lzt0
+0000000000000002 l.*0e SECT   01 0000 \[.text\] Lmt0
+0000000000000004 l.*0e SECT   01 0000 \[.text\] Lat0
+0000000000000000 l.*0e SECT   02 0000 \[.data\] Lzd0
+0000000000000002 l.*0e SECT   02 0000 \[.data\] Lmd0
+0000000000000005 l.*0e SECT   02 0000 \[.data\] Lad0
+0000000000000000 l.*0e SECT   03 0000 \[.bss\] zlcomm0
+0000000000000006 l.*0e SECT   03 0000 \[.bss\] mlcomm0
+000000000000000c l.*0e SECT   03 0000 \[.bss\] alcomm0
+0000000000000000 l.*0e SECT   04 0000 \[__HERE.__there\] Lzs0
+0000000000000002 l.*0e SECT   04 0000 \[__HERE.__there\] Lms0
+0000000000000004 l.*0e SECT   04 0000 \[__HERE.__there\] Las0
+000000000000001e l.*0e SECT   01 0000 \[.text\] Lzt1
+0000000000000021 l.*0e SECT   01 0000 \[.text\] Lmt1
+0000000000000023 l.*0e SECT   01 0000 \[.text\] Lat1
+000000000000001e l.*0e SECT   02 0000 \[.data\] Lzd1
+0000000000000020 l.*0e SECT   02 0000 \[.data\] Lmd1
+0000000000000023 l.*0e SECT   02 0000 \[.data\] Lad1
+0000000000000012 l.*0e SECT   03 0000 \[.bss\] zlcomm1
+0000000000000018 l.*0e SECT   03 0000 \[.bss\] mlcomm1
+000000000000001e l.*0e SECT   03 0000 \[.bss\] alcomm1
+0000000000000026 l.*0e SECT   04 0000 \[__HERE.__there\] Lzs1
+0000000000000032 l.*0e SECT   04 0000 \[__HERE.__there\] Lms1
+0000000000000033 l.*0e SECT   04 0000 \[__HERE.__there\] Las1
+0000000000000004 g.*0f SECT   02 0000 \[.data\] adg0
+0000000000000022 g.*0f SECT   02 0000 \[.data\] adg1
+0000000000000005 g.*0f SECT   04 0000 \[__HERE.__there\] asg0
+0000000000000031 g.*0f SECT   04 0000 \[__HERE.__there\] asg1
+0000000000000005 g.*0f SECT   01 0000 \[.text\] atg0
+0000000000000022 g.*0f SECT   01 0000 \[.text\] atg1
+0000000000000003 g.*0f SECT   02 0000 \[.data\] mdg0
+0000000000000021 g.*0f SECT   02 0000 \[.data\] mdg1
+0000000000000003 g.*0f SECT   04 0000 \[__HERE.__there\] msg0
+0000000000000030 g.*0f SECT   04 0000 \[__HERE.__there\] msg1
+0000000000000003 g.*0f SECT   01 0000 \[.text\] mtg0
+0000000000000020 g.*0f SECT   01 0000 \[.text\] mtg1
+0000000000000001 g.*0f SECT   02 0000 \[.data\] zdg0
+000000000000001f g.*0f SECT   02 0000 \[.data\] zdg1
+0000000000000001 g.*0f SECT   04 0000 \[__HERE.__there\] zsg0
+0000000000000027 g.*0f SECT   04 0000 \[__HERE.__there\] zsg1
+0000000000000001 g.*0f SECT   01 0000 \[.text\] ztg0
+000000000000001f g.*0f SECT   01 0000 \[.text\] ztg1
+0000000000000000 g.*01 UND    00 0000 _aud0
+0000000000000000 g.*01 UND    00 0000 _aud1
+0000000000000000 g.*01 UND    00 0000 _aus0
+0000000000000000 g.*01 UND    00 0000 _aus1
+0000000000000000 g.*01 UND    00 0000 _aut0
+0000000000000000 g.*01 UND    00 0000 _mud0
+0000000000000000 g.*01 UND    00 0000 _mud1
+0000000000000000 g.*01 UND    00 0000 _mus0
+0000000000000000 g.*01 UND    00 0000 _mus1
+0000000000000000 g.*01 UND    00 0000 _mut0
+0000000000000000 g.*01 UND    00 0000 _zud0
+0000000000000000 g.*01 UND    00 0000 _zud1
+0000000000000000 g.*01 UND    00 0000 _zus0
+0000000000000000 g.*01 UND    00 0000 _zus1
+0000000000000000 g.*01 UND    00 0000 _zut0
+000000000000000a.*01 COM    00 0300 acommon0
+000000000000000a.*01 COM    00 0300 acommon1
+000000000000000a.*01 COM    00 0300 mcommon0
+000000000000000a.*01 COM    00 0300 mcommon1
+000000000000000a.*01 COM    00 0300 zcommon0
+000000000000000a.*01 COM    00 0300 zcommon1
\ No newline at end of file
diff --git a/gas/testsuite/gas/mach-o/symbols-1.d b/gas/testsuite/gas/mach-o/symbols-1.d
new file mode 100644 (file)
index 0000000..cfc1dca
--- /dev/null
@@ -0,0 +1,70 @@
+#as: -L
+#objdump: -t
+#target: i?86-*-darwin* powerpc-*-darwin*
+#source: symbols-base.s
+.*: +file format mach-o.*
+#...
+SYMBOL TABLE:
+00000000 l.*0e SECT   01 0000 \[.text\] Lzt0
+00000002 l.*0e SECT   01 0000 \[.text\] Lmt0
+00000004 l.*0e SECT   01 0000 \[.text\] Lat0
+00000000 l.*0e SECT   02 0000 \[.data\] Lzd0
+00000002 l.*0e SECT   02 0000 \[.data\] Lmd0
+00000005 l.*0e SECT   02 0000 \[.data\] Lad0
+00000000 l.*0e SECT   03 0000 \[.bss\] zlcomm0
+00000006 l.*0e SECT   03 0000 \[.bss\] mlcomm0
+0000000c l.*0e SECT   03 0000 \[.bss\] alcomm0
+00000000 l.*0e SECT   04 0000 \[__HERE.__there\] Lzs0
+00000002 l.*0e SECT   04 0000 \[__HERE.__there\] Lms0
+00000004 l.*0e SECT   04 0000 \[__HERE.__there\] Las0
+00000012 l.*0e SECT   01 0000 \[.text\] Lzt1
+00000015 l.*0e SECT   01 0000 \[.text\] Lmt1
+00000017 l.*0e SECT   01 0000 \[.text\] Lat1
+00000012 l.*0e SECT   02 0000 \[.data\] Lzd1
+00000014 l.*0e SECT   02 0000 \[.data\] Lmd1
+00000017 l.*0e SECT   02 0000 \[.data\] Lad1
+00000012 l.*0e SECT   03 0000 \[.bss\] zlcomm1
+00000018 l.*0e SECT   03 0000 \[.bss\] mlcomm1
+0000001e l.*0e SECT   03 0000 \[.bss\] alcomm1
+00000016 l.*0e SECT   04 0000 \[__HERE.__there\] Lzs1
+0000001e l.*0e SECT   04 0000 \[__HERE.__there\] Lms1
+0000001f l.*0e SECT   04 0000 \[__HERE.__there\] Las1
+00000004 g.*0f SECT   02 0000 \[.data\] adg0
+00000016 g.*0f SECT   02 0000 \[.data\] adg1
+00000005 g.*0f SECT   04 0000 \[__HERE.__there\] asg0
+0000001d g.*0f SECT   04 0000 \[__HERE.__there\] asg1
+00000005 g.*0f SECT   01 0000 \[.text\] atg0
+00000016 g.*0f SECT   01 0000 \[.text\] atg1
+00000003 g.*0f SECT   02 0000 \[.data\] mdg0
+00000015 g.*0f SECT   02 0000 \[.data\] mdg1
+00000003 g.*0f SECT   04 0000 \[__HERE.__there\] msg0
+0000001c g.*0f SECT   04 0000 \[__HERE.__there\] msg1
+00000003 g.*0f SECT   01 0000 \[.text\] mtg0
+00000014 g.*0f SECT   01 0000 \[.text\] mtg1
+00000001 g.*0f SECT   02 0000 \[.data\] zdg0
+00000013 g.*0f SECT   02 0000 \[.data\] zdg1
+00000001 g.*0f SECT   04 0000 \[__HERE.__there\] zsg0
+00000017 g.*0f SECT   04 0000 \[__HERE.__there\] zsg1
+00000001 g.*0f SECT   01 0000 \[.text\] ztg0
+00000013 g.*0f SECT   01 0000 \[.text\] ztg1
+00000000 g.*01 UND    00 0000 _aud0
+00000000 g.*01 UND    00 0000 _aud1
+00000000 g.*01 UND    00 0000 _aus0
+00000000 g.*01 UND    00 0000 _aus1
+00000000 g.*01 UND    00 0000 _aut0
+00000000 g.*01 UND    00 0000 _mud0
+00000000 g.*01 UND    00 0000 _mud1
+00000000 g.*01 UND    00 0000 _mus0
+00000000 g.*01 UND    00 0000 _mus1
+00000000 g.*01 UND    00 0000 _mut0
+00000000 g.*01 UND    00 0000 _zud0
+00000000 g.*01 UND    00 0000 _zud1
+00000000 g.*01 UND    00 0000 _zus0
+00000000 g.*01 UND    00 0000 _zus1
+00000000 g.*01 UND    00 0000 _zut0
+0000000a.*01 COM    00 0300 acommon0
+0000000a.*01 COM    00 0300 acommon1
+0000000a.*01 COM    00 0300 mcommon0
+0000000a.*01 COM    00 0300 mcommon1
+0000000a.*01 COM    00 0300 zcommon0
+0000000a.*01 COM    00 0300 zcommon1
\ No newline at end of file
diff --git a/gas/testsuite/gas/mach-o/symbols-base-64.s b/gas/testsuite/gas/mach-o/symbols-base-64.s
new file mode 100644 (file)
index 0000000..604501c
--- /dev/null
@@ -0,0 +1,97 @@
+# baseline symbols in sections.
+Lzt0:  .space 1
+       .globl ztg0
+ztg0:  .space 1
+Lmt0:  .space 1
+       .globl mtg0
+mtg0:  .space 1
+Lat0:  .space 1
+       .globl atg0
+atg0:  .space 1
+
+       .quad   _zut0
+       .quad   _mut0
+       .quad   _aut0
+
+       .comm zcommon0, 10, 3
+       .comm mcommon0, 10, 3
+       .comm acommon0, 10, 3
+
+       .data
+Lzd0:  .space 1
+       .globl zdg0
+zdg0:  .space 1
+Lmd0:  .space 1
+       .globl mdg0
+mdg0:  .space 1
+adg0:  .space 1
+       .globl adg0
+Lad0:  .space 1
+
+       .quad   _zud0
+       .quad   _mud0
+       .quad   _aud0
+
+       .lcomm zlcomm0, 5, 1
+       .lcomm mlcomm0, 5, 1
+       .lcomm alcomm0, 5, 1
+
+       .section __HERE,__there
+Lzs0:  .space 1
+       .globl zsg0
+zsg0:  .space 1
+Lms0:  .space 1
+       .globl msg0
+msg0:  .space 1
+Las0:  .space 1
+asg0:  .space 1
+       .globl asg0
+
+       .quad   _zus0
+       .quad   _mus0
+       .quad   _aus0
+
+       .text
+Lzt1:  .space 1
+       .globl ztg1
+ztg1:  .space 1
+       .globl mtg1
+mtg1:  .space 1
+Lmt1:  .space 1
+atg1:  .space 1
+       .globl atg1
+Lat1:  .space 1
+
+       .comm zcommon1, 10, 3
+       .comm mcommon1, 10, 3
+       .comm acommon1, 10, 3
+
+       .data
+Lzd1:  .space 1
+       .globl zdg1, mdg1, adg1
+zdg1:  .space 1
+Lmd1:  .space 1
+mdg1:  .space 1
+adg1:  .space 1
+Lad1:  .space 1
+
+       .quad   _zud1
+       .quad   _mud1
+       .quad   _aud1
+
+       .lcomm zlcomm1, 5, 1
+       .lcomm mlcomm1, 5, 1
+       .lcomm alcomm1, 5, 1
+
+       .section __HERE,__there
+       .quad   _zus1
+Lzs1:  .space 1
+zsg1:  .space 1
+       .quad   _mus1
+msg1:  .space 1
+asg1:  .space 1
+       .globl zsg1, msg1, asg1
+Lms1:  .space 1
+Las1:  .space 1
+
+       .quad   _aus1
diff --git a/gas/testsuite/gas/mach-o/symbols-base.s b/gas/testsuite/gas/mach-o/symbols-base.s
new file mode 100644 (file)
index 0000000..a7b8e75
--- /dev/null
@@ -0,0 +1,97 @@
+# baseline symbols in sections.
+Lzt0:  .space 1
+       .globl ztg0
+ztg0:  .space 1
+Lmt0:  .space 1
+       .globl mtg0
+mtg0:  .space 1
+Lat0:  .space 1
+       .globl atg0
+atg0:  .space 1
+
+       .long   _zut0
+       .long   _mut0
+       .long   _aut0
+
+       .comm zcommon0, 10, 3
+       .comm mcommon0, 10, 3
+       .comm acommon0, 10, 3
+
+       .data
+Lzd0:  .space 1
+       .globl zdg0
+zdg0:  .space 1
+Lmd0:  .space 1
+       .globl mdg0
+mdg0:  .space 1
+adg0:  .space 1
+       .globl adg0
+Lad0:  .space 1
+
+       .long   _zud0
+       .long   _mud0
+       .long   _aud0
+
+       .lcomm zlcomm0, 5, 1
+       .lcomm mlcomm0, 5, 1
+       .lcomm alcomm0, 5, 1
+
+       .section __HERE,__there
+Lzs0:  .space 1
+       .globl zsg0
+zsg0:  .space 1
+Lms0:  .space 1
+       .globl msg0
+msg0:  .space 1
+Las0:  .space 1
+asg0:  .space 1
+       .globl asg0
+
+       .long   _zus0
+       .long   _mus0
+       .long   _aus0
+
+       .text
+Lzt1:  .space 1
+       .globl ztg1
+ztg1:  .space 1
+       .globl mtg1
+mtg1:  .space 1
+Lmt1:  .space 1
+atg1:  .space 1
+       .globl atg1
+Lat1:  .space 1
+
+       .comm zcommon1, 10, 3
+       .comm mcommon1, 10, 3
+       .comm acommon1, 10, 3
+
+       .data
+Lzd1:  .space 1
+       .globl zdg1, mdg1, adg1
+zdg1:  .space 1
+Lmd1:  .space 1
+mdg1:  .space 1
+adg1:  .space 1
+Lad1:  .space 1
+
+       .long   _zud1
+       .long   _mud1
+       .long   _aud1
+
+       .lcomm zlcomm1, 5, 1
+       .lcomm mlcomm1, 5, 1
+       .lcomm alcomm1, 5, 1
+
+       .section __HERE,__there
+       .long   _zus1
+Lzs1:  .space 1
+zsg1:  .space 1
+       .long   _mus1
+msg1:  .space 1
+asg1:  .space 1
+       .globl zsg1, msg1, asg1
+Lms1:  .space 1
+Las1:  .space 1
+
+       .long   _aus1