From 7a35908d56fb8a0c06db4fdc2b70640862e75642 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 23 Mar 2010 06:46:30 -0700 Subject: Add support for #pragma dynexport. R=rsc CC=golang-dev http://codereview.appspot.com/661043 --- src/cmd/5c/swt.c | 7 ++-- src/cmd/5l/asm.c | 96 +++++++++++++++++++++++++++++++++++------------------- src/cmd/5l/l.h | 1 + src/cmd/6c/swt.c | 7 ++-- src/cmd/6l/asm.c | 77 +++++++++++++++++++++++++------------------ src/cmd/6l/l.h | 1 + src/cmd/8c/swt.c | 7 ++-- src/cmd/8l/asm.c | 75 +++++++++++++++++++++++++----------------- src/cmd/8l/l.h | 1 + src/cmd/cc/cc.h | 11 +++++++ src/cmd/cc/dpchk.c | 29 +++++++++++++++++ src/cmd/cc/lexbody | 7 ++++ src/cmd/cc/macbody | 4 +++ src/cmd/ld/elf.c | 56 +++++++++++++++++++++++++++++++ src/cmd/ld/elf.h | 1 + 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; itype == 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-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; ilink) { - 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-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; ilink) { - 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-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 @@ -53,6 +53,13 @@ pragdynimport(void) ; } +void +pragdynexport(void) +{ + while(getnsc() != '\n') + ; +} + void pragfpround(void) { 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; hlink) { + 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; idynimplib != 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