master
1const builtin = @import("builtin");
2const std = @import("../../std.zig");
3const SYS = std.os.linux.SYS;
4
5pub fn syscall0(number: SYS) u32 {
6 return asm volatile ("int $0x80"
7 : [ret] "={eax}" (-> u32),
8 : [number] "{eax}" (@intFromEnum(number)),
9 : .{ .memory = true });
10}
11
12pub fn syscall1(number: SYS, arg1: u32) u32 {
13 return asm volatile ("int $0x80"
14 : [ret] "={eax}" (-> u32),
15 : [number] "{eax}" (@intFromEnum(number)),
16 [arg1] "{ebx}" (arg1),
17 : .{ .memory = true });
18}
19
20pub fn syscall2(number: SYS, arg1: u32, arg2: u32) u32 {
21 return asm volatile ("int $0x80"
22 : [ret] "={eax}" (-> u32),
23 : [number] "{eax}" (@intFromEnum(number)),
24 [arg1] "{ebx}" (arg1),
25 [arg2] "{ecx}" (arg2),
26 : .{ .memory = true });
27}
28
29pub fn syscall3(number: SYS, arg1: u32, arg2: u32, arg3: u32) u32 {
30 return asm volatile ("int $0x80"
31 : [ret] "={eax}" (-> u32),
32 : [number] "{eax}" (@intFromEnum(number)),
33 [arg1] "{ebx}" (arg1),
34 [arg2] "{ecx}" (arg2),
35 [arg3] "{edx}" (arg3),
36 : .{ .memory = true });
37}
38
39pub fn syscall4(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32) u32 {
40 return asm volatile ("int $0x80"
41 : [ret] "={eax}" (-> u32),
42 : [number] "{eax}" (@intFromEnum(number)),
43 [arg1] "{ebx}" (arg1),
44 [arg2] "{ecx}" (arg2),
45 [arg3] "{edx}" (arg3),
46 [arg4] "{esi}" (arg4),
47 : .{ .memory = true });
48}
49
50pub fn syscall5(number: SYS, arg1: u32, arg2: u32, arg3: u32, arg4: u32, arg5: u32) u32 {
51 return asm volatile ("int $0x80"
52 : [ret] "={eax}" (-> u32),
53 : [number] "{eax}" (@intFromEnum(number)),
54 [arg1] "{ebx}" (arg1),
55 [arg2] "{ecx}" (arg2),
56 [arg3] "{edx}" (arg3),
57 [arg4] "{esi}" (arg4),
58 [arg5] "{edi}" (arg5),
59 : .{ .memory = true });
60}
61
62pub fn syscall6(
63 number: SYS,
64 arg1: u32,
65 arg2: u32,
66 arg3: u32,
67 arg4: u32,
68 arg5: u32,
69 arg6: u32,
70) u32 {
71 // arg6 can't be passed to asm in a register because ebp might be reserved as the frame pointer
72 // and there are no more GPRs available; so we'll need a memory operand for it. Adding that
73 // memory operand means that on PIC we might need a reference to the GOT, which in turn needs
74 // *its* own GPR, so we need to pass another arg in memory too! This is surprisingly hard to get
75 // right, because we can't touch esp or ebp until we're done with the memory input (as that
76 // input could be relative to esp or ebp).
77 const args56: [2]u32 = .{ arg5, arg6 };
78 return asm volatile (
79 \\ push %[args56]
80 \\ push %%ebp
81 \\ mov 4(%%esp), %%ebp
82 \\ mov %%edi, 4(%%esp)
83 \\ // The saved %edi and %ebp are on the stack, and %ebp points to `args56`.
84 \\ // Prepare the last two args, syscall, then pop the saved %ebp and %edi.
85 \\ mov (%%ebp), %%edi
86 \\ mov 4(%%ebp), %%ebp
87 \\ int $0x80
88 \\ pop %%ebp
89 \\ pop %%edi
90 : [ret] "={eax}" (-> u32),
91 : [number] "{eax}" (@intFromEnum(number)),
92 [arg1] "{ebx}" (arg1),
93 [arg2] "{ecx}" (arg2),
94 [arg3] "{edx}" (arg3),
95 [arg4] "{esi}" (arg4),
96 [args56] "rm" (&args56),
97 : .{ .memory = true });
98}
99
100pub fn socketcall(call: u32, args: [*]const u32) u32 {
101 return asm volatile ("int $0x80"
102 : [ret] "={eax}" (-> u32),
103 : [number] "{eax}" (@intFromEnum(SYS.socketcall)),
104 [arg1] "{ebx}" (call),
105 [arg2] "{ecx}" (@intFromPtr(args)),
106 : .{ .memory = true });
107}
108
109pub fn clone() callconv(.naked) u32 {
110 // __clone(func, stack, flags, arg, ptid, tls, ctid)
111 // +8, +12, +16, +20, +24, +28, +32
112 //
113 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
114 // eax, ebx, ecx, edx, esi, edi
115 asm volatile (
116 \\ pushl %%ebp
117 \\ movl %%esp,%%ebp
118 \\ pushl %%ebx
119 \\ pushl %%esi
120 \\ pushl %%edi
121 \\ // Setup the arguments
122 \\ movl 16(%%ebp),%%ebx
123 \\ movl 12(%%ebp),%%ecx
124 \\ andl $-16,%%ecx
125 \\ subl $20,%%ecx
126 \\ movl 20(%%ebp),%%eax
127 \\ movl %%eax,4(%%ecx)
128 \\ movl 8(%%ebp),%%eax
129 \\ movl %%eax,0(%%ecx)
130 \\ movl 24(%%ebp),%%edx
131 \\ movl 28(%%ebp),%%esi
132 \\ movl 32(%%ebp),%%edi
133 \\ movl $120,%%eax // SYS_clone
134 \\ int $128
135 \\ testl %%eax,%%eax
136 \\ jz 1f
137 \\ popl %%edi
138 \\ popl %%esi
139 \\ popl %%ebx
140 \\ popl %%ebp
141 \\ retl
142 \\
143 \\1:
144 );
145 if (builtin.unwind_tables != .none or !builtin.strip_debug_info) asm volatile (
146 \\ .cfi_undefined %%eip
147 );
148 asm volatile (
149 \\ xorl %%ebp,%%ebp
150 \\
151 \\ popl %%eax
152 \\ calll *%%eax
153 \\ movl %%eax,%%ebx
154 \\ movl $1,%%eax // SYS_exit
155 \\ int $128
156 );
157}
158
159pub fn restore() callconv(.naked) noreturn {
160 switch (builtin.zig_backend) {
161 .stage2_c => asm volatile (
162 \\ addl $4, %%esp
163 \\ movl %[number], %%eax
164 \\ int $0x80
165 :
166 : [number] "i" (@intFromEnum(SYS.sigreturn)),
167 ),
168 else => asm volatile (
169 \\ addl $4, %%esp
170 \\ int $0x80
171 :
172 : [number] "{eax}" (@intFromEnum(SYS.sigreturn)),
173 ),
174 }
175}
176
177pub fn restore_rt() callconv(.naked) noreturn {
178 switch (builtin.zig_backend) {
179 .stage2_c => asm volatile (
180 \\ movl %[number], %%eax
181 \\ int $0x80
182 :
183 : [number] "i" (@intFromEnum(SYS.rt_sigreturn)),
184 ),
185 else => asm volatile (
186 \\ int $0x80
187 :
188 : [number] "{eax}" (@intFromEnum(SYS.rt_sigreturn)),
189 ),
190 }
191}
192
193pub const VDSO = struct {
194 pub const CGT_SYM = "__vdso_clock_gettime";
195 pub const CGT_VER = "LINUX_2.6";
196};
197
198pub const blksize_t = i32;
199pub const nlink_t = u32;
200pub const time_t = i32;
201pub const mode_t = u32;
202pub const off_t = i64;
203pub const ino_t = u64;
204pub const dev_t = u64;
205pub const blkcnt_t = i64;
206
207// The `stat` definition used by the Linux kernel.
208pub const Stat = extern struct {
209 dev: dev_t,
210 __dev_padding: u32,
211 __ino_truncated: u32,
212 mode: mode_t,
213 nlink: nlink_t,
214 uid: std.os.linux.uid_t,
215 gid: std.os.linux.gid_t,
216 rdev: dev_t,
217 __rdev_padding: u32,
218 size: off_t,
219 blksize: blksize_t,
220 blocks: blkcnt_t,
221 atim: std.os.linux.timespec,
222 mtim: std.os.linux.timespec,
223 ctim: std.os.linux.timespec,
224 ino: ino_t,
225
226 pub fn atime(self: @This()) std.os.linux.timespec {
227 return self.atim;
228 }
229
230 pub fn mtime(self: @This()) std.os.linux.timespec {
231 return self.mtim;
232 }
233
234 pub fn ctime(self: @This()) std.os.linux.timespec {
235 return self.ctim;
236 }
237};
238
239pub const user_desc = extern struct {
240 entry_number: u32,
241 base_addr: u32,
242 limit: u32,
243 flags: packed struct(u32) {
244 seg_32bit: u1,
245 contents: u2,
246 read_exec_only: u1,
247 limit_in_pages: u1,
248 seg_not_present: u1,
249 useable: u1,
250 _: u25 = undefined,
251 },
252};
253
254/// socketcall() call numbers
255pub const SC = struct {
256 pub const socket = 1;
257 pub const bind = 2;
258 pub const connect = 3;
259 pub const listen = 4;
260 pub const accept = 5;
261 pub const getsockname = 6;
262 pub const getpeername = 7;
263 pub const socketpair = 8;
264 pub const send = 9;
265 pub const recv = 10;
266 pub const sendto = 11;
267 pub const recvfrom = 12;
268 pub const shutdown = 13;
269 pub const setsockopt = 14;
270 pub const getsockopt = 15;
271 pub const sendmsg = 16;
272 pub const recvmsg = 17;
273 pub const accept4 = 18;
274 pub const recvmmsg = 19;
275 pub const sendmmsg = 20;
276};