]> Cypherpunks repositories - gostls13.git/commitdiff
liblink, cmd/ld, cmd/5l: darwin/arm support
authorShenghou Ma <minux@golang.org>
Fri, 26 Dec 2014 05:15:07 +0000 (00:15 -0500)
committerMinux Ma <minux@golang.org>
Fri, 6 Feb 2015 05:41:15 +0000 (05:41 +0000)
liblink:
 - set dummy value for ctxt->tlsoffset.
cmd/ld:
 - always do external linking when using cgo on darwin/arm,
   as our linker might not generate codesign-compatible binary.
cmd/5l:
 - support generate ARM Mach-O binaries
 - add machoreloc1() that translate our internal relocation to
   macho relocations used by external linking.

Change-Id: Ic5454aeb87009aaf8f1453ec7fe33e6da55d5f06
Reviewed-on: https://go-review.googlesource.com/3273
Reviewed-by: David Crawshaw <crawshaw@golang.org>
src/cmd/5l/asm.c
src/cmd/5l/obj.c
src/cmd/ld/lib.c
src/cmd/ld/macho.c
src/cmd/ld/macho.h
src/liblink/sym.c

index 59930791262c4fedfd45784ce6ffac11d8738f4a..3ed5b673d4ecaf4fd283721493a0e5ea20199b87 100644 (file)
@@ -33,9 +33,9 @@
 #include       "l.h"
 #include       "../ld/lib.h"
 #include       "../ld/elf.h"
+#include       "../ld/macho.h"
 #include       "../ld/dwarf.h"
 
-
 char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
 char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
 char openbsddynld[] = "XXX";
@@ -301,10 +301,58 @@ elfsetupplt(void)
 int
 machoreloc1(Reloc *r, vlong sectoff)
 {
-       USED(r);
-       USED(sectoff);
+       uint32 v;
+       LSym *rs;
 
-       return -1;
+       rs = r->xsym;
+
+       if(rs->type == SHOSTOBJ || r->type == R_CALLARM) {
+               if(rs->dynid < 0) {
+                       diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+                       return -1;
+               }
+               v = rs->dynid;
+               v |= 1<<27; // external relocation
+       } else {
+               v = rs->sect->extnum;
+               if(v == 0) {
+                       diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+                       return -1;
+               }
+       }
+
+       switch(r->type) {
+       default:
+               return -1;
+       case R_ADDR:
+               v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+               break;
+       case R_CALLARM:
+               v |= 1<<24; // pc-relative bit
+               v |= MACHO_ARM_RELOC_BR24<<28;
+               break;
+       }
+
+       switch(r->siz) {
+       default:
+               return -1;
+       case 1:
+               v |= 0<<25;
+               break;
+       case 2:
+               v |= 1<<25;
+               break;
+       case 4:
+               v |= 2<<25;
+               break;
+       case 8:
+               v |= 3<<25;
+               break;
+       }
+
+       LPUT(sectoff);
+       LPUT(v);
+       return 0;
 }
 
 
@@ -333,6 +381,14 @@ archreloc(Reloc *r, LSym *s, vlong *val)
                                diag("missing section for %s", rs->name);
                        r->xsym = rs;
 
+                       // ld64 for arm seems to want the symbol table to contain offset
+                       // into the section rather than pseudo virtual address that contains
+                       // the section load address.
+                       // we need to compensate that by removing the instruction's address
+                       // from addend.
+                       if(HEADTYPE == Hdarwin)
+                               r->xadd -= symaddr(s) + r->off;
+
                        *val = braddoff((0xff000000U & (uint32)r->add), 
                                                        (0xffffff & (uint32)(r->xadd / 4)));
                        return 0;
@@ -539,6 +595,8 @@ adddynlib(char *lib)
                if(s->size == 0)
                        addstring(s, "");
                elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+       } else if(HEADTYPE == Hdarwin) {
+               machoadddynlib(lib);
        } else {
                diag("adddynlib: unsupported binary format");
        }
@@ -547,7 +605,7 @@ adddynlib(char *lib)
 void
 asmb(void)
 {
-       uint32 symo;
+       uint32 symo, dwarfoff, machlink;
        Section *sect;
        LSym *sym;
        int i;
@@ -583,6 +641,22 @@ asmb(void)
        cseek(segdata.fileoff);
        datblk(segdata.vaddr, segdata.filelen);
 
+       machlink = 0;
+       if(HEADTYPE == Hdarwin) {
+               if(debug['v'])
+                       Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+               if(!debug['w']) { // TODO(minux): enable DWARF Support
+                       dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+                       cseek(dwarfoff);
+
+                       segdwarf.fileoff = cpos();
+                       dwarfemitdebugsections();
+                       segdwarf.filelen = cpos() - segdwarf.fileoff;
+               }
+               machlink = domacholink();
+       }
+
        /* output symbol table */
        symsize = 0;
        lcsize = 0;
@@ -599,6 +673,9 @@ asmb(void)
                case Hplan9:
                        symo = segdata.fileoff+segdata.filelen;
                        break;
+               case Hdarwin:
+                       symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
+                       break;
                ElfSym:
                        symo = segdata.fileoff+segdata.filelen;
                        symo = rnd(symo, INITRND);
@@ -635,6 +712,10 @@ asmb(void)
                                cflush();
                        }
                        break;
+               case Hdarwin:
+                       if(linkmode == LinkExternal)
+                               machoemitreloc();
+                       break;
                }
        }
 
