Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lld][WebAssembly] Fix regression in function signature checking #78831

Merged
merged 1 commit into from
Jan 20, 2024

Conversation

sbc100
Copy link
Collaborator

@sbc100 sbc100 commented Jan 20, 2024

Followup to #78658, which caused a regression in emscripten.

When a lazy symbol is added, which resolved and existing undefined symbol, we don't need/want to replace the undefined symbol with the lazy one. Instead we called extract, which replaces the undefined symbol with the defined one.

The fact that we were first replacing the undefined symbol with a lazy one before extracting the archive member doesn't normally matter but, in the case of the function symbol, replacing the undefined symbol with a lazy symbol means that addDefinedFunction sees the existing symbol as lazy and simply replaces it.

Note that this is consistent with both the ELF code in Symbol::resolve(const LazySymbol &other) and the wasm code prior to
#78658, neither of which replace the existing symbol with the lazy one
in this case.

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 20, 2024

@llvm/pr-subscribers-lld

Author: Sam Clegg (sbc100)

Changes

Followup to #78658, which caused a regression in emscripten.

When a lazy symbol is added, which resolved and existing undefined symbol, we don't need/want to replace the undefined symbol with the lazy one. Instead we called extract, which replaces the undefined symbol with the defined one.

The fact that we were first replacing the undefined symbol with a lazy one before extracting the archive member doesn't normally matter but, in the case of the function symbol, replacing the undefined symbol with a lazy symbol means that addDefinedFunction sees the existing symbol as lazy and simply replaces it.

Note that this is consistent with both the ELF code in Symbol::resolve(const LazySymbol &other) and the wasm code prior to
#78658, neither of which replace the existing symbol with the lazy one
in this case.


Full diff: https://github.com/llvm/llvm-project/pull/78831.diff

3 Files Affected:

  • (modified) lld/test/wasm/signature-mismatch.s (+10-1)
  • (modified) lld/wasm/SymbolTable.cpp (+3-3)
  • (modified) lld/wasm/Symbols.h (+1-1)
diff --git a/lld/test/wasm/signature-mismatch.s b/lld/test/wasm/signature-mismatch.s
index 5d305efca24649..7dc1b8ced3530d 100644
--- a/lld/test/wasm/signature-mismatch.s
+++ b/lld/test/wasm/signature-mismatch.s
@@ -8,6 +8,11 @@
 # RUN: wasm-ld -r -o %t.reloc.o %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=WARN
 # RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC
 
+# RUN: rm -f %t.a
+# RUN: ar crS %t.a %t.ret32.o %t.call.o
+# RUN: wasm-ld --export=call_ret32 --export=ret32 -o %t2.wasm %t.main.o %t.a 2>&1 | FileCheck %s -check-prefix=ARCHIVE
+# RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefix=YAML
+
 # RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=ERROR
 
 .functype ret32 (i32, i64, i32) -> (i32)
@@ -42,6 +47,10 @@ ret32_address_main:
 # WARN-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
 # WARN-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
 
+# ARCHIVE: warning: function signature mismatch: ret32
+# ARCHIVE-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
+# ARCHIVE-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
+
 # ERROR: error: function signature mismatch: ret32
 # ERROR-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
 # ERROR-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
@@ -56,7 +65,7 @@ ret32_address_main:
 
 # YAML:        - Type:            CUSTOM
 # YAML-NEXT:     Name:            name
-# YAML-NEXT:     FunctionNames:   
+# YAML-NEXT:     FunctionNames:
 # YAML-NEXT:       - Index:           0
 # YAML-NEXT:         Name:            'signature_mismatch:ret32'
 # YAML-NEXT:       - Index:           1
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index c98aa3ee3a7a32..c000d5d3b97dc0 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -749,7 +749,7 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) {
   std::tie(s, wasInserted) = insertName(name);
 
   if (wasInserted) {
-    replaceSymbol<LazySymbol>(s, name, 0, file);
+    replaceSymbol<LazySymbol>(s, name, file);
     return;
   }
 
@@ -767,14 +767,14 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) {
       oldSig = f->signature;
     LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
     auto newSym =
-        replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, file);
+        replaceSymbol<LazySymbol>(s, name, file, WASM_SYMBOL_BINDING_WEAK);
     newSym->signature = oldSig;
     return;
   }
 
   LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
   const InputFile *oldFile = s->getFile();
