| ... | ... | @@ -289,17 +289,42 @@ fn _start() callconv(.Naked) noreturn { |
| 289 | 289 | , |
| 290 | 290 | .mips, .mipsel => |
| 291 | 291 | \\ 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 |
| 292 | 300 | \\ move $ra, $0 |
| 293 | 301 | \\ move $a0, $sp |
| 294 | 302 | \\ and $sp, -8 |
| 295 | | \\ j %[posixCallMainAndExit] |
| 303 | \\ subu $sp, $sp, 16 |
| 304 | \\ jalr $25 |
| 296 | 305 | , |
| 297 | 306 | .mips64, .mips64el => |
| 298 | 307 | \\ 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 |
| 299 | 323 | \\ move $ra, $0 |
| 300 | 324 | \\ move $a0, $sp |
| 301 | 325 | \\ and $sp, -16 |
| 302 | | \\ j %[posixCallMainAndExit] |
| 326 | \\ dsubu $sp, $sp, 16 |
| 327 | \\ jalr $25 |
| 303 | 328 | , |
| 304 | 329 | .powerpc, .powerpcle => |
| 305 | 330 | // 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 { |
| 389 | 414 | if (native_os == .linux) { |
| 390 | 415 | // Find the beginning of the auxiliary vector |
| 391 | 416 | const auxv: [*]elf.Auxv = @ptrCast(@alignCast(envp.ptr + envp_count + 1)); |
| 392 | | std.os.linux.elf_aux_maybe = auxv; |
| 393 | 417 | |
| 394 | 418 | var at_hwcap: usize = 0; |
| 395 | 419 | const phdrs = init: { |
| ... | ... | @@ -407,12 +431,17 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.C) noreturn { |
| 407 | 431 | break :init @as([*]elf.Phdr, @ptrFromInt(at_phdr))[0..at_phnum]; |
| 408 | 432 | }; |
| 409 | 433 | |
| 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. |
| 412 | 437 | if (builtin.position_independent_executable) { |
| 413 | | std.os.linux.pie.relocate(phdrs); |
| 438 | @call(.always_inline, std.os.linux.pie.relocate, .{phdrs}); |
| 414 | 439 | } |
| 415 | 440 | |
| 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 | |
| 416 | 445 | if (!builtin.single_threaded) { |
| 417 | 446 | // ARMv6 targets (and earlier) have no support for TLS in hardware. |
| 418 | 447 | // FIXME: Elide the check for targets >= ARMv7 when the target feature API |