diff --git a/lib/libc/musl/src/thread/aarch64/clone.s b/lib/libc/musl/src/thread/aarch64/clone.s index e3c83395cad25634fbd6597aef8f7dc2e74046d5..9ac272bde3e6199b65ed760378a65afa6824d780 100644 --- a/lib/libc/musl/src/thread/aarch64/clone.s +++ b/lib/libc/musl/src/thread/aarch64/clone.s @@ -24,7 +24,8 @@ __clone: // parent ret // child -1: ldp x1,x0,[sp],#16 +1: mov fp, 0 + ldp x1,x0,[sp],#16 blr x1 mov x8,#93 // SYS_exit svc #0 diff --git a/lib/libc/musl/src/thread/arm/clone.s b/lib/libc/musl/src/thread/arm/clone.s index bb0965dafe8298e652a5291dd443893153c748af..4ff0c0e88b1d8892f914fc3b1703a1bf8a13239a 100644 --- a/lib/libc/musl/src/thread/arm/clone.s +++ b/lib/libc/musl/src/thread/arm/clone.s @@ -19,7 +19,8 @@ __clone: ldmfd sp!,{r4,r5,r6,r7} bx lr -1: mov r0,r6 +1: mov fp,#0 + mov r0,r6 bl 3f 2: mov r7,#1 svc 0 diff --git a/lib/libc/musl/src/thread/i386/clone.s b/lib/libc/musl/src/thread/i386/clone.s index e237d3c6324b984601048c07d8b7976b6c6e601a..f89ddd9d5314d1b7bc28812c6008dd4abf72b5ef 100644 --- a/lib/libc/musl/src/thread/i386/clone.s +++ b/lib/libc/musl/src/thread/i386/clone.s @@ -30,20 +30,19 @@ __clone: mov 8(%ebp),%ebp int $128 test %eax,%eax - jnz 1f - - mov %ebp,%eax - xor %ebp,%ebp - call *%eax - mov %eax,%ebx - xor %eax,%eax - inc %eax - int $128 - hlt - -1: add $16,%esp + jz 1f + add $16,%esp pop %edi pop %esi pop %ebx pop %ebp ret + +1: mov %ebp,%eax + xor %ebp,%ebp + call *%eax + mov %eax,%ebx + xor %eax,%eax + inc %eax + int $128 + hlt diff --git a/lib/libc/musl/src/thread/loongarch64/clone.s b/lib/libc/musl/src/thread/loongarch64/clone.s index a165b365a38e43178b4bbf5d381075aa9ac48197..cb4aacfc6d8980332b6f0b3ff3f8788d12f1be8d 100644 --- a/lib/libc/musl/src/thread/loongarch64/clone.s +++ b/lib/libc/musl/src/thread/loongarch64/clone.s @@ -22,6 +22,7 @@ __clone: beqz $a0, 1f # whether child process jirl $zero, $ra, 0 # parent process return 1: + move $fp, $zero ld.d $t8, $sp, 0 # function pointer ld.d $a0, $sp, 8 # argument pointer jirl $ra, $t8, 0 # call the user's function diff --git a/lib/libc/musl/src/thread/m68k/clone.s b/lib/libc/musl/src/thread/m68k/clone.s index f6dfa06f49daef59a7e49b2e6525ec5e800fb5c5..42ec19f7242aa38170bdce518b3a59fa05f4d1b1 100644 --- a/lib/libc/musl/src/thread/m68k/clone.s +++ b/lib/libc/musl/src/thread/m68k/clone.s @@ -18,7 +18,8 @@ __clone: beq 1f movem.l (%sp)+,%d2-%d5 rts -1: move.l %a1,-(%sp) +1: suba.l %%fp,%%fp + move.l %a1,-(%sp) jsr (%a0) move.l #1,%d0 trap #0 diff --git a/lib/libc/musl/src/thread/microblaze/clone.s b/lib/libc/musl/src/thread/microblaze/clone.s index b68cc5fc22130c1ee6460192f49a0033d133c84c..64e3f0743f6ce2a1d00c5323e60d8e6916d59a28 100644 --- a/lib/libc/musl/src/thread/microblaze/clone.s +++ b/lib/libc/musl/src/thread/microblaze/clone.s @@ -22,7 +22,8 @@ __clone: rtsd r15, 8 nop -1: lwi r3, r1, 0 +1: add r19, r0, r0 + lwi r3, r1, 0 lwi r5, r1, 4 brald r15, r3 nop diff --git a/lib/libc/musl/src/thread/mips/clone.s b/lib/libc/musl/src/thread/mips/clone.s index 0446338568f0a8add741a32427a5b042fc1036b4..229b987e96919cc9f8ef806cd5a5833060f58b91 100644 --- a/lib/libc/musl/src/thread/mips/clone.s +++ b/lib/libc/musl/src/thread/mips/clone.s @@ -27,7 +27,8 @@ __clone: addu $sp, $sp, 16 jr $ra nop -1: lw $25, 0($sp) +1: move $fp, $0 + lw $25, 0($sp) lw $4, 4($sp) jalr $25 nop diff --git a/lib/libc/musl/src/thread/mips64/clone.s b/lib/libc/musl/src/thread/mips64/clone.s index 2d86899a1daa0c43991fb7e4ad07f929ad788d09..8de3db6c4e36dce0e3842bc6c1a3a26173027d3a 100644 --- a/lib/libc/musl/src/thread/mips64/clone.s +++ b/lib/libc/musl/src/thread/mips64/clone.s @@ -25,7 +25,8 @@ __clone: nop jr $ra nop -1: ld $25, 0($sp) # function pointer +1: move $fp, $0 + ld $25, 0($sp) # function pointer ld $4, 8($sp) # argument pointer jalr $25 # call the user's function nop diff --git a/lib/libc/musl/src/thread/mipsn32/clone.s b/lib/libc/musl/src/thread/mipsn32/clone.s index 4d3c8c7a2502e96a4eafa9b0eaf2534d4e23f59f..9571231a62cfe02806ba34879eef6c9ae569cbbe 100644 --- a/lib/libc/musl/src/thread/mipsn32/clone.s +++ b/lib/libc/musl/src/thread/mipsn32/clone.s @@ -25,7 +25,8 @@ __clone: nop jr $ra nop -1: lw $25, 0($sp) # function pointer +1: move $fp, $0 + lw $25, 0($sp) # function pointer lw $4, 4($sp) # argument pointer jalr $25 # call the user's function nop diff --git a/lib/libc/musl/src/thread/or1k/clone.s b/lib/libc/musl/src/thread/or1k/clone.s index 2473ac2040366733ca60059065a1520e7b367a1e..05c55c6982dc8742fa44b60e6cad635601d79b59 100644 --- a/lib/libc/musl/src/thread/or1k/clone.s +++ b/lib/libc/musl/src/thread/or1k/clone.s @@ -23,7 +23,8 @@ __clone: l.jr r9 l.nop -1: l.lwz r11, 0(r1) +1: l.ori r2, r0, 0 + l.lwz r11, 0(r1) l.jalr r11 l.lwz r3, 4(r1) diff --git a/lib/libc/musl/src/thread/powerpc/clone.s b/lib/libc/musl/src/thread/powerpc/clone.s index da13f446c03a3d134f7e0aa52c083e26ffa1c168..019fd62a95afc6e4cff64f0c5bce1e1d41ae33c8 100644 --- a/lib/libc/musl/src/thread/powerpc/clone.s +++ b/lib/libc/musl/src/thread/powerpc/clone.s @@ -48,9 +48,16 @@ neg 3, 3 #negate the result (errno) # compare sc result with 0 cmpwi cr7, 3, 0 -# if not 0, jump to end -bne cr7, 2f +# if not 0, restore stack and return +beq cr7, 2f +lwz 30, 0(1) +lwz 31, 4(1) +addi 1, 1, 16 + +blr + +2: #else: we're the child #call funcptr: move arg (d) into r3 mr 3, 31 @@ -61,13 +68,3 @@ bctrl # mov SYS_exit into r0 (the exit param is already in r3) li 0, 1 sc - -2: - -# restore stack -lwz 30, 0(1) -lwz 31, 4(1) -addi 1, 1, 16 - -blr - diff --git a/lib/libc/musl/src/thread/x32/clone.s b/lib/libc/musl/src/thread/x32/clone.s index b870880f93d4754f4b36e67affa388bb4784be6d..d713452676333d3e34ef9f004fcec4eebf2bcd6d 100644 --- a/lib/libc/musl/src/thread/x32/clone.s +++ b/lib/libc/musl/src/thread/x32/clone.s @@ -15,12 +15,12 @@ __clone: mov %rcx,(%rsi) syscall test %eax,%eax - jnz 1f - xor %ebp,%ebp + jz 1f + ret +1: xor %ebp,%ebp pop %rdi call *%r9 mov %eax,%edi movl $0x4000003c,%eax /* SYS_exit */ syscall hlt -1: ret diff --git a/lib/libc/musl/src/thread/x86_64/clone.s b/lib/libc/musl/src/thread/x86_64/clone.s index 6e47bc0a37dee7157ceaf1369659891a2d7d16bb..3c30220e507705fbc54617517445712917d36b13 100644 --- a/lib/libc/musl/src/thread/x86_64/clone.s +++ b/lib/libc/musl/src/thread/x86_64/clone.s @@ -16,8 +16,9 @@ __clone: mov %rcx,(%rsi) syscall test %eax,%eax - jnz 1f - xor %ebp,%ebp + jz 1f + ret +1: xor %ebp,%ebp pop %rdi call *%r9 mov %eax,%edi @@ -25,4 +26,3 @@ __clone: mov $60,%al syscall hlt -1: ret diff --git a/lib/std/Build.zig b/lib/std/Build.zig index 041de3e06f1b06472d412368cc458081048cf001..65e2db3d1d2b8672fd801fe55cdfea34a45e7ec8 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -706,7 +706,7 @@ pub const ExecutableOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -762,7 +762,7 @@ pub const ObjectOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -810,7 +810,7 @@ pub const SharedLibraryOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -867,7 +867,7 @@ pub const StaticLibraryOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, @@ -919,7 +919,7 @@ pub const TestOptions = struct { single_threaded: ?bool = null, pic: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, omit_frame_pointer: ?bool = null, sanitize_thread: ?bool = null, error_tracing: ?bool = null, diff --git a/lib/std/Build/Module.zig b/lib/std/Build/Module.zig index 347695a4c038a70640dad9ea42ba78895ce8d75e..0e421280f0958ca4bf7fa2fcc7d712f37869923a 100644 --- a/lib/std/Build/Module.zig +++ b/lib/std/Build/Module.zig @@ -22,7 +22,7 @@ frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions), link_objects: std.ArrayListUnmanaged(LinkObject), strip: ?bool, -unwind_tables: ?bool, +unwind_tables: ?std.builtin.UnwindTables, single_threaded: ?bool, stack_protector: ?bool, stack_check: ?bool, @@ -218,7 +218,7 @@ pub const CreateOptions = struct { link_libcpp: ?bool = null, single_threaded: ?bool = null, strip: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, dwarf_format: ?std.dwarf.Format = null, code_model: std.builtin.CodeModel = .default, stack_protector: ?bool = null, @@ -675,7 +675,6 @@ pub fn appendZigProcessFlags( const b = m.owner; try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip"); - try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables"); try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded"); try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check"); try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); @@ -695,6 +694,14 @@ pub fn appendZigProcessFlags( }); } + if (m.unwind_tables) |unwind_tables| { + try zig_args.append(switch (unwind_tables) { + .none => "-fno-unwind-tables", + .sync => "-funwind-tables", + .@"async" => "-fasync-unwind-tables", + }); + } + try zig_args.ensureUnusedCapacity(1); if (m.optimize) |optimize| switch (optimize) { .Debug => zig_args.appendAssumeCapacity("-ODebug"), diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 5ddde66a0a0a3c89a09b7278e2c44a32d3d8369e..eda7f0ff4f5e66e43a0319461968e720ce7b8a1e 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -804,6 +804,14 @@ pub const LinkMode = enum { dynamic, }; +/// This data structure is used by the Zig language code generation and +/// therefore must be kept in sync with the compiler implementation. +pub const UnwindTables = enum { + none, + sync, + @"async", +}; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const WasiExecModel = enum { diff --git a/lib/std/os/linux/aarch64.zig b/lib/std/os/linux/aarch64.zig index 9248360ae97dd2af673b8a2fca2046a3d5622eae..db304a3a33b43647245fbd70c2be3b8638f05ae6 100644 --- a/lib/std/os/linux/aarch64.zig +++ b/lib/std/os/linux/aarch64.zig @@ -120,8 +120,13 @@ pub fn clone() callconv(.Naked) usize { \\ cbz x0,1f \\ // parent \\ ret + \\ \\ // child - \\1: ldp x1,x0,[sp],#16 + \\1: .cfi_undefined lr + \\ mov fp, 0 + \\ mov lr, 0 + \\ + \\ ldp x1,x0,[sp],#16 \\ blr x1 \\ mov x8,#93 // SYS_exit \\ svc #0 diff --git a/lib/std/os/linux/arm.zig b/lib/std/os/linux/arm.zig index 1d22b8c3dba79e1c1b83f4af2fb682a19da0a399..e9263b5cea8523404d3d6b7c37222ff98ddb6935 100644 --- a/lib/std/os/linux/arm.zig +++ b/lib/std/os/linux/arm.zig @@ -120,11 +120,16 @@ pub fn clone() callconv(.Naked) usize { \\ ldmfd sp!,{r4,r5,r6,r7} \\ bx lr \\ - \\1: mov r0,r6 + \\ // https://github.com/llvm/llvm-project/issues/115891 + \\1: mov r7, #0 + \\ mov r11, #0 + \\ mov lr, #0 + \\ + \\ mov r0,r6 \\ bl 3f - \\2: mov r7,#1 // SYS_exit + \\ mov r7,#1 // SYS_exit \\ svc 0 - \\ b 2b + \\ \\3: bx r5 ); } diff --git a/lib/std/os/linux/hexagon.zig b/lib/std/os/linux/hexagon.zig index e9bf9ab57c4757daf873d3b5ec0376a0147f2d0b..0839ea8297a0906f045b3a9466d21c368520e814 100644 --- a/lib/std/os/linux/hexagon.zig +++ b/lib/std/os/linux/hexagon.zig @@ -118,6 +118,10 @@ pub fn clone() callconv(.Naked) usize { \\ p0 = cmp.eq(r0, #0) \\ if (!p0) dealloc_return \\ + \\ .cfi_undefined r31 + \\ r30 = #0 + \\ r31 = #0 + \\ \\ r0 = r10 \\ callr r11 \\ diff --git a/lib/std/os/linux/loongarch64.zig b/lib/std/os/linux/loongarch64.zig index def39154946298dc04577a3e7fd16bbcba5d7ef1..b52f1d10b137e625ab70e1dff12d5163214e28be 100644 --- a/lib/std/os/linux/loongarch64.zig +++ b/lib/std/os/linux/loongarch64.zig @@ -121,6 +121,10 @@ pub fn clone() callconv(.Naked) usize { \\ beqz $a0, 1f # whether child process \\ jirl $zero, $ra, 0 # parent process return \\1: + \\ .cfi_undefined 1 + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ ld.d $t8, $sp, 0 # function pointer \\ ld.d $a0, $sp, 8 # argument pointer \\ jirl $ra, $t8, 0 # call the user's function diff --git a/lib/std/os/linux/mips.zig b/lib/std/os/linux/mips.zig index e6cb5f7900252d8a188c80a0a233545ad329bbf4..5d786ccde7f652a40e7d17614b1e088fb5ef86c3 100644 --- a/lib/std/os/linux/mips.zig +++ b/lib/std/os/linux/mips.zig @@ -231,6 +231,10 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + \\ .cfi_undefined $ra + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ lw $25, 0($sp) \\ lw $4, 4($sp) \\ jalr $25 diff --git a/lib/std/os/linux/mips64.zig b/lib/std/os/linux/mips64.zig index 5e6661eae5cff36e8a0bc498c29dbfc7e448759b..256c911bbe58753219952b53a0cf78b3e35928ad 100644 --- a/lib/std/os/linux/mips64.zig +++ b/lib/std/os/linux/mips64.zig @@ -210,6 +210,10 @@ pub fn clone() callconv(.Naked) usize { \\ jr $ra \\ nop \\1: + \\ .cfi_undefined $ra + \\ move $fp, $zero + \\ move $ra, $zero + \\ \\ ld $25, 0($sp) \\ ld $4, 8($sp) \\ jalr $25 diff --git a/lib/std/os/linux/powerpc.zig b/lib/std/os/linux/powerpc.zig index 7b56b94823cd1f8adf6d268edbfc3c8f057e84d4..9dde326e1b043d68db1c500c8494f93c50b102c5 100644 --- a/lib/std/os/linux/powerpc.zig +++ b/lib/std/os/linux/powerpc.zig @@ -133,14 +133,14 @@ pub fn clone() callconv(.Naked) usize { // syscall(SYS_clone, flags, stack, ptid, tls, ctid) // 0 3, 4, 5, 6, 7 asm volatile ( - \\ # store non-volatile regs r30, r31 on stack in order to put our + \\ # store non-volatile regs r29, r30 on stack in order to put our \\ # start func and its arg there - \\ stwu 30, -16(1) - \\ stw 31, 4(1) + \\ stwu 29, -16(1) + \\ stw 30, 4(1) \\ - \\ # save r3 (func) into r30, and r6(arg) into r31 - \\ mr 30, 3 - \\ mr 31, 6 + \\ # save r3 (func) into r29, and r6(arg) into r30 + \\ mr 29, 3 + \\ mr 30, 6 \\ \\ # create initial stack frame for new thread \\ clrrwi 4, 4, 4 @@ -167,28 +167,28 @@ pub fn clone() callconv(.Naked) usize { \\ # compare sc result with 0 \\ cmpwi cr7, 3, 0 \\ - \\ # if not 0, jump to end - \\ bne cr7, 2f + \\ # if not 0, restore stack and return + \\ beq cr7, 2f + \\ lwz 29, 0(1) + \\ lwz 30, 4(1) + \\ addi 1, 1, 16 + \\ blr \\ \\ #else: we're the child + \\ 2: + \\ .cfi_undefined lr + \\ li 31, 0 + \\ mtlr 0 + \\ \\ #call funcptr: move arg (d) into r3 - \\ mr 3, 31 - \\ #move r30 (funcptr) into CTR reg - \\ mtctr 30 + \\ mr 3, 30 + \\ #move r29 (funcptr) into CTR reg + \\ mtctr 29 \\ # call CTR reg \\ bctrl \\ # mov SYS_exit into r0 (the exit param is already in r3) \\ li 0, 1 \\ sc - \\ - \\ 2: - \\ - \\ # restore stack - \\ lwz 30, 0(1) - \\ lwz 31, 4(1) - \\ addi 1, 1, 16 - \\ - \\ blr ); } diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig index 06b67c17f16379325f97ef896bc457a1e46f5591..6a1f98a65fba318c6741fec91c88f88267f5ad8e 100644 --- a/lib/std/os/linux/powerpc64.zig +++ b/lib/std/os/linux/powerpc64.zig @@ -160,7 +160,12 @@ pub fn clone() callconv(.Naked) usize { \\ cmpwi cr7, 3, 0 \\ bnelr cr7 \\ - \\ # we're the child. call fn(arg) + \\ # we're the child + \\ .cfi_undefined lr + \\ li 31, 0 + \\ mtlr 0 + \\ + \\ # call fn(arg) \\ ld 3, 16(1) \\ ld 12, 8(1) \\ mtctr 12 diff --git a/lib/std/os/linux/riscv32.zig b/lib/std/os/linux/riscv32.zig index 457d7e50b4b445a0bf433d4007f067b8e5afa2d4..dc444a19560bd09762b12a71291bff27bd0c4cba 100644 --- a/lib/std/os/linux/riscv32.zig +++ b/lib/std/os/linux/riscv32.zig @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: lw a1, 0(sp) + \\1: .cfi_undefined ra + \\ mv fp, zero + \\ mv ra, zero + \\ + \\ lw a1, 0(sp) \\ lw a0, 4(sp) \\ jalr a1 \\ diff --git a/lib/std/os/linux/riscv64.zig b/lib/std/os/linux/riscv64.zig index e33169c5b115b63cfed8733d2b9a18a84d078702..45ba568c1bf985f6a11d3afb24c4f967abb1e50a 100644 --- a/lib/std/os/linux/riscv64.zig +++ b/lib/std/os/linux/riscv64.zig @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { \\ ret \\ \\ # Child - \\1: ld a1, 0(sp) + \\1: .cfi_undefined ra + \\ mv fp, zero + \\ mv ra, zero + \\ + \\ ld a1, 0(sp) \\ ld a0, 8(sp) \\ jalr a1 \\ diff --git a/lib/std/os/linux/s390x.zig b/lib/std/os/linux/s390x.zig index efc48af4ff396ad80e0d37b9d8d4767e21ff6fd0..8fbe1c930b3b523089a380448093b6fab84ea892 100644 --- a/lib/std/os/linux/s390x.zig +++ b/lib/std/os/linux/s390x.zig @@ -133,7 +133,12 @@ pub fn clone() callconv(.Naked) usize { \\ltgr %%r2, %%r2 \\bnzr %%r14 \\ - \\# we're the child. call fn(arg) + \\# we're the child + \\.cfi_undefined %%r14 + \\lghi %%r11, 0 + \\lghi %%r14, 0 + \\ + \\# call fn(arg) \\lg %%r1, 8(%%r15) \\lg %%r2, 16(%%r15) \\basr %%r14, %%r1 diff --git a/lib/std/os/linux/sparc64.zig b/lib/std/os/linux/sparc64.zig index c146ed17cf2a0d41fdfc071ee050828e932bca69..d81e6fb40a7894d94a2817d5d8e94f43b0d7603c 100644 --- a/lib/std/os/linux/sparc64.zig +++ b/lib/std/os/linux/sparc64.zig @@ -198,29 +198,34 @@ pub fn clone() callconv(.Naked) usize { \\ mov %%i5, %%o3 \\ ldx [%%fp + 0x8af], %%o4 \\ t 0x6d - \\ bcs,pn %%xcc, 2f + \\ bcs,pn %%xcc, 1f \\ nop \\ # The child pid is returned in o0 while o1 tells if this \\ # process is # the child (=1) or the parent (=0). - \\ brnz %%o1, 1f + \\ brnz %%o1, 2f \\ nop \\ # Parent process, return the child pid \\ mov %%o0, %%i0 \\ ret \\ restore \\1: - \\ # Child process, call func(arg) + \\ # The syscall failed + \\ sub %%g0, %%o0, %%i0 + \\ ret + \\ restore + \\2: + \\ # Child process + \\ .cfi_undefined %%i7 + \\ mov %%g0, %%fp + \\ mov %%g0, %%i7 + \\ + \\ # call func(arg) \\ mov %%g0, %%fp \\ call %%g2 \\ mov %%g3, %%o0 \\ # Exit \\ mov 1, %%g1 // SYS_exit \\ t 0x6d - \\2: - \\ # The syscall failed - \\ sub %%g0, %%o0, %%i0 - \\ ret - \\ restore ); } diff --git a/lib/std/os/linux/x86.zig b/lib/std/os/linux/x86.zig index abcfb99b37777f7a06cab6830013f7321dbe95f5..cb746e52a8dc8af51e866a3b740f1572428af6dd 100644 --- a/lib/std/os/linux/x86.zig +++ b/lib/std/os/linux/x86.zig @@ -148,19 +148,22 @@ pub fn clone() callconv(.Naked) usize { \\ movl $120,%%eax // SYS_clone \\ int $128 \\ testl %%eax,%%eax - \\ jnz 1f - \\ popl %%eax - \\ xorl %%ebp,%%ebp - \\ calll *%%eax - \\ movl %%eax,%%ebx - \\ movl $1,%%eax // SYS_exit - \\ int $128 - \\1: + \\ jz 1f \\ popl %%edi \\ popl %%esi \\ popl %%ebx \\ popl %%ebp \\ retl + \\ + \\1: + \\ .cfi_undefined %%eip + \\ xorl %%ebp,%%ebp + \\ + \\ popl %%eax + \\ calll *%%eax + \\ movl %%eax,%%ebx + \\ movl $1,%%eax // SYS_exit + \\ int $128 ); } diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index cef15105eee77a920a092866d054bf521e8cd9c9..44a37345f0f46e8d441418f63c7bdb13c4ce9dc5 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -116,8 +116,10 @@ pub fn clone() callconv(.Naked) usize { \\ testq %%rax,%%rax \\ jz 1f \\ retq + \\ \\1: .cfi_undefined %%rip \\ xorl %%ebp,%%ebp + \\ \\ popq %%rdi \\ callq *%%r9 \\ movl %%eax,%%edi diff --git a/lib/std/start.zig b/lib/std/start.zig index 0ded8ea625432513b9831e4206d0d7be59cc8a9c..9da0cb2ec61b3b36bf9513ef1fc69f4c0623c211 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -230,6 +230,29 @@ fn _start() callconv(.naked) noreturn { ); } + // This is the first userspace frame. Prevent DWARF-based unwinders from unwinding further. We + // prevent FP-based unwinders from unwinding further by zeroing the register further below. + asm volatile (switch (native_arch) { + .arc => ".cfi_undefined blink", + .arm, .armeb, .thumb, .thumbeb => "", // https://github.com/llvm/llvm-project/issues/115891 + .aarch64, .aarch64_be => ".cfi_undefined lr", + .csky => ".cfi_undefined lr", + .hexagon => ".cfi_undefined r31", + .loongarch32, .loongarch64 => ".cfi_undefined 1", + .m68k => ".cfi_undefined pc", + .mips, .mipsel, .mips64, .mips64el => ".cfi_undefined $ra", + .powerpc, .powerpcle, .powerpc64, .powerpc64le => ".cfi_undefined lr", + .riscv32, .riscv64 => if (builtin.zig_backend == .stage2_riscv64) + "" + else + ".cfi_undefined ra", + .s390x => ".cfi_undefined %%r14", + .sparc, .sparc64 => ".cfi_undefined %%i7", + .x86 => ".cfi_undefined %%eip", + .x86_64 => ".cfi_undefined %%rip", + else => @compileError("unsupported arch"), + }); + // Move this to the riscv prong below when this is resolved: https://github.com/ziglang/zig/issues/20918 if (builtin.cpu.arch.isRISCV() and builtin.zig_backend != .stage2_riscv64) asm volatile ( \\ .weak __global_pointer$ @@ -247,7 +270,6 @@ fn _start() callconv(.naked) noreturn { // linker explicitly. asm volatile (switch (native_arch) { .x86_64 => - \\ .cfi_undefined %%rip \\ xorl %%ebp, %%ebp \\ movq %%rsp, %%rdi \\ andq $-16, %%rsp @@ -279,8 +301,10 @@ fn _start() callconv(.naked) noreturn { , .arm, .armeb, .thumb, .thumbeb => // Note that this code must work for Thumb-1. + // r7 = FP (local), r11 = FP (unwind) \\ movs v1, #0 - \\ mov fp, v1 + \\ mov r7, v1 + \\ mov r11, v1 \\ mov lr, v1 \\ mov a1, sp \\ subs v1, #16 @@ -290,20 +314,23 @@ fn _start() callconv(.naked) noreturn { , .csky => // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for - // position-independent code to work. We depend on this in `std.os.linux.start_pie` - // to locate `_DYNAMIC` as well. + // position-independent code to work. We depend on this in `std.os.linux.pie` to locate + // `_DYNAMIC` as well. + // r8 = FP \\ grs t0, 1f \\ 1: \\ lrw gb, 1b@GOTPC \\ addu gb, t0 + \\ movi r8, 0 \\ movi lr, 0 \\ mov a0, sp \\ andi sp, sp, -8 \\ jmpi %[posixCallMainAndExit] , .hexagon => - // r29 = SP, r30 = FP + // r29 = SP, r30 = FP, r31 = LR \\ r30 = #0 + \\ r31 = #0 \\ r0 = r29 \\ r29 = and(r29, #-16) \\ memw(r29 + #-8) = r29 @@ -312,12 +339,13 @@ fn _start() callconv(.naked) noreturn { , .loongarch32, .loongarch64 => \\ move $fp, $zero + \\ move $ra, $zero \\ move $a0, $sp \\ bstrins.d $sp, $zero, 3, 0 \\ b %[posixCallMainAndExit] , .riscv32, .riscv64 => - \\ li s0, 0 + \\ li fp, 0 \\ li ra, 0 \\ mv a0, sp \\ andi sp, sp, -16 @@ -371,28 +399,35 @@ fn _start() callconv(.naked) noreturn { , .powerpc, .powerpcle => // Set up the initial stack frame, and clear the back chain pointer. + // r1 = SP, r31 = FP \\ mr 3, 1 \\ clrrwi 1, 1, 4 \\ li 0, 0 \\ stwu 1, -16(1) \\ stw 0, 0(1) + \\ li 31, 0 \\ mtlr 0 \\ b %[posixCallMainAndExit] , .powerpc64, .powerpc64le => // Set up the ToC and initial stack frame, and clear the back chain pointer. + // r1 = SP, r2 = ToC, r31 = FP \\ addis 2, 12, .TOC. - %[_start]@ha \\ addi 2, 2, .TOC. - %[_start]@l \\ mr 3, 1 \\ clrrdi 1, 1, 4 \\ li 0, 0 \\ stdu 0, -32(1) + \\ li 31, 0 \\ mtlr 0 \\ b %[posixCallMainAndExit] \\ nop , .s390x => // Set up the stack frame (register save area and cleared back-chain slot). + // r11 = FP, r14 = LR, r15 = SP + \\ lghi %%r11, 0 + \\ lghi %%r14, 0 \\ lgr %%r2, %%r15 \\ lghi %%r0, -16 \\ ngr %%r15, %%r0 @@ -403,7 +438,9 @@ fn _start() callconv(.naked) noreturn { , .sparc => // argc is stored after a register window (16 registers * 4 bytes). + // i7 = LR \\ mov %%g0, %%fp + \\ mov %%g0, %%i7 \\ add %%sp, 64, %%o0 \\ and %%sp, -8, %%sp \\ ba,a %[posixCallMainAndExit] @@ -411,7 +448,9 @@ fn _start() callconv(.naked) noreturn { .sparc64 => // argc is stored after a register window (16 registers * 8 bytes) plus the stack bias // (2047 bytes). + // i7 = LR \\ mov %%g0, %%fp + \\ mov %%g0, %%i7 \\ add %%sp, 2175, %%o0 \\ add %%sp, 2047, %%sp \\ and %%sp, -16, %%sp diff --git a/src/Builtin.zig b/src/Builtin.zig index 8dc5b31c163967d473b8613eadf34497ba581c7f..1782527f699b511f88d4621e8032b7fd4c87170a 100644 --- a/src/Builtin.zig +++ b/src/Builtin.zig @@ -2,6 +2,7 @@ target: std.Target, zig_backend: std.builtin.CompilerBackend, output_mode: std.builtin.OutputMode, link_mode: std.builtin.LinkMode, +unwind_tables: std.builtin.UnwindTables, is_test: bool, single_threaded: bool, link_libc: bool, @@ -40,6 +41,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { \\ \\pub const output_mode: std.builtin.OutputMode = .{p_}; \\pub const link_mode: std.builtin.LinkMode = .{p_}; + \\pub const unwind_tables: std.builtin.UnwindTables = .{p_}; \\pub const is_test = {}; \\pub const single_threaded = {}; \\pub const abi: std.Target.Abi = .{p_}; @@ -53,6 +55,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { std.zig.fmtId(@tagName(zig_backend)), std.zig.fmtId(@tagName(opts.output_mode)), std.zig.fmtId(@tagName(opts.link_mode)), + std.zig.fmtId(@tagName(opts.unwind_tables)), opts.is_test, opts.single_threaded, std.zig.fmtId(@tagName(target.abi)), diff --git a/src/Compilation.zig b/src/Compilation.zig index 5f4404ff99c6b0cac22e52f3710ed08f6abde922..947012e716b6e2de459e3adc9e3b22bcfb724e32 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1261,12 +1261,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil // The "any" values provided by resolved config only account for // explicitly-provided settings. We now make them additionally account // for default setting resolution. - const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables; + const any_unwind_tables = switch (options.config.any_unwind_tables) { + .none => options.root_mod.unwind_tables, + .sync, .@"async" => |uwt| uwt, + }; const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; - const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables; + const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables != .none; const build_id = options.build_id orelse .none; const link_libc = options.config.link_libc; @@ -1354,6 +1357,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil cache.hash.add(options.config.pie); cache.hash.add(options.config.lto); cache.hash.add(options.config.link_mode); + cache.hash.add(options.config.any_unwind_tables); cache.hash.add(options.function_sections); cache.hash.add(options.data_sections); cache.hash.add(link_libc); @@ -5553,10 +5557,17 @@ pub fn addCCArgs( try argv.append("-Werror=date-time"); } - if (mod.unwind_tables) { - try argv.append("-funwind-tables"); - } else { - try argv.append("-fno-unwind-tables"); + switch (mod.unwind_tables) { + .none => { + try argv.append("-fno-unwind-tables"); + try argv.append("-fno-asynchronous-unwind-tables"); + }, + .sync => { + // Need to override Clang's convoluted default logic. + try argv.append("-fno-asynchronous-unwind-tables"); + try argv.append("-funwind-tables"); + }, + .@"async" => try argv.append("-fasynchronous-unwind-tables"), } }, .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {}, @@ -6288,6 +6299,7 @@ pub const CrtFileOptions = struct { function_sections: ?bool = null, data_sections: ?bool = null, omit_frame_pointer: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, pic: ?bool = null, no_builtin: ?bool = null, }; @@ -6349,7 +6361,8 @@ pub fn build_crt_file( // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer, .valgrind = false, - .unwind_tables = false, + // Some libcs (e.g. MinGW) are opinionated about -funwind-tables. + .unwind_tables = options.unwind_tables orelse .none, // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. .pic = options.pic orelse comp.root_mod.pic, .optimize_mode = comp.compilerRtOptMode(), diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 4458d474bbf03d4aeb7c1aa02352f5f0bd2ac8e8..baaa6c9f4741bddd893c60327fc0c6edd5eda037 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -12,13 +12,14 @@ link_libunwind: bool, /// True if and only if the c_source_files field will have nonzero length when /// calling Compilation.create. any_c_source_files: bool, -/// This is true if any Module has unwind_tables set explicitly to true. Until -/// Compilation.create is called, it is possible for this to be false while in -/// fact all Module instances have unwind_tables=true due to the default -/// being unwind_tables=true. After Compilation.create is called this will -/// also take into account the default setting, making this value true if and -/// only if any Module has unwind_tables set to true. -any_unwind_tables: bool, +/// This is not `.none` if any `Module` has `unwind_tables` set explicitly to a +/// value other than `.none`. Until `Compilation.create()` is called, it is +/// possible for this to be `.none` while in fact all `Module` instances have +/// `unwind_tables != .none` due to the default. After `Compilation.create()` is +/// called, this will also take into account the default setting, making this +/// value `.sync` or `.@"async"` if and only if any `Module` has +/// `unwind_tables != .none`. +any_unwind_tables: std.builtin.UnwindTables, /// This is true if any Module has single_threaded set explicitly to false. Until /// Compilation.create is called, it is possible for this to be false while in /// fact all Module instances have single_threaded=false due to the default @@ -85,7 +86,7 @@ pub const Options = struct { any_non_single_threaded: bool = false, any_sanitize_thread: bool = false, any_fuzz: bool = false, - any_unwind_tables: bool = false, + any_unwind_tables: std.builtin.UnwindTables = .none, any_dyn_libs: bool = false, any_c_source_files: bool = false, any_non_stripped: bool = false, @@ -356,8 +357,11 @@ pub fn resolve(options: Options) ResolveError!Config { break :b false; }; - const any_unwind_tables = options.any_unwind_tables or - link_libunwind or target_util.needUnwindTables(target); + const any_unwind_tables = b: { + if (options.any_unwind_tables != .none) break :b options.any_unwind_tables; + + break :b target_util.needUnwindTables(target, link_libunwind, options.any_sanitize_thread); + }; const link_mode = b: { const explicitly_exe_or_dyn_lib = switch (options.output_mode) { diff --git a/src/Package/Module.zig b/src/Package/Module.zig index 781a8e50c25dcdf44fd6b4b900b94c18a499de4b..bfcef038edb757e2f757fe3d8b1dd2c18e80b73f 100644 --- a/src/Package/Module.zig +++ b/src/Package/Module.zig @@ -27,7 +27,7 @@ red_zone: bool, sanitize_c: bool, sanitize_thread: bool, fuzz: bool, -unwind_tables: bool, +unwind_tables: std.builtin.UnwindTables, cc_argv: []const []const u8, /// (SPIR-V) whether to generate a structured control flow graph or not structured_cfg: bool, @@ -91,7 +91,7 @@ pub const CreateOptions = struct { /// other number means stack protection with that buffer size. stack_protector: ?u32 = null, red_zone: ?bool = null, - unwind_tables: ?bool = null, + unwind_tables: ?std.builtin.UnwindTables = null, sanitize_c: ?bool = null, sanitize_thread: ?bool = null, fuzz: ?bool = null, @@ -112,7 +112,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread); if (options.inherited.fuzz == true) assert(options.global.any_fuzz); if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); - if (options.inherited.unwind_tables == true) assert(options.global.any_unwind_tables); + if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables != .none); if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); const resolved_target = options.inherited.resolved_target orelse options.parent.?.resolved_target; @@ -382,6 +382,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { .zig_backend = zig_backend, .output_mode = options.global.output_mode, .link_mode = options.global.link_mode, + .unwind_tables = options.global.any_unwind_tables, .is_test = options.global.is_test, .single_threaded = single_threaded, .link_libc = options.global.link_libc, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index 29a0a8b8b5b4e36e9f39890a0f0117620b4536ea..a836d02d711dac58bb9e78892d165268dcb597e0 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -8442,6 +8442,10 @@ fn failSymbol(func: *Func, comptime format: []const u8, args: anytype) InnerErro } fn parseRegName(name: []const u8) ?Register { + // The `fp` alias for `s0` is awkward to fit into the current `Register` scheme, so for now we + // special-case it here. + if (std.mem.eql(u8, name, "fp")) return .s0; + return std.meta.stringToEnum(Register, name); } diff --git a/src/clang_options_data.zig b/src/clang_options_data.zig index 9ced7e9ebe2137df5d8d1150c79f44f7e368d5c8..88cf41d0d4ff0b145f8ea05db79da08429c9642b 100644 --- a/src/clang_options_data.zig +++ b/src/clang_options_data.zig @@ -2757,7 +2757,14 @@ flagpd1("fast"), flagpd1("fastcp"), flagpd1("fastf"), flagpd1("fasync-exceptions"), -flagpd1("fasynchronous-unwind-tables"), +.{ + .name = "fasynchronous-unwind-tables", + .syntax = .flag, + .zig_equivalent = .asynchronous_unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fauto-import"), flagpd1("fauto-profile"), flagpd1("fauto-profile-accurate"), @@ -3247,7 +3254,14 @@ flagpd1("fno-assume-sane-operator-new"), flagpd1("fno-assume-unique-vtables"), flagpd1("fno-assumptions"), flagpd1("fno-async-exceptions"), -flagpd1("fno-asynchronous-unwind-tables"), +.{ + .name = "fno-asynchronous-unwind-tables", + .syntax = .flag, + .zig_equivalent = .no_asynchronous_unwind_tables, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-auto-import"), flagpd1("fno-auto-profile"), flagpd1("fno-auto-profile-accurate"), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ff1e6798988000b8ae586f1f2a489897a611a79b..b94ea0799573879fdaa43b1e139e83d5acf14366 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3141,8 +3141,11 @@ pub const Object = struct { } }, &o.builder); } try attributes.addFnAttr(.nounwind, &o.builder); - if (owner_mod.unwind_tables) { - try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); + if (owner_mod.unwind_tables != .none) { + try attributes.addFnAttr( + .{ .uwtable = if (owner_mod.unwind_tables == .@"async") .@"async" else .sync }, + &o.builder, + ); } if (owner_mod.no_builtin) { // The intent here is for compiler-rt and libc functions to not generate diff --git a/src/libcxx.zig b/src/libcxx.zig index 39fd999112d04f97d98230848e3681b6450b52d3..6386d493a608cd88e97a2d177764b00a8f79ca44 100644 --- a/src/libcxx.zig +++ b/src/libcxx.zig @@ -397,7 +397,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); - const unwind_tables = true; const config = Compilation.Config.resolve(.{ .output_mode = output_mode, @@ -409,7 +408,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .root_optimize_mode = optimize_mode, .root_strip = strip, .link_libc = true, - .any_unwind_tables = unwind_tables, .lto = comp.config.lto, .any_sanitize_thread = comp.config.any_sanitize_thread, }) catch |err| { @@ -440,7 +438,12 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .valgrind = false, .optimize_mode = optimize_mode, .structured_cfg = comp.root_mod.structured_cfg, - .unwind_tables = unwind_tables, + // See the `-fno-exceptions` logic for WASI. + // The old 32-bit x86 variant of SEH doesn't use tables. + .unwind_tables = if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows)) + .none + else + .@"async", .pic = comp.root_mod.pic, }, .global = config, diff --git a/src/libunwind.zig b/src/libunwind.zig index 1e101da229f0167afe69cbbbbbebd2fc14a6fcc4..4b3583e1cde4a612dc3118f60d42dba764bf6f23 100644 --- a/src/libunwind.zig +++ b/src/libunwind.zig @@ -65,7 +65,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .sanitize_c = false, .sanitize_thread = false, // necessary so that libunwind can unwind through its own stack frames - .unwind_tables = true, + // The old 32-bit x86 variant of SEH doesn't use tables. + .unwind_tables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async", .pic = if (target_util.supports_fpic(target)) true else null, .optimize_mode = comp.compilerRtOptMode(), }, diff --git a/src/main.zig b/src/main.zig index 23c4d7507e450fab2de8de491d6384ff08b9d2fa..1f8bd8d06541b767a6b4150b32e3e0cab93673c1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -510,6 +510,7 @@ const usage_build_generic = \\ -ffuzz Enable fuzz testing instrumentation \\ -fno-fuzz Disable fuzz testing instrumentation \\ -funwind-tables Always produce unwind table entries for all functions + \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions \\ -fno-unwind-tables Never produce unwind table entries \\ -ferror-tracing Enable error tracing in ReleaseFast mode \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode @@ -1385,9 +1386,11 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-lto")) { create_module.opts.lto = false; } else if (mem.eql(u8, arg, "-funwind-tables")) { - mod_opts.unwind_tables = true; + mod_opts.unwind_tables = .sync; + } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) { + mod_opts.unwind_tables = .@"async"; } else if (mem.eql(u8, arg, "-fno-unwind-tables")) { - mod_opts.unwind_tables = false; + mod_opts.unwind_tables = .none; } else if (mem.eql(u8, arg, "-fstack-check")) { mod_opts.stack_check = true; } else if (mem.eql(u8, arg, "-fno-stack-check")) { @@ -1973,8 +1976,27 @@ fn buildOutputType( } }, .no_stack_protector => mod_opts.stack_protector = 0, - .unwind_tables => mod_opts.unwind_tables = true, - .no_unwind_tables => mod_opts.unwind_tables = false, + // The way these unwind table options are processed in GCC and Clang is crazy + // convoluted, and we also don't know the target triple here, so this is all + // best-effort. + .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => { + mod_opts.unwind_tables = .sync; + }, + .sync, .@"async" => {}, + } else { + mod_opts.unwind_tables = .sync; + }, + .no_unwind_tables => mod_opts.unwind_tables = .none, + .asynchronous_unwind_tables => mod_opts.unwind_tables = .@"async", + .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none, .sync => {}, + .@"async" => { + mod_opts.unwind_tables = .sync; + }, + } else { + mod_opts.unwind_tables = .sync; + }, .nostdlib => { create_module.opts.ensure_libc_on_non_freestanding = false; create_module.opts.ensure_libcpp_on_non_freestanding = false; @@ -2788,8 +2810,15 @@ fn buildOutputType( create_module.opts.any_sanitize_thread = true; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; - if (mod_opts.unwind_tables == true) - create_module.opts.any_unwind_tables = true; + if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => {}, + .sync => if (create_module.opts.any_unwind_tables == .none) { + create_module.opts.any_unwind_tables = .sync; + }, + .@"async" => { + create_module.opts.any_unwind_tables = .@"async"; + }, + }; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; if (mod_opts.error_tracing == true) @@ -5713,6 +5742,8 @@ pub const ClangArgIterator = struct { no_lto, unwind_tables, no_unwind_tables, + asynchronous_unwind_tables, + no_asynchronous_unwind_tables, nostdlib, nostdlib_cpp, shared, @@ -7435,8 +7466,15 @@ fn handleModArg( create_module.opts.any_sanitize_thread = true; if (mod_opts.fuzz == true) create_module.opts.any_fuzz = true; - if (mod_opts.unwind_tables == true) - create_module.opts.any_unwind_tables = true; + if (mod_opts.unwind_tables) |uwt| switch (uwt) { + .none => {}, + .sync => if (create_module.opts.any_unwind_tables == .none) { + create_module.opts.any_unwind_tables = .sync; + }, + .@"async" => { + create_module.opts.any_unwind_tables = .@"async"; + }, + }; if (mod_opts.strip == false) create_module.opts.any_non_stripped = true; if (mod_opts.error_tracing == true) diff --git a/src/mingw.zig b/src/mingw.zig index cdee9acb070b32188863126c4c6921636d853f0c..8473a7a93b235c1073eb5c6955b964352a641943 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -24,6 +24,10 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); + const target = comp.getTarget(); + + // The old 32-bit x86 variant of SEH doesn't use tables. + const unwind_tables: std.builtin.UnwindTables = if (target.cpu.arch != .x86) .@"async" else .none; switch (crt_file) { .crt2_o => { @@ -41,7 +45,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; - return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{}); + return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{ + .unwind_tables = unwind_tables, + }); }, .dllcrt2_o => { @@ -56,7 +62,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }, }; - return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{}); + return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{ + .unwind_tables = unwind_tables, + }); }, .mingw32_lib => { @@ -73,7 +81,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre .owner = undefined, }); } - const target = comp.getTarget(); if (target.cpu.arch == .x86 or target.cpu.arch == .x86_64) { for (mingw32_x86_src) |dep| { try c_source_files.append(.{ @@ -118,7 +125,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre } else { @panic("unsupported arch"); } - return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{}); + return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{ + .unwind_tables = unwind_tables, + }); }, } } diff --git a/src/target.zig b/src/target.zig index a1c9a1972482719f406a11a3979d6ee81fa9db16..37f2cd50da50566ff454dac72d6c7fda1763595a 100644 --- a/src/target.zig +++ b/src/target.zig @@ -4,6 +4,7 @@ const assert = std.debug.assert; const Type = @import("Type.zig"); const AddressSpace = std.builtin.AddressSpace; const Alignment = @import("InternPool.zig").Alignment; +const Compilation = @import("Compilation.zig"); const Feature = @import("Zcu.zig").Feature; pub const default_stack_protector_buffer_size = 4; @@ -408,8 +409,16 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool { }; } -pub fn needUnwindTables(target: std.Target) bool { - return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target); +pub fn needUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables { + if (target.os.tag == .windows) { + // The old 32-bit x86 variant of SEH doesn't use tables. + return if (target.cpu.arch != .x86) .@"async" else .none; + } + if (target.os.tag.isDarwin()) return .@"async"; + if (libunwind) return .@"async"; + if (libtsan) return .@"async"; + if (std.debug.Dwarf.abi.supportsUnwinding(target)) return .@"async"; + return .none; } pub fn defaultAddressSpace( diff --git a/test/standalone/stack_iterator/build.zig b/test/standalone/stack_iterator/build.zig index ac9a6769304c0c35b989e1bdc80210e253fff5e9..38f66edd9f606c3a80a367b0d41e959b1808dcf4 100644 --- a/test/standalone/stack_iterator/build.zig +++ b/test/standalone/stack_iterator/build.zig @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = if (target.result.isDarwin()) true else null, + .unwind_tables = if (target.result.isDarwin()) .@"async" else null, .omit_frame_pointer = false, }); @@ -46,7 +46,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = true, + .unwind_tables = .@"async", .omit_frame_pointer = true, }); @@ -85,7 +85,7 @@ pub fn build(b: *std.Build) void { .root_source_file = b.path("shared_lib_unwind.zig"), .target = target, .optimize = optimize, - .unwind_tables = if (target.result.isDarwin()) true else null, + .unwind_tables = if (target.result.isDarwin()) .@"async" else null, .omit_frame_pointer = true, }); diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 637c9a5eaff6d50f5177ea234e8a18746febab3f..9cc0ad90cd71cad892ffb64036c591c57b1ee1d4 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -110,6 +110,14 @@ const known_options = [_]KnownOpt{ .name = "fno-unwind-tables", .ident = "no_unwind_tables", }, + .{ + .name = "fasynchronous-unwind-tables", + .ident = "asynchronous_unwind_tables", + }, + .{ + .name = "fno-asynchronous-unwind-tables", + .ident = "no_asynchronous_unwind_tables", + }, .{ .name = "nolibc", .ident = "nostdlib",