rts linker: Introduce MachOTypes
authorMoritz Angermann <moritz.angermann@gmail.com>
Tue, 21 Mar 2017 14:59:49 +0000 (10:59 -0400)
committerBen Gamari <ben@smart-cactus.org>
Mon, 27 Mar 2017 01:37:22 +0000 (21:37 -0400)
This diff introduces MachOTypes, to reduce the need to typing `struct`
all the time.  It also coaleces the 64 and non 64 structs. It also adds
additional fiedls to the object code structure for macho, which makes
working with macho object code much simpler and requires less passing
around of variabls or address recomputation for the header, symbol
table, etc...

Furthermore this diff introduces a type for a linked list of stubs.

I had to move the #ifdef from the bottom of the file up, to be able to
extend the object code structure conditional on the use of the macho file format.

This is just one of the pieces for the rts linker
support for ios (aarch64-macho)

---

The following diagram and legend tries to explain the dependencies a
bit:
```
  .- D3240
  v
D3255 <- D3252 <- D3251 <- This
  ^
  '- D3238
```

- In D3238 we started allowing preloading object code with mmap
  in iOS, where we can't have r+w+x.
- In D3239 we introduced a richer extension of the object code
  data type to make working with mach-o files easier.
- In D3240 we set the stage to allow loading archives (.a) on iOS
- In D3251 we added init and deinit functions to populate and
  depopulate the enriched object code data structure for mach-o
  files.
- In D3252 we refactored most of the MachO.c file to use the
  new types and data structure.
- in D3255 we finally introduce the aarch64-mach-o linker.

Reviewers: austin, erikd, simonmar, rwbarton, bgamari

Subscribers: rwbarton, thomie, ryantrinkle

Differential Revision: https://phabricator.haskell.org/D3239

rts/Linker.c
rts/LinkerInternals.h
rts/linker/MachOTypes.h [new file with mode: 0644]

index 7654f2b..87f1eeb 100644 (file)
@@ -1163,6 +1163,9 @@ void freeObjectCode (ObjectCode *oc)
                     break;
                 }
             }
+            if (oc->sections[i].info) {
+                stgFree(oc->sections[i].info);
+            }
         }
         stgFree(oc->sections);
     }
