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 {...@@ -1275,12 +1275,14 @@ const LinuxThreadImpl = struct {
1275 .entry_number = os.linux.tls.tls_image.gdt_entry_number,1275 .entry_number = os.linux.tls.tls_image.gdt_entry_number,
1276 .base_addr = tls_ptr,1276 .base_addr = tls_ptr,
1277 .limit = 0xfffff,1277 .limit = 0xfffff,
1278 .seg_32bit = 1,1278 .flags = .{
1279 .contents = 0, // Data1279 .seg_32bit = 1,
1280 .read_exec_only = 0,1280 .contents = 0, // Data
1281 .limit_in_pages = 1,1281 .read_exec_only = 0,
1282 .seg_not_present = 0,1282 .limit_in_pages = 1,
1283 .useable = 1,1283 .seg_not_present = 0,
1284 .useable = 1,
1285 },
1284 };1286 };
1285 }1287 }
12861288
lib/std/os/linux/arm-eabi.zig+26-2
...@@ -104,7 +104,19 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;...@@ -104,7 +104,19 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;104pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
105105
106pub fn restore() callconv(.Naked) void {106pub 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 : [number] "{r7}" (@intFromEnum(SYS.sigreturn)),121 : [number] "{r7}" (@intFromEnum(SYS.sigreturn)),
110 : "memory"122 : "memory"
...@@ -112,7 +124,19 @@ pub fn restore() callconv(.Naked) void {...@@ -112,7 +124,19 @@ pub fn restore() callconv(.Naked) void {
112}124}
113125
114pub fn restore_rt() callconv(.Naked) void {126pub 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 : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)),141 : [number] "{r7}" (@intFromEnum(SYS.rt_sigreturn)),
118 : "memory"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,20 +106,24 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *
106pub const restore = restore_rt;106pub const restore = restore_rt;
107107
108pub fn restore_rt() callconv(.Naked) void {108pub fn restore_rt() callconv(.Naked) void {
109 switch (@import("builtin").zig_backend) {109 if (@import("builtin").zig_backend == .stage2_c) {
110 .stage2_c => return asm volatile (110 asm volatile (
111 \\ mov x8, %[number]111 \\ mov x8, %[number]
112 \\ svc #0112 \\ svc #0
113 \\ ret
113 :114 :
114 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),115 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
115 : "memory", "cc"116 : "memory", "cc"
116 ),117 );
117 else => return asm volatile ("svc #0"118 unreachable;
118 :
119 : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)),
120 : "memory", "cc"
121 ),
122 }119 }
120
121 asm volatile (
122 \\ svc #0
123 :
124 : [number] "{x8}" (@intFromEnum(SYS.rt_sigreturn)),
125 : "memory", "cc"
126 );
123}127}
124128
125pub const O = struct {129pub const O = struct {
lib/std/os/linux/tls.zig+8-6
...@@ -115,12 +115,14 @@ pub fn setThreadPointer(addr: usize) void {...@@ -115,12 +115,14 @@ pub fn setThreadPointer(addr: usize) void {
115 .entry_number = tls_image.gdt_entry_number,115 .entry_number = tls_image.gdt_entry_number,
116 .base_addr = addr,116 .base_addr = addr,
117 .limit = 0xfffff,117 .limit = 0xfffff,
118 .seg_32bit = 1,118 .flags = .{
119 .contents = 0, // Data119 .seg_32bit = 1,
120 .read_exec_only = 0,120 .contents = 0, // Data
121 .limit_in_pages = 1,121 .read_exec_only = 0,
122 .seg_not_present = 0,122 .limit_in_pages = 1,
123 .useable = 1,123 .seg_not_present = 0,
124 .useable = 1,
125 },
124 };126 };
125 const rc = std.os.linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));127 const rc = std.os.linux.syscall1(.set_thread_area, @intFromPtr(&user_desc));
126 assert(rc == 0);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,45 +124,45 @@ const CloneFn = *const fn (arg: usize) callconv(.C) u8;
124pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;124pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
125125
126pub fn restore() callconv(.Naked) void {126pub fn restore() callconv(.Naked) void {
127 switch (@import("builtin").zig_backend) {127 if (@import("builtin").zig_backend == .stage2_c) {
128 .stage2_c => asm volatile (128 asm volatile (
129 \\ movl %[number], %%eax129 \\ movl %[number], %%eax
130 \\ int $0x80130 \\ int $0x80
131 \\ ret131 \\ retl
132 :132 :
133 : [number] "i" (@intFromEnum(SYS.sigreturn)),133 : [number] "i" (@intFromEnum(SYS.sigreturn)),
134 : "memory"134 : "memory"
135 ),135 );
136 else => asm volatile (136 unreachable;
137 \\ int $0x80
138 \\ ret
139 :
140 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
141 : "memory"
142 ),
143 }137 }
144 unreachable;138
139 asm volatile (
140 \\ int $0x80
141 :
142 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
143 : "memory"
144 );
145}145}
146146
147pub fn restore_rt() callconv(.Naked) void {147pub fn restore_rt() callconv(.Naked) void {
148 switch (@import("builtin").zig_backend) {148 if (@import("builtin").zig_backend == .stage2_c) {
149 .stage2_c => asm volatile (149 asm volatile (
150 \\ movl %[number], %%eax150 \\ movl %[number], %%eax
151 \\ int $0x80151 \\ int $0x80
152 \\ ret152 \\ retl
153 :153 :
154 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),154 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
155 : "memory"155 : "memory"
156 ),156 );
157 else => asm volatile (157 unreachable;
158 \\ int $0x80
159 \\ ret
160 :
161 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
162 : "memory"
163 ),
164 }158 }
165 unreachable;159
160 asm volatile (
161 \\ int $0x80
162 :
163 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
164 : "memory"
165 );
166}166}
167167
168pub const O = struct {168pub const O = struct {
...@@ -354,16 +354,19 @@ pub const ucontext_t = extern struct {...@@ -354,16 +354,19 @@ pub const ucontext_t = extern struct {
354354
355pub const Elf_Symndx = u32;355pub const Elf_Symndx = u32;
356356
357pub const user_desc = packed struct {357pub const user_desc = extern struct {
358 entry_number: u32,358 entry_number: u32,
359 base_addr: u32,359 base_addr: u32,
360 limit: u32,360 limit: u32,
361 seg_32bit: u1,361 flags: packed struct(u32) {
362 contents: u2,362 seg_32bit: u1,
363 read_exec_only: u1,363 contents: u2,
364 limit_in_pages: u1,364 read_exec_only: u1,
365 seg_not_present: u1,365 limit_in_pages: u1,
366 useable: u1,366 seg_not_present: u1,
367 useable: u1,
368 _: u25 = undefined,
369 },
367};370};
368371
369/// socketcall() call numbers372/// socketcall() call numbers
...@@ -400,63 +403,63 @@ noinline fn getContextReturnAddress() usize {...@@ -400,63 +403,63 @@ noinline fn getContextReturnAddress() usize {
400403
401pub fn getContextInternal() callconv(.Naked) void {404pub fn getContextInternal() callconv(.Naked) void {
402 asm volatile (405 asm volatile (
403 \\ movl $0, (%[flags_offset])(%%edx)406 \\ movl $0, %[flags_offset:c](%%edx)
404 \\ movl $0, (%[link_offset])(%%edx)407 \\ movl $0, %[link_offset:c](%%edx)
405 \\ movl %%edi, (%[edi_offset])(%%edx)408 \\ movl %%edi, %[edi_offset:c](%%edx)
406 \\ movl %%esi, (%[esi_offset])(%%edx)409 \\ movl %%esi, %[esi_offset:c](%%edx)
407 \\ movl %%ebp, (%[ebp_offset])(%%edx)410 \\ movl %%ebp, %[ebp_offset:c](%%edx)
408 \\ movl %%ebx, (%[ebx_offset])(%%edx)411 \\ movl %%ebx, %[ebx_offset:c](%%edx)
409 \\ movl %%edx, (%[edx_offset])(%%edx)412 \\ movl %%edx, %[edx_offset:c](%%edx)
410 \\ movl %%ecx, (%[ecx_offset])(%%edx)413 \\ movl %%ecx, %[ecx_offset:c](%%edx)
411 \\ movl %%eax, (%[eax_offset])(%%edx)414 \\ movl %%eax, %[eax_offset:c](%%edx)
412 \\ movl (%%esp), %%ecx415 \\ movl (%%esp), %%ecx
413 \\ movl %%ecx, (%[eip_offset])(%%edx)416 \\ movl %%ecx, %[eip_offset:c](%%edx)
414 \\ leal 4(%%esp), %%ecx417 \\ leal 4(%%esp), %%ecx
415 \\ movl %%ecx, (%[esp_offset])(%%edx)418 \\ movl %%ecx, %[esp_offset:c](%%edx)
416 \\ xorl %%ecx, %%ecx419 \\ xorl %%ecx, %%ecx
417 \\ movw %%fs, %%cx420 \\ movw %%fs, %%cx
418 \\ movl %%ecx, (%[fs_offset])(%%edx)421 \\ movl %%ecx, %[fs_offset:c](%%edx)
419 \\ leal (%[regspace_offset])(%%edx), %%ecx422 \\ leal %[regspace_offset:c](%%edx), %%ecx
420 \\ movl %%ecx, (%[fpregs_offset])(%%edx)423 \\ movl %%ecx, %[fpregs_offset:c](%%edx)
421 \\ fnstenv (%%ecx)424 \\ fnstenv (%%ecx)
422 \\ fldenv (%%ecx)425 \\ fldenv (%%ecx)
423 \\ pushl %%ebx426 \\ pushl %%ebx
424 \\ pushl %%esi427 \\ pushl %%esi
425 \\ xorl %%ebx, %%ebx428 \\ xorl %%ebx, %%ebx
426 \\ movl %[sigaltstack], %%eax429 \\ movl %[sigaltstack], %%eax
427 \\ leal (%[stack_offset])(%%edx), %%ecx430 \\ leal %[stack_offset:c](%%edx), %%ecx
428 \\ int $0x80431 \\ int $0x80
429 \\ cmpl $0, %%eax432 \\ testl %%eax, %%eax
430 \\ jne return433 \\ jnz 0f
431 \\ movl %[sigprocmask], %%eax434 \\ movl %[sigprocmask], %%eax
432 \\ xorl %%ecx, %%ecx435 \\ xorl %%ecx, %%ecx
433 \\ leal (%[sigmask_offset])(%%edx), %%edx436 \\ leal %[sigmask_offset:c](%%edx), %%edx
434 \\ movl %[sigset_size], %%esi437 \\ movl %[sigset_size], %%esi
435 \\ int $0x80438 \\ int $0x80
436 \\ return:439 \\0:
437 \\ popl %%esi440 \\ popl %%esi
438 \\ popl %%ebx441 \\ popl %%ebx
439 :442 :
440 : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")),443 : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")),
441 [link_offset] "p" (@offsetOf(ucontext_t, "link")),444 [link_offset] "i" (@offsetOf(ucontext_t, "link")),
442 [edi_offset] "p" (comptime gpRegisterOffset(REG.EDI)),445 [edi_offset] "i" (comptime gpRegisterOffset(REG.EDI)),
443 [esi_offset] "p" (comptime gpRegisterOffset(REG.ESI)),446 [esi_offset] "i" (comptime gpRegisterOffset(REG.ESI)),
444 [ebp_offset] "p" (comptime gpRegisterOffset(REG.EBP)),447 [ebp_offset] "i" (comptime gpRegisterOffset(REG.EBP)),
445 [esp_offset] "p" (comptime gpRegisterOffset(REG.ESP)),448 [esp_offset] "i" (comptime gpRegisterOffset(REG.ESP)),
446 [ebx_offset] "p" (comptime gpRegisterOffset(REG.EBX)),449 [ebx_offset] "i" (comptime gpRegisterOffset(REG.EBX)),
447 [edx_offset] "p" (comptime gpRegisterOffset(REG.EDX)),450 [edx_offset] "i" (comptime gpRegisterOffset(REG.EDX)),
448 [ecx_offset] "p" (comptime gpRegisterOffset(REG.ECX)),451 [ecx_offset] "i" (comptime gpRegisterOffset(REG.ECX)),
449 [eax_offset] "p" (comptime gpRegisterOffset(REG.EAX)),452 [eax_offset] "i" (comptime gpRegisterOffset(REG.EAX)),
450 [eip_offset] "p" (comptime gpRegisterOffset(REG.EIP)),453 [eip_offset] "i" (comptime gpRegisterOffset(REG.EIP)),
451 [fs_offset] "p" (comptime gpRegisterOffset(REG.FS)),454 [fs_offset] "i" (comptime gpRegisterOffset(REG.FS)),
452 [fpregs_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),455 [fpregs_offset] "i" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
453 [regspace_offset] "p" (@offsetOf(ucontext_t, "regspace")),456 [regspace_offset] "i" (@offsetOf(ucontext_t, "regspace")),
454 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),457 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
455 [stack_offset] "p" (@offsetOf(ucontext_t, "stack")),458 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
456 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),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 [sigset_size] "i" (linux.NSIG / 8),461 [sigset_size] "i" (linux.NSIG / 8),
459 : "memory", "eax", "ecx", "edx"462 : "cc", "memory", "eax", "ecx", "edx"
460 );463 );
461}464}
462465
...@@ -464,11 +467,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {...@@ -464,11 +467,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {
464 // This method is used so that getContextInternal can control467 // This method is used so that getContextInternal can control
465 // its prologue in order to read ESP from a constant offset.468 // its prologue in order to read ESP from a constant offset.
466 // The unused &getContextInternal input is required so the function is included in the binary.469 // The unused &getContextInternal input is required so the function is included in the binary.
470 var clobber_edx: usize = undefined;
467 return asm volatile (471 return asm volatile (
468 \\ call os.linux.x86.getContextInternal472 \\ calll %[getContextInternal:P]
469 : [ret] "={eax}" (-> usize),473 : [_] "={eax}" (-> usize),
470 : [context] "{edx}" (context),474 [_] "={edx}" (clobber_edx),
475 : [_] "{edx}" (context),
471 [getContextInternal] "X" (&getContextInternal),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,24 +108,24 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid:
108pub const restore = restore_rt;108pub const restore = restore_rt;
109109
110pub fn restore_rt() callconv(.Naked) void {110pub fn restore_rt() callconv(.Naked) void {
111 switch (@import("builtin").zig_backend) {111 if (@import("builtin").zig_backend == .stage2_c) {
112 .stage2_c => asm volatile (112 asm volatile (
113 \\ movl %[number], %%eax113 \\ movl %[number], %%eax
114 \\ syscall114 \\ syscall
115 \\ retq115 \\ retq
116 :116 :
117 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),117 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
118 : "rcx", "r11", "memory"118 : "rcx", "r11", "memory"
119 ),119 );
120 else => asm volatile (120 unreachable;
121 \\ syscall
122 \\ retq
123 :
124 : [number] "{rax}" (@intFromEnum(SYS.rt_sigreturn)),
125 : "rcx", "r11", "memory"
126 ),
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}
130130
131pub const mode_t = usize;131pub const mode_t = usize;
...@@ -403,77 +403,77 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {...@@ -403,77 +403,77 @@ fn gpRegisterOffset(comptime reg_index: comptime_int) usize {
403fn getContextInternal() callconv(.Naked) void {403fn getContextInternal() callconv(.Naked) void {
404 // TODO: Read GS/FS registers?404 // TODO: Read GS/FS registers?
405 asm volatile (405 asm volatile (
406 \\ movq $0, (%[flags_offset])(%%rdi)406 \\ movq $0, %[flags_offset:c](%%rdi)
407 \\ movq $0, (%[link_offset])(%%rdi)407 \\ movq $0, %[link_offset:c](%%rdi)
408 \\ movq %%r8, (%[r8_offset])(%%rdi)408 \\ movq %%r8, %[r8_offset:c](%%rdi)
409 \\ movq %%r9, (%[r9_offset])(%%rdi)409 \\ movq %%r9, %[r9_offset:c](%%rdi)
410 \\ movq %%r10, (%[r10_offset])(%%rdi)410 \\ movq %%r10, %[r10_offset:c](%%rdi)
411 \\ movq %%r11, (%[r11_offset])(%%rdi)411 \\ movq %%r11, %[r11_offset:c](%%rdi)
412 \\ movq %%r12, (%[r12_offset])(%%rdi)412 \\ movq %%r12, %[r12_offset:c](%%rdi)
413 \\ movq %%r13, (%[r13_offset])(%%rdi)413 \\ movq %%r13, %[r13_offset:c](%%rdi)
414 \\ movq %%r14, (%[r14_offset])(%%rdi)414 \\ movq %%r14, %[r14_offset:c](%%rdi)
415 \\ movq %%r15, (%[r15_offset])(%%rdi)415 \\ movq %%r15, %[r15_offset:c](%%rdi)
416 \\ movq %%rdi, (%[rdi_offset])(%%rdi)416 \\ movq %%rdi, %[rdi_offset:c](%%rdi)
417 \\ movq %%rsi, (%[rsi_offset])(%%rdi)417 \\ movq %%rsi, %[rsi_offset:c](%%rdi)
418 \\ movq %%rbp, (%[rbp_offset])(%%rdi)418 \\ movq %%rbp, %[rbp_offset:c](%%rdi)
419 \\ movq %%rbx, (%[rbx_offset])(%%rdi)419 \\ movq %%rbx, %[rbx_offset:c](%%rdi)
420 \\ movq %%rdx, (%[rdx_offset])(%%rdi)420 \\ movq %%rdx, %[rdx_offset:c](%%rdi)
421 \\ movq %%rax, (%[rax_offset])(%%rdi)421 \\ movq %%rax, %[rax_offset:c](%%rdi)
422 \\ movq %%rcx, (%[rcx_offset])(%%rdi)422 \\ movq %%rcx, %[rcx_offset:c](%%rdi)
423 \\ movq (%%rsp), %%rcx423 \\ movq (%%rsp), %%rcx
424 \\ movq %%rcx, (%[rip_offset])(%%rdi)424 \\ movq %%rcx, %[rip_offset:c](%%rdi)
425 \\ leaq 8(%%rsp), %%rcx425 \\ leaq 8(%%rsp), %%rcx
426 \\ movq %%rcx, (%[rsp_offset])(%%rdi)426 \\ movq %%rcx, %[rsp_offset:c](%%rdi)
427 \\ pushfq427 \\ pushfq
428 \\ popq (%[efl_offset])(%%rdi)428 \\ popq %[efl_offset:c](%%rdi)
429 \\ leaq (%[fpmem_offset])(%%rdi), %%rcx429 \\ leaq %[fpmem_offset:c](%%rdi), %%rcx
430 \\ movq %%rcx, (%[fpstate_offset])(%%rdi)430 \\ movq %%rcx, %[fpstate_offset:c](%%rdi)
431 \\ fnstenv (%%rcx)431 \\ fnstenv (%%rcx)
432 \\ fldenv (%%rcx)432 \\ fldenv (%%rcx)
433 \\ stmxcsr (%[mxcsr_offset])(%%rdi)433 \\ stmxcsr %[mxcsr_offset:c](%%rdi)
434 \\ leaq (%[stack_offset])(%%rdi), %%rsi434 \\ leaq %[stack_offset:c](%%rdi), %%rsi
435 \\ movq %%rdi, %%r8435 \\ movq %%rdi, %%r8
436 \\ xorq %%rdi, %%rdi436 \\ xorl %%edi, %%edi
437 \\ movq %[sigaltstack], %%rax437 \\ movq %[sigaltstack], %%rax
438 \\ syscall438 \\ syscall
439 \\ cmpq $0, %%rax439 \\ testq %%rax, %%rax
440 \\ jne return440 \\ jnz 0f
441 \\ movq %[sigprocmask], %%rax441 \\ movq %[sigprocmask], %%rax
442 \\ xorq %%rsi, %%rsi442 \\ xorl %%esi, %%esi
443 \\ leaq (%[sigmask_offset])(%%r8), %%rdx443 \\ leaq %[sigmask_offset:c](%%r8), %%rdx
444 \\ movq %[sigset_size], %%r10444 \\ movl %[sigset_size], %%r10d
445 \\ syscall445 \\ syscall
446 \\ return:446 \\0:
447 :447 :
448 : [flags_offset] "p" (@offsetOf(ucontext_t, "flags")),448 : [flags_offset] "i" (@offsetOf(ucontext_t, "flags")),
449 [link_offset] "p" (@offsetOf(ucontext_t, "link")),449 [link_offset] "i" (@offsetOf(ucontext_t, "link")),
450 [r8_offset] "p" (comptime gpRegisterOffset(REG.R8)),450 [r8_offset] "i" (comptime gpRegisterOffset(REG.R8)),
451 [r9_offset] "p" (comptime gpRegisterOffset(REG.R9)),451 [r9_offset] "i" (comptime gpRegisterOffset(REG.R9)),
452 [r10_offset] "p" (comptime gpRegisterOffset(REG.R10)),452 [r10_offset] "i" (comptime gpRegisterOffset(REG.R10)),
453 [r11_offset] "p" (comptime gpRegisterOffset(REG.R11)),453 [r11_offset] "i" (comptime gpRegisterOffset(REG.R11)),
454 [r12_offset] "p" (comptime gpRegisterOffset(REG.R12)),454 [r12_offset] "i" (comptime gpRegisterOffset(REG.R12)),
455 [r13_offset] "p" (comptime gpRegisterOffset(REG.R13)),455 [r13_offset] "i" (comptime gpRegisterOffset(REG.R13)),
456 [r14_offset] "p" (comptime gpRegisterOffset(REG.R14)),456 [r14_offset] "i" (comptime gpRegisterOffset(REG.R14)),
457 [r15_offset] "p" (comptime gpRegisterOffset(REG.R15)),457 [r15_offset] "i" (comptime gpRegisterOffset(REG.R15)),
458 [rdi_offset] "p" (comptime gpRegisterOffset(REG.RDI)),458 [rdi_offset] "i" (comptime gpRegisterOffset(REG.RDI)),
459 [rsi_offset] "p" (comptime gpRegisterOffset(REG.RSI)),459 [rsi_offset] "i" (comptime gpRegisterOffset(REG.RSI)),
460 [rbp_offset] "p" (comptime gpRegisterOffset(REG.RBP)),460 [rbp_offset] "i" (comptime gpRegisterOffset(REG.RBP)),
461 [rbx_offset] "p" (comptime gpRegisterOffset(REG.RBX)),461 [rbx_offset] "i" (comptime gpRegisterOffset(REG.RBX)),
462 [rdx_offset] "p" (comptime gpRegisterOffset(REG.RDX)),462 [rdx_offset] "i" (comptime gpRegisterOffset(REG.RDX)),
463 [rax_offset] "p" (comptime gpRegisterOffset(REG.RAX)),463 [rax_offset] "i" (comptime gpRegisterOffset(REG.RAX)),
464 [rcx_offset] "p" (comptime gpRegisterOffset(REG.RCX)),464 [rcx_offset] "i" (comptime gpRegisterOffset(REG.RCX)),
465 [rsp_offset] "p" (comptime gpRegisterOffset(REG.RSP)),465 [rsp_offset] "i" (comptime gpRegisterOffset(REG.RSP)),
466 [rip_offset] "p" (comptime gpRegisterOffset(REG.RIP)),466 [rip_offset] "i" (comptime gpRegisterOffset(REG.RIP)),
467 [efl_offset] "p" (comptime gpRegisterOffset(REG.EFL)),467 [efl_offset] "i" (comptime gpRegisterOffset(REG.EFL)),
468 [fpstate_offset] "p" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),468 [fpstate_offset] "i" (@offsetOf(ucontext_t, "mcontext") + @offsetOf(mcontext_t, "fpregs")),
469 [fpmem_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem")),469 [fpmem_offset] "i" (@offsetOf(ucontext_t, "fpregs_mem")),
470 [mxcsr_offset] "p" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")),470 [mxcsr_offset] "i" (@offsetOf(ucontext_t, "fpregs_mem") + @offsetOf(fpstate, "mxcsr")),
471 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),471 [sigaltstack] "i" (@intFromEnum(linux.SYS.sigaltstack)),
472 [stack_offset] "p" (@offsetOf(ucontext_t, "stack")),472 [stack_offset] "i" (@offsetOf(ucontext_t, "stack")),
473 [sigprocmask] "i" (@intFromEnum(linux.SYS.rt_sigprocmask)),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 [sigset_size] "i" (linux.NSIG / 8),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}
479479
...@@ -481,11 +481,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {...@@ -481,11 +481,13 @@ pub inline fn getcontext(context: *ucontext_t) usize {
481 // This method is used so that getContextInternal can control481 // This method is used so that getContextInternal can control
482 // its prologue in order to read RSP from a constant offset482 // its prologue in order to read RSP from a constant offset
483 // The unused &getContextInternal input is required so the function is included in the binary.483 // The unused &getContextInternal input is required so the function is included in the binary.
484 var clobber_rdi: usize = undefined;
484 return asm volatile (485 return asm volatile (
485 \\ call os.linux.x86_64.getContextInternal486 \\ callq %[getContextInternal:P]
486 : [ret] "={rax}" (-> usize),487 : [_] "={rax}" (-> usize),
487 : [context] "{rdi}" (context),488 [_] "={rdi}" (clobber_rdi),
489 : [_] "{rdi}" (context),
488 [getContextInternal] "X" (&getContextInternal),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,38 +256,38 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv
256fn _start() callconv(.Naked) noreturn {256fn _start() callconv(.Naked) noreturn {
257 switch (builtin.zig_backend) {257 switch (builtin.zig_backend) {
258 .stage2_c => {258 .stage2_c => {
259 @export(argc_argv_ptr, .{ .name = "argc_argv_ptr" });259 asm volatile (switch (native_arch) {
260 @export(posixCallMainAndExit, .{ .name = "_posixCallMainAndExit" });260 .x86_64 =>
261 switch (native_arch) {
262 .x86_64 => asm volatile (
263 \\ xorl %%ebp, %%ebp261 \\ xorl %%ebp, %%ebp
264 \\ movq %%rsp, argc_argv_ptr262 \\ movq %%rsp, %[argc_argv_ptr]
265 \\ andq $-16, %%rsp263 \\ andq $-16, %%rsp
266 \\ call _posixCallMainAndExit264 \\ callq %[posixCallMainAndExit:P]
267 ),265 ,
268 .x86 => asm volatile (266 .x86 =>
269 \\ xorl %%ebp, %%ebp267 \\ xorl %%ebp, %%ebp
270 \\ movl %%esp, argc_argv_ptr268 \\ movl %%esp, %[argc_argv_ptr]
271 \\ andl $-16, %%esp269 \\ andl $-16, %%esp
272 \\ jmp _posixCallMainAndExit270 \\ calll %[posixCallMainAndExit:P]
273 ),271 ,
274 .aarch64, .aarch64_be => asm volatile (272 .aarch64, .aarch64_be =>
275 \\ mov fp, #0273 \\ mov fp, #0
276 \\ mov lr, #0274 \\ mov lr, #0
277 \\ mov x0, sp275 \\ mov x0, sp
278 \\ adrp x1, argc_argv_ptr276 \\ str x0, %[argc_argv_ptr]
279 \\ str x0, [x1, :lo12:argc_argv_ptr]277 \\ b %[posixCallMainAndExit]
280 \\ b _posixCallMainAndExit278 ,
281 ),279 .arm, .armeb, .thumb =>
282 .arm, .armeb, .thumb => asm volatile (
283 \\ mov fp, #0280 \\ mov fp, #0
284 \\ mov lr, #0281 \\ mov lr, #0
285 \\ str sp, argc_argv_ptr282 \\ str sp, %[argc_argv_ptr]
286 \\ and sp, #-16283 \\ and sp, #-16
287 \\ b _posixCallMainAndExit284 \\ b %[posixCallMainAndExit]
288 ),285 ,
289 else => @compileError("unsupported arch"),286 else => @compileError("unsupported arch"),
290 }287 }
288 : [argc_argv_ptr] "=m" (argc_argv_ptr),
289 : [posixCallMainAndExit] "X" (&posixCallMainAndExit),
290 );
291 unreachable;291 unreachable;
292 },292 },
293 else => switch (native_arch) {293 else => switch (native_arch) {
src/codegen/c.zig+50-35
...@@ -30,7 +30,7 @@ pub const CValue = union(enum) {...@@ -30,7 +30,7 @@ pub const CValue = union(enum) {
30 /// Address of a local.30 /// Address of a local.
31 local_ref: LocalIndex,31 local_ref: LocalIndex,
32 /// A constant instruction, to be rendered inline.32 /// A constant instruction, to be rendered inline.
33 constant: Air.Inst.Ref,33 constant: InternPool.Index,
34 /// Index into the parameters34 /// Index into the parameters
35 arg: usize,35 arg: usize,
36 /// The array field of a parameter36 /// The array field of a parameter
...@@ -302,7 +302,7 @@ pub const Function = struct {...@@ -302,7 +302,7 @@ pub const Function = struct {
302 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);302 try f.object.dg.renderValue(writer, ty, val, .StaticInitializer);
303 try writer.writeAll(";\n ");303 try writer.writeAll(";\n ");
304 break :result decl_c_value;304 break :result decl_c_value;
305 } else .{ .constant = ref };305 } else .{ .constant = val.toIntern() };
306306
307 gop.value_ptr.* = result;307 gop.value_ptr.* = result;
308 return result;308 return result;
...@@ -352,57 +352,63 @@ pub const Function = struct {...@@ -352,57 +352,63 @@ pub const Function = struct {
352352
353 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {353 fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void {
354 switch (c_value) {354 switch (c_value) {
355 .constant => |inst| {355 .constant => |val| try f.object.dg.renderValue(
356 const mod = f.object.dg.module;356 w,
357 const ty = f.typeOf(inst);357 f.object.dg.module.intern_pool.typeOf(val).toType(),
358 const val = (try f.air.value(inst, mod)).?;358 val.toValue(),
359 return f.object.dg.renderValue(w, ty, val, location);359 location,
360 },360 ),
361 .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location),361 .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location),
362 else => return f.object.dg.writeCValue(w, c_value),362 else => try f.object.dg.writeCValue(w, c_value),
363 }363 }
364 }364 }
365365
366 fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void {366 fn writeCValueDeref(f: *Function, w: anytype, c_value: CValue) !void {
367 switch (c_value) {367 switch (c_value) {
368 .constant => |inst| {368 .constant => |val| {
369 const mod = f.object.dg.module;
370 const ty = f.typeOf(inst);
371 const val = (try f.air.value(inst, mod)).?;
372 try w.writeAll("(*");369 try w.writeAll("(*");
373 try f.object.dg.renderValue(w, ty, val, .Other);370 try f.object.dg.renderValue(
374 return w.writeByte(')');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 }
379381
380 fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {382 fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {
381 switch (c_value) {383 switch (c_value) {
382 .constant => |inst| {384 .constant => |val| {
383 const mod = f.object.dg.module;385 try f.object.dg.renderValue(
384 const ty = f.typeOf(inst);386 w,
385 const val = (try f.air.value(inst, mod)).?;387 f.object.dg.module.intern_pool.typeOf(val).toType(),
386 try f.object.dg.renderValue(w, ty, val, .Other);388 val.toValue(),
389 .Other,
390 );
387 try w.writeByte('.');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 }
393397
394 fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {398 fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void {
395 switch (c_value) {399 switch (c_value) {
396 .constant => |inst| {400 .constant => |val| {
397 const mod = f.object.dg.module;
398 const ty = f.typeOf(inst);
399 const val = (try f.air.value(inst, mod)).?;
400 try w.writeByte('(');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 try w.writeAll(")->");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 }
408414
...@@ -4763,11 +4769,20 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4763,11 +4769,20 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
4763 return .none;4769 return .none;
4764}4770}
47654771
4766fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool {4772fn asmInputNeedsLocal(f: *Function, constraint: []const u8, value: CValue) bool {
4767 return switch (constraint[0]) {4773 return switch (constraint[0]) {
4768 '{' => true,4774 '{' => true,
4769 'i', 'r' => false,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}
47734788
...@@ -4848,7 +4863,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4848,7 +4863,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
48484863
4849 const is_reg = constraint[0] == '{';4864 const is_reg = constraint[0] == '{';
4850 const input_val = try f.resolveInst(input);4865 const input_val = try f.resolveInst(input);
4851 if (asmInputNeedsLocal(constraint, input_val)) {4866 if (asmInputNeedsLocal(f, constraint, input_val)) {
4852 const input_ty = f.typeOf(input);4867 const input_ty = f.typeOf(input);
4853 if (is_reg) try writer.writeAll("register ");4868 if (is_reg) try writer.writeAll("register ");
4854 const alignment = 0;4869 const alignment = 0;
...@@ -4969,7 +4984,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4969,7 +4984,7 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue {
4969 const is_reg = constraint[0] == '{';4984 const is_reg = constraint[0] == '{';
4970 const input_val = try f.resolveInst(input);4985 const input_val = try f.resolveInst(input);
4971 try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint, null)});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 const input_local = .{ .local = locals_index };4988 const input_local = .{ .local = locals_index };
4974 locals_index += 1;4989 locals_index += 1;
4975 break :local input_local;4990 break :local input_local;
test/behavior/fn.zig+1
...@@ -151,6 +151,7 @@ fn fnWithUnreachable() noreturn {...@@ -151,6 +151,7 @@ fn fnWithUnreachable() noreturn {
151151
152test "extern struct with stdcallcc fn pointer" {152test "extern struct with stdcallcc fn pointer" {
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;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 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;155 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
155156
156 const S = extern struct {157 const S = extern struct {
test/tests.zig+1
...@@ -1053,6 +1053,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -1053,6 +1053,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
1053 // TODO stop violating these pedantic errors. spotted on linux1053 // TODO stop violating these pedantic errors. spotted on linux
1054 "-Wno-address-of-packed-member",1054 "-Wno-address-of-packed-member",
1055 "-Wno-gnu-folding-constant",1055 "-Wno-gnu-folding-constant",
1056 "-Wno-incompatible-function-pointer-types",
1056 "-Wno-incompatible-pointer-types",1057 "-Wno-incompatible-pointer-types",
1057 "-Wno-overlength-strings",1058 "-Wno-overlength-strings",
1058 // TODO stop violating these pedantic errors. spotted on darwin1059 // TODO stop violating these pedantic errors. spotted on darwin