[lld] [llvm] [llvm-objcopy][WebAssembly] Allow --strip-debug to operate on relocatable files. (PR #102978)

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 12 16:14:46 PDT 2024


https://github.com/sbc100 updated https://github.com/llvm/llvm-project/pull/102978

>From 05a578be2aecbfc1751960ecfb14cd61f193ff1c Mon Sep 17 00:00:00 2001
From: Sam Clegg <sbc at chromium.org>
Date: Mon, 12 Aug 2024 13:53:33 -0700
Subject: [PATCH] [llvm-objcopy][WebAssembly] Allow --strip-debug to operate on
 relocatable files.

This change is enough to allow `--strip-debug` to work on object files,
without breaking the relocation information or symbol table.

A more complete version of this change would instead reconstruct the
symbol table and relocation sections, but that is much larger change.

Bug: #102002
---
 lld/wasm/Writer.cpp                           |  5 ++
 llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp         |  2 +-
 llvm/lib/ObjCopy/wasm/WasmObject.cpp          | 18 ++++++-
 llvm/lib/ObjCopy/wasm/WasmObject.h            |  1 +
 llvm/lib/ObjCopy/wasm/WasmReader.cpp          |  1 +
 llvm/lib/ObjectYAML/WasmEmitter.cpp           |  2 +-
 .../tools/llvm-objcopy/wasm/strip-debug.test  | 50 +++++++++++++++++--
 7 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 6a66a29d2498c5..6beef81d39a381 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -138,6 +138,11 @@ void Writer::calculateCustomSections() {
       // Exclude COMDAT sections that are not selected for inclusion
       if (section->discarded)
         continue;
+      // Ignore empty custom sections.  In particular objcopy/strip will
+      // sometimes replace stripped sections with empty custom sections to
+      // avoid section re-numbering.
+      if (section->getSize() == 0)
+        continue;
       StringRef name = section->name;
       // These custom sections are known the linker and synthesized rather than
       // blindly copied.
diff --git a/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp b/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
index 5bba1dea9adf0e..cf3d884bee3bd8 100644
--- a/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
+++ b/llvm/lib/ObjCopy/wasm/WasmObjcopy.cpp
@@ -22,7 +22,7 @@ using namespace object;
 using SectionPred = std::function<bool(const Section &Sec)>;
 
 static bool isDebugSection(const Section &Sec) {
-  return Sec.Name.starts_with(".debug");
+  return Sec.Name.starts_with(".debug") || Sec.Name.starts_with("reloc..debug");
 }
 
 static bool isLinkerSection(const Section &Sec) {
diff --git a/llvm/lib/ObjCopy/wasm/WasmObject.cpp b/llvm/lib/ObjCopy/wasm/WasmObject.cpp
index 28a2de6e6e4f12..0b543b793f049e 100644
--- a/llvm/lib/ObjCopy/wasm/WasmObject.cpp
+++ b/llvm/lib/ObjCopy/wasm/WasmObject.cpp
@@ -25,8 +25,22 @@ void Object::addSectionWithOwnedContents(
 }
 
 void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
-  // TODO: remove reloc sections for the removed section, handle symbols, etc.
-  llvm::erase_if(Sections, ToRemove);
+  if (isRelocatableObject) {
+    // For relocatable objects, avoid actually removing any sections,
+    // since that can invalidate the symbol table and relocation sections.
+    // TODO: Allow removal of sections by re-generating symbol table and
+    // relocation sections here instead.
+    for (auto &Sec : Sections) {
+      if (ToRemove(Sec)) {
+        Sec.Name = ".objcopy.removed";
+        Sec.SectionType = wasm::WASM_SEC_CUSTOM;
+        Sec.Contents = {};
+        Sec.HeaderSecSizeEncodingLen = std::nullopt;
+      }
+    }
+  } else {
+    llvm::erase_if(Sections, ToRemove);
+  }
 }
 
 } // end namespace wasm
diff --git a/llvm/lib/ObjCopy/wasm/WasmObject.h b/llvm/lib/ObjCopy/wasm/WasmObject.h
index f860ec697e5684..374e523cd879b6 100644
--- a/llvm/lib/ObjCopy/wasm/WasmObject.h
+++ b/llvm/lib/ObjCopy/wasm/WasmObject.h
@@ -32,6 +32,7 @@ struct Object {
   llvm::wasm::WasmObjectHeader Header;
   // For now don't discriminate between kinds of sections.
   std::vector<Section> Sections;
+  bool isRelocatableObject = false;
 
   void addSectionWithOwnedContents(Section NewSection,
                                    std::unique_ptr<MemoryBuffer> &&Content);
diff --git a/llvm/lib/ObjCopy/wasm/WasmReader.cpp b/llvm/lib/ObjCopy/wasm/WasmReader.cpp
index 578e78955af3e4..420d17f9864323 100644
--- a/llvm/lib/ObjCopy/wasm/WasmReader.cpp
+++ b/llvm/lib/ObjCopy/wasm/WasmReader.cpp
@@ -18,6 +18,7 @@ using namespace llvm::wasm;
 Expected<std::unique_ptr<Object>> Reader::create() const {
   auto Obj = std::make_unique<Object>();
   Obj->Header = WasmObj.getHeader();
+  Obj->isRelocatableObject = WasmObj.isRelocatableObject();
   std::vector<Section> Sections;
   Obj->Sections.reserve(WasmObj.getNumSections());
   for (const SectionRef &Sec : WasmObj.sections()) {
diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp
index 9b8fd11f85437e..c728e3a51e82e8 100644
--- a/llvm/lib/ObjectYAML/WasmEmitter.cpp
+++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp
@@ -604,7 +604,7 @@ bool WasmWriter::writeWasm(raw_ostream &OS) {
     if (auto S = dyn_cast<WasmYAML::CustomSection>(Sec.get()))
       SecName = S->Name;
     if (!Checker.isValidSectionOrder(Sec->Type, SecName)) {
-      reportError("out of order section type: " + Twine(Sec->Type));
+      reportError("out of order section type: " + wasm::sectionTypeToString(Sec->Type));
       return false;
     }
     encodeULEB128(Sec->Type, OS);
diff --git a/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
index 2747c3bab742ea..e8dd6a05b30f85 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
@@ -1,7 +1,39 @@
-## Test that debug sections (but not linking or names) are stripped with --strip-debug
 # RUN: yaml2obj %s -o %t
-# RUN: llvm-strip --strip-debug %t
-# RUN: obj2yaml %t | FileCheck --implicit-check-not=.debug %s
+# RUN: cp %t %t3
+# RUN: llvm-objcopy --strip-debug %t %t2
+## Test that debug sections (but not linking or names) are stripped with --strip-debug
+# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=.debug %s
+#
+# RUN: llvm-objcopy -g %t %t2g
+# Verify that --strip-debug and -g produce the same output
+# RUN: cmp %t2 %t2g
+
+# RUN: llvm-strip --strip-debug %t3
+# RUN: cmp %t2 %t3
+
+# RUN: cp %t %t4
+# RUN: llvm-strip -d %t4
+# RUN: cmp %t2 %t4
+
+# RUN: cp %t %t5
+# RUN: llvm-strip -g %t5
+# RUN: cmp %t2 %t5
+
+# RUN: cp %t %t6
+# RUN: llvm-strip -S %t6
+# RUN: cmp %t2 %t6
+
+# Verify that an archive with multiple object files is handled correctly.
+# RUN: cp %t %t.duplicate
+# RUN: cp %t2 %t.duplicate.stripped
+# RUN: rm -f %t.multiple-stripped-obj.a
+# RUN: llvm-ar crs %t.multiple-stripped-obj.a %t2 %t.duplicate.stripped
+# RUN: rm -f %t.multiple-obj.a
+# RUN: llvm-ar crs %t.multiple-obj.a %t %t.duplicate
+# RUN: llvm-objcopy --strip-debug %t.multiple-obj.a %t.multiple-obj.stripped.a
+# RUN: llvm-ar p %t.multiple-stripped-obj.a > %t.multiple-stripped-obj.a.dump
+# RUN: llvm-ar p %t.multiple-obj.stripped.a > %t.multiple-obj.stripped.a.dump
+# RUN: cmp %t.multiple-stripped-obj.a.dump %t.multiple-obj.stripped.a.dump
 
 # CHECK:      Sections:
 # CHECK-NEXT:   - Type: TYPE
@@ -28,7 +60,11 @@ Sections:
         Body: 0B
   - Type: CUSTOM
     Name: .debug_info
-    Payload: CAFE1234
+    Payload: 'CAFE123456'
+    Relocations:
+      - Type:   R_WASM_FUNCTION_INDEX_LEB
+        Index:  0
+        Offset: 0x0000000
   - Type:            CUSTOM
     Name:            linking
     Version:         2
@@ -50,4 +86,8 @@ Sections:
         Version: 9.0.0
   - Type: CUSTOM
     Name: .debug_line
-    Payload: DEADBEEF
+    Payload: 'DEADBEEF01'
+    Relocations:
+      - Type:   R_WASM_FUNCTION_INDEX_LEB
+        Index:  0
+        Offset: 0x0000000



More information about the llvm-commits mailing list