Skip to content

Commit 7342017

Browse files
authored
Merge pull request #20822 from alexrp/start-mips-fixes
`start`: A handful of MIPS fixes
2 parents 19e4de1 + d633b35 commit 7342017

File tree

1 file changed

+35
-6
lines changed

1 file changed

+35
-6
lines changed

lib/std/start.zig

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -289,17 +289,42 @@ fn _start() callconv(.Naked) noreturn {
289289
,
290290
.mips, .mipsel =>
291291
\\ move $fp, $0
292+
\\ bal 1f
293+
\\ .gpword .
294+
\\ .gpword %[posixCallMainAndExit]
295+
\\ 1:
296+
\\ lw $gp, 0($ra)
297+
\\ subu $gp, $ra, $gp
298+
\\ lw $25, 4($ra)
299+
\\ addu $25, $25, $gp
292300
\\ move $ra, $0
293301
\\ move $a0, $sp
294302
\\ and $sp, -8
295-
\\ j %[posixCallMainAndExit]
303+
\\ subu $sp, $sp, 16
304+
\\ jalr $25
296305
,
297306
.mips64, .mips64el =>
298307
\\ move $fp, $0
308+
// This is needed because early MIPS versions don't support misaligned loads. Without
309+
// this directive, the hidden `nop` inserted to fill the delay slot after `bal` would
310+
// cause the two doublewords to be aligned to 4 bytes instead of 8.
311+
\\ .balign 8
312+
\\ bal 1f
313+
\\ .gpdword .
314+
\\ .gpdword %[posixCallMainAndExit]
315+
\\ 1:
316+
// The `gp` register on MIPS serves a similar purpose to `r2` (ToC pointer) on PPC64.
317+
// We need to set it up in order for dynamically-linked / position-independent code to
318+
// work.
319+
\\ ld $gp, 0($ra)
320+
\\ dsubu $gp, $ra, $gp
321+
\\ ld $25, 8($ra)
322+
\\ daddu $25, $25, $gp
299323
\\ move $ra, $0
300324
\\ move $a0, $sp
301325
\\ and $sp, -16
302-
\\ j %[posixCallMainAndExit]
326+
\\ dsubu $sp, $sp, 16
327+
\\ jalr $25
303328
,
304329
.powerpc, .powerpcle =>
305330
// Set up the initial stack frame, and clear the back chain pointer.
@@ -389,7 +414,6 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {
389414
if (native_os == .linux) {
390415
// Find the beginning of the auxiliary vector
391416
const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1));
392-
std.os.linux.elf_aux_maybe = auxv;
393417

394418
var at_hwcap: usize = 0;
395419
const phdrs = init: {
@@ -407,12 +431,17 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn {
407431
break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum];
408432
};
409433

410-
// Apply the initial relocations as early as possible in the startup
411-
// process.
434+
// Apply the initial relocations as early as possible in the startup process. We cannot
435+
// make calls yet on some architectures (e.g. MIPS) *because* they haven't been applied yet,
436+
// so this must be fully inlined.
412437
if (builtin.position_independent_executable) {
413-
std.os.linux.pie.relocate(phdrs);
438+
@call(.always_inline, std.os.linux.pie.relocate, .{phdrs});
414439
}
415440

441+
// This must be done after PIE relocations have been applied or we may crash
442+
// while trying to access the global variable (happens on MIPS at least).
443+
std.os.linux.elf_aux_maybe = auxv;
444+
416445
if (!builtin.single_threaded) {
417446
// ARMv6 targets (and earlier) have no support for TLS in hardware.
418447
// FIXME: Elide the check for targets >= ARMv7 when the target feature API

0 commit comments

Comments
 (0)