This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [Patch mach-o, indirect symbols 1/2] support indirect symbols in mach-o.


On Dec 30, 2011, at 4:46 PM, Iain Sandoe wrote:

> this part 1 of 2 patches implementing support for mach-o indirect symbols in bfd.
> Patch 2 contains the testsuite additions.
> 
> [the GAS support for mach-o symbol qualifiers (including indirect) follows as separate patches].
> 
> To support mach-o indirect symbols the following are required:
> 
> 1/ the symbol table must be sorted so that the indices in the dysymtab for local, defined, undefined make sense.
>   (also, indirect symbols carry reference to their counterpart whether the dysymtab is used or not, which means that they must be sorted to the end of the symbols table)
> 
> 2/ reorganize the command build and output code so that we can determine the required data at command-generation time.
>  -- I've also made the segment command builder general, since we should be able to support single module exes and dylibs soon.
> 
> 3/ split the sorted indirect symbols from the main symbol table and place them to be output as part of the dysymtab.
> 
> 4/ provide the dysymtab output code, and use it when writing the file.
> 
> I guess it looks like a big patch, but it seems unavoidable when adding functionality - assuming that one wants to get to a testable point.
> 
> NOTE: if [with the GAS patches applied - so that you can emit indirects] you disable the dysymtab (by setting bfd_mach_o_should_emit_dysymtab FALSE in mach-o.h), the indirect symbols are emitted into the object as part of the symbol table (and correctly recognized by the Darwin system nm command).

Ok with the suggested changes (mostly stylistic).  Bracketed points are not required to be addressed for the commit.

Tristan.

> 
> OK?
> Iain
> 
> 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 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.
> 
> bfd/mach-o.c |  798 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
> bfd/mach-o.h |   31 +++-
> 2 files changed, 727 insertions(+), 102 deletions(-)
> 
> diff --git a/bfd/mach-o.c b/bfd/mach-o.c
> index cc68d89..9a14003 100644
> --- a/bfd/mach-o.c
> +++ b/bfd/mach-o.c
> @@ -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 ((s->n_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_INDR)

[ Maybe we should create a macro to test for indirect symbols ]

> +	/* 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;

[ One issue is that we don't follow the BFD convention for indirect symbols.  To be fixed later ]
[ One question: does it make sense to output the indirect name here and therefore avoiding taking care of indirect symbols while sorting ? ]

> +
>       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 ((s->n_type & BFD_MACH_O_N_TYPE) != BFD_MACH_O_N_INDR)
> +	    s->symbol.udata.i = str_index;
> +
>           if (str_index == (bfd_size_type) -1)
>             goto err;
>         }
> @@ -1420,15 +1443,287 @@ 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_mangle_symbols (bfd *abfd)
> +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;
> +      int wide = bfd_mach_o_wide_p (abfd);
> +      unsigned int module_len = wide ? 56 : 52;
> +
> +      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 long v;
> +          unsigned char buf[56];
> +
> +          bfd_h_put_32 (abfd, module->module_name_idx, buf + 0);
> +          bfd_h_put_32 (abfd, module->iextdefsym, buf + 4);
> +          bfd_h_put_32 (abfd, module->nextdefsym, buf + 8);
> +          bfd_h_put_32 (abfd, module->irefsym, buf + 12);
> +          bfd_h_put_32 (abfd, module->nrefsym, buf + 16);
> +          bfd_h_put_32 (abfd, module->ilocalsym, buf + 20);
> +          bfd_h_put_32 (abfd, module->nlocalsym, buf + 24);
> +          bfd_h_put_32 (abfd, module->iextrel, buf + 28);
> +          bfd_h_put_32 (abfd, module->nextrel, buf + 32);
> +          v = module->iinit & 0xffff;
> +          v |= ((module->iterm & 0xffff) << 16);
> +          bfd_h_put_32 (abfd, v, buf +36);
> +          v = module->ninit  & 0xffff;
> +          v |= ((module->nterm & 0xffff) << 16);
> +          bfd_h_put_32 (abfd, v, buf + 40);
> +          if (wide)
> +            {
> +              bfd_h_put_32 (abfd, module->objc_module_info_size, buf + 44);
> +              bfd_h_put_64 (abfd, module->objc_module_info_addr, buf + 48);
> +            }
> +          else
> +            {
> +              bfd_h_put_32 (abfd, module->objc_module_info_addr, buf + 44);
> +              bfd_h_put_32 (abfd, module->objc_module_info_size, buf + 48);
> +            }

Please don't use the raw buffer buf.  Instead use mach_o_dylib_module[_64]_external.  I know it is boring because of 32/64.
[ Bonus point for creating a separate function to encode (swap out). ]

> +
> +          if (bfd_bwrite ((void *) buf, module_len, abfd) != module_len)
> +            return FALSE;
> +        }
> +    }
> +
> +  if (cmd->ntoc != 0)
> +    {
> +      unsigned int i;
> +
> +      if (bfd_seek (abfd, cmd->tocoff, SEEK_SET) != 0)
> +        return -1;
> +
> +      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);

[ Ditto (although might be considered as too trivial) ]

> +	  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);

[ Ditto ]

> +          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;

GNU style issue: not on the same line!

> +  /* Local (we should never see an undefined local AFAICT).  */
> +  if (!ext) return 0;

Ditto

> +  /* Common symbols look like undefined externs.  */
> +  if (type == BFD_MACH_O_N_UNDF) return 2;

Ditto.

> +  /* 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;

Blank line will be appreciated here!

> +  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);

[ Unfortunately qsort is not stable! ]

> +
> +  /* 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 ((s->n_type & BFD_MACH_O_N_TYPE) == BFD_MACH_O_N_INDR)
> +	nin--;
> +      else
> +	break;
> +    } while (nin-1 > 0);

Style: nin - 1

> +  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_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 +1740,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 +1752,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 ((s->n_type & BFD_MACH_O_N_TYPE) != BFD_MACH_O_N_INDR)
> +	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 +1871,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 +1908,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 +1924,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 +1979,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 +2151,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 possibly 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 +2307,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;
> 
> diff --git a/bfd/mach-o.h b/bfd/mach-o.h
> index 89dce1a..e327b11 100644
> --- a/bfd/mach-o.h
> +++ b/bfd/mach-o.h
> @@ -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[];

Tristan.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]