-  replaceSymbol<LazySymbol>(s, name, 0, file)->extract();
+  LazySymbol(name, file).extract();
   if (!config->whyExtract.empty())
     ctx.whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s);
 }
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index de52c92d34e78b..9908f23f38695b 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -497,7 +497,7 @@ class UndefinedTag : public TagSymbol {
 // symbols into consideration.
 class LazySymbol : public Symbol {
 public:
-  LazySymbol(StringRef name, uint32_t flags, InputFile *file)
+  LazySymbol(StringRef name, InputFile *file, uint8_t flags = 0)
       : Symbol(name, LazyKind, flags, file) {}
 
   static bool classof(const Symbol *s) { return s->kind() == LazyKind; }

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 20, 2024

@llvm/pr-subscribers-lld-wasm

Author: Sam Clegg (sbc100)

Changes

Followup to #78658, which caused a regression in emscripten.

When a lazy symbol is added, which resolved and existing undefined symbol, we don't need/want to replace the undefined symbol with the lazy one. Instead we called extract, which replaces the undefined symbol with the defined one.

The fact that we were first replacing the undefined symbol with a lazy one before extracting the archive member doesn't normally matter but, in the case of the function symbol, replacing the undefined symbol with a lazy symbol means that addDefinedFunction sees the existing symbol as lazy and simply replaces it.

Note that this is consistent with both the ELF code in Symbol::resolve(const LazySymbol &amp;other) and the wasm code prior to
#78658, neither of which replace the existing symbol with the lazy one
in this case.


Full diff: https://github.com/llvm/llvm-project/pull/78831.diff

3 Files Affected:

  • (modified) lld/test/wasm/signature-mismatch.s (+10-1)
  • (modified) lld/wasm/SymbolTable.cpp (+3-3)
  • (modified) lld/wasm/Symbols.h (+1-1)
diff --git a/lld/test/wasm/signature-mismatch.s b/lld/test/wasm/signature-mismatch.s
index 5d305efca246496..7dc1b8ced3530d5 100644
--- a/lld/test/wasm/signature-mismatch.s
+++ b/lld/test/wasm/signature-mismatch.s
@@ -8,6 +8,11 @@
 # RUN: wasm-ld -r -o %t.reloc.o %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=WARN
 # RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC
 
+# RUN: rm -f %t.a
+# RUN: ar crS %t.a %t.ret32.o %t.call.o
+# RUN: wasm-ld --export=call_ret32 --export=ret32 -o %t2.wasm %t.main.o %t.a 2>&1 | FileCheck %s -check-prefix=ARCHIVE
+# RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefix=YAML
+
 # RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=ERROR
 
 .functype ret32 (i32, i64, i32) -> (i32)
@@ -42,6 +47,10 @@ ret32_address_main:
 # WARN-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
 # WARN-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
 
+# ARCHIVE: warning: function signature mismatch: ret32
+# ARCHIVE-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
+# ARCHIVE-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
+
 # ERROR: error: function signature mismatch: ret32
 # ERROR-NEXT: >>> defined as (i32, i64, i32) -> i32 in {{.*}}.main.o
 # ERROR-NEXT: >>> defined as (f32) -> i32 in {{.*}}.ret32.o
@@ -56,7 +65,7 @@ ret32_address_main:
 
 # YAML:        - Type:            CUSTOM
 # YAML-NEXT:     Name:            name
-# YAML-NEXT:     FunctionNames:   
+# YAML-NEXT:     FunctionNames:
 # YAML-NEXT:       - Index:           0
 # YAML-NEXT:         Name:            'signature_mismatch:ret32'
 # YAML-NEXT:       - Index:           1
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index c98aa3ee3a7a320..c000d5d3b97dc0d 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -749,7 +749,7 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) {
   std::tie(s, wasInserted) = insertName(name);
 
   if (wasInserted) {
-    replaceSymbol<LazySymbol>(s, name, 0, file);
+    replaceSymbol<LazySymbol>(s, name, file);
     return;
   }
 
@@ -767,14 +767,14 @@ void SymbolTable::addLazy(StringRef name, InputFile *file) {
       oldSig = f->signature;
     LLVM_DEBUG(dbgs() << "replacing existing weak undefined symbol\n");
     auto newSym =
-        replaceSymbol<LazySymbol>(s, name, WASM_SYMBOL_BINDING_WEAK, file);
+        replaceSymbol<LazySymbol>(s, name, file, WASM_SYMBOL_BINDING_WEAK);
     newSym->signature = oldSig;
     return;
   }
 
   LLVM_DEBUG(dbgs() << "replacing existing undefined\n");
   const InputFile *oldFile = s->getFile();
-  replaceSymbol<LazySymbol>(s, name, 0, file)->extract();
+  LazySymbol(name, file).extract();
   if (!config->whyExtract.empty())
     ctx.whyExtractRecords.emplace_back(toString(oldFile), s->getFile(), *s);
 }
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index de52c92d34e78b0..9908f23f38695b8 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -497,7 +497,7 @@ class UndefinedTag : public TagSymbol {
 // symbols into consideration.
 class LazySymbol : public Symbol {
 public:
-  LazySymbol(StringRef name, uint32_t flags, InputFile *file)
+  LazySymbol(StringRef name, InputFile *file, uint8_t flags = 0)
       : Symbol(name, LazyKind, flags, file) {}
 
   static bool classof(const Symbol *s) { return s->kind() == LazyKind; }

Followup to llvm#78658, which caused a regression in emscripten.

When a lazy symbol is added, which resolved and existing undefined
symbol, we don't need/want to replace the undefined symbol with the lazy
one.  Instead we called extract, which replaces the undefined symbol
with the defined one.

The fact that we were first replacing the undefined symbol with a lazy
one before extracting the archive member doesn't normally matter but,
in the case of the function symbol, replacing the undefined symbol with
a lazy symbol means that `addDefinedFunction` sees the existing symbol
as lazy and simply replaces it.

Note that this is consistent with both the ELF code in
`Symbol::resolve(const LazySymbol &other)` and the wasm code prior to
 llvm#78658, neither of which replace the existing symbol with the lazy one
in this case.
@sbc100 sbc100 merged commit 58d5a48 into llvm:main Jan 20, 2024
3 of 4 checks passed
@sbc100 sbc100 deleted the fix_lazy branch January 20, 2024 05:45
@@ -8,6 +8,11 @@
# RUN: wasm-ld -r -o %t.reloc.o %t.main.o %t.ret32.o %t.call.o 2>&1 | FileCheck %s -check-prefix=WARN
# RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC

# RUN: rm -f %t.a
# RUN: ar crS %t.a %t.ret32.o %t.call.o
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be llvm-ar? I wasn't sure this would work on e.g. Windows where there's no "system" ar, and the (few) other uses of 'ar' in tests use llvm-ar.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by: 4b4763f

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants