Fix Opcode generation of ld a,(bc) and ld a,(de) on target z80
[binutils-gdb.git] / bfd / mach-o.c
index 6991612f07cffee1edb7fad041b201daca526418..d3d3abc365b1e10c10b4afe7735e5bba4738c789 100644 (file)
@@ -1,12 +1,12 @@
 /* Mach-O support for BFD.
-   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
+#include "sysdep.h"
 #include "mach-o.h"
 #include "bfd.h"
-#include "sysdep.h"
 #include "libbfd.h"
 #include "libiberty.h"
 #include <ctype.h>
@@ -52,9 +53,6 @@
 #define bfd_mach_o_bfd_make_debug_symbol              _bfd_nosymbols_bfd_make_debug_symbol
 #define bfd_mach_o_read_minisymbols                   _bfd_generic_read_minisymbols
 #define bfd_mach_o_minisymbol_to_symbol               _bfd_generic_minisymbol_to_symbol
-#define bfd_mach_o_get_reloc_upper_bound              _bfd_norelocs_get_reloc_upper_bound
-#define bfd_mach_o_canonicalize_reloc                 _bfd_norelocs_canonicalize_reloc
-#define bfd_mach_o_bfd_reloc_type_lookup              _bfd_norelocs_bfd_reloc_type_lookup
 #define bfd_mach_o_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
 #define bfd_mach_o_bfd_relax_section                  bfd_generic_relax_section
 #define bfd_mach_o_bfd_link_hash_table_create         _bfd_generic_link_hash_table_create
@@ -75,6 +73,7 @@
 #define bfd_mach_o_bfd_discard_group                  bfd_generic_discard_group
 #define bfd_mach_o_section_already_linked             _bfd_generic_section_already_linked
 #define bfd_mach_o_bfd_copy_private_header_data       _bfd_generic_bfd_copy_private_header_data
+#define bfd_mach_o_core_file_matches_executable_p     generic_core_file_matches_executable_p
 
 
 /* The flags field of a section structure is separated into two parts a section
 #define N_STAB 0xe0
 #define N_TYPE 0x1e
 #define N_EXT  0x01
+
 #define N_UNDF 0x0
 #define N_ABS  0x2
+#define N_TEXT 0x4
+#define N_DATA 0x6
+#define N_BSS  0x8
 #define N_SECT 0xe
 #define N_INDR 0xa
 
+static unsigned int 
+bfd_mach_o_version (bfd *abfd)
+{
+  bfd_mach_o_data_struct *mdata = NULL;
+
+  BFD_ASSERT (bfd_mach_o_valid (abfd));
+  mdata = abfd->tdata.mach_o_data;
+
+  return mdata->header.version;
+}
+
 bfd_boolean
 bfd_mach_o_valid (bfd *abfd)
 {
@@ -265,32 +279,46 @@ bfd_mach_o_convert_architecture (bfd_mach_o_cpu_type mtype,
     {
     case BFD_MACH_O_CPU_TYPE_VAX: *type = bfd_arch_vax; break;
     case BFD_MACH_O_CPU_TYPE_MC680x0: *type = bfd_arch_m68k; break;
-    case BFD_MACH_O_CPU_TYPE_I386: *type = bfd_arch_i386; break;
+    case BFD_MACH_O_CPU_TYPE_I386:
+      *type = bfd_arch_i386;
+      *subtype = bfd_mach_i386_i386;
+      break;
+    case BFD_MACH_O_CPU_TYPE_X86_64:
+      *type = bfd_arch_i386;
+      *subtype = bfd_mach_x86_64;
+      break;
     case BFD_MACH_O_CPU_TYPE_MIPS: *type = bfd_arch_mips; break;
     case BFD_MACH_O_CPU_TYPE_MC98000: *type = bfd_arch_m98k; break;
     case BFD_MACH_O_CPU_TYPE_HPPA: *type = bfd_arch_hppa; break;
     case BFD_MACH_O_CPU_TYPE_ARM: *type = bfd_arch_arm; break;
     case BFD_MACH_O_CPU_TYPE_MC88000: *type = bfd_arch_m88k; break;
-    case BFD_MACH_O_CPU_TYPE_SPARC: *type = bfd_arch_sparc; break;
+    case BFD_MACH_O_CPU_TYPE_SPARC:
+      *type = bfd_arch_sparc;
+      *subtype = bfd_mach_sparc;
+      break;
     case BFD_MACH_O_CPU_TYPE_I860: *type = bfd_arch_i860; break;
     case BFD_MACH_O_CPU_TYPE_ALPHA: *type = bfd_arch_alpha; break;
-    case BFD_MACH_O_CPU_TYPE_POWERPC: *type = bfd_arch_powerpc; break;
-    default: *type = bfd_arch_unknown; break;
-    }
-
-  switch (*type)
-    {
-    case bfd_arch_i386: *subtype = bfd_mach_i386_i386; break;
-    case bfd_arch_sparc: *subtype = bfd_mach_sparc; break;
+    case BFD_MACH_O_CPU_TYPE_POWERPC:
+      *type = bfd_arch_powerpc;
+      *subtype = bfd_mach_ppc; 
+      break;
+    case BFD_MACH_O_CPU_TYPE_POWERPC_64:
+      *type = bfd_arch_powerpc;
+      *subtype = bfd_mach_ppc64; 
+      break;
     default:
-      *subtype = bfd_arch_unknown;
+      *type = bfd_arch_unknown;
+      break;
     }
 }
 
 static int
 bfd_mach_o_write_header (bfd *abfd, bfd_mach_o_header *header)
 {
-  unsigned char buf[28];
+  unsigned char buf[32];
+  unsigned int size;
+
+  size = (header->version == 2) ? 32 : 28;
 
   bfd_h_put_32 (abfd, header->magic, buf + 0);
   bfd_h_put_32 (abfd, header->cputype, buf + 4);
@@ -300,16 +328,18 @@ bfd_mach_o_write_header (bfd *abfd, bfd_mach_o_header *header)
   bfd_h_put_32 (abfd, header->sizeofcmds, buf + 20);
   bfd_h_put_32 (abfd, header->flags, buf + 24);
 
+  if (header->version == 2)
+    bfd_h_put_32 (abfd, header->reserved, buf + 28);
+
   bfd_seek (abfd, 0, SEEK_SET);
-  if (bfd_bwrite ((PTR) buf, 28, abfd) != 28)
+  if (bfd_bwrite ((PTR) buf, size, abfd) != size)
     return -1;
 
   return 0;
 }
 
 static int
-bfd_mach_o_scan_write_thread (bfd *abfd,
-                             bfd_mach_o_load_command *command)
+bfd_mach_o_scan_write_thread (bfd *abfd, bfd_mach_o_load_command *command)
 {
   bfd_mach_o_thread_command *cmd = &command->command.thread;
   unsigned int i;
@@ -341,9 +371,9 @@ bfd_mach_o_scan_write_thread (bfd *abfd,
 }
 
 static int
-bfd_mach_o_scan_write_section (bfd *abfd,
-                              bfd_mach_o_section *section,
-                              bfd_vma offset)
+bfd_mach_o_scan_write_section_32 (bfd *abfd,
+                                 bfd_mach_o_section *section,
+                                 bfd_vma offset)
 {
   unsigned char buf[68];
 
@@ -356,8 +386,8 @@ bfd_mach_o_scan_write_section (bfd *abfd,
   bfd_h_put_32 (abfd, section->reloff, buf + 48);
   bfd_h_put_32 (abfd, section->nreloc, buf + 52);
   bfd_h_put_32 (abfd, section->flags, buf + 56);
-  /* bfd_h_put_32 (abfd, section->reserved1, buf + 60); */
-  /* bfd_h_put_32 (abfd, section->reserved2, buf + 64); */
+  bfd_h_put_32 (abfd, section->reserved1, buf + 60);
+  bfd_h_put_32 (abfd, section->reserved2, buf + 64);
 
   bfd_seek (abfd, offset, SEEK_SET);
   if (bfd_bwrite ((PTR) buf, 68, abfd) != 68)
