Skip to content

[lld][WebAssembly] Do not emit relocs against dead symbols #129346

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

Merged
merged 4 commits into from
Mar 4, 2025

Conversation

dschuff
Copy link
Member

@dschuff dschuff commented Mar 1, 2025

When emitting relocs with linked output (i.e. --emit-relocs)
skip relocs against dead symbols (which do not appear in the output)
and do not emit them.

When emitting relocs with linked output (i.e. --emit-relocs)
skip relocs against dead symbols (which donot appear in the output)
and do not emit them.
@dschuff dschuff requested a review from sbc100 March 1, 2025 01:49
@dschuff dschuff requested a review from aheejin March 1, 2025 01:49
@llvmbot
Copy link
Member

llvmbot commented Mar 1, 2025

@llvm/pr-subscribers-lld-wasm

Author: Derek Schuff (dschuff)

Changes

When emitting relocs with linked output (i.e. --emit-relocs)
skip relocs against dead symbols (which donot appear in the output)
and do not emit them.


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

6 Files Affected:

  • (modified) lld/test/wasm/emit-relocs.s (+15)
  • (modified) lld/wasm/InputChunks.cpp (+15)
  • (modified) lld/wasm/InputChunks.h (+1)
  • (modified) lld/wasm/OutputSections.cpp (+1-1)
  • (modified) lld/wasm/OutputSections.h (+1)
  • (modified) lld/wasm/Symbols.cpp (+1-1)
diff --git a/lld/test/wasm/emit-relocs.s b/lld/test/wasm/emit-relocs.s
index bd136ba810b5e..385344cb23321 100644
--- a/lld/test/wasm/emit-relocs.s
+++ b/lld/test/wasm/emit-relocs.s
@@ -27,6 +27,12 @@ foo:
   .int32  0
   .size   foo, 4
 
+.section .debug_info,"",@
+.p2align 2
+.int32 unused_function
+.int32 _start
+.int32 0
+
 # CHECK:        - Type:            CODE
 # CHECK-NEXT:     Relocations:
 # CHECK-NEXT:       - Type:            R_WASM_FUNCTION_INDEX_LEB
@@ -42,6 +48,15 @@ foo:
 # CHECK-NEXT:           Value:           1024
 # CHECK-NEXT:         Content:         '00000000'
 
+# There should be a single relocation in this section (just the live symbol)
+# CHECK-NEXT:  - Type:            CUSTOM
+# CHECK-NEXT:    Relocations:
+# CHECK-NEXT:      - Type:            R_WASM_FUNCTION_OFFSET_I32
+# CHECK-NEXT:        Index:           0
+# CHECK-NEXT:        Offset:          0x4
+# CHECK-NEXT:    Name:            .debug_info
+# CHECK-NEXT:    Payload:         FFFFFFFF0200000000000000
+
 # CHECK:        - Type:            CUSTOM
 # CHECK-NEXT:     Name:            linking
 # CHECK-NEXT:     Version:         2
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index ccdc92f5c8d71..0558f64aa7c42 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -167,6 +167,19 @@ void InputChunk::relocate(uint8_t *buf) const {
   }
 }
 
+static bool relocIsLive(const WasmRelocation& rel, ObjFile* file) {
+  return rel.Type == R_WASM_TYPE_INDEX_LEB ||
+    file->getSymbol(rel.Index)->isLive();
+}
+
+size_t InputChunk::getNumLiveRelocations() const {
+  size_t result = 0;
+  for (const WasmRelocation& rel : relocations) {
+    if (relocIsLive(rel, file)) result ++;
+  }
+  return result;
+}
+
 // Copy relocation entries to a given output stream.
 // This function is used only when a user passes "-r". For a regular link,
 // we consume relocations instead of copying them to an output file.