@@ -662,6 +743,9 @@ asmb(void)
        case Hnacl:
                asmbelf(symo);
                break;
+       case Hdarwin:
+               asmbmacho();
+               break;
        }
        cflush();
        if(debug['c']){
index c6f60ee7c86359d6c17d27efda31464928cd2e7b..73ff7514871905ef0dcae8635eeb561094491256 100644 (file)
@@ -33,6 +33,7 @@
 #include       "l.h"
 #include       "../ld/lib.h"
 #include       "../ld/elf.h"
+#include       "../ld/macho.h"
 #include       "../ld/dwarf.h"
 #include       <ar.h>
 
@@ -64,6 +65,7 @@ archinit(void)
        case Hlinux:
        case Hfreebsd:
        case Hnacl:
+       case Hdarwin:
                break;
        }
 
@@ -104,6 +106,17 @@ archinit(void)
                if(INITRND == -1)
                        INITRND = 0x10000;
                break;
+       case Hdarwin:   /* apple MACH */
+               debug['w'] = 1; // disable DWARF generataion
+               machoinit();
+               HEADR = INITIAL_MACHO_HEADR;
+               if(INITTEXT == -1)
+                       INITTEXT = 4096+HEADR;
+               if(INITDAT == -1)
+                       INITDAT = 0;
+               if(INITRND == -1)
+                       INITRND = 4096;
+               break;
        }
        if(INITDAT != 0 && INITRND != 0)
                print("warning: -D0x%ux is ignored because of -R0x%ux\n",
index 192e28398bd50c852b75baca723099861503ec08..202841170bdd1fd786ec25426f8da8f199a1ac71 100644 (file)
@@ -212,6 +212,14 @@ loadlib(void)
                // Force external linking for android.
                if(strcmp(goos, "android") == 0)
                        linkmode = LinkExternal;
+
+               // cgo on Darwin must use external linking
+               // we can always use external linking, but then there will be circular
+               // dependency problems when compiling natively (external linking requires
+               // runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
+               // compiled using external linking.)
+               if(thechar == '5' && HEADTYPE == Hdarwin && iscgo)
+                       linkmode = LinkExternal;
        }
 
        if(linkmode == LinkExternal && !iscgo) {
index ffb20b3a55be523549dcf846ba35a0d7867fe746..ce0aa77b6636a7be9324e37a530d89ab274dfadf 100644 (file)
@@ -357,6 +357,10 @@ asmbmacho(void)
        default:
                diag("unknown mach architecture");
                errorexit();
+       case '5':
+               mh->cpu = MACHO_CPU_ARM;
+               mh->subcpu = MACHO_SUBCPU_ARMV7;
+               break;
        case '6':
                mh->cpu = MACHO_CPU_AMD64;
                mh->subcpu = MACHO_SUBCPU_X86;
@@ -416,6 +420,12 @@ asmbmacho(void)
                default:
                        diag("unknown macho architecture");
                        errorexit();
+               case '5':
+                       ml = newMachoLoad(5, 17+2);     /* unix thread */
+                       ml->data[0] = 1;        /* thread type */
+                       ml->data[1] = 17;       /* word count */
+                       ml->data[2+15] = entryvalue();  /* start pc */
+                       break;
                case '6':
                        ml = newMachoLoad(5, 42+2);     /* unix thread */
                        ml->data[0] = 4;        /* thread type */
index d759f4b0f8dd1af87a0d23b2c63c9f0947b37500..d21109b38f6e7ad0845dbda30ca45c39fcfca0a1 100644 (file)
@@ -66,6 +66,9 @@ enum {
        MACHO_CPU_AMD64 = (1<<24)|7,
        MACHO_CPU_386 = 7,
        MACHO_SUBCPU_X86 = 3,
+       MACHO_CPU_ARM = 12,
+       MACHO_SUBCPU_ARM = 0,
+       MACHO_SUBCPU_ARMV7 = 9,
 
        MACHO32SYMSIZE = 12,
        MACHO64SYMSIZE = 16,
@@ -80,6 +83,9 @@ enum {
        MACHO_X86_64_RELOC_SIGNED_2 = 7,
        MACHO_X86_64_RELOC_SIGNED_4 = 8,
        
+       MACHO_ARM_RELOC_VANILLA = 0,
+       MACHO_ARM_RELOC_BR24 = 5,
+       
        MACHO_GENERIC_RELOC_VANILLA = 0,
        
        MACHO_FAKE_GOTPCREL = 100,
index 079f600aa9f48d57647747562fd1d5055d966fd7..cae7e4aafe71343af954adddcfc45ab51fc40d90 100644 (file)
@@ -148,15 +148,15 @@ linknew(LinkArch *arch)
                switch(ctxt->arch->thechar) {
                default:
                        sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
+               case '5':
+                       ctxt->tlsoffset = 0;
+                       break;
                case '6':
                        ctxt->tlsoffset = 0;
                        break;
                case '8':
                        ctxt->tlsoffset = -8;
                        break;
-               case '5':
-                       ctxt->tlsoffset = 0;
-                       break;
                }
                break;
 
@@ -174,6 +174,9 @@ linknew(LinkArch *arch)
                case '8':
                        ctxt->tlsoffset = 0x468;
                        break;
+               case '5':
+                       ctxt->tlsoffset = 0; // dummy value, not needed
+                       break;
                }
                break;
        }