]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Mach-O: Add objdump -P dyld_info to dump dyld data.
authorTristan Gingold <tristan.gingold@adacore.com>
Fri, 11 Apr 2014 15:10:03 +0000 (17:10 +0200)
committerTristan Gingold <tristan.gingold@adacore.com>
Wed, 16 Apr 2014 10:16:02 +0000 (12:16 +0200)
include/mach-o/
* loader.h: Add macros for rebase, bind and export constants.

binutils/
* od-macho.c (OPT_DYLD_INFO): New macro.
(options): Add entry for dyld_info.
(mach_o_help): Likewise.
(load_and_dump, dump_dyld_info_rebase, dump_dyld_info_bind)
(dump_dyld_info_export_1, dump_dyld_info_export): New functions.
(bfd_mach_o_dyld_rebase_type_name): New array.
(export_info_data): New struct.
(dump_dyld_info): Add verbose argument.  Dump rebase, bind and
exports data.
(dump_load_command): Adjust dump_dyld_info call.
(mach_o_dump): Handle dyld_info.

binutils/ChangeLog
binutils/od-macho.c
include/mach-o/ChangeLog
include/mach-o/loader.h

index 02931b78d6e5711d6221a8cb9d2fecab4306de10..ddf72934f6a10c9e37e64b6a34aedb3e072832b3 100644 (file)
@@ -1,3 +1,17 @@
+2014-04-16  Tristan Gingold  <gingold@adacore.com>
+
+       * od-macho.c (OPT_DYLD_INFO): New macro.
+       (options): Add entry for dyld_info.
+       (mach_o_help): Likewise.
+       (load_and_dump, dump_dyld_info_rebase, dump_dyld_info_bind)
+       (dump_dyld_info_export_1, dump_dyld_info_export): New functions.
+       (bfd_mach_o_dyld_rebase_type_name): New array.
+       (export_info_data): New struct.
+       (dump_dyld_info): Add verbose argument.  Dump rebase, bind and
+       exports data.
+       (dump_load_command): Adjust dump_dyld_info call.
+       (mach_o_dump): Handle dyld_info.
+
 2014-04-16  Tristan Gingold  <gingold@adacore.com>
 
        * od-macho.c (dump_header): Display sizeofcmds in decimal too.
index 92d6a73322f49a3f5607b8e9c92284e9dea8aff7..bf90f090ebe41b9a4770f7d0ba422f9d69a68ea3 100644 (file)
@@ -45,6 +45,7 @@
 #define OPT_FUNCTION_STARTS 8
 #define OPT_DATA_IN_CODE 9
 #define OPT_TWOLEVEL_HINTS 10
+#define OPT_DYLD_INFO 11
 
 /* List of actions.  */
 static struct objdump_private_option options[] =
@@ -60,6 +61,7 @@ static struct objdump_private_option options[] =
     { "function_starts", 0 },
     { "data_in_code", 0 },
     { "twolevel_hints", 0 },
+    { "dyld_info", 0 },
     { NULL, 0 }
   };
 
@@ -81,6 +83,7 @@ For Mach-O files:\n\
   function_starts  Display start address of functions\n\
   data_in_code     Display data in code entries\n\
   twolevel_hints   Display the two-level namespace lookup hints table\n\
+  dyld_info        Display dyld information\n\
 "));
 }
 
@@ -622,8 +625,319 @@ dump_dysymtab (bfd *abfd, bfd_mach_o_load_command *cmd, bfd_boolean verbose)
 
 }
 
