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)
Bprint(&outbuf, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++)
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");
......
......@@ -106,6 +106,7 @@ main(int argc, char *argv[])
INITENTRY = EARGF(usage());
break;
case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage());
break;
case 'L':
......
......@@ -259,6 +259,10 @@ outcode(void)
Bprint(&b, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++)
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");
......
......@@ -114,6 +114,7 @@ main(int argc, char *argv[])
HEADTYPE = headtype(EARGF(usage()));
break;
case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage());
break;
case 'L':
......
......@@ -263,6 +263,10 @@ outcode(void)
Bprint(&b, "\n$$ // dynexport\n");
for(i=0; i<ndynexp; i++)
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");
......
......@@ -119,6 +119,7 @@ main(int argc, char *argv[])
HEADTYPE = headtype(EARGF(usage()));
break;
case 'I':
debug['I'] = 1; // denote cmdline interpreter override
interpreter = EARGF(usage());
break;
case 'L':
......
......@@ -774,6 +774,8 @@ void pragtextflag(void);
void pragincomplete(void);
void pragdynimport(void);
void pragdynexport(void);
void pragdynlinker(void);
EXTERN char *dynlinker;
/*
* calls to machine depend part
......
......@@ -725,3 +725,20 @@ out:
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)
;
}
void
pragdynlinker(void)
{
while(getnsc() != '\n')
;
}
void
pragfpround(void)
{
......
......@@ -751,6 +751,10 @@ macprag(void)
pragdynexport();
return;
}
if(s && strcmp(s->name, "dynlinker") == 0) {
pragdynlinker();
return;
}
while(getnsc() != '\n')
;
return;
......
......@@ -128,6 +128,12 @@ func dynimport(obj string) {
}
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()
if err != nil {
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
......
......@@ -69,6 +69,7 @@ ilookup(char *name)
static void loadpkgdata(char*, char*, char*, int);
static void loaddynimport(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 parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
......@@ -204,7 +205,7 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
if(p0 != nil) {
p0 = strchr(p0+1, '\n');
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'])
errorexit();
return;
......@@ -213,13 +214,34 @@ ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
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);
fprint(2, "%s: cannot find end of // dynexport section in %s\n", argv0, filename);
if(debug['u'])
errorexit();
return;
}
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
......@@ -551,6 +573,44 @@ err:
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 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