Commit dac4c3ee authored by Shenghou Ma's avatar Shenghou Ma

cmd/cgo, cmd/cc, cmd/ld: detect dynamic linker automatically

Some newer Linux distributions (Ubuntu ARM at least) use a new multiarch
directory organization, where dynamic linker is no longer in the hardcoded
path in our linker.
For example, Ubuntu 12.04 ARM hardfloat places its dynamic linker at
/lib/arm-linux-gnueabihf/ld-linux.so.3

Ref: http://lackof.org/taggart/hacking/multiarch/

Also, to support Debian GNU/kFreeBSD as a FreeBSD variant, we need this capability, so it's part of issue 3533.

This CL add a new pragma (#pragma dynlinker "path") to cc.

R=iant, rsc
CC=golang-dev
https://golang.org/cl/6086043
parent a29304bf
...@@ -405,6 +405,10 @@ outcode(void) ...@@ -405,6 +405,10 @@ outcode(void)
Bprint(&outbuf, "\n$$ // dynexport\n"); Bprint(&outbuf, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++) for(i=0; i<ndynexp; i++)
Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); Bprint(&outbuf, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
Bprint(&outbuf, "\n$$ // dynlinker\n");
if(dynlinker != nil) {
Bprint(&outbuf, "dynlinker %s\n", dynlinker);
}
Bprint(&outbuf, "\n$$\n\n"); Bprint(&outbuf, "\n$$\n\n");
} }
Bprint(&outbuf, "!\n"); Bprint(&outbuf, "!\n");
......
...@@ -106,6 +106,7 @@ main(int argc, char *argv[]) ...@@ -106,6 +106,7 @@ main(int argc, char *argv[])
INITENTRY = EARGF(usage()); INITENTRY = EARGF(usage());
break; break;
case 'I': case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage()); interpreter = EARGF(usage());
break; break;
case 'L': case 'L':
......
...@@ -259,6 +259,10 @@ outcode(void) ...@@ -259,6 +259,10 @@ outcode(void)
Bprint(&b, "\n$$ // dynexport\n"); Bprint(&b, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++) for(i=0; i<ndynexp; i++)
Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
Bprint(&b, "\n$$ // dynlinker\n");
if(dynlinker != nil) {
Bprint(&b, "dynlinker %s\n", dynlinker);
}
Bprint(&b, "\n$$\n\n"); Bprint(&b, "\n$$\n\n");
} }
Bprint(&b, "!\n"); Bprint(&b, "!\n");
......
...@@ -114,6 +114,7 @@ main(int argc, char *argv[]) ...@@ -114,6 +114,7 @@ main(int argc, char *argv[])
HEADTYPE = headtype(EARGF(usage())); HEADTYPE = headtype(EARGF(usage()));
break; break;
case 'I': case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage()); interpreter = EARGF(usage());
break; break;
case 'L': case 'L':
......
...@@ -263,6 +263,10 @@ outcode(void) ...@@ -263,6 +263,10 @@ outcode(void)
Bprint(&b, "\n$$ // dynexport\n"); Bprint(&b, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++) for(i=0; i<ndynexp; i++)
Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote); Bprint(&b, "dynexport %s %s\n", dynexp[i].local, dynexp[i].remote);
Bprint(&b, "\n$$ // dynlinker\n");
if(dynlinker != nil) {
Bprint(&b, "dynlinker %s\n", dynlinker);
}
Bprint(&b, "\n$$\n\n"); Bprint(&b, "\n$$\n\n");
} }
Bprint(&b, "!\n"); Bprint(&b, "!\n");
......
...@@ -119,6 +119,7 @@ main(int argc, char *argv[]) ...@@ -119,6 +119,7 @@ main(int argc, char *argv[])
HEADTYPE = headtype(EARGF(usage())); HEADTYPE = headtype(EARGF(usage()));
break; break;
case 'I': case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage()); interpreter = EARGF(usage());
break; break;
case 'L': case 'L':
......
...@@ -774,6 +774,8 @@ void pragtextflag(void); ...@@ -774,6 +774,8 @@ void pragtextflag(void);
void pragincomplete(void); void pragincomplete(void);
void pragdynimport(void); void pragdynimport(void);
void pragdynexport(void); void pragdynexport(void);
void pragdynlinker(void);
EXTERN char *dynlinker;
/* /*
* calls to machine depend part * calls to machine depend part
......
...@@ -725,3 +725,20 @@ out: ...@@ -725,3 +725,20 @@ out:
while(getnsc() != '\n') while(getnsc() != '\n')
; ;
} }
void
pragdynlinker(void)
{
dynlinker = getquoted();
if(dynlinker == nil)
goto err;
goto out;
err:
yyerror("usage: #pragma dynlinker \"path\"");
out:
while(getnsc() != '\n')
;
}
...@@ -60,6 +60,13 @@ pragdynexport(void) ...@@ -60,6 +60,13 @@ pragdynexport(void)
; ;
} }
void
pragdynlinker(void)
{
while(getnsc() != '\n')
;
}
void void
pragfpround(void) pragfpround(void)
{ {
......
...@@ -751,6 +751,10 @@ macprag(void) ...@@ -751,6 +751,10 @@ macprag(void)
pragdynexport(); pragdynexport();
return; return;
} }
if(s && strcmp(s->name, "dynlinker") == 0) {
pragdynlinker();
return;
}
while(getnsc() != '\n') while(getnsc() != '\n')
; ;
return; return;
......
...@@ -128,6 +128,12 @@ func dynimport(obj string) { ...@@ -128,6 +128,12 @@ func dynimport(obj string) {
} }
if f, err := elf.Open(obj); err == nil { if f, err := elf.Open(obj); err == nil {
if sec := f.Section(".interp"); sec != nil {
if data, err := sec.Data(); err == nil && len(data) > 1 {
// skip trailing \0 in data
fmt.Fprintf(stdout, "#pragma dynlinker %q\n", string(data[:len(data)-1]))
}
}
sym, err := f.ImportedSymbols() sym, err := f.ImportedSymbols()
if err != nil { if err != nil {
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
......
...@@ -69,6 +69,7 @@ ilookup(char *name) ...@@ -69,6 +69,7 @@ ilookup(char *name)
static void loadpkgdata(char*, char*, char*, int); static void loadpkgdata(char*, char*, char*, int);
static void loaddynimport(char*, char*, char*, int); static void loaddynimport(char*, char*, char*, int);
static void loaddynexport(char*, char*, char*, int); static void loaddynexport(char*, char*, char*, int);
static void loaddynlinker(char*, char*, char*, int);
static int parsemethod(char**, char*, char**); static int parsemethod(char**, char*, char**);
static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**); static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
...@@ -204,7 +205,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) ...@@ -204,7 +205,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
if(p0 != nil) { if(p0 != nil) {
p0 = strchr(p0+1, '\n'); p0 = strchr(p0+1, '\n');
if(p0 == nil) { if(p0 == nil) {
fprint(2, "%s: found $$ // dynexporg but no newline in %s\n", argv0, filename); fprint(2, "%s: found $$ // dynexport but no newline in %s\n", argv0, filename);
if(debug['u']) if(debug['u'])
errorexit(); errorexit();
return; return;
...@@ -213,13 +214,34 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence) ...@@ -213,13 +214,34 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
if(p1 == nil) if(p1 == nil)
p1 = strstr(p0, "\n!\n"); p1 = strstr(p0, "\n!\n");
if(p1 == nil) { if(p1 == nil) {
fprint(2, "%s: cannot find end of // dynexporg section in %s\n", argv0, filename); fprint(2, "%s: cannot find end of // dynexport section in %s\n", argv0, filename);
if(debug['u']) if(debug['u'])
errorexit(); errorexit();
return; return;
} }
loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1)); loaddynexport(filename, pkg, p0 + 1, p1 - (p0+1));
} }
p0 = strstr(p1, "\n$$ // dynlinker");
if(p0 != nil) {
p0 = strchr(p0+1, '\n');
if(p0 == nil) {
fprint(2, "%s: found $$ // dynlinker but no newline in %s\n", argv0, filename);
if(debug['u'])
errorexit();
return;
}
p1 = strstr(p0, "\n$$");
if(p1 == nil)
p1 = strstr(p0, "\n!\n");
if(p1 == nil) {
fprint(2, "%s: cannot find end of // dynlinker section in %s\n", argv0, filename);
if(debug['u'])
errorexit();
return;
}
loaddynlinker(filename, pkg, p0 + 1, p1 - (p0+1));
}
} }
static void static void
...@@ -551,6 +573,44 @@ err: ...@@ -551,6 +573,44 @@ err:
nerrors++; nerrors++;
} }
static void
loaddynlinker(char *file, char *pkg, char *p, int n)
{
char *pend, *next, *dynlinker, *p0;
USED(file);
pend = p + n;
for(; p<pend; p=next) {
next = strchr(p, '\n');
if(next == nil)
next = "";
else
*next++ = '\0';
p0 = p;
if(strncmp(p, "dynlinker ", 10) != 0)
goto err;
p += 10;
dynlinker = p;
if(*dynlinker == '\0')
goto err;
if(!debug['I']) { // not overrided by cmdline
if(interpreter != nil && strcmp(interpreter, dynlinker) != 0) {
fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, dynlinker);
nerrors++;
return;
}
free(interpreter);
interpreter = strdup(dynlinker);
}
}
return;
err:
fprint(2, "%s: invalid dynlinker line: %s\n", argv0, p0);
nerrors++;
}
static int markdepth; static int markdepth;
static void static void
......
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