@@ -367,28 +397,92 @@ bfd_mach_o_scan_write_section (bfd *abfd,
 }
 
 static int
-bfd_mach_o_scan_write_segment (bfd *abfd, bfd_mach_o_load_command *command)
+bfd_mach_o_scan_write_section_64 (bfd *abfd,
+                                 bfd_mach_o_section *section,
+                                 bfd_vma offset)
 {
-  unsigned char buf[48];
-  bfd_mach_o_segment_command *seg = &command->command.segment;
-  unsigned long i;
+  unsigned char buf[80];
 
-  BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT);
-
-  memcpy (buf, seg->segname, 16);
-  bfd_h_put_32 (abfd, seg->vmaddr, buf + 16);
-  bfd_h_put_32 (abfd, seg->vmsize, buf + 20);
-  bfd_h_put_32 (abfd, seg->fileoff, buf + 24);
-  bfd_h_put_32 (abfd, seg->filesize, buf + 28);
-  bfd_h_put_32 (abfd, 0 /* seg->maxprot */, buf + 32);
-  bfd_h_put_32 (abfd, 0 /* seg->initprot */, buf + 36);
-  bfd_h_put_32 (abfd, seg->nsects, buf + 40);
-  bfd_h_put_32 (abfd, seg->flags, buf + 44);
+  memcpy (buf, section->sectname, 16);
+  memcpy (buf + 16, section->segname, 16);
+  bfd_h_put_64 (abfd, section->addr, buf + 32);
+  bfd_h_put_64 (abfd, section->size, buf + 40);
+  bfd_h_put_32 (abfd, section->offset, buf + 48);
+  bfd_h_put_32 (abfd, section->align, buf + 52);
+  bfd_h_put_32 (abfd, section->reloff, buf + 56);
+  bfd_h_put_32 (abfd, section->nreloc, buf + 60);
+  bfd_h_put_32 (abfd, section->flags, buf + 64);
+  bfd_h_put_32 (abfd, section->reserved1, buf + 68);
+  bfd_h_put_32 (abfd, section->reserved2, buf + 72);
+  bfd_h_put_32 (abfd, section->reserved3, buf + 76);
 
-  bfd_seek (abfd, command->offset + 8, SEEK_SET);
-  if (bfd_bwrite ((PTR) buf, 48, abfd) != 48)
+  bfd_seek (abfd, offset, SEEK_SET);
+  if (bfd_bwrite ((PTR) buf, 80, abfd) != 80)
     return -1;
 
