authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-30 03:18:10-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-31 01:58:10-04:00
log817fa3af8631d894004fbdb668da0882836dbe9b
tree3e63751b5ebb46fe8c45eca41a5248075d97bda8
parent43b830415368ac4fb08bf5e154a222a38baf4a24

std: cleanup asm usage

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 {
12751275 .entry_number = os.linux.tls.tls_image.gdt_entry_number,
12761276 .base_addr = tls_ptr,
12771277 .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 },
12841286 };
12851287 }
12861288
lib/std/os/linux/arm-eabi.zig+26-2
......@@ -104,7 +104,19 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
104104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
105105
106106pub 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"
108120 :
109121 : [number] "{r7}" (@intFromEnum(SYS.sigreturn)),
110122 : "memory"
......@@ -112,7 +124,19 @@ pub fn restore() callconv(.Naked) void {
112124}
113125
114126pub 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"
116140 :
117141 : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)),
118142 : "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: *
106106pub const restore = restore_rt;
107107
108108pub 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 (
111111 \\ mov x8, %[number]
112112 \\ svc #0
113 \\ ret
113114 :
114115 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
115116 : "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;
122119 }
120
121 asm volatile (
122 \\ svc #0
123 :
124 : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)),
125 : "memory", "cc"
126 );
123127}
124128
125129pub const O = struct {
lib/std/os/linux/tls.zig+8-6
......@@ -115,12 +115,14 @@ pub fn setThreadPointer(addr: usize) void {
115115 .entry_number = tls_image.gdt_entry_number,
116116 .base_addr = addr,
117117 .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 },
124126 };
125127 const rc = std.os.linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));
126128 assert(rc == 0);
lib/std/os/linux/x86.zig+76-71
......@@ -124,45 +124,45 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
124124pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
125125
126126pub 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 (
129129 \\ movl %[number], %%eax
130130 \\ int $0x80
131 \\ ret
131 \\ retl
132132 :
133133 : [number] "i" (@intFromEnum(SYS.sigreturn)),
134134 : "memory"
135 ),
136 else => asm volatile (
137 \\ int $0x80
138 \\ ret
139 :
140 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
141 : "memory"
142 ),
135 );
136 unreachable;
143137 }
144 unreachable;
138
139 asm volatile (
140 \\ int $0x80
141 :
142 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
143 : "memory"
144 );
145145}
146146
147147pub 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 (
150150 \\ movl %[number], %%eax
151151 \\ int $0x80
152 \\ ret
152 \\ retl
153153 :
154154 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
155155 : "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;
164158 }
165 unreachable;
159
160 asm volatile (
161 \\ int $0x80
162 :
163 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
164 : "memory"
165 );
166166}
167167
168168pub const O = struct {
......@@ -354,16 +354,19 @@ pub const ucontext_t = extern struct {
354354
355355pub const Elf_Symndx = u32;
356356
357pub const user_desc = packed struct {
357pub const user_desc = extern struct {
358358 entry_number: u32,
359359 base_addr: u32,
360360 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 },
367370};
368371
369372/// socketcall() call numbers
......@@ -400,63 +403,63 @@ noinline fn getContextReturnAddress() usize {
400403
401404pub fn getContextInternal() callconv(.Naked) void {
402405 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)
412415 \\ movl (%%esp), %%ecx
413 \\ movl %%ecx, (%[eip_offset])(%%edx)
416 \\ movl %%ecx, %[eip_offset:c](%%edx)
414417 \\ leal 4(%%esp), %%ecx
415 \\ movl %%ecx, (%[esp_offset])(%%edx)
418 \\ movl %%ecx, %[esp_offset:c](%%edx)
416419 \\ xorl %%ecx, %%ecx
417420 \\ 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)
421424 \\ fnstenv (%%ecx)
422425 \\ fldenv (%%ecx)
423426 \\ pushl %%ebx
424427 \\ pushl %%esi
425428 \\ xorl %%ebx, %%ebx
426429 \\ movl %[sigaltstack], %%eax
427 \\ leal (%[stack_offset])(%%edx), %%ecx
430 \\ leal %[stack_offset:c](%%edx), %%ecx
428431 \\ int $0x80
429 \\ cmpl $0, %%eax
430 \\ jne return
432 \\ testl %%eax, %%eax
433 \\ jnz 0f
431434 \\ movl %[sigprocmask], %%eax
432435 \\ xorl %%ecx, %%ecx
433 \\ leal (%[sigmask_offset])(%%edx), %%edx
436 \\ leal %[sigmask_offset:c](%%edx), %%edx
434437 \\ movl %[sigset_size], %%esi
435438 \\ int $0x80
436 \\ return:
439 \\0:
437440 \\ popl %%esi
438441 \\ popl %%ebx
439442 :
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")),
454457 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
455 [stack_offset] "p" (@offsetOf(ucontext_t, "stack")),
458 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
456459 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
457 [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")),
460 [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),
458461 [sigset_size] "i" (linux.NSIG / 8),
459 : "memory", "eax", "ecx", "edx"
462 : "cc", "memory", "eax", "ecx", "edx"
460463 );
461464}
462465
......@@ -464,11 +467,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {
464467 // This method is used so that getContextInternal can control
465468 // its prologue in order to read ESP from a constant offset.
466469 // The unused &getContextInternal input is required so the function is included in the binary.
470 var clobber_edx: usize = undefined;
467471 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),
471476 [getContextInternal] "X" (&getContextInternal),
472 : "memory", "ecx"
477 : "cc", "memory", "ecx"
473478 );
474479}
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:
108108pub const restore = restore_rt;
109109
110110pub 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 (
113113 \\ movl %[number], %%eax
114114 \\ syscall
115115 \\ retq
116116 :
117117 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
118118 : "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;
127121 }
128 unreachable;
122
123 asm volatile (
124 \\ syscall
125 :
126 : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)),
127 : "rcx", "r11", "memory"
128 );
129129}
130130
131131pub const mode_t = usize;
......@@ -403,77 +403,77 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
403403fn getContextInternal() callconv(.Naked) void {
404404 // TODO: Read GS/FS registers?
405405 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)
423423 \\ movq (%%rsp), %%rcx
424 \\ movq %%rcx, (%[rip_offset])(%%rdi)
424 \\ movq %%rcx, %[rip_offset:c](%%rdi)
425425 \\ leaq 8(%%rsp), %%rcx
426 \\ movq %%rcx, (%[rsp_offset])(%%rdi)
426 \\ movq %%rcx, %[rsp_offset:c](%%rdi)
427427 \\ 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)
431431 \\ fnstenv (%%rcx)
432432 \\ 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
435435 \\ movq %%rdi, %%r8
436 \\ xorq %%rdi, %%rdi
436 \\ xorl %%edi, %%edi
437437 \\ movq %[sigaltstack], %%rax
438438 \\ syscall
439 \\ cmpq $0, %%rax
440 \\ jne return
439 \\ testq %%rax, %%rax
440 \\ jnz 0f
441441 \\ 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
445445 \\ syscall
446 \\ return:
446 \\0:
447447 :
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")),
471471 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
472 [stack_offset] "p" (@offsetOf(ucontext_t, "stack")),
472 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
473473 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),
474 [sigmask_offset] "p" (@offsetOf(ucontext_t, "sigmask")),
474 [sigmask_offset] "i" (@offsetOf(ucontext_t, "sigmask")),
475475 [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"
477477 );
478478}
479479
......@@ -481,11 +481,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {
481481 // This method is used so that getContextInternal can control
482482 // its prologue in order to read RSP from a constant offset
483483 // The unused &getContextInternal input is required so the function is included in the binary.
484 var clobber_rdi: usize = undefined;
484485 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),
488490 [getContextInternal] "X" (&getContextInternal),
489 : "memory", "rcx", "rdx", "rdi", "rsi", "r8", "r10", "r11"
491 : "cc", "memory", "rcx", "rdx", "rsi", "r8", "r10", "r11"
490492 );
491493}
lib/std/start.zig+22-22
......@@ -256,38 +256,38 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
256256fn _start() callconv(.Naked) noreturn {
257257 switch (builtin.zig_backend) {
258258 .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 =>
263261 \\ xorl %%ebp, %%ebp
264 \\ movq %%rsp, argc_argv_ptr
262 \\ movq %%rsp, %[argc_argv_ptr]
265263 \\ andq $-16, %%rsp
266 \\ call _posixCallMainAndExit
267 ),
268 .x86 => asm volatile (
264 \\ callq %[posixCallMainAndExit:P]
265 ,
266 .x86 =>
269267 \\ xorl %%ebp, %%ebp
270 \\ movl %%esp, argc_argv_ptr
268 \\ movl %%esp, %[argc_argv_ptr]
271269 \\ andl $-16, %%esp
272 \\ jmp _posixCallMainAndExit
273 ),
274 .aarch64, .aarch64_be => asm volatile (
270 \\ calll %[posixCallMainAndExit:P]
271 ,
272 .aarch64, .aarch64_be =>
275273 \\ mov fp, #0
276274 \\ mov lr, #0
277275 \\ 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 =>
283280 \\ mov fp, #0
284281 \\ mov lr, #0
285 \\ str sp, argc_argv_ptr
282 \\ str sp, %[argc_argv_ptr]
286283 \\ 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 );
291291 unreachable;
292292 },
293293 else => switch (native_arch) {
src/codegen/c.zig+50-35
......@@ -30,7 +30,7 @@ pub const CValue = union(enum) {
3030 /// Address of a local.
3131 local_ref: LocalIndex,
3232 /// A constant instruction, to be rendered inline.
33 constant: Air.Inst.Ref,
33 constant: InternPool.Index,
3434 /// Index into the parameters
3535 arg: usize,
3636 /// The array field of a parameter
......@@ -302,7 +302,7 @@ pub const Function = struct {
302302 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
303303 try writer.writeAll(";\n ");
304304 break :result decl_c_value;
305 } else .{ .constant = ref };
305 } else .{ .constant = val.toIntern() };
306306
307307 gop.value_ptr.* = result;
308308 return result;
......@@ -352,57 +352,63 @@ pub const Function = struct {
352352
353353 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
354354 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),
363363 }
364364 }
365365
366366 fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void {
367367 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| {
372369 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(')');
375377 },
376 else => return f.object.dg.writeCValueDeref(w, c_value),
378 else => try f.object.dg.writeCValueDeref(w, c_value),
377379 }
378380 }
379381
380382 fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {
381383 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 );
387391 try w.writeByte('.');
388 return f.writeCValue(w, member, .Other);
392 try f.writeCValue(w, member, .Other);
389393 },
390 else => return f.object.dg.writeCValueMember(w, c_value, member),
394 else => try f.object.dg.writeCValueMember(w, c_value, member),
391395 }
392396 }
393397
394398 fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {
395399 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| {
400401 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 );
402408 try w.writeAll(")->");
403 return f.writeCValue(w, member, .Other);
409 try f.writeCValue(w, member, .Other);
404410 },
405 else => return f.object.dg.writeCValueDerefMember(w, c_value, member),
411 else => try f.object.dg.writeCValueDerefMember(w, c_value, member),
406412 }
407413 }
408414
......@@ -4763,11 +4769,20 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
47634769 return .none;
47644770}
47654771
4766fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {
4772fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
47674773 return switch (constraint[0]) {
47684774 '{' => true,
47694775 '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 },
47714786 };
47724787}
47734788
......@@ -4848,7 +4863,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48484863
48494864 const is_reg = constraint[0] == '{';
48504865 const input_val = try f.resolveInst(input);
4851 if (asmInputNeedsLocal(constraint, input_val)) {
4866 if (asmInputNeedsLocal(f, constraint, input_val)) {
48524867 const input_ty = f.typeOf(input);
48534868 if (is_reg) try writer.writeAll("register ");
48544869 const alignment = 0;
......@@ -4969,7 +4984,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
49694984 const is_reg = constraint[0] == '{';
49704985 const input_val = try f.resolveInst(input);
49714986 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: {
49734988 const input_local = .{ .local = locals_index };
49744989 locals_index += 1;
49754990 break :local input_local;
test/behavior/fn.zig+1
......@@ -151,6 +151,7 @@ fn fnWithUnreachable() noreturn {
151151
152152test "extern struct with stdcallcc fn pointer" {
153153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
154 if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .x86) return error.SkipZigTest;
154155 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
155156
156157 const S = extern struct {
test/tests.zig+1
......@@ -1053,6 +1053,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
10531053 // TODO stop violating these pedantic errors. spotted on linux
10541054 "-Wno-address-of-packed-member",
10551055 "-Wno-gnu-folding-constant",
1056 "-Wno-incompatible-function-pointer-types",
10561057 "-Wno-incompatible-pointer-types",
10571058 "-Wno-overlength-strings",
10581059 // TODO stop violating these pedantic errors. spotted on darwin