diff --git a/chore/nmdump/nmdump.go b/chore/nmdump/nmdump.go index aa1a2bee..4a0e2a8b 100644 --- a/chore/nmdump/nmdump.go +++ b/chore/nmdump/nmdump.go @@ -22,6 +22,7 @@ import ( "os" "github.com/goplus/llgo/xtool/env/llvm" + nmtool "github.com/goplus/llgo/xtool/nm" ) func main() { @@ -45,10 +46,17 @@ func main() { fmt.Printf("\n%s:\n", item.File) } for _, sym := range item.Symbols { + var versionInfo string + switch sym.VersionType { + case nmtool.VersionSpecific: + versionInfo = fmt.Sprintf("@%s", sym.Version) + case nmtool.VersionDefault: + versionInfo = fmt.Sprintf("@@%s", sym.Version) + } if sym.FAddr { - fmt.Printf("%016x %c %s\n", sym.Addr, sym.Type, sym.Name) + fmt.Printf("%016x %c %s%s\n", sym.Addr, sym.Type, sym.Name, versionInfo) } else { - fmt.Printf("%16s %c %s\n", "", sym.Type, sym.Name) + fmt.Printf("%16s %c %s%s\n", "", sym.Type, sym.Name, versionInfo) } } } diff --git a/xtool/nm/nm.go b/xtool/nm/nm.go index 156c9a50..a1c44e0d 100644 --- a/xtool/nm/nm.go +++ b/xtool/nm/nm.go @@ -62,12 +62,26 @@ const ( LocalASym = SymbolType('s') // Local symbol in an assembler source file ) +// VersionType represents the version type of a symbol. +// This is specific to Linux systems. +// On macOS , this will always be VersionNone. +// https://sourceware.org/binutils/docs/binutils/nm.html +type VersionType int + +const ( + VersionNone VersionType = iota // No version information + VersionSpecific // Specific version (@) + VersionDefault // Default version (@@) +) + // Symbol represents a symbol in an object file. type Symbol struct { - Name string // symbol name - Addr uint64 // symbol address - Type SymbolType // symbol type - FAddr bool // address is valid + Name string // symbol name + Addr uint64 // symbol address + Type SymbolType // symbol type + FAddr bool // address is valid + VersionType VersionType // version type of the symbol + Version string // version information of the symbol } // ObjectFile represents an object file. @@ -143,28 +157,48 @@ func listOutput(data []byte) (items []*ObjectFile, err error) { return } var sym *Symbol + var fullSymName string if is64bits(line) { + fullSymName = string(line[19:]) sym = &Symbol{ - Name: string(line[19:]), Type: SymbolType(line[17]), } if sym.FAddr = hasAddr(line); sym.FAddr { sym.Addr = hexUint64(line) } } else { + fullSymName = string(line[11:]) sym = &Symbol{ - Name: string(line[11:]), Type: SymbolType(line[9]), } if sym.FAddr = hasAddr(line); sym.FAddr { sym.Addr = uint64(hexUint32(line)) } } + + sym.Name, sym.VersionType, sym.Version = parseSymName(fullSymName) item.Symbols = append(item.Symbols, sym) } return } +func parseSymName(symName string) (name string, versionType VersionType, version string) { + if idx := strings.LastIndex(symName, "@"); idx != -1 { + name = symName[:idx] + version = symName[idx+1:] + if idx > 0 && symName[idx-1] == '@' { + versionType = VersionDefault + name = symName[:idx-1] + } else { + versionType = VersionSpecific + } + } else { + name = symName + versionType = VersionNone + } + return +} + func hasAddr(line []byte) bool { c := line[0] return c != ' ' && c != '-'