+  return 0;
+}
+
+static int
+bfd_mach_o_scan_write_section (bfd *abfd, 
+                              bfd_mach_o_section *section,
+                              bfd_vma offset,
+                              unsigned int wide)
+{
+  if (wide)
+    return bfd_mach_o_scan_write_section_64 (abfd, section, offset);
+  else
+    return bfd_mach_o_scan_write_section_32 (abfd, section, offset);
+}
+
+static int
+bfd_mach_o_scan_write_segment (bfd *abfd,
+                              bfd_mach_o_load_command *command,
+                              unsigned int wide)
+{
+  unsigned char buf[64];
+  bfd_mach_o_segment_command *seg = &command->command.segment;
+  unsigned long i;
+
+  if (wide)
+    {
+      BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT_64);
+      
+      memcpy (buf, seg->segname, 16);
+
+      bfd_h_put_64 (abfd, seg->vmaddr, buf + 16);
+      bfd_h_put_64 (abfd, seg->vmsize, buf + 24);
+      bfd_h_put_64 (abfd, seg->fileoff, buf + 32);
+      bfd_h_put_64 (abfd, seg->filesize, buf + 40);
+      bfd_h_put_32 (abfd, seg->maxprot, buf + 48);
+      bfd_h_put_32 (abfd, seg->initprot, buf + 52);
+      bfd_h_put_32 (abfd, seg->nsects, buf + 56);
+      bfd_h_put_32 (abfd, seg->flags, buf + 60);
+
+      bfd_seek (abfd, command->offset + 8, SEEK_SET);
+      if (bfd_bwrite ((PTR) buf, 64, abfd) != 64)
+       return -1;
+    }
+  else
+    {
+      BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT);
+      
+      memcpy (buf, seg->segname, 16);
+
+      bfd_h_put_32 (abfd, seg->vmaddr, buf + 16);
+      bfd_h_put_32 (abfd, seg->vmsize, buf + 20);
+      bfd_h_put_32 (abfd, seg->fileoff, buf + 24);
+      bfd_h_put_32 (abfd, seg->filesize, buf + 28);
+      bfd_h_put_32 (abfd, seg->maxprot, buf + 32);
+      bfd_h_put_32 (abfd, seg->initprot, buf + 36);
+      bfd_h_put_32 (abfd, seg->nsects, buf + 40);
+      bfd_h_put_32 (abfd, seg->flags, buf + 44);
+
+      bfd_seek (abfd, command->offset + 8, SEEK_SET);
+      if (bfd_bwrite ((PTR) buf, 48, abfd) != 48)
+       return -1;
+    }
+
   {
     char buf[1024];
     bfd_vma nbytes = seg->filesize;
@@ -396,29 +490,34 @@ bfd_mach_o_scan_write_segment (bfd *abfd, bfd_mach_o_load_command *command)
 
     while (nbytes > 0)
       {
-       bfd_vma thisread = nbytes;
+       bfd_vma thiswrite = nbytes;
 
-       if (thisread > 1024)
-         thisread = 1024;
+       if (thiswrite > 1024)
+         thiswrite = 1024;
 
        bfd_seek (abfd, curoff, SEEK_SET);
-       if (bfd_bread ((PTR) buf, thisread, abfd) != thisread)
+       if (bfd_bread ((PTR) buf, thiswrite, abfd) != thiswrite)
          return -1;
 
        bfd_seek (abfd, curoff, SEEK_SET);
-       if (bfd_bwrite ((PTR) buf, thisread, abfd) != thisread)
+       if (bfd_bwrite ((PTR) buf, thiswrite, abfd) != thiswrite)
          return -1;
 
-       nbytes -= thisread;
-       curoff += thisread;
+       nbytes -= thiswrite;
+       curoff += thiswrite;
       }
   }
 
   for (i = 0; i < seg->nsects; i++)
     {
-      bfd_vma segoff = command->offset + 48 + 8 + (i * 68);
-
-      if (bfd_mach_o_scan_write_section (abfd, &seg->sections[i], segoff) != 0)
+      bfd_vma segoff;
+      if (wide)
+       segoff = command->offset + 64 + 8 + (i * 80);
+      else
+       segoff = command->offset + 48 + 8 + (i * 68);
+
+      if (bfd_mach_o_scan_write_section
+         (abfd, &seg->sections[i], segoff, wide) != 0)
        return -1;
     }
 
@@ -426,8 +525,19 @@ bfd_mach_o_scan_write_segment (bfd *abfd, bfd_mach_o_load_command *command)
 }
 
 static int
-bfd_mach_o_scan_write_symtab_symbols (bfd *abfd,
-                                     bfd_mach_o_load_command *command)
+bfd_mach_o_scan_write_segment_32 (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  return bfd_mach_o_scan_write_segment (abfd, command, 0);
+}
+
+static int
+bfd_mach_o_scan_write_segment_64 (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  return bfd_mach_o_scan_write_segment (abfd, command, 1);
+}
+
+static int
+bfd_mach_o_scan_write_symtab_symbols (bfd *abfd, bfd_mach_o_load_command *command)
 {
   bfd_mach_o_symtab_command *sym = &command->command.symtab;
   asymbol *s = NULL;
@@ -525,7 +635,11 @@ bfd_mach_o_write_contents (bfd *abfd)
       switch (cur->type)
        {
        case BFD_MACH_O_LC_SEGMENT:
-         if (bfd_mach_o_scan_write_segment (abfd, cur) != 0)
+         if (bfd_mach_o_scan_write_segment_32 (abfd, cur) != 0)
+           return FALSE;
+         break;
+       case BFD_MACH_O_LC_SEGMENT_64:
+         if (bfd_mach_o_scan_write_segment_64 (abfd, cur) != 0)
            return FALSE;
          break;
        case BFD_MACH_O_LC_SYMTAB:
@@ -557,7 +671,7 @@ bfd_mach_o_write_contents (bfd *abfd)
        default:
          fprintf (stderr,
                   "unable to write unknown load command 0x%lx\n",
-                  (long) cur->type);
+                  (unsigned long) cur->type);
          return FALSE;
        }
     }