@@ -179,6 +192,8 @@ void InputChunk::writeRelocations(raw_ostream &os) const {
                     << " offset=" << Twine(off) << "\n");
 
   for (const WasmRelocation &rel : relocations) {
+    if (!relocIsLive(rel, file))
+      continue;
     writeUleb128(os, rel.Type, "reloc type");
     writeUleb128(os, rel.Offset + off, "reloc offset");
     writeUleb128(os, file->calcNewIndex(rel), "reloc index");
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index f545449e1246f..1fe78d76631f1 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -77,6 +77,7 @@ class InputChunk {
   uint32_t getInputSectionOffset() const { return inputSectionOffset; }
 
   size_t getNumRelocations() const { return relocations.size(); }
+  size_t getNumLiveRelocations() const;
   void writeRelocations(llvm::raw_ostream &os) const;
   bool generateRelocationCode(raw_ostream &os) const;
 
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index d679d1e676479..5038cd8ea965b 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -274,7 +274,7 @@ void CustomSection::writeTo(uint8_t *buf) {
 uint32_t CustomSection::getNumRelocations() const {
   uint32_t count = 0;
   for (const InputChunk *inputSect : inputSections)
-    count += inputSect->getNumRelocations();
+    count += inputSect->getNumLiveRelocations();
   return count;
 }
 
diff --git a/lld/wasm/OutputSections.h b/lld/wasm/OutputSections.h
index fcc8cf45dc73b..4b0329dd16cf2 100644
--- a/lld/wasm/OutputSections.h
+++ b/lld/wasm/OutputSections.h
@@ -41,6 +41,7 @@ class OutputSection {
   virtual void writeTo(uint8_t *buf) = 0;
   virtual void finalizeContents() = 0;
   virtual uint32_t getNumRelocations() const { return 0; }
+  virtual uint32_t getNumLiveRelocations() const { return getNumRelocations(); }
   virtual void writeRelocations(raw_ostream &os) const {}
 
   std::string header;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index a687fd6d6c4ef..09f110d0885f6 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -183,7 +183,7 @@ void Symbol::markLive() {
 }
 
 uint32_t Symbol::getOutputSymbolIndex() const {
-  assert(outputSymbolIndex != INVALID_INDEX);
+  assert(outputSymbolIndex != INVALID_INDEX || !isLive());
   return outputSymbolIndex;
 }
 

@llvmbot
Copy link
Member

llvmbot commented Mar 1, 2025

@llvm/pr-subscribers-lld

Author: Derek Schuff (dschuff)

Changes

When emitting relocs with linked output (i.e. --emit-relocs)
skip relocs against dead symbols (which donot appear in the output)
and do not emit them.


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

6 Files Affected:

  • (modified) lld/test/wasm/emit-relocs.s (+15)
  • (modified) lld/wasm/InputChunks.cpp (+15)
  • (modified) lld/wasm/InputChunks.h (+1)
  • (modified) lld/wasm/OutputSections.cpp (+1-1)
  • (modified) lld/wasm/OutputSections.h (+1)
  • (modified) lld/wasm/Symbols.cpp (+1-1)
diff --git a/lld/test/wasm/emit-relocs.s b/lld/test/wasm/emit-relocs.s
index bd136ba810b5e..385344cb23321 100644
--- a/lld/test/wasm/emit-relocs.s
+++ b/lld/test/wasm/emit-relocs.s
@@ -27,6 +27,12 @@ foo:
   .int32  0
   .size   foo, 4
 
+.section .debug_info,"",@
+.p2align 2
+.int32 unused_function
+.int32 _start
+.int32 0
+
 # CHECK:        - Type:            CODE
 # CHECK-NEXT:     Relocations:
 # CHECK-NEXT:       - Type:            R_WASM_FUNCTION_INDEX_LEB
@@ -42,6 +48,15 @@ foo:
 # CHECK-NEXT:           Value:           1024
 # CHECK-NEXT:         Content:         '00000000'
 
+# There should be a single relocation in this section (just the live symbol)
+# CHECK-NEXT:  - Type:            CUSTOM
+# CHECK-NEXT:    Relocations:
+# CHECK-NEXT:      - Type:            R_WASM_FUNCTION_OFFSET_I32
+# CHECK-NEXT:        Index:           0
+# CHECK-NEXT:        Offset:          0x4
+# CHECK-NEXT:    Name:            .debug_info
+# CHECK-NEXT:    Payload:         FFFFFFFF0200000000000000
+
 # CHECK:        - Type:            CUSTOM
 # CHECK-NEXT:     Name:            linking
 # CHECK-NEXT:     Version:         2
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index ccdc92f5c8d71..0558f64aa7c42 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -167,6 +167,19 @@ void InputChunk::relocate(uint8_t *buf) const {
   }
 }
 
+static bool relocIsLive(const WasmRelocation& rel, ObjFile* file) {
+  return rel.Type == R_WASM_TYPE_INDEX_LEB ||
+    file->getSymbol(rel.Index)->isLive();
+}
+
+size_t InputChunk::getNumLiveRelocations() const {
+  size_t result = 0;
+  for (const WasmRelocation& rel : relocations) {
+    if (relocIsLive(rel, file)) result ++;
+  }
+  return result;
+}
+
 // Copy relocation entries to a given output stream.
 // This function is used only when a user passes "-r". For a regular link,
 // we consume relocations instead of copying them to an output file.
@@ -179,6 +192,8 @@ void InputChunk::writeRelocations(raw_ostream &os) const {
                     << " offset=" << Twine(off) << "\n");
 
   for (const WasmRelocation &rel : relocations) {
+    if (!relocIsLive(rel, file))
+      continue;
     writeUleb128(os, rel.Type, "reloc type");
     writeUleb128(os, rel.Offset + off, "reloc offset");
     writeUleb128(os, file->calcNewIndex(rel), "reloc index");
diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h
index f545449e1246f..1fe78d76631f1 100644
--- a/lld/wasm/InputChunks.h
+++ b/lld/wasm/InputChunks.h
@@ -77,6 +77,7 @@ class InputChunk {
   uint32_t getInputSectionOffset() const { return inputSectionOffset; }
 
   size_t getNumRelocations() const { return relocations.size(); }
+  size_t getNumLiveRelocations() const;
   void writeRelocations(llvm::raw_ostream &os) const;
   bool generateRelocationCode(raw_ostream &os) const;
 
diff --git a/lld/wasm/OutputSections.cpp b/lld/wasm/OutputSections.cpp
index d679d1e676479..5038cd8ea965b 100644
--- a/lld/wasm/OutputSections.cpp
+++ b/lld/wasm/OutputSections.cpp
@@ -274,7 +274,7 @@ void CustomSection::writeTo(uint8_t *buf) {
 uint32_t CustomSection::getNumRelocations() const {
   uint32_t count = 0;
   for (const InputChunk *inputSect : inputSections)
-    count += inputSect->getNumRelocations();
+    count += inputSect->getNumLiveRelocations();
   return count;
 }
 
diff --git a/lld/wasm/OutputSections.h b/lld/wasm/OutputSections.h
index fcc8cf45dc73b..4b0329dd16cf2 100644
--- a/lld/wasm/OutputSections.h
+++ b/lld/wasm/OutputSections.h
@@ -41,6 +41,7 @@ class OutputSection {
   virtual void writeTo(uint8_t *buf) = 0;
   virtual void finalizeContents() = 0;
   virtual uint32_t getNumRelocations() const { return 0; }
+  virtual uint32_t getNumLiveRelocations() const { return getNumRelocations(); }
   virtual void writeRelocations(raw_ostream &os) const {}
 
   std::string header;
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index a687fd6d6c4ef..09f110d0885f6 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -183,7 +183,7 @@ void Symbol::markLive() {
 }
 
 uint32_t Symbol::getOutputSymbolIndex() const {
-  assert(outputSymbolIndex != INVALID_INDEX);
+  assert(outputSymbolIndex != INVALID_INDEX || !isLive());
   return outputSymbolIndex;
 }
 

Copy link

github-actions bot commented Mar 1, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

if (relocIsLive(rel, file))
result++;
}
return result;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there a modern C++ way to write an accumulator like this?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think the alternative would be something like

  return std::count_if(relocations.begin(), relocations.end(),
                       [&](const WasmRelocation &rel) {
                         return relocIsLive(rel, file);
                       });

That's... a little shorter, I guess?

@sbc100 sbc100 changed the title [lld][Wasm] Do not emit relocs against dead symbols [lld][WebAssembly] Do not emit relocs against dead symbols Mar 1, 2025
@dschuff dschuff merged commit a59b17c into llvm:main Mar 4, 2025
11 checks passed
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
When emitting relocs with linked output (i.e. --emit-relocs)
skip relocs against dead symbols (which do not appear in the output)
and do not emit them.
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.

3 participants