1
0
mirror of https://github.com/golang/go synced 2024-11-26 02:37:58 -07:00

cmd/ld: darwin support for host linking

R=ken2
CC=golang-dev
https://golang.org/cl/7626045
This commit is contained in:
Russ Cox 2013-03-11 00:51:42 -04:00
parent 9e13803ae1
commit 3b85b724c5
11 changed files with 341 additions and 105 deletions

View File

@ -316,6 +316,63 @@ elfreloc1(Reloc *r, vlong sectoff)
return 0;
}
int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
Sym *rs;
rs = r->xsym;
if(rs->type == SHOSTOBJ) {
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 D_ADDR:
v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
break;
case D_PCREL:
v |= 1<<24; // pc-relative bit
v |= MACHO_X86_64_RELOC_BRANCH<<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;
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
{
@ -677,6 +734,10 @@ asmb(void)
dwarfemitdebugsections();
break;
case Hdarwin:
if(isobj)
machoemitreloc();
break;
}
}

View File

@ -141,8 +141,11 @@ main(int argc, char *argv[])
switch(HEADTYPE) {
default:
sysfatal("cannot use -hostobj with -H %s", headstr(HEADTYPE));
case Hlinux:
case Hdarwin:
case Hfreebsd:
case Hlinux:
case Hnetbsd:
case Hopenbsd:
break;
}
}

View File

@ -299,6 +299,78 @@ elfreloc1(Reloc *r, vlong sectoff)
return 0;
}
int
machoreloc1(Reloc *r, vlong sectoff)
{
uint32 v;
Sym *rs;
rs = r->xsym;
if(rs->type == SHOSTOBJ) {
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 D_ADDR:
v |= MACHO_GENERIC_RELOC_VANILLA<<28;
break;
case D_PCREL:
v |= 1<<24; // pc-relative bit
v |= MACHO_GENERIC_RELOC_VANILLA<<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;
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
{
USED(s);
switch(r->type) {
case D_CONST:
*val = r->add;
return 0;
case D_GOTOFF:
*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
return 0;
}
return -1;
}
void
elfsetupplt(void)
{
@ -327,21 +399,6 @@ elfsetupplt(void)
}
}
int
archreloc(Reloc *r, Sym *s, vlong *val)
{
USED(s);
switch(r->type) {
case D_CONST:
*val = r->add;
return 0;
case D_GOTOFF:
*val = symaddr(r->sym) + r->add - symaddr(lookup(".got", 0));
return 0;
}
return -1;
}
static void
addpltsym(Sym *s)
{
@ -636,6 +693,10 @@ asmb(void)
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
break;
case Hdarwin:
if(isobj)
machoemitreloc();
break;
}
}
if(debug['v'])

View File

@ -147,8 +147,11 @@ main(int argc, char *argv[])
switch(HEADTYPE) {
default:
sysfatal("cannot use -hostobj with -H %s", headstr(HEADTYPE));
case Hdarwin:
case Hfreebsd:
case Hlinux:
case Hnetbsd:
case Hopenbsd:
break;
}
}

View File

@ -192,12 +192,20 @@ relocsym(Sym *s)
r->xadd += symaddr(rs) - symaddr(rs->outer);
rs = rs->outer;
}
if(rs->type != SHOSTOBJ && rs->sect == nil)
diag("missing section for %s", rs->name);
r->xsym = rs;
if(thechar == '6')
o = 0;
else
o = r->xadd;
o = r->xadd;
if(iself) {
if(thechar == '6')
o = 0;
} else if(HEADTYPE == Hdarwin) {
if(rs->type != SHOSTOBJ)
o += symaddr(rs);
} else {
diag("unhandled pcrel relocation for %s", headtype);
}
break;
}
o = symaddr(r->sym) + r->add;
@ -214,13 +222,22 @@ relocsym(Sym *s)
r->xadd += symaddr(rs) - symaddr(rs->outer);
rs = rs->outer;
}
r->xadd -= r->siz; // relative to address after the relocated chunk
if(rs->type != SHOSTOBJ && rs->sect == nil)
diag("missing section for %s", rs->name);
r->xsym = rs;
r->xadd -= r->siz;
if(thechar == '6')
o = 0;
else
o = r->xadd;
o = r->xadd;
if(iself) {
if(thechar == '6')
o = 0;
} else if(HEADTYPE == Hdarwin) {
if(rs->type != SHOSTOBJ)
o += symaddr(rs) - rs->sect->vaddr;
o -= r->off; // WTF?
} else {
diag("unhandled pcrel relocation for %s", headtype);
}
break;
}
o = 0;