@@ -567,7 +681,7 @@ bfd_mach_o_write_contents (bfd *abfd)
 
 static int
 bfd_mach_o_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
-                          bfd_boolean b ATTRIBUTE_UNUSED)
+                          struct bfd_link_info *info ATTRIBUTE_UNUSED)
 {
   return 0;
 }
@@ -590,24 +704,42 @@ bfd_mach_o_make_empty_symbol (bfd *abfd)
 static int
 bfd_mach_o_read_header (bfd *abfd, bfd_mach_o_header *header)
 {
-  unsigned char buf[28];
+  unsigned char buf[32];
+  unsigned int size;
   bfd_vma (*get32) (const void *) = NULL;
 
   bfd_seek (abfd, 0, SEEK_SET);
 
-  if (bfd_bread ((PTR) buf, 28, abfd) != 28)
+  /* Just read the magic number.  */
+  if (bfd_bread ((PTR) buf, 4, abfd) != 4)
     return -1;
 
   if (bfd_getb32 (buf) == 0xfeedface)
     {
       header->byteorder = BFD_ENDIAN_BIG;
       header->magic = 0xfeedface;
+      header->version = 1;
       get32 = bfd_getb32;
     }
   else if (bfd_getl32 (buf) == 0xfeedface)
     {
       header->byteorder = BFD_ENDIAN_LITTLE;
       header->magic = 0xfeedface;
+      header->version = 1;
+      get32 = bfd_getl32;
+    }
+  else if (bfd_getb32 (buf) == 0xfeedfacf)
+    {
+      header->byteorder = BFD_ENDIAN_BIG;
+      header->magic = 0xfeedfacf;
+      header->version = 2;
+      get32 = bfd_getb32;
+    }
+  else if (bfd_getl32 (buf) == 0xfeedfacf)
+    {
+      header->byteorder = BFD_ENDIAN_LITTLE;
+      header->magic = 0xfeedfacf;
+      header->version = 2;
       get32 = bfd_getl32;
     }
   else
@@ -616,6 +748,13 @@ bfd_mach_o_read_header (bfd *abfd, bfd_mach_o_header *header)
       return -1;
     }
 
+  /* Once the size of the header is known, read the full header.  */
+  size = (header->version == 2) ? 32 : 28;
+
+  bfd_seek (abfd, 0, SEEK_SET);
+  if (bfd_bread ((PTR) buf, size, abfd) != size)
+    return -1;
+
   header->cputype = (*get32) (buf + 4);
   header->cpusubtype = (*get32) (buf + 8);
   header->filetype = (*get32) (buf + 12);
@@ -623,6 +762,9 @@ bfd_mach_o_read_header (bfd *abfd, bfd_mach_o_header *header)
   header->sizeofcmds = (*get32) (buf + 20);
   header->flags = (*get32) (buf + 24);
 
+  if (header->version == 2)
+    header->reserved = (*get32) (buf + 28);
+
   return 0;
 }
 
@@ -633,6 +775,7 @@ bfd_mach_o_make_bfd_section (bfd *abfd, bfd_mach_o_section *section)
   char *sname;
   const char *prefix = "LC_SEGMENT";
   unsigned int snamelen;
+  flagword flags;
 
   snamelen = strlen (prefix) + 1
     + strlen (section->segname) + 1
@@ -643,7 +786,10 @@ bfd_mach_o_make_bfd_section (bfd *abfd, bfd_mach_o_section *section)
     return NULL;
   sprintf (sname, "%s.%s.%s", prefix, section->segname, section->sectname);
 
-  bfdsec = bfd_make_section_anyway (abfd, sname);
+  flags = SEC_ALLOC;
+  if ((section->flags & SECTION_TYPE) != BFD_MACH_O_S_ZEROFILL)
+    flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
+  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, flags);
   if (bfdsec == NULL)
     return NULL;
 
@@ -652,19 +798,15 @@ bfd_mach_o_make_bfd_section (bfd *abfd, bfd_mach_o_section *section)
   bfdsec->size = section->size;
   bfdsec->filepos = section->offset;
   bfdsec->alignment_power = section->align;
-
-  if (section->flags & BFD_MACH_O_S_ZEROFILL)
-    bfdsec->flags = SEC_ALLOC;
-  else
-    bfdsec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
+  bfdsec->segment_mark = 0;
 
   return bfdsec;
 }
 
 static int
