diff options
author | Ian Lance Taylor <iant@golang.org> | 2010-03-23 06:46:30 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2010-03-23 06:46:30 -0700 |
commit | 7a35908d56fb8a0c06db4fdc2b70640862e75642 (patch) | |
tree | 51bae5f6a4a8102569673b40c33f03d1c402f03f | |
parent | 959ab0cfa4baa2027f7a9634e5ed6396e6d5da6f (diff) | |
download | golang-7a35908d56fb8a0c06db4fdc2b70640862e75642.tar.gz |
Add support for #pragma dynexport.
R=rsc
CC=golang-dev
http://codereview.appspot.com/661043
-rw-r--r-- | src/cmd/5c/swt.c | 7 | ||||
-rw-r--r-- | src/cmd/5l/asm.c | 96 | ||||
-rw-r--r-- | src/cmd/5l/l.h | 1 | ||||
-rw-r--r-- | src/cmd/6c/swt.c | 7 | ||||
-rw-r--r-- | src/cmd/6l/asm.c | 77 | ||||
-rw-r--r-- | src/cmd/6l/l.h | 1 | ||||
-rw-r--r-- | src/cmd/8c/swt.c | 7 | ||||
-rw-r--r-- | src/cmd/8l/asm.c | 75 | ||||
-rw-r--r-- | src/cmd/8l/l.h | 1 | ||||
-rw-r--r-- | src/cmd/cc/cc.h | 11 | ||||
-rw-r--r-- | src/cmd/cc/dpchk.c | 29 | ||||
-rw-r--r-- | src/cmd/cc/lexbody | 7 | ||||
-rw-r--r-- | src/cmd/cc/macbody | 4 | ||||
-rw-r--r-- | src/cmd/ld/elf.c | 56 | ||||
-rw-r--r-- | src/cmd/ld/elf.h | 1 | ||||
-rw-r--r-- | src/cmd/ld/go.c | 87 |
16 files changed, 362 insertions, 105 deletions
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c index 3aaf748a4..75f768dda 100644 --- a/src/cmd/5c/swt.c +++ b/src/cmd/5c/swt.c @@ -374,7 +374,7 @@ outcode(void) } Bprint(&outbuf, "%s\n", thestring); - if(ndynimp > 0) { + if(ndynimp > 0 || ndynexp > 0) { int i; Bprint(&outbuf, "\n"); @@ -383,7 +383,10 @@ outcode(void) Bprint(&outbuf, "$$ // dynimport\n", thestring); for(i=0; i<ndynimp; i++) Bprint(&outbuf, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path); - Bprint(&outbuf, "$$\n\n"); + Bprint(&outbuf, "\n$$ // dynexport\n", thestring); + for(i=0; i<ndynexp; i++) + Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); + Bprint(&outbuf, "\n$$\n\n"); } Bprint(&outbuf, "!\n"); diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c index 306d828b2..f7cbccec5 100644 --- a/src/cmd/5l/asm.c +++ b/src/cmd/5l/asm.c @@ -192,11 +192,27 @@ enum { vlong elfstr[NElfStr]; +static int +needlib(char *name) +{ + char *p; + Sym *s; + + /* reuse hash code in symbol table */ + p = smprint(".dynlib.%s", name); + s = lookup(p, 0); + if(s->type == 0) { + s->type = 100; // avoid SDATA, etc. + return 1; + } + return 0; +} + void doelf(void) { - Sym *s, *shstrtab, *dynamic, *dynstr; - int h, nsym; + Sym *s, *shstrtab, *dynamic, *dynstr, *d; + int h, nsym, t; if(!iself) return; @@ -267,48 +283,62 @@ doelf(void) for(s=hash[h]; s!=S; s=s->link) { if(!s->reachable || (s->type != SDATA && s->type != SBSS) || s->dynimpname == nil) continue; - #if 0 - d = lookup(".rel", 0); - addaddr(d, s); - adduint32(d, ELF32_R_INFO(nsym, R_386_32)); + + if(!s->dynexport) { + d = lookup(".rel", 0); + addaddr(d, s); + adduint32(d, ELF32_R_INFO(nsym, R_ARM_ABS32)); + } + nsym++; d = lookup(".dynsym", 0); adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname)); - adduint32(d, 0); /* value */ - adduint32(d, 0); /* size of object */ + /* value */ + if(!s->dynexport) + adduint32(d, 0); + else + addaddr(d, s); + + /* size of object */ + adduint32(d, 0); + + /* type */ t = STB_GLOBAL << 4; - t |= STT_OBJECT; // works for func too, empirically + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; adduint8(d, t); - adduint8(d, 0); /* reserved */ - adduint16(d, SHN_UNDEF); /* section where symbol is defined */ - if(needlib(s->dynimplib)) + /* reserved */ + adduint8(d, 0); + + /* section where symbol is defined */ + if(!s->dynexport) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 9; + break; + case SDATA: + t = 10; + break; + case SBSS: + t = 11; + break; + } + adduint16(d, t); + } + + if(!s->dynexport && needlib(s->dynimplib)) elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib)); - #endif } } - /* - * hash table. - * only entries that other objects need to find when - * linking us need to be in the table. right now that is - * no entries. - * - * freebsd insists on having chains enough for all - * the local symbols, though. for now, we just lay - * down a trivial hash table with 1 bucket and a long chain, - * because no one is actually looking for our symbols. - */ - s = lookup(".hash", 0); - s->type = SDATA; // TODO: rodata - s->reachable = 1; - adduint32(s, 1); // nbucket - adduint32(s, nsym); // nchain - adduint32(s, nsym-1); // bucket 0 - adduint32(s, 0); // chain 0 - for(h=1; h<nsym; h++) // chain nsym-1 -> nsym-2 -> ... -> 2 -> 1 -> 0 - adduint32(s, h-1); + elfdynhash(nsym); /* * .dynamic table diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h index 45ddd616f..44bd923a9 100644 --- a/src/cmd/5l/l.h +++ b/src/cmd/5l/l.h @@ -125,6 +125,7 @@ struct Sym uchar subtype; uchar dupok; uchar reachable; + uchar dynexport; int32 value; int32 sig; int32 size; diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c index cdb948f89..0c8370468 100644 --- a/src/cmd/6c/swt.c +++ b/src/cmd/6c/swt.c @@ -232,7 +232,7 @@ outcode(void) Binit(&b, f, OWRITE); Bprint(&b, "%s\n", thestring); - if(ndynimp > 0) { + if(ndynimp > 0 || ndynexp > 0) { int i; Bprint(&b, "\n"); @@ -241,7 +241,10 @@ outcode(void) Bprint(&b, "$$ // dynimport\n", thestring); for(i=0; i<ndynimp; i++) Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path); - Bprint(&b, "$$\n\n"); + Bprint(&b, "\n$$ // dynexport\n", thestring); + for(i=0; i<ndynexp; i++) + Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); + Bprint(&b, "\n$$\n\n"); } Bprint(&b, "!\n"); diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c index 1fc3db98d..af00f5594 100644 --- a/src/cmd/6l/asm.c +++ b/src/cmd/6l/asm.c @@ -351,50 +351,65 @@ doelf(void) nsym = 1; // sym 0 is reserved 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->dynimpname == nil) + if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil) continue; - d = lookup(".rela", 0); - addaddr(d, s); - adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64)); - adduint64(d, 0); + if(!s->dynexport) { + d = lookup(".rela", 0); + addaddr(d, s); + adduint64(d, ELF64_R_INFO(nsym, R_X86_64_64)); + adduint64(d, 0); + } + nsym++; d = lookup(".dynsym", 0); adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname)); + /* type */ t = STB_GLOBAL << 4; - t |= STT_OBJECT; // works for func too, empirically + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; adduint8(d, t); - adduint8(d, 0); /* reserved */ - adduint16(d, SHN_UNDEF); /* section where symbol is defined */ - adduint64(d, 0); /* value */ - adduint64(d, 0); /* size of object */ - if(needlib(s->dynimplib)) + /* reserved */ + adduint8(d, 0); + + /* section where symbol is defined */ + if(!s->dynexport) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 9; + break; + case SDATA: + t = 10; + break; + case SBSS: + t = 11; + break; + } + adduint16(d, t); + } + + /* value */ + if(!s->dynexport) + adduint64(d, 0); + else + addaddr(d, s); + + /* size of object */ + adduint64(d, 0); + + if(!s->dynexport && needlib(s->dynimplib)) elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib)); } } - /* - * hash table. - * only entries that other objects need to find when - * linking us need to be in the table. right now that is - * no entries. - * - * freebsd insists on having chains enough for all - * the local symbols, though. for now, we just lay - * down a trivial hash table with 1 bucket and a long chain, - * because no one is actually looking for our symbols. - */ - s = lookup(".hash", 0); - s->type = SDATA; // TODO: rodata - s->reachable = 1; - adduint32(s, 1); // nbucket - adduint32(s, nsym); // nchain - adduint32(s, nsym-1); // bucket 0 - adduint32(s, 0); // chain 0 - for(h=1; h<nsym; h++) // chain nsym-1 -> nsym-2 -> ... -> 2 -> 1 -> 0 - adduint32(s, h-1); + elfdynhash(nsym); /* * .dynamic table diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h index 4b911ff69..5f99e9a51 100644 --- a/src/cmd/6l/l.h +++ b/src/cmd/6l/l.h @@ -123,6 +123,7 @@ struct Sym uchar subtype; uchar dupok; uchar reachable; + uchar dynexport; vlong value; vlong size; int32 sig; diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c index 035b8e9c3..72cebc00c 100644 --- a/src/cmd/8c/swt.c +++ b/src/cmd/8c/swt.c @@ -231,7 +231,7 @@ outcode(void) Binit(&b, f, OWRITE); Bprint(&b, "%s\n", thestring); - if(ndynimp > 0) { + if(ndynimp > 0 || ndynexp > 0) { int i; Bprint(&b, "\n"); @@ -240,7 +240,10 @@ outcode(void) Bprint(&b, "$$ // dynimport\n", thestring); for(i=0; i<ndynimp; i++) Bprint(&b, "dynimport %s %s %s\n", dynimp[i].local, dynimp[i].remote, dynimp[i].path); - Bprint(&b, "$$\n\n"); + Bprint(&b, "\n$$ // dynexport\n", thestring); + for(i=0; i<ndynexp; i++) + Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); + Bprint(&b, "\n$$\n\n"); } Bprint(&b, "!\n"); diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c index a4d8adc31..eddf6617b 100644 --- a/src/cmd/8l/asm.c +++ b/src/cmd/8l/asm.c @@ -342,49 +342,64 @@ doelf(void) nsym = 1; // sym 0 is reserved 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->dynimpname == nil) + if(!s->reachable || (s->type != STEXT && s->type != SDATA && s->type != SBSS) || s->dynimpname == nil) continue; - d = lookup(".rel", 0); - addaddr(d, s); - adduint32(d, ELF32_R_INFO(nsym, R_386_32)); + if(!s->dynexport) { + d = lookup(".rel", 0); + addaddr(d, s); + adduint32(d, ELF32_R_INFO(nsym, R_386_32)); + } + nsym++; d = lookup(".dynsym", 0); adduint32(d, addstring(lookup(".dynstr", 0), s->dynimpname)); - adduint32(d, 0); /* value */ - adduint32(d, 0); /* size of object */ + /* value */ + if(!s->dynexport) + adduint32(d, 0); + else + addaddr(d, s); + + /* size of object */ + adduint32(d, 0); + + /* type */ t = STB_GLOBAL << 4; - t |= STT_OBJECT; // works for func too, empirically + if(s->dynexport && s->type == STEXT) + t |= STT_FUNC; + else + t |= STT_OBJECT; adduint8(d, t); - adduint8(d, 0); /* reserved */ - adduint16(d, SHN_UNDEF); /* section where symbol is defined */ - if(needlib(s->dynimplib)) + /* reserved */ + adduint8(d, 0); + + /* section where symbol is defined */ + if(!s->dynexport) + adduint16(d, SHN_UNDEF); + else { + switch(s->type) { + default: + case STEXT: + t = 9; + break; + case SDATA: + t = 10; + break; + case SBSS: + t = 11; + break; + } + adduint16(d, t); + } + + if(!s->dynexport && needlib(s->dynimplib)) elfwritedynent(dynamic, DT_NEEDED, addstring(dynstr, s->dynimplib)); } } - /* - * hash table. - * only entries that other objects need to find when - * linking us need to be in the table. right now that is - * no entries. - * - * freebsd insists on having chains enough for all - * the local symbols, though. for now, we just lay - * down a trivial hash table with 1 bucket and a long chain, - * because no one is actually looking for our symbols. - */ - s = lookup(".hash", 0); - s->type = SDATA; // TODO: rodata - s->reachable = 1; - adduint32(s, 1); // nbucket - adduint32(s, nsym); // nchain - adduint32(s, nsym-1); // bucket 0 - adduint32(s, 0); // chain 0 - for(h=1; h<nsym; h++) // chain nsym-1 -> nsym-2 -> ... -> 2 -> 1 -> 0 - adduint32(s, h-1); + elfdynhash(nsym); /* * .dynamic table diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h index 04f6c0e27..8f02bdefd 100644 --- a/src/cmd/8l/l.h +++ b/src/cmd/8l/l.h @@ -123,6 +123,7 @@ struct Sym uchar subtype; uchar dupok; uchar reachable; + uchar dynexport; int32 value; int32 size; int32 sig; diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h index 4241c18f7..725a3cb08 100644 --- a/src/cmd/cc/cc.h +++ b/src/cmd/cc/cc.h @@ -57,6 +57,7 @@ typedef struct Term Term; typedef struct Init Init; typedef struct Bits Bits; typedef struct Dynimp Dynimp; +typedef struct Dynexp Dynexp; #define NHUNK 50000L #define BUFSIZ 8192 @@ -454,6 +455,15 @@ struct Dynimp EXTERN Dynimp *dynimp; EXTERN int ndynimp; +struct Dynexp +{ + char* local; + char* remote; +}; + +EXTERN Dynexp *dynexp; +EXTERN int ndynexp; + EXTERN struct { Type* tenum; /* type of entire enum */ @@ -761,6 +771,7 @@ void pragfpround(void); void pragtextflag(void); void pragincomplete(void); void pragdynimport(void); +void pragdynexporg(void); /* * calls to machine depend part diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c index 99d8c05f1..046c0e4da 100644 --- a/src/cmd/cc/dpchk.c +++ b/src/cmd/cc/dpchk.c @@ -566,3 +566,32 @@ out: while(getnsc() != '\n') ; } + +void +pragdynexport(void) +{ + Sym *local, *remote; + Dynexp *f; + + local = getsym(); + if(local == nil) + goto err; + + remote = getsym(); + if(remote == nil) + goto err; + + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + f = &dynexp[ndynexp++]; + f->local = local->name; + f->remote = remote->name; + goto out; + +err: + yyerror("usage: #pragma dynexport local remote"); + +out: + while(getnsc() != '\n') + ; +} diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody index 743e6e52d..0bccc1733 100644 --- a/src/cmd/cc/lexbody +++ b/src/cmd/cc/lexbody @@ -54,6 +54,13 @@ pragdynimport(void) } void +pragdynexport(void) +{ + while(getnsc() != '\n') + ; +} + +void pragfpround(void) { while(getnsc() != '\n') diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody index 37ddc81c9..ca8a54c0b 100644 --- a/src/cmd/cc/macbody +++ b/src/cmd/cc/macbody @@ -743,6 +743,10 @@ macprag(void) pragdynimport(); return; } + if(s && strcmp(s->name, "dynexport") == 0) { + pragdynexport(); + return; + } while(getnsc() != '\n') ; return; diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c index d2adca16c..a0bcba35a 100644 --- a/src/cmd/ld/elf.c +++ b/src/cmd/ld/elf.c @@ -309,3 +309,59 @@ elfinterp(ElfShdr *sh, uint64 startva, char *p) sh->off = ELFRESERVE - n; sh->size = n; } + +void +elfdynhash(int nsym) +{ + Sym *s, *sy; + int i, h, nbucket, b; + uchar *pc; + uint32 hc, g; + uint32 *chain, *buckets; + + s = lookup(".hash", 0); + s->type = SDATA; // TODO: rodata + s->reachable = 1; + + i = nsym; + nbucket = 1; + while(i > 0) { + ++nbucket; + i >>= 1; + } + + chain = malloc(nsym * sizeof(uint32)); + memset(chain, 0, nsym * sizeof(uint32)); + buckets = malloc(nbucket * sizeof(uint32)); + memset(buckets, 0, nbucket * sizeof(uint32)); + i = 1; + for(h = 0; h<NHASH; h++) { + for(sy=hash[h]; sy!=S; sy=sy->link) { + if (!sy->reachable || (sy->type != STEXT && sy->type != SDATA && sy->type != SBSS) || sy->dynimpname == nil) + continue; + + hc = 0; + for(pc = (uchar*)sy->dynimpname; *pc; pc++) { + hc = (hc<<4) + *pc; + g = hc & 0xf0000000; + hc ^= g >> 24; + hc &= ~g; + } + + b = hc % nbucket; + chain[i] = buckets[b]; + buckets[b] = i; + i++; + } + } + + adduint32(s, nbucket); + adduint32(s, nsym); + for(i = 0; i<nbucket; i++) + adduint32(s, buckets[i]); + for(i = 0; i<nsym; i++) + adduint32(s, chain[i]); + + free(chain); + free(buckets); +} diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h index cd78f2d9c..9b5fdb17e 100644 --- a/src/cmd/ld/elf.h +++ b/src/cmd/ld/elf.h @@ -964,6 +964,7 @@ extern int numelfshdr; extern int iself; int elfwriteinterp(void); void elfinterp(ElfShdr*, uint64, char*); +void elfdynhash(int); /* * Total amount of space to reserve at the start of the file diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 4a3b4725b..b5e0def7b 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -67,9 +67,13 @@ ilookup(char *name) static void loadpkgdata(char*, char*, char*, int); static void loaddynimport(char*, char*, int); +static void loaddynexport(char*, char*, char*, int); static int parsemethod(char**, char*, char**); static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); +static int ndynexp; +static Sym **dynexp; + void ldpkg(Biobuf *f, char *pkg, int64 len, char *filename) { @@ -156,7 +160,25 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename) fprint(2, "%s: cannot find end of // dynimport section in %s\n", argv0, filename); return; } - loaddynimport(filename, p0 + 1, p1 - p0); + loaddynimport(filename, p0 + 1, p1 - (p0+1)); + } + + // look for dynexp section + p0 = strstr(p1, "\n$$ // dynexport"); + if(p0 != nil) { + p0 = strchr(p0+1, '\n'); + if(p0 == nil) { + fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename); + return; + } + p1 = strstr(p0, "\n$$"); + if(p1 == nil) + p1 = strstr(p0, "\n!\n"); + if(p1 == nil) { + fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename); + return; + } + loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1)); } } @@ -339,13 +361,12 @@ parsemethod(char **pp, char *ep, char **methp) static void loaddynimport(char *file, char *p, int n) { - char *next, *name, *def, *p0, *lib; + char *pend, *next, *name, *def, *p0, *lib; Sym *s; - p[n] = '\0'; - + pend = p + n; p0 = p; - for(; *p; p=next) { + for(; p<pend; p=next) { next = strchr(p, '\n'); if(next == nil) next = ""; @@ -384,6 +405,59 @@ err: nerrors++; } +static void +loaddynexport(char *file, char *pkg, char *p, int n) +{ + char *pend, *next, *local, *elocal, *remote, *p0; + Sym *s; + + pend = p + n; + p0 = p; + for(; p<pend; p=next) { + next = strchr(p, '\n'); + if(next == nil) + next = ""; + else + *next++ = '\0'; + p0 = p; + if(strncmp(p, "dynexport ", 10) != 0) + goto err; + p += 10; + local = p; + p = strchr(local, ' '); + if(p == nil) + goto err; + while(*p == ' ') + p++; + remote = p; + + // successful parse: now can edit the line + *strchr(local, ' ') = 0; + + elocal = expandpkg(local, pkg); + + s = lookup(elocal, 0); + if(s->dynimplib != nil) { + fprint(2, "%s: symbol is both dynimport and dynexport %s\n", argv0, local); + nerrors++; + } + s->dynimpname = remote; + s->dynexport = 1; + + if(ndynexp%32 == 0) + dynexp = realloc(dynexp, (ndynexp+32)*sizeof dynexp[0]); + dynexp[ndynexp++] = s; + + if (elocal != local) + free(elocal); + } + return; + +err: + fprint(2, "%s: invalid dynexport line: %s\n", argv0, p0); + nerrors++; +} + static int markdepth; static void @@ -502,6 +576,9 @@ deadcode(void) for(i=0; i<nelem(morename); i++) mark(lookup(morename[i], 0)); + for(i=0; i<ndynexp; i++) + mark(dynexp[i]); + // remove dead data sweeplist(&datap, &edatap); } |