Skip to content
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

Module level, inline assembly for wasm segfaults. #13129

Open
gcoakes opened this issue Oct 11, 2022 · 6 comments
Open

Module level, inline assembly for wasm segfaults. #13129

gcoakes opened this issue Oct 11, 2022 · 6 comments
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-llvm The LLVM backend outputs an LLVM IR Module. bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Milestone

Comments

@gcoakes
Copy link
Contributor

gcoakes commented Oct 11, 2022

Zig Version

0.10.0-dev.4254+7f508480f

Steps to Reproduce

main.zig:

comptime {
    asm (
        \\.globl wasm_nop
        \\wasm_nop:
        \\  .functype wasm_nop () -> ()
        \\  nop
        \\  end_function
    );
}

Compile:

$ zig build-lib -dynamic -target wasm32-freestanding main.zig
LLVM Emit Object... Segmentation fault at address 0x0
???:?:?: 0x7f2d2771d249 in ??? (???)
???:?:?: 0x72732f73656b616e in ??? (???)
fish: Job 1, 'zig build-lib -dynamic -target…' terminated by signal SIGABRT (Abort)

Expected Behavior

A wasm file at least containing:

(module (func $wasm_nop nop))

Actual Behavior

$ zig build-lib -dynamic -target wasm32-freestanding main.zig
LLVM Emit Object... Segmentation fault at address 0x0
???:?:?: 0x7f2d2771d249 in ??? (???)
???:?:?: 0x72732f73656b616e in ??? (???)
fish: Job 1, 'zig build-lib -dynamic -target…' terminated by signal SIGABRT (Abort)
@gcoakes gcoakes added the bug Observed behavior contradicts documented or intended behavior label Oct 11, 2022
@nektro
Copy link
Contributor

nektro commented Oct 11, 2022

export fn wasm_nop() void {}

this is the way to do that. using asm inside a comptime block is illegal. however, this issue should stay open because that should be a compiler error not a compiler panic

@Luukdegram Luukdegram added frontend Tokenization, parsing, AstGen, Sema, and Liveness. arch-wasm 32-bit and 64-bit WebAssembly backend-llvm The LLVM backend outputs an LLVM IR Module. labels Oct 11, 2022
@Luukdegram Luukdegram added this to the 0.11.0 milestone Oct 11, 2022
@gcoakes
Copy link
Contributor Author

gcoakes commented Oct 11, 2022

using asm inside a comptime block is illegal

I don't think this is generally correct. There are behavior tests for this, and #256 added support for it. Are you saying it's just not legal for WASM?

