| author | |
| committer | |
| log | 130f7c2ed8e3358e24bb2fc7cca57f7a6f1f85c3 |
| tree | ebb88312b13fb8b1e67b852bcb0e42903ad11193 |
| parent | d48611ba67c7871cb348f28a01b89d8771170dd8 |
| parent | c666ebb1f8aac440a4d0d554e9f8aa836bf58060 |
| signature |
Better unwind table support + unwind protection in `_start()` and `clone()`45 files changed, 361 insertions(+), 138 deletions(-)
lib/libc/musl/src/thread/aarch64/clone.s+2-1| ... | ... | @@ -24,7 +24,8 @@ __clone: |
| 24 | 24 | 	// parent |
| 25 | 25 | 	ret |
| 26 | 26 | 	// child |
| 27 | 1:	ldp x1,x0,[sp],#16 | |
| 27 | 1:	mov fp, 0 | |
| 28 | 	ldp x1,x0,[sp],#16 | |
| 28 | 29 | 	blr x1 |
| 29 | 30 | 	mov x8,#93 // SYS_exit |
| 30 | 31 | 	svc #0 |
lib/libc/musl/src/thread/arm/clone.s+2-1| ... | ... | @@ -19,7 +19,8 @@ __clone: |
| 19 | 19 | 	ldmfd sp!,{r4,r5,r6,r7} |
| 20 | 20 | 	bx lr |
| 21 | 21 | |
| 22 | 1:	mov r0,r6 | |
| 22 | 1:	mov fp,#0 | |
| 23 | 	mov r0,r6 | |
| 23 | 24 | 	bl 3f |
| 24 | 25 | 2:	mov r7,#1 |
| 25 | 26 | 	svc 0 |
lib/libc/musl/src/thread/i386/clone.s+8-9| ... | ... | @@ -30,9 +30,15 @@ __clone: |
| 30 | 30 | 	mov 8(%ebp),%ebp |
| 31 | 31 | 	int $128 |
| 32 | 32 | 	test %eax,%eax |
| 33 | 	jnz 1f | |
| 33 | 	jz 1f | |
| 34 | 	add $16,%esp | |
| 35 | 	pop %edi | |
| 36 | 	pop %esi | |
| 37 | 	pop %ebx | |
| 38 | 	pop %ebp | |
| 39 | 	ret | |
| 34 | 40 | |
| 35 | 	mov %ebp,%eax | |
| 41 | 1:	mov %ebp,%eax | |
| 36 | 42 | 	xor %ebp,%ebp |
| 37 | 43 | 	call *%eax |
| 38 | 44 | 	mov %eax,%ebx |
| ... | ... | @@ -40,10 +46,3 @@ __clone: |
| 40 | 46 | 	inc %eax |
| 41 | 47 | 	int $128 |
| 42 | 48 | 	hlt |
| 43 | ||
| 44 | 1:	add $16,%esp | |
| 45 | 	pop %edi | |
| 46 | 	pop %esi | |
| 47 | 	pop %ebx | |
| 48 | 	pop %ebp | |
| 49 | 	ret |
lib/libc/musl/src/thread/loongarch64/clone.s+1| ... | ... | @@ -22,6 +22,7 @@ __clone: |
| 22 | 22 | 	beqz $a0, 1f # whether child process |
| 23 | 23 | 	jirl $zero, $ra, 0 # parent process return |
| 24 | 24 | 1: |
| 25 | 	move $fp, $zero | |
| 25 | 26 | 	ld.d $t8, $sp, 0 # function pointer |
| 26 | 27 | 	ld.d $a0, $sp, 8 # argument pointer |
| 27 | 28 | 	jirl $ra, $t8, 0 # call the user's function |
lib/libc/musl/src/thread/m68k/clone.s+2-1| ... | ... | @@ -18,7 +18,8 @@ __clone: |
| 18 | 18 | 	beq 1f |
| 19 | 19 | 	movem.l (%sp)+,%d2-%d5 |
| 20 | 20 | 	rts |
| 21 | 1:	move.l %a1,-(%sp) | |
| 21 | 1:	suba.l %%fp,%%fp | |
| 22 | 	move.l %a1,-(%sp) | |
| 22 | 23 | 	jsr (%a0) |
| 23 | 24 | 	move.l #1,%d0 |
| 24 | 25 | 	trap #0 |
lib/libc/musl/src/thread/microblaze/clone.s+2-1| ... | ... | @@ -22,7 +22,8 @@ __clone: |
| 22 | 22 | 	rtsd r15, 8 |
| 23 | 23 | 	nop |
| 24 | 24 | |
| 25 | 1:	lwi r3, r1, 0 | |
| 25 | 1:	add r19, r0, r0 | |
| 26 | 	lwi r3, r1, 0 | |
| 26 | 27 | 	lwi r5, r1, 4 |
| 27 | 28 | 	brald r15, r3 |
| 28 | 29 | 	nop |
lib/libc/musl/src/thread/mips/clone.s+2-1| ... | ... | @@ -27,7 +27,8 @@ __clone: |
| 27 | 27 | 	addu $sp, $sp, 16 |
| 28 | 28 | 	jr $ra |
| 29 | 29 | 	nop |
| 30 | 1:	lw $25, 0($sp) | |
| 30 | 1:	move $fp, $0 | |
| 31 | 	lw $25, 0($sp) | |
| 31 | 32 | 	lw $4, 4($sp) |
| 32 | 33 | 	jalr $25 |
| 33 | 34 | 	nop |
lib/libc/musl/src/thread/mips64/clone.s+2-1| ... | ... | @@ -25,7 +25,8 @@ __clone: |
| 25 | 25 | 	nop |
| 26 | 26 | 	jr	$ra |
| 27 | 27 | 	nop |
| 28 | 1:	ld	$25, 0($sp)	# function pointer | |
| 28 | 1:	move	$fp, $0 | |
| 29 | 	ld	$25, 0($sp)	# function pointer | |
| 29 | 30 | 	ld	$4, 8($sp)	# argument pointer |
| 30 | 31 | 	jalr	$25		# call the user's function |
| 31 | 32 | 	nop |
lib/libc/musl/src/thread/mipsn32/clone.s+2-1| ... | ... | @@ -25,7 +25,8 @@ __clone: |
| 25 | 25 | 	nop |
| 26 | 26 | 	jr	$ra |
| 27 | 27 | 	nop |
| 28 | 1:	lw	$25, 0($sp)	# function pointer | |
| 28 | 1:	move	$fp, $0 | |
| 29 | 	lw	$25, 0($sp)	# function pointer | |
| 29 | 30 | 	lw	$4, 4($sp)	# argument pointer |
| 30 | 31 | 	jalr	$25		# call the user's function |
| 31 | 32 | 	nop |
lib/libc/musl/src/thread/or1k/clone.s+2-1| ... | ... | @@ -23,7 +23,8 @@ __clone: |
| 23 | 23 | 	l.jr	r9 |
| 24 | 24 | 	 l.nop |
| 25 | 25 | |
| 26 | 1:	l.lwz	r11, 0(r1) | |
| 26 | 1:	l.ori	r2, r0, 0 | |
| 27 | 	l.lwz	r11, 0(r1) | |
| 27 | 28 | 	l.jalr	r11 |
| 28 | 29 | 	 l.lwz	r3, 4(r1) |
| 29 | 30 |
lib/libc/musl/src/thread/powerpc/clone.s+9-12| ... | ... | @@ -48,9 +48,16 @@ neg 3, 3 #negate the result (errno) |
| 48 | 48 | # compare sc result with 0 |
| 49 | 49 | cmpwi cr7, 3, 0 |
| 50 | 50 | |
| 51 | # if not 0, jump to end | |
| 52 | bne cr7, 2f | |
| 51 | # if not 0, restore stack and return | |
| 52 | beq cr7, 2f | |
| 53 | 53 | |
| 54 | lwz 30, 0(1) | |
| 55 | lwz 31, 4(1) | |
| 56 | addi 1, 1, 16 | |
| 57 | ||
| 58 | blr | |
| 59 | ||
| 60 | 2: | |
| 54 | 61 | #else: we're the child |
| 55 | 62 | #call funcptr: move arg (d) into r3 |
| 56 | 63 | mr 3, 31 |
| ... | ... | @@ -61,13 +68,3 @@ bctrl |
| 61 | 68 | # mov SYS_exit into r0 (the exit param is already in r3) |
| 62 | 69 | li 0, 1 |
| 63 | 70 | sc |
| 64 | ||
| 65 | 2: | |
| 66 | ||
| 67 | # restore stack | |
| 68 | lwz 30, 0(1) | |
| 69 | lwz 31, 4(1) | |
| 70 | addi 1, 1, 16 | |
| 71 | ||
| 72 | blr | |
| 73 |
lib/libc/musl/src/thread/x32/clone.s+3-3| ... | ... | @@ -15,12 +15,12 @@ __clone: |
| 15 | 15 | 	mov %rcx,(%rsi) |
| 16 | 16 | 	syscall |
| 17 | 17 | 	test %eax,%eax |
| 18 | 	jnz 1f | |
| 19 | 	xor %ebp,%ebp | |
| 18 | 	jz 1f | |
| 19 | 	ret | |
| 20 | 1:	xor %ebp,%ebp | |
| 20 | 21 | 	pop %rdi |
| 21 | 22 | 	call *%r9 |
| 22 | 23 | 	mov %eax,%edi |
| 23 | 24 | 	movl $0x4000003c,%eax /* SYS_exit */ |
| 24 | 25 | 	syscall |
| 25 | 26 | 	hlt |
| 26 | 1:	ret |
lib/libc/musl/src/thread/x86_64/clone.s+3-3| ... | ... | @@ -16,8 +16,9 @@ __clone: |
| 16 | 16 | 	mov %rcx,(%rsi) |
| 17 | 17 | 	syscall |
| 18 | 18 | 	test %eax,%eax |
| 19 | 	jnz 1f | |
| 20 | 	xor %ebp,%ebp | |
| 19 | 	jz 1f | |
| 20 | 	ret | |
| 21 | 1:	xor %ebp,%ebp | |
| 21 | 22 | 	pop %rdi |
| 22 | 23 | 	call *%r9 |
| 23 | 24 | 	mov %eax,%edi |
| ... | ... | @@ -25,4 +26,3 @@ __clone: |
| 25 | 26 | 	mov $60,%al |
| 26 | 27 | 	syscall |
| 27 | 28 | 	hlt |
| 28 | 1:	ret |
lib/std/Build.zig+5-5| ... | ... | @@ -706,7 +706,7 @@ pub const ExecutableOptions = struct { |
| 706 | 706 | single_threaded: ?bool = null, |
| 707 | 707 | pic: ?bool = null, |
| 708 | 708 | strip: ?bool = null, |
| 709 | unwind_tables: ?bool = null, | |
| 709 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 710 | 710 | omit_frame_pointer: ?bool = null, |
| 711 | 711 | sanitize_thread: ?bool = null, |
| 712 | 712 | error_tracing: ?bool = null, |
| ... | ... | @@ -762,7 +762,7 @@ pub const ObjectOptions = struct { |
| 762 | 762 | single_threaded: ?bool = null, |
| 763 | 763 | pic: ?bool = null, |
| 764 | 764 | strip: ?bool = null, |
| 765 | unwind_tables: ?bool = null, | |
| 765 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 766 | 766 | omit_frame_pointer: ?bool = null, |
| 767 | 767 | sanitize_thread: ?bool = null, |
| 768 | 768 | error_tracing: ?bool = null, |
| ... | ... | @@ -810,7 +810,7 @@ pub const SharedLibraryOptions = struct { |
| 810 | 810 | single_threaded: ?bool = null, |
| 811 | 811 | pic: ?bool = null, |
| 812 | 812 | strip: ?bool = null, |
| 813 | unwind_tables: ?bool = null, | |
| 813 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 814 | 814 | omit_frame_pointer: ?bool = null, |
| 815 | 815 | sanitize_thread: ?bool = null, |
| 816 | 816 | error_tracing: ?bool = null, |
| ... | ... | @@ -867,7 +867,7 @@ pub const StaticLibraryOptions = struct { |
| 867 | 867 | single_threaded: ?bool = null, |
| 868 | 868 | pic: ?bool = null, |
| 869 | 869 | strip: ?bool = null, |
| 870 | unwind_tables: ?bool = null, | |
| 870 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 871 | 871 | omit_frame_pointer: ?bool = null, |
| 872 | 872 | sanitize_thread: ?bool = null, |
| 873 | 873 | error_tracing: ?bool = null, |
| ... | ... | @@ -919,7 +919,7 @@ pub const TestOptions = struct { |
| 919 | 919 | single_threaded: ?bool = null, |
| 920 | 920 | pic: ?bool = null, |
| 921 | 921 | strip: ?bool = null, |
| 922 | unwind_tables: ?bool = null, | |
| 922 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 923 | 923 | omit_frame_pointer: ?bool = null, |
| 924 | 924 | sanitize_thread: ?bool = null, |
| 925 | 925 | error_tracing: ?bool = null, |
lib/std/Build/Module.zig+10-3| ... | ... | @@ -22,7 +22,7 @@ frameworks: std.StringArrayHashMapUnmanaged(LinkFrameworkOptions), |
| 22 | 22 | link_objects: std.ArrayListUnmanaged(LinkObject), |
| 23 | 23 | |
| 24 | 24 | strip: ?bool, |
| 25 | unwind_tables: ?bool, | |
| 25 | unwind_tables: ?std.builtin.UnwindTables, | |
| 26 | 26 | single_threaded: ?bool, |
| 27 | 27 | stack_protector: ?bool, |
| 28 | 28 | stack_check: ?bool, |
| ... | ... | @@ -218,7 +218,7 @@ pub const CreateOptions = struct { |
| 218 | 218 | link_libcpp: ?bool = null, |
| 219 | 219 | single_threaded: ?bool = null, |
| 220 | 220 | strip: ?bool = null, |
| 221 | unwind_tables: ?bool = null, | |
| 221 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 222 | 222 | dwarf_format: ?std.dwarf.Format = null, |
| 223 | 223 | code_model: std.builtin.CodeModel = .default, |
| 224 | 224 | stack_protector: ?bool = null, |
| ... | ... | @@ -675,7 +675,6 @@ pub fn appendZigProcessFlags( |
| 675 | 675 | const b = m.owner; |
| 676 | 676 | |
| 677 | 677 | try addFlag(zig_args, m.strip, "-fstrip", "-fno-strip"); |
| 678 | try addFlag(zig_args, m.unwind_tables, "-funwind-tables", "-fno-unwind-tables"); | |
| 679 | 678 | try addFlag(zig_args, m.single_threaded, "-fsingle-threaded", "-fno-single-threaded"); |
| 680 | 679 | try addFlag(zig_args, m.stack_check, "-fstack-check", "-fno-stack-check"); |
| 681 | 680 | try addFlag(zig_args, m.stack_protector, "-fstack-protector", "-fno-stack-protector"); |
| ... | ... | @@ -695,6 +694,14 @@ pub fn appendZigProcessFlags( |
| 695 | 694 | }); |
| 696 | 695 | } |
| 697 | 696 | |
| 697 | if (m.unwind_tables) |unwind_tables| { | |
| 698 | try zig_args.append(switch (unwind_tables) { | |
| 699 | .none => "-fno-unwind-tables", | |
| 700 | .sync => "-funwind-tables", | |
| 701 | .@"async" => "-fasync-unwind-tables", | |
| 702 | }); | |
| 703 | } | |
| 704 | ||
| 698 | 705 | try zig_args.ensureUnusedCapacity(1); |
| 699 | 706 | if (m.optimize) |optimize| switch (optimize) { |
| 700 | 707 | .Debug => zig_args.appendAssumeCapacity("-ODebug"), |
lib/std/builtin.zig+8| ... | ... | @@ -804,6 +804,14 @@ pub const LinkMode = enum { |
| 804 | 804 | dynamic, |
| 805 | 805 | }; |
| 806 | 806 | |
| 807 | /// This data structure is used by the Zig language code generation and | |
| 808 | /// therefore must be kept in sync with the compiler implementation. | |
| 809 | pub const UnwindTables = enum { | |
| 810 | none, | |
| 811 | sync, | |
| 812 | @"async", | |
| 813 | }; | |
| 814 | ||
| 807 | 815 | /// This data structure is used by the Zig language code generation and |
| 808 | 816 | /// therefore must be kept in sync with the compiler implementation. |
| 809 | 817 | pub const WasiExecModel = enum { |
lib/std/os/linux/aarch64.zig+6-1| ... | ... | @@ -120,8 +120,13 @@ pub fn clone() callconv(.Naked) usize { |
| 120 | 120 | \\ cbz x0,1f |
| 121 | 121 | \\ // parent |
| 122 | 122 | \\ ret |
| 123 | \\ | |
| 123 | 124 | \\ // child |
| 124 | \\1: ldp x1,x0,[sp],#16 | |
| 125 | \\1: .cfi_undefined lr | |
| 126 | \\ mov fp, 0 | |
| 127 | \\ mov lr, 0 | |
| 128 | \\ | |
| 129 | \\ ldp x1,x0,[sp],#16 | |
| 125 | 130 | \\ blr x1 |
| 126 | 131 | \\ mov x8,#93 // SYS_exit |
| 127 | 132 | \\ svc #0 |
lib/std/os/linux/arm.zig+8-3| ... | ... | @@ -120,11 +120,16 @@ pub fn clone() callconv(.Naked) usize { |
| 120 | 120 | \\ ldmfd sp!,{r4,r5,r6,r7} |
| 121 | 121 | \\ bx lr |
| 122 | 122 | \\ |
| 123 | \\1: mov r0,r6 | |
| 123 | \\ // https://github.com/llvm/llvm-project/issues/115891 | |
| 124 | \\1: mov r7, #0 | |
| 125 | \\ mov r11, #0 | |
| 126 | \\ mov lr, #0 | |
| 127 | \\ | |
| 128 | \\ mov r0,r6 | |
| 124 | 129 | \\ bl 3f |
| 125 | \\2: mov r7,#1 // SYS_exit | |
| 130 | \\ mov r7,#1 // SYS_exit | |
| 126 | 131 | \\ svc 0 |
| 127 | \\ b 2b | |
| 132 | \\ | |
| 128 | 133 | \\3: bx r5 |
| 129 | 134 | ); |
| 130 | 135 | } |
lib/std/os/linux/hexagon.zig+4| ... | ... | @@ -118,6 +118,10 @@ pub fn clone() callconv(.Naked) usize { |
| 118 | 118 | \\ p0 = cmp.eq(r0, #0) |
| 119 | 119 | \\ if (!p0) dealloc_return |
| 120 | 120 | \\ |
| 121 | \\ .cfi_undefined r31 | |
| 122 | \\ r30 = #0 | |
| 123 | \\ r31 = #0 | |
| 124 | \\ | |
| 121 | 125 | \\ r0 = r10 |
| 122 | 126 | \\ callr r11 |
| 123 | 127 | \\ |
lib/std/os/linux/loongarch64.zig+4| ... | ... | @@ -121,6 +121,10 @@ pub fn clone() callconv(.Naked) usize { |
| 121 | 121 | \\ beqz $a0, 1f # whether child process |
| 122 | 122 | \\ jirl $zero, $ra, 0 # parent process return |
| 123 | 123 | \\1: |
| 124 | \\ .cfi_undefined 1 | |
| 125 | \\ move $fp, $zero | |
| 126 | \\ move $ra, $zero | |
| 127 | \\ | |
| 124 | 128 | \\ ld.d $t8, $sp, 0 # function pointer |
| 125 | 129 | \\ ld.d $a0, $sp, 8 # argument pointer |
| 126 | 130 | \\ jirl $ra, $t8, 0 # call the user's function |
lib/std/os/linux/mips.zig+4| ... | ... | @@ -231,6 +231,10 @@ pub fn clone() callconv(.Naked) usize { |
| 231 | 231 | \\ jr $ra |
| 232 | 232 | \\ nop |
| 233 | 233 | \\1: |
| 234 | \\ .cfi_undefined $ra | |
| 235 | \\ move $fp, $zero | |
| 236 | \\ move $ra, $zero | |
| 237 | \\ | |
| 234 | 238 | \\ lw $25, 0($sp) |
| 235 | 239 | \\ lw $4, 4($sp) |
| 236 | 240 | \\ jalr $25 |
lib/std/os/linux/mips64.zig+4| ... | ... | @@ -210,6 +210,10 @@ pub fn clone() callconv(.Naked) usize { |
| 210 | 210 | \\ jr $ra |
| 211 | 211 | \\ nop |
| 212 | 212 | \\1: |
| 213 | \\ .cfi_undefined $ra | |
| 214 | \\ move $fp, $zero | |
| 215 | \\ move $ra, $zero | |
| 216 | \\ | |
| 213 | 217 | \\ ld $25, 0($sp) |
| 214 | 218 | \\ ld $4, 8($sp) |
| 215 | 219 | \\ jalr $25 |
lib/std/os/linux/powerpc.zig+20-20| ... | ... | @@ -133,14 +133,14 @@ pub fn clone() callconv(.Naked) usize { |
| 133 | 133 | // syscall(SYS_clone, flags, stack, ptid, tls, ctid) |
| 134 | 134 | // 0 3, 4, 5, 6, 7 |
| 135 | 135 | asm volatile ( |
| 136 | \\ # store non-volatile regs r30, r31 on stack in order to put our | |
| 136 | \\ # store non-volatile regs r29, r30 on stack in order to put our | |
| 137 | 137 | \\ # start func and its arg there |
| 138 | \\ stwu 30, -16(1) | |
| 139 | \\ stw 31, 4(1) | |
| 138 | \\ stwu 29, -16(1) | |
| 139 | \\ stw 30, 4(1) | |
| 140 | 140 | \\ |
| 141 | \\ # save r3 (func) into r30, and r6(arg) into r31 | |
| 142 | \\ mr 30, 3 | |
| 143 | \\ mr 31, 6 | |
| 141 | \\ # save r3 (func) into r29, and r6(arg) into r30 | |
| 142 | \\ mr 29, 3 | |
| 143 | \\ mr 30, 6 | |
| 144 | 144 | \\ |
| 145 | 145 | \\ # create initial stack frame for new thread |
| 146 | 146 | \\ clrrwi 4, 4, 4 |
| ... | ... | @@ -167,28 +167,28 @@ pub fn clone() callconv(.Naked) usize { |
| 167 | 167 | \\ # compare sc result with 0 |
| 168 | 168 | \\ cmpwi cr7, 3, 0 |
| 169 | 169 | \\ |
| 170 | \\ # if not 0, jump to end | |
| 171 | \\ bne cr7, 2f | |
| 170 | \\ # if not 0, restore stack and return | |
| 171 | \\ beq cr7, 2f | |
| 172 | \\ lwz 29, 0(1) | |
| 173 | \\ lwz 30, 4(1) | |
| 174 | \\ addi 1, 1, 16 | |
| 175 | \\ blr | |
| 172 | 176 | \\ |
| 173 | 177 | \\ #else: we're the child |
| 178 | \\ 2: | |
| 179 | \\ .cfi_undefined lr | |
| 180 | \\ li 31, 0 | |
| 181 | \\ mtlr 0 | |
| 182 | \\ | |
| 174 | 183 | \\ #call funcptr: move arg (d) into r3 |
| 175 | \\ mr 3, 31 | |
| 176 | \\ #move r30 (funcptr) into CTR reg | |
| 177 | \\ mtctr 30 | |
| 184 | \\ mr 3, 30 | |
| 185 | \\ #move r29 (funcptr) into CTR reg | |
| 186 | \\ mtctr 29 | |
| 178 | 187 | \\ # call CTR reg |
| 179 | 188 | \\ bctrl |
| 180 | 189 | \\ # mov SYS_exit into r0 (the exit param is already in r3) |
| 181 | 190 | \\ li 0, 1 |
| 182 | 191 | \\ sc |
| 183 | \\ | |
| 184 | \\ 2: | |
| 185 | \\ | |
| 186 | \\ # restore stack | |
| 187 | \\ lwz 30, 0(1) | |
| 188 | \\ lwz 31, 4(1) | |
| 189 | \\ addi 1, 1, 16 | |
| 190 | \\ | |
| 191 | \\ blr | |
| 192 | 192 | ); |
| 193 | 193 | } |
| 194 | 194 |
lib/std/os/linux/powerpc64.zig+6-1| ... | ... | @@ -160,7 +160,12 @@ pub fn clone() callconv(.Naked) usize { |
| 160 | 160 | \\ cmpwi cr7, 3, 0 |
| 161 | 161 | \\ bnelr cr7 |
| 162 | 162 | \\ |
| 163 | \\ # we're the child. call fn(arg) | |
| 163 | \\ # we're the child | |
| 164 | \\ .cfi_undefined lr | |
| 165 | \\ li 31, 0 | |
| 166 | \\ mtlr 0 | |
| 167 | \\ | |
| 168 | \\ # call fn(arg) | |
| 164 | 169 | \\ ld 3, 16(1) |
| 165 | 170 | \\ ld 12, 8(1) |
| 166 | 171 | \\ mtctr 12 |
lib/std/os/linux/riscv32.zig+5-1| ... | ... | @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { |
| 120 | 120 | \\ ret |
| 121 | 121 | \\ |
| 122 | 122 | \\ # Child |
| 123 | \\1: lw a1, 0(sp) | |
| 123 | \\1: .cfi_undefined ra | |
| 124 | \\ mv fp, zero | |
| 125 | \\ mv ra, zero | |
| 126 | \\ | |
| 127 | \\ lw a1, 0(sp) | |
| 124 | 128 | \\ lw a0, 4(sp) |
| 125 | 129 | \\ jalr a1 |
| 126 | 130 | \\ |
lib/std/os/linux/riscv64.zig+5-1| ... | ... | @@ -120,7 +120,11 @@ pub fn clone() callconv(.Naked) usize { |
| 120 | 120 | \\ ret |
| 121 | 121 | \\ |
| 122 | 122 | \\ # Child |
| 123 | \\1: ld a1, 0(sp) | |
| 123 | \\1: .cfi_undefined ra | |
| 124 | \\ mv fp, zero | |
| 125 | \\ mv ra, zero | |
| 126 | \\ | |
| 127 | \\ ld a1, 0(sp) | |
| 124 | 128 | \\ ld a0, 8(sp) |
| 125 | 129 | \\ jalr a1 |
| 126 | 130 | \\ |
lib/std/os/linux/s390x.zig+6-1| ... | ... | @@ -133,7 +133,12 @@ pub fn clone() callconv(.Naked) usize { |
| 133 | 133 | \\ltgr %%r2, %%r2 |
| 134 | 134 | \\bnzr %%r14 |
| 135 | 135 | \\ |
| 136 | \\# we're the child. call fn(arg) | |
| 136 | \\# we're the child | |
| 137 | \\.cfi_undefined %%r14 | |
| 138 | \\lghi %%r11, 0 | |
| 139 | \\lghi %%r14, 0 | |
| 140 | \\ | |
| 141 | \\# call fn(arg) | |
| 137 | 142 | \\lg %%r1, 8(%%r15) |
| 138 | 143 | \\lg %%r2, 16(%%r15) |
| 139 | 144 | \\basr %%r14, %%r1 |
lib/std/os/linux/sparc64.zig+13-8| ... | ... | @@ -198,29 +198,34 @@ pub fn clone() callconv(.Naked) usize { |
| 198 | 198 | \\ mov %%i5, %%o3 |
| 199 | 199 | \\ ldx [%%fp + 0x8af], %%o4 |
| 200 | 200 | \\ t 0x6d |
| 201 | \\ bcs,pn %%xcc, 2f | |
| 201 | \\ bcs,pn %%xcc, 1f | |
| 202 | 202 | \\ nop |
| 203 | 203 | \\ # The child pid is returned in o0 while o1 tells if this |
| 204 | 204 | \\ # process is # the child (=1) or the parent (=0). |
| 205 | \\ brnz %%o1, 1f | |
| 205 | \\ brnz %%o1, 2f | |
| 206 | 206 | \\ nop |
| 207 | 207 | \\ # Parent process, return the child pid |
| 208 | 208 | \\ mov %%o0, %%i0 |
| 209 | 209 | \\ ret |
| 210 | 210 | \\ restore |
| 211 | 211 | \\1: |
| 212 | \\ # Child process, call func(arg) | |
| 212 | \\ # The syscall failed | |
| 213 | \\ sub %%g0, %%o0, %%i0 | |
| 214 | \\ ret | |
| 215 | \\ restore | |
| 216 | \\2: | |
| 217 | \\ # Child process | |
| 218 | \\ .cfi_undefined %%i7 | |
| 219 | \\ mov %%g0, %%fp | |
| 220 | \\ mov %%g0, %%i7 | |
| 221 | \\ | |
| 222 | \\ # call func(arg) | |
| 213 | 223 | \\ mov %%g0, %%fp |
| 214 | 224 | \\ call %%g2 |
| 215 | 225 | \\ mov %%g3, %%o0 |
| 216 | 226 | \\ # Exit |
| 217 | 227 | \\ mov 1, %%g1 // SYS_exit |
| 218 | 228 | \\ t 0x6d |
| 219 | \\2: | |
| 220 | \\ # The syscall failed | |
| 221 | \\ sub %%g0, %%o0, %%i0 | |
| 222 | \\ ret | |
| 223 | \\ restore | |
| 224 | 229 | ); |
| 225 | 230 | } |
| 226 | 231 |
lib/std/os/linux/x86.zig+11-8| ... | ... | @@ -148,19 +148,22 @@ pub fn clone() callconv(.Naked) usize { |
| 148 | 148 | \\ movl $120,%%eax // SYS_clone |
| 149 | 149 | \\ int $128 |
| 150 | 150 | \\ testl %%eax,%%eax |
| 151 | \\ jnz 1f | |
| 152 | \\ popl %%eax | |
| 153 | \\ xorl %%ebp,%%ebp | |
| 154 | \\ calll *%%eax | |
| 155 | \\ movl %%eax,%%ebx | |
| 156 | \\ movl $1,%%eax // SYS_exit | |
| 157 | \\ int $128 | |
| 158 | \\1: | |
| 151 | \\ jz 1f | |
| 159 | 152 | \\ popl %%edi |
| 160 | 153 | \\ popl %%esi |
| 161 | 154 | \\ popl %%ebx |
| 162 | 155 | \\ popl %%ebp |
| 163 | 156 | \\ retl |
| 157 | \\ | |
| 158 | \\1: | |
| 159 | \\ .cfi_undefined %%eip | |
| 160 | \\ xorl %%ebp,%%ebp | |
| 161 | \\ | |
| 162 | \\ popl %%eax | |
| 163 | \\ calll *%%eax | |
| 164 | \\ movl %%eax,%%ebx | |
| 165 | \\ movl $1,%%eax // SYS_exit | |
| 166 | \\ int $128 | |
| 164 | 167 | ); |
| 165 | 168 | } |
| 166 | 169 |
lib/std/os/linux/x86_64.zig+2| ... | ... | @@ -116,8 +116,10 @@ pub fn clone() callconv(.Naked) usize { |
| 116 | 116 | \\ testq %%rax,%%rax |
| 117 | 117 | \\ jz 1f |
| 118 | 118 | \\ retq |
| 119 | \\ | |
| 119 | 120 | \\1: .cfi_undefined %%rip |
| 120 | 121 | \\ xorl %%ebp,%%ebp |
| 122 | \\ | |
| 121 | 123 | \\ popq %%rdi |
| 122 | 124 | \\ callq *%%r9 |
| 123 | 125 | \\ movl %%eax,%%edi |
lib/std/start.zig+45-6| ... | ... | @@ -230,6 +230,29 @@ fn _start() callconv(.naked) noreturn { |
| 230 | 230 | ); |
| 231 | 231 | } |
| 232 | 232 | |
| 233 | // This is the first userspace frame. Prevent DWARF-based unwinders from unwinding further. We | |
| 234 | // prevent FP-based unwinders from unwinding further by zeroing the register further below. | |
| 235 | asm volatile (switch (native_arch) { | |
| 236 | .arc => ".cfi_undefined blink", | |
| 237 | .arm, .armeb, .thumb, .thumbeb => "", // https://github.com/llvm/llvm-project/issues/115891 | |
| 238 | .aarch64, .aarch64_be => ".cfi_undefined lr", | |
| 239 | .csky => ".cfi_undefined lr", | |
| 240 | .hexagon => ".cfi_undefined r31", | |
| 241 | .loongarch32, .loongarch64 => ".cfi_undefined 1", | |
| 242 | .m68k => ".cfi_undefined pc", | |
| 243 | .mips, .mipsel, .mips64, .mips64el => ".cfi_undefined $ra", | |
| 244 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => ".cfi_undefined lr", | |
| 245 | .riscv32, .riscv64 => if (builtin.zig_backend == .stage2_riscv64) | |
| 246 | "" | |
| 247 | else | |
| 248 | ".cfi_undefined ra", | |
| 249 | .s390x => ".cfi_undefined %%r14", | |
| 250 | .sparc, .sparc64 => ".cfi_undefined %%i7", | |
| 251 | .x86 => ".cfi_undefined %%eip", | |
| 252 | .x86_64 => ".cfi_undefined %%rip", | |
| 253 | else => @compileError("unsupported arch"), | |
| 254 | }); | |
| 255 | ||
| 233 | 256 | // Move this to the riscv prong below when this is resolved: https://github.com/ziglang/zig/issues/20918 |
| 234 | 257 | if (builtin.cpu.arch.isRISCV() and builtin.zig_backend != .stage2_riscv64) asm volatile ( |
| 235 | 258 | \\ .weak __global_pointer$ |
| ... | ... | @@ -247,7 +270,6 @@ fn _start() callconv(.naked) noreturn { |
| 247 | 270 | // linker explicitly. |
| 248 | 271 | asm volatile (switch (native_arch) { |
| 249 | 272 | .x86_64 => |
| 250 | \\ .cfi_undefined %%rip | |
| 251 | 273 | \\ xorl %%ebp, %%ebp |
| 252 | 274 | \\ movq %%rsp, %%rdi |
| 253 | 275 | \\ andq $-16, %%rsp |
| ... | ... | @@ -279,8 +301,10 @@ fn _start() callconv(.naked) noreturn { |
| 279 | 301 | , |
| 280 | 302 | .arm, .armeb, .thumb, .thumbeb => |
| 281 | 303 | // Note that this code must work for Thumb-1. |
| 304 | // r7 = FP (local), r11 = FP (unwind) | |
| 282 | 305 | \\ movs v1, #0 |
| 283 | \\ mov fp, v1 | |
| 306 | \\ mov r7, v1 | |
| 307 | \\ mov r11, v1 | |
| 284 | 308 | \\ mov lr, v1 |
| 285 | 309 | \\ mov a1, sp |
| 286 | 310 | \\ subs v1, #16 |
| ... | ... | @@ -290,20 +314,23 @@ fn _start() callconv(.naked) noreturn { |
| 290 | 314 | , |
| 291 | 315 | .csky => |
| 292 | 316 | // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for |
| 293 | // position-independent code to work. We depend on this in `std.os.linux.start_pie` | |
| 294 | // to locate `_DYNAMIC` as well. | |
| 317 | // position-independent code to work. We depend on this in `std.os.linux.pie` to locate | |
| 318 | // `_DYNAMIC` as well. | |
| 319 | // r8 = FP | |
| 295 | 320 | \\ grs t0, 1f |
| 296 | 321 | \\ 1: |
| 297 | 322 | \\ lrw gb, 1b@GOTPC |
| 298 | 323 | \\ addu gb, t0 |
| 324 | \\ movi r8, 0 | |
| 299 | 325 | \\ movi lr, 0 |
| 300 | 326 | \\ mov a0, sp |
| 301 | 327 | \\ andi sp, sp, -8 |
| 302 | 328 | \\ jmpi %[posixCallMainAndExit] |
| 303 | 329 | , |
| 304 | 330 | .hexagon => |
| 305 | // r29 = SP, r30 = FP | |
| 331 | // r29 = SP, r30 = FP, r31 = LR | |
| 306 | 332 | \\ r30 = #0 |
| 333 | \\ r31 = #0 | |
| 307 | 334 | \\ r0 = r29 |
| 308 | 335 | \\ r29 = and(r29, #-16) |
| 309 | 336 | \\ memw(r29 + #-8) = r29 |
| ... | ... | @@ -312,12 +339,13 @@ fn _start() callconv(.naked) noreturn { |
| 312 | 339 | , |
| 313 | 340 | .loongarch32, .loongarch64 => |
| 314 | 341 | \\ move $fp, $zero |
| 342 | \\ move $ra, $zero | |
| 315 | 343 | \\ move $a0, $sp |
| 316 | 344 | \\ bstrins.d $sp, $zero, 3, 0 |
| 317 | 345 | \\ b %[posixCallMainAndExit] |
| 318 | 346 | , |
| 319 | 347 | .riscv32, .riscv64 => |
| 320 | \\ li s0, 0 | |
| 348 | \\ li fp, 0 | |
| 321 | 349 | \\ li ra, 0 |
| 322 | 350 | \\ mv a0, sp |
| 323 | 351 | \\ andi sp, sp, -16 |
| ... | ... | @@ -371,28 +399,35 @@ fn _start() callconv(.naked) noreturn { |
| 371 | 399 | , |
| 372 | 400 | .powerpc, .powerpcle => |
| 373 | 401 | // Set up the initial stack frame, and clear the back chain pointer. |
| 402 | // r1 = SP, r31 = FP | |
| 374 | 403 | \\ mr 3, 1 |
| 375 | 404 | \\ clrrwi 1, 1, 4 |
| 376 | 405 | \\ li 0, 0 |
| 377 | 406 | \\ stwu 1, -16(1) |
| 378 | 407 | \\ stw 0, 0(1) |
| 408 | \\ li 31, 0 | |
| 379 | 409 | \\ mtlr 0 |
| 380 | 410 | \\ b %[posixCallMainAndExit] |
| 381 | 411 | , |
| 382 | 412 | .powerpc64, .powerpc64le => |
| 383 | 413 | // Set up the ToC and initial stack frame, and clear the back chain pointer. |
| 414 | // r1 = SP, r2 = ToC, r31 = FP | |
| 384 | 415 | \\ addis 2, 12, .TOC. - %[_start]@ha |
| 385 | 416 | \\ addi 2, 2, .TOC. - %[_start]@l |
| 386 | 417 | \\ mr 3, 1 |
| 387 | 418 | \\ clrrdi 1, 1, 4 |
| 388 | 419 | \\ li 0, 0 |
| 389 | 420 | \\ stdu 0, -32(1) |
| 421 | \\ li 31, 0 | |
| 390 | 422 | \\ mtlr 0 |
| 391 | 423 | \\ b %[posixCallMainAndExit] |
| 392 | 424 | \\ nop |
| 393 | 425 | , |
| 394 | 426 | .s390x => |
| 395 | 427 | // Set up the stack frame (register save area and cleared back-chain slot). |
| 428 | // r11 = FP, r14 = LR, r15 = SP | |
| 429 | \\ lghi %%r11, 0 | |
| 430 | \\ lghi %%r14, 0 | |
| 396 | 431 | \\ lgr %%r2, %%r15 |
| 397 | 432 | \\ lghi %%r0, -16 |
| 398 | 433 | \\ ngr %%r15, %%r0 |
| ... | ... | @@ -403,7 +438,9 @@ fn _start() callconv(.naked) noreturn { |
| 403 | 438 | , |
| 404 | 439 | .sparc => |
| 405 | 440 | // argc is stored after a register window (16 registers * 4 bytes). |
| 441 | // i7 = LR | |
| 406 | 442 | \\ mov %%g0, %%fp |
| 443 | \\ mov %%g0, %%i7 | |
| 407 | 444 | \\ add %%sp, 64, %%o0 |
| 408 | 445 | \\ and %%sp, -8, %%sp |
| 409 | 446 | \\ ba,a %[posixCallMainAndExit] |
| ... | ... | @@ -411,7 +448,9 @@ fn _start() callconv(.naked) noreturn { |
| 411 | 448 | .sparc64 => |
| 412 | 449 | // argc is stored after a register window (16 registers * 8 bytes) plus the stack bias |
| 413 | 450 | // (2047 bytes). |
| 451 | // i7 = LR | |
| 414 | 452 | \\ mov %%g0, %%fp |
| 453 | \\ mov %%g0, %%i7 | |
| 415 | 454 | \\ add %%sp, 2175, %%o0 |
| 416 | 455 | \\ add %%sp, 2047, %%sp |
| 417 | 456 | \\ and %%sp, -16, %%sp |
src/Builtin.zig+3| ... | ... | @@ -2,6 +2,7 @@ target: std.Target, |
| 2 | 2 | zig_backend: std.builtin.CompilerBackend, |
| 3 | 3 | output_mode: std.builtin.OutputMode, |
| 4 | 4 | link_mode: std.builtin.LinkMode, |
| 5 | unwind_tables: std.builtin.UnwindTables, | |
| 5 | 6 | is_test: bool, |
| 6 | 7 | single_threaded: bool, |
| 7 | 8 | link_libc: bool, |
| ... | ... | @@ -40,6 +41,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { |
| 40 | 41 | \\ |
| 41 | 42 | \\pub const output_mode: std.builtin.OutputMode = .{p_}; |
| 42 | 43 | \\pub const link_mode: std.builtin.LinkMode = .{p_}; |
| 44 | \\pub const unwind_tables: std.builtin.UnwindTables = .{p_}; | |
| 43 | 45 | \\pub const is_test = {}; |
| 44 | 46 | \\pub const single_threaded = {}; |
| 45 | 47 | \\pub const abi: std.Target.Abi = .{p_}; |
| ... | ... | @@ -53,6 +55,7 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void { |
| 53 | 55 | std.zig.fmtId(@tagName(zig_backend)), |
| 54 | 56 | std.zig.fmtId(@tagName(opts.output_mode)), |
| 55 | 57 | std.zig.fmtId(@tagName(opts.link_mode)), |
| 58 | std.zig.fmtId(@tagName(opts.unwind_tables)), | |
| 56 | 59 | opts.is_test, |
| 57 | 60 | opts.single_threaded, |
| 58 | 61 | std.zig.fmtId(@tagName(target.abi)), |
src/Compilation.zig+20-7| ... | ... | @@ -1261,12 +1261,15 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1261 | 1261 | // The "any" values provided by resolved config only account for |
| 1262 | 1262 | // explicitly-provided settings. We now make them additionally account |
| 1263 | 1263 | // for default setting resolution. |
| 1264 | const any_unwind_tables = options.config.any_unwind_tables or options.root_mod.unwind_tables; | |
| 1264 | const any_unwind_tables = switch (options.config.any_unwind_tables) { | |
| 1265 | .none => options.root_mod.unwind_tables, | |
| 1266 | .sync, .@"async" => |uwt| uwt, | |
| 1267 | }; | |
| 1265 | 1268 | const any_non_single_threaded = options.config.any_non_single_threaded or !options.root_mod.single_threaded; |
| 1266 | 1269 | const any_sanitize_thread = options.config.any_sanitize_thread or options.root_mod.sanitize_thread; |
| 1267 | 1270 | const any_fuzz = options.config.any_fuzz or options.root_mod.fuzz; |
| 1268 | 1271 | |
| 1269 | const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables; | |
| 1272 | const link_eh_frame_hdr = options.link_eh_frame_hdr or any_unwind_tables != .none; | |
| 1270 | 1273 | const build_id = options.build_id orelse .none; |
| 1271 | 1274 | |
| 1272 | 1275 | const link_libc = options.config.link_libc; |
| ... | ... | @@ -1354,6 +1357,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1354 | 1357 | cache.hash.add(options.config.pie); |
| 1355 | 1358 | cache.hash.add(options.config.lto); |
| 1356 | 1359 | cache.hash.add(options.config.link_mode); |
| 1360 | cache.hash.add(options.config.any_unwind_tables); | |
| 1357 | 1361 | cache.hash.add(options.function_sections); |
| 1358 | 1362 | cache.hash.add(options.data_sections); |
| 1359 | 1363 | cache.hash.add(link_libc); |
| ... | ... | @@ -5553,10 +5557,17 @@ pub fn addCCArgs( |
| 5553 | 5557 | try argv.append("-Werror=date-time"); |
| 5554 | 5558 | } |
| 5555 | 5559 | |
| 5556 | if (mod.unwind_tables) { | |
| 5557 | try argv.append("-funwind-tables"); | |
| 5558 | } else { | |
| 5559 | try argv.append("-fno-unwind-tables"); | |
| 5560 | switch (mod.unwind_tables) { | |
| 5561 | .none => { | |
| 5562 | try argv.append("-fno-unwind-tables"); | |
| 5563 | try argv.append("-fno-asynchronous-unwind-tables"); | |
| 5564 | }, | |
| 5565 | .sync => { | |
| 5566 | // Need to override Clang's convoluted default logic. | |
| 5567 | try argv.append("-fno-asynchronous-unwind-tables"); | |
| 5568 | try argv.append("-funwind-tables"); | |
| 5569 | }, | |
| 5570 | .@"async" => try argv.append("-fasynchronous-unwind-tables"), | |
| 5560 | 5571 | } |
| 5561 | 5572 | }, |
| 5562 | 5573 | .shared_library, .ll, .bc, .unknown, .static_library, .object, .def, .zig, .res, .manifest => {}, |
| ... | ... | @@ -6288,6 +6299,7 @@ pub const CrtFileOptions = struct { |
| 6288 | 6299 | function_sections: ?bool = null, |
| 6289 | 6300 | data_sections: ?bool = null, |
| 6290 | 6301 | omit_frame_pointer: ?bool = null, |
| 6302 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 6291 | 6303 | pic: ?bool = null, |
| 6292 | 6304 | no_builtin: ?bool = null, |
| 6293 | 6305 | }; |
| ... | ... | @@ -6349,7 +6361,8 @@ pub fn build_crt_file( |
| 6349 | 6361 | // Some libcs (e.g. musl) are opinionated about -fomit-frame-pointer. |
| 6350 | 6362 | .omit_frame_pointer = options.omit_frame_pointer orelse comp.root_mod.omit_frame_pointer, |
| 6351 | 6363 | .valgrind = false, |
| 6352 | .unwind_tables = false, | |
| 6364 | // Some libcs (e.g. MinGW) are opinionated about -funwind-tables. | |
| 6365 | .unwind_tables = options.unwind_tables orelse .none, | |
| 6353 | 6366 | // Some CRT objects (e.g. musl's rcrt1.o and Scrt1.o) are opinionated about PIC. |
| 6354 | 6367 | .pic = options.pic orelse comp.root_mod.pic, |
| 6355 | 6368 | .optimize_mode = comp.compilerRtOptMode(), |
src/Compilation/Config.zig+14-10| ... | ... | @@ -12,13 +12,14 @@ link_libunwind: bool, |
| 12 | 12 | /// True if and only if the c_source_files field will have nonzero length when |
| 13 | 13 | /// calling Compilation.create. |
| 14 | 14 | any_c_source_files: bool, |
| 15 | /// This is true if any Module has unwind_tables set explicitly to true. Until | |
| 16 | /// Compilation.create is called, it is possible for this to be false while in | |
| 17 | /// fact all Module instances have unwind_tables=true due to the default | |
| 18 | /// being unwind_tables=true. After Compilation.create is called this will | |
| 19 | /// also take into account the default setting, making this value true if and | |
| 20 | /// only if any Module has unwind_tables set to true. | |
| 21 | any_unwind_tables: bool, | |
| 15 | /// This is not `.none` if any `Module` has `unwind_tables` set explicitly to a | |
| 16 | /// value other than `.none`. Until `Compilation.create()` is called, it is | |
| 17 | /// possible for this to be `.none` while in fact all `Module` instances have | |
| 18 | /// `unwind_tables != .none` due to the default. After `Compilation.create()` is | |
| 19 | /// called, this will also take into account the default setting, making this | |
| 20 | /// value `.sync` or `.@"async"` if and only if any `Module` has | |
| 21 | /// `unwind_tables != .none`. | |
| 22 | any_unwind_tables: std.builtin.UnwindTables, | |
| 22 | 23 | /// This is true if any Module has single_threaded set explicitly to false. Until |
| 23 | 24 | /// Compilation.create is called, it is possible for this to be false while in |
| 24 | 25 | /// fact all Module instances have single_threaded=false due to the default |
| ... | ... | @@ -85,7 +86,7 @@ pub const Options = struct { |
| 85 | 86 | any_non_single_threaded: bool = false, |
| 86 | 87 | any_sanitize_thread: bool = false, |
| 87 | 88 | any_fuzz: bool = false, |
| 88 | any_unwind_tables: bool = false, | |
| 89 | any_unwind_tables: std.builtin.UnwindTables = .none, | |
| 89 | 90 | any_dyn_libs: bool = false, |
| 90 | 91 | any_c_source_files: bool = false, |
| 91 | 92 | any_non_stripped: bool = false, |
| ... | ... | @@ -356,8 +357,11 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 356 | 357 | break :b false; |
| 357 | 358 | }; |
| 358 | 359 | |
| 359 | const any_unwind_tables = options.any_unwind_tables or | |
| 360 | link_libunwind or target_util.needUnwindTables(target); | |
| 360 | const any_unwind_tables = b: { | |
| 361 | if (options.any_unwind_tables != .none) break :b options.any_unwind_tables; | |
| 362 | ||
| 363 | break :b target_util.needUnwindTables(target, link_libunwind, options.any_sanitize_thread); | |
| 364 | }; | |
| 361 | 365 | |
| 362 | 366 | const link_mode = b: { |
| 363 | 367 | const explicitly_exe_or_dyn_lib = switch (options.output_mode) { |
src/Package/Module.zig+4-3| ... | ... | @@ -27,7 +27,7 @@ red_zone: bool, |
| 27 | 27 | sanitize_c: bool, |
| 28 | 28 | sanitize_thread: bool, |
| 29 | 29 | fuzz: bool, |
| 30 | unwind_tables: bool, | |
| 30 | unwind_tables: std.builtin.UnwindTables, | |
| 31 | 31 | cc_argv: []const []const u8, |
| 32 | 32 | /// (SPIR-V) whether to generate a structured control flow graph or not |
| 33 | 33 | structured_cfg: bool, |
| ... | ... | @@ -91,7 +91,7 @@ pub const CreateOptions = struct { |
| 91 | 91 | /// other number means stack protection with that buffer size. |
| 92 | 92 | stack_protector: ?u32 = null, |
| 93 | 93 | red_zone: ?bool = null, |
| 94 | unwind_tables: ?bool = null, | |
| 94 | unwind_tables: ?std.builtin.UnwindTables = null, | |
| 95 | 95 | sanitize_c: ?bool = null, |
| 96 | 96 | sanitize_thread: ?bool = null, |
| 97 | 97 | fuzz: ?bool = null, |
| ... | ... | @@ -112,7 +112,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 112 | 112 | if (options.inherited.sanitize_thread == true) assert(options.global.any_sanitize_thread); |
| 113 | 113 | if (options.inherited.fuzz == true) assert(options.global.any_fuzz); |
| 114 | 114 | if (options.inherited.single_threaded == false) assert(options.global.any_non_single_threaded); |
| 115 | if (options.inherited.unwind_tables == true) assert(options.global.any_unwind_tables); | |
| 115 | if (options.inherited.unwind_tables) |uwt| if (uwt != .none) assert(options.global.any_unwind_tables != .none); | |
| 116 | 116 | if (options.inherited.error_tracing == true) assert(options.global.any_error_tracing); |
| 117 | 117 | |
| 118 | 118 | 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 { |
| 382 | 382 | .zig_backend = zig_backend, |
| 383 | 383 | .output_mode = options.global.output_mode, |
| 384 | 384 | .link_mode = options.global.link_mode, |
| 385 | .unwind_tables = options.global.any_unwind_tables, | |
| 385 | 386 | .is_test = options.global.is_test, |
| 386 | 387 | .single_threaded = single_threaded, |
| 387 | 388 | .link_libc = options.global.link_libc, |
src/arch/riscv64/CodeGen.zig+4| ... | ... | @@ -8442,6 +8442,10 @@ fn failSymbol(func: *Func, comptime format: []const u8, args: anytype) InnerErro |
| 8442 | 8442 | } |
| 8443 | 8443 | |
| 8444 | 8444 | fn parseRegName(name: []const u8) ?Register { |
| 8445 | // The `fp` alias for `s0` is awkward to fit into the current `Register` scheme, so for now we | |
| 8446 | // special-case it here. | |
| 8447 | if (std.mem.eql(u8, name, "fp")) return .s0; | |
| 8448 | ||
| 8445 | 8449 | return std.meta.stringToEnum(Register, name); |
| 8446 | 8450 | } |
| 8447 | 8451 |
src/clang_options_data.zig+16-2| ... | ... | @@ -2757,7 +2757,14 @@ flagpd1("fast"), |
| 2757 | 2757 | flagpd1("fastcp"), |
| 2758 | 2758 | flagpd1("fastf"), |
| 2759 | 2759 | flagpd1("fasync-exceptions"), |
| 2760 | flagpd1("fasynchronous-unwind-tables"), | |
| 2760 | .{ | |
| 2761 | .name = "fasynchronous-unwind-tables", | |
| 2762 | .syntax = .flag, | |
| 2763 | .zig_equivalent = .asynchronous_unwind_tables, | |
| 2764 | .pd1 = true, | |
| 2765 | .pd2 = false, | |
| 2766 | .psl = false, | |
| 2767 | }, | |
| 2761 | 2768 | flagpd1("fauto-import"), |
| 2762 | 2769 | flagpd1("fauto-profile"), |
| 2763 | 2770 | flagpd1("fauto-profile-accurate"), |
| ... | ... | @@ -3247,7 +3254,14 @@ flagpd1("fno-assume-sane-operator-new"), |
| 3247 | 3254 | flagpd1("fno-assume-unique-vtables"), |
| 3248 | 3255 | flagpd1("fno-assumptions"), |
| 3249 | 3256 | flagpd1("fno-async-exceptions"), |
| 3250 | flagpd1("fno-asynchronous-unwind-tables"), | |
| 3257 | .{ | |
| 3258 | .name = "fno-asynchronous-unwind-tables", | |
| 3259 | .syntax = .flag, | |
| 3260 | .zig_equivalent = .no_asynchronous_unwind_tables, | |
| 3261 | .pd1 = true, | |
| 3262 | .pd2 = false, | |
| 3263 | .psl = false, | |
| 3264 | }, | |
| 3251 | 3265 | flagpd1("fno-auto-import"), |
| 3252 | 3266 | flagpd1("fno-auto-profile"), |
| 3253 | 3267 | flagpd1("fno-auto-profile-accurate"), |
src/codegen/llvm.zig+5-2| ... | ... | @@ -3141,8 +3141,11 @@ pub const Object = struct { |
| 3141 | 3141 | } }, &o.builder); |
| 3142 | 3142 | } |
| 3143 | 3143 | try attributes.addFnAttr(.nounwind, &o.builder); |
| 3144 | if (owner_mod.unwind_tables) { | |
| 3145 | try attributes.addFnAttr(.{ .uwtable = Builder.Attribute.UwTable.default }, &o.builder); | |
| 3144 | if (owner_mod.unwind_tables != .none) { | |
| 3145 | try attributes.addFnAttr( | |
| 3146 | .{ .uwtable = if (owner_mod.unwind_tables == .@"async") .@"async" else .sync }, | |
| 3147 | &o.builder, | |
| 3148 | ); | |
| 3146 | 3149 | } |
| 3147 | 3150 | if (owner_mod.no_builtin) { |
| 3148 | 3151 | // The intent here is for compiler-rt and libc functions to not generate |
src/libcxx.zig+6-3| ... | ... | @@ -397,7 +397,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 397 | 397 | |
| 398 | 398 | const optimize_mode = comp.compilerRtOptMode(); |
| 399 | 399 | const strip = comp.compilerRtStrip(); |
| 400 | const unwind_tables = true; | |
| 401 | 400 | |
| 402 | 401 | const config = Compilation.Config.resolve(.{ |
| 403 | 402 | .output_mode = output_mode, |
| ... | ... | @@ -409,7 +408,6 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 409 | 408 | .root_optimize_mode = optimize_mode, |
| 410 | 409 | .root_strip = strip, |
| 411 | 410 | .link_libc = true, |
| 412 | .any_unwind_tables = unwind_tables, | |
| 413 | 411 | .lto = comp.config.lto, |
| 414 | 412 | .any_sanitize_thread = comp.config.any_sanitize_thread, |
| 415 | 413 | }) catch |err| { |
| ... | ... | @@ -440,7 +438,12 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 440 | 438 | .valgrind = false, |
| 441 | 439 | .optimize_mode = optimize_mode, |
| 442 | 440 | .structured_cfg = comp.root_mod.structured_cfg, |
| 443 | .unwind_tables = unwind_tables, | |
| 441 | // See the `-fno-exceptions` logic for WASI. | |
| 442 | // The old 32-bit x86 variant of SEH doesn't use tables. | |
| 443 | .unwind_tables = if (target.os.tag == .wasi or (target.cpu.arch == .x86 and target.os.tag == .windows)) | |
| 444 | .none | |
| 445 | else | |
| 446 | .@"async", | |
| 444 | 447 | .pic = comp.root_mod.pic, |
| 445 | 448 | }, |
| 446 | 449 | .global = config, |
src/libunwind.zig+2-1| ... | ... | @@ -65,7 +65,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 65 | 65 | .sanitize_c = false, |
| 66 | 66 | .sanitize_thread = false, |
| 67 | 67 | // necessary so that libunwind can unwind through its own stack frames |
| 68 | .unwind_tables = true, | |
| 68 | // The old 32-bit x86 variant of SEH doesn't use tables. | |
| 69 | .unwind_tables = if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async", | |
| 69 | 70 | .pic = if (target_util.supports_fpic(target)) true else null, |
| 70 | 71 | .optimize_mode = comp.compilerRtOptMode(), |
| 71 | 72 | }, |
src/main.zig+46-8| ... | ... | @@ -510,6 +510,7 @@ const usage_build_generic = |
| 510 | 510 | \\ -ffuzz Enable fuzz testing instrumentation |
| 511 | 511 | \\ -fno-fuzz Disable fuzz testing instrumentation |
| 512 | 512 | \\ -funwind-tables Always produce unwind table entries for all functions |
| 513 | \\ -fasync-unwind-tables Always produce asynchronous unwind table entries for all functions | |
| 513 | 514 | \\ -fno-unwind-tables Never produce unwind table entries |
| 514 | 515 | \\ -ferror-tracing Enable error tracing in ReleaseFast mode |
| 515 | 516 | \\ -fno-error-tracing Disable error tracing in Debug and ReleaseSafe mode |
| ... | ... | @@ -1385,9 +1386,11 @@ fn buildOutputType( |
| 1385 | 1386 | } else if (mem.eql(u8, arg, "-fno-lto")) { |
| 1386 | 1387 | create_module.opts.lto = false; |
| 1387 | 1388 | } else if (mem.eql(u8, arg, "-funwind-tables")) { |
| 1388 | mod_opts.unwind_tables = true; | |
| 1389 | mod_opts.unwind_tables = .sync; | |
| 1390 | } else if (mem.eql(u8, arg, "-fasync-unwind-tables")) { | |
| 1391 | mod_opts.unwind_tables = .@"async"; | |
| 1389 | 1392 | } else if (mem.eql(u8, arg, "-fno-unwind-tables")) { |
| 1390 | mod_opts.unwind_tables = false; | |
| 1393 | mod_opts.unwind_tables = .none; | |
| 1391 | 1394 | } else if (mem.eql(u8, arg, "-fstack-check")) { |
| 1392 | 1395 | mod_opts.stack_check = true; |
| 1393 | 1396 | } else if (mem.eql(u8, arg, "-fno-stack-check")) { |
| ... | ... | @@ -1973,8 +1976,27 @@ fn buildOutputType( |
| 1973 | 1976 | } |
| 1974 | 1977 | }, |
| 1975 | 1978 | .no_stack_protector => mod_opts.stack_protector = 0, |
| 1976 | .unwind_tables => mod_opts.unwind_tables = true, | |
| 1977 | .no_unwind_tables => mod_opts.unwind_tables = false, | |
| 1979 | // The way these unwind table options are processed in GCC and Clang is crazy | |
| 1980 | // convoluted, and we also don't know the target triple here, so this is all | |
| 1981 | // best-effort. | |
| 1982 | .unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { | |
| 1983 | .none => { | |
| 1984 | mod_opts.unwind_tables = .sync; | |
| 1985 | }, | |
| 1986 | .sync, .@"async" => {}, | |
| 1987 | } else { | |
| 1988 | mod_opts.unwind_tables = .sync; | |
| 1989 | }, | |
| 1990 | .no_unwind_tables => mod_opts.unwind_tables = .none, | |
| 1991 | .asynchronous_unwind_tables => mod_opts.unwind_tables = .@"async", | |
| 1992 | .no_asynchronous_unwind_tables => if (mod_opts.unwind_tables) |uwt| switch (uwt) { | |
| 1993 | .none, .sync => {}, | |
| 1994 | .@"async" => { | |
| 1995 | mod_opts.unwind_tables = .sync; | |
| 1996 | }, | |
| 1997 | } else { | |
| 1998 | mod_opts.unwind_tables = .sync; | |
| 1999 | }, | |
| 1978 | 2000 | .nostdlib => { |
| 1979 | 2001 | create_module.opts.ensure_libc_on_non_freestanding = false; |
| 1980 | 2002 | create_module.opts.ensure_libcpp_on_non_freestanding = false; |
| ... | ... | @@ -2788,8 +2810,15 @@ fn buildOutputType( |
| 2788 | 2810 | create_module.opts.any_sanitize_thread = true; |
| 2789 | 2811 | if (mod_opts.fuzz == true) |
| 2790 | 2812 | create_module.opts.any_fuzz = true; |
| 2791 | if (mod_opts.unwind_tables == true) | |
| 2792 | create_module.opts.any_unwind_tables = true; | |
| 2813 | if (mod_opts.unwind_tables) |uwt| switch (uwt) { | |
| 2814 | .none => {}, | |
| 2815 | .sync => if (create_module.opts.any_unwind_tables == .none) { | |
| 2816 | create_module.opts.any_unwind_tables = .sync; | |
| 2817 | }, | |
| 2818 | .@"async" => { | |
| 2819 | create_module.opts.any_unwind_tables = .@"async"; | |
| 2820 | }, | |
| 2821 | }; | |
| 2793 | 2822 | if (mod_opts.strip == false) |
| 2794 | 2823 | create_module.opts.any_non_stripped = true; |
| 2795 | 2824 | if (mod_opts.error_tracing == true) |
| ... | ... | @@ -5713,6 +5742,8 @@ pub const ClangArgIterator = struct { |
| 5713 | 5742 | no_lto, |
| 5714 | 5743 | unwind_tables, |
| 5715 | 5744 | no_unwind_tables, |
| 5745 | asynchronous_unwind_tables, | |
| 5746 | no_asynchronous_unwind_tables, | |
| 5716 | 5747 | nostdlib, |
| 5717 | 5748 | nostdlib_cpp, |
| 5718 | 5749 | shared, |
| ... | ... | @@ -7435,8 +7466,15 @@ fn handleModArg( |
| 7435 | 7466 | create_module.opts.any_sanitize_thread = true; |
| 7436 | 7467 | if (mod_opts.fuzz == true) |
| 7437 | 7468 | create_module.opts.any_fuzz = true; |
| 7438 | if (mod_opts.unwind_tables == true) | |
| 7439 | create_module.opts.any_unwind_tables = true; | |
| 7469 | if (mod_opts.unwind_tables) |uwt| switch (uwt) { | |
| 7470 | .none => {}, | |
| 7471 | .sync => if (create_module.opts.any_unwind_tables == .none) { | |
| 7472 | create_module.opts.any_unwind_tables = .sync; | |
| 7473 | }, | |
| 7474 | .@"async" => { | |
| 7475 | create_module.opts.any_unwind_tables = .@"async"; | |
| 7476 | }, | |
| 7477 | }; | |
| 7440 | 7478 | if (mod_opts.strip == false) |
| 7441 | 7479 | create_module.opts.any_non_stripped = true; |
| 7442 | 7480 | if (mod_opts.error_tracing == true) |
src/mingw.zig+13-4| ... | ... | @@ -24,6 +24,10 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre |
| 24 | 24 | var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); |
| 25 | 25 | defer arena_allocator.deinit(); |
| 26 | 26 | const arena = arena_allocator.allocator(); |
| 27 | const target = comp.getTarget(); | |
| 28 | ||
| 29 | // The old 32-bit x86 variant of SEH doesn't use tables. | |
| 30 | const unwind_tables: std.builtin.UnwindTables = if (target.cpu.arch != .x86) .@"async" else .none; | |
| 27 | 31 | |
| 28 | 32 | switch (crt_file) { |
| 29 | 33 | .crt2_o => { |
| ... | ... | @@ -41,7 +45,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre |
| 41 | 45 | .owner = undefined, |
| 42 | 46 | }, |
| 43 | 47 | }; |
| 44 | return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{}); | |
| 48 | return comp.build_crt_file("crt2", .Obj, .@"mingw-w64 crt2.o", prog_node, &files, .{ | |
| 49 | .unwind_tables = unwind_tables, | |
| 50 | }); | |
| 45 | 51 | }, |
| 46 | 52 | |
| 47 | 53 | .dllcrt2_o => { |
| ... | ... | @@ -56,7 +62,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre |
| 56 | 62 | .owner = undefined, |
| 57 | 63 | }, |
| 58 | 64 | }; |
| 59 | return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{}); | |
| 65 | return comp.build_crt_file("dllcrt2", .Obj, .@"mingw-w64 dllcrt2.o", prog_node, &files, .{ | |
| 66 | .unwind_tables = unwind_tables, | |
| 67 | }); | |
| 60 | 68 | }, |
| 61 | 69 | |
| 62 | 70 | .mingw32_lib => { |
| ... | ... | @@ -73,7 +81,6 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre |
| 73 | 81 | .owner = undefined, |
| 74 | 82 | }); |
| 75 | 83 | } |
| 76 | const target = comp.getTarget(); | |
| 77 | 84 | if (target.cpu.arch == .x86 or target.cpu.arch == .x86_64) { |
| 78 | 85 | for (mingw32_x86_src) |dep| { |
| 79 | 86 | try c_source_files.append(.{ |
| ... | ... | @@ -118,7 +125,9 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre |
| 118 | 125 | } else { |
| 119 | 126 | @panic("unsupported arch"); |
| 120 | 127 | } |
| 121 | return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{}); | |
| 128 | return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{ | |
| 129 | .unwind_tables = unwind_tables, | |
| 130 | }); | |
| 122 | 131 | }, |
| 123 | 132 | } |
| 124 | 133 | } |
src/target.zig+11-2| ... | ... | @@ -4,6 +4,7 @@ const assert = std.debug.assert; |
| 4 | 4 | const Type = @import("Type.zig"); |
| 5 | 5 | const AddressSpace = std.builtin.AddressSpace; |
| 6 | 6 | const Alignment = @import("InternPool.zig").Alignment; |
| 7 | const Compilation = @import("Compilation.zig"); | |
| 7 | 8 | const Feature = @import("Zcu.zig").Feature; |
| 8 | 9 | |
| 9 | 10 | pub const default_stack_protector_buffer_size = 4; |
| ... | ... | @@ -408,8 +409,16 @@ pub fn clangSupportsNoImplicitFloatArg(target: std.Target) bool { |
| 408 | 409 | }; |
| 409 | 410 | } |
| 410 | 411 | |
| 411 | pub fn needUnwindTables(target: std.Target) bool { | |
| 412 | return target.os.tag == .windows or target.isDarwin() or std.debug.Dwarf.abi.supportsUnwinding(target); | |
| 412 | pub fn needUnwindTables(target: std.Target, libunwind: bool, libtsan: bool) std.builtin.UnwindTables { | |
| 413 | if (target.os.tag == .windows) { | |
| 414 | // The old 32-bit x86 variant of SEH doesn't use tables. | |
| 415 | return if (target.cpu.arch != .x86) .@"async" else .none; | |
| 416 | } | |
| 417 | if (target.os.tag.isDarwin()) return .@"async"; | |
| 418 | if (libunwind) return .@"async"; | |
| 419 | if (libtsan) return .@"async"; | |
| 420 | if (std.debug.Dwarf.abi.supportsUnwinding(target)) return .@"async"; | |
| 421 | return .none; | |
| 413 | 422 | } |
| 414 | 423 | |
| 415 | 424 | pub fn defaultAddressSpace( |
test/standalone/stack_iterator/build.zig+3-3| ... | ... | @@ -23,7 +23,7 @@ pub fn build(b: *std.Build) void { |
| 23 | 23 | .root_source_file = b.path("unwind.zig"), |
| 24 | 24 | .target = target, |
| 25 | 25 | .optimize = optimize, |
| 26 | .unwind_tables = if (target.result.isDarwin()) true else null, | |
| 26 | .unwind_tables = if (target.result.isDarwin()) .@"async" else null, | |
| 27 | 27 | .omit_frame_pointer = false, |
| 28 | 28 | }); |
| 29 | 29 | |
| ... | ... | @@ -46,7 +46,7 @@ pub fn build(b: *std.Build) void { |
| 46 | 46 | .root_source_file = b.path("unwind.zig"), |
| 47 | 47 | .target = target, |
| 48 | 48 | .optimize = optimize, |
| 49 | .unwind_tables = true, | |
| 49 | .unwind_tables = .@"async", | |
| 50 | 50 | .omit_frame_pointer = true, |
| 51 | 51 | }); |
| 52 | 52 | |
| ... | ... | @@ -85,7 +85,7 @@ pub fn build(b: *std.Build) void { |
| 85 | 85 | .root_source_file = b.path("shared_lib_unwind.zig"), |
| 86 | 86 | .target = target, |
| 87 | 87 | .optimize = optimize, |
| 88 | .unwind_tables = if (target.result.isDarwin()) true else null, | |
| 88 | .unwind_tables = if (target.result.isDarwin()) .@"async" else null, | |
| 89 | 89 | .omit_frame_pointer = true, |
| 90 | 90 | }); |
| 91 | 91 |
tools/update_clang_options.zig+8| ... | ... | @@ -110,6 +110,14 @@ const known_options = [_]KnownOpt{ |
| 110 | 110 | .name = "fno-unwind-tables", |
| 111 | 111 | .ident = "no_unwind_tables", |
| 112 | 112 | }, |
| 113 | .{ | |
| 114 | .name = "fasynchronous-unwind-tables", | |
| 115 | .ident = "asynchronous_unwind_tables", | |
| 116 | }, | |
| 117 | .{ | |
| 118 | .name = "fno-asynchronous-unwind-tables", | |
| 119 | .ident = "no_asynchronous_unwind_tables", | |
| 120 | }, | |
| 113 | 121 | .{ |
| 114 | 122 | .name = "nolibc", |
| 115 | 123 | .ident = "nostdlib", |