[lld][WebAssembly] Disallow exporting of TLS symbols

Cross module TLS is currently not supported by our ABI.  This
change makes explicitly exporting a TLS symbol into an error
and prevents implicit exporting (via --export-all).

See https://github.com/emscripten-core/emscripten/issues/14120

Differential Revision: https://reviews.llvm.org/D102044
This commit is contained in:
Sam Clegg 2021-05-06 20:29:05 -07:00
parent f44c6f20f5
commit bda8b84884
8 changed files with 48 additions and 9 deletions

View File

@ -0,0 +1,26 @@
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
# RUN: wasm-ld -no-gc-sections --shared-memory --no-entry -o %t.wasm %t.o
# RUN: not wasm-ld --shared-memory --no-entry --export=tls1 -o %t.wasm %t.o 2>&1 | FileCheck %s
# With --export-all we ignore TLS symbols so we don't expect an error here
# RUN: wasm-ld --shared-memory --no-entry --export-all -o %t.wasm %t.o
# CHECK: error: TLS symbols cannot yet be exported: `tls1`
.section .tdata.tls1,"",@
.globl tls1
.p2align 2
tls1:
.int32 1
.size tls1, 4
.section .custom_section.target_features,"",@
.int8 3
.int8 43
.int8 7
.ascii "atomics"
.int8 43
.int8 11
.ascii "bulk-memory"
.int8 43
.int8 15
.ascii "mutable-globals"

View File

@ -117,6 +117,9 @@ public:
const OutputSegment *outputSeg = nullptr;
uint32_t outputSegmentOffset = 0;
uint32_t alignment = 0;
bool isTLS() {
return getName().startswith(".tdata") || getName().startswith(".tbss");
}
protected:
ArrayRef<uint8_t> data() const override { return segment.Data.Content; }

View File

@ -247,7 +247,7 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
// files created before we introduced TLS relocations.
// TODO(sbc): Remove this legacy behaviour one day. This will break
// backward compat with old object files built with `-fPIC`.
if (D->segment && D->segment->outputSeg->name == ".tdata")
if (D->segment && D->segment->outputSeg->isTLS())
return D->getOutputSegmentOffset() + reloc.Addend;
uint64_t value = D->getVA(reloc.Addend);

View File

@ -32,6 +32,8 @@ public:
size += inSeg->getSize();
}
bool isTLS() const { return name == ".tdata"; }
StringRef name;
bool isBss = false;
uint32_t index = 0;

View File

@ -115,7 +115,7 @@ void scanRelocations(InputChunk *chunk) {
break;
case R_WASM_MEMORY_ADDR_TLS_SLEB:
if (auto *D = dyn_cast<DefinedData>(sym)) {
if (D->segment->outputSeg->name != ".tdata") {
if (!D->segment->outputSeg->isTLS()) {
error(toString(file) + ": relocation " +
relocTypeToString(reloc.Type) + " cannot be used against `" +
toString(*sym) +

View File

@ -207,13 +207,14 @@ bool Symbol::isExported() const {
if (!isDefined() || isLocal())
return false;
if (forceExport || config->exportAll)
if (config->exportAll || (config->exportDynamic && !isHidden()))
return true;
if (config->exportDynamic && !isHidden())
return true;
return isExportedExplicit();
}
return flags & WASM_SYMBOL_EXPORTED;
bool Symbol::isExportedExplicit() const {
return forceExport || flags & WASM_SYMBOL_EXPORTED;
}
bool Symbol::isNoStrip() const {

View File

@ -110,6 +110,7 @@ public:
WasmSymbolType getWasmType() const;
bool isExported() const;
bool isExportedExplicit() const;
// Indicates that the symbol is used in an __attribute__((used)) directive
// or similar.

View File

@ -270,7 +270,7 @@ void Writer::layoutMemory() {
log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", seg->name,
memoryPtr, seg->size, seg->alignment));
if (!config->relocatable && seg->name == ".tdata") {
if (!config->relocatable && seg->isTLS()) {
if (config->sharedMemory) {
auto *tlsSize = cast<DefinedGlobal>(WasmSym::tlsSize);
setGlobalPtr(tlsSize, seg->size);
@ -631,6 +631,12 @@ void Writer::calculateExports() {
} else if (auto *e = dyn_cast<DefinedEvent>(sym)) {
export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()};
} else if (auto *d = dyn_cast<DefinedData>(sym)) {
if (d->segment && d->segment->isTLS()) {
// We can't currenly export TLS data symbols.
if (sym->isExportedExplicit())
error("TLS symbols cannot yet be exported: `" + toString(*sym) + "`");
continue;
}
out.globalSec->dataAddressGlobals.push_back(d);
export_ = {name, WASM_EXTERNAL_GLOBAL, globalIndex++};
} else {
@ -900,7 +906,7 @@ void Writer::combineOutputSegments() {
OutputSegment *combined = nullptr;
std::vector<OutputSegment *> new_segments;
for (OutputSegment *s : segments) {
if (s->name == ".tdata") {
if (s->isTLS()) {
new_segments.push_back(s);
} else {
if (!combined) {
@ -946,7 +952,7 @@ static void createFunction(DefinedFunction *func, StringRef bodyContent) {
bool Writer::needsPassiveInitialization(const OutputSegment *segment) {
return segment->initFlags & WASM_DATA_SEGMENT_IS_PASSIVE &&
segment->name != ".tdata" && !segment->isBss;
!segment->isTLS() && !segment->isBss;
}
bool Writer::hasPassiveInitializedSegments() {