fix(asm): reject duplicate symbol declarations like the toolchain
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
a69f8cf4a8
commit
c107b45933
2 files changed
+154
-4
No files matched your search
+56
-4
@@ -557,11 +557,66 @@ type dataSym struct {
|
||||
relocs []Reloc
|
||||
}
|
||||
|
||||
// checkDuplicateDecls rejects a symbol the file declares twice, the
|
||||
// toolchain's OnList rule (cmd/internal/obj, InitTextSym and GloblPos,
|
||||
// measured with go tool asm): the second declaration of a symbol is
|
||||
// diagnosed as a redeclaration whether the pair is two TEXTs, two GLOBLs
|
||||
// or one of each, and a second TEXT carries the other declaration's line
|
||||
// the way the toolchain's note does. The DUPOK flag plays no part at
|
||||
// assembly time: it legalises duplicate definitions across files
|
||||
// (AttrDuplicateOK, which the linker resolves), never two declarations
|
||||
// inside one file, so a DUPOK pair here is rejected exactly like a plain
|
||||
// one. Symbol identity follows the object model: the package prefix and
|
||||
// the <> static marker are part of the name (foo(SB), foo<>(SB) and
|
||||
// other·foo(SB) are three symbols); the ABI selector is not, because
|
||||
// outside the runtime package, where alone it is legal, foo<ABIInternal>(SB)
|
||||
// resolves to foo(SB) and is a redeclaration.
|
||||
func checkDuplicateDecls(f *ast.File) error {
|
||||
type decl struct {
|
||||
text bool
|
||||
line int
|
||||
}
|
||||
seen := make(map[string]decl)
|
||||
symKey := func(s *ast.Symbol) string {
|
||||
key := s.Pkg + "\x00" + s.Name
|
||||
if s.Static {
|
||||
key += "\x00<>"
|
||||
}
|
||||
return key
|
||||
}
|
||||
for _, d := range f.Decls {
|
||||
switch t := d.(type) {
|
||||
case *ast.Text:
|
||||
if first, dup := seen[symKey(t.Name)]; dup {
|
||||
if first.text {
|
||||
return fmt.Errorf("symbol %q redeclared (other declaration on line %d)", t.Name.Name, first.line)
|
||||
}
|
||||
return fmt.Errorf("symbol %q redeclared", t.Name.Name)
|
||||
}
|
||||
seen[symKey(t.Name)] = decl{text: true, line: t.Pos().Line}
|
||||
case *ast.Globl:
|
||||
if t.Name == nil || t.Name.Pseudo != "SB" {
|
||||
continue
|
||||
}
|
||||
if _, dup := seen[symKey(t.Name)]; dup {
|
||||
return fmt.Errorf("symbol %q redeclared", t.Name.Name)
|
||||
}
|
||||
seen[symKey(t.Name)] = decl{line: t.Pos().Line}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// collectData gathers the file's static symbols (GLOBL) and their initial
|
||||
// contents (DATA) into byte buffers. Two passes: the Plan 9 convention puts
|
||||
// every DATA line before its symbol's GLOBL, so the symbols are registered
|
||||
// before the initialisers are applied.
|
||||
// before the initialisers are applied. Every per-architecture entry point
|
||||
// collects data before assembling text, so the duplicate-declaration check
|
||||
// rides here and covers them all.
|
||||
func collectData(f *ast.File) ([]dataSym, error) {
|
||||
if err := checkDuplicateDecls(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
index := map[string]int{}
|
||||
var syms []dataSym
|
||||
for _, d := range f.Decls {
|
||||
@@ -573,9 +628,6 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
||||
continue
|
||||
}
|
||||
name := gd.Name.Name
|
||||
if _, dup := index[name]; dup {
|
||||
return nil, fmt.Errorf("duplicate GLOBL %q", name)
|
||||
}
|
||||
size := 0
|
||||
if gd.Size != nil && gd.Size.Imm.HasVal {
|
||||
size = int(gd.Size.Imm.Val)
|
||||
|
||||
Reference in new issue
Block a user