diff options
author | Russ Cox <rsc@golang.org> | 2009-10-03 10:37:12 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2009-10-03 10:37:12 -0700 |
commit | e7a28869ec5829d4e202b44797b748522a533b2a (patch) | |
tree | 7b69b0974f4999bac76d11abed2071a2dc9e97aa /src/cmd | |
parent | e6310aac93e28c68953277b30e2eaf8bdd9f106a (diff) | |
download | go-e7a28869ec5829d4e202b44797b748522a533b2a.tar.gz |
8c, 8l dynamic loading support.
better mach binaries.
cgo working on darwin+linux amd64+386.
eliminated context switches - pi is 30x faster.
add libcgo to build.
on snow leopard:
- non-cgo binaries work; all tests pass.
- cgo binaries work on amd64 but not 386.
R=r
DELTA=2031 (1316 added, 626 deleted, 89 changed)
OCL=35264
CL=35304
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/6l/asm.c | 101 | ||||
-rw-r--r-- | src/cmd/6l/l.h | 4 | ||||
-rw-r--r-- | src/cmd/6l/obj.c | 6 | ||||
-rw-r--r-- | src/cmd/6l/pass.c | 10 | ||||
-rw-r--r-- | src/cmd/6l/span.c | 11 | ||||
-rw-r--r-- | src/cmd/8l/asm.c | 109 | ||||
-rw-r--r-- | src/cmd/8l/l.h | 4 | ||||
-rw-r--r-- | src/cmd/8l/obj.c | 21 | ||||
-rw-r--r-- | src/cmd/8l/pass.c | 12 | ||||
-rw-r--r-- | src/cmd/8l/span.c | 11 | ||||
-rw-r--r-- | src/cmd/cgo/ast.go | 1 | ||||
-rw-r--r-- | src/cmd/cgo/gcc.go | 16 | ||||
-rw-r--r-- | src/cmd/cgo/main.go | 38 | ||||
-rw-r--r-- | src/cmd/cgo/out.go | 2 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 2 | ||||
-rw-r--r-- | src/cmd/ld/macho.c | 321 | ||||
-rw-r--r-- | src/cmd/ld/macho.h | 9 |
17 files changed, 474 insertions, 204 deletions
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 5562ee4e3..a0f8524e7 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -425,16 +425,11 @@ asmb(void) int32 v, magic; int a, dynsym; uchar *op1; - vlong vl, va, startva, fo, w, symo; + vlong vl, va, startva, fo, w, symo, machlink; vlong symdatva = 0x99LL<<32; ElfEhdr *eh; ElfPhdr *ph, *pph; ElfShdr *sh; - MachoHdr *mh; - MachoSect *msect; - MachoSeg *ms; - MachoDebug *md; - MachoLoad *ml; if(debug['v']) Bprint(&bso, "%5.2f asmb\n", cputime()); @@ -523,6 +518,10 @@ asmb(void) datblk(v, datsize-v); } + machlink = 0; + if(HEADTYPE == 6) + machlink = domacholink(); + symsize = 0; spsize = 0; lcsize = 0; @@ -539,7 +538,7 @@ asmb(void) symo = HEADR+textsize+datsize; break; case 6: - symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND); + symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink; break; case 7: symo = rnd(HEADR+textsize, INITRND)+datsize; @@ -607,92 +606,8 @@ asmb(void) lputb(lcsize); /* line offsets */ break; case 6: - /* apple MACH */ - va = HEADR; - mh = getMachoHdr(); - mh->cpu = MACHO_CPU_AMD64; - mh->subcpu = MACHO_SUBCPU_X86; - - /* segment for zero page */ - ms = newMachoSeg("__PAGEZERO", 0); - ms->vsize = va; - - /* text */ - v = rnd(HEADR+textsize, INITRND); - ms = newMachoSeg("__TEXT", 1); - ms->vaddr = va; - ms->vsize = v; - ms->filesize = v; - ms->prot1 = 7; - ms->prot2 = 5; - - msect = newMachoSect(ms, "__text"); - msect->addr = va+HEADR; - msect->size = v - HEADR; - msect->off = HEADR; - msect->flag = 0x400; /* flag - some instructions */ - - /* data */ - w = datsize+bsssize; - ms = newMachoSeg("__DATA", 2); - ms->vaddr = va+v; - ms->vsize = w; - ms->fileoffset = v; - ms->filesize = datsize; - ms->prot1 = 7; - ms->prot2 = 3; - - msect = newMachoSect(ms, "__data"); - msect->addr = va+v; - msect->size = datsize; - msect->off = v; - - msect = newMachoSect(ms, "__bss"); - msect->addr = va+v+datsize; - msect->size = bsssize; - msect->flag = 1; /* flag - zero fill */ - - 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()>>32; - - if(!debug['d']) { - ml = newMachoLoad(2, 4); /* LC_SYMTAB */ - USED(ml); - - ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ - USED(ml); - - ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ - ml->data[0] = 12; /* offset to string */ - strcpy((char*)&ml->data[1], "/usr/lib/dyld"); - } - - if(!debug['s']) { - ms = newMachoSeg("__SYMDAT", 1); - ms->vaddr = symdatva; - ms->vsize = 8+symsize+lcsize; - ms->fileoffset = symo; - ms->filesize = 8+symsize+lcsize; - ms->prot1 = 7; - ms->prot2 = 5; - - md = newMachoDebug(); - md->fileoffset = symo+8; - md->filesize = symsize; - - md = newMachoDebug(); - md->fileoffset = symo+8+symsize; - md->filesize = lcsize; - } - - a = machowrite(); - if(a > MACHORESERVE) - diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); + asmbmacho(symdatva, symo); break; - case 7: /* elf amd-64 */ @@ -965,6 +880,8 @@ datblk(int32 s, int32 n) curp = p; if(!p->from.sym->reachable) diag("unreachable symbol in datblk - %s", p->from.sym->name); + if(p->from.sym->type == SMACHO) + continue; l = p->from.sym->value + p->from.offset - s; c = p->from.scale; i = 0; diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index a1c2ec527..28c37a82c 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -160,6 +160,8 @@ enum SIMPORT, SEXPORT, + SMACHO, + NHASH = 10007, NHUNK = 100000, MINSIZ = 8, @@ -362,6 +364,7 @@ EXTERN Prog undefp; EXTERN vlong textstksiz; EXTERN vlong textarg; extern char thechar; +EXTERN int dynptrsize; #define UP (&undefp) @@ -403,6 +406,7 @@ void dobss(void); void dodata(void); void doelf(void); void doinit(void); +void domacho(void); void doprof1(void); void doprof2(void); void dostkoff(void); diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c index ba2dec3b2..4b40cce61 100644 --- a/src/cmd/6l/obj.c +++ b/src/cmd/6l/obj.c @@ -191,12 +191,12 @@ main(int argc, char *argv[]) case 6: /* apple MACH */ machoinit(); HEADR = MACHORESERVE; + if(INITRND == -1) + INITRND = 4096; if(INITTEXT == -1) INITTEXT = 4096+HEADR; if(INITDAT == -1) INITDAT = 0; - if(INITRND == -1) - INITRND = 4096; break; case 7: /* elf64 executable */ elfinit(); @@ -393,6 +393,8 @@ main(int argc, char *argv[]) patch(); follow(); doelf(); + if(HEADTYPE == 6) + domacho(); dodata(); dobss(); dostkoff(); diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c index c2f560500..2da88bac1 100644 --- a/src/cmd/6l/pass.c +++ b/src/cmd/6l/pass.c @@ -142,6 +142,11 @@ dobss(void) Sym *s; int32 t; + if(dynptrsize > 0) { + /* dynamic pointer section between data and bss */ + datsize = rnd(datsize, 8); + } + /* now the bss */ bsssize = 0; for(i=0; i<NHASH; i++) @@ -154,12 +159,13 @@ dobss(void) s->size = t; if(t >= 8) bsssize = rnd(bsssize, 8); - s->value = bsssize + datsize; + s->value = bsssize + dynptrsize + datsize; bsssize += t; } + xdefine("data", SBSS, 0); xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, bsssize + datsize); + xdefine("end", SBSS, dynptrsize + bsssize + datsize); } Prog* diff --git a/src/cmd/6l/span.c b/src/cmd/6l/span.c index f1eafff00..18bf8cc0c 100644 --- a/src/cmd/6l/span.c +++ b/src/cmd/6l/span.c @@ -237,6 +237,12 @@ asmsym(void) putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype); continue; + case SMACHO: + if(!s->reachable) + continue; + putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype); + continue; + case SBSS: if(!s->reachable) continue; @@ -715,6 +721,11 @@ vaddr(Adr *a) v += INITTEXT; /* TO DO */ v += s->value; break; + case SMACHO: + if(!s->reachable) + sysfatal("unreachable symbol in vaddr - %s", s->name); + v += INITDAT + datsize + s->value; + break; default: if(!s->reachable) diag("unreachable symbol in vaddr - %s", s->name); diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index 449467a5c..c70af7072 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -257,7 +257,7 @@ needlib(char *name) Sym *s; /* reuse hash code in symbol table */ - p = smprint(".elfload.%s", name); + p = smprint(".dynlib.%s", name); s = lookup(p, 0); if(s->type == 0) { s->type = 100; // avoid SDATA, etc. @@ -414,8 +414,8 @@ asmb(void) { Prog *p; int32 v, magic; - int a, dynsym; - uint32 va, fo, w, symo, startva; + int a, i, dynsym; + uint32 va, fo, w, symo, startva, machlink; uchar *op1; ulong expectpc; ElfEhdr *eh; @@ -547,6 +547,10 @@ asmb(void) datblk(v, datsize-v); } + machlink = 0; + if(HEADTYPE == 6) + machlink = domacholink(); + symsize = 0; spsize = 0; lcsize = 0; @@ -572,7 +576,7 @@ asmb(void) symo = HEADR+textsize+datsize; break; case 6: - symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND); + symo = rnd(HEADR+textsize, INITRND)+rnd(datsize, INITRND)+machlink; break; case 7: case 8: @@ -740,89 +744,7 @@ asmb(void) break; case 6: - /* apple MACH */ - va = HEADR; - mh = getMachoHdr(); - mh->cpu = MACHO_CPU_386; - mh->subcpu = MACHO_SUBCPU_X86; - - /* segment for zero page */ - ms = newMachoSeg("__PAGEZERO", 0); - ms->vsize = va; - - /* text */ - v = rnd(HEADR+textsize, INITRND); - ms = newMachoSeg("__TEXT", 1); - ms->vaddr = va; - ms->vsize = v; - ms->filesize = v; - ms->prot1 = 7; - ms->prot2 = 5; - - msect = newMachoSect(ms, "__text"); - msect->addr = va+HEADR; - msect->size = v - HEADR; - msect->off = HEADR; - msect->flag = 0x400; /* flag - some instructions */ - - /* data */ - w = datsize+bsssize; - ms = newMachoSeg("__DATA", 2); - ms->vaddr = va+v; - ms->vsize = w; - ms->fileoffset = v; - ms->filesize = datsize; - ms->prot1 = 7; - ms->prot2 = 3; - - msect = newMachoSect(ms, "__data"); - msect->addr = va+v; - msect->size = datsize; - msect->off = v; - - msect = newMachoSect(ms, "__bss"); - msect->addr = va+v+datsize; - msect->size = bsssize; - msect->flag = 1; /* flag - zero fill */ - - 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 */ - - if(!debug['d']) { - ml = newMachoLoad(2, 4); /* LC_SYMTAB */ - USED(ml); - - ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ - USED(ml); - - ml = newMachoLoad(14, 6); /* LC_LOAD_DYLINKER */ - ml->data[0] = 12; /* offset to string */ - strcpy((char*)&ml->data[1], "/usr/lib/dyld"); - } - - if(!debug['s']) { - ms = newMachoSeg("__SYMDAT", 1); - ms->vaddr = symdatva; - ms->vsize = 8+symsize+lcsize; - ms->fileoffset = symo; - ms->filesize = 8+symsize+lcsize; - ms->prot1 = 7; - ms->prot2 = 5; - - md = newMachoDebug(); - md->fileoffset = symo+8; - md->filesize = symsize; - - md = newMachoDebug(); - md->fileoffset = symo+8+symsize; - md->filesize = lcsize; - } - - a = machowrite(); - if(a > MACHORESERVE) - diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); + asmbmacho(symdatva, symo); break; case 7: @@ -963,6 +885,17 @@ asmb(void) ph->type = PT_DYNAMIC; ph->flags = PF_R + PF_W; phsh(ph, sh); + + /* + * Thread-local storage segment (really just size). + */ + if(tlsoffset != 0) { + ph = newElfPhdr(); + ph->type = PT_TLS; + ph->flags = PF_R; + ph->memsz = -tlsoffset; + ph->align = 4; + } } ph = newElfPhdr(); @@ -1105,6 +1038,8 @@ datblk(int32 s, int32 n) curp = p; if(!p->from.sym->reachable) diag("unreachable symbol in datblk - %s", p->from.sym->name); + if(p->from.sym->type == SMACHO) + continue; l = p->from.sym->value + p->from.offset - s; c = p->from.scale; i = 0; diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index cc5901fcb..1959b2c74 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -151,6 +151,8 @@ enum SIMPORT, SEXPORT, + SMACHO, /* pointer to mach-o imported symbol */ + NHASH = 10007, NHUNK = 100000, MINSIZ = 4, @@ -272,6 +274,7 @@ EXTERN Prog* curtext; EXTERN Prog* datap; EXTERN Prog* edatap; EXTERN int32 datsize; +EXTERN int32 dynptrsize; EXTERN char debug[128]; EXTERN char literal[32]; EXTERN Prog* etextp; @@ -311,6 +314,7 @@ EXTERN int version; EXTERN Prog zprg; EXTERN int dtype; EXTERN char thechar; +EXTERN int tlsoffset; EXTERN Adr* reloca; EXTERN int doexp, dlm; diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c index 4b6532568..aa197be53 100644 --- a/src/cmd/8l/obj.c +++ b/src/cmd/8l/obj.c @@ -213,6 +213,11 @@ main(int argc, char *argv[]) Bprint(&bso, "HEADR = 0x%ld\n", HEADR); break; case 6: /* apple MACH */ + /* + * OS X system constant - offset from %gs to our TLS. + * Explained in ../../libcgo/darwin_386.c. + */ + tlsoffset = 0x468; machoinit(); HEADR = MACHORESERVE; if(INITTEXT == -1) @@ -223,6 +228,13 @@ main(int argc, char *argv[]) INITRND = 4096; break; case 7: /* elf32 executable */ + /* + * Linux ELF uses TLS offsets negative from %gs. + * Translate 0(GS) and 4(GS) into -8(GS) and -4(GS). + * Also known to ../../pkg/runtime/linux/386/sys.s + * and ../../libcgo/linux_386.c. + */ + tlsoffset = -8; elfinit(); HEADR = ELFRESERVE; if(INITTEXT == -1) @@ -373,6 +385,8 @@ main(int argc, char *argv[]) patch(); follow(); doelf(); + if(HEADTYPE == 6) + domacho(); dodata(); dostkoff(); if(debug['p']) @@ -592,11 +606,14 @@ zaddr(Biobuf *f, Adr *a, Sym *h[]) a->type = Bgetc(f); if(t & T_GOTYPE) a->gotype = h[Bgetc(f)]; + + t = a->type; + if(t == D_INDIR+D_GS) + a->offset += tlsoffset; + s = a->sym; if(s == S) return; - - t = a->type; if(t != D_AUTO && t != D_PARAM) { if(a->gotype) s->gotype = a->gotype; diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c index 7ce419e8f..c624f750a 100644 --- a/src/cmd/8l/pass.c +++ b/src/cmd/8l/pass.c @@ -125,6 +125,11 @@ dodata(void) datsize += u; } + if(dynptrsize > 0) { + /* dynamic pointer section between data and bss */ + datsize = rnd(datsize, 4); + } + /* now the bss */ bsssize = 0; for(i=0; i<NHASH; i++) @@ -135,12 +140,13 @@ dodata(void) continue; t = s->value; s->size = t; - s->value = bsssize + datsize; + s->value = bsssize + dynptrsize + datsize; bsssize += t; } + xdefine("data", SBSS, 0); xdefine("edata", SBSS, datsize); - xdefine("end", SBSS, bsssize + datsize); + xdefine("end", SBSS, dynptrsize + bsssize + datsize); } Prog* @@ -570,7 +576,7 @@ dostkoff(void) p = appendp(p); // load g into CX p->as = AMOVL; p->from.type = D_INDIR+D_GS; - p->from.offset = 0; + p->from.offset = tlsoffset + 0; p->to.type = D_CX; if(debug['K']) { diff --git a/src/cmd/8l/span.c b/src/cmd/8l/span.c index 71607fcf2..6f62f9b4d 100644 --- a/src/cmd/8l/span.c +++ b/src/cmd/8l/span.c @@ -219,6 +219,12 @@ asmsym(void) putsymb(s->name, 'D', s->value+INITDAT, s->version, s->gotype); continue; + case SMACHO: + if(!s->reachable) + continue; + putsymb(s->name, 'D', s->value+INITDAT+datsize+bsssize, s->version, s->gotype); + continue; + case SBSS: if(!s->reachable) continue; @@ -611,6 +617,11 @@ vaddr(Adr *a) sysfatal("unreachable symbol in vaddr - %s", s->name); v += s->value; break; + case SMACHO: + if(!s->reachable) + sysfatal("unreachable symbol in vaddr - %s", s->name); + v += INITDAT + datsize + s->value; + break; default: if(!s->reachable) sysfatal("unreachable symbol in vaddr - %s", s->name); diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 9b122676c..57500680b 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -36,6 +36,7 @@ type Prog struct { Vardef map[string]*Type; Funcdef map[string]*FuncType; PtrSize int64; + GccOptions []string; } // A Type collects information about a type in both the C and Go worlds. diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index e3f526845..f573b98cb 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -172,6 +172,17 @@ func (p *Prog) loadDebugInfo() { p.Typedef = conv.typedef; } +func concat(a, b []string) []string { + c := make([]string, len(a)+len(b)); + for i, s := range a { + c[i] = s; + } + for i, s := range b { + c[i+len(a)] = s; + } + return c; +} + // gccDebug runs gcc -gdwarf-2 over the C program stdin and // returns the corresponding DWARF data and any messages // printed to standard error. @@ -182,7 +193,7 @@ func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) { } tmp := "_cgo_.o"; - _, stderr, ok := run(stdin, []string{ + base := []string{ "gcc", machine, "-Wall", // many warnings @@ -192,7 +203,8 @@ func (p *Prog) gccDebug(stdin []byte) (*dwarf.Data, string) { "-c", // do not link "-xc", // input language is C "-", // read input from standard input - }); + }; + _, stderr, ok := run(stdin, concat(base, p.GccOptions)); if !ok { return nil, string(stderr); } diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index b629f0a22..eb04fa77d 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -11,15 +11,13 @@ package main import ( - "flag"; "fmt"; "go/ast"; "os"; ) func usage() { - fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n"); - flag.PrintDefaults(); + fmt.Fprint(os.Stderr, "usage: cgo [compiler options] file.go\n"); } var ptrSizeMap = map[string]int64 { @@ -28,9 +26,24 @@ var ptrSizeMap = map[string]int64 { "arm": 4 } +var expandName = map[string]string { + "schar": "signed char", + "uchar": "unsigned char", + "ushort": "unsigned short", + "uint": "unsigned int", + "ulong": "unsigned long", + "longlong": "long long", + "ulonglong": "unsigned long long", +} + func main() { - flag.Usage = usage; - flag.Parse(); + args := os.Args; + if len(args) < 2 { + usage(); + os.Exit(2); + } + gccOptions := args[1:len(args)-1]; + input := args[len(args)-1]; arch := os.Getenv("GOARCH"); if arch == "" { @@ -41,14 +54,17 @@ func main() { fatal("unknown architecture %s", arch); } - args := flag.Args(); - if len(args) != 1 { - usage(); - os.Exit(2); + p := openProg(input); + for _, cref := range p.Crefs { + // Convert C.ulong to C.unsigned long, etc. + if expand, ok := expandName[cref.Name]; ok { + cref.Name = expand; + } } - p := openProg(args[0]); + p.PtrSize = ptrSize; p.Preamble = p.Preamble + "\n" + builtinProlog; + p.GccOptions = gccOptions; p.loadDebugInfo(); p.Vardef = make(map[string]*Type); p.Funcdef = make(map[string]*FuncType); @@ -83,5 +99,5 @@ func main() { } p.PackagePath = p.Package; - p.writeOutput(args[0]); + p.writeOutput(input); } diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 91473abeb..d2eedc331 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -198,7 +198,7 @@ const cProlog = ` #include "cgocall.h" #pragma dynld initcgo initcgo "%s/libcgo.so" -#pragma dynld cgo cgo "%s/libcgo.so" +#pragma dynld libcgo_thread_start libcgo_thread_start "%s/libcgo.so" #pragma dynld _cgo_malloc _cgo_malloc "%s/libcgo.so" #pragma dynld _cgo_free free "%s/libcgo.so" diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index cb4857248..e0c2bd1b6 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -243,7 +243,7 @@ typedef struct { #define PT_NOTE 4 /* Auxiliary information. */ #define PT_SHLIB 5 /* Reserved (not used). */ #define PT_PHDR 6 /* Location of program header itself. */ -#define PT_TLS 7 /* Thread local storage segment */ +#define PT_TLS 7 /* Thread local storage segment */ #define PT_LOOS 0x60000000 /* First OS-specific. */ #define PT_HIOS 0x6fffffff /* Last OS-specific. */ #define PT_LOPROC 0x70000000 /* First processor-specific type. */ diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c index 159aceb9e..e4fe963ac 100644 --- a/src/cmd/ld/macho.c +++ b/src/cmd/ld/macho.c @@ -92,6 +92,22 @@ newMachoDebug(void) return &xdebug[ndebug++]; } + +// Generic linking code. + +static uchar *linkdata; +static uint32 nlinkdata; +static uint32 mlinkdata; + +static uchar *strtab; +static uint32 nstrtab; +static uint32 mstrtab; + +static char **dylib; +static int ndylib; + +static vlong linkoff; + int machowrite(void) { @@ -205,3 +221,308 @@ machowrite(void) return Boffset(&bso) - o1; } + +static void* +grow(uchar **dat, uint32 *ndat, uint32 *mdat, uint32 n) +{ + uchar *p; + uint32 old; + + if(*ndat+n > *mdat) { + old = *mdat; + *mdat = (*ndat+n)*2 + 128; + *dat = realloc(*dat, *mdat); + if(*dat == 0) { + diag("out of memory"); + errorexit(); + } + memset(*dat+old, 0, *mdat-old); + } + p = *dat + *ndat; + *ndat += n; + return p; +} + +static int +needlib(char *name) +{ + char *p; + Sym *s; + + /* reuse hash code in symbol table */ + p = smprint(".machoload.%s", name); + s = lookup(p, 0); + if(s->type == 0) { + s->type = 100; // avoid SDATA, etc. + return 1; + } + return 0; +} + +void +domacho(void) +{ + int h, nsym, ptrsize; + char *p; + uchar *dat; + uint32 x; + Sym *s; + + ptrsize = 4; + if(macho64) + ptrsize = 8; + + // empirically, string table must begin with " \x00". + if(!debug['d']) + *(char*)grow(&strtab, &nstrtab, &mstrtab, 2) = ' '; + + nsym = 0; + for(h=0; h<NHASH; h++) { + for(s=hash[h]; s!=S; s=s->link) { + if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynldname == nil) + continue; + if(debug['d']) { + diag("cannot use dynamic loading and -d"); + errorexit(); + } + s->type = SMACHO; + s->value = nsym*ptrsize; + + /* symbol table entry - darwin still puts _ prefixes on all C symbols */ + x = nstrtab; + p = grow(&strtab, &nstrtab, &mstrtab, 1+strlen(s->dynldname)+1); + *p++ = '_'; + strcpy(p, s->dynldname); + + dat = grow(&linkdata, &nlinkdata, &mlinkdata, 8+ptrsize); + dat[0] = x; + dat[1] = x>>8; + dat[2] = x>>16; + dat[3] = x>>24; + dat[4] = 0x01; // type: N_EXT - external symbol + + if(needlib(s->dynldlib)) { + if(ndylib%32 == 0) { + dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]); + if(dylib == nil) { + diag("out of memory"); + errorexit(); + } + } + dylib[ndylib++] = s->dynldlib; + } + nsym++; + } + } + + /* + * list of symbol table indexes. + * we don't take advantage of the opportunity + * to order the symbol table differently from + * this list, so it is boring: 0 1 2 3 4 ... + */ + for(x=0; x<nsym; x++) { + dat = grow(&linkdata, &nlinkdata, &mlinkdata, 4); + dat[0] = x; + dat[1] = x>>8; + dat[2] = x>>16; + dat[3] = x>>24; + } + + dynptrsize = nsym*ptrsize; +} + +vlong +domacholink(void) +{ + linkoff = 0; + if(nlinkdata > 0) { + linkoff = rnd(HEADR+textsize, INITRND) + rnd(datsize, INITRND); + seek(cout, linkoff, 0); + write(cout, linkdata, nlinkdata); + write(cout, strtab, nstrtab); + } + return rnd(nlinkdata+nstrtab, INITRND); +} + +void +asmbmacho(vlong symdatva, vlong symo) +{ + vlong v, w; + vlong va; + int a, i, ptrsize; + MachoHdr *mh; + MachoSect *msect; + MachoSeg *ms; + MachoDebug *md; + MachoLoad *ml; + + /* apple MACH */ + va = INITTEXT - HEADR; + mh = getMachoHdr(); + switch(thechar){ + default: + diag("unknown mach architecture"); + errorexit(); + case '6': + mh->cpu = MACHO_CPU_AMD64; + mh->subcpu = MACHO_SUBCPU_X86; + ptrsize = 8; + break; + case '8': + mh->cpu = MACHO_CPU_386; + mh->subcpu = MACHO_SUBCPU_X86; + ptrsize = 4; + break; + } + + /* segment for zero page */ + ms = newMachoSeg("__PAGEZERO", 0); + ms->vsize = va; + + /* text */ + v = rnd(HEADR+textsize, INITRND); + ms = newMachoSeg("__TEXT", 1); + ms->vaddr = va; + ms->vsize = v; + ms->filesize = v; + ms->prot1 = 7; + ms->prot2 = 5; + + msect = newMachoSect(ms, "__text"); + msect->addr = INITTEXT; + msect->size = textsize; + msect->off = INITTEXT - va; + msect->flag = 0x400; /* flag - some instructions */ + + /* data */ + w = datsize+dynptrsize+bsssize; + ms = newMachoSeg("__DATA", 2+(dynptrsize>0)); + ms->vaddr = va+v; + ms->vsize = w; + ms->fileoffset = v; + ms->filesize = datsize; + ms->prot1 = 7; + ms->prot2 = 3; + + msect = newMachoSect(ms, "__data"); + msect->addr = va+v; + msect->size = datsize; + msect->off = v; + + if(dynptrsize > 0) { + msect = newMachoSect(ms, "__nl_symbol_ptr"); + msect->addr = va+v+datsize; + msect->size = dynptrsize; + msect->align = 2; + msect->flag = 6; /* section with nonlazy symbol pointers */ + /* + * The reserved1 field is supposed to be the index of + * the first entry in the list of symbol table indexes + * in isymtab for the symbols we need. We only use + * pointers, so we need the entire list, so the index + * here should be 0, which luckily is what the Mach-O + * writing code emits by default for this not really reserved field. + msect->reserved1 = 0; - first indirect symbol table entry we need + */ + } + + msect = newMachoSect(ms, "__bss"); + msect->addr = va+v+datsize+dynptrsize; + msect->size = bsssize; + msect->flag = 1; /* flag - zero fill */ + + 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()>>32; + 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']) { + int nsym; + + nsym = dynptrsize/ptrsize; + + ms = newMachoSeg("__LINKEDIT", 0); + ms->vaddr = va+v+rnd(datsize+dynptrsize+bsssize, INITRND); + ms->vsize = nlinkdata+nstrtab; + ms->fileoffset = linkoff; + ms->filesize = nlinkdata+nstrtab; + ms->prot1 = 7; + ms->prot2 = 3; + + ml = newMachoLoad(2, 4); /* LC_SYMTAB */ + ml->data[0] = linkoff; /* symoff */ + ml->data[1] = nsym; /* nsyms */ + ml->data[2] = linkoff + nlinkdata; /* stroff */ + ml->data[3] = nstrtab; /* strsize */ + + ml = newMachoLoad(11, 18); /* LC_DYSYMTAB */ + ml->data[0] = 0; /* ilocalsym */ + ml->data[1] = 0; /* nlocalsym */ + ml->data[2] = 0; /* iextdefsym */ + ml->data[3] = 0; /* nextdefsym */ + ml->data[4] = 0; /* iundefsym */ + ml->data[5] = nsym; /* nundefsym */ + ml->data[6] = 0; /* tocoffset */ + ml->data[7] = 0; /* ntoc */ + ml->data[8] = 0; /* modtaboff */ + ml->data[9] = 0; /* nmodtab */ + ml->data[10] = 0; /* extrefsymoff */ + ml->data[11] = 0; /* nextrefsyms */ + ml->data[12] = linkoff + nlinkdata - nsym*4; /* indirectsymoff */ + ml->data[13] = nsym; /* nindirectsyms */ + ml->data[14] = 0; /* extreloff */ + ml->data[15] = 0; /* nextrel */ + ml->data[16] = 0; /* locreloff */ + ml->data[17] = 0; /* nlocrel */ + + 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]); + } + } + + if(!debug['s']) { + ms = newMachoSeg("__SYMDAT", 1); + ms->vaddr = symdatva; + ms->vsize = 8+symsize+lcsize; + ms->fileoffset = symo; + ms->filesize = 8+symsize+lcsize; + ms->prot1 = 7; + ms->prot2 = 5; + + md = newMachoDebug(); + md->fileoffset = symo+8; + md->filesize = symsize; + + md = newMachoDebug(); + md->fileoffset = symo+8+symsize; + md->filesize = lcsize; + } + + a = machowrite(); + if(a > MACHORESERVE) + diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE); +} diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h index 747adac2d..a96b2a383 100644 --- a/src/cmd/ld/macho.h +++ b/src/cmd/ld/macho.h @@ -61,10 +61,17 @@ void machoinit(void); * for Header, PHeaders, and SHeaders. * May waste some. */ -#define MACHORESERVE 4096 +#define MACHORESERVE 3*1024 enum { MACHO_CPU_AMD64 = (1<<24)|7, MACHO_CPU_386 = 7, MACHO_SUBCPU_X86 = 3, + + MACHO32SYMSIZE = 12, + MACHO64SYMSIZE = 16, }; + +void domacho(void); +vlong domacholink(void); +void asmbmacho(vlong, vlong); |