-bfd_mach_o_scan_read_section (bfd *abfd,
-                             bfd_mach_o_section *section,
-                             bfd_vma offset)
+bfd_mach_o_scan_read_section_32 (bfd *abfd,
+                                bfd_mach_o_section *section,
+                                bfd_vma offset)
 {
   unsigned char buf[68];
 
@@ -685,6 +827,40 @@ bfd_mach_o_scan_read_section (bfd *abfd,
   section->flags = bfd_h_get_32 (abfd, buf + 56);
   section->reserved1 = bfd_h_get_32 (abfd, buf + 60);
   section->reserved2 = bfd_h_get_32 (abfd, buf + 64);
+  section->reserved3 = 0;
+  section->bfdsection = bfd_mach_o_make_bfd_section (abfd, section);
+
+  if (section->bfdsection == NULL)
+    return -1;
+
+  return 0;
+}
+
+static int
+bfd_mach_o_scan_read_section_64 (bfd *abfd,
+                                bfd_mach_o_section *section,
+                                bfd_vma offset)
+{
+  unsigned char buf[80];
+
+  bfd_seek (abfd, offset, SEEK_SET);
+  if (bfd_bread ((PTR) buf, 80, abfd) != 80)
+    return -1;
+
+  memcpy (section->sectname, buf, 16);
+  section->sectname[16] = '\0';
+  memcpy (section->segname, buf + 16, 16);
+  section->segname[16] = '\0';
+  section->addr = bfd_h_get_64 (abfd, buf + 32);
+  section->size = bfd_h_get_64 (abfd, buf + 40);
+  section->offset = bfd_h_get_32 (abfd, buf + 48);
+  section->align = bfd_h_get_32 (abfd, buf + 52);
+  section->reloff = bfd_h_get_32 (abfd, buf + 56);
+  section->nreloc = bfd_h_get_32 (abfd, buf + 60);
+  section->flags = bfd_h_get_32 (abfd, buf + 64);
+  section->reserved1 = bfd_h_get_32 (abfd, buf + 68);
+  section->reserved2 = bfd_h_get_32 (abfd, buf + 72);
+  section->reserved3 = bfd_h_get_32 (abfd, buf + 76);
   section->bfdsection = bfd_mach_o_make_bfd_section (abfd, section);
 
   if (section->bfdsection == NULL)
@@ -693,6 +869,18 @@ bfd_mach_o_scan_read_section (bfd *abfd,
   return 0;
 }
 
+static int
+bfd_mach_o_scan_read_section (bfd *abfd,
+                             bfd_mach_o_section *section,
+                             bfd_vma offset,
+                             unsigned int wide)
+{
+  if (wide)
+    return bfd_mach_o_scan_read_section_64 (abfd, section, offset);
+  else
+    return bfd_mach_o_scan_read_section_32 (abfd, section, offset);
+}
+
 int
 bfd_mach_o_scan_read_symtab_symbol (bfd *abfd,
                                    bfd_mach_o_symtab_command *sym,
@@ -700,22 +888,24 @@ bfd_mach_o_scan_read_symtab_symbol (bfd *abfd,
                                    unsigned long i)
 {
   bfd_mach_o_data_struct *mdata = abfd->tdata.mach_o_data;
-  bfd_vma symoff = sym->symoff + (i * 12);
-  unsigned char buf[12];
+  unsigned int wide = (mdata->header.version == 2);
+  unsigned int symwidth = wide ? 16 : 12;
+  bfd_vma symoff = sym->symoff + (i * symwidth);
+  unsigned char buf[16];
   unsigned char type = -1;
   unsigned char section = -1;
   short desc = -1;
-  unsigned long value = -1;
+  symvalue value = -1;
   unsigned long stroff = -1;
   unsigned int symtype = -1;
 
   BFD_ASSERT (sym->strtab != NULL);
 
   bfd_seek (abfd, symoff, SEEK_SET);
-  if (bfd_bread ((PTR) buf, 12, abfd) != 12)
+  if (bfd_bread ((PTR) buf, symwidth, abfd) != symwidth)
     {
       fprintf (stderr, "bfd_mach_o_scan_read_symtab_symbol: unable to read %d bytes at %lu\n",
-              12, (unsigned long) symoff);
+              symwidth, (unsigned long) symoff);
       return -1;
     }
 
@@ -724,7 +914,10 @@ bfd_mach_o_scan_read_symtab_symbol (bfd *abfd,
   symtype = (type & 0x0e);
   section = bfd_h_get_8 (abfd, buf + 5) - 1;
   desc = bfd_h_get_16 (abfd, buf + 6);
-  value = bfd_h_get_32 (abfd, buf + 8);
+  if (wide)
+    value = bfd_h_get_64 (abfd, buf + 8);
+  else
+    value = bfd_h_get_32 (abfd, buf + 8);
 
   if (stroff >= sym->strsize)
     {
@@ -772,8 +965,8 @@ bfd_mach_o_scan_read_symtab_symbol (bfd *abfd,
        case BFD_MACH_O_N_SECT:
          if ((section > 0) && (section <= mdata->nsects))
            {
-             s->section = mdata->sections[section - 1]->bfdsection;
-             s->value = s->value - mdata->sections[section - 1]->addr;
+             s->section = mdata->sections[section]->bfdsection;
+             s->value = s->value - mdata->sections[section]->addr;
            }
          else
            {
@@ -965,7 +1158,7 @@ bfd_mach_o_scan_read_dylinker (bfd *abfd,
     return -1;
   strcpy (sname, prefix);
 
-  bfdsec = bfd_make_section_anyway (abfd, sname);
+  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, SEC_HAS_CONTENTS);
   if (bfdsec == NULL)
     return -1;
 
@@ -974,7 +1167,6 @@ bfd_mach_o_scan_read_dylinker (bfd *abfd,
   bfdsec->size = command->len - 8;
   bfdsec->filepos = command->offset + 8;
   bfdsec->alignment_power = 0;
-  bfdsec->flags = SEC_HAS_CONTENTS;
 
   cmd->section = bfdsec;
 
@@ -1021,7 +1213,7 @@ bfd_mach_o_scan_read_dylib (bfd *abfd, bfd_mach_o_load_command *command)
     return -1;
   strcpy (sname, prefix);
 
-  bfdsec = bfd_make_section_anyway (abfd, sname);
+  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, SEC_HAS_CONTENTS);
   if (bfdsec == NULL)
     return -1;
 
@@ -1030,7 +1222,6 @@ bfd_mach_o_scan_read_dylib (bfd *abfd, bfd_mach_o_load_command *command)
   bfdsec->size = command->len - 8;
   bfdsec->filepos = command->offset + 8;
   bfdsec->alignment_power = 0;
-  bfdsec->flags = SEC_HAS_CONTENTS;
 
   cmd->section = bfdsec;
 
@@ -1118,9 +1309,11 @@ bfd_mach_o_scan_read_thread (bfd *abfd, bfd_mach_o_load_command *command)
       switch (mdata->header.cputype)
        {
        case BFD_MACH_O_CPU_TYPE_POWERPC:
+       case BFD_MACH_O_CPU_TYPE_POWERPC_64:
          flavourstr = bfd_mach_o_ppc_flavour_string (cmd->flavours[i].flavour);
          break;
        case BFD_MACH_O_CPU_TYPE_I386:
+       case BFD_MACH_O_CPU_TYPE_X86_64:
          flavourstr = bfd_mach_o_i386_flavour_string (cmd->flavours[i].flavour);
          break;
        default:
@@ -1141,14 +1334,13 @@ bfd_mach_o_scan_read_thread (bfd *abfd, bfd_mach_o_load_command *command)
          j++;
        }
 
-      bfdsec = bfd_make_section (abfd, sname);
+      bfdsec = bfd_make_section_with_flags (abfd, sname, SEC_HAS_CONTENTS);
 
       bfdsec->vma = 0;
       bfdsec->lma = 0;
       bfdsec->size = cmd->flavours[i].size;
       bfdsec->filepos = cmd->flavours[i].offset;
       bfdsec->alignment_power = 0x0;
-      bfdsec->flags = SEC_HAS_CONTENTS;
 
       cmd->section = bfdsec;
     }
@@ -1198,6 +1390,7 @@ bfd_mach_o_scan_read_symtab (bfd *abfd, bfd_mach_o_load_command *command)
   asection *bfdsec;
   char *sname;
   const char *prefix = "LC_SYMTAB.stabs";
+  int nlist_size = (bfd_mach_o_version (abfd) > 1) ? 16 : 12;
 
   BFD_ASSERT (command->type == BFD_MACH_O_LC_SYMTAB);
 
@@ -1217,16 +1410,15 @@ bfd_mach_o_scan_read_symtab (bfd *abfd, bfd_mach_o_load_command *command)
     return -1;
   strcpy (sname, prefix);
 
-  bfdsec = bfd_make_section_anyway (abfd, sname);
+  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, SEC_HAS_CONTENTS);
   if (bfdsec == NULL)
     return -1;
 
   bfdsec->vma = 0;
   bfdsec->lma = 0;
-  bfdsec->size = seg->nsyms * 12;
+  bfdsec->size = seg->nsyms * nlist_size;
   bfdsec->filepos = seg->symoff;
   bfdsec->alignment_power = 0;
-  bfdsec->flags = SEC_HAS_CONTENTS;
 
   seg->stabs_segment = bfdsec;
 
@@ -1236,7 +1428,7 @@ bfd_mach_o_scan_read_symtab (bfd *abfd, bfd_mach_o_load_command *command)
     return -1;
   strcpy (sname, prefix);
 
-  bfdsec = bfd_make_section_anyway (abfd, sname);
+  bfdsec = bfd_make_section_anyway_with_flags (abfd, sname, SEC_HAS_CONTENTS);
   if (bfdsec == NULL)
     return -1;
 
@@ -1245,7 +1437,6 @@ bfd_mach_o_scan_read_symtab (bfd *abfd, bfd_mach_o_load_command *command)
   bfdsec->size = seg->strsize;
   bfdsec->filepos = seg->stroff;
   bfdsec->alignment_power = 0;
-  bfdsec->flags = SEC_HAS_CONTENTS;
 
   seg->stabstr_segment = bfdsec;
 
@@ -1253,9 +1444,11 @@ bfd_mach_o_scan_read_symtab (bfd *abfd, bfd_mach_o_load_command *command)
 }
 
 static int
-bfd_mach_o_scan_read_segment (bfd *abfd, bfd_mach_o_load_command *command)
+bfd_mach_o_scan_read_segment (bfd *abfd,
+                             bfd_mach_o_load_command *command,
+                             unsigned int wide)
 {
-  unsigned char buf[48];
+  unsigned char buf[64];
   bfd_mach_o_segment_command *seg = &command->command.segment;
   unsigned long i;
   asection *bfdsec;
@@ -1263,21 +1456,44 @@ bfd_mach_o_scan_read_segment (bfd *abfd, bfd_mach_o_load_command *command)
   const char *prefix = "LC_SEGMENT";
   unsigned int snamelen;
 
-  BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT);
+  if (wide)
+    {
+      BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT_64);
 
-  bfd_seek (abfd, command->offset + 8, SEEK_SET);
-  if (bfd_bread ((PTR) buf, 48, abfd) != 48)
-    return -1;
+      bfd_seek (abfd, command->offset + 8, SEEK_SET);
+      if (bfd_bread ((PTR) buf, 64, abfd) != 64)
+       return -1;
+
+      memcpy (seg->segname, buf, 16);
+
+      seg->vmaddr = bfd_h_get_64 (abfd, buf + 16);
+      seg->vmsize = bfd_h_get_64 (abfd, buf + 24);
+      seg->fileoff = bfd_h_get_64 (abfd, buf + 32);
+      seg->filesize = bfd_h_get_64 (abfd, buf + 40);
+      seg->maxprot = bfd_h_get_32 (abfd, buf + 48);
+      seg->initprot = bfd_h_get_32 (abfd, buf + 52);
+      seg->nsects = bfd_h_get_32 (abfd, buf + 56);
+      seg->flags = bfd_h_get_32 (abfd, buf + 60);
+    }
+  else
+    {
+      BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT);
+
+      bfd_seek (abfd, command->offset + 8, SEEK_SET);
+      if (bfd_bread ((PTR) buf, 48, abfd) != 48)
+       return -1;
 
-  memcpy (seg->segname, buf, 16);
-  seg->vmaddr = bfd_h_get_32 (abfd, buf + 16);
-  seg->vmsize = bfd_h_get_32 (abfd, buf + 20);
-  seg->fileoff = bfd_h_get_32 (abfd, buf + 24);
-  seg->filesize = bfd_h_get_32 (abfd, buf +  28);
-  /* seg->maxprot = bfd_h_get_32 (abfd, buf + 32); */
-  /* seg->initprot = bfd_h_get_32 (abfd, buf + 36); */
-  seg->nsects = bfd_h_get_32 (abfd, buf + 40);
-  seg->flags = bfd_h_get_32 (abfd, buf + 44);
+      memcpy (seg->segname, buf, 16);
+
+      seg->vmaddr = bfd_h_get_32 (abfd, buf + 16);
+      seg->vmsize = bfd_h_get_32 (abfd, buf + 20);
+      seg->fileoff = bfd_h_get_32 (abfd, buf + 24);
+      seg->filesize = bfd_h_get_32 (abfd, buf +  28);
+      seg->maxprot = bfd_h_get_32 (abfd, buf + 32);
+      seg->initprot = bfd_h_get_32 (abfd, buf + 36);
+      seg->nsects = bfd_h_get_32 (abfd, buf + 40);
+      seg->flags = bfd_h_get_32 (abfd, buf + 44);
+    }
 
   snamelen = strlen (prefix) + 1 + strlen (seg->segname) + 1;
   sname = bfd_alloc (abfd, snamelen);
@@ -1295,6 +1511,7 @@ bfd_mach_o_scan_read_segment (bfd *abfd, bfd_mach_o_load_command *command)
   bfdsec->filepos = seg->fileoff;
   bfdsec->alignment_power = 0x0;
   bfdsec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
+  bfdsec->segment_mark = 1;
 
   seg->segment = bfdsec;
 
@@ -1306,10 +1523,14 @@ bfd_mach_o_scan_read_segment (bfd *abfd, bfd_mach_o_load_command *command)
 
       for (i = 0; i < seg->nsects; i++)
        {
-         bfd_vma segoff = command->offset + 48 + 8 + (i * 68);
+         bfd_vma segoff;
+         if (wide)
+           segoff = command->offset + 64 + 8 + (i * 80);
+         else
+           segoff = command->offset + 48 + 8 + (i * 68);
 
-         if (bfd_mach_o_scan_read_section (abfd, &seg->sections[i],
-                                           segoff) != 0)
+         if (bfd_mach_o_scan_read_section
+             (abfd, &seg->sections[i], segoff, wide) != 0)
            return -1;
        }
     }
@@ -1317,6 +1538,18 @@ bfd_mach_o_scan_read_segment (bfd *abfd, bfd_mach_o_load_command *command)
   return 0;
 }
 
