-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lld][WebAssembly] Fix TLS-relative relocations when linking without shared memory #116136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-lld @llvm/pr-subscribers-lld-wasm Author: Sam Clegg (sbc100) ChangesTLS-relative relocation always need to be relative the TLS section since they get added to Without this change the tls base address was effectively being added to the final value twice in this case. This only effects code the is built with Fixes: emscripten-core/emscripten#22880 Full diff: https://github.com/llvm/llvm-project/pull/116136.diff 5 Files Affected:
diff --git a/lld/test/wasm/tls-non-shared-memory.s b/lld/test/wasm/tls-non-shared-memory.s
index 1754fd6254bb80..04fbb62228a7e2 100644
--- a/lld/test/wasm/tls-non-shared-memory.s
+++ b/lld/test/wasm/tls-non-shared-memory.s
@@ -44,6 +44,7 @@ tls1:
# RUN: wasm-ld --no-gc-sections --no-entry -o %t.wasm %t.o
# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump --disassemble-symbols=get_tls1 --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS
# RUN: wasm-ld --experimental-pic -shared -o %t.so %t.o
# RUN: obj2yaml %t.so | FileCheck %s --check-prefixes=SHARED,PIC
@@ -97,6 +98,14 @@ tls1:
# CHECK-NEXT: Content: 2A000000
# CHECK-NEXT: - Type: CUSTOM
+# The constant value here which we add to `__tls_base` should not be absolute
+# but relative to `__tls_base`, in this case zero rather than 1024.
+# DIS: <get_tls1>:
+# DIS-EMPTY:
+# DIS-NEXT: global.get 1
+# DIS-NEXT: i32.const 0
+# DIS-NEXT: i32.add
+# DIS-NEXT: end
# In PIC mode we expect TLS data and non-TLS data to be merged into
# a single segment which is initialized via the __memory_base import
diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index 45ad32701616a1..2776ede8be9034 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -122,16 +122,16 @@ void scanRelocations(InputChunk *chunk) {
" cannot be used against an undefined symbol `" + toString(*sym) +
"`");
}
+ if (!sym->isTLS()) {
+ error(toString(file) + ": relocation " +
+ relocTypeToString(reloc.Type) +
+ " cannot be used against non-TLS symbol `" + toString(*sym) +
+ "`");
+ }
// In single-threaded builds TLS is lowered away and TLS data can be
// merged with normal data and allowing TLS relocation in non-TLS
// segments.
if (config->sharedMemory) {
- if (!sym->isTLS()) {
- error(toString(file) + ": relocation " +
- relocTypeToString(reloc.Type) +
- " cannot be used against non-TLS symbol `" + toString(*sym) +
- "`");
- }
if (auto *D = dyn_cast<DefinedData>(sym)) {
if (!D->segment->outputSeg->isTLS()) {
error(toString(file) + ": relocation " +
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index b2bbd11c53ef23..8df850ce23032f 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -310,12 +310,11 @@ uint32_t DefinedFunction::getExportedFunctionIndex() const {
return function->getFunctionIndex();
}
-uint64_t DefinedData::getVA() const {
+uint64_t DefinedData::getVA(bool absolute) const {
LLVM_DEBUG(dbgs() << "getVA: " << getName() << "\n");
- // In the shared memory case, TLS symbols are relative to the start of the TLS
- // output segment (__tls_base). When building without shared memory, TLS
- // symbols absolute, just like non-TLS.
- if (isTLS() && config->sharedMemory)
+ // TLS symbols are relative to the start of the TLS output segment
+ // (__tls_base).
+ if (isTLS() && !absolute)
return getOutputSegmentOffset();
if (segment)
return segment->getVA(value);
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 5ce3ecbc4ab194..310842b89098f9 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -315,7 +315,9 @@ class DefinedData : public DataSymbol {
static bool classof(const Symbol *s) { return s->kind() == DefinedDataKind; }
// Returns the output virtual address of a defined data symbol.
- uint64_t getVA() const;
+ // For TLS symbols, by default (unless absolute us set), this returns an
+ // address relative the `__tls_base`.
+ uint64_t getVA(bool absolute = false) const;
void setVA(uint64_t va);
// Returns the offset of a defined data symbol within its OutputSegment.
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index a3bc90cfe759ca..1e8abe9bc7b246 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -514,7 +514,10 @@ void GlobalSection::writeBody() {
} else {
WasmInitExpr initExpr;
if (auto *d = dyn_cast<DefinedData>(sym))
- initExpr = intConst(d->getVA(), is64);
+ // In the sharedMemory case `__wasm_apply_global_tls_relocs` is used
+ // to set the final value of this globel, but in the non-shared case
+ // we know the absolute value at link time.
+ initExpr = intConst(d->getVA(/*absolute=*/!config->sharedMemory), is64);
else if (auto *f = dyn_cast<FunctionSymbol>(sym))
initExpr = intConst(f->isStub ? 0 : f->getTableIndex(), is64);
else {
|
ab1c799
to
de8fdac
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
lld/wasm/Relocations.cpp
Outdated
relocTypeToString(reloc.Type) + | ||
" cannot be used against non-TLS symbol `" + toString(*sym) + | ||
"`"); | ||
} | ||
// In single-threaded builds TLS is lowered away and TLS data can be |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this comment move up too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this change is kind of separate so I just reverted it for now.
@@ -514,7 +514,10 @@ void GlobalSection::writeBody() { | |||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does the extended-const case also need to be updated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No since in that case we do the addition with __tls_base
as part of the const expression. i.e. its don't for us at instantiation time.
So I guess there are 3 ways this addition can happen:
- At instantiation time via extended const
- As part of __wasm_apply_global_tls_relocs at runtime
- At static link time via
getVA(absolute=true)
de8fdac
to
95dd1e3
Compare
ptal.. |
…shared memory TLS-relative relocation always need to be relative the TLS section since they get added to `__tls_base` at runtime. Without this change the tls base address was effectively being added to the final value twice in this case. This only effects code the is built with `-pthread` but linked without shared memory (i.e. without threads). Fixes: emscripten-core/emscripten#22880
95dd1e3
to
08e071c
Compare
TLS-relative relocations always need to be relative the TLS section since they get added to
__tls_base
at runtime.Without this change the tls base address was effectively being added to the final value twice in this case.
This only effects code the is built with
-pthread
but linked without shared memory (i.e. without threads).Fixes: emscripten-core/emscripten#22880