commit e02655798fbd97a069ee8be38a6eceac18335a4d (tree)
parent e6ac082437b87fccf6a7e592f813d3403427e512
Author: Andrew Kelley <andrew@ziglang.org>
Date: Thu, 22 Oct 2020 17:39:26 -0400
Merge pull request #6743 from LemonBoy/someppc64stuff
Some ppc64 stuff
Diffstat:
5 files changed, 54 insertions(+), 35 deletions(-)
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
@@ -327,9 +327,9 @@ pub fn writeStackTrace(
}
pub const StackIterator = struct {
- // Skip every frame before this address is found
+ // Skip every frame before this address is found.
first_address: ?usize,
- // Last known value of the frame pointer register
+ // Last known value of the frame pointer register.
fp: usize,
pub fn init(first_address: ?usize, fp: ?usize) StackIterator {
@@ -339,14 +339,19 @@ pub const StackIterator = struct {
};
}
- // On some architectures such as x86 the frame pointer is the address where
- // the previous fp is stored, while on some other architectures such as
- // RISC-V it points to the "top" of the frame, just above where the previous
- // fp and the return address are stored.
+ // Negative 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
+ // slot where the previous frame pointer is saved.
2 * @sizeOf(usize)
else
0;
+ // Positive offset of the saved PC wrt the frame pointer.
+ const pc_offset = if (builtin.arch == .powerpc64le)
+ 2 * @sizeOf(usize)
+ else
+ @sizeOf(usize);
pub fn next(self: *StackIterator) ?usize {
var address = self.next_internal() orelse return null;
@@ -364,7 +369,7 @@ pub const StackIterator = struct {
fn next_internal(self: *StackIterator) ?usize {
const fp = math.sub(usize, self.fp, fp_offset) catch return null;
- // Sanity check
+ // Sanity check.
if (fp == 0 or !mem.isAligned(fp, @alignOf(usize)))
return null;
@@ -373,11 +378,14 @@ pub const StackIterator = struct {
// 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.
// A zero frame pointer often signals this is the last frame, that case
- // is gracefully handled by the next call to next_internal
+ // is gracefully handled by the next call to next_internal.
if (new_fp != 0 and new_fp < self.fp)
return null;
- const new_pc = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
+ const new_pc = @intToPtr(
+ *const usize,
+ math.add(usize, fp, pc_offset) catch return null,
+ ).*;
self.fp = new_fp;
diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig
@@ -29,6 +29,7 @@ pub usingnamespace @import("linux/prctl.zig");
pub usingnamespace @import("linux/securebits.zig");
const is_mips = builtin.arch.isMIPS();
+const is_ppc64 = builtin.arch.isPPC64();
pub const pid_t = i32;
pub const fd_t = i32;
@@ -540,8 +541,8 @@ pub const TIOCGPGRP = 0x540F;
pub const TIOCSPGRP = 0x5410;
pub const TIOCOUTQ = if (is_mips) 0x7472 else 0x5411;
pub const TIOCSTI = 0x5412;
-pub const TIOCGWINSZ = if (is_mips) 0x40087468 else 0x5413;
-pub const TIOCSWINSZ = if (is_mips) 0x80087467 else 0x5414;
+pub const TIOCGWINSZ = if (is_mips or is_ppc64) 0x40087468 else 0x5413;
+pub const TIOCSWINSZ = if (is_mips or is_ppc64) 0x80087467 else 0x5414;
pub const TIOCMGET = 0x5415;
pub const TIOCMBIS = 0x5416;
pub const TIOCMBIC = 0x5417;
diff --git a/lib/std/start.zig b/lib/std/start.zig
@@ -102,46 +102,49 @@ fn _start() callconv(.Naked) noreturn {
switch (builtin.arch) {
.x86_64 => {
- starting_stack_ptr = asm (""
+ starting_stack_ptr = asm volatile (
+ \\ xor %%rbp, %%rbp
: [argc] "={rsp}" (-> [*]usize)
);
},
.i386 => {
- starting_stack_ptr = asm (""
+ starting_stack_ptr = asm volatile (
+ \\ xor %%ebp, %%ebp
: [argc] "={esp}" (-> [*]usize)
);
},
- .aarch64, .aarch64_be, .arm => {
- starting_stack_ptr = asm ("mov %[argc], sp"
- : [argc] "=r" (-> [*]usize)
+ .aarch64, .aarch64_be, .arm, .armeb => {
+ starting_stack_ptr = asm volatile (
+ \\ mov fp, #0
+ \\ mov lr, #0
+ : [argc] "={sp}" (-> [*]usize)
);
},
.riscv64 => {
- starting_stack_ptr = asm ("mv %[argc], sp"
- : [argc] "=r" (-> [*]usize)
+ starting_stack_ptr = asm volatile (
+ \\ li s0, 0
+ \\ li ra, 0
+ : [argc] "={sp}" (-> [*]usize)
);
},
.mips, .mipsel => {
- // Need noat here because LLVM is free to pick any register
- starting_stack_ptr = asm (
- \\ .set noat
- \\ move %[argc], $sp
- : [argc] "=r" (-> [*]usize)
+ // The lr is already zeroed on entry, as specified by the ABI.
+ starting_stack_ptr = asm volatile (
+ \\ move $fp, $0
+ : [argc] "={sp}" (-> [*]usize)
);
},
.powerpc64le => {
- // Before returning the stack pointer, we have to set up a backchain
- // and a few other registers required by the ELFv2 ABI.
+ // Setup the initial stack frame and clear the back chain pointer.
// TODO: Support powerpc64 (big endian) on ELFv2.
- starting_stack_ptr = asm (
+ starting_stack_ptr = asm volatile (
\\ mr 4, 1
- \\ subi 1, 1, 32
- \\ li 5, 0
- \\ std 5, 0(1)
- \\ mr %[argc], 4
- : [argc] "=r" (-> [*]usize)
+ \\ li 0, 0
+ \\ stdu 0, -32(1)
+ \\ mtlr 0
+ : [argc] "={r4}" (-> [*]usize)
:
- : "r4", "r5"
+ : "r0"
);
},
else => @compileError("unsupported arch"),
diff --git a/lib/std/target.zig b/lib/std/target.zig
@@ -754,6 +754,13 @@ pub const Target = struct {
};
}
+ pub fn isPPC64(arch: Arch) bool {
+ return switch (arch) {
+ .powerpc64, .powerpc64le => true,
+ else => false,
+ };
+ }
+
pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
for (arch.allCpuModels()) |cpu| {
if (mem.eql(u8, cpu_name, cpu.name)) {
diff --git a/test/stack_traces.zig b/test/stack_traces.zig
@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\source.zig:10:8: [address] in main (test)
\\ foo();
\\ ^
- \\start.zig:319:29: [address] in std.start.posixCallMainAndExit (test)
+ \\start.zig:322:29: [address] in std.start.posixCallMainAndExit (test)
\\ return root.main();
\\ ^
- \\start.zig:151:5: [address] in std.start._start (test)
+ \\start.zig:154:5: [address] in std.start._start (test)
\\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
\\ ^
\\
@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
switch (std.Target.current.cpu.arch) {
.aarch64 => "", // TODO disabled; results in segfault
else =>
- \\start.zig:151:5: [address] in std.start._start (test)
+ \\start.zig:154:5: [address] in std.start._start (test)
\\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
\\ ^
\\