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};