diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/std/debug.zig | 26 | ||||
| -rw-r--r-- | lib/std/os/bits/linux.zig | 5 | ||||
| -rw-r--r-- | lib/std/start.zig | 45 | ||||
| -rw-r--r-- | lib/std/target.zig | 7 |
4 files changed, 51 insertions, 32 deletions
diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 84d1e8155b..fb1ae69f09 100644 --- 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 index 6f2c68b63b..19cc3be775 100644 --- 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 index b8e0de9574..c6f05e790c 100644 --- 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 index e7cb931c0c..7fbac8a4be 100644 --- 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)) { |
