From 1eb2e4801448aca29471bf6f7582135ddafb15fe Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 4 Feb 2021 20:51:41 +0700 Subject: [PATCH 1/4] std.debug.StackIterator: account for SPARC %fp quirk On SPARC, previous %fp is saved with a 14 slots offset from current %fp+bias. Also account for the bias constant at the new_fp calculation. --- lib/std/debug.zig | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index a434fe0e8b..b887899c7a 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -366,8 +366,18 @@ pub const StackIterator = struct { // area, on pretty much every other architecture it points to the stack // slot where the previous frame pointer is saved. 2 * @sizeOf(usize) + else if (builtin.arch.isSPARC()) + // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. + 14 * @sizeOf(usize) else 0; + + const fp_bias = if (builtin.arch.isSPARC()) + // On SPARC frame pointers are biased by a constant. + 2047 + else + 0; + // Positive offset of the saved PC wrt the frame pointer. const pc_offset = if (builtin.arch == .powerpc64le) 2 * @sizeOf(usize) @@ -394,7 +404,7 @@ pub const StackIterator = struct { if (fp == 0 or !mem.isAligned(fp, @alignOf(usize))) return null; - const new_fp = @intToPtr(*const usize, fp).*; + const new_fp = math.add(usize, @intToPtr(*const usize, fp).*, fp_bias) catch return null; // Sanity check: the stack grows down thus all the parent frames must be // be at addresses that are greater (or equal) than the previous one. From e3e4af727103d90cb191f130159928d237263e1f Mon Sep 17 00:00:00 2001 From: Koakuma Date: Thu, 4 Feb 2021 20:51:53 +0700 Subject: [PATCH 2/4] stage1: set gen_frame_size alignment to work around requirement mismatch Explicitly set the alignment requirements to 1 (i.e, mark the load as unaligned) since there are some architectures (e.g SPARCv9) which has different alignment requirements between a function pointer and usize pointer. On those architectures, not explicitly setting it will lead into @frameSize generating usize-aligned load instruction that could crash if the function pointer happens to be not usize-aligned. --- src/stage1/codegen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 6aa134c3b0..5236bb26ae 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -4160,7 +4160,9 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { LLVMValueRef casted_fn_val = LLVMBuildBitCast(g->builder, fn_val, ptr_usize_llvm_type, ""); LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true); LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, ""); - return LLVMBuildLoad(g->builder, prefix_ptr, ""); + LLVMValueRef load_inst = LLVMBuildLoad(g->builder, prefix_ptr, ""); + LLVMSetAlignment(load_inst, 1); + return load_inst; } static void gen_init_stack_trace(CodeGen *g, LLVMValueRef trace_field_ptr, LLVMValueRef addrs_field_ptr) { From d23dfdeab9358f0f026990e4d0f1da0ddaa6b177 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 5 Feb 2021 00:25:01 +0700 Subject: [PATCH 3/4] Add comment explaining the alignment setting --- src/stage1/codegen.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 5236bb26ae..71a22ce79b 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -4161,6 +4161,12 @@ static LLVMValueRef gen_frame_size(CodeGen *g, LLVMValueRef fn_val) { LLVMValueRef negative_one = LLVMConstInt(LLVMInt32Type(), -1, true); LLVMValueRef prefix_ptr = LLVMBuildInBoundsGEP(g->builder, casted_fn_val, &negative_one, 1, ""); LLVMValueRef load_inst = LLVMBuildLoad(g->builder, prefix_ptr, ""); + + // Some architectures (e.g SPARCv9) has different alignment requirements between a + // function/usize pointer and also require all loads to be aligned. + // On those architectures, not explicitly setting the alignment will lead into @frameSize + // generating usize-aligned load instruction that could crash if the function pointer + // happens to be not usize-aligned. LLVMSetAlignment(load_inst, 1); return load_inst; } From 448a28325c7517e6cd62ba7932a4b6c836250757 Mon Sep 17 00:00:00 2001 From: Koakuma Date: Fri, 5 Feb 2021 00:28:07 +0700 Subject: [PATCH 4/4] Fix previous %fp calculation --- lib/std/debug.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index b887899c7a..9d90dd5c4b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -360,7 +360,7 @@ pub const StackIterator = struct { }; } - // Negative offset of the saved BP wrt the frame pointer. + // Offset of the saved BP wrt the frame pointer. const fp_offset = if (builtin.arch.isRISCV()) // On RISC-V the frame pointer points to the top of the saved register // area, on pretty much every other architecture it points to the stack @@ -398,7 +398,11 @@ pub const StackIterator = struct { } fn next_internal(self: *StackIterator) ?usize { - const fp = math.sub(usize, self.fp, fp_offset) catch return null; + const fp = if (builtin.arch.isSPARC()) + // On SPARC the offset is positive. (!) + math.add(usize, self.fp, fp_offset) catch return null + else + math.sub(usize, self.fp, fp_offset) catch return null; // Sanity check. if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))