[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