[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
Wed Aug 14 14:30:38 PDT 2024


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

>From f85db243bdcd64e30be603efffb2bcb9a1c38b44 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 +-
 .../llvm-objcopy/wasm/basic-only-section.test | 16 +++--
 .../llvm-objcopy/wasm/only-keep-debug.test    | 38 +++++-----
 .../tools/llvm-objcopy/wasm/strip-all.test    |  6 ++
 .../tools/llvm-objcopy/wasm/strip-debug.test  | 71 +++++++++++++++++--
 .../tools/llvm-objcopy/wasm/strip-reloc.test  |  4 +-
 11 files changed, 130 insertions(+), 34 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/basic-only-section.test b/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test
index fe47d5c027733a..f30743c632bc86 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/basic-only-section.test
@@ -1,15 +1,15 @@
 ## Test --only-section.
 # RUN: yaml2obj %s -o %t
 # RUN: llvm-objcopy --only-section=foo %t %t2
-# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not linking %s
+# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not producers %s
 
 ## Test that it's the same with only-section + keep-section (for the same section).
 # RUN: llvm-objcopy --only-section=foo --keep-section=foo %t %t2
-# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not linking %s
+# RUN: obj2yaml %t2 | FileCheck --implicit-check-not TYPE --implicit-check-not producers %s
 
 ## Also test that only-section overrides remove-section.
 # RUN: llvm-objcopy --only-section=foo --remove-section=foo %t %t2
-# RUN: obj2yaml %t2 | FileCheck --implicit-check-not linking %s
+# RUN: obj2yaml %t2 | FileCheck --implicit-check-not producers %s
 
 ## This file has both known and custom sections. Check that only the foo section is left.
 # CHECK:      Sections:
@@ -19,10 +19,10 @@
 # CHECK-NEXT: ...
 
 ## Test that only-section + keep-section keeps both sections.
-# RUN: llvm-objcopy --only-section=foo --keep-section=linking %t %t2
+# RUN: llvm-objcopy --only-section=foo --keep-section=producers %t %t2
 # RUN: obj2yaml %t2 | FileCheck --implicit-check-not=TYPE --check-prefix=KEEP %s
 # KEEP: Name: foo
-# KEEP: Name: linking
+# KEEP: Name: producers
 
 --- !WASM
 FileHeader:
@@ -39,5 +39,7 @@ Sections:
         ReturnTypes:
           - F32
   - Type: CUSTOM
-    Name: linking
-    Version: 2
+    Name: producers
+    Tools:
+      - Name:   clang
+        Version: 9.0.0
diff --git a/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test b/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test
index fc57329bdd74c2..c7a5da99b1edf7 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/only-keep-debug.test
@@ -1,26 +1,32 @@
 ## Test that only debug sections are kept with --only-keep-debug.
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-strip --only-keep-debug %t
-# RUN: obj2yaml %t | FileCheck %s
+# RUN: yaml2obj %s -o %t.wasm
+# RUN: llvm-strip --only-keep-debug %t.wasm -o %t2.wasm
+# RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefixes=CHECK,STRIPTYPE,STRIPFOO
 
 ## Test that keep-section overrides only-keep-debug.
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-strip --only-keep-debug --keep-section=foo %t
-# RUN: obj2yaml %t | FileCheck --implicit-check-not=Name --check-prefix=CHECK --check-prefix=KEEP %s
+# RUN: llvm-strip --only-keep-debug --keep-section=foo %t.wasm -o %t3.wasm
+# RUN: obj2yaml %t3.wasm | FileCheck --implicit-check-not=Name --check-prefixes=CHECK,STRIPTYPE,KEEPFOO %s
 
 ## Test that keep-section overrides only-keep-debug, even for known sections.
-# RUN: yaml2obj %s -o %t
-# RUN: llvm-strip --only-keep-debug --keep-section=TYPE %t
-# RUN: obj2yaml %t | FileCheck --implicit-check-not=Name --check-prefix=CHECK --check-prefix=KEEPTYPE %s
+# RUN: llvm-strip --only-keep-debug --keep-section=TYPE %t.wasm -o %t4.wasm
+# RUN: obj2yaml %t4.wasm | FileCheck --implicit-check-not=Name --check-prefixes=CHECK,KEEPTYPE,STRIPFOO %s
 
 # CHECK:      Sections:
-# KEEPTYPE:     - Type: TYPE
-# CHECK-NOT:    - Type: TYPE
-# CHECK:        - Type: CUSTOM
-# CHECK-NEXT:     Name: .debug_info
-# CHECK:        - Type: CUSTOM
-# CHECK-NEXT:     Name: .debug_line
-# KEEP:           Name: foo
+# KEEPTYPE:       - Type: TYPE
+# STRIPTYPE-NOT:  - Type: TYPE
+# STRIPTYPE:      - Type: CUSTOM
+# STRIPTYPE-NEXT:   Name: .objcopy.removed
+# CHECK:          - Type: CUSTOM
+# CHECK-NEXT:       Name: .debug_info
+# CHECK:          - Type: CUSTOM
+# CHECK-NEXT:       Name: .objcopy.removed
+# CHECK:          - Type: CUSTOM
+# CHECK-NEXT:       Name: .objcopy.removed
+# CHECK:          - Type: CUSTOM
+# CHECK-NEXT:       Name: .debug_line
+# CHECK:          - Type: CUSTOM
+# KEEPFOO-NEXT:     Name: foo
+# STRIPFOO-NEXT:    Name: .objcopy.removed
 
 ## Test that remove-section overrides only-keep-debug.
 # RUN: yaml2obj %s -o %t
diff --git a/llvm/test/tools/llvm-objcopy/wasm/strip-all.test b/llvm/test/tools/llvm-objcopy/wasm/strip-all.test
index 9a9015713242c8..ef7c1a90e61075 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/strip-all.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/strip-all.test
@@ -7,6 +7,12 @@
 # CHECK:      Sections:
 # CHECK-NEXT:   - Type: TYPE
 # CHECK:        - Type: CUSTOM
+# CHECK-NEXT:        Name: .objcopy.removed
+# CHECK:        - Type: CUSTOM
+# CHECK-NEXT:        Name: .objcopy.removed
+# CHECK:        - Type: CUSTOM
+# CHECK-NEXT:        Name: .objcopy.removed
+# CHECK:        - Type: CUSTOM
 # CHECK-NEXT:        Name: foo
 
 --- !WASM
diff --git a/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
index 2747c3bab742ea..53e8153dd3539a 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/strip-debug.test
@@ -1,14 +1,65 @@
-## 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
-# CHECK:          Name: linking
+# CHECK:        - Type: CUSTOM
+## We expect the linking section to be preceeded by the removed `.debug_info`
+## section.
+# CHECK-NEXT:     Name:            .objcopy.removed
+# CHECK-NEXT:     Payload:         ''
+# CHECK-NEXT:   - Type: CUSTOM
+# CHECK-NEXT:     Name: linking
 # CHECK:          Name: name
 # CHECK-NEXT:     FunctionNames:
 # CHECK:          Name: producers
+## Following the producers section we expect to find three removed sections.
+## The `.debug_line` section that two reloction section corresponding to the
+## two debug sections.
+# CHECK:        - Type:            CUSTOM
+# CHECK-NEXT:     Name:            .objcopy.removed
+# CHECK-NEXT:     Payload:         ''
+# CHECK-NEXT:   - Type:            CUSTOM
+# CHECK-NEXT:     Name:            .objcopy.removed
+# CHECK-NEXT:     Payload:         ''
+# CHECK-NEXT:   - Type:            CUSTOM
+# CHECK-NEXT:     Name:            .objcopy.removed
+# CHECK-NEXT:     Payload:         ''
+
 
 --- !WASM
 FileHeader:
@@ -28,7 +79,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 +105,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
diff --git a/llvm/test/tools/llvm-objcopy/wasm/strip-reloc.test b/llvm/test/tools/llvm-objcopy/wasm/strip-reloc.test
index 4c8d1ba670447f..d072bf70c9db76 100644
--- a/llvm/test/tools/llvm-objcopy/wasm/strip-reloc.test
+++ b/llvm/test/tools/llvm-objcopy/wasm/strip-reloc.test
@@ -5,13 +5,15 @@
 
 # RUN: yaml2obj %s -o %t
 # RUN: llvm-objcopy --strip-all %t %t2
-# RUN: obj2yaml %t2 | FileCheck --implicit-check-not=Type: %s
+# RUN: obj2yaml %t2 | FileCheck %s
 
 ## Check that the known sections are still present.
 # CHECK: Sections:
 # CHECK: - Type: TYPE
 # CHECK: - Type: FUNCTION
 # CHECK: - Type: CODE
+# CHECK-NOT: Relocations
+# CHECK-NOT: linking
 ## Check that there are still functions in the code section.
 # CHECK: Functions:
 



More information about the llvm-commits mailing list