diff options
author | Russ Cox <rsc@golang.org> | 2014-08-31 22:49:14 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-08-31 22:49:14 -0400 |
commit | a564350b3dcfd480034780da11487c4456809429 (patch) | |
tree | ca655e006228b73f339b0dc3db71f3dfaf7fae56 /src/cmd | |
parent | 21fcd05421c57caf41815f070c8bbf7016fd17fe (diff) | |
download | go-a564350b3dcfd480034780da11487c4456809429.tar.gz |
cmd/ld: diagnose Go calling C
For example:
go build -ldflags -C cmd/go 2>&1 | awk '{print $NF}' | sort | uniq -c | sort -nr
LGTM=khr
R=khr, josharian
CC=golang-codereviews
https://codereview.appspot.com/135170044
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/cc/pgen.c | 1 | ||||
-rw-r--r-- | src/cmd/ld/lib.c | 53 | ||||
-rw-r--r-- | src/cmd/ld/lib.h | 1 | ||||
-rw-r--r-- | src/cmd/ld/pobj.c | 2 |
4 files changed, 57 insertions, 0 deletions
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c index 53410a11a..99128d400 100644 --- a/src/cmd/cc/pgen.c +++ b/src/cmd/cc/pgen.c @@ -131,6 +131,7 @@ codgen(Node *n, Node *nn) nearln = nn->lineno; p = gtext(n1->sym, stkoff); + p->from.sym->cfunc = 1; sp = p; /* diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index a68993715..51e10bb99 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -1554,3 +1554,56 @@ diag(char *fmt, ...) errorexit(); } } + +void +checkgo(void) +{ + LSym *s; + Reloc *r; + int i; + int changed; + + if(!debug['C']) + return; + + // TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all, + // which would simplify this logic quite a bit. + + // Mark every Go-called C function with cfunc=2, recursively. + do { + changed = 0; + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) + continue; + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { + if(r->sym->cfunc == 1) { + changed = 1; + r->sym->cfunc = 2; + } + } + } + } + } + }while(changed); + + // Complain about Go-called C functions that can split the stack + // (that can be preempted for garbage collection or trigger a stack copy). + for(s = ctxt->textp; s != nil; s = s->next) { + if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) { + for(i=0; i<s->nr; i++) { + r = &s->r[i]; + if(r->sym == nil) + continue; + if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) { + if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit) + print("Go %s calls C %s\n", s->name, r->sym->name); + else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit) + print("Go calls C %s calls %s\n", s->name, r->sym->name); + } + } + } + } +} diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index dd2399023..067ffa0bc 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -183,6 +183,7 @@ uint16 be16(uchar *b); uint32 be32(uchar *b); uint64 be64(uchar *b); void callgraph(void); +void checkgo(void); void cflush(void); void codeblk(int64 addr, int64 size); vlong cpos(void); diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c index d78dacd36..54c5ef247 100644 --- a/src/cmd/ld/pobj.c +++ b/src/cmd/ld/pobj.c @@ -71,6 +71,7 @@ main(int argc, char *argv[]) if(thechar == '6') flagcount("8", "assume 64-bit addresses", &debug['8']); flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); + flagcount("C", "check Go calls to C code", &debug['C']); flagint64("D", "addr: data address", &INITDAT); flagstr("E", "sym: entry symbol", &INITENTRY); if(thechar == '5') @@ -162,6 +163,7 @@ main(int argc, char *argv[]) mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); } + checkgo(); deadcode(); callgraph(); paramspace = "SP"; /* (FP) now (SP) on output */ |