+static int
+bfd_mach_o_scan_read_segment_32 (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  return bfd_mach_o_scan_read_segment (abfd, command, 0);
+}
+
+static int
+bfd_mach_o_scan_read_segment_64 (bfd *abfd, bfd_mach_o_load_command *command)
+{
+  return bfd_mach_o_scan_read_segment (abfd, command, 1);
+}
+
 static int
 bfd_mach_o_scan_read_command (bfd *abfd, bfd_mach_o_load_command *command)
 {
@@ -1334,7 +1567,11 @@ bfd_mach_o_scan_read_command (bfd *abfd, bfd_mach_o_load_command *command)
   switch (command->type)
     {
     case BFD_MACH_O_LC_SEGMENT:
-      if (bfd_mach_o_scan_read_segment (abfd, command) != 0)
+      if (bfd_mach_o_scan_read_segment_32 (abfd, command) != 0)
+       return -1;
+      break;
+    case BFD_MACH_O_LC_SEGMENT_64:
+      if (bfd_mach_o_scan_read_segment_64 (abfd, command) != 0)
        return -1;
       break;
     case BFD_MACH_O_LC_SYMTAB:
@@ -1401,7 +1638,8 @@ bfd_mach_o_flatten_sections (bfd *abfd)
 
   for (i = 0; i < mdata->header.ncmds; i++)
     {
-      if (mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT)
+      if (mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT
+         || mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT_64)
        {
          bfd_mach_o_segment_command *seg;
 
@@ -1416,7 +1654,8 @@ bfd_mach_o_flatten_sections (bfd *abfd)
 
   for (i = 0; i < mdata->header.ncmds; i++)
     {
-      if (mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT)
+      if (mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT
+         || mdata->commands[i].type == BFD_MACH_O_LC_SEGMENT_64)
        {
          bfd_mach_o_segment_command *seg;
 
@@ -1478,6 +1717,30 @@ bfd_mach_o_scan_start_address (bfd *abfd)
 
          abfd->start_address = bfd_h_get_32 (abfd, buf);
        }
+      else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_POWERPC_64)
+               && (cmd->flavours[i].flavour == BFD_MACH_O_PPC_THREAD_STATE_64))
+        {
+          unsigned char buf[8];
+
+          bfd_seek (abfd, cmd->flavours[i].offset + 0, SEEK_SET);
+
+          if (bfd_bread (buf, 8, abfd) != 8)
+            return -1;
+
+          abfd->start_address = bfd_h_get_64 (abfd, buf);
+        }
+      else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_X86_64)
+               && (cmd->flavours[i].flavour == BFD_MACH_O_x86_THREAD_STATE64))
+        {
+          unsigned char buf[8];
+
+          bfd_seek (abfd, cmd->flavours[i].offset + (16 * 8), SEEK_SET);
+
+          if (bfd_bread (buf, 8, abfd) != 8)
+            return -1;
+
+          abfd->start_address = bfd_h_get_64 (abfd, buf);
+        }
     }
 
   return 0;
