Skip to content

Commit 09092a7

Browse files
committed
cgo: handle versioned ELF symbols
Fixes #1397. R=iant CC=golang-dev https://golang.org/cl/4444064
1 parent 70b0de8 commit 09092a7

File tree

14 files changed

+451
-116
lines changed

14 files changed

+451
-116
lines changed

src/cmd/5l/l.h

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ struct Sym
156156
char* file;
157157
char* dynimpname;
158158
char* dynimplib;
159+
char* dynimpvers;
159160

160161
// STEXT
161162
Auto* autom;

src/cmd/6l/asm.c

+37-2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ enum {
9595
ElfStrStrtab,
9696
ElfStrRelaPlt,
9797
ElfStrPlt,
98+
ElfStrGnuVersion,
99+
ElfStrGnuVersionR,
98100
NElfStr
99101
};
100102

@@ -436,6 +438,7 @@ adddynsym(Sym *s)
436438
s->dynid = nelfsym++;
437439

438440
d = lookup(".dynsym", 0);
441+
439442
name = s->dynimpname;
440443
if(name == nil)
441444
name = s->name;
@@ -586,6 +589,8 @@ doelf(void)
586589
elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
587590
elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
588591
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
592+
elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
593+
elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
589594

590595
/* dynamic symbol table - first entry all zeros */
591596
s = lookup(".dynsym", 0);
@@ -629,6 +634,14 @@ doelf(void)
629634
s = lookup(".rela.plt", 0);
630635
s->reachable = 1;
631636
s->type = SELFDATA;
637+
638+
s = lookup(".gnu.version", 0);
639+
s->reachable = 1;
640+
s->type = SELFDATA;
641+
642+
s = lookup(".gnu.version_r", 0);
643+
s->reachable = 1;
644+
s->type = SELFDATA;
632645

633646
/* define dynamic elf table */
634647
s = lookup(".dynamic", 0);
@@ -653,7 +666,8 @@ doelf(void)
653666
elfwritedynent(s, DT_PLTREL, DT_RELA);
654667
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
655668
elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
656-
elfwritedynent(s, DT_NULL, 0);
669+
670+
// Do not write DT_NULL. elfdynhash will finish it.
657671
}
658672
}
659673

@@ -735,8 +749,11 @@ asmb(void)
735749
/* index of elf text section; needed by asmelfsym, double-checked below */
736750
/* !debug['d'] causes extra sections before the .text section */
737751
elftextsh = 1;
738-
if(!debug['d'])
752+
if(!debug['d']) {
739753
elftextsh += 10;
754+
if(elfverneed)
755+
elftextsh += 2;
756+
}
740757
break;
741758
case Hwindows:
742759
break;
@@ -920,6 +937,24 @@ asmb(void)
920937
sh->addralign = 1;
921938
shsym(sh, lookup(".dynstr", 0));
922939

940+
if(elfverneed) {
941+
sh = newElfShdr(elfstr[ElfStrGnuVersion]);
942+
sh->type = SHT_GNU_VERSYM;
943+
sh->flags = SHF_ALLOC;
944+
sh->addralign = 2;
945+
sh->link = dynsym;
946+
sh->entsize = 2;
947+
shsym(sh, lookup(".gnu.version", 0));
948+
949+
sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
950+
sh->type = SHT_GNU_VERNEED;
951+
sh->flags = SHF_ALLOC;
952+
sh->addralign = 8;
953+
sh->info = elfverneed;
954+
sh->link = dynsym+1; // dynstr
955+
shsym(sh, lookup(".gnu.version_r", 0));
956+
}
957+
923958
sh = newElfShdr(elfstr[ElfStrRelaPlt]);
924959
sh->type = SHT_RELA;
925960
sh->flags = SHF_ALLOC;

src/cmd/6l/l.h

+1
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ struct Sym
148148
char* file;
149149
char* dynimpname;
150150
char* dynimplib;
151+
char* dynimpvers;
151152

152153
// STEXT
153154
Auto* autom;

src/cmd/8l/asm.c

+37-3
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ enum {
9191
ElfStrStrtab,
9292
ElfStrRelPlt,
9393
ElfStrPlt,
94+
ElfStrGnuVersion,
95+
ElfStrGnuVersionR,
9496
NElfStr
9597
};
9698

@@ -420,7 +422,7 @@ adddynsym(Sym *s)
420422
s->dynid = nelfsym++;
421423

