mirror of
https://github.com/golang/go
synced 2024-11-20 01:04:40 -07:00
cgo: handle versioned ELF symbols
Fixes #1397. R=iant CC=golang-dev https://golang.org/cl/4444064
This commit is contained in:
parent
70b0de8e98
commit
09092a78e6
@ -156,6 +156,7 @@ struct Sym
|
||||
char* file;
|
||||
char* dynimpname;
|
||||
char* dynimplib;
|
||||
char* dynimpvers;
|
||||
|
||||
// STEXT
|
||||
Auto* autom;
|
||||
|
@ -95,6 +95,8 @@ enum {
|
||||
ElfStrStrtab,
|
||||
ElfStrRelaPlt,
|
||||
ElfStrPlt,
|
||||
ElfStrGnuVersion,
|
||||
ElfStrGnuVersionR,
|
||||
NElfStr
|
||||
};
|
||||
|
||||
@ -436,6 +438,7 @@ adddynsym(Sym *s)
|
||||
s->dynid = nelfsym++;
|
||||
|
||||
d = lookup(".dynsym", 0);
|
||||
|
||||
name = s->dynimpname;
|
||||
if(name == nil)
|
||||
name = s->name;
|
||||
@ -586,6 +589,8 @@ doelf(void)
|
||||
elfstr[ElfStrRela] = addstring(shstrtab, ".rela");
|
||||
elfstr[ElfStrRelaPlt] = addstring(shstrtab, ".rela.plt");
|
||||
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
|
||||
elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
|
||||
elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
|
||||
|
||||
/* dynamic symbol table - first entry all zeros */
|
||||
s = lookup(".dynsym", 0);
|
||||
@ -629,6 +634,14 @@ doelf(void)
|
||||
s = lookup(".rela.plt", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
s = lookup(".gnu.version", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
s = lookup(".gnu.version_r", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
/* define dynamic elf table */
|
||||
s = lookup(".dynamic", 0);
|
||||
@ -653,7 +666,8 @@ doelf(void)
|
||||
elfwritedynent(s, DT_PLTREL, DT_RELA);
|
||||
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rela.plt", 0));
|
||||
elfwritedynentsym(s, DT_JMPREL, lookup(".rela.plt", 0));
|
||||
elfwritedynent(s, DT_NULL, 0);
|
||||
|
||||
// Do not write DT_NULL. elfdynhash will finish it.
|
||||
}
|
||||
}
|
||||
|
||||
@ -735,8 +749,11 @@ asmb(void)
|
||||
/* index of elf text section; needed by asmelfsym, double-checked below */
|
||||
/* !debug['d'] causes extra sections before the .text section */
|
||||
elftextsh = 1;
|
||||
if(!debug['d'])
|
||||
if(!debug['d']) {
|
||||
elftextsh += 10;
|
||||
if(elfverneed)
|
||||
elftextsh += 2;
|
||||
}
|
||||
break;
|
||||
case Hwindows:
|
||||
break;
|
||||
@ -920,6 +937,24 @@ asmb(void)
|
||||
sh->addralign = 1;
|
||||
shsym(sh, lookup(".dynstr", 0));
|
||||
|
||||
if(elfverneed) {
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersion]);
|
||||
sh->type = SHT_GNU_VERSYM;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 2;
|
||||
sh->link = dynsym;
|
||||
sh->entsize = 2;
|
||||
shsym(sh, lookup(".gnu.version", 0));
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
|
||||
sh->type = SHT_GNU_VERNEED;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 8;
|
||||
sh->info = elfverneed;
|
||||
sh->link = dynsym+1; // dynstr
|
||||
shsym(sh, lookup(".gnu.version_r", 0));
|
||||
}
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrRelaPlt]);
|
||||
sh->type = SHT_RELA;
|
||||
sh->flags = SHF_ALLOC;
|
||||
|
@ -148,6 +148,7 @@ struct Sym
|
||||
char* file;
|
||||
char* dynimpname;
|
||||
char* dynimplib;
|
||||
char* dynimpvers;
|
||||
|
||||
// STEXT
|
||||
Auto* autom;
|
||||
|
@ -91,6 +91,8 @@ enum {
|
||||
ElfStrStrtab,
|
||||
ElfStrRelPlt,
|
||||
ElfStrPlt,
|
||||
ElfStrGnuVersion,
|
||||
ElfStrGnuVersionR,
|
||||
NElfStr
|
||||
};
|
||||
|
||||
@ -420,7 +422,7 @@ adddynsym(Sym *s)
|
||||
s->dynid = nelfsym++;
|
||||
|
||||
d = lookup(".dynsym", 0);
|
||||
|
||||
|
||||
/* name */
|
||||
name = s->dynimpname;
|
||||
if(name == nil)
|
||||
@ -545,6 +547,8 @@ doelf(void)
|
||||
elfstr[ElfStrRel] = addstring(shstrtab, ".rel");
|
||||
elfstr[ElfStrRelPlt] = addstring(shstrtab, ".rel.plt");
|
||||
elfstr[ElfStrPlt] = addstring(shstrtab, ".plt");
|
||||
elfstr[ElfStrGnuVersion] = addstring(shstrtab, ".gnu.version");
|
||||
elfstr[ElfStrGnuVersionR] = addstring(shstrtab, ".gnu.version_r");
|
||||
|
||||
/* interpreter string */
|
||||
s = lookup(".interp", 0);
|
||||
@ -592,6 +596,14 @@ doelf(void)
|
||||
s = lookup(".rel.plt", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
s = lookup(".gnu.version", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
s = lookup(".gnu.version_r", 0);
|
||||
s->reachable = 1;
|
||||
s->type = SELFDATA;
|
||||
|
||||
elfsetupplt();
|
||||
|
||||
@ -617,7 +629,8 @@ doelf(void)
|
||||
elfwritedynent(s, DT_PLTREL, DT_REL);
|
||||
elfwritedynentsymsize(s, DT_PLTRELSZ, lookup(".rel.plt", 0));
|
||||
elfwritedynentsym(s, DT_JMPREL, lookup(".rel.plt", 0));
|
||||
elfwritedynent(s, DT_NULL, 0);
|
||||
|
||||
// Do not write DT_NULL. elfdynhash will finish it.
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,8 +694,11 @@ asmb(void)
|
||||
/* index of elf text section; needed by asmelfsym, double-checked below */
|
||||
/* !debug['d'] causes extra sections before the .text section */
|
||||
elftextsh = 1;
|
||||
if(!debug['d'])
|
||||
if(!debug['d']) {
|
||||
elftextsh += 10;
|
||||
if(elfverneed)
|
||||
elftextsh += 2;
|
||||
}
|
||||
}
|
||||
|
||||
symsize = 0;
|
||||
@ -966,6 +982,24 @@ asmb(void)
|
||||
sh->addralign = 1;
|
||||
shsym(sh, lookup(".dynstr", 0));
|
||||
|
||||
if(elfverneed) {
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersion]);
|
||||
sh->type = SHT_GNU_VERSYM;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 2;
|
||||
sh->link = dynsym;
|
||||
sh->entsize = 2;
|
||||
shsym(sh, lookup(".gnu.version", 0));
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrGnuVersionR]);
|
||||
sh->type = SHT_GNU_VERNEED;
|
||||
sh->flags = SHF_ALLOC;
|
||||
sh->addralign = 4;
|
||||
sh->info = elfverneed;
|
||||
sh->link = dynsym+1; // dynstr
|
||||
shsym(sh, lookup(".gnu.version_r", 0));
|
||||
}
|
||||
|
||||
sh = newElfShdr(elfstr[ElfStrRelPlt]);
|
||||
sh->type = SHT_REL;
|
||||
sh->flags = SHF_ALLOC;
|
||||
|
@ -147,6 +147,7 @@ struct Sym
|
||||
char* file;
|
||||
char* dynimpname;
|
||||
char* dynimplib;
|
||||
char* dynimpvers;
|
||||
|
||||
// STEXT
|
||||
Auto* autom;
|
||||
|
@ -534,6 +534,32 @@ out:
|
||||
print("%s incomplete\n", s->name);
|
||||
}
|
||||
|
||||
Sym*
|
||||
getimpsym(void)
|
||||
{
|
||||
int c;
|
||||
char *cp;
|
||||
|
||||
c = getnsc();
|
||||
if(isspace(c) || c == '"') {
|
||||
unget(c);
|
||||
return S;
|
||||
}
|
||||
for(cp = symb;;) {
|
||||
if(cp <= symb+NSYMB-4)
|
||||
*cp++ = c;
|
||||
c = getc();
|
||||
if(c > 0 && !isspace(c) && c != '"')
|
||||
continue;
|
||||
unget(c);
|
||||
break;
|
||||
}
|
||||
*cp = 0;
|
||||
if(cp > symb+NSYMB-4)
|
||||
yyerror("symbol too large: %s", symb);
|
||||
return lookup();
|
||||
}
|
||||
|
||||
void
|
||||
pragdynimport(void)
|
||||
{
|
||||
@ -541,11 +567,11 @@ pragdynimport(void)
|
||||
char *path;
|
||||
Dynimp *f;
|
||||
|
||||
local = getsym();
|
||||
local = getimpsym();
|
||||
if(local == nil)
|
||||
goto err;
|
||||
|
||||
remote = getsym();
|
||||
remote = getimpsym();
|
||||
if(remote == nil)
|
||||
goto err;
|
||||
|
||||
|
@ -63,7 +63,7 @@ getsym(void)
|
||||
if(cp <= symb+NSYMB-4)
|
||||
*cp++ = c;
|
||||
c = getc();
|
||||
if(isalnum(c) || c == '_' || c >= 0x80 || c == '$')
|
||||
if(isalnum(c) || c == '_' || c >= 0x80)
|
||||
continue;
|
||||
unget(c);
|
||||
break;
|
||||
|
@ -20,7 +20,6 @@ import (
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// A Package collects information about the package we're going to write.
|
||||
@ -135,20 +134,7 @@ func main() {
|
||||
// instead of needing to make the linkers duplicate all the
|
||||
// specialized knowledge gcc has about where to look for imported
|
||||
// symbols and which ones to use.
|
||||
syms, imports := dynimport(*dynobj)
|
||||
if runtime.GOOS == "windows" {
|
||||
for _, sym := range syms {
|
||||
ss := strings.Split(sym, ":", -1)
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, sym := range syms {
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", sym, sym, "")
|
||||
}
|
||||
for _, p := range imports {
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", "_", "_", p)
|
||||
}
|
||||
dynimport(*dynobj)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -95,42 +95,63 @@ func (p *Package) writeDefs() {
|
||||
fc.Close()
|
||||
}
|
||||
|
||||
func dynimport(obj string) (syms, imports []string) {
|
||||
var f interface {
|
||||
ImportedLibraries() ([]string, os.Error)
|
||||
ImportedSymbols() ([]string, os.Error)
|
||||
}
|
||||
var isMacho bool
|
||||
var err1, err2, err3 os.Error
|
||||
if f, err1 = elf.Open(obj); err1 != nil {
|
||||
if f, err2 = pe.Open(obj); err2 != nil {
|
||||
if f, err3 = macho.Open(obj); err3 != nil {
|
||||
fatalf("cannot parse %s as ELF (%v) or PE (%v) or Mach-O (%v)", obj, err1, err2, err3)
|
||||
}
|
||||
isMacho = true
|
||||
func dynimport(obj string) {
|
||||
if f, err := elf.Open(obj); err == nil {
|
||||
sym, err := f.ImportedSymbols()
|
||||
if err != nil {
|
||||
fatalf("cannot load imported symbols from ELF file %s: %v", obj, err)
|
||||
}
|
||||
}
|
||||
|
||||
var err os.Error
|
||||
syms, err = f.ImportedSymbols()
|
||||
if err != nil {
|
||||
fatalf("cannot load dynamic symbols: %v", err)
|
||||
}
|
||||
if isMacho {
|
||||
// remove leading _ that OS X insists on
|
||||
for i, s := range syms {
|
||||
if len(s) >= 2 && s[0] == '_' {
|
||||
syms[i] = s[1:]
|
||||
for _, s := range sym {
|
||||
targ := s.Name
|
||||
if s.Version != "" {
|
||||
targ += "@" + s.Version
|
||||
}
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", s.Name, targ, s.Library)
|
||||
}
|
||||
lib, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
|
||||
}
|
||||
for _, l := range lib {
|
||||
fmt.Printf("#pragma dynimport _ _ %q\n", l)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
imports, err = f.ImportedLibraries()
|
||||
if err != nil {
|
||||
fatalf("cannot load dynamic imports: %v", err)
|
||||
if f, err := macho.Open(obj); err == nil {
|
||||
sym, err := f.ImportedSymbols()
|
||||
if err != nil {
|
||||
fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err)
|
||||
}
|
||||
for _, s := range sym {
|
||||
if len(s) > 0 && s[0] == '_' {
|
||||
s = s[1:]
|
||||
}
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", s, s, "")
|
||||
}
|
||||
lib, err := f.ImportedLibraries()
|
||||
if err != nil {
|
||||
fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
|
||||
}
|
||||
for _, l := range lib {
|
||||
fmt.Printf("#pragma dynimport _ _ %q\n", l)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
if f, err := pe.Open(obj); err == nil {
|
||||
sym, err := f.ImportedSymbols()
|
||||
if err != nil {
|
||||
fatalf("cannot load imported symbols from PE file %s: v", obj, err)
|
||||
}
|
||||
for _, s := range sym {
|
||||
ss := strings.Split(s, ":", -1)
|
||||
fmt.Printf("#pragma dynimport %s %s %q\n", ss[0], ss[0], strings.ToLower(ss[1]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
|
||||
}
|
||||
|
||||
// Construct a gcc struct matching the 6c argument frame.
|
||||
|
135
src/cmd/ld/elf.c
135
src/cmd/ld/elf.c
@ -331,17 +331,62 @@ elfinterp(ElfShdr *sh, uint64 startva, char *p)
|
||||
}
|
||||
|
||||
extern int nelfsym;
|
||||
int elfverneed;
|
||||
|
||||
typedef struct Elfaux Elfaux;
|
||||
typedef struct Elflib Elflib;
|
||||
|
||||
struct Elflib
|
||||
{
|
||||
Elflib *next;
|
||||
Elfaux *aux;
|
||||
char *file;
|
||||
};
|
||||
|
||||
struct Elfaux
|
||||
{
|
||||
Elfaux *next;
|
||||
int num;
|
||||
char *vers;
|
||||
};
|
||||
|
||||
Elfaux*
|
||||
addelflib(Elflib **list, char *file, char *vers)
|
||||
{
|
||||
Elflib *lib;
|
||||
Elfaux *aux;
|
||||
|
||||
for(lib=*list; lib; lib=lib->next)
|
||||
if(strcmp(lib->file, file) == 0)
|
||||
goto havelib;
|
||||
lib = mal(sizeof *lib);
|
||||
lib->next = *list;
|
||||
lib->file = file;
|
||||
*list = lib;
|
||||
havelib:
|
||||
for(aux=lib->aux; aux; aux=aux->next)
|
||||
if(strcmp(aux->vers, vers) == 0)
|
||||
goto haveaux;
|
||||
aux = mal(sizeof *aux);
|
||||
aux->next = lib->aux;
|
||||
aux->vers = vers;
|
||||
lib->aux = aux;
|
||||
haveaux:
|
||||
return aux;
|
||||
}
|
||||
|
||||
void
|
||||
elfdynhash(void)
|
||||
{
|
||||
Sym *s, *sy;
|
||||
int i, nbucket, b;
|
||||
uchar *pc;
|
||||
uint32 hc, g;
|
||||
uint32 *chain, *buckets;
|
||||
Sym *s, *sy, *dynstr;
|
||||
int i, j, nbucket, b, nfile;
|
||||
uint32 hc, *chain, *buckets;
|
||||
int nsym;
|
||||
char *name;
|
||||
Elfaux **need;
|
||||
Elflib *needlib;
|
||||
Elflib *l;
|
||||
Elfaux *x;
|
||||
|
||||
if(!iself)
|
||||
return;
|
||||
@ -358,29 +403,29 @@ elfdynhash(void)
|
||||
i >>= 1;
|
||||
}
|
||||
|
||||
chain = malloc(nsym * sizeof(uint32));
|
||||
buckets = malloc(nbucket * sizeof(uint32));
|
||||
if(chain == nil || buckets == nil) {
|
||||
needlib = nil;
|
||||
need = malloc(nsym * sizeof need[0]);
|
||||
chain = malloc(nsym * sizeof chain[0]);
|
||||
buckets = malloc(nbucket * sizeof buckets[0]);
|
||||
if(need == nil || chain == nil || buckets == nil) {
|
||||
cursym = nil;
|
||||
diag("out of memory");
|
||||
errorexit();
|
||||
}
|
||||
memset(chain, 0, nsym * sizeof(uint32));
|
||||
memset(buckets, 0, nbucket * sizeof(uint32));
|
||||
memset(need, 0, nsym * sizeof need[0]);
|
||||
memset(chain, 0, nsym * sizeof chain[0]);
|
||||
memset(buckets, 0, nbucket * sizeof buckets[0]);
|
||||
for(sy=allsym; sy!=S; sy=sy->allsym) {
|
||||
if (sy->dynid <= 0)
|
||||
continue;
|
||||
|
||||
hc = 0;
|
||||
if(sy->dynimpvers)
|
||||
need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
|
||||
|
||||
name = sy->dynimpname;
|
||||
if(name == nil)
|
||||
name = sy->name;
|
||||
for(pc = (uchar*)name; *pc; pc++) {
|
||||
hc = (hc<<4) + *pc;
|
||||
g = hc & 0xf0000000;
|
||||
hc ^= g >> 24;
|
||||
hc &= ~g;
|
||||
}
|
||||
hc = elfhash((uchar*)name);
|
||||
|
||||
b = hc % nbucket;
|
||||
chain[sy->dynid] = buckets[b];
|
||||
@ -396,8 +441,62 @@ elfdynhash(void)
|
||||
|
||||
free(chain);
|
||||
free(buckets);
|
||||
|
||||
// version symbols
|
||||
dynstr = lookup(".dynstr", 0);
|
||||
s = lookup(".gnu.version_r", 0);
|
||||
i = 2;
|
||||
nfile = 0;
|
||||
for(l=needlib; l; l=l->next) {
|
||||
nfile++;
|
||||
// header
|
||||
adduint16(s, 1); // table version
|
||||
j = 0;
|
||||
for(x=l->aux; x; x=x->next)
|
||||
j++;
|
||||
adduint16(s, j); // aux count
|
||||
adduint32(s, addstring(dynstr, l->file)); // file string offset
|
||||
adduint32(s, 16); // offset from header to first aux
|
||||
if(l->next)
|
||||
adduint32(s, 16+j*16); // offset from this header to next
|
||||
else
|
||||
adduint32(s, 0);
|
||||
|
||||
for(x=l->aux; x; x=x->next) {
|
||||
x->num = i++;
|
||||
// aux struct
|
||||
adduint32(s, elfhash((uchar*)x->vers)); // hash
|
||||
adduint16(s, 0); // flags
|
||||
adduint16(s, x->num); // other - index we refer to this by
|
||||
adduint32(s, addstring(dynstr, x->vers)); // version string offset
|
||||
if(x->next)
|
||||
adduint32(s, 16); // offset from this aux to next
|
||||
else
|
||||
adduint32(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
elfwritedynent(lookup(".dynamic", 0), DT_NULL, 0);
|
||||
// version references
|
||||
s = lookup(".gnu.version", 0);
|
||||
for(i=0; i<nsym; i++) {
|
||||
if(i == 0)
|
||||
adduint16(s, 0); // first entry - no symbol
|
||||
else if(need[i] == nil)
|
||||
adduint16(s, 1); // global
|
||||
else
|
||||
adduint16(s, need[i]->num);
|
||||
}
|
||||
|
||||
free(need);
|
||||
|
||||
s = lookup(".dynamic", 0);
|
||||
elfverneed = nfile;
|
||||
if(elfverneed) {
|
||||
elfwritedynentsym(s, DT_VERNEED, lookup(".gnu.version_r", 0));
|
||||
elfwritedynent(s, DT_VERNEEDNUM, nfile);
|
||||
elfwritedynentsym(s, DT_VERSYM, lookup(".gnu.version", 0));
|
||||
}
|
||||
elfwritedynent(s, DT_NULL, 0);
|
||||
}
|
||||
|
||||
ElfPhdr*
|
||||
|
@ -216,6 +216,9 @@ typedef struct {
|
||||
#define SHT_SYMTAB_SHNDX 18 /* Section indexes (see SHN_XINDEX). */
|
||||
#define SHT_LOOS 0x60000000 /* First of OS specific semantics */
|
||||
#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */
|
||||
#define SHT_GNU_VERDEF 0x6ffffffd
|
||||
#define SHT_GNU_VERNEED 0x6ffffffe
|
||||
#define SHT_GNU_VERSYM 0x6fffffff
|
||||
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
|
||||
#define SHT_HIPROC 0x7fffffff /* specific section header types */
|
||||
#define SHT_LOUSER 0x80000000 /* reserved range for application */
|
||||
@ -311,6 +314,10 @@ typedef struct {
|
||||
#define DT_LOPROC 0x70000000 /* First processor-specific type. */
|
||||
#define DT_HIPROC 0x7fffffff /* Last processor-specific type. */
|
||||
|
||||
#define DT_VERNEED 0x6ffffffe
|
||||
#define DT_VERNEEDNUM 0x6fffffff
|
||||
#define DT_VERSYM 0x6ffffff0
|
||||
|
||||
/* Values for DT_FLAGS */
|
||||
#define DF_ORIGIN 0x0001 /* Indicates that the object being loaded may
|
||||
make reference to the $ORIGIN substitution
|
||||
@ -962,12 +969,14 @@ uint64 endelf(void);
|
||||
extern int numelfphdr;
|
||||
extern int numelfshdr;
|
||||
extern int iself;
|
||||
extern int elfverneed;
|
||||
int elfwriteinterp(void);
|
||||
void elfinterp(ElfShdr*, uint64, char*);
|
||||
void elfdynhash(void);
|
||||
ElfPhdr* elfphload(Segment*);
|
||||
ElfShdr* elfshbits(Section*);
|
||||
void elfsetstring(char*, int);
|
||||
void elfaddverneed(Sym*);
|
||||
|
||||
/*
|
||||
* Total amount of space to reserve at the start of the file
|
||||
|
@ -412,7 +412,7 @@ parsemethod(char **pp, char *ep, char **methp)
|
||||
static void
|
||||
loaddynimport(char *file, char *pkg, char *p, int n)
|
||||
{
|
||||
char *pend, *next, *name, *def, *p0, *lib;
|
||||
char *pend, *next, *name, *def, *p0, *lib, *q;
|
||||
Sym *s;
|
||||
|
||||
pend = p + n;
|
||||
@ -459,10 +459,14 @@ loaddynimport(char *file, char *pkg, char *p, int n)
|
||||
}
|
||||
|
||||
name = expandpkg(name, pkg);
|
||||
q = strchr(def, '@');
|
||||
if(q)
|
||||
*q++ = '\0';
|
||||
s = lookup(name, 0);
|
||||
if(s->type == 0 || s->type == SXREF) {
|
||||
s->dynimplib = lib;
|
||||
s->dynimpname = def;
|
||||
s->dynimpvers = q;
|
||||
s->type = SDYNIMPORT;
|
||||
}
|
||||
}
|
||||
|
@ -330,29 +330,35 @@ func (i SectionIndex) GoString() string { return stringName(uint32(i), shnString
|
||||
type SectionType uint32
|
||||
|
||||
const (
|
||||
SHT_NULL SectionType = 0 /* inactive */
|
||||
SHT_PROGBITS SectionType = 1 /* program defined information */
|
||||
SHT_SYMTAB SectionType = 2 /* symbol table section */
|
||||
SHT_STRTAB SectionType = 3 /* string table section */
|
||||
SHT_RELA SectionType = 4 /* relocation section with addends */
|
||||
SHT_HASH SectionType = 5 /* symbol hash table section */
|
||||
SHT_DYNAMIC SectionType = 6 /* dynamic section */
|
||||
SHT_NOTE SectionType = 7 /* note section */
|
||||
SHT_NOBITS SectionType = 8 /* no space section */
|
||||
SHT_REL SectionType = 9 /* relocation section - no addends */
|
||||
SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */
|
||||
SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */
|
||||
SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */
|
||||
SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */
|
||||
SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */
|
||||
SHT_GROUP SectionType = 17 /* Section group. */
|
||||
SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */
|
||||
SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */
|
||||
SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */
|
||||
SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */
|
||||
SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */
|
||||
SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */
|
||||
SHT_HIUSER SectionType = 0xffffffff /* specific indexes */
|
||||
SHT_NULL SectionType = 0 /* inactive */
|
||||
SHT_PROGBITS SectionType = 1 /* program defined information */
|
||||
SHT_SYMTAB SectionType = 2 /* symbol table section */
|
||||
SHT_STRTAB SectionType = 3 /* string table section */
|
||||
SHT_RELA SectionType = 4 /* relocation section with addends */
|
||||
SHT_HASH SectionType = 5 /* symbol hash table section */
|
||||
SHT_DYNAMIC SectionType = 6 /* dynamic section */
|
||||
SHT_NOTE SectionType = 7 /* note section */
|
||||
SHT_NOBITS SectionType = 8 /* no space section */
|
||||
SHT_REL SectionType = 9 /* relocation section - no addends */
|
||||
SHT_SHLIB SectionType = 10 /* reserved - purpose unknown */
|
||||
SHT_DYNSYM SectionType = 11 /* dynamic symbol table section */
|
||||
SHT_INIT_ARRAY SectionType = 14 /* Initialization function pointers. */
|
||||
SHT_FINI_ARRAY SectionType = 15 /* Termination function pointers. */
|
||||
SHT_PREINIT_ARRAY SectionType = 16 /* Pre-initialization function ptrs. */
|
||||
SHT_GROUP SectionType = 17 /* Section group. */
|
||||
SHT_SYMTAB_SHNDX SectionType = 18 /* Section indexes (see SHN_XINDEX). */
|
||||
SHT_LOOS SectionType = 0x60000000 /* First of OS specific semantics */
|
||||
SHT_GNU_ATTRIBUTES SectionType = 0x6ffffff5 /* GNU object attributes */
|
||||
SHT_GNU_HASH SectionType = 0x6ffffff6 /* GNU hash table */
|
||||
SHT_GNU_LIBLIST SectionType = 0x6ffffff7 /* GNU prelink library list */
|
||||
SHT_GNU_VERDEF SectionType = 0x6ffffffd /* GNU version definition section */
|
||||
SHT_GNU_VERNEED SectionType = 0x6ffffffe /* GNU version needs section */
|
||||
SHT_GNU_VERSYM SectionType = 0x6fffffff /* GNU version symbol table */
|
||||
SHT_HIOS SectionType = 0x6fffffff /* Last of OS specific semantics */
|
||||
SHT_LOPROC SectionType = 0x70000000 /* reserved range for processor */
|
||||
SHT_HIPROC SectionType = 0x7fffffff /* specific section header types */
|
||||
SHT_LOUSER SectionType = 0x80000000 /* reserved range for application */
|
||||
SHT_HIUSER SectionType = 0xffffffff /* specific indexes */
|
||||
)
|
||||
|
||||
var shtStrings = []intName{
|
||||
@ -374,7 +380,12 @@ var shtStrings = []intName{
|
||||
{17, "SHT_GROUP"},
|
||||
{18, "SHT_SYMTAB_SHNDX"},
|
||||
{0x60000000, "SHT_LOOS"},
|
||||
{0x6fffffff, "SHT_HIOS"},
|
||||
{0x6ffffff5, "SHT_GNU_ATTRIBUTES"},
|
||||
{0x6ffffff6, "SHT_GNU_HASH"},
|
||||
{0x6ffffff7, "SHT_GNU_LIBLIST"},
|
||||
{0x6ffffffd, "SHT_GNU_VERDEF"},
|
||||
{0x6ffffffe, "SHT_GNU_VERNEED"},
|
||||
{0x6fffffff, "SHT_GNU_VERSYM"},
|
||||
{0x70000000, "SHT_LOPROC"},
|
||||
{0x7fffffff, "SHT_HIPROC"},
|
||||
{0x80000000, "SHT_LOUSER"},
|
||||
@ -518,6 +529,9 @@ const (
|
||||
DT_PREINIT_ARRAYSZ DynTag = 33 /* Size in bytes of the array of pre-initialization functions. */
|
||||
DT_LOOS DynTag = 0x6000000d /* First OS-specific */
|
||||
DT_HIOS DynTag = 0x6ffff000 /* Last OS-specific */
|
||||
DT_VERSYM DynTag = 0x6ffffff0
|
||||
DT_VERNEED DynTag = 0x6ffffffe
|
||||
DT_VERNEEDNUM DynTag = 0x6fffffff
|
||||
DT_LOPROC DynTag = 0x70000000 /* First processor-specific type. */
|
||||
DT_HIPROC DynTag = 0x7fffffff /* Last processor-specific type. */
|
||||
)
|
||||
@ -559,6 +573,9 @@ var dtStrings = []intName{
|
||||
{33, "DT_PREINIT_ARRAYSZ"},
|
||||
{0x6000000d, "DT_LOOS"},
|
||||
{0x6ffff000, "DT_HIOS"},
|
||||
{0x6ffffff0, "DT_VERSYM"},
|
||||
{0x6ffffffe, "DT_VERNEED"},
|
||||
{0x6fffffff, "DT_VERNEEDNUM"},
|
||||
{0x70000000, "DT_LOPROC"},
|
||||
{0x7fffffff, "DT_HIPROC"},
|
||||
}
|
||||
|
@ -35,9 +35,11 @@ type FileHeader struct {
|
||||
// A File represents an open ELF file.
|
||||
type File struct {
|
||||
FileHeader
|
||||
Sections []*Section
|
||||
Progs []*Prog
|
||||
closer io.Closer
|
||||
Sections []*Section
|
||||
Progs []*Prog
|
||||
closer io.Closer
|
||||
gnuNeed []verneed
|
||||
gnuVersym []byte
|
||||
}
|
||||
|
||||
// A SectionHeader represents a single ELF section header.
|
||||
@ -329,8 +331,8 @@ func NewFile(r io.ReaderAt) (*File, os.Error) {
|
||||
}
|
||||
|
||||
// getSymbols returns a slice of Symbols from parsing the symbol table
|
||||
// with the given type.
|
||||
func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) {
|
||||
// with the given type, along with the associated string table.
|
||||
func (f *File) getSymbols(typ SectionType) ([]Symbol, []byte, os.Error) {
|
||||
switch f.Class {
|
||||
case ELFCLASS64:
|
||||
return f.getSymbols64(typ)
|
||||
@ -339,27 +341,27 @@ func (f *File) getSymbols(typ SectionType) ([]Symbol, os.Error) {
|
||||
return f.getSymbols32(typ)
|
||||
}
|
||||
|
||||
return nil, os.ErrorString("not implemented")
|
||||
return nil, nil, os.ErrorString("not implemented")
|
||||
}
|
||||
|
||||
func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) {
|
||||
func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, os.Error) {
|
||||
symtabSection := f.SectionByType(typ)
|
||||
if symtabSection == nil {
|
||||
return nil, os.ErrorString("no symbol section")
|
||||
return nil, nil, os.ErrorString("no symbol section")
|
||||
}
|
||||
|
||||
data, err := symtabSection.Data()
|
||||
if err != nil {
|
||||
return nil, os.ErrorString("cannot load symbol section")
|
||||
return nil, nil, os.ErrorString("cannot load symbol section")
|
||||
}
|
||||
symtab := bytes.NewBuffer(data)
|
||||
if symtab.Len()%Sym32Size != 0 {
|
||||
return nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
|
||||
return nil, nil, os.ErrorString("length of symbol section is not a multiple of SymSize")
|
||||
}
|
||||
|
||||
strdata, err := f.stringTable(symtabSection.Link)
|
||||
if err != nil {
|
||||
return nil, os.ErrorString("cannot load string table section")
|
||||
return nil, nil, os.ErrorString("cannot load string table section")
|
||||
}
|
||||
|
||||
// The first entry is all zeros.
|
||||
@ -382,27 +384,27 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, os.Error) {
|
||||
i++
|
||||
}
|
||||
|
||||
return symbols, nil
|
||||
return symbols, strdata, nil
|
||||
}
|
||||
|
||||
func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) {
|
||||
func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, os.Error) {
|
||||
symtabSection := f.SectionByType(typ)
|
||||
if symtabSection == nil {
|
||||
return nil, os.ErrorString("no symbol section")
|
||||
return nil, nil, os.ErrorString("no symbol section")
|
||||
}
|
||||
|
||||
data, err := symtabSection.Data()
|
||||
if err != nil {
|
||||
return nil, os.ErrorString("cannot load symbol section")
|
||||
return nil, nil, os.ErrorString("cannot load symbol section")
|
||||
}
|
||||
symtab := bytes.NewBuffer(data)
|
||||
if symtab.Len()%Sym64Size != 0 {
|
||||
return nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
|
||||
return nil, nil, os.ErrorString("length of symbol section is not a multiple of Sym64Size")
|
||||
}
|
||||
|
||||
strdata, err := f.stringTable(symtabSection.Link)
|
||||
if err != nil {
|
||||
return nil, os.ErrorString("cannot load string table section")
|
||||
return nil, nil, os.ErrorString("cannot load string table section")
|
||||
}
|
||||
|
||||
// The first entry is all zeros.
|
||||
@ -425,7 +427,7 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, os.Error) {
|
||||
i++
|
||||
}
|
||||
|
||||
return symbols, nil
|
||||
return symbols, strdata, nil
|
||||
}
|
||||
|
||||
// getString extracts a string from an ELF string table.
|
||||
@ -468,7 +470,7 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) os.Error {
|
||||
return os.ErrorString("length of relocation section is not a multiple of Sym64Size")
|
||||
}
|
||||
|
||||
symbols, err := f.getSymbols(SHT_SYMTAB)
|
||||
symbols, _, err := f.getSymbols(SHT_SYMTAB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -544,24 +546,123 @@ func (f *File) DWARF() (*dwarf.Data, os.Error) {
|
||||
return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
|
||||
}
|
||||
|
||||
type ImportedSymbol struct {
|
||||
Name string
|
||||
Version string
|
||||
Library string
|
||||
}
|
||||
|
||||
// ImportedSymbols returns the names of all symbols
|
||||
// referred to by the binary f that are expected to be
|
||||
// satisfied by other libraries at dynamic load time.
|
||||
// It does not return weak symbols.
|
||||
func (f *File) ImportedSymbols() ([]string, os.Error) {
|
||||
sym, err := f.getSymbols(SHT_DYNSYM)
|
||||
func (f *File) ImportedSymbols() ([]ImportedSymbol, os.Error) {
|
||||
sym, str, err := f.getSymbols(SHT_DYNSYM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var all []string
|
||||
for _, s := range sym {
|
||||
f.gnuVersionInit(str)
|
||||
var all []ImportedSymbol
|
||||
for i, s := range sym {
|
||||
if ST_BIND(s.Info) == STB_GLOBAL && s.Section == SHN_UNDEF {
|
||||
all = append(all, s.Name)
|
||||
all = append(all, ImportedSymbol{Name: s.Name})
|
||||
f.gnuVersion(i, &all[len(all)-1])
|
||||
}
|
||||
}
|
||||
return all, nil
|
||||
}
|
||||
|
||||
type verneed struct {
|
||||
File string
|
||||
Name string
|
||||
}
|
||||
|
||||
// gnuVersionInit parses the GNU version tables
|
||||
// for use by calls to gnuVersion.
|
||||
func (f *File) gnuVersionInit(str []byte) {
|
||||
// Accumulate verneed information.
|
||||
vn := f.SectionByType(SHT_GNU_VERNEED)
|
||||
if vn == nil {
|
||||
return
|
||||
}
|
||||
d, _ := vn.Data()
|
||||
|
||||
var need []verneed
|
||||
i := 0
|
||||
for {
|
||||
if i+16 > len(d) {
|
||||
break
|
||||
}
|
||||
vers := f.ByteOrder.Uint16(d[i : i+2])
|
||||
if vers != 1 {
|
||||
break
|
||||
}
|
||||
cnt := f.ByteOrder.Uint16(d[i+2 : i+4])
|
||||
fileoff := f.ByteOrder.Uint32(d[i+4 : i+8])
|
||||
aux := f.ByteOrder.Uint32(d[i+8 : i+12])
|
||||
next := f.ByteOrder.Uint32(d[i+12 : i+16])
|
||||
file, _ := getString(str, int(fileoff))
|
||||
|
||||
var name string
|
||||
j := i + int(aux)
|
||||
for c := 0; c < int(cnt); c++ {
|
||||
if j+16 > len(d) {
|
||||
break
|
||||
}
|
||||
// hash := f.ByteOrder.Uint32(d[j:j+4])
|
||||
// flags := f.ByteOrder.Uint16(d[j+4:j+6])
|
||||
other := f.ByteOrder.Uint16(d[j+6 : j+8])
|
||||
nameoff := f.ByteOrder.Uint32(d[j+8 : j+12])
|
||||
next := f.ByteOrder.Uint32(d[j+12 : j+16])
|
||||
name, _ = getString(str, int(nameoff))
|
||||
ndx := int(other)
|
||||
if ndx >= len(need) {
|
||||
a := make([]verneed, 2*(ndx+1))
|
||||
copy(a, need)
|
||||
need = a
|
||||
}
|
||||
|
||||
need[ndx] = verneed{file, name}
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
j += int(next)
|
||||
}
|
||||
|
||||
if next == 0 {
|
||||
break
|
||||
}
|
||||
i += int(next)
|
||||
}
|
||||
|
||||
// Versym parallels symbol table, indexing into verneed.
|
||||
vs := f.SectionByType(SHT_GNU_VERSYM)
|
||||
if vs == nil {
|
||||
return
|
||||
}
|
||||
d, _ = vs.Data()
|
||||
|
||||
f.gnuNeed = need
|
||||
f.gnuVersym = d
|
||||
}
|
||||
|
||||
// gnuVersion adds Library and Version information to sym,
|
||||
// which came from offset i of the symbol table.
|
||||
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
|
||||
// Each entry is two bytes; skip undef entry at beginning.
|
||||
i = (i + 1) * 2
|
||||
if i >= len(f.gnuVersym) {
|
||||
return
|
||||
}
|
||||
j := int(f.ByteOrder.Uint16(f.gnuVersym[i:]))
|
||||
if j < 2 || j >= len(f.gnuNeed) {
|
||||
return
|
||||
}
|
||||
n := &f.gnuNeed[j]
|
||||
sym.Library = n.File
|
||||
sym.Version = n.Name
|
||||
}
|
||||
|
||||
// ImportedLibraries returns the names of all libraries
|
||||
// referred to by the binary f that are expected to be
|
||||
// linked with the binary at dynamic link time.
|
||||
|
Loading…
Reference in New Issue
Block a user