Skip to content

Commit 89d5635

Browse files
committed
[lld][WebAssembly] Add --keep-section flag
This flag causes wasm-ld preserve a section even in the face of `--strip-all`. This is useful, for example, to preserve the target_features section in the ase of clang (which can run wasm-opt after linking), and emcc (which performs a bunch of post-link work). Fixes: #60613 Fixes: #55781 Differential Revision: https://reviews.llvm.org/D149917
1 parent 01fc345 commit 89d5635

File tree

7 files changed

+73
-22
lines changed

7 files changed

+73
-22
lines changed

clang/lib/Driver/ToolChains/WebAssembly.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
141141
CmdArgs.push_back("-o");
142142
CmdArgs.push_back(Output.getFilename());
143143

144+
// When optimizing, if wasm-opt is available, run it.
145+
std::string WasmOptPath;
146+
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
147+
WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
148+
if (WasmOptPath == "wasm-opt") {
149+
WasmOptPath = {};
150+
}
151+
}
152+
153+
if (!WasmOptPath.empty()) {
154+
CmdArgs.push_back("--keep-section=target_features");
155+
}
156+
144157
C.addCommand(std::make_unique<Command>(JA, *this,
145158
ResponseFileSupport::AtFileCurCP(),
146159
Linker, CmdArgs, Inputs, Output));
147160

148-
// When optimizing, if wasm-opt is available, run it.
149161
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
150-
auto WasmOptPath = ToolChain.GetProgramPath("wasm-opt");
151-
if (WasmOptPath != "wasm-opt") {
162+
if (!WasmOptPath.empty()) {
152163
StringRef OOpt = "s";
153164
if (A->getOption().matches(options::OPT_O4) ||
154165
A->getOption().matches(options::OPT_Ofast))
@@ -160,13 +171,13 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA,
160171

161172
if (OOpt != "0") {
162173
const char *WasmOpt = Args.MakeArgString(WasmOptPath);
163-
ArgStringList CmdArgs;
164-
CmdArgs.push_back(Output.getFilename());
165-
CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
166-
CmdArgs.push_back("-o");
167-
CmdArgs.push_back(Output.getFilename());
174+
ArgStringList OptArgs;
175+
OptArgs.push_back(Output.getFilename());
176+
OptArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt));
177+
OptArgs.push_back("-o");
178+
OptArgs.push_back(Output.getFilename());
168179
C.addCommand(std::make_unique<Command>(
169-
JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, CmdArgs,
180+
JA, *this, ResponseFileSupport::AtFileCurCP(), WasmOpt, OptArgs,
170181
Inputs, Output));
171182
}
172183
}

lld/test/wasm/strip-all.s

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.start.o
2+
# RUN: wasm-ld --strip-all -o %t.wasm %t.start.o
3+
# RUN: obj2yaml %t.wasm | FileCheck %s
4+
#
5+
## Test alias -s
6+
# RUN: wasm-ld -s -o %t2.wasm %t.start.o
7+
# RUN: obj2yaml %t2.wasm | FileCheck %s
8+
#
9+
## Check that there is no name section
10+
# CHECK-NOT: Name: name
11+
# CHECK-NOT: Name: target_features
12+
#
13+
## Test --keep-section=name preserver the name section
14+
# RUN: wasm-ld --strip-all --keep-section=name -o %t3.wasm %t.start.o
15+
# RUN: obj2yaml %t3.wasm | FileCheck --check-prefix=CHECK-NAME %s
16+
#
17+
# CHECK-NAME: Name: name
18+
# CHECK-NAME-NOT: Name: target_features
19+
#
20+
## Test --keep-section can be specified more than once
21+
# RUN: wasm-ld --strip-all --keep-section=name --keep-section=target_features -o %t4.wasm %t.start.o
22+
# RUN: obj2yaml %t4.wasm | FileCheck --check-prefix=CHECK-FEATURES %s
23+
#
24+
# CHECK-FEATURES: Name: name
25+
# CHECK-FEATURES: Name: target_features
26+
27+
.globl _start
28+
_start:
29+
.functype _start () -> ()
30+
end_function
31+
32+
.section .custom_section.target_features,"",@
33+
.int8 1
34+
.int8 43
35+
.int8 15
36+
.ascii "mutable-globals"

lld/test/wasm/strip-all.test

Lines changed: 0 additions & 10 deletions
This file was deleted.

lld/wasm/Config.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ struct Configuration {
4949
bool extendedConst;
5050
bool growableTable;
5151
bool gcSections;
52+
llvm::StringSet<> keepSections;
5253
std::optional<std::pair<llvm::StringRef, llvm::StringRef>> memoryImport;
5354
std::optional<llvm::StringRef> memoryExport;
5455
bool sharedMemory;

lld/wasm/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ static void readConfigs(opt::InputArgList &args) {
478478
config->relocatable = args.hasArg(OPT_relocatable);
479479
config->gcSections =
480480
args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !config->relocatable);
481+
for (auto *arg : args.filtered(OPT_keep_section))
482+
config->keepSections.insert(arg->getValue());
481483
config->mergeDataSegments =
482484
args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments,
483485
!config->relocatable);

lld/wasm/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ def growable_table: FF<"growable-table">,
193193
def global_base: JJ<"global-base=">,
194194
HelpText<"Memory offset at which to place global data (Defaults to 1024)">;
195195

196+
defm keep_section: Eq<"keep-section",
197+
"Preserve a section even when --strip-all is given. This is useful for compiler drivers such as clang or emcc that, for example, depend on the features section for post-link processing. Can be specified multiple times to keep multiple sections">;
198+
196199
def import_memory: FF<"import-memory">,
197200
HelpText<"Import the module's memory from the default module of \"env\" with the name \"memory\".">;
198201
def import_memory_with_name: JJ<"import-memory=">,

lld/wasm/SyntheticSections.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,11 @@ class NameSection : public SyntheticSection {
373373
NameSection(ArrayRef<OutputSegment *> segments)
374374
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "name"),
375375
segments(segments) {}
376-
bool isNeeded() const override { return !config->stripAll && numNames() > 0; }
376+
bool isNeeded() const override {
377+
if (config->stripAll && !config->keepSections.count(name))
378+
return false;
379+
return numNames() > 0;
380+
}
377381
void writeBody() override;
378382
unsigned numNames() const {
379383
// We always write at least one name which is the name of the
@@ -393,7 +397,9 @@ class ProducersSection : public SyntheticSection {
393397
ProducersSection()
394398
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "producers") {}
395399
bool isNeeded() const override {
396-
return !config->stripAll && fieldCount() > 0;
400+
if (config->stripAll && !config->keepSections.count(name))
401+
return false;
402+
return fieldCount() > 0;
397403
}
398404
void writeBody() override;
399405
void addInfo(const llvm::wasm::WasmProducerInfo &info);
@@ -412,7 +418,9 @@ class TargetFeaturesSection : public SyntheticSection {
412418
TargetFeaturesSection()
413419
: SyntheticSection(llvm::wasm::WASM_SEC_CUSTOM, "target_features") {}
414420
bool isNeeded() const override {
415-
return !config->stripAll && features.size() > 0;
421+
if (config->stripAll && !config->keepSections.count(name))
422+
return false;
423+
return features.size() > 0;
416424
}
417425
void writeBody() override;
418426

0 commit comments

Comments
 (0)