422424
d = lookup(".dynsym", 0);
423-
425+
424426
/* name */
425427
name = s->dynimpname;
426428
if(name == nil)
@@ -545,6 +547,8 @@ doelf(void)
545547
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
546548
elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
547549
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
550+
elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
551+
elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
548552

549553
/* interpreter string */
550554
s = lookup(".interp", 0);
@@ -592,6 +596,14 @@ doelf(void)
592596
s = lookup(".rel.plt", 0);
593597
s->reachable = 1;
594598
s->type = SELFDATA;
599+
600+
s = lookup(".gnu.version", 0);
601+
s->reachable = 1;
602+
s->type = SELFDATA;
603+
604+
s = lookup(".gnu.version_r", 0);
605+
s->reachable = 1;
606+
s->type = SELFDATA;
595607

596608
elfsetupplt();
597609

@@ -617,7 +629,8 @@ doelf(void)
617629
elfwritedynent(s, DT_PLTREL, DT_REL);
618630
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
619631
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
620-
elfwritedynent(s, DT_NULL, 0);
632+
633+
// Do not write DT_NULL. elfdynhash will finish it.
621634
}
622635
}
623636

@@ -681,8 +694,11 @@ asmb(void)
681694
/* index of elf text section; needed by asmelfsym, double-checked below */
682695
/* !debug['d'] causes extra sections before the .text section */
683696
elftextsh = 1;
684-
if(!debug['d'])
697+
if(!debug['d']) {
685698
elftextsh += 10;
699+
if(elfverneed)
700+
elftextsh += 2;
701+
}
686702
}
687703

688704
symsize = 0;
@@ -966,6 +982,24 @@ asmb(void)
966982
sh->addralign = 1;
967983
shsym(sh, lookup(".dynstr", 0));
968984

985+
if(elfverneed) {
986+
sh = newElfShdr(elfstr[ElfStrGnuVersion]);
987+
sh->type = SHT_GNU_VERSYM;
988+
sh->flags = SHF_ALLOC;
989+
sh->addralign = 2;
990+
sh->link = dynsym;
991+
sh->entsize = 2;
992+
shsym(sh, lookup(".gnu.version", 0));
993+
994+
sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
995+
sh->type = SHT_GNU_VERNEED;
996+
sh->flags = SHF_ALLOC;
997+
sh->addralign = 4;
998+
sh->info = elfverneed;
999+
sh->link = dynsym+1; // dynstr
1000+
shsym(sh, lookup(".gnu.version_r", 0));
1001+
}
1002+
9691003
sh = newElfShdr(elfstr[ElfStrRelPlt]);
9701004
sh->type = SHT_REL;
9711005
sh->flags = SHF_ALLOC;

src/cmd/8l/l.h

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ struct Sym
147147
char* file;
148148
char* dynimpname;
149149
char* dynimplib;
150+
char* dynimpvers;
150151

151152
// STEXT
152153
Auto* autom;

src/cmd/cc/dpchk.c

+28-2
Original file line numberDiff line numberDiff line change
@@ -534,18 +534,44 @@ pragincomplete(void)
534534
print("%s incomplete\n", s->name);
535535
}
536536

537+
Sym*
538+
getimpsym(void)
539+
{
540+
int c;
541+
char *cp;
542+
543+
c = getnsc();
544+
if(isspace(c) || c == '"') {
545+
unget(c);
546+
return S;
547+
}
548+
for(cp = symb;;) {
549+
if(cp <= symb+NSYMB-4)
550+
*cp++ = c;
551+
c = getc();
552+
if(c > 0 && !isspace(c) && c != '"')
553+
continue;
554+
unget(c);
555+
break;
556+
}
557+
*cp = 0;
558+
if(cp > symb+NSYMB-4)
559+
yyerror("symbol too large: %s", symb);
560+
return lookup();
561+
}
562+
537563
void
538564
pragdynimport(void)
539565
{
540566
Sym *local, *remote;
541567
char *path;
542568
Dynimp *f;
543569

544-
local = getsym();
570+
local = getimpsym();
545571
if(local == nil)
546572
goto err;
547573

548-
remote = getsym();
574+
remote = getimpsym();
549575
if(remote == nil)
550576
goto err;
551577

src/cmd/cc/macbody

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ getsym(void)
6363
if(cp <= symb+NSYMB-4)
6464
*cp++ = c;
6565
c = getc();
66-
if(isalnum(c) || c == '_' || c >= 0x80 || c == '$')
66+
if(isalnum(c) || c == '_' || c >= 0x80)
6767
continue;
6868
unget(c);
6969
break;

src/cmd/cgo/main.go

+1-15
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"os"
2121
"reflect"
2222
"strings"
23-
"runtime"
2423
)
2524

