1
0
mirror of https://github.com/golang/go synced 2024-11-05 15:36:09 -07:00

liblink, cmd/ld, cmd/5l: darwin/arm support

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>
This commit is contained in:
Shenghou Ma 2014-12-26 00:15:07 -05:00 committed by Minux Ma
parent db0d3892e0
commit 1083715b7f
6 changed files with 132 additions and 8 deletions

View File

@ -33,9 +33,9 @@
#include "l.h" #include "l.h"
#include "../ld/lib.h" #include "../ld/lib.h"
#include "../ld/elf.h" #include "../ld/elf.h"
#include "../ld/macho.h"
#include "../ld/dwarf.h" #include "../ld/dwarf.h"
char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
char freebsddynld[] = "/usr/libexec/ld-elf.so.1"; char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
char openbsddynld[] = "XXX"; char openbsddynld[] = "XXX";
@ -301,10 +301,58 @@ elfsetupplt(void)
int int
machoreloc1(Reloc *r, vlong sectoff) machoreloc1(Reloc *r, vlong sectoff)
{ {
USED(r); uint32 v;
USED(sectoff); 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); diag("missing section for %s", rs->name);
r->xsym = rs; 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), *val = braddoff((0xff000000U & (uint32)r->add),
(0xffffff & (uint32)(r->xadd / 4))); (0xffffff & (uint32)(r->xadd / 4)));
return 0; return 0;
@ -539,6 +595,8 @@ adddynlib(char *lib)
if(s->size == 0) if(s->size == 0)
addstring(s, ""); addstring(s, "");
elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib)); elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
} else if(HEADTYPE == Hdarwin) {
machoadddynlib(lib);
} else { } else {
diag("adddynlib: unsupported binary format"); diag("adddynlib: unsupported binary format");
} }
@ -547,7 +605,7 @@ adddynlib(char *lib)
void void
asmb(void) asmb(void)
{ {
uint32 symo; uint32 symo, dwarfoff, machlink;
Section *sect; Section *sect;
LSym *sym; LSym *sym;
int i; int i;
@ -583,6 +641,22 @@ asmb(void)
cseek(segdata.fileoff); cseek(segdata.fileoff);
datblk(segdata.vaddr, segdata.filelen); 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 */ /* output symbol table */
symsize = 0; symsize = 0;
lcsize = 0; lcsize = 0;
@ -599,6 +673,9 @@ asmb(void)
case Hplan9: case Hplan9:
symo = segdata.fileoff+segdata.filelen; symo = segdata.fileoff+segdata.filelen;
break; break;
case Hdarwin:
symo = rnd(HEADR+segtext.filelen, INITRND)+rnd(segdata.filelen, INITRND)+machlink;
break;
ElfSym: ElfSym:
symo = segdata.fileoff+segdata.filelen; symo = segdata.fileoff+segdata.filelen;
symo = rnd(symo, INITRND); symo = rnd(symo, INITRND);
@ -635,6 +712,10 @@ asmb(void)
cflush(); cflush();
} }
break; break;
case Hdarwin:
if(linkmode == LinkExternal)
machoemitreloc();
break;
} }
} }
@ -662,6 +743,9 @@ asmb(void)
case Hnacl: case Hnacl:
asmbelf(symo); asmbelf(symo);
break; break;
case Hdarwin:
asmbmacho();
break;
} }
cflush(); cflush();
if(debug['c']){ if(debug['c']){

View File

@ -33,6 +33,7 @@
#include "l.h" #include "l.h"
#include "../ld/lib.h" #include "../ld/lib.h"
#include "../ld/elf.h" #include "../ld/elf.h"
#include "../ld/macho.h"
#include "../ld/dwarf.h" #include "../ld/dwarf.h"
#include <ar.h> #include <ar.h>
@ -64,6 +65,7 @@ archinit(void)
case Hlinux: case Hlinux:
case Hfreebsd: case Hfreebsd:
case Hnacl: case Hnacl:
case Hdarwin:
break; break;
} }
@ -104,6 +106,17 @@ archinit(void)
if(INITRND == -1) if(INITRND == -1)
INITRND = 0x10000; INITRND = 0x10000;
break; 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) if(INITDAT != 0 && INITRND != 0)
print("warning: -D0x%ux is ignored because of -R0x%ux\n", print("warning: -D0x%ux is ignored because of -R0x%ux\n",

View File

@ -212,6 +212,14 @@ loadlib(void)
// Force external linking for android. // Force external linking for android.
if(strcmp(goos, "android") == 0) if(strcmp(goos, "android") == 0)
linkmode = LinkExternal; 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) { if(linkmode == LinkExternal && !iscgo) {

View File

@ -357,6 +357,10 @@ asmbmacho(void)
default: default:
diag("unknown mach architecture"); diag("unknown mach architecture");
errorexit(); errorexit();
case '5':
mh->cpu = MACHO_CPU_ARM;
mh->subcpu = MACHO_SUBCPU_ARMV7;
break;
case '6': case '6':
mh->cpu = MACHO_CPU_AMD64; mh->cpu = MACHO_CPU_AMD64;
mh->subcpu = MACHO_SUBCPU_X86; mh->subcpu = MACHO_SUBCPU_X86;
@ -416,6 +420,12 @@ asmbmacho(void)
default: default:
diag("unknown macho architecture"); diag("unknown macho architecture");
errorexit(); 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': case '6':
ml = newMachoLoad(5, 42+2); /* unix thread */ ml = newMachoLoad(5, 42+2); /* unix thread */
ml->data[0] = 4; /* thread type */ ml->data[0] = 4; /* thread type */

View File

@ -66,6 +66,9 @@ enum {
MACHO_CPU_AMD64 = (1<<24)|7, MACHO_CPU_AMD64 = (1<<24)|7,
MACHO_CPU_386 = 7, MACHO_CPU_386 = 7,
MACHO_SUBCPU_X86 = 3, MACHO_SUBCPU_X86 = 3,
MACHO_CPU_ARM = 12,
MACHO_SUBCPU_ARM = 0,
MACHO_SUBCPU_ARMV7 = 9,
MACHO32SYMSIZE = 12, MACHO32SYMSIZE = 12,
MACHO64SYMSIZE = 16, MACHO64SYMSIZE = 16,
@ -80,6 +83,9 @@ enum {
MACHO_X86_64_RELOC_SIGNED_2 = 7, MACHO_X86_64_RELOC_SIGNED_2 = 7,
MACHO_X86_64_RELOC_SIGNED_4 = 8, MACHO_X86_64_RELOC_SIGNED_4 = 8,
MACHO_ARM_RELOC_VANILLA = 0,
MACHO_ARM_RELOC_BR24 = 5,
MACHO_GENERIC_RELOC_VANILLA = 0, MACHO_GENERIC_RELOC_VANILLA = 0,
MACHO_FAKE_GOTPCREL = 100, MACHO_FAKE_GOTPCREL = 100,

View File

@ -148,15 +148,15 @@ linknew(LinkArch *arch)
switch(ctxt->arch->thechar) { switch(ctxt->arch->thechar) {
default: default:
sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name); sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
case '5':
ctxt->tlsoffset = 0;
break;
case '6': case '6':
ctxt->tlsoffset = 0; ctxt->tlsoffset = 0;
break; break;
case '8': case '8':
ctxt->tlsoffset = -8; ctxt->tlsoffset = -8;
break; break;
case '5':
ctxt->tlsoffset = 0;
break;
} }
break; break;
@ -174,6 +174,9 @@ linknew(LinkArch *arch)
case '8': case '8':
ctxt->tlsoffset = 0x468; ctxt->tlsoffset = 0x468;
break; break;
case '5':
ctxt->tlsoffset = 0; // dummy value, not needed
break;
} }
break; break;
} }