@@ -1491,6 +1754,9 @@ bfd_mach_o_scan (bfd *abfd,
   unsigned int i;
   enum bfd_architecture cputype;
   unsigned long cpusubtype;
+  unsigned int hdrsize;
+
+  hdrsize = (header->version == 2) ? 32 : 28;
 
   mdata->header = *header;
   mdata->symbols = NULL;
@@ -1521,7 +1787,7 @@ bfd_mach_o_scan (bfd *abfd,
          bfd_mach_o_load_command *cur = &mdata->commands[i];
 
          if (i == 0)
-           cur->offset = 28;
+           cur->offset = hdrsize;
          else
            {
              bfd_mach_o_load_command *prev = &mdata->commands[i - 1];
@@ -1582,7 +1848,7 @@ bfd_mach_o_object_p (bfd *abfd)
         || header.byteorder == BFD_ENDIAN_LITTLE))
     {
       fprintf (stderr, "unknown header byte-order value 0x%lx\n",
-              (long) header.byteorder);
+              (unsigned long) header.byteorder);
       goto wrong;
     }
 
@@ -1629,7 +1895,7 @@ bfd_mach_o_core_p (bfd *abfd)
         || header.byteorder == BFD_ENDIAN_LITTLE))
     {
       fprintf (stderr, "unknown header byte-order value 0x%lx\n",
-              (long) header.byteorder);
+              (unsigned long) header.byteorder);
       abort ();
     }
 