Also, my use case is not strictly the minimal example I gave. I want to be able to define wrapper functions (a la wasm-bindgen) with parameters which are not expressible in zig (#10491).

@Luukdegram
Copy link
Member

Luukdegram commented Oct 11, 2022

The code in the OP is perfectly valid. The segfault occurs in LLVM when we try to generate a binary. This smells like an issue upstream, but that requires some extra research. Here's a stack trace of the segfault which I'll update once I have the time to compile a debug version of LLVM:

LLVM Emit Object... Segmentation fault at address 0x6c2f73726573552f
???:?:?: 0x19baef104 in ??? (???)
???:?:?: 0x10334fa5f in _f128M_roundToInt (???)
???:?:?: 0x10334e1cf in _f128M_roundToInt (???)
???:?:?: 0x102f3f11f in __ZN4llvm16cast_convert_valIN5clang16EnumConstantDeclEPNS1_4DeclES4_E4doitEPKS3_ (???)
???:?:?: 0x1032c3833 in _f128M_roundToInt (???)
???:?:?: 0x102c9d523 in __ZN4llvm16cast_convert_valIN5clang16EnumConstantDeclEPNS1_4DeclES4_E4doitEPKS3_ (???)
???:?:?: 0x102c9801f in __ZN4llvm16cast_convert_valIN5clang16EnumConstantDeclEPNS1_4DeclES4_E4doitEPKS3_ (???)
???:?:?: 0x1023b6faf in _ZigLLVMTargetMachineEmitToFile (???)
/Users/luuk/dev/zig-dev/src/codegen/llvm.zig:795:43: 0x100da4803 in flushModule (zig)
        if (self.target_machine.emitToFile(
                                          ^
/Users/luuk/dev/zig-dev/src/link/Wasm.zig:2116:47: 0x100db4737 in flushModule (zig)
            return try llvm_object.flushModule(comp, prog_node);
                                              ^
/Users/luuk/dev/zig-dev/src/link/Wasm.zig:2872:29: 0x100daea97 in linkWithLLD (zig)
        try wasm.flushModule(comp, prog_node);
                            ^
/Users/luuk/dev/zig-dev/src/link/Wasm.zig:2104:32: 0x100da0e23 in flush (zig)
        return wasm.linkWithLLD(comp, prog_node);
                               ^
/Users/luuk/dev/zig-dev/src/link.zig:658:70: 0x100d9dde3 in flush (zig)
            .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp, prog_node),
                                                                     ^
/Users/luuk/dev/zig-dev/src/Compilation.zig:2440:24: 0x100f1a833 in flush (zig)
    comp.bin_file.flush(comp, prog_node) catch |err| switch (err) {
                       ^
/Users/luuk/dev/zig-dev/src/Compilation.zig:2421:23: 0x100f1c86f in update (zig)
        try comp.flush(main_progress_node);
                      ^
/Users/luuk/dev/zig-dev/src/main.zig:3383:20: 0x100f42dbb in updateModule (zig)
    try comp.update();
                   ^
/Users/luuk/dev/zig-dev/src/main.zig:3068:17: 0x100cd5e0b in buildOutputType (zig)
    updateModule(gpa, comp, hook) catch |err| switch (err) {
                ^
/Users/luuk/dev/zig-dev/src/main.zig:234:31: 0x100cb319b in mainArgs (zig)
        return buildOutputType(gpa, arena, args, .{ .build = .Obj });
                              ^
/Users/luuk/dev/zig-dev/src/stage1.zig:48:24: 0x100f8f217 in main (zig)
        stage2.mainArgs(gpa, arena, args) catch unreachable;

We can verify the correctness of the assembly using the following steps:

  • Generate assembly from the code using:
zig build-obj test.zig -target wasm32-freestanding -fno-emit-bin -femit-asm=test.s
  • And then using LLVM's playground:
llvm-mc -filetype=obj -triple=wasm32-unknown-unknown test.s -o test.o
  • Generates a valid Wasm file:
> wasm-objdump test.o -x

test.wasm:	file format wasm 0x1

Section Details:

Type[1]:
 - type[0] () -> nil
Import[1]:
 - memory[0] pages: initial=0 <- env.__linear_memory
Function[1]:
 - func[0] sig=0 <wasm_nop>
Code[1]:
 - func[0] size=3 <wasm_nop>
Custom:
 - name: "linking"
  - symbol table [count=1]
   - 0: F <wasm_nop> func=0 [ binding=global vis=default ]
Custom:
 - name: "producers"

@gcoakes
Copy link
Contributor Author

gcoakes commented Oct 11, 2022

Slightly off topic, but I tried building the failing case using a debug build of LLVM as described in the wiki (which took ages). It produced identical output to my original report. @Luukdegram, was there something different you used to produce your stack trace?

@Luukdegram
Copy link
Member

Slightly off topic, but I tried building the failing case using a debug build of LLVM as described in the wiki (which took ages). It produced identical output to my original report. @Luukdegram, was there something different you used to produce your stack trace?

Did you also build a debug version of the Zig compiler and not only of LLVM?

@gcoakes
Copy link
Contributor Author

gcoakes commented Oct 12, 2022

It's not all module-level asm. Maybe something specific to defining a function there? The following compiles:

comptime {
    asm (
        \\.globl __refs
        \\.tabletype __refs, externref, 32
        \\__refs:
    );
}

export fn refsSize() usize {
    return asm volatile (
        \\table.size __refs
        \\local.set %[ret]
        : [ret] "=r" (-> usize),
    );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm 32-bit and 64-bit WebAssembly backend-llvm The LLVM backend outputs an LLVM IR Module. bug Observed behavior contradicts documented or intended behavior frontend Tokenization, parsing, AstGen, Sema, and Liveness.
Projects
None yet
Development

No branches or pull requests

4 participants