+static bfd_boolean
+load_and_dump (bfd *abfd, ufile_ptr off, unsigned int len,
+              void (*dump)(bfd *abfd, unsigned char *buf, unsigned int len,
+                           ufile_ptr off))
+{
+  unsigned char *buf;
+
+  if (len == 0)
+    return TRUE;
+
+  buf = xmalloc (len);
+
+  if (bfd_seek (abfd, off, SEEK_SET) == 0
+      && bfd_bread (buf, len, abfd) == len)
+    dump (abfd, buf, len, off);
+  else
+    return FALSE;
+
+  free (buf);
+  return TRUE;
+}
+
+static const bfd_mach_o_xlat_name bfd_mach_o_dyld_rebase_type_name[] =
+{
+  { "pointer",      BFD_MACH_O_REBASE_TYPE_POINTER },
+  { "text_abs32",   BFD_MACH_O_REBASE_TYPE_TEXT_ABSOLUTE32 },
+  { "text_pcrel32", BFD_MACH_O_REBASE_TYPE_TEXT_PCREL32 },
+  { NULL, 0 }
+};
+
+static void
+dump_dyld_info_rebase (bfd *abfd, unsigned char *buf, unsigned int len,
+                      ufile_ptr off ATTRIBUTE_UNUSED)
+{
+  unsigned int i;
+  bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+  unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+  for (i = 0; i < len; )
+    {
+      unsigned char b = buf[i++];
+      unsigned char imm = b & BFD_MACH_O_REBASE_IMMEDIATE_MASK;
+      bfd_vma leb;
+      unsigned int leblen;
+
+      printf ("   [0x%04x] 0x%02x: ", i, b);
+      switch (b & BFD_MACH_O_REBASE_OPCODE_MASK)
+       {
+       case BFD_MACH_O_REBASE_OPCODE_DONE:
+         printf ("done\n");
+         return;
+       case BFD_MACH_O_REBASE_OPCODE_SET_TYPE_IMM:
+         printf ("set_type %s\n",
+                 bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("set segment: %u and offset: 0x%08x\n",
+                 imm, (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+         printf ("add addr imm scaled: %u\n", imm * ptrsize);
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+         printf ("rebase imm times: %u\n", imm);
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("rebase uleb times: %u\n", (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("rebase add addr uleb: %u\n", (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("rebase uleb times (%u)", (unsigned) leb);
+         i += leblen;
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf (" skipping uleb (%u)\n", (unsigned) leb);
+         i += leblen;
+         break;
+       default:
+         printf ("unknown\n");
+         return;
+       }
+    }
+  printf ("   rebase commands without end!\n");
+}
+
+static void
+dump_dyld_info_bind (bfd *abfd, unsigned char *buf, unsigned int len,
+                    ufile_ptr off ATTRIBUTE_UNUSED)
+{
+  unsigned int i;
+  bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+  unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+  for (i = 0; i < len; )
+    {
+      unsigned char b = buf[i++];
+      unsigned char imm = b & BFD_MACH_O_BIND_IMMEDIATE_MASK;
+      bfd_vma leb;
+      unsigned int leblen;
+
+      printf ("   [0x%04x] 0x%02x: ", i, b);
+      switch (b & BFD_MACH_O_BIND_OPCODE_MASK)
+       {
+       case BFD_MACH_O_BIND_OPCODE_DONE:
+         printf ("done\n");
+         return;
+       case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+         printf ("set dylib ordinal imm: %u\n", imm);
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("set dylib ordinal uleb: %u\n", imm);
+         i += leblen;
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+         imm = (imm != 0) ? imm | BFD_MACH_O_BIND_OPCODE_MASK : imm;
+         printf ("set dylib special imm: %d\n", imm);
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+         printf ("set symbol trailing flags imm: 0x%02x, ", imm);
+         for (; i < len && buf[i] != 0; i++)
+           putchar (buf[i] >= ' ' && buf[i] < 0x7f ? buf[i] : '?');
+         putchar ('\n');
+         i++;
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_TYPE_IMM:
+         /* Kludge: use the same table as rebase type.  */
+         printf ("set_type %s\n",
+                 bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_ADDEND_SLEB:
+         {
+           bfd_signed_vma svma;
+           svma = read_unsigned_leb128 (abfd, buf + i, &leblen);
+           printf ("set addend sleb: 0x%08x\n", (unsigned) svma);
+           i += leblen;
+         }
+         break;
+       case BFD_MACH_O_BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("set segment: %u and offset: 0x%08x\n",
+                 imm, (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_BIND_OPCODE_ADD_ADDR_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_BIND_OPCODE_DO_BIND:
+         printf ("do bind\n");
+         break;
+       case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("do bind add addr uleb: 0x%08x\n", (unsigned) leb);
+         i += leblen;
+         break;
+       case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+         printf ("do bind add addr imm scaled: %u\n", imm * ptrsize);
+         break;
+       case BFD_MACH_O_BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf ("do bind uleb times (%u)", (unsigned) leb);
+         i += leblen;
+         leb = read_unsigned_leb128 (abfd, buf + i, &leblen);
+         printf (" skipping uleb (%u)\n", (unsigned) leb);
+         i += leblen;
+         break;
+       default:
+         printf ("unknown\n");
+         return;
+       }
+    }
+  printf ("   bind commands without end!\n");
+}
+
+struct export_info_data
+{
+  const unsigned char *name;
+  struct export_info_data *next;
+};
+
 static void
-dump_dyld_info (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd)
+dump_dyld_info_export_1 (bfd *abfd, unsigned char *buf, unsigned int len,
+                        unsigned int off, struct export_info_data *parent,
+                        struct export_info_data *base)
+{
+  bfd_vma size;
+  unsigned int leblen;
+  unsigned int child_count;
+  unsigned int i;
+
+  size = read_unsigned_leb128 (abfd, buf + off, &leblen);
+  off += leblen;
+
+  if (size != 0)
+    {
+      bfd_vma flags;
+      struct export_info_data *d;
+
+      flags = read_unsigned_leb128 (abfd, buf + off, &leblen);
+      off += leblen;
+
+      fputs ("   ", stdout);
+      switch (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_MASK)
+       {
+       case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
+         putchar ('-');
+         break;
+       case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
+         putchar ('T');
+         break;
+       default:
+         putchar ('?');
+         break;
+       }
+      putchar ((flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION) ?
+              'W' : '-');
+
+      if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_REEXPORT)
+       {
+         bfd_vma lib;
+
+         lib = read_unsigned_leb128 (abfd, buf + off, &leblen);
+         off += leblen;
+
+         fputs (" [reexport] ", stdout);
+         for (d = base; d != NULL; d = d->next)
+           printf ("%s", d->name);
+
+         fputs (" (", stdout);
+         if (buf[off] != 0)
+           {
+             fputs ((const char *)buf + off, stdout);
+             putchar (' ');
+             off += strlen ((const char *)buf + off);
+           }
+         printf ("from dylib %u)\n", (unsigned) lib);
+         off++;
+       }
+      else
+       {
+         bfd_vma offset;
+         bfd_vma resolv = 0;
+
+         offset = read_unsigned_leb128 (abfd, buf + off, &leblen);
+         off += leblen;
+
+         if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+           {
+             resolv = read_unsigned_leb128 (abfd, buf + off, &leblen);
+             off += leblen;
+           }
+
+         printf (" 0x%08x ", (unsigned) offset);
+         for (d = base; d != NULL; d = d->next)
+           printf ("%s", d->name);
+         if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+           printf (" [resolv: 0x%08x]", (unsigned) resolv);
+         printf ("\n");
+       }
+    }
+
+  child_count = read_unsigned_leb128 (abfd, buf + off, &leblen);
+  off += leblen;
+
+  for (i = 0; i < child_count; i++)
+    {
+      struct export_info_data sub_data;
+      bfd_vma sub_off;
+
+      sub_data.name = buf + off;
+      sub_data.next = NULL;
+      parent->next = &sub_data;
+
+      off += strlen ((const char *)buf + off) + 1;
+
+      sub_off = read_unsigned_leb128 (abfd, buf + off, &leblen);
+      off += leblen;
+
+      dump_dyld_info_export_1 (abfd, buf, len, sub_off, &sub_data, base);
+    }
+}
+
+static void
+dump_dyld_info_export (bfd *abfd, unsigned char *buf, unsigned int len,
+                      ufile_ptr off ATTRIBUTE_UNUSED)
+{
+  struct export_info_data data;
+
+  data.name = (const unsigned char *) "";
+  data.next = NULL;
+
+  printf ("   fl offset     sym        (Flags: Tls Weak)\n");
+  dump_dyld_info_export_1 (abfd, buf, len, 0, &data, &data);
+}
+
+static void
+dump_dyld_info (bfd *abfd, bfd_mach_o_load_command *cmd,
+               bfd_boolean verbose)
 {
   bfd_mach_o_dyld_info_command *info = &cmd->command.dyld_info;
 
@@ -642,6 +956,34 @@ dump_dyld_info (bfd *abfd ATTRIBUTE_UNUSED, bfd_mach_o_load_command *cmd)
   printf ("       export: off: 0x%08x  size: %-8u   (endoff: 0x%08x)\n",
          info->export_off, info->export_size,
          info->export_off + info->export_size);
+
+  if (!verbose)
+    return;
+
+  printf ("   rebase:\n");
+  if (!load_and_dump (abfd, info->rebase_off, info->rebase_size,
+                     dump_dyld_info_rebase))
+    non_fatal (_("cannot read rebase dyld info"));
+
+  printf ("   bind:\n");
+  if (!load_and_dump (abfd, info->bind_off, info->bind_size,
+                     dump_dyld_info_bind))
+    non_fatal (_("cannot read bind dyld info"));
+
+  printf ("   weak bind:\n");
+  if (!load_and_dump (abfd, info->weak_bind_off, info->weak_bind_size,
+                     dump_dyld_info_bind))
+    non_fatal (_("cannot read weak bind dyld info"));
+
+  printf ("   lazy bind:\n");
+  if (!load_and_dump (abfd, info->lazy_bind_off, info->lazy_bind_size,
+                     dump_dyld_info_bind))
+    non_fatal (_("cannot read lazy bind dyld info"));
+
+  printf ("   exported symbols:\n");
+  if (!load_and_dump (abfd, info->export_off, info->export_size,
+                     dump_dyld_info_export))
+    non_fatal (_("cannot read export symbols dyld info"));
 }
 
 static void
@@ -1219,16 +1561,15 @@ dump_load_command (bfd *abfd, bfd_mach_o_load_command *cmd,
       {
         bfd_mach_o_encryption_info_command *cryp =
           &cmd->command.encryption_info;
-        printf
-          ("  cryptoff: 0x%08x  cryptsize: 0x%08x (endoff 0x%08x)"
-           " cryptid: %u\n",
-           cryp->cryptoff, cryp->cryptsize,
-           cryp->cryptoff + cryp->cryptsize,
-           cryp->cryptid);
+        printf ("  cryptoff: 0x%08x  cryptsize: 0x%08x (endoff 0x%08x)"
+               " cryptid: %u\n",
+               cryp->cryptoff, cryp->cryptsize,
+               cryp->cryptoff + cryp->cryptsize,
+               cryp->cryptid);
       }
       break;
     case BFD_MACH_O_LC_DYLD_INFO:
-      dump_dyld_info (abfd, cmd);
+      dump_dyld_info (abfd, cmd, verbose);
       break;
     case BFD_MACH_O_LC_VERSION_MIN_MACOSX:
     case BFD_MACH_O_LC_VERSION_MIN_IPHONEOS:
@@ -1791,6 +2132,8 @@ mach_o_dump (bfd *abfd)
       dump_section_content (abfd, "__TEXT", "__unwind_info",
                            dump_exe_compact_unwind);
     }
+  if (options[OPT_DYLD_INFO].selected)
+    dump_load_commands (abfd, BFD_MACH_O_LC_DYLD_INFO, 0);
 }
 
 /* Vector for Mach-O.  */
index 0f2721a41641bf92c46c01d9622d5a2e7ce70d30..7adbc497683e97b5631e7eb5bdd18d6a911bd94e 100644 (file)
@@ -1,3 +1,7 @@
+2014-04-16  Tristan Gingold  <gingold@adacore.com>
+
+       * loader.h: Add macros for rebase, bind and export constants.
+
 2014-04-16  Tristan Gingold  <gingold@adacore.com>
 
        * loader.h (BFD_MACH_O_CPU_ARCH_MASK, BFD_MACH_O_CPU_ARCH_ABI64)
index 20cfe42cf47e936acd465f51ca38b4f8df8024ea..ff794a3b939960e45ec59b0014b17f3e9a830a48 100644 (file)
@@ -342,6 +342,63 @@ bfd_mach_o_section_attribute;
 #define BFD_MACH_O_INDIRECT_SYM_LOCAL                  0x80000000
 #define BFD_MACH_O_INDIRECT_SYM_ABS                    0x40000000
 \f
+/* Constants for dyld info rebase.  */
+#define BFD_MACH_O_REBASE_OPCODE_MASK     0xf0
+#define BFD_MACH_O_REBASE_IMMEDIATE_MASK  0x0f
+
+/* The rebase opcodes.  */
+#define BFD_MACH_O_REBASE_OPCODE_DONE                               0x00
+#define BFD_MACH_O_REBASE_OPCODE_SET_TYPE_IMM                       0x10
+#define BFD_MACH_O_REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB        0x20
+#define BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_ULEB                      0x30
+#define BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_IMM_SCALED                0x40
+#define BFD_MACH_O_REBASE_OPCODE_DO_REBASE_IMM_TIMES                0x50
+#define BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES               0x60
+#define BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB            0x70
+#define BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB 0x80
+
+/* The rebase type.  */
+#define BFD_MACH_O_REBASE_TYPE_POINTER            1
+#define BFD_MACH_O_REBASE_TYPE_TEXT_ABSOLUTE32    2
+#define BFD_MACH_O_REBASE_TYPE_TEXT_PCREL32       3
+
+/* Constants for dyld info bind.  */
+#define BFD_MACH_O_BIND_OPCODE_MASK    0xf0
+#define BFD_MACH_O_BIND_IMMEDIATE_MASK 0x0f
+
+/* The bind opcodes.  */
+#define BFD_MACH_O_BIND_OPCODE_DONE                             0x00
+#define BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_IMM            0x10
+#define BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB           0x20
+#define BFD_MACH_O_BIND_OPCODE_SET_DYLIB_SPECIAL_IMM            0x30
+#define BFD_MACH_O_BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM    0x40
+#define BFD_MACH_O_BIND_OPCODE_SET_TYPE_IMM                     0x50
+#define BFD_MACH_O_BIND_OPCODE_SET_ADDEND_SLEB                  0x60
+#define BFD_MACH_O_BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB      0x70
+#define BFD_MACH_O_BIND_OPCODE_ADD_ADDR_ULEB                    0x80
+#define BFD_MACH_O_BIND_OPCODE_DO_BIND                          0x90
+#define BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB            0xa0
+#define BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED      0xb0
+#define BFD_MACH_O_BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB 0xc0
+
+/* The bind types.  */
+#define BFD_MACH_O_BIND_TYPE_POINTER            1
+#define BFD_MACH_O_BIND_TYPE_TEXT_ABSOLUTE32    2
+#define BFD_MACH_O_BIND_TYPE_TEXT_PCREL32       3
+
+/* The special dylib.  */
+#define BFD_MACH_O_BIND_SPECIAL_DYLIB_SELF             0
+#define BFD_MACH_O_BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE -1
+#define BFD_MACH_O_BIND_SPECIAL_DYLIB_FLAT_LOOKUP     -2
+
+/* Constants for dyld info export.  */
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_MASK            0x03
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_REGULAR         0x00
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL    0x01
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION      0x04
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_REEXPORT             0x08
+#define BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER    0x10
+
 /* Constants for DATA_IN_CODE entries.  */
 typedef enum bfd_mach_o_data_in_code_entry_kind
 {