Commit 0bb14d74 authored by Russ Cox's avatar Russ Cox

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://golang.org/cl/135170044
parent 310bc980
...@@ -126,6 +126,7 @@ struct LSym ...@@ -126,6 +126,7 @@ struct LSym
short type; short type;
short version; short version;
uchar dupok; uchar dupok;
uchar cfunc;
uchar external; uchar external;
uchar nosplit; uchar nosplit;
uchar reachable; uchar reachable;
......
...@@ -131,6 +131,7 @@ codgen(Node *n, Node *nn) ...@@ -131,6 +131,7 @@ codgen(Node *n, Node *nn)
nearln = nn->lineno; nearln = nn->lineno;
p = gtext(n1->sym, stkoff); p = gtext(n1->sym, stkoff);
p->from.sym->cfunc = 1;
sp = p; sp = p;
/* /*
......
...@@ -1554,3 +1554,56 @@ diag(char *fmt, ...) ...@@ -1554,3 +1554,56 @@ diag(char *fmt, ...)
errorexit(); 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);
}
}
}
}
}
...@@ -183,6 +183,7 @@ uint16 be16(uchar *b); ...@@ -183,6 +183,7 @@ uint16 be16(uchar *b);
uint32 be32(uchar *b); uint32 be32(uchar *b);
uint64 be64(uchar *b); uint64 be64(uchar *b);
void callgraph(void); void callgraph(void);
void checkgo(void);
void cflush(void); void cflush(void);
void codeblk(int64 addr, int64 size); void codeblk(int64 addr, int64 size);
vlong cpos(void); vlong cpos(void);
......
...@@ -71,6 +71,7 @@ main(int argc, char *argv[]) ...@@ -71,6 +71,7 @@ main(int argc, char *argv[])
if(thechar == '6') if(thechar == '6')
flagcount("8", "assume 64-bit addresses", &debug['8']); flagcount("8", "assume 64-bit addresses", &debug['8']);
flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo); 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); flagint64("D", "addr: data address", &INITDAT);
flagstr("E", "sym: entry symbol", &INITENTRY); flagstr("E", "sym: entry symbol", &INITENTRY);
if(thechar == '5') if(thechar == '5')
...@@ -162,6 +163,7 @@ main(int argc, char *argv[]) ...@@ -162,6 +163,7 @@ main(int argc, char *argv[])
mark(linklookup(ctxt, "runtime.read_tls_fallback", 0)); mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
} }
checkgo();
deadcode(); deadcode();
callgraph(); callgraph();
paramspace = "SP"; /* (FP) now (SP) on output */ paramspace = "SP"; /* (FP) now (SP) on output */
......
...@@ -38,7 +38,8 @@ ...@@ -38,7 +38,8 @@
// - type [int] // - type [int]
// - name [string] // - name [string]
// - version [int] // - version [int]
// - dupok [int] // - flags [int]
// 1 dupok
// - size [int] // - size [int]
// - gotype [symbol reference] // - gotype [symbol reference]
// - p [data block] // - p [data block]
...@@ -50,7 +51,9 @@ ...@@ -50,7 +51,9 @@
// - args [int] // - args [int]
// - locals [int] // - locals [int]
// - nosplit [int] // - nosplit [int]
// - leaf [int] // - flags [int]
// 1 leaf
// 2 C function
// - nlocal [int] // - nlocal [int]
// - local [nlocal automatics] // - local [nlocal automatics]
// - pcln [pcln table] // - pcln [pcln table]
...@@ -289,6 +292,8 @@ writesym(Link *ctxt, Biobuf *b, LSym *s) ...@@ -289,6 +292,8 @@ writesym(Link *ctxt, Biobuf *b, LSym *s)
Bprint(ctxt->bso, "t=%d ", s->type); Bprint(ctxt->bso, "t=%d ", s->type);
if(s->dupok) if(s->dupok)
Bprint(ctxt->bso, "dupok "); Bprint(ctxt->bso, "dupok ");
if(s->cfunc)
Bprint(ctxt->bso, "cfunc ");
if(s->nosplit) if(s->nosplit)
Bprint(ctxt->bso, "nosplit "); Bprint(ctxt->bso, "nosplit ");
Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value); Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
...@@ -351,7 +356,7 @@ writesym(Link *ctxt, Biobuf *b, LSym *s) ...@@ -351,7 +356,7 @@ writesym(Link *ctxt, Biobuf *b, LSym *s)
wrint(b, s->args); wrint(b, s->args);
wrint(b, s->locals); wrint(b, s->locals);
wrint(b, s->nosplit); wrint(b, s->nosplit);
wrint(b, s->leaf); wrint(b, s->leaf | s->cfunc<<1);
n = 0; n = 0;
for(a = s->autom; a != nil; a = a->link) for(a = s->autom; a != nil; a = a->link)
n++; n++;
...@@ -519,6 +524,7 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) ...@@ -519,6 +524,7 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
if(v != 0 && v != 1) if(v != 0 && v != 1)
sysfatal("invalid symbol version %d", v); sysfatal("invalid symbol version %d", v);
dupok = rdint(f); dupok = rdint(f);
dupok &= 1;
size = rdint(f); size = rdint(f);
if(v != 0) if(v != 0)
...@@ -573,7 +579,9 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) ...@@ -573,7 +579,9 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
s->args = rdint(f); s->args = rdint(f);
s->locals = rdint(f); s->locals = rdint(f);
s->nosplit = rdint(f); s->nosplit = rdint(f);
s->leaf = rdint(f); v = rdint(f);
s->leaf = v&1;
s->cfunc = v&2;
n = rdint(f); n = rdint(f);
for(i=0; i<n; i++) { for(i=0; i<n; i++) {
a = emallocz(sizeof *a); a = emallocz(sizeof *a);
...@@ -629,6 +637,8 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn) ...@@ -629,6 +637,8 @@ readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
Bprint(ctxt->bso, "t=%d ", s->type); Bprint(ctxt->bso, "t=%d ", s->type);
if(s->dupok) if(s->dupok)
Bprint(ctxt->bso, "dupok "); Bprint(ctxt->bso, "dupok ");
if(s->cfunc)
Bprint(ctxt->bso, "cfunc ");
if(s->nosplit) if(s->nosplit)
Bprint(ctxt->bso, "nosplit "); Bprint(ctxt->bso, "nosplit ");
Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value); Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
......
...@@ -602,7 +602,8 @@ func (r *objReader) parseObject(prefix []byte) error { ...@@ -602,7 +602,8 @@ func (r *objReader) parseObject(prefix []byte) error {
s := &Sym{SymID: r.readSymID()} s := &Sym{SymID: r.readSymID()}
r.p.Syms = append(r.p.Syms, s) r.p.Syms = append(r.p.Syms, s)
s.Kind = SymKind(typ) s.Kind = SymKind(typ)
s.DupOK = r.readInt() != 0 flags := r.readInt()
s.DupOK = flags&1 != 0
s.Size = r.readInt() s.Size = r.readInt()
s.Type = r.readSymID() s.Type = r.readSymID()
s.Data = r.readData() s.Data = r.readData()
...@@ -623,7 +624,8 @@ func (r *objReader) parseObject(prefix []byte) error { ...@@ -623,7 +624,8 @@ func (r *objReader) parseObject(prefix []byte) error {
s.Func = f s.Func = f
f.Args = r.readInt() f.Args = r.readInt()
f.Frame = r.readInt() f.Frame = r.readInt()
f.Leaf = r.readInt() != 0 flags := r.readInt()
f.Leaf = flags&1 != 0
f.NoSplit = r.readInt() != 0 f.NoSplit = r.readInt() != 0
f.Var = make([]Var, r.readInt()) f.Var = make([]Var, r.readInt())
for i := range f.Var { for i := range f.Var {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment