// The shared library contains a note containing the ABI hash that is mapped into // memory and there is a local symbol called go.link.abihashbytes that points 16 // bytes into it. func testABIHashNote(t *testing.T, f *elf.File, note *note) { if note.section.Flags != elf.SHF_ALLOC { t.Errorf("abi hash section has flags %v", note.section.Flags) } if !isOffsetLoaded(f, note.section.Offset) { t.Errorf("abihash section not contained in PT_LOAD segment") } var hashbytes elf.Symbol symbols, err := f.Symbols() if err != nil { t.Errorf("error reading symbols %v", err) return } for _, sym := range symbols { if sym.Name == "go.link.abihashbytes" { hashbytes = sym } } if hashbytes.Name == "" { t.Errorf("no symbol called go.link.abihashbytes") return } if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL { t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info)) } if f.Sections[hashbytes.Section] != note.section { t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name) } if hashbytes.Value-note.section.Addr != 16 { t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr) } }
func elfSymbols(f *os.File) (syms []Sym, goarch string) { p, err := elf.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return } elfSyms, err := p.Symbols() if err != nil { errorf("parsing %s: %v", f.Name(), err) return } switch p.Machine { case elf.EM_X86_64: goarch = "amd64" case elf.EM_386: goarch = "386" case elf.EM_ARM: goarch = "arm" } for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i < 0 || i >= len(p.Sections) { break } sect := p.Sections[i] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return }
func elfSymbols(f *os.File) []Sym { p, err := elf.NewFile(f) if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } elfSyms, err := p.Symbols() if err != nil { errorf("parsing %s: %v", f.Name(), err) return nil } var syms []Sym for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i <= 0 || i > len(p.Sections) { break } sect := p.Sections[i-1] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return syms }
func (f *elfFile) symbols() ([]Sym, error) { elfSyms, err := f.elf.Symbols() if err != nil { return nil, err } var syms []Sym for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i < 0 || i >= len(f.elf.Sections) { break } sect := f.elf.Sections[i] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return syms, nil }
func ldshlibsyms(shlib string) { found := false libpath := "" for _, libdir := range Ctxt.Libdir { libpath = filepath.Join(libdir, shlib) if _, err := os.Stat(libpath); err == nil { found = true break } } if !found { Diag("cannot find shared library: %s", shlib) return } for _, processedlib := range Ctxt.Shlibs { if processedlib.Path == libpath { return } } if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil { fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath) Ctxt.Bso.Flush() } f, err := elf.Open(libpath) if err != nil { Diag("cannot open shared library: %s", libpath) return } defer f.Close() syms, err := f.Symbols() if err != nil { Diag("cannot read symbols from shared library: %s", libpath) return } // If a package has a global variable of a type defined in another shared // library, we need to know the gcmask used by the type, if any. To support // this, we read all the runtime.gcbits.* symbols, keep a map of address to // gcmask, and after we're read all the symbols, read the addresses of the // gcmasks symbols out of the type data to look up the gcmask for each type. // This depends on the fact that the runtime.gcbits.* symbols are local (so // the address is actually present in the type data and we don't have to // search all relocations to find the ones which correspond to gcmasks) and // also that the shared library we are linking against has not had the symbol // table removed. gcmasks := make(map[uint64][]byte) types := []*LSym{} var hash []byte for _, s := range syms { if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION { continue } if s.Section == elf.SHN_UNDEF { continue } if strings.HasPrefix(s.Name, "_") { continue } if strings.HasPrefix(s.Name, "runtime.gcbits.") { gcmasks[s.Value] = readelfsymboldata(f, &s) } if s.Name == "go.link.abihashbytes" { hash = readelfsymboldata(f, &s) } if elf.ST_BIND(s.Info) != elf.STB_GLOBAL { continue } lsym := Linklookup(Ctxt, s.Name, 0) if lsym.Type != 0 && lsym.Dupok == 0 { Diag( "Found duplicate symbol %s reading from %s, first found in %s", s.Name, shlib, lsym.File) } lsym.Type = obj.SDYNIMPORT lsym.ElfType = elf.ST_TYPE(s.Info) lsym.File = libpath if strings.HasPrefix(lsym.Name, "type.") { if f.Sections[s.Section].Type == elf.SHT_PROGBITS { lsym.P = readelfsymboldata(f, &s) } if !strings.HasPrefix(lsym.Name, "type..") { types = append(types, lsym) } } } for _, t := range types { if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 { continue } addr := decodetype_gcprog_shlib(t) tgcmask, ok := gcmasks[addr] if !ok { Diag("bits not found for %s at %d", t.Name, addr) } t.gcmask = tgcmask } // We might have overwritten some functions above (this tends to happen for the // autogenerated type equality/hashing functions) and we don't want to generated // pcln table entries for these any more so unstitch them from the Textp linked // list. var last *LSym for s := Ctxt.Textp; s != nil; s = s.Next { if s.Type == obj.SDYNIMPORT { continue } if last == nil { Ctxt.Textp = s } else { last.Next = s } last = s } if last == nil { Ctxt.Textp = nil Ctxt.Etextp = nil } else { last.Next = nil Ctxt.Etextp = last } Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash}) }