llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.23k stars 11.65k forks source link

[WebAssembly] non-pie dynamic-linking executable seems broken (LLVM 19 regression) #107387

Open yamt opened 3 weeks ago

yamt commented 3 weeks ago

build the following test code as a non-pie dynamically-linked executable. llvm 19 produces non-working binary. llvm 18 worked fine. you can find the full test code and compiler/linker options in https://github.com/yamt/garbage/tree/master/c/shlib_2

void f(void);
void (*f_p)(void) = f;

void
_start(void)
{
                f_p();
}
spacetanuki% toywasm --dyld main
Error: [trap] uninitialized element (8): call_indirect (null funcref) 0
current pc 0000fd
frame[  0] funcpc 0000e2 (main:_start)
2024-09-05 20:43:42 (1725536622.157386000): [10fb06600] instance_execute_func failed with -1
2024-09-05 20:43:42 (1725536622.157883000): [10fb06600] invoke failed with -1
spacetanuki% 

note that llvm 19's __wasm_apply_data_relocs is empty.

llvm 19.1.0-rc4

(module $main
  (type (;0;) (func))
  (import "env" "f" (func $f (type 0)))
  (func $__wasm_apply_data_relocs (type 0))
  (func $_start (type 0)
    global.get $GOT.data.internal.__memory_base
    i32.const 1024
    i32.add
    i32.load
    call_indirect (type 0))
  (table (;0;) 1 funcref)
  (memory (;0;) 2)
  (global $__stack_pointer (mut i32) (i32.const 66576))
  (global $GOT.data.internal.__memory_base i32 (i32.const 0))
  (global (;2;) i32 (i32.const 66576))
  (global (;3;) i32 (i32.const 131072))
  (export "memory" (memory 0))
  (export "__stack_pointer" (global $__stack_pointer))
  (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs))
  (export "_start" (func $_start))
  (export "__indirect_function_table" (table 0))
  (export "__heap_base" (global 2))
  (export "__heap_end" (global 3))
  (data $.data (i32.const 1024) "\00\00\00\00"))

llvm 18.1.2

(module $main
  (type (;0;) (func))
  (import "env" "f" (func $f (type 0)))
  (import "GOT.func" "f" (global $f (mut i32)))
  (func $__wasm_apply_data_relocs (type 0)
    i32.const 1024
    global.get $f
    i32.store)
  (func $_start (type 0)
    global.get $GOT.data.internal.__memory_base
    i32.const 1024
    i32.add
    i32.load
    call_indirect (type 0))
  (table (;0;) 1 funcref)
  (memory (;0;) 2)
  (global $__stack_pointer (mut i32) (i32.const 66576))
  (global $GOT.data.internal.__memory_base i32 (i32.const 0))
  (global (;3;) i32 (i32.const 66576))
  (global (;4;) i32 (i32.const 131072))
  (export "memory" (memory 0))
  (export "__stack_pointer" (global $__stack_pointer))
  (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs))
  (export "_start" (func $_start))
  (export "__indirect_function_table" (table 0))
  (export "__heap_base" (global 3))
  (export "__heap_end" (global 4))
  (data $.data (i32.const 1024) "\00\00\00\00"))
yamt commented 3 weeks ago

i did a bisection. this has been broken since 22b7b84860d39da71964c9b329937f2ee1d875ba. @sbc100 any idea?

llvmbot commented 3 weeks ago

@llvm/issue-subscribers-lld-wasm

Author: YAMAMOTO Takashi (yamt)

build the following test code as a non-pie dynamically-linked executable. llvm 19 produces non-working binary. llvm 18 worked fine. you can find the full test code and compiler/linker options in https://github.com/yamt/garbage/tree/master/c/shlib_2 ```c void f(void); void (*f_p)(void) = f; void _start(void) { f_p(); } ``` ```shell spacetanuki% toywasm --dyld main Error: [trap] uninitialized element (8): call_indirect (null funcref) 0 current pc 0000fd frame[ 0] funcpc 0000e2 (main:_start) 2024-09-05 20:43:42 (1725536622.157386000): [10fb06600] instance_execute_func failed with -1 2024-09-05 20:43:42 (1725536622.157883000): [10fb06600] invoke failed with -1 spacetanuki% ``` note that llvm 19's __wasm_apply_data_relocs is empty. llvm 19.1.0-rc4 ``` (module $main (type (;0;) (func)) (import "env" "f" (func $f (type 0))) (func $__wasm_apply_data_relocs (type 0)) (func $_start (type 0) global.get $GOT.data.internal.__memory_base i32.const 1024 i32.add i32.load call_indirect (type 0)) (table (;0;) 1 funcref) (memory (;0;) 2) (global $__stack_pointer (mut i32) (i32.const 66576)) (global $GOT.data.internal.__memory_base i32 (i32.const 0)) (global (;2;) i32 (i32.const 66576)) (global (;3;) i32 (i32.const 131072)) (export "memory" (memory 0)) (export "__stack_pointer" (global $__stack_pointer)) (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) (export "_start" (func $_start)) (export "__indirect_function_table" (table 0)) (export "__heap_base" (global 2)) (export "__heap_end" (global 3)) (data $.data (i32.const 1024) "\00\00\00\00")) ``` llvm 18.1.2 ``` (module $main (type (;0;) (func)) (import "env" "f" (func $f (type 0))) (import "GOT.func" "f" (global $f (mut i32))) (func $__wasm_apply_data_relocs (type 0) i32.const 1024 global.get $f i32.store) (func $_start (type 0) global.get $GOT.data.internal.__memory_base i32.const 1024 i32.add i32.load call_indirect (type 0)) (table (;0;) 1 funcref) (memory (;0;) 2) (global $__stack_pointer (mut i32) (i32.const 66576)) (global $GOT.data.internal.__memory_base i32 (i32.const 0)) (global (;3;) i32 (i32.const 66576)) (global (;4;) i32 (i32.const 131072)) (export "memory" (memory 0)) (export "__stack_pointer" (global $__stack_pointer)) (export "__wasm_apply_data_relocs" (func $__wasm_apply_data_relocs)) (export "_start" (func $_start)) (export "__indirect_function_table" (table 0)) (export "__heap_base" (global 3)) (export "__heap_end" (global 4)) (data $.data (i32.const 1024) "\00\00\00\00")) ```
sbc100 commented 3 weeks ago

I wasn't aware that non-PIE dynamic executables were something that was working. I had hoped to get it working since emscripten could benefit from this I think, but its not something that emscripten currently uses, which is the biggest user of dynamic linking today (IIUC). So I guess I'm not surprised that this use case broke, but we should certainly fix it, and improve the tests in this area.