@@ -1810,7 +2076,8 @@ bfd_mach_o_lookup_section (bfd *abfd,
       struct bfd_mach_o_load_command *cmd = &md->commands[i];
       struct bfd_mach_o_segment_command *seg = NULL;
 
-      if (cmd->type != BFD_MACH_O_LC_SEGMENT)
+      if (cmd->type != BFD_MACH_O_LC_SEGMENT
+         || cmd->type != BFD_MACH_O_LC_SEGMENT_64)
        continue;
       seg = &cmd->command.segment;
 
@@ -1929,13 +2196,18 @@ bfd_mach_o_core_fetch_environment (bfd *abfd,
              if (size > (end - start))
                size = (end - start);
 
-             buf = bfd_realloc (buf, size);
-
+             buf = bfd_realloc_or_free (buf, size);
+             if (buf == NULL)
+               return -1;
+             
              bfd_seek (abfd, end - size, SEEK_SET);
              nread = bfd_bread (buf, size, abfd);
 
              if (nread != size)
-               return -1;
+               {
+                 free (buf);
+                 return -1;
+               }
 
              for (offset = 4; offset <= size; offset += 4)
                {
@@ -1958,6 +2230,7 @@ bfd_mach_o_core_fetch_environment (bfd *abfd,
                      *rlen = top - bottom;
 
                      memcpy (*rbuf, buf + size - *rlen, *rlen);
+                     free (buf);
                      return 0;
                    }
                }
@@ -1967,6 +2240,8 @@ bfd_mach_o_core_fetch_environment (bfd *abfd,
 
              size *= 2;
            }
+
+         free (buf);
        }
     }
 
@@ -1993,13 +2268,6 @@ bfd_mach_o_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
   return 0;
 }
 
-bfd_boolean
-bfd_mach_o_core_file_matches_executable_p (bfd *core_bfd ATTRIBUTE_UNUSED,
-                                          bfd *exec_bfd ATTRIBUTE_UNUSED)
-{
-  return TRUE;
-}
-
 #define TARGET_NAME            mach_o_be_vec
 #define TARGET_STRING          "mach-o-be"
 #define TARGET_BIG_ENDIAN      1