ldpkg(ctxt, f, lib, import1-import0-2, pn) // -2 for !\n
f.Seek(import1, 0)
- objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, eof-f.Offset(), pn)
+ flags := 0
+ switch *FlagStrictDups {
+ case 0:
+ break
+ case 1:
+ flags = objfile.StrictDupsWarnFlag
+ case 2:
+ flags = objfile.StrictDupsErrFlag
+ default:
+ log.Fatalf("invalid -strictdups flag value %d", *FlagStrictDups)
+ }
+ objfile.Load(ctxt.Arch, ctxt.Syms, f, lib, eof-f.Offset(), pn, flags)
addImports(ctxt, lib, pn)
return nil
}
Flag8 bool // use 64-bit addresses in symbol table
flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
+ FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
+ "fmt"
"io"
"log"
+ "os"
"strconv"
"strings"
)
pn string
dupSym *sym.Symbol
localSymVersion int
+ flags int
// rdBuf is used by readString and readSymName as scratch for reading strings.
rdBuf []byte
file []*sym.Symbol
}
+// Flags to enable optional behavior during object loading/reading.
+
+const (
+ NoFlag int = iota
+
+ // Sanity-check duplicate symbol contents, issuing warning
+ // when duplicates have different lengths or contents.
+ StrictDupsWarnFlag
+
+ // Similar to StrictDupsWarnFlag, but issue fatal error.
+ StrictDupsErrFlag
+)
+
// Load loads an object file f into library lib.
// The symbols loaded are added to syms.
-func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, length int64, pn string) {
+func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, length int64, pn string, flags int) {
start := f.Offset()
r := &objReader{
rd: f.Reader,
pn: pn,
dupSym: &sym.Symbol{Name: ".dup"},
localSymVersion: syms.IncVersion(),
+ flags: flags,
}
r.loadObjFile()
if f.Offset() != start+length {
if s.Type == sym.SDWARFINFO {
r.patchDWARFName(s)
}
+
+ if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
+ // Compare the just-read symbol with the previously read
+ // symbol of the same name, verifying that they have the same
+ // payload. If not, issue a warning and possibly an error.
+ if !bytes.Equal(s.P, dup.P) {
+ reason := "same length but different contents"
+ if len(s.P) != len(dup.P) {
+ reason = fmt.Sprintf("new length %d != old length %d",
+ len(data), len(dup.P))
+ }
+ fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Lib, reason)
+
+ // For the moment, whitelist DWARF subprogram DIEs for
+ // auto-generated wrapper functions. What seems to happen
+ // here is that we get different line numbers on formal
+ // params; I am guessing that the pos is being inherited
+ // from the spot where the wrapper is needed.
+ whitelist := strings.HasPrefix(dup.Name, "go.info.go.interface")
+
+ if r.flags&StrictDupsErrFlag != 0 && !whitelist {
+ log.Fatalf("failed duplicate symbol check on '%s' reading %s", dup.Name, r.pn)
+ }
+ }
+ }
}
func (r *objReader) patchDWARFName(s *sym.Symbol) {