View File

@ -486,11 +486,8 @@ loadcgo(char *file, char *pkg, char *p, int n)
}
if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
// TODO: Make Mach-O code happier. Right now it sees the dynimpname and
// includes CgoExportStatic symbols in the dynamic table, and then dyld
// cannot find them when we run the binary. Disabling Windows too
// because it probably has the same issue.
if(strcmp(f[0], "cgo_export_static") == 0 && (HEADTYPE == Hdarwin || HEADTYPE == Hwindows))
// TODO: Remove once we know Windows is okay.
if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows)
continue;
if(nf < 2 || nf > 3)

View File

@ -614,6 +614,8 @@ hostlink(void)
}
if(!debug['s'])
argv[argc++] = "-ggdb";
if(HEADTYPE == Hdarwin)
argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000";
argv[argc++] = "-o";
argv[argc++] = outfile;

View File

@ -150,7 +150,10 @@ machowrite(void)
LPUT(0xfeedface);
LPUT(hdr.cpu);
LPUT(hdr.subcpu);
LPUT(2); /* file type - mach executable */
if(isobj)
LPUT(1); /* file type - mach object */
else
LPUT(2); /* file type - mach executable */
LPUT(nload+nseg+ndebug);
LPUT(loadsize);
LPUT(1); /* flags - no undefines */
@ -245,22 +248,24 @@ domacho(void)
s->type = SMACHOSYMTAB;
s->reachable = 1;
s = lookup(".plt", 0); // will be __symbol_stub
s->type = SMACHOPLT;
s->reachable = 1;
if(!isobj) {
s = lookup(".plt", 0); // will be __symbol_stub
s->type = SMACHOPLT;
s->reachable = 1;
s = lookup(".got", 0); // will be __nl_symbol_ptr
s->type = SMACHOGOT;
s->reachable = 1;
s->align = 4;
s = lookup(".got", 0); // will be __nl_symbol_ptr
s->type = SMACHOGOT;
s->reachable = 1;
s->align = 4;
s = lookup(".linkedit.plt", 0); // indirect table for .plt
s->type = SMACHOINDIRECTPLT;
s->reachable = 1;
s = lookup(".linkedit.plt", 0); // indirect table for .plt
s->type = SMACHOINDIRECTPLT;
s->reachable = 1;
s = lookup(".linkedit.got", 0); // indirect table for .got
s->type = SMACHOINDIRECTGOT;
s->reachable = 1;
s = lookup(".linkedit.got", 0); // indirect table for .got
s->type = SMACHOINDIRECTGOT;
s->reachable = 1;
}
}
void
@ -295,6 +300,10 @@ machoshbits(MachoSeg *mseg, Section *sect, char *segname)
*p = '_';
msect = newMachoSect(mseg, estrdup(buf), segname);
if(sect->rellen > 0) {
msect->reloc = sect->reloff;
msect->nreloc = sect->rellen / 8;
}
while(1<<msect->align < sect->align)
msect->align++;
@ -357,53 +366,69 @@ asmbmacho(void)
break;
}
ms = nil;
if(isobj) {
/* segment for entire file */
ms = newMachoSeg("", 40);
ms->fileoffset = segtext.fileoff;
ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff;
}
/* segment for zero page */
ms = newMachoSeg("__PAGEZERO", 0);
ms->vsize = va;
if(!isobj) {
ms = newMachoSeg("__PAGEZERO", 0);
ms->vsize = va;
}
/* text */
v = rnd(HEADR+segtext.len, INITRND);
ms = newMachoSeg("__TEXT", 20);
ms->vaddr = va;
ms->vsize = v;
ms->fileoffset = 0;
ms->filesize = v;
ms->prot1 = 7;
ms->prot2 = 5;
if(!isobj) {
ms = newMachoSeg("__TEXT", 20);
ms->vaddr = va;
ms->vsize = v;
ms->fileoffset = 0;
ms->filesize = v;
ms->prot1 = 7;
ms->prot2 = 5;
}
for(sect=segtext.sect; sect!=nil; sect=sect->next)
machoshbits(ms, sect, "__TEXT");
/* data */
w = segdata.len;
ms = newMachoSeg("__DATA", 20);
ms->vaddr = va+v;
ms->vsize = w;
ms->fileoffset = v;
ms->filesize = segdata.filelen;
ms->prot1 = 3;
ms->prot2 = 3;
if(!isobj) {
w = segdata.len;
ms = newMachoSeg("__DATA", 20);
ms->vaddr = va+v;
ms->vsize = w;
ms->fileoffset = v;
ms->filesize = segdata.filelen;
ms->prot1 = 3;
ms->prot2 = 3;
}
for(sect=segdata.sect; sect!=nil; sect=sect->next)
machoshbits(ms, sect, "__DATA");
switch(thechar) {
default:
diag("unknown macho architecture");
errorexit();
case '6':
ml = newMachoLoad(5, 42+2); /* unix thread */
ml->data[0] = 4; /* thread type */
ml->data[1] = 42; /* word count */
ml->data[2+32] = entryvalue(); /* start pc */
ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
break;
case '8':
ml = newMachoLoad(5, 16+2); /* unix thread */
ml->data[0] = 1; /* thread type */
ml->data[1] = 16; /* word count */
ml->data[2+10] = entryvalue(); /* start pc */
break;
if(!isobj) {
switch(thechar) {
default:
diag("unknown macho architecture");
errorexit();
case '6':
ml = newMachoLoad(5, 42+2); /* unix thread */
ml->data[0] = 4; /* thread type */
ml->data[1] = 42; /* word count */
ml->data[2+32] = entryvalue(); /* start pc */
ml->data[2+32+1] = entryvalue()>>16>>16; // hide >>32 for 8l
break;
case '8':
ml = newMachoLoad(5, 16+2); /* unix thread */
ml->data[0] = 1; /* thread type */
ml->data[1] = 16; /* word count */
ml->data[2+10] = entryvalue(); /* start pc */
break;
}
}
if(!debug['d']) {
@ -415,13 +440,15 @@ asmbmacho(void)
s3 = lookup(".linkedit.got", 0);
s4 = lookup(".machosymstr", 0);
ms = newMachoSeg("__LINKEDIT", 0);
ms->vaddr = va+v+rnd(segdata.len, INITRND);
ms->vsize = s1->size + s2->size + s3->size + s4->size;
ms->fileoffset = linkoff;
ms->filesize = ms->vsize;
ms->prot1 = 7;
ms->prot2 = 3;
if(!isobj) {
ms = newMachoSeg("__LINKEDIT", 0);
ms->vaddr = va+v+rnd(segdata.len, INITRND);
ms->vsize = s1->size + s2->size + s3->size + s4->size;
ms->fileoffset = linkoff;
ms->filesize = ms->vsize;
ms->prot1 = 7;
ms->prot2 = 3;
}
ml = newMachoLoad(2, 4); /* LC_SYMTAB */
ml->data[0] = linkoff; /* symoff */
@ -431,21 +458,24 @@ asmbmacho(void)
machodysymtab();
ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
ml->data[0] = 12; /* offset to string */
strcpy((char*)&ml->data[1], "/usr/lib/dyld");
if(!isobj) {
ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */
ml->data[0] = 12; /* offset to string */
strcpy((char*)&ml->data[1], "/usr/lib/dyld");
for(i=0; i<ndylib; i++) {
ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
ml->data[0] = 24; /* offset of string from beginning of load */
ml->data[1] = 0; /* time stamp */
ml->data[2] = 0; /* version */
ml->data[3] = 0; /* compatibility version */
strcpy((char*)&ml->data[4], dylib[i]);
for(i=0; i<ndylib; i++) {
ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2); /* LC_LOAD_DYLIB */
ml->data[0] = 24; /* offset of string from beginning of load */
ml->data[1] = 0; /* time stamp */
ml->data[2] = 0; /* version */
ml->data[3] = 0; /* compatibility version */
strcpy((char*)&ml->data[4], dylib[i]);
}
}
}
if(!debug['s'])
// TODO: dwarf headers go in ms too
if(!debug['s'] && !isobj)
dwarfaddmachoheaders();
a = machowrite();
@ -515,7 +545,8 @@ machogenasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
genasmsym(put);
for(s=allsym; s; s=s->allsym)
if(s->type == SDYNIMPORT)
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
if(s->reachable)
put(s, nil, 'D', 0, 0, 0, nil);
}
@ -552,13 +583,16 @@ machosymtab(void)
adduint32(symtab, symstr->size);
adduint8(symstr, '_');
addstring(symstr, s->extname);
if(s->type == SDYNIMPORT) {
if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
adduint8(symtab, 0x01); // type N_EXT, external symbol
adduint8(symtab, 0); // no section
adduint16(symtab, 0); // desc
adduintxx(symtab, 0, PtrSize); // no value
} else {
adduint8(symtab, 0x0f);
if(s->cgoexport)
adduint8(symtab, 0x0f);
else
adduint8(symtab, 0x0e);
o = s;
while(o->outer != nil)
o = o->outer;
@ -663,3 +697,56 @@ domacholink(void)
return rnd(size, INITRND);
}
void
machorelocsect(Section *sect, Sym *first)
{
Sym *sym;
int32 eaddr;
Reloc *r;
// If main section has no bits, nothing to relocate.
if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
return;
sect->reloff = cpos();
for(sym = first; sym != nil; sym = sym->next) {
if(!sym->reachable)
continue;
if(sym->value >= sect->vaddr)
break;
}
eaddr = sect->vaddr + sect->len;
for(; sym != nil; sym = sym->next) {
if(!sym->reachable)
continue;
if(sym->value >= eaddr)
break;
cursym = sym;
for(r = sym->r; r < sym->r+sym->nr; r++) {
if(r->done)
continue;
if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
}
}
sect->rellen = cpos() - sect->reloff;
}
void
machoemitreloc(void)
{
Section *sect;
while(cpos()&7)
cput(0);
machorelocsect(segtext.sect, textp);
for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
machorelocsect(sect, datap);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
machorelocsect(sect, datap);
}

View File

@ -52,6 +52,8 @@ MachoLoad* newMachoLoad(uint32, uint32);
int machowrite(void);
void machoinit(void);
void machosymorder(void);
void machoemitreloc(void);
int machoreloc1(Reloc*, vlong);
/*
* Total amount of space to reserve at the start of the file

View File

@ -26,9 +26,8 @@ TEXT _rt0_386(SB),7,$0
MOVL _cgo_init(SB), AX
TESTL AX, AX
JZ needtls
PUSHL BP
MOVL BP, 0(SP)
CALL AX
POPL BP
// skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows
CMPL runtime·iswindows(SB), $0
JEQ ok

View File

@ -77,6 +77,10 @@ go run $GOROOT/test/run.go - .
[ "$GOHOSTOS" == openbsd ] || # issue 4878
(xcd ../misc/cgo/test
go test
case "$GOHOSTOS-$GOARCH" in
darwin-386 | darwin-amd64 | linux-386 | linux-amd64)
go test -ldflags '-w -hostobj'
esac
) || exit $?
[ "$CGO_ENABLED" != 1 ] ||