| author | |
| committer | |
| log | 817fa3af8631d894004fbdb668da0882836dbe9b |
| tree | 3e63751b5ebb46fe8c45eca41a5248075d97bda8 |
| parent | 43b830415368ac4fb08bf5e154a222a38baf4a24 |
After fixing some issues with inline assembly in the C backend, the std
cleanups have the side effect of making these functions compatible with
the backend, allowing it to be used on linux without linking libc.10 files changed, 278 insertions(+), 222 deletions(-)
lib/std/Thread.zig+8-6| ... | ... | @@ -1275,12 +1275,14 @@ const LinuxThreadImpl = struct { |
| 1275 | 1275 | .entry_number = os.linux.tls.tls_image.gdt_entry_number, |
| 1276 | 1276 | .base_addr = tls_ptr, |
| 1277 | 1277 | .limit = 0xfffff, |
| 1278 | .seg_32bit = 1, | |
| 1279 | .contents = 0, // Data | |
| 1280 | .read_exec_only = 0, | |
| 1281 | .limit_in_pages = 1, | |
| 1282 | .seg_not_present = 0, | |
| 1283 | .useable = 1, | |
| 1278 | .flags = .{ | |
| 1279 | .seg_32bit = 1, | |
| 1280 | .contents = 0, // Data | |
| 1281 | .read_exec_only = 0, | |
| 1282 | .limit_in_pages = 1, | |
| 1283 | .seg_not_present = 0, | |
| 1284 | .useable = 1, | |
| 1285 | }, | |
| 1284 | 1286 | }; |
| 1285 | 1287 | } |
| 1286 | 1288 |
lib/std/os/linux/arm-eabi.zig+26-2| ... | ... | @@ -104,7 +104,19 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8; |
| 104 | 104 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; |
| 105 | 105 | |
| 106 | 106 | pub fn restore() callconv(.Naked) void { |
| 107 | return asm volatile ("svc #0" | |
| 107 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 108 | asm volatile ( | |
| 109 | \\ mov r7, %[number] | |
| 110 | \\ svc #0 | |
| 111 | \\ bx lr | |
| 112 | : | |
| 113 | : [number] "i" (@intFromEnum(SYS.sigreturn)), | |
| 114 | : "memory" | |
| 115 | ); | |
| 116 | unreachable; | |
| 117 | } | |
| 118 | ||
| 119 | asm volatile ("svc #0" | |
| 108 | 120 | : |
| 109 | 121 | : [number] "{r7}" (@intFromEnum(SYS.sigreturn)), |
| 110 | 122 | : "memory" |
| ... | ... | @@ -112,7 +124,19 @@ pub fn restore() callconv(.Naked) void { |
| 112 | 124 | } |
| 113 | 125 | |
| 114 | 126 | pub fn restore_rt() callconv(.Naked) void { |
| 115 | return asm volatile ("svc #0" | |
| 127 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 128 | asm volatile ( | |
| 129 | \\ mov r7, %[number] | |
| 130 | \\ svc #0 | |
| 131 | \\ bx lr | |
| 132 | : | |
| 133 | : [number] "i" (@intFromEnum(SYS.rt_sigreturn)), | |
| 134 | : "memory" | |
| 135 | ); | |
| 136 | unreachable; | |
| 137 | } | |
| 138 | ||
| 139 | asm volatile ("svc #0" | |
| 116 | 140 | : |
| 117 | 141 | : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)), |
| 118 | 142 | : "memory" |
lib/std/os/linux/arm64.zig+12-8| ... | ... | @@ -106,20 +106,24 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: * |
| 106 | 106 | pub const restore = restore_rt; |
| 107 | 107 | |
| 108 | 108 | pub fn restore_rt() callconv(.Naked) void { |
| 109 | switch (@import("builtin").zig_backend) { | |
| 110 | .stage2_c => return asm volatile ( | |
| 109 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 110 | asm volatile ( | |
| 111 | 111 | \\ mov x8, %[number] |
| 112 | 112 | \\ svc #0 |
| 113 | \\ ret | |
| 113 | 114 | : |
| 114 | 115 | : [number] "i" (@intFromEnum(SYS.rt_sigreturn)), |
| 115 | 116 | : "memory", "cc" |
| 116 | ), | |
| 117 | else => return asm volatile ("svc #0" | |
| 118 | : | |
| 119 | : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 120 | : "memory", "cc" | |
| 121 | ), | |
| 117 | ); | |
| 118 | unreachable; | |
| 122 | 119 | } |
| 120 | ||
| 121 | asm volatile ( | |
| 122 | \\ svc #0 | |
| 123 | : | |
| 124 | : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 125 | : "memory", "cc" | |
| 126 | ); | |
| 123 | 127 | } |
| 124 | 128 | |
| 125 | 129 | pub const O = struct { |
lib/std/os/linux/tls.zig+8-6| ... | ... | @@ -115,12 +115,14 @@ pub fn setThreadPointer(addr: usize) void { |
| 115 | 115 | .entry_number = tls_image.gdt_entry_number, |
| 116 | 116 | .base_addr = addr, |
| 117 | 117 | .limit = 0xfffff, |
| 118 | .seg_32bit = 1, | |
| 119 | .contents = 0, // Data | |
| 120 | .read_exec_only = 0, | |
| 121 | .limit_in_pages = 1, | |
| 122 | .seg_not_present = 0, | |
| 123 | .useable = 1, | |
| 118 | .flags = .{ | |
| 119 | .seg_32bit = 1, | |
| 120 | .contents = 0, // Data | |
| 121 | .read_exec_only = 0, | |
| 122 | .limit_in_pages = 1, | |
| 123 | .seg_not_present = 0, | |
| 124 | .useable = 1, | |
| 125 | }, | |
| 124 | 126 | }; |
| 125 | 127 | const rc = std.os.linux.syscall1(.set_thread_area, @intFromPtr(&user_desc)); |
| 126 | 128 | assert(rc == 0); |
lib/std/os/linux/x86.zig+76-71| ... | ... | @@ -124,45 +124,45 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8; |
| 124 | 124 | pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; |
| 125 | 125 | |
| 126 | 126 | pub fn restore() callconv(.Naked) void { |
| 127 | switch (@import("builtin").zig_backend) { | |
| 128 | .stage2_c => asm volatile ( | |
| 127 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 128 | asm volatile ( | |
| 129 | 129 | \\ movl %[number], %%eax |
| 130 | 130 | \\ int $0x80 |
| 131 | \\ ret | |
| 131 | \\ retl | |
| 132 | 132 | : |
| 133 | 133 | : [number] "i" (@intFromEnum(SYS.sigreturn)), |
| 134 | 134 | : "memory" |
| 135 | ), | |
| 136 | else => asm volatile ( | |
| 137 | \\ int $0x80 | |
| 138 | \\ ret | |
| 139 | : | |
| 140 | : [number] "{eax}" (@intFromEnum(SYS.sigreturn)), | |
| 141 | : "memory" | |
| 142 | ), | |
| 135 | ); | |
| 136 | unreachable; | |
| 143 | 137 | } |
| 144 | unreachable; | |
| 138 | ||
| 139 | asm volatile ( | |
| 140 | \\ int $0x80 | |
| 141 | : | |
| 142 | : [number] "{eax}" (@intFromEnum(SYS.sigreturn)), | |
| 143 | : "memory" | |
| 144 | ); | |
| 145 | 145 | } |
| 146 | 146 | |
| 147 | 147 | pub fn restore_rt() callconv(.Naked) void { |
| 148 | switch (@import("builtin").zig_backend) { | |
| 149 | .stage2_c => asm volatile ( | |
| 148 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 149 | asm volatile ( | |
| 150 | 150 | \\ movl %[number], %%eax |
| 151 | 151 | \\ int $0x80 |
| 152 | \\ ret | |
| 152 | \\ retl | |
| 153 | 153 | : |
| 154 | 154 | : [number] "i" (@intFromEnum(SYS.rt_sigreturn)), |
| 155 | 155 | : "memory" |
| 156 | ), | |
| 157 | else => asm volatile ( | |
| 158 | \\ int $0x80 | |
| 159 | \\ ret | |
| 160 | : | |
| 161 | : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 162 | : "memory" | |
| 163 | ), | |
| 156 | ); | |
| 157 | unreachable; | |
| 164 | 158 | } |
| 165 | unreachable; | |
| 159 | ||
| 160 | asm volatile ( | |
| 161 | \\ int $0x80 | |
| 162 | : | |
| 163 | : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 164 | : "memory" | |
| 165 | ); | |
| 166 | 166 | } |
| 167 | 167 | |
| 168 | 168 | pub const O = struct { |
| ... | ... | @@ -354,16 +354,19 @@ pub const ucontext_t = extern struct { |
| 354 | 354 | |
| 355 | 355 | pub const Elf_Symndx = u32; |
| 356 | 356 | |
| 357 | pub const user_desc = packed struct { | |
| 357 | pub const user_desc = extern struct { | |
| 358 | 358 | entry_number: u32, |
| 359 | 359 | base_addr: u32, |
| 360 | 360 | limit: u32, |
| 361 | seg_32bit: u1, | |
| 362 | contents: u2, | |
| 363 | read_exec_only: u1, | |
| 364 | limit_in_pages: u1, | |
| 365 | seg_not_present: u1, | |
| 366 | useable: u1, | |
| 361 | flags: packed struct(u32) { | |
| 362 | seg_32bit: u1, | |
| 363 | contents: u2, | |
| 364 | read_exec_only: u1, | |
| 365 | limit_in_pages: u1, | |
| 366 | seg_not_present: u1, | |
| 367 | useable: u1, | |
| 368 | _: u25 = undefined, | |
| 369 | }, | |
| 367 | 370 | }; |
| 368 | 371 | |
| 369 | 372 | /// socketcall() call numbers |
| ... | ... | @@ -400,63 +403,63 @@ noinline fn getContextReturnAddress() usize { |
| 400 | 403 | |
| 401 | 404 | pub fn getContextInternal() callconv(.Naked) void { |
| 402 | 405 | asm volatile ( |
| 403 | \\ movl $0, (%[flags_offset])(%%edx) | |
| 404 | \\ movl $0, (%[link_offset])(%%edx) | |
| 405 | \\ movl %%edi, (%[edi_offset])(%%edx) | |
| 406 | \\ movl %%esi, (%[esi_offset])(%%edx) | |
| 407 | \\ movl %%ebp, (%[ebp_offset])(%%edx) | |
| 408 | \\ movl %%ebx, (%[ebx_offset])(%%edx) | |
| 409 | \\ movl %%edx, (%[edx_offset])(%%edx) | |
| 410 | \\ movl %%ecx, (%[ecx_offset])(%%edx) | |
| 411 | \\ movl %%eax, (%[eax_offset])(%%edx) | |
| 406 | \\ movl $0, %[flags_offset:c](%%edx) | |
| 407 | \\ movl $0, %[link_offset:c](%%edx) | |
| 408 | \\ movl %%edi, %[edi_offset:c](%%edx) | |
| 409 | \\ movl %%esi, %[esi_offset:c](%%edx) | |
| 410 | \\ movl %%ebp, %[ebp_offset:c](%%edx) | |
| 411 | \\ movl %%ebx, %[ebx_offset:c](%%edx) | |
| 412 | \\ movl %%edx, %[edx_offset:c](%%edx) | |
| 413 | \\ movl %%ecx, %[ecx_offset:c](%%edx) | |
| 414 | \\ movl %%eax, %[eax_offset:c](%%edx) | |
| 412 | 415 | \\ movl (%%esp), %%ecx |
| 413 | \\ movl %%ecx, (%[eip_offset])(%%edx) | |
| 416 | \\ movl %%ecx, %[eip_offset:c](%%edx) | |
| 414 | 417 | \\ leal 4(%%esp), %%ecx |
| 415 | \\ movl %%ecx, (%[esp_offset])(%%edx) | |
| 418 | \\ movl %%ecx, %[esp_offset:c](%%edx) | |
| 416 | 419 | \\ xorl %%ecx, %%ecx |
| 417 | 420 | \\ movw %%fs, %%cx |
| 418 | \\ movl %%ecx, (%[fs_offset])(%%edx) | |
| 419 | \\ leal (%[regspace_offset])(%%edx), %%ecx | |
| 420 | \\ movl %%ecx, (%[fpregs_offset])(%%edx) | |
| 421 | \\ movl %%ecx, %[fs_offset:c](%%edx) | |
| 422 | \\ leal %[regspace_offset:c](%%edx), %%ecx | |
| 423 | \\ movl %%ecx, %[fpregs_offset:c](%%edx) | |
| 421 | 424 | \\ fnstenv (%%ecx) |
| 422 | 425 | \\ fldenv (%%ecx) |
| 423 | 426 | \\ pushl %%ebx |
| 424 | 427 | \\ pushl %%esi |
| 425 | 428 | \\ xorl %%ebx, %%ebx |
| 426 | 429 | \\ movl %[sigaltstack], %%eax |
| 427 | \\ leal (%[stack_offset])(%%edx), %%ecx | |
| 430 | \\ leal %[stack_offset:c](%%edx), %%ecx | |
| 428 | 431 | \\ int $0x80 |
| 429 | \\ cmpl $0, %%eax | |
| 430 | \\ jne return | |
| 432 | \\ testl %%eax, %%eax | |
| 433 | \\ jnz 0f | |
| 431 | 434 | \\ movl %[sigprocmask], %%eax |
| 432 | 435 | \\ xorl %%ecx, %%ecx |
| 433 | \\ leal (%[sigmask_offset])(%%edx), %%edx | |
| 436 | \\ leal %[sigmask_offset:c](%%edx), %%edx | |
| 434 | 437 | \\ movl %[sigset_size], %%esi |
| 435 | 438 | \\ int $0x80 |
| 436 | \\ return: | |
| 439 | \\0: | |
| 437 | 440 | \\ popl %%esi |
| 438 | 441 | \\ popl %%ebx |
| 439 | 442 | : |
| 440 | : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")), | |
| 441 | [link_offset] "p" (@offsetOf(ucontext_t, "link")), | |
| 442 | [edi_offset] "p" (comptime gpRegisterOffset(REG.EDI)), | |
| 443 | [esi_offset] "p" (comptime gpRegisterOffset(REG.ESI)), | |
| 444 | [ebp_offset] "p" (comptime gpRegisterOffset(REG.EBP)), | |
| 445 | [esp_offset] "p" (comptime gpRegisterOffset(REG.ESP)), | |
| 446 | [ebx_offset] "p" (comptime gpRegisterOffset(REG.EBX)), | |
| 447 | [edx_offset] "p" (comptime gpRegisterOffset(REG.EDX)), | |
| 448 | [ecx_offset] "p" (comptime gpRegisterOffset(REG.ECX)), | |
| 449 | [eax_offset] "p" (comptime gpRegisterOffset(REG.EAX)), | |
| 450 | [eip_offset] "p" (comptime gpRegisterOffset(REG.EIP)), | |
| 451 | [fs_offset] "p" (comptime gpRegisterOffset(REG.FS)), | |
| 452 | [fpregs_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | |
| 453 | [regspace_offset] "p" (@offsetOf(ucontext_t, "regspace")), | |
| 443 | : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")), | |
| 444 | [link_offset] "i" (@offsetOf(ucontext_t, "link")), | |
| 445 | [edi_offset] "i" (comptime gpRegisterOffset(REG.EDI)), | |
| 446 | [esi_offset] "i" (comptime gpRegisterOffset(REG.ESI)), | |
| 447 | [ebp_offset] "i" (comptime gpRegisterOffset(REG.EBP)), | |
| 448 | [esp_offset] "i" (comptime gpRegisterOffset(REG.ESP)), | |
| 449 | [ebx_offset] "i" (comptime gpRegisterOffset(REG.EBX)), | |
| 450 | [edx_offset] "i" (comptime gpRegisterOffset(REG.EDX)), | |
| 451 | [ecx_offset] "i" (comptime gpRegisterOffset(REG.ECX)), | |
| 452 | [eax_offset] "i" (comptime gpRegisterOffset(REG.EAX)), | |
| 453 | [eip_offset] "i" (comptime gpRegisterOffset(REG.EIP)), | |
| 454 | [fs_offset] "i" (comptime gpRegisterOffset(REG.FS)), | |
| 455 | [fpregs_offset] "i" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | |
| 456 | [regspace_offset] "i" (@offsetOf(ucontext_t, "regspace")), | |
| 454 | 457 | [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)), |
| 455 | [stack_offset] "p" (@offsetOf(ucontext_t, "stack")), | |
| 458 | [stack_offset] "i" (@offsetOf(ucontext_t, "stack")), | |
| 456 | 459 | [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)), |
| 457 | [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")), | |
| 460 | [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")), | |
| 458 | 461 | [sigset_size] "i" (linux.NSIG / 8), |
| 459 | : "memory", "eax", "ecx", "edx" | |
| 462 | : "cc", "memory", "eax", "ecx", "edx" | |
| 460 | 463 | ); |
| 461 | 464 | } |
| 462 | 465 | |
| ... | ... | @@ -464,11 +467,13 @@ pub inline fn getcontext(context: *ucontext_t) usize { |
| 464 | 467 | // This method is used so that getContextInternal can control |
| 465 | 468 | // its prologue in order to read ESP from a constant offset. |
| 466 | 469 | // The unused &getContextInternal input is required so the function is included in the binary. |
| 470 | var clobber_edx: usize = undefined; | |
| 467 | 471 | return asm volatile ( |
| 468 | \\ call os.linux.x86.getContextInternal | |
| 469 | : [ret] "={eax}" (-> usize), | |
| 470 | : [context] "{edx}" (context), | |
| 472 | \\ calll %[getContextInternal:P] | |
| 473 | : [_] "={eax}" (-> usize), | |
| 474 | [_] "={edx}" (clobber_edx), | |
| 475 | : [_] "{edx}" (context), | |
| 471 | 476 | [getContextInternal] "X" (&getContextInternal), |
| 472 | : "memory", "ecx" | |
| 477 | : "cc", "memory", "ecx" | |
| 473 | 478 | ); |
| 474 | 479 | } |
lib/std/os/linux/x86_64.zig+74-72| ... | ... | @@ -108,24 +108,24 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: |
| 108 | 108 | pub const restore = restore_rt; |
| 109 | 109 | |
| 110 | 110 | pub fn restore_rt() callconv(.Naked) void { |
| 111 | switch (@import("builtin").zig_backend) { | |
| 112 | .stage2_c => asm volatile ( | |
| 111 | if (@import("builtin").zig_backend == .stage2_c) { | |
| 112 | asm volatile ( | |
| 113 | 113 | \\ movl %[number], %%eax |
| 114 | 114 | \\ syscall |
| 115 | 115 | \\ retq |
| 116 | 116 | : |
| 117 | 117 | : [number] "i" (@intFromEnum(SYS.rt_sigreturn)), |
| 118 | 118 | : "rcx", "r11", "memory" |
| 119 | ), | |
| 120 | else => asm volatile ( | |
| 121 | \\ syscall | |
| 122 | \\ retq | |
| 123 | : | |
| 124 | : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 125 | : "rcx", "r11", "memory" | |
| 126 | ), | |
| 119 | ); | |
| 120 | unreachable; | |
| 127 | 121 | } |
| 128 | unreachable; | |
| 122 | ||
| 123 | asm volatile ( | |
| 124 | \\ syscall | |
| 125 | : | |
| 126 | : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)), | |
| 127 | : "rcx", "r11", "memory" | |
| 128 | ); | |
| 129 | 129 | } |
| 130 | 130 | |
| 131 | 131 | pub const mode_t = usize; |
| ... | ... | @@ -403,77 +403,77 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize { |
| 403 | 403 | fn getContextInternal() callconv(.Naked) void { |
| 404 | 404 | // TODO: Read GS/FS registers? |
| 405 | 405 | asm volatile ( |
| 406 | \\ movq $0, (%[flags_offset])(%%rdi) | |
| 407 | \\ movq $0, (%[link_offset])(%%rdi) | |
| 408 | \\ movq %%r8, (%[r8_offset])(%%rdi) | |
| 409 | \\ movq %%r9, (%[r9_offset])(%%rdi) | |
| 410 | \\ movq %%r10, (%[r10_offset])(%%rdi) | |
| 411 | \\ movq %%r11, (%[r11_offset])(%%rdi) | |
| 412 | \\ movq %%r12, (%[r12_offset])(%%rdi) | |
| 413 | \\ movq %%r13, (%[r13_offset])(%%rdi) | |
| 414 | \\ movq %%r14, (%[r14_offset])(%%rdi) | |
| 415 | \\ movq %%r15, (%[r15_offset])(%%rdi) | |
| 416 | \\ movq %%rdi, (%[rdi_offset])(%%rdi) | |
| 417 | \\ movq %%rsi, (%[rsi_offset])(%%rdi) | |
| 418 | \\ movq %%rbp, (%[rbp_offset])(%%rdi) | |
| 419 | \\ movq %%rbx, (%[rbx_offset])(%%rdi) | |
| 420 | \\ movq %%rdx, (%[rdx_offset])(%%rdi) | |
| 421 | \\ movq %%rax, (%[rax_offset])(%%rdi) | |
| 422 | \\ movq %%rcx, (%[rcx_offset])(%%rdi) | |
| 406 | \\ movq $0, %[flags_offset:c](%%rdi) | |
| 407 | \\ movq $0, %[link_offset:c](%%rdi) | |
| 408 | \\ movq %%r8, %[r8_offset:c](%%rdi) | |
| 409 | \\ movq %%r9, %[r9_offset:c](%%rdi) | |
| 410 | \\ movq %%r10, %[r10_offset:c](%%rdi) | |
| 411 | \\ movq %%r11, %[r11_offset:c](%%rdi) | |
| 412 | \\ movq %%r12, %[r12_offset:c](%%rdi) | |
| 413 | \\ movq %%r13, %[r13_offset:c](%%rdi) | |
| 414 | \\ movq %%r14, %[r14_offset:c](%%rdi) | |
| 415 | \\ movq %%r15, %[r15_offset:c](%%rdi) | |
| 416 | \\ movq %%rdi, %[rdi_offset:c](%%rdi) | |
| 417 | \\ movq %%rsi, %[rsi_offset:c](%%rdi) | |
| 418 | \\ movq %%rbp, %[rbp_offset:c](%%rdi) | |
| 419 | \\ movq %%rbx, %[rbx_offset:c](%%rdi) | |
| 420 | \\ movq %%rdx, %[rdx_offset:c](%%rdi) | |
| 421 | \\ movq %%rax, %[rax_offset:c](%%rdi) | |
| 422 | \\ movq %%rcx, %[rcx_offset:c](%%rdi) | |
| 423 | 423 | \\ movq (%%rsp), %%rcx |
| 424 | \\ movq %%rcx, (%[rip_offset])(%%rdi) | |
| 424 | \\ movq %%rcx, %[rip_offset:c](%%rdi) | |
| 425 | 425 | \\ leaq 8(%%rsp), %%rcx |
| 426 | \\ movq %%rcx, (%[rsp_offset])(%%rdi) | |
| 426 | \\ movq %%rcx, %[rsp_offset:c](%%rdi) | |
| 427 | 427 | \\ pushfq |
| 428 | \\ popq (%[efl_offset])(%%rdi) | |
| 429 | \\ leaq (%[fpmem_offset])(%%rdi), %%rcx | |
| 430 | \\ movq %%rcx, (%[fpstate_offset])(%%rdi) | |
| 428 | \\ popq %[efl_offset:c](%%rdi) | |
| 429 | \\ leaq %[fpmem_offset:c](%%rdi), %%rcx | |
| 430 | \\ movq %%rcx, %[fpstate_offset:c](%%rdi) | |
| 431 | 431 | \\ fnstenv (%%rcx) |
| 432 | 432 | \\ fldenv (%%rcx) |
| 433 | \\ stmxcsr (%[mxcsr_offset])(%%rdi) | |
| 434 | \\ leaq (%[stack_offset])(%%rdi), %%rsi | |
| 433 | \\ stmxcsr %[mxcsr_offset:c](%%rdi) | |
| 434 | \\ leaq %[stack_offset:c](%%rdi), %%rsi | |
| 435 | 435 | \\ movq %%rdi, %%r8 |
| 436 | \\ xorq %%rdi, %%rdi | |
| 436 | \\ xorl %%edi, %%edi | |
| 437 | 437 | \\ movq %[sigaltstack], %%rax |
| 438 | 438 | \\ syscall |
| 439 | \\ cmpq $0, %%rax | |
| 440 | \\ jne return | |
| 439 | \\ testq %%rax, %%rax | |
| 440 | \\ jnz 0f | |
| 441 | 441 | \\ movq %[sigprocmask], %%rax |
| 442 | \\ xorq %%rsi, %%rsi | |
| 443 | \\ leaq (%[sigmask_offset])(%%r8), %%rdx | |
| 444 | \\ movq %[sigset_size], %%r10 | |
| 442 | \\ xorl %%esi, %%esi | |
| 443 | \\ leaq %[sigmask_offset:c](%%r8), %%rdx | |
| 444 | \\ movl %[sigset_size], %%r10d | |
| 445 | 445 | \\ syscall |
| 446 | \\ return: | |
| 446 | \\0: | |
| 447 | 447 | : |
| 448 | : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")), | |
| 449 | [link_offset] "p" (@offsetOf(ucontext_t, "link")), | |
| 450 | [r8_offset] "p" (comptime gpRegisterOffset(REG.R8)), | |
| 451 | [r9_offset] "p" (comptime gpRegisterOffset(REG.R9)), | |
| 452 | [r10_offset] "p" (comptime gpRegisterOffset(REG.R10)), | |
| 453 | [r11_offset] "p" (comptime gpRegisterOffset(REG.R11)), | |
| 454 | [r12_offset] "p" (comptime gpRegisterOffset(REG.R12)), | |
| 455 | [r13_offset] "p" (comptime gpRegisterOffset(REG.R13)), | |
| 456 | [r14_offset] "p" (comptime gpRegisterOffset(REG.R14)), | |
| 457 | [r15_offset] "p" (comptime gpRegisterOffset(REG.R15)), | |
| 458 | [rdi_offset] "p" (comptime gpRegisterOffset(REG.RDI)), | |
| 459 | [rsi_offset] "p" (comptime gpRegisterOffset(REG.RSI)), | |
| 460 | [rbp_offset] "p" (comptime gpRegisterOffset(REG.RBP)), | |
| 461 | [rbx_offset] "p" (comptime gpRegisterOffset(REG.RBX)), | |
| 462 | [rdx_offset] "p" (comptime gpRegisterOffset(REG.RDX)), | |
| 463 | [rax_offset] "p" (comptime gpRegisterOffset(REG.RAX)), | |
| 464 | [rcx_offset] "p" (comptime gpRegisterOffset(REG.RCX)), | |
| 465 | [rsp_offset] "p" (comptime gpRegisterOffset(REG.RSP)), | |
| 466 | [rip_offset] "p" (comptime gpRegisterOffset(REG.RIP)), | |
| 467 | [efl_offset] "p" (comptime gpRegisterOffset(REG.EFL)), | |
| 468 | [fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | |
| 469 | [fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")), | |
| 470 | [mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")), | |
| 448 | : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")), | |
| 449 | [link_offset] "i" (@offsetOf(ucontext_t, "link")), | |
| 450 | [r8_offset] "i" (comptime gpRegisterOffset(REG.R8)), | |
| 451 | [r9_offset] "i" (comptime gpRegisterOffset(REG.R9)), | |
| 452 | [r10_offset] "i" (comptime gpRegisterOffset(REG.R10)), | |
| 453 | [r11_offset] "i" (comptime gpRegisterOffset(REG.R11)), | |
| 454 | [r12_offset] "i" (comptime gpRegisterOffset(REG.R12)), | |
| 455 | [r13_offset] "i" (comptime gpRegisterOffset(REG.R13)), | |
| 456 | [r14_offset] "i" (comptime gpRegisterOffset(REG.R14)), | |
| 457 | [r15_offset] "i" (comptime gpRegisterOffset(REG.R15)), | |
| 458 | [rdi_offset] "i" (comptime gpRegisterOffset(REG.RDI)), | |
| 459 | [rsi_offset] "i" (comptime gpRegisterOffset(REG.RSI)), | |
| 460 | [rbp_offset] "i" (comptime gpRegisterOffset(REG.RBP)), | |
| 461 | [rbx_offset] "i" (comptime gpRegisterOffset(REG.RBX)), | |
| 462 | [rdx_offset] "i" (comptime gpRegisterOffset(REG.RDX)), | |
| 463 | [rax_offset] "i" (comptime gpRegisterOffset(REG.RAX)), | |
| 464 | [rcx_offset] "i" (comptime gpRegisterOffset(REG.RCX)), | |
| 465 | [rsp_offset] "i" (comptime gpRegisterOffset(REG.RSP)), | |
| 466 | [rip_offset] "i" (comptime gpRegisterOffset(REG.RIP)), | |
| 467 | [efl_offset] "i" (comptime gpRegisterOffset(REG.EFL)), | |
| 468 | [fpstate_offset] "i" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")), | |
| 469 | [fpmem_offset] "i" (@offsetOf(ucontext_t, "fpregs_mem")), | |
| 470 | [mxcsr_offset] "i" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")), | |
| 471 | 471 | [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)), |
| 472 | [stack_offset] "p" (@offsetOf(ucontext_t, "stack")), | |
| 472 | [stack_offset] "i" (@offsetOf(ucontext_t, "stack")), | |
| 473 | 473 | [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)), |
| 474 | [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")), | |
| 474 | [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")), | |
| 475 | 475 | [sigset_size] "i" (linux.NSIG / 8), |
| 476 | : "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11" | |
| 476 | : "cc", "memory", "rax", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11" | |
| 477 | 477 | ); |
| 478 | 478 | } |
| 479 | 479 | |
| ... | ... | @@ -481,11 +481,13 @@ pub inline fn getcontext(context: *ucontext_t) usize { |
| 481 | 481 | // This method is used so that getContextInternal can control |
| 482 | 482 | // its prologue in order to read RSP from a constant offset |
| 483 | 483 | // The unused &getContextInternal input is required so the function is included in the binary. |
| 484 | var clobber_rdi: usize = undefined; | |
| 484 | 485 | return asm volatile ( |
| 485 | \\ call os.linux.x86_64.getContextInternal | |
| 486 | : [ret] "={rax}" (-> usize), | |
| 487 | : [context] "{rdi}" (context), | |
| 486 | \\ callq %[getContextInternal:P] | |
| 487 | : [_] "={rax}" (-> usize), | |
| 488 | [_] "={rdi}" (clobber_rdi), | |
| 489 | : [_] "{rdi}" (context), | |
| 488 | 490 | [getContextInternal] "X" (&getContextInternal), |
| 489 | : "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11" | |
| 491 | : "cc", "memory", "rcx", "rdx", "rsi", "r8", "r10", "r11" | |
| 490 | 492 | ); |
| 491 | 493 | } |
lib/std/start.zig+22-22| ... | ... | @@ -256,38 +256,38 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv |
| 256 | 256 | fn _start() callconv(.Naked) noreturn { |
| 257 | 257 | switch (builtin.zig_backend) { |
| 258 | 258 | .stage2_c => { |
| 259 | @export(argc_argv_ptr, .{ .name = "argc_argv_ptr" }); | |
| 260 | @export(posixCallMainAndExit, .{ .name = "_posixCallMainAndExit" }); | |
| 261 | switch (native_arch) { | |
| 262 | .x86_64 => asm volatile ( | |
| 259 | asm volatile (switch (native_arch) { | |
| 260 | .x86_64 => | |
| 263 | 261 | \\ xorl %%ebp, %%ebp |
| 264 | \\ movq %%rsp, argc_argv_ptr | |
| 262 | \\ movq %%rsp, %[argc_argv_ptr] | |
| 265 | 263 | \\ andq $-16, %%rsp |
| 266 | \\ call _posixCallMainAndExit | |
| 267 | ), | |
| 268 | .x86 => asm volatile ( | |
| 264 | \\ callq %[posixCallMainAndExit:P] | |
| 265 | , | |
| 266 | .x86 => | |
| 269 | 267 | \\ xorl %%ebp, %%ebp |
| 270 | \\ movl %%esp, argc_argv_ptr | |
| 268 | \\ movl %%esp, %[argc_argv_ptr] | |
| 271 | 269 | \\ andl $-16, %%esp |
| 272 | \\ jmp _posixCallMainAndExit | |
| 273 | ), | |
| 274 | .aarch64, .aarch64_be => asm volatile ( | |
| 270 | \\ calll %[posixCallMainAndExit:P] | |
| 271 | , | |
| 272 | .aarch64, .aarch64_be => | |
| 275 | 273 | \\ mov fp, #0 |
| 276 | 274 | \\ mov lr, #0 |
| 277 | 275 | \\ mov x0, sp |
| 278 | \\ adrp x1, argc_argv_ptr | |
| 279 | \\ str x0, [x1, :lo12:argc_argv_ptr] | |
| 280 | \\ b _posixCallMainAndExit | |
| 281 | ), | |
| 282 | .arm, .armeb, .thumb => asm volatile ( | |
| 276 | \\ str x0, %[argc_argv_ptr] | |
| 277 | \\ b %[posixCallMainAndExit] | |
| 278 | , | |
| 279 | .arm, .armeb, .thumb => | |
| 283 | 280 | \\ mov fp, #0 |
| 284 | 281 | \\ mov lr, #0 |
| 285 | \\ str sp, argc_argv_ptr | |
| 282 | \\ str sp, %[argc_argv_ptr] | |
| 286 | 283 | \\ and sp, #-16 |
| 287 | \\ b _posixCallMainAndExit | |
| 288 | ), | |
| 289 | else => @compileError("unsupported arch"), | |
| 290 | } | |
| 284 | \\ b %[posixCallMainAndExit] | |
| 285 | , | |
| 286 | else => @compileError("unsupported arch"), | |
| 287 | } | |
| 288 | : [argc_argv_ptr] "=m" (argc_argv_ptr), | |
| 289 | : [posixCallMainAndExit] "X" (&posixCallMainAndExit), | |
| 290 | ); | |
| 291 | 291 | unreachable; |
| 292 | 292 | }, |
| 293 | 293 | else => switch (native_arch) { |
src/codegen/c.zig+50-35| ... | ... | @@ -30,7 +30,7 @@ pub const CValue = union(enum) { |
| 30 | 30 | /// Address of a local. |
| 31 | 31 | local_ref: LocalIndex, |
| 32 | 32 | /// A constant instruction, to be rendered inline. |
| 33 | constant: Air.Inst.Ref, | |
| 33 | constant: InternPool.Index, | |
| 34 | 34 | /// Index into the parameters |
| 35 | 35 | arg: usize, |
| 36 | 36 | /// The array field of a parameter |
| ... | ... | @@ -302,7 +302,7 @@ pub const Function = struct { |
| 302 | 302 | try f.object.dg.renderValue(writer, ty, val, .StaticInitializer); |
| 303 | 303 | try writer.writeAll(";\n "); |
| 304 | 304 | break :result decl_c_value; |
| 305 | } else .{ .constant = ref }; | |
| 305 | } else .{ .constant = val.toIntern() }; | |
| 306 | 306 | |
| 307 | 307 | gop.value_ptr.* = result; |
| 308 | 308 | return result; |
| ... | ... | @@ -352,57 +352,63 @@ pub const Function = struct { |
| 352 | 352 | |
| 353 | 353 | fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { |
| 354 | 354 | switch (c_value) { |
| 355 | .constant => |inst| { | |
| 356 | const mod = f.object.dg.module; | |
| 357 | const ty = f.typeOf(inst); | |
| 358 | const val = (try f.air.value(inst, mod)).?; | |
| 359 | return f.object.dg.renderValue(w, ty, val, location); | |
| 360 | }, | |
| 361 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), | |
| 362 | else => return f.object.dg.writeCValue(w, c_value), | |
| 355 | .constant => |val| try f.object.dg.renderValue( | |
| 356 | w, | |
| 357 | f.object.dg.module.intern_pool.typeOf(val).toType(), | |
| 358 | val.toValue(), | |
| 359 | location, | |
| 360 | ), | |
| 361 | .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location), | |
| 362 | else => try f.object.dg.writeCValue(w, c_value), | |
| 363 | 363 | } |
| 364 | 364 | } |
| 365 | 365 | |
| 366 | 366 | fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void { |
| 367 | 367 | switch (c_value) { |
| 368 | .constant => |inst| { | |
| 369 | const mod = f.object.dg.module; | |
| 370 | const ty = f.typeOf(inst); | |
| 371 | const val = (try f.air.value(inst, mod)).?; | |
| 368 | .constant => |val| { | |
| 372 | 369 | try w.writeAll("(*"); |
| 373 | try f.object.dg.renderValue(w, ty, val, .Other); | |
| 374 | return w.writeByte(')'); | |
| 370 | try f.object.dg.renderValue( | |
| 371 | w, | |
| 372 | f.object.dg.module.intern_pool.typeOf(val).toType(), | |
| 373 | val.toValue(), | |
| 374 | .Other, | |
| 375 | ); | |
| 376 | try w.writeByte(')'); | |
| 375 | 377 | }, |
| 376 | else => return f.object.dg.writeCValueDeref(w, c_value), | |
| 378 | else => try f.object.dg.writeCValueDeref(w, c_value), | |
| 377 | 379 | } |
| 378 | 380 | } |
| 379 | 381 | |
| 380 | 382 | fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 381 | 383 | switch (c_value) { |
| 382 | .constant => |inst| { | |
| 383 | const mod = f.object.dg.module; | |
| 384 | const ty = f.typeOf(inst); | |
| 385 | const val = (try f.air.value(inst, mod)).?; | |
| 386 | try f.object.dg.renderValue(w, ty, val, .Other); | |
| 384 | .constant => |val| { | |
| 385 | try f.object.dg.renderValue( | |
| 386 | w, | |
| 387 | f.object.dg.module.intern_pool.typeOf(val).toType(), | |
| 388 | val.toValue(), | |
| 389 | .Other, | |
| 390 | ); | |
| 387 | 391 | try w.writeByte('.'); |
| 388 | return f.writeCValue(w, member, .Other); | |
| 392 | try f.writeCValue(w, member, .Other); | |
| 389 | 393 | }, |
| 390 | else => return f.object.dg.writeCValueMember(w, c_value, member), | |
| 394 | else => try f.object.dg.writeCValueMember(w, c_value, member), | |
| 391 | 395 | } |
| 392 | 396 | } |
| 393 | 397 | |
| 394 | 398 | fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { |
| 395 | 399 | switch (c_value) { |
| 396 | .constant => |inst| { | |
| 397 | const mod = f.object.dg.module; | |
| 398 | const ty = f.typeOf(inst); | |
| 399 | const val = (try f.air.value(inst, mod)).?; | |
| 400 | .constant => |val| { | |
| 400 | 401 | try w.writeByte('('); |
| 401 | try f.object.dg.renderValue(w, ty, val, .Other); | |
| 402 | try f.object.dg.renderValue( | |
| 403 | w, | |
| 404 | f.object.dg.module.intern_pool.typeOf(val).toType(), | |
| 405 | val.toValue(), | |
| 406 | .Other, | |
| 407 | ); | |
| 402 | 408 | try w.writeAll(")->"); |
| 403 | return f.writeCValue(w, member, .Other); | |
| 409 | try f.writeCValue(w, member, .Other); | |
| 404 | 410 | }, |
| 405 | else => return f.object.dg.writeCValueDerefMember(w, c_value, member), | |
| 411 | else => try f.object.dg.writeCValueDerefMember(w, c_value, member), | |
| 406 | 412 | } |
| 407 | 413 | } |
| 408 | 414 | |
| ... | ... | @@ -4763,11 +4769,20 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4763 | 4769 | return .none; |
| 4764 | 4770 | } |
| 4765 | 4771 | |
| 4766 | fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { | |
| 4772 | fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool { | |
| 4767 | 4773 | return switch (constraint[0]) { |
| 4768 | 4774 | '{' => true, |
| 4769 | 4775 | 'i', 'r' => false, |
| 4770 | else => value == .constant, | |
| 4776 | else => switch (value) { | |
| 4777 | .constant => |val| switch (f.object.dg.module.intern_pool.indexToKey(val)) { | |
| 4778 | .ptr => |ptr| switch (ptr.addr) { | |
| 4779 | .decl => false, | |
| 4780 | else => true, | |
| 4781 | }, | |
| 4782 | else => true, | |
| 4783 | }, | |
| 4784 | else => false, | |
| 4785 | }, | |
| 4771 | 4786 | }; |
| 4772 | 4787 | } |
| 4773 | 4788 | |
| ... | ... | @@ -4848,7 +4863,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4848 | 4863 | |
| 4849 | 4864 | const is_reg = constraint[0] == '{'; |
| 4850 | 4865 | const input_val = try f.resolveInst(input); |
| 4851 | if (asmInputNeedsLocal(constraint, input_val)) { | |
| 4866 | if (asmInputNeedsLocal(f, constraint, input_val)) { | |
| 4852 | 4867 | const input_ty = f.typeOf(input); |
| 4853 | 4868 | if (is_reg) try writer.writeAll("register "); |
| 4854 | 4869 | const alignment = 0; |
| ... | ... | @@ -4969,7 +4984,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4969 | 4984 | const is_reg = constraint[0] == '{'; |
| 4970 | 4985 | const input_val = try f.resolveInst(input); |
| 4971 | 4986 | try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)}); |
| 4972 | try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: { | |
| 4987 | try f.writeCValue(writer, if (asmInputNeedsLocal(f, constraint, input_val)) local: { | |
| 4973 | 4988 | const input_local = .{ .local = locals_index }; |
| 4974 | 4989 | locals_index += 1; |
| 4975 | 4990 | break :local input_local; |
test/behavior/fn.zig+1| ... | ... | @@ -151,6 +151,7 @@ fn fnWithUnreachable() noreturn { |
| 151 | 151 | |
| 152 | 152 | test "extern struct with stdcallcc fn pointer" { |
| 153 | 153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 154 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .x86) return error.SkipZigTest; | |
| 154 | 155 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 155 | 156 | |
| 156 | 157 | const S = extern struct { |
test/tests.zig+1| ... | ... | @@ -1053,6 +1053,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { |
| 1053 | 1053 | // TODO stop violating these pedantic errors. spotted on linux |
| 1054 | 1054 | "-Wno-address-of-packed-member", |
| 1055 | 1055 | "-Wno-gnu-folding-constant", |
| 1056 | "-Wno-incompatible-function-pointer-types", | |
| 1056 | 1057 | "-Wno-incompatible-pointer-types", |
| 1057 | 1058 | "-Wno-overlength-strings", |
| 1058 | 1059 | // TODO stop violating these pedantic errors. spotted on darwin |