2625
// A Package collects information about the package we're going to write.
@@ -135,20 +134,7 @@ func main() {
135134
// instead of needing to make the linkers duplicate all the
136135
// specialized knowledge gcc has about where to look for imported
137136
// symbols and which ones to use.
138-
syms, imports := dynimport(*dynobj)
139-
if runtime.GOOS == "windows" {
140-
for _, sym := range syms {
141-
ss := strings.Split(sym, ":", -1)
142-
fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
143-
}
144-
return
145-
}
146-
for _, sym := range syms {
147-
fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "")
148-
}
149-
for _, p := range imports {
150-
fmt.Printf("#pragma dynimport %s %s %q\n", "_", "_", p)
151-
}
137+
dynimport(*dynobj)
152138
return
153139
}
154140

src/cmd/cgo/out.go

+47-26
Original file line numberDiff line numberDiff line change
@@ -95,42 +95,63 @@ func (p *Package) writeDefs() {
9595
fc.Close()
9696
}
9797

98-
func dynimport(obj string) (syms, imports []string) {
99-
var f interface {
100-
ImportedLibraries() ([]string, os.Error)
101-
ImportedSymbols() ([]string, os.Error)
102-
}
103-
var isMacho bool
104-
var err1, err2, err3 os.Error
105-
if f, err1 = elf.Open(obj); err1 != nil {
106-
if f, err2 = pe.Open(obj); err2 != nil {
107-
if f, err3 = macho.Open(obj); err3 != nil {
108-
fatalf("cannot parse %s as ELF (%v) or PE (%v) or Mach-O (%v)", obj, err1, err2, err3)
98+
func dynimport(obj string) {
99+
if f, err := elf.Open(obj); err == nil {
100+
sym, err := f.ImportedSymbols()
101+
if err != nil {
102+
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
103+
}
104+
for _, s := range sym {
105+
targ := s.Name
106+
if s.Version != "" {
107+
targ += "@" + s.Version
109108
}
110-
isMacho = true
109+
fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
110+
}
111+
lib, err := f.ImportedLibraries()
112+
if err != nil {
113+
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
114+
}
115+
for _, l := range lib {
116+
fmt.Printf("#pragma dynimport _ _ %q\n", l)
111117
}
118+
return
112119
}
113120

114-
var err os.Error
115-
syms, err = f.ImportedSymbols()
116-
if err != nil {
117-
fatalf("cannot load dynamic symbols: %v", err)
118-
}
119-
if isMacho {
120-
// remove leading _ that OS X insists on
121-
for i, s := range syms {
122-
if len(s) >= 2 && s[0] == '_' {
123-
syms[i] = s[1:]
121+
if f, err := macho.Open(obj); err == nil {
122+
sym, err := f.ImportedSymbols()
123+
if err != nil {
124+
fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
125+
}
126+
for _, s := range sym {
127+
if len(s) > 0 && s[0] == '_' {
128+
s = s[1:]
124129
}
130+
fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
125131
}
132+
lib, err := f.ImportedLibraries()
133+
if err != nil {
134+
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
135+
}
136+
for _, l := range lib {
137+
fmt.Printf("#pragma dynimport _ _ %q\n", l)
138+
}
139+
return
126140
}
127141

128-
imports, err = f.ImportedLibraries()
129-
if err != nil {
130-
fatalf("cannot load dynamic imports: %v", err)
142+
if f, err := pe.Open(obj); err == nil {
143+
sym, err := f.ImportedSymbols()
144+
if err != nil {
145+
fatalf("cannot load imported symbols from PE file %s: v", obj, err)
146+
}
147+
for _, s := range sym {
148+
ss := strings.Split(s, ":", -1)
149+
fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
150+
}
151+
return
131152
}
132153

133-
return
154+
fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
134155
}
135156

136157
// Construct a gcc struct matching the 6c argument frame.

0 commit comments

Comments
 (0)