@@ -1732,6 +1735,9 @@ addSection (Section *s, SectionKind kind, SectionAlloc alloc,
    s->mapped_start = mapped_start; /* start of mmap() block */
    s->mapped_size  = mapped_size;  /* size of mmap() block */
 
+   s->info = (SectionFormatInfo*)stgCallocBytes(1, sizeof(SectionFormatInfo),
+                                            "addSection(SectionFormatInfo)");
+
    IF_DEBUG(linker,
             debugBelch("addSection: %p-%p (size %" FMT_Word "), kind %d\n",
                        start, (void*)((StgWord)start + size),
index 76497df..2217c5e 100644 (file)
@@ -21,6 +21,9 @@
 typedef void SymbolAddr;
 typedef char SymbolName;
 
+typedef struct _SectionFormatInfo SectionFormatInfo;
+typedef struct _ObjectCodeFormatInfo ObjectCodeFormatInfo;
+
 /* See Linker.c Note [runtime-linker-phases] */
 typedef enum {
     OBJECT_LOADED,
@@ -63,6 +66,9 @@ typedef
       StgWord mapped_offset;      /* offset from the image of mapped_start */
       void* mapped_start;         /* start of mmap() block */
       StgWord mapped_size;        /* size of mmap() block */
+
+      /* A customizable type to augment the Section type. */
+       SectionFormatInfo* info;
    }
    Section;
 
@@ -86,7 +92,10 @@ typedef struct ForeignExportStablePtr_ {
 } ForeignExportStablePtr;
 
 #if powerpc_HOST_ARCH || x86_64_HOST_ARCH || arm_HOST_ARCH
+/* ios currently uses adjacent got tables, and no symbol extras */
+#if !defined(ios_HOST_OS)
 #define NEED_SYMBOL_EXTRAS 1
+#endif /* ios_HOST_OS */
 #endif
 
 /* Jump Islands are sniplets of machine code required for relative
@@ -132,6 +141,10 @@ typedef struct _ObjectCode {
 
     /* ptr to mem containing the object file image */
     char*      image;
+
+    /* A customizable type, that formats can use to augment ObjectCode */
+    ObjectCodeFormatInfo *info;
+
     /* non-zero if the object file was mmap'd, otherwise malloc'd */
     int        imageMapped;
 
@@ -299,12 +312,23 @@ char *cstring_from_section_name(
 #endif
 
 /* Which object file format are we targetting? */
-#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) || defined(freebsd_HOST_OS) || defined(kfreebsdgnu_HOST_OS) || defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) || defined(openbsd_HOST_OS) || defined(gnu_HOST_OS)
+#if defined(linux_HOST_OS) || defined(solaris2_HOST_OS) \
+|| defined(linux_android_HOST_OS) \
+|| defined(freebsd_HOST_OS) || defined(kfreebsdgnu_HOST_OS) \
+|| defined(dragonfly_HOST_OS) || defined(netbsd_HOST_OS) \
+|| defined(openbsd_HOST_OS) || defined(gnu_HOST_OS)
 #  define OBJFORMAT_ELF
+typedef struct _ObjectCodeFormatInfo { void* placeholder;} ObjectCodeFormatInfo;
+typedef struct _SectionFormatInfo { void* placeholder; } SectionFormatInfo;
 #elif defined (mingw32_HOST_OS)
 #  define OBJFORMAT_PEi386
-#elif defined(darwin_HOST_OS)
+typedef struct _ObjectCodeFormatInfo { void* placeholder;} ObjectCodeFormatInfo;
+typedef struct _SectionFormatInfo { void* placeholder; } SectionFormatInfo;
+#elif defined(darwin_HOST_OS) || defined(ios_HOST_OS)
 #  define OBJFORMAT_MACHO
+#  include "linker/MachOTypes.h"
+#else
+#error "Unknown OBJECT_FORMAT for HOST_OS"
 #endif
 
 /* In order to simplify control flow a bit, some references to mmap-related
diff --git a/rts/linker/MachOTypes.h b/rts/linker/MachOTypes.h
new file mode 100644 (file)
index 0000000..31bfdb4
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef MachOTypes_h
+#define MachOTypes_h
+
+#if defined(darwin_HOST_OS) || defined(ios_HOST_OS)
+
+#include "ghcplatform.h"
+
+#include <mach-o/loader.h>
+
+#if x86_64_HOST_ARCH || powerpc64_HOST_ARCH \
+ || aarch64_HOST_ARCH || arm64_HOST_ARCH
+typedef struct mach_header_64     MachOHeader;
+typedef struct segment_command_64 MachOSegmentCommand;
+typedef struct section_64         MachOSection;
+typedef struct nlist_64           MachONList;
+#elif i386_HOST_ARCH || powerpc_HOST_ARCH || arm_HOST_ARCH
+typedef struct mach_header     MachOHeader;
+typedef struct segment_command MachOSegmentCommand;
+typedef struct section         MachOSection;
+typedef struct nlist           MachONList;
+#else
+#error Unknown Darwin architecture
+#endif
+typedef struct load_command     MachOLoadCommand;
+typedef struct symtab_command   MachOSymtabCommand;
+typedef struct dysymtab_command MachODsymtabCommand;
+typedef struct relocation_info  MachORelocationInfo;
+typedef struct scattered_relocation_info MachOScatteredRelocationInfo;
+
+/* Dealing with nlist symbol entries can become
+ * painful.  We'll have our own Symbol struct that
+ * mirrors the symbol from the nlist and can carry
+ * some more infomration (like addr).
+ */
+typedef struct _MachOSymbol {
+    SymbolName * name;  /* the name of the symbol. */
+    SymbolAddr * addr;  /* the final resting place of the symbol */
+    void * got_addr;    /* address of the got slot for this symbol, if any */
+    MachONList * nlist; /* the nlist symbol entry */
+} MachOSymbol;
+
+typedef struct _ObjectCodeFormatInfo {
+    // while we have the image
+    // we can store some pointers
+    // into it, so we don't have
+    // recompute them each time.
+    /* the object header */
+    MachOHeader          *header;
+    MachOSymtabCommand   *symCmd;
+    MachOSegmentCommand  *segCmd;
+    MachODsymtabCommand  *dsymCmd;
+    /* points to the first nlist in the image */
+    MachONList           *nlist;
+    /* points to the names offset in the image */
+    char                 *names;
+
+    /* points to the start of the sections */
+    MachOSection         *macho_sections;
+
+    /* A richer nlist type */
+    MachOSymbol          *macho_symbols;
+    size_t               n_macho_symbols;
+
+    /* pointer to the global offset table */
+    void                 *got_start;
+    size_t                got_size;
+} ObjectCodeFormatInfo;
+
+/* When loading sections of the macho
+ * into different pages, such that the
+ * pages can be marked r+x for text and
+ * r+w for data, relocation may need
+ * to be done indirectly, as the symbol
+ * is not within reach of the of the
+ * call site. E.g. B/BL instructions on
+ * aarch64 have +-128mb relative
+ * range.  When pages are mmap'd they
+ * may end up at random positions.
+ *
+ * Hence we reserve space for the stub
+ * slots right after the text section
+ *
+ *  .----------. - page start
+ *  |          |
+ *  |  __TEXT  |
+ *  |          |
+ *  |----------|
+ *  |  Stubs   |
+ *  '----------'
+ *
+ * Therefore, unless the __TEXT section
+ * grows beyond 128mb-|Stubs|, we can
+ * always reach the corresponding stub
+ * for a symbol.
+ *
+ * Stubs will be rendered as
+ * - 8 bytes: target address
+ * - 4 bytes: relative load at -8bytes
+ instruction
+ * - 4 bytes: branch instruction
+ *
+ * These are very similar to the SymbolExtras
+ * below.  However the SymbolExtras are allocated
+ * per ObejctCode and not per Section.
+ *
+ * TODO: Merge SymbolExtras and Stubs.
+ */
+typedef
+struct _Stub {
+    void * addr;
+    void * target;
+    struct _Stub * next;
+}
+Stub;
+
+typedef struct _SectionFormatInfo {
+    /*
+     * The following fields are relevant for stubs next to sections only.
+     */
+    void * stub_offset;
+    size_t stub_size;
+    size_t nstubs;
+    Stub * stubs;
+
+    /*
+     * The following fields make working with mach-o objects much easier.
+     */
+    MachOSection * macho_section;
+    MachORelocationInfo * relocation_info;
+} SectionFormatInfo;
+
+#endif /* darwin_HOST_OS || ios_HOST_OS */
+#endif /* MachOTypes_h */