-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[lld][WebAssembly] Fix non-pie dynamic-linking executable #108146
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: YAMAMOTO Takashi (yamt) ChangesFixes #107387 Full diff: https://github.com/llvm/llvm-project/pull/108146.diff 3 Files Affected:
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index cb8fe2534f5fe7..79cacc63922ee5 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -913,7 +913,8 @@ static void createSyntheticSymbols() {
}
if (ctx.isPic ||
- config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) {
+ config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic ||
+ !config->isStatic) {
// For PIC code, or when dynamically importing addresses, we create
// synthetic functions that apply relocations. These get called from
// __wasm_call_ctors before the user-level constructors.
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 975225974aff6e..dbf800422e45b5 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -378,7 +378,7 @@ void InputChunk::generateRelocationCode(raw_ostream &os) const {
uint64_t offset = getVA(rel.Offset) - getInputSectionOffset();
Symbol *sym = file->getSymbol(rel);
- if (!ctx.isPic && sym->isDefined())
+ if (!ctx.isPic && sym->isDefined() && !sym->hasGOTIndex())
continue;
LLVM_DEBUG(dbgs() << "gen reloc: type=" << relocTypeToString(rel.Type)
diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index 6f33a4f28a9d09..70229179afdcfc 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -146,7 +146,8 @@ void scanRelocations(InputChunk *chunk) {
if (ctx.isPic ||
(sym->isUndefined() &&
- config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) {
+ config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) ||
+ sym->isShared()) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
|
lld/wasm/Driver.cpp
Outdated
@@ -913,7 +913,8 @@ static void createSyntheticSymbols() { | |||
} | |||
|
|||
if (ctx.isPic || | |||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) { | |||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic || | |||
!config->isStatic) { |
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.
I wonder if can replace ctx.isPic
with !config->isStatic
above? Does it make sense to allow -shared
+ -static
? Or -pie
+ -static
?
I wonder if we need a better way to detect if dynamic linking used at all since you can imagine a case where isStatic
is true, but we do have dynamic linking. For example:
$ wasm-ld foo.o -Bdynamic -ldylib -Bstatic -lstaticlib
In that case since -Bstatic
comes last on the command line the config->isStatic
will be false even though we include libdylib.so dyanmically.
Another example:
wasm-ld foo.o libdylib.so libstaticlib.a
Here config->isStatic
will remain false even though dynamic linking is used.
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 it looks like that the latter case should reject the .so
file. I see the ELF linker does this:
llvm-project/lld/ELF/Driver.cpp
Lines 341 to 344 in 96b7c64
if (config->isStatic) { | |
error("attempted static link of dynamic object " + path); | |
return; | |
} |
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.
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.
I wonder if can replace
ctx.isPic
with!config->isStatic
above? Does it make sense to allow-shared
+-static
? Or-pie
+-static
?I wonder if we need a better way to detect if dynamic linking used at all since you can imagine a case where
isStatic
is true, but we do have dynamic linking. For example:$ wasm-ld foo.o -Bdynamic -ldylib -Bstatic -lstaticlib
In that case since
-Bstatic
comes last on the command line theconfig->isStatic
will be false even though we include libdylib.so dyanmically.
i guess it's simpler to defer the decision to createApplyDataRelocationsFunction.
how do you think?
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.
i guess it's simpler to defer the decision to createApplyDataRelocationsFunction.
i pushed a commit to implement it.
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.
@sbc100 do you have any more concerns?
82dd674
to
9513512
Compare
lld/wasm/Writer.cpp
Outdated
make<SyntheticFunction>(nullSignature, "__wasm_apply_data_relocs")); | ||
def->markLive(); | ||
|
||
createFunction(def, bodyContent); |
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.
This change seems to incorporate a couple of different things now. Would you mind separating out the change to "Only create __wasm_apply_data_relocs conditionally". That seems like it could land separately and is somewhat unrelated to fix at hand?
Also, regarding the conditional creation of this symbol, what happens if somebody does --export=__wasm_apply_data_relocs
or otherwise references this symbol, but we "skip" creating it?
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.
This change seems to incorporate a couple of different things now. Would you mind separating out the change to "Only create __wasm_apply_data_relocs conditionally". That seems like it could land separately and is somewhat unrelated to fix at hand?
Also, regarding the conditional creation of this symbol, what happens if somebody does
--export=__wasm_apply_data_relocs
or otherwise references this symbol, but we "skip" creating it?
is it expected to work at all? do you have real use cases? or is it just a theoretical concern?
i thought __wasm_apply_data_relocs was just for dynamic-linking.
Could you update the PR description describing what was broken and how this fixes the issue? Also, can we add a new test or update one of the existing ones to make sure we don't regress again? |
i will update if/when #109249 is merged. |
3559e1f
to
91f33a4
Compare
The commit 22b7b84 made the symbols provided by shared libraries "defined", and thus effectively made it impossible to generate non-pie dynamically linked executables using --unresolved-symbols=import-dynamic. This commit, based on llvm#109249, fixes it by checking sym->isShared() explictly. (as a bonus, you don't need to rely on --unresolved-symbols=import-dynamic anymore.) Fixes llvm#107387
91f33a4
to
06482d7
Compare
|
lld/test/wasm/Inputs/lib.s
Outdated
.type f,@function | ||
f: | ||
.functype f () -> () | ||
end_function |
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.
Rather than creating a new file here you can just pick an existing file such as ret32.s
and compile that
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.
ok. i will try.
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.
done
lld/wasm/Relocations.cpp
Outdated
@@ -146,7 +146,8 @@ void scanRelocations(InputChunk *chunk) { | |||
|
|||
if (ctx.isPic || | |||
(sym->isUndefined() && | |||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic)) { | |||
config->unresolvedSymbols == UnresolvedPolicy::ImportDynamic) || | |||
sym->isShared()) { |
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.
Can you put this new clause on line 147 (e.g. if (ctx.isPic || sym->isShared() ||
)
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.
ok
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.
done
lld/test/wasm/dylink-non-pie.s
Outdated
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.lib.o %p/Inputs/lib.s | ||
# RUN: wasm-ld -m wasm32 --experimental-pic -shared --no-entry %t.lib.o -o %t.lib.so | ||
# RUN: llvm-mc -filetype=obj -mattr=+reference-types -triple=wasm32-unknown-unknown -o %t.o %s | ||
# RUN: wasm-ld -m wasm32 --features=mutable-globals -Bdynamic --export-table --growable-table --export-memory --export=__stack_pointer --export=__heap_base --export=__heap_end --entry=_start %t.o %t.lib.so -o %t.wasm |
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.
Can you remove any link flags that you don't need here? e.g. all of the --export
flags and the --entry
flag?
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.
i wanted to mimic the real situation to link a non-pie executable.
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.
done
lld/test/wasm/dylink-non-pie.s
Outdated
i32.const f_p@MBREL | ||
i32.add | ||
i32.load 0 | ||
call_indirect __indirect_function_table, () -> () |
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.
You don't need the __indirect_function_table
symbol to make this test work. You can just do i32.const f_p
followed by drop
I think.
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.
let me think a bit. thank you.
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.
done
no functional changes are intended
|
||
# CHECK: - Type: EXPORT | ||
# CHECK: - Name: __wasm_apply_data_relocs | ||
# CHECK-NEXT: Kind: FUNCTION |
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 we be checking for some more things here?
Perhaps we can check that GOT.ret32
is imported? Perhaps we can decompile __wasm_apply_data_relocs
and verify that is using GOT.ret32
as expected?
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.
do you know any existing tests doing similar things which i can use as an example?
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.
Yes, there are a few tests that disassembly stuff. Looks for DIS-NEXT
in lld/test/wasm.
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.
ok. i will take a look.
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.
done
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.lib.o %p/Inputs/ret32.s | ||
# RUN: wasm-ld -m wasm32 --experimental-pic -shared --no-entry %t.lib.o -o %t.lib.so | ||
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s | ||
# RUN: wasm-ld -m wasm32 -Bdynamic %t.o %t.lib.so -o %t.wasm |
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.
Just to confirm, this effectively generates a non-PIC output? And ctx.isPic
not set?
I wonder if we can confirm this this test somehow? Perhaps its enough that we successfully use i32.const f_p
(which would not work if the output was PIC, right?) instead of i32.const f_p@MBREL
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.
ctx.isPic
is not set as neither of pie or shared is set.
the following is the generated output. it looks reasonable to me.
(module $dylink-non-pie.s.tmp.wasm
(type (;0;) (func (param f32) (result i32)))
(type (;1;) (func))
(import "env" "ret32" (func $ret32 (type 0)))
(import "GOT.func" "ret32" (global $ret32 (mut i32)))
(func $__wasm_apply_data_relocs (type 1)
i32.const 1024
global.get $ret32
i32.store)
(func $_start (type 1)
i32.const 1024
drop)
(table (;0;) 1 1 funcref)
(memory (;0;) 2)
(global $__stack_pointer (mut i32) (i32.const 66576))
(export "memory" (memory 0))
(export "_start" (func $_start))
(export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs))
(data $.data (i32.const 1024) "\00\00\00\00"))
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.
I wonder if we can confirm this this test somehow? Perhaps its enough that we successfully use i32.const f_p (which would not work if the output was PIC, right?) instead of i32.const f_p@MBREL
maybe we can confirm it doesn't have __memory_base/__table_base imports?
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.
done
@sbc100 do you have any more concerns? |
lld/test/wasm/dylink-non-pie.s
Outdated
.functype ret32 (f32) -> (i32) | ||
.functype _start () -> () | ||
.globl _start | ||
.type _start,@function |
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.
this line is not needed I think
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.
removed
lld/test/wasm/dylink-non-pie.s
Outdated
# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS | ||
|
||
.functype ret32 (f32) -> (i32) | ||
.functype _start () -> () |
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.
This line is not needed since its already on line 13
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.
removed
lld/test/wasm/dylink-non-pie.s
Outdated
end_function | ||
|
||
.section .data.f_p,"",@ | ||
.globl f_p |
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 this need to be global symbol? i.e. can you remove this line?
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.
it doesn't seem necessary. removed. thank you.
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.
lgtm % nits
can this land? |
The commit 22b7b84
made the symbols provided by shared libraries "defined",
and thus effectively made it impossible to generate non-pie
dynamically linked executables using --unresolved-symbols=import-dynamic.
This commit, based on #109249,
fixes it by checking sym->isShared() explictly.
(as a bonus, you don't need to rely on --unresolved-symbols=import-dynamic
anymore.)
Fixes #107387