diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-09-12 10:48:38 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-09-12 10:48:38 -0700 |
| commit | af4cc20ce275aeb0e59eee3d893b2f310c1f0239 (patch) | |
| tree | cc3ff8fa792c20ff0fc0f1e19e98998cc76c07c2 /lib/std | |
| parent | 03a23418ff13e6ff64cdeed3ef4b54f99c533d88 (diff) | |
| parent | 9fe4c89230df2d78c8bf37b4b1d7a9bedb92677b (diff) | |
| download | zig-af4cc20ce275aeb0e59eee3d893b2f310c1f0239.tar.gz zig-af4cc20ce275aeb0e59eee3d893b2f310c1f0239.zip | |
Merge remote-tracking branch 'origin/master' into stage2-zig-cc
Master branch added in the concept of library versioning being optional
to main.cpp. It will need to be re-added into this branch before merging
back into master.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/build.zig | 124 | ||||
| -rw-r--r-- | lib/std/c.zig | 15 | ||||
| -rw-r--r-- | lib/std/compress.zig | 2 | ||||
| -rw-r--r-- | lib/std/compress/deflate.zig | 184 | ||||
| -rw-r--r-- | lib/std/compress/gzip.zig | 248 | ||||
| -rw-r--r-- | lib/std/compress/rfc1952.txt.gz | bin | 0 -> 8059 bytes | |||
| -rw-r--r-- | lib/std/event/loop.zig | 3 | ||||
| -rw-r--r-- | lib/std/fs/file.zig | 8 | ||||
| -rw-r--r-- | lib/std/os.zig | 43 | ||||
| -rw-r--r-- | lib/std/os/bits/linux.zig | 3 | ||||
| -rw-r--r-- | lib/std/os/bits/linux/powerpc64.zig | 602 | ||||
| -rw-r--r-- | lib/std/os/bits/linux/prctl.zig | 158 | ||||
| -rw-r--r-- | lib/std/os/bits/linux/securebits.zig | 41 | ||||
| -rw-r--r-- | lib/std/os/linux.zig | 5 | ||||
| -rw-r--r-- | lib/std/os/linux/powerpc64.zig | 127 | ||||
| -rw-r--r-- | lib/std/os/linux/tls.zig | 13 | ||||
| -rw-r--r-- | lib/std/priority_queue.zig | 11 | ||||
| -rw-r--r-- | lib/std/process.zig | 14 | ||||
| -rw-r--r-- | lib/std/special/c.zig | 55 | ||||
| -rw-r--r-- | lib/std/start.zig | 15 |
20 files changed, 1572 insertions, 99 deletions
diff --git a/lib/std/build.zig b/lib/std/build.zig index 1673737bef..30ecf98b76 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -258,9 +258,14 @@ pub const Builder = struct { })); } - pub fn addSharedLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8, ver: Version) *LibExeObjStep { + pub fn addSharedLibrary( + self: *Builder, + name: []const u8, + root_src: ?[]const u8, + kind: LibExeObjStep.SharedLibKind, + ) *LibExeObjStep { const root_src_param = if (root_src) |p| @as(FileSource, .{ .path = p }) else null; - return LibExeObjStep.createSharedLibrary(self, name, root_src_param, ver); + return LibExeObjStep.createSharedLibrary(self, name, root_src_param, kind); } pub fn addStaticLibrary(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { @@ -338,11 +343,13 @@ pub const Builder = struct { return TranslateCStep.create(self, source); } - pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) Version { - return Version{ - .major = major, - .minor = minor, - .patch = patch, + pub fn version(self: *const Builder, major: u32, minor: u32, patch: u32) LibExeObjStep.SharedLibKind { + return .{ + .versioned = .{ + .major = major, + .minor = minor, + .patch = patch, + }, }; } @@ -1048,6 +1055,7 @@ pub const Builder = struct { .Bin => self.exe_dir, .Lib => self.lib_dir, .Header => self.h_dir, + .Custom => |path| fs.path.join(self.allocator, &[_][]const u8{ self.install_path, path }) catch unreachable, }; return fs.path.resolve( self.allocator, @@ -1166,7 +1174,7 @@ pub const LibExeObjStep = struct { version_script: ?[]const u8 = null, out_filename: []const u8, is_dynamic: bool, - version: Version, + version: ?Version, build_mode: builtin.Mode, kind: Kind, major_only_filename: []const u8, @@ -1212,6 +1220,8 @@ pub const LibExeObjStep = struct { is_linking_libc: bool = false, vcpkg_bin_path: ?[]const u8 = null, + /// This may be set in order to override the default install directory + override_dest_dir: ?InstallDir, installed_path: ?[]const u8, install_step: ?*InstallArtifactStep, @@ -1268,33 +1278,41 @@ pub const LibExeObjStep = struct { Test, }; - pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, ver: Version) *LibExeObjStep { + const SharedLibKind = union(enum) { + versioned: Version, + unversioned: void, + }; + + pub fn createSharedLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource, kind: SharedLibKind) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, ver); + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, true, switch (kind) { + .versioned => |ver| ver, + .unversioned => null, + }); return self; } pub fn createStaticLibrary(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Lib, false, null); return self; } pub fn createObject(builder: *Builder, name: []const u8, root_src: ?FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Obj, false, null); return self; } pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?FileSource, is_dynamic: bool) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Exe, is_dynamic, null); return self; } pub fn createTest(builder: *Builder, name: []const u8, root_src: FileSource) *LibExeObjStep { const self = builder.allocator.create(LibExeObjStep) catch unreachable; - self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, builder.version(0, 0, 0)); + self.* = initExtraArgs(builder, name, root_src, Kind.Test, false, null); return self; } @@ -1304,7 +1322,7 @@ pub const LibExeObjStep = struct { root_src: ?FileSource, kind: Kind, is_dynamic: bool, - ver: Version, + ver: ?Version, ) LibExeObjStep { if (mem.indexOf(u8, name, "/") != null or mem.indexOf(u8, name, "\\") != null) { panic("invalid name: '{}'. It looks like a file path, but it is supposed to be the library or application name.", .{name}); @@ -1348,6 +1366,7 @@ pub const LibExeObjStep = struct { .rdynamic = false, .output_dir = null, .single_threaded = false, + .override_dest_dir = null, .installed_path = null, .install_step = null, }; @@ -1375,17 +1394,17 @@ pub const LibExeObjStep = struct { self.target.staticLibSuffix(), }); self.out_lib_filename = self.out_filename; - } else { + } else if (self.version) |version| { if (self.target.isDarwin()) { self.out_filename = self.builder.fmt("lib{}.{d}.{d}.{d}.dylib", .{ self.name, - self.version.major, - self.version.minor, - self.version.patch, + version.major, + version.minor, + version.patch, }); self.major_only_filename = self.builder.fmt("lib{}.{d}.dylib", .{ self.name, - self.version.major, + version.major, }); self.name_only_filename = self.builder.fmt("lib{}.dylib", .{self.name}); self.out_lib_filename = self.out_filename; @@ -1395,14 +1414,25 @@ pub const LibExeObjStep = struct { } else { self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}", .{ self.name, - self.version.major, - self.version.minor, - self.version.patch, + version.major, + version.minor, + version.patch, }); - self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, self.version.major }); + self.major_only_filename = self.builder.fmt("lib{}.so.{d}", .{ self.name, version.major }); self.name_only_filename = self.builder.fmt("lib{}.so", .{self.name}); self.out_lib_filename = self.out_filename; } + } else { + if (self.target.isDarwin()) { + self.out_filename = self.builder.fmt("lib{}.dylib", .{self.name}); + self.out_lib_filename = self.out_filename; + } else if (self.target.isWindows()) { + self.out_filename = self.builder.fmt("{}.dll", .{self.name}); + self.out_lib_filename = self.builder.fmt("{}.lib", .{self.name}); + } else { + self.out_filename = self.builder.fmt("lib{}.so", .{self.name}); + self.out_lib_filename = self.out_filename; + } } }, } @@ -2037,14 +2067,16 @@ pub const LibExeObjStep = struct { zig_args.append(self.name) catch unreachable; if (self.kind == Kind.Lib and self.is_dynamic) { - zig_args.append("--ver-major") catch unreachable; - zig_args.append(builder.fmt("{}", .{self.version.major})) catch unreachable; + if (self.version) |version| { + zig_args.append("--ver-major") catch unreachable; + zig_args.append(builder.fmt("{}", .{version.major})) catch unreachable; - zig_args.append("--ver-minor") catch unreachable; - zig_args.append(builder.fmt("{}", .{self.version.minor})) catch unreachable; + zig_args.append("--ver-minor") catch unreachable; + zig_args.append(builder.fmt("{}", .{version.minor})) catch unreachable; - zig_args.append("--ver-patch") catch unreachable; - zig_args.append(builder.fmt("{}", .{self.version.patch})) catch unreachable; + zig_args.append("--ver-patch") catch unreachable; + zig_args.append(builder.fmt("{}", .{version.patch})) catch unreachable; + } } if (self.is_dynamic) { try zig_args.append("-dynamic"); @@ -2285,7 +2317,7 @@ pub const LibExeObjStep = struct { } } - if (self.kind == Kind.Lib and self.is_dynamic and self.target.wantSharedLibSymLinks()) { + if (self.kind == Kind.Lib and self.is_dynamic and self.version != null and self.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, self.getOutputPath(), self.major_only_filename, self.name_only_filename); } } @@ -2309,17 +2341,17 @@ pub const InstallArtifactStep = struct { .builder = builder, .step = Step.init(.InstallArtifact, builder.fmt("install {}", .{artifact.step.name}), builder.allocator, make), .artifact = artifact, - .dest_dir = switch (artifact.kind) { + .dest_dir = artifact.override_dest_dir orelse switch (artifact.kind) { .Obj => unreachable, .Test => unreachable, - .Exe => .Bin, - .Lib => .Lib, + .Exe => InstallDir{ .Bin = {} }, + .Lib => InstallDir{ .Lib = {} }, }, .pdb_dir = if (artifact.producesPdbFile()) blk: { if (artifact.kind == .Exe) { - break :blk InstallDir.Bin; + break :blk InstallDir{ .Bin = {} }; } else { - break :blk InstallDir.Lib; + break :blk InstallDir{ .Lib = {} }; } } else null, .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null, @@ -2329,8 +2361,10 @@ pub const InstallArtifactStep = struct { builder.pushInstalledFile(self.dest_dir, artifact.out_filename); if (self.artifact.isDynamicLibrary()) { - builder.pushInstalledFile(.Lib, artifact.major_only_filename); - builder.pushInstalledFile(.Lib, artifact.name_only_filename); + if (self.artifact.version != null) { + builder.pushInstalledFile(.Lib, artifact.major_only_filename); + builder.pushInstalledFile(.Lib, artifact.name_only_filename); + } if (self.artifact.target.isWindows()) { builder.pushInstalledFile(.Lib, artifact.out_lib_filename); } @@ -2350,7 +2384,7 @@ pub const InstallArtifactStep = struct { const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename); try builder.updateFile(self.artifact.getOutputPath(), full_dest_path); - if (self.artifact.isDynamicLibrary() and self.artifact.target.wantSharedLibSymLinks()) { + if (self.artifact.isDynamicLibrary() and self.artifact.version != null and self.artifact.target.wantSharedLibSymLinks()) { try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename); } if (self.pdb_dir) |pdb_dir| { @@ -2615,11 +2649,13 @@ const VcpkgRootStatus = enum { pub const VcpkgLinkage = std.builtin.LinkMode; -pub const InstallDir = enum { - Prefix, - Lib, - Bin, - Header, +pub const InstallDir = union(enum) { + Prefix: void, + Lib: void, + Bin: void, + Header: void, + /// A path relative to the prefix + Custom: []const u8, }; pub const InstalledFile = struct { diff --git a/lib/std/c.zig b/lib/std/c.zig index 1b3f403ab5..aa50fff90e 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -132,8 +132,6 @@ pub usingnamespace switch (builtin.os.tag) { }, }; -pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; -pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; pub extern "c" fn rmdir(path: [*:0]const u8) c_int; pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8; pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; @@ -237,8 +235,15 @@ pub usingnamespace switch (builtin.os.tag) { pub extern "c" fn kill(pid: pid_t, sig: c_int) c_int; pub extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; -pub extern "c" fn setgid(ruid: c_uint, euid: c_uint) c_int; -pub extern "c" fn setuid(uid: c_uint) c_int; + +pub extern "c" fn setuid(uid: uid_t) c_int; +pub extern "c" fn setgid(gid: gid_t) c_int; +pub extern "c" fn seteuid(euid: uid_t) c_int; +pub extern "c" fn setegid(egid: gid_t) c_int; +pub extern "c" fn setreuid(ruid: uid_t, euid: uid_t) c_int; +pub extern "c" fn setregid(rgid: gid_t, egid: gid_t) c_int; +pub extern "c" fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) c_int; +pub extern "c" fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) c_int; pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?*c_void; pub extern "c" fn malloc(usize) ?*c_void; @@ -335,3 +340,5 @@ pub extern "c" fn sync() void; pub extern "c" fn syncfs(fd: c_int) c_int; pub extern "c" fn fsync(fd: c_int) c_int; pub extern "c" fn fdatasync(fd: c_int) c_int; + +pub extern "c" fn prctl(option: c_int, ...) c_int; diff --git a/lib/std/compress.zig b/lib/std/compress.zig index 5518f807df..95f496021e 100644 --- a/lib/std/compress.zig +++ b/lib/std/compress.zig @@ -6,8 +6,10 @@ const std = @import("std.zig"); pub const deflate = @import("compress/deflate.zig"); +pub const gzip = @import("compress/gzip.zig"); pub const zlib = @import("compress/zlib.zig"); test "" { + _ = gzip; _ = zlib; } diff --git a/lib/std/compress/deflate.zig b/lib/std/compress/deflate.zig index bad23349e8..9fe96cacb7 100644 --- a/lib/std/compress/deflate.zig +++ b/lib/std/compress/deflate.zig @@ -21,48 +21,121 @@ const MAXDCODES = 30; const MAXCODES = MAXLCODES + MAXDCODES; const FIXLCODES = 288; +// The maximum length of a Huffman code's prefix we can decode using the fast +// path. The factor 9 is inherited from Zlib, tweaking the value showed little +// or no changes in the profiler output. +const PREFIX_LUT_BITS = 9; + const Huffman = struct { + // Number of codes for each possible length count: [MAXBITS + 1]u16, + // Mapping between codes and symbols symbol: [MAXCODES]u16, - fn construct(self: *Huffman, length: []const u16) !void { + // The decoding process uses a trick explained by Mark Adler in [1]. + // We basically precompute for a fixed number of codes (0 <= x <= 2^N-1) + // the symbol and the effective code length we'd get if the decoder was run + // on the given N-bit sequence. + // A code with length 0 means the sequence is not a valid prefix for this + // canonical Huffman code and we have to decode it using a slower method. + // + // [1] https://github.com/madler/zlib/blob/v1.2.11/doc/algorithm.txt#L58 + prefix_lut: [1 << PREFIX_LUT_BITS]u16, + prefix_lut_len: [1 << PREFIX_LUT_BITS]u16, + // The following info refer to the codes of length PREFIX_LUT_BITS+1 and are + // used to bootstrap the bit-by-bit reading method if the fast-path fails. + last_code: u16, + last_index: u16, + + fn construct(self: *Huffman, code_length: []const u16) !void { for (self.count) |*val| { val.* = 0; } - for (length) |val| { - self.count[val] += 1; + for (code_length) |len| { + self.count[len] += 1; } - if (self.count[0] == length.len) + // All zero. + if (self.count[0] == code_length.len) return; var left: isize = 1; for (self.count[1..]) |val| { + // Each added bit doubles the amount of codes. left *= 2; + // Make sure the number of codes with this length isn't too high. left -= @as(isize, @bitCast(i16, val)); if (left < 0) return error.InvalidTree; } - var offs: [MAXBITS + 1]u16 = undefined; + // Compute the offset of the first symbol represented by a code of a + // given length in the symbol table, together with the first canonical + // Huffman code for that length. + var offset: [MAXBITS + 1]u16 = undefined; + var codes: [MAXBITS + 1]u16 = undefined; { + offset[1] = 0; + codes[1] = 0; var len: usize = 1; - offs[1] = 0; while (len < MAXBITS) : (len += 1) { - offs[len + 1] = offs[len] + self.count[len]; + offset[len + 1] = offset[len] + self.count[len]; + codes[len + 1] = (codes[len] + self.count[len]) << 1; } } - for (length) |val, symbol| { - if (val != 0) { - self.symbol[offs[val]] = @truncate(u16, symbol); - offs[val] += 1; + self.prefix_lut_len = mem.zeroes(@TypeOf(self.prefix_lut_len)); + + for (code_length) |len, symbol| { + if (len != 0) { + // Fill the symbol table. + // The symbols are assigned sequentially for each length. + self.symbol[offset[len]] = @truncate(u16, symbol); + // Track the last assigned offset + offset[len] += 1; + } + + if (len == 0 or len > PREFIX_LUT_BITS) + continue; + + // Given a Huffman code of length N we have to massage it so + // that it becomes an index in the lookup table. + // The bit order is reversed as the fast path reads the bit + // sequence MSB to LSB using an &, the order is flipped wrt the + // one obtained by reading bit-by-bit. + // The codes are prefix-free, if the prefix matches we can + // safely ignore the trail bits. We do so by replicating the + // symbol info for each combination of the trailing bits. + const bits_to_fill = @intCast(u5, PREFIX_LUT_BITS - len); + const rev_code = bitReverse(codes[len], len); + // Track the last used code, but only for lengths < PREFIX_LUT_BITS + codes[len] += 1; + + var j: usize = 0; + while (j < @as(usize, 1) << bits_to_fill) : (j += 1) { + const index = rev_code | (j << @intCast(u5, len)); + assert(self.prefix_lut_len[index] == 0); + self.prefix_lut[index] = @truncate(u16, symbol); + self.prefix_lut_len[index] = @truncate(u16, len); } } + + self.last_code = codes[PREFIX_LUT_BITS + 1]; + self.last_index = offset[PREFIX_LUT_BITS + 1] - self.count[PREFIX_LUT_BITS + 1]; } }; +// Reverse bit-by-bit a N-bit value +fn bitReverse(x: usize, N: usize) usize { + var tmp: usize = 0; + var i: usize = 0; + while (i < N) : (i += 1) { + tmp |= ((x >> @intCast(u5, i)) & 1) << @intCast(u5, N - i - 1); + } + return tmp; +} + pub fn InflateStream(comptime ReaderType: type) type { return struct { const Self = @This(); @@ -83,7 +156,7 @@ pub fn InflateStream(comptime ReaderType: type) type { }; pub const Reader = io.Reader(*Self, Error, read); - bit_reader: io.BitReader(.Little, ReaderType), + inner_reader: ReaderType, // True if the decoder met the end of the compressed stream, no further // data can be decompressed @@ -135,7 +208,7 @@ pub fn InflateStream(comptime ReaderType: type) type { // Insert a single byte into the window. // Assumes there's enough space. - fn appendUnsafe(self: *WSelf, value: u8) void { + inline fn appendUnsafe(self: *WSelf, value: u8) void { self.buf[self.wi] = value; self.wi = (self.wi + 1) & (self.buf.len - 1); self.el += 1; @@ -180,7 +253,7 @@ pub fn InflateStream(comptime ReaderType: type) type { // of the window memory for the non-overlapping case. var i: usize = 0; while (i < N) : (i += 1) { - const index = (self.wi -% distance) % self.buf.len; + const index = (self.wi -% distance) & (self.buf.len - 1); self.appendUnsafe(self.buf[index]); } @@ -196,13 +269,36 @@ pub fn InflateStream(comptime ReaderType: type) type { hdist: *Huffman, hlen: *Huffman, + // Temporary buffer for the bitstream, only bits 0..`bits_left` are + // considered valid. + bits: u32, + bits_left: usize, + + fn peekBits(self: *Self, bits: usize) !u32 { + while (self.bits_left < bits) { + const byte = try self.inner_reader.readByte(); + self.bits |= @as(u32, byte) << @intCast(u5, self.bits_left); + self.bits_left += 8; + } + return self.bits & ((@as(u32, 1) << @intCast(u5, bits)) - 1); + } + fn readBits(self: *Self, bits: usize) !u32 { + const val = self.peekBits(bits); + self.discardBits(bits); + return val; + } + fn discardBits(self: *Self, bits: usize) void { + self.bits >>= @intCast(u5, bits); + self.bits_left -= bits; + } + fn stored(self: *Self) !void { // Discard the remaining bits, the lenght field is always // byte-aligned (and so is the data) - self.bit_reader.alignToByte(); + self.discardBits(self.bits_left); - const length = (try self.bit_reader.readBitsNoEof(u16, 16)); - const length_cpl = (try self.bit_reader.readBitsNoEof(u16, 16)); + const length = try self.inner_reader.readIntLittle(u16); + const length_cpl = try self.inner_reader.readIntLittle(u16); if (length != ~length_cpl) return error.InvalidStoredSize; @@ -237,11 +333,11 @@ pub fn InflateStream(comptime ReaderType: type) type { fn dynamic(self: *Self) !void { // Number of length codes - const nlen = (try self.bit_reader.readBitsNoEof(usize, 5)) + 257; + const nlen = (try self.readBits(5)) + 257; // Number of distance codes - const ndist = (try self.bit_reader.readBitsNoEof(usize, 5)) + 1; + const ndist = (try self.readBits(5)) + 1; // Number of code length codes - const ncode = (try self.bit_reader.readBitsNoEof(usize, 4)) + 4; + const ncode = (try self.readBits(4)) + 4; if (nlen > MAXLCODES or ndist > MAXDCODES) return error.BadCounts; @@ -259,7 +355,7 @@ pub fn InflateStream(comptime ReaderType: type) type { // Read the code lengths, missing ones are left as zero for (ORDER[0..ncode]) |val| { - lengths[val] = try self.bit_reader.readBitsNoEof(u16, 3); + lengths[val] = @intCast(u16, try self.readBits(3)); } try lencode.construct(lengths[0..]); @@ -284,7 +380,7 @@ pub fn InflateStream(comptime ReaderType: type) type { if (i == 0) return error.NoLastLength; const last_length = lengths[i - 1]; - const repeat = 3 + (try self.bit_reader.readBitsNoEof(usize, 2)); + const repeat = 3 + (try self.readBits(2)); const last_index = i + repeat; while (i < last_index) : (i += 1) { lengths[i] = last_length; @@ -292,11 +388,11 @@ pub fn InflateStream(comptime ReaderType: type) type { }, 17 => { // repeat zero 3..10 times - i += 3 + (try self.bit_reader.readBitsNoEof(usize, 3)); + i += 3 + (try self.readBits(3)); }, 18 => { // repeat zero 11..138 times - i += 11 + (try self.bit_reader.readBitsNoEof(usize, 7)); + i += 11 + (try self.readBits(7)); }, else => return error.InvalidSymbol, } @@ -359,11 +455,11 @@ pub fn InflateStream(comptime ReaderType: type) type { // Length/distance pair const length_symbol = symbol - 257; const length = LENS[length_symbol] + - try self.bit_reader.readBitsNoEof(u16, LEXT[length_symbol]); + @intCast(u16, try self.readBits(LEXT[length_symbol])); const distance_symbol = try self.decode(distcode); const distance = DISTS[distance_symbol] + - try self.bit_reader.readBitsNoEof(u16, DEXT[distance_symbol]); + @intCast(u16, try self.readBits(DEXT[distance_symbol])); if (distance > self.window.buf.len) return error.InvalidDistance; @@ -385,13 +481,29 @@ pub fn InflateStream(comptime ReaderType: type) type { } fn decode(self: *Self, h: *Huffman) !u16 { - var len: usize = 1; - var code: usize = 0; - var first: usize = 0; - var index: usize = 0; + // Fast path, read some bits and hope they're prefixes of some code + const prefix = try self.peekBits(PREFIX_LUT_BITS); + if (h.prefix_lut_len[prefix] != 0) { + self.discardBits(h.prefix_lut_len[prefix]); + return h.prefix_lut[prefix]; + } + + // The sequence we've read is not a prefix of any code of length <= + // PREFIX_LUT_BITS, keep decoding it using a slower method + self.discardBits(PREFIX_LUT_BITS); + + // Speed up the decoding by starting from the first code length + // that's not covered by the table + var len: usize = PREFIX_LUT_BITS + 1; + var first: usize = h.last_code; + var index: usize = h.last_index; + + // Reverse the prefix so that the LSB becomes the MSB and make space + // for the next bit + var code = bitReverse(prefix, PREFIX_LUT_BITS + 1); while (len <= MAXBITS) : (len += 1) { - code |= try self.bit_reader.readBitsNoEof(usize, 1); + code |= try self.readBits(1); const count = h.count[len]; if (code < first + count) return h.symbol[index + (code - first)]; @@ -411,8 +523,8 @@ pub fn InflateStream(comptime ReaderType: type) type { // The compressed stream is done if (self.seen_eos) return; - const last = try self.bit_reader.readBitsNoEof(u1, 1); - const kind = try self.bit_reader.readBitsNoEof(u2, 2); + const last = @intCast(u1, try self.readBits(1)); + const kind = @intCast(u2, try self.readBits(2)); self.seen_eos = last != 0; @@ -439,7 +551,7 @@ pub fn InflateStream(comptime ReaderType: type) type { var i: usize = 0; while (i < N) : (i += 1) { var tmp: [1]u8 = undefined; - if ((try self.bit_reader.read(&tmp)) != 1) { + if ((try self.inner_reader.read(&tmp)) != 1) { // Unexpected end of stream, keep this error // consistent with the use of readBitsNoEof return error.EndOfStream; @@ -478,12 +590,14 @@ pub fn InflateStream(comptime ReaderType: type) type { assert(math.isPowerOfTwo(window_slice.len)); return Self{ - .bit_reader = io.bitReader(.Little, source), + .inner_reader = source, .window = .{ .buf = window_slice }, .seen_eos = false, .state = .DecodeBlockHeader, .hdist = undefined, .hlen = undefined, + .bits = 0, + .bits_left = 0, }; } diff --git a/lib/std/compress/gzip.zig b/lib/std/compress/gzip.zig new file mode 100644 index 0000000000..aad1731393 --- /dev/null +++ b/lib/std/compress/gzip.zig @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +// +// Decompressor for GZIP data streams (RFC1952) + +const std = @import("std"); +const io = std.io; +const fs = std.fs; +const testing = std.testing; +const mem = std.mem; +const deflate = std.compress.deflate; + +// Flags for the FLG field in the header +const FTEXT = 1 << 0; +const FHCRC = 1 << 1; +const FEXTRA = 1 << 2; +const FNAME = 1 << 3; +const FCOMMENT = 1 << 4; + +pub fn GzipStream(comptime ReaderType: type) type { + return struct { + const Self = @This(); + + pub const Error = ReaderType.Error || + deflate.InflateStream(ReaderType).Error || + error{ CorruptedData, WrongChecksum }; + pub const Reader = io.Reader(*Self, Error, read); + + allocator: *mem.Allocator, + inflater: deflate.InflateStream(ReaderType), + in_reader: ReaderType, + hasher: std.hash.Crc32, + window_slice: []u8, + read_amt: usize, + + info: struct { + filename: ?[]const u8, + comment: ?[]const u8, + modification_time: u32, + }, + + fn init(allocator: *mem.Allocator, source: ReaderType) !Self { + // gzip header format is specified in RFC1952 + const header = try source.readBytesNoEof(10); + + // Check the ID1/ID2 fields + if (header[0] != 0x1f or header[1] != 0x8b) + return error.BadHeader; + + const CM = header[2]; + // The CM field must be 8 to indicate the use of DEFLATE + if (CM != 8) return error.InvalidCompression; + // Flags + const FLG = header[3]; + // Modification time, as a Unix timestamp. + // If zero there's no timestamp available. + const MTIME = mem.readIntLittle(u32, header[4..8]); + // Extra flags + const XFL = header[8]; + // Operating system where the compression took place + const OS = header[9]; + + if (FLG & FEXTRA != 0) { + // Skip the extra data, we could read and expose it to the user + // if somebody needs it. + const len = try source.readIntLittle(u16); + try source.skipBytes(len, .{}); + } + + var filename: ?[]const u8 = null; + if (FLG & FNAME != 0) { + filename = try source.readUntilDelimiterAlloc( + allocator, + 0, + std.math.maxInt(usize), + ); + } + errdefer if (filename) |p| allocator.free(p); + + var comment: ?[]const u8 = null; + if (FLG & FCOMMENT != 0) { + comment = try source.readUntilDelimiterAlloc( + allocator, + 0, + std.math.maxInt(usize), + ); + } + errdefer if (comment) |p| allocator.free(p); + + if (FLG & FHCRC != 0) { + // TODO: Evaluate and check the header checksum. The stdlib has + // no CRC16 yet :( + _ = try source.readIntLittle(u16); + } + + // The RFC doesn't say anything about the DEFLATE window size to be + // used, default to 32K. + var window_slice = try allocator.alloc(u8, 32 * 1024); + + return Self{ + .allocator = allocator, + .inflater = deflate.inflateStream(source, window_slice), + .in_reader = source, + .hasher = std.hash.Crc32.init(), + .window_slice = window_slice, + .info = .{ + .filename = filename, + .comment = comment, + .modification_time = MTIME, + }, + .read_amt = 0, + }; + } + + pub fn deinit(self: *Self) void { + self.allocator.free(self.window_slice); + if (self.info.filename) |filename| + self.allocator.free(filename); + if (self.info.comment) |comment| + self.allocator.free(comment); + } + + // Implements the io.Reader interface + pub fn read(self: *Self, buffer: []u8) Error!usize { + if (buffer.len == 0) + return 0; + + // Read from the compressed stream and update the computed checksum + const r = try self.inflater.read(buffer); + if (r != 0) { + self.hasher.update(buffer[0..r]); + self.read_amt += r; + return r; + } + + // We've reached the end of stream, check if the checksum matches + const hash = try self.in_reader.readIntLittle(u32); + if (hash != self.hasher.final()) + return error.WrongChecksum; + + // The ISIZE field is the size of the uncompressed input modulo 2^32 + const input_size = try self.in_reader.readIntLittle(u32); + if (self.read_amt & 0xffffffff != input_size) + return error.CorruptedData; + + return 0; + } + + pub fn reader(self: *Self) Reader { + return .{ .context = self }; + } + }; +} + +pub fn gzipStream(allocator: *mem.Allocator, reader: anytype) !GzipStream(@TypeOf(reader)) { + return GzipStream(@TypeOf(reader)).init(allocator, reader); +} + +fn testReader(data: []const u8, comptime expected: []const u8) !void { + var in_stream = io.fixedBufferStream(data); + + var gzip_stream = try gzipStream(testing.allocator, in_stream.reader()); + defer gzip_stream.deinit(); + + // Read and decompress the whole file + const buf = try gzip_stream.reader().readAllAlloc(testing.allocator, std.math.maxInt(usize)); + defer testing.allocator.free(buf); + // Calculate its SHA256 hash and check it against the reference + var hash: [32]u8 = undefined; + std.crypto.hash.sha2.Sha256.hash(buf, hash[0..], .{}); + + assertEqual(expected, &hash); +} + +// Assert `expected` == `input` where `input` is a bytestring. +pub fn assertEqual(comptime expected: []const u8, input: []const u8) void { + var expected_bytes: [expected.len / 2]u8 = undefined; + for (expected_bytes) |*r, i| { + r.* = std.fmt.parseInt(u8, expected[2 * i .. 2 * i + 2], 16) catch unreachable; + } + + testing.expectEqualSlices(u8, &expected_bytes, input); +} + +// All the test cases are obtained by compressing the RFC1952 text +// +// https://tools.ietf.org/rfc/rfc1952.txt length=25037 bytes +// SHA256=164ef0897b4cbec63abf1b57f069f3599bd0fb7c72c2a4dee21bd7e03ec9af67 +test "compressed data" { + try testReader( + @embedFile("rfc1952.txt.gz"), + "164ef0897b4cbec63abf1b57f069f3599bd0fb7c72c2a4dee21bd7e03ec9af67", + ); +} + +test "sanity checks" { + // Truncated header + testing.expectError( + error.EndOfStream, + testReader(&[_]u8{ 0x1f, 0x8B }, ""), + ); + // Wrong CM + testing.expectError( + error.InvalidCompression, + testReader(&[_]u8{ + 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, + }, ""), + ); + // Wrong checksum + testing.expectError( + error.WrongChecksum, + testReader(&[_]u8{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + }, ""), + ); + // Truncated checksum + testing.expectError( + error.EndOfStream, + testReader(&[_]u8{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + }, ""), + ); + // Wrong initial size + testing.expectError( + error.CorruptedData, + testReader(&[_]u8{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + }, ""), + ); + // Truncated initial size field + testing.expectError( + error.EndOfStream, + testReader(&[_]u8{ + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + }, ""), + ); +} diff --git a/lib/std/compress/rfc1952.txt.gz b/lib/std/compress/rfc1952.txt.gz Binary files differnew file mode 100644 index 0000000000..be43b90a79 --- /dev/null +++ b/lib/std/compress/rfc1952.txt.gz diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index b34ad8c940..2600b337b3 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -112,7 +112,8 @@ pub const Loop = struct { /// have the correct pointer value. /// https://github.com/ziglang/zig/issues/2761 and https://github.com/ziglang/zig/issues/2765 pub fn init(self: *Loop) !void { - if (builtin.single_threaded) { + if (builtin.single_threaded + or (@hasDecl(root, "event_loop_mode") and root.event_loop_mode == .single_threaded)) { return self.initSingleThreaded(); } else { return self.initMultiThreaded(); diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index ef1b501ec3..73babf5fa2 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -728,7 +728,7 @@ pub const File = struct { } var i: usize = 0; while (i < trailers.len) { - while (amt >= headers[i].iov_len) { + while (amt >= trailers[i].iov_len) { amt -= trailers[i].iov_len; i += 1; if (i >= trailers.len) return; @@ -740,14 +740,16 @@ pub const File = struct { } pub const Reader = io.Reader(File, ReadError, read); + /// Deprecated: use `Reader` pub const InStream = Reader; - pub fn reader(file: File) io.Reader(File, ReadError, read) { + pub fn reader(file: File) Reader { return .{ .context = file }; } + /// Deprecated: use `reader` - pub fn inStream(file: File) io.InStream(File, ReadError, read) { + pub fn inStream(file: File) Reader { return .{ .context = file }; } diff --git a/lib/std/os.zig b/lib/std/os.zig index 181bf4930d..91365c81dd 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2515,9 +2515,9 @@ pub fn readlinkatZ(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) Read pub const SetEidError = error{ InvalidUserId, PermissionDenied, -}; +} || UnexpectedError; -pub const SetIdError = error{ResourceLimitReached} || SetEidError || UnexpectedError; +pub const SetIdError = error{ResourceLimitReached} || SetEidError; pub fn setuid(uid: uid_t) SetIdError!void { switch (errno(system.setuid(uid))) { @@ -5418,3 +5418,42 @@ pub fn fdatasync(fd: fd_t) SyncError!void { else => |err| return std.os.unexpectedErrno(err), } } + +pub const PrctlError = error{ + /// Can only occur with PR_SET_SECCOMP/SECCOMP_MODE_FILTER or + /// PR_SET_MM/PR_SET_MM_EXE_FILE + AccessDenied, + /// Can only occur with PR_SET_MM/PR_SET_MM_EXE_FILE + InvalidFileDescriptor, + InvalidAddress, + /// Can only occur with PR_SET_SPECULATION_CTRL, PR_MPX_ENABLE_MANAGEMENT, + /// or PR_MPX_DISABLE_MANAGEMENT + UnsupportedFeature, + /// Can only occur wih PR_SET_FP_MODE + OperationNotSupported, + PermissionDenied, +} || UnexpectedError; + +pub fn prctl(option: i32, args: anytype) PrctlError!u31 { + if (@typeInfo(@TypeOf(args)) != .Struct) + @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args))); + if (args.len > 4) + @compileError("prctl takes a maximum of 4 optional arguments"); + + var buf: [4]usize = undefined; + inline for (args) |arg, i| buf[i] = arg; + + const rc = system.prctl(option, buf[0], buf[1], buf[2], buf[3]); + switch (errno(rc)) { + 0 => return @intCast(u31, rc), + EACCES => return error.AccessDenied, + EBADF => return error.InvalidFileDescriptor, + EFAULT => return error.InvalidAddress, + EINVAL => unreachable, + ENODEV, ENXIO => return error.UnsupportedFeature, + EOPNOTSUPP => return error.OperationNotSupported, + EPERM, EBUSY => return error.PermissionDenied, + ERANGE => unreachable, + else => |err| return std.os.unexpectedErrno(err), + } +} diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index cec8833dfe..df31bc32fd 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -20,10 +20,13 @@ pub usingnamespace switch (builtin.arch) { .arm => @import("linux/arm-eabi.zig"), .riscv64 => @import("linux/riscv64.zig"), .mips, .mipsel => @import("linux/mips.zig"), + .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"), else => struct {}, }; pub usingnamespace @import("linux/netlink.zig"); +pub usingnamespace @import("linux/prctl.zig"); +pub usingnamespace @import("linux/securebits.zig"); const is_mips = builtin.arch.isMIPS(); diff --git a/lib/std/os/bits/linux/powerpc64.zig b/lib/std/os/bits/linux/powerpc64.zig new file mode 100644 index 0000000000..adc6c87c1a --- /dev/null +++ b/lib/std/os/bits/linux/powerpc64.zig @@ -0,0 +1,602 @@ +const std = @import("../../../std.zig"); +const linux = std.os.linux; +const socklen_t = linux.socklen_t; +const iovec = linux.iovec; +const iovec_const = linux.iovec_const; +const uid_t = linux.uid_t; +const gid_t = linux.gid_t; +const pid_t = linux.pid_t; +const stack_t = linux.stack_t; +const sigset_t = linux.sigset_t; +pub const SYS = extern enum(usize) { + restart_syscall = 0, + exit = 1, + fork = 2, + read = 3, + write = 4, + open = 5, + close = 6, + waitpid = 7, + creat = 8, + link = 9, + unlink = 10, + execve = 11, + chdir = 12, + time = 13, + mknod = 14, + chmod = 15, + lchown = 16, + @"break" = 17, + oldstat = 18, + lseek = 19, + getpid = 20, + mount = 21, + umount = 22, + setuid = 23, + getuid = 24, + stime = 25, + ptrace = 26, + alarm = 27, + oldfstat = 28, + pause = 29, + utime = 30, + stty = 31, + gtty = 32, + access = 33, + nice = 34, + ftime = 35, + sync = 36, + kill = 37, + rename = 38, + mkdir = 39, + rmdir = 40, + dup = 41, + pipe = 42, + times = 43, + prof = 44, + brk = 45, + setgid = 46, + getgid = 47, + signal = 48, + geteuid = 49, + getegid = 50, + acct = 51, + umount2 = 52, + lock = 53, + ioctl = 54, + fcntl = 55, + mpx = 56, + setpgid = 57, + ulimit = 58, + oldolduname = 59, + umask = 60, + chroot = 61, + ustat = 62, + dup2 = 63, + getppid = 64, + getpgrp = 65, + setsid = 66, + sigaction = 67, + sgetmask = 68, + ssetmask = 69, + setreuid = 70, + setregid = 71, + sigsuspend = 72, + sigpending = 73, + sethostname = 74, + setrlimit = 75, + getrlimit = 76, + getrusage = 77, + gettimeofday = 78, + settimeofday = 79, + getgroups = 80, + setgroups = 81, + select = 82, + symlink = 83, + oldlstat = 84, + readlink = 85, + uselib = 86, + swapon = 87, + reboot = 88, + readdir = 89, + mmap = 90, + munmap = 91, + truncate = 92, + ftruncate = 93, + fchmod = 94, + fchown = 95, + getpriority = 96, + setpriority = 97, + profil = 98, + statfs = 99, + fstatfs = 100, + ioperm = 101, + socketcall = 102, + syslog = 103, + setitimer = 104, + getitimer = 105, + stat = 106, + lstat = 107, + fstat = 108, + olduname = 109, + iopl = 110, + vhangup = 111, + idle = 112, + vm86 = 113, + wait4 = 114, + swapoff = 115, + sysinfo = 116, + ipc = 117, + fsync = 118, + sigreturn = 119, + clone = 120, + setdomainname = 121, + uname = 122, + modify_ldt = 123, + adjtimex = 124, + mprotect = 125, + sigprocmask = 126, + create_module = 127, + init_module = 128, + delete_module = 129, + get_kernel_syms = 130, + quotactl = 131, + getpgid = 132, + fchdir = 133, + bdflush = 134, + sysfs = 135, + personality = 136, + afs_syscall = 137, + setfsuid = 138, + setfsgid = 139, + _llseek = 140, + getdents = 141, + _newselect = 142, + flock = 143, + msync = 144, + readv = 145, + writev = 146, + getsid = 147, + fdatasync = 148, + _sysctl = 149, + mlock = 150, + munlock = 151, + mlockall = 152, + munlockall = 153, + sched_setparam = 154, + sched_getparam = 155, + sched_setscheduler = 156, + sched_getscheduler = 157, + sched_yield = 158, + sched_get_priority_max = 159, + sched_get_priority_min = 160, + sched_rr_get_interval = 161, + nanosleep = 162, + mremap = 163, + setresuid = 164, + getresuid = 165, + query_module = 166, + poll = 167, + nfsservctl = 168, + setresgid = 169, + getresgid = 170, + prctl = 171, + rt_sigreturn = 172, + rt_sigaction = 173, + rt_sigprocmask = 174, + rt_sigpending = 175, + rt_sigtimedwait = 176, + rt_sigqueueinfo = 177, + rt_sigsuspend = 178, + pread64 = 179, + pwrite64 = 180, + chown = 181, + getcwd = 182, + capget = 183, + capset = 184, + sigaltstack = 185, + sendfile = 186, + getpmsg = 187, + putpmsg = 188, + vfork = 189, + ugetrlimit = 190, + readahead = 191, + pciconfig_read = 198, + pciconfig_write = 199, + pciconfig_iobase = 200, + multiplexer = 201, + getdents64 = 202, + pivot_root = 203, + madvise = 205, + mincore = 206, + gettid = 207, + tkill = 208, + setxattr = 209, + lsetxattr = 210, + fsetxattr = 211, + getxattr = 212, + lgetxattr = 213, + fgetxattr = 214, + listxattr = 215, + llistxattr = 216, + flistxattr = 217, + removexattr = 218, + lremovexattr = 219, + fremovexattr = 220, + futex = 221, + sched_setaffinity = 222, + sched_getaffinity = 223, + tuxcall = 225, + io_setup = 227, + io_destroy = 228, + io_getevents = 229, + io_submit = 230, + io_cancel = 231, + set_tid_address = 232, + fadvise64 = 233, + exit_group = 234, + lookup_dcookie = 235, + epoll_create = 236, + epoll_ctl = 237, + epoll_wait = 238, + remap_file_pages = 239, + timer_create = 240, + timer_settime = 241, + timer_gettime = 242, + timer_getoverrun = 243, + timer_delete = 244, + clock_settime = 245, + clock_gettime = 246, + clock_getres = 247, + clock_nanosleep = 248, + swapcontext = 249, + tgkill = 250, + utimes = 251, + statfs64 = 252, + fstatfs64 = 253, + rtas = 255, + sys_debug_setcontext = 256, + migrate_pages = 258, + mbind = 259, + get_mempolicy = 260, + set_mempolicy = 261, + mq_open = 262, + mq_unlink = 263, + mq_timedsend = 264, + mq_timedreceive = 265, + mq_notify = 266, + mq_getsetattr = 267, + kexec_load = 268, + add_key = 269, + request_key = 270, + keyctl = 271, + waitid = 272, + ioprio_set = 273, + ioprio_get = 274, + inotify_init = 275, + inotify_add_watch = 276, + inotify_rm_watch = 277, + spu_run = 278, + spu_create = 279, + pselect6 = 280, + ppoll = 281, + unshare = 282, + splice = 283, + tee = 284, + vmsplice = 285, + openat = 286, + mkdirat = 287, + mknodat = 288, + fchownat = 289, + futimesat = 290, + newfstatat = 291, + unlinkat = 292, + renameat = 293, + linkat = 294, + symlinkat = 295, + readlinkat = 296, + fchmodat = 297, + faccessat = 298, + get_robust_list = 299, + set_robust_list = 300, + move_pages = 301, + getcpu = 302, + epoll_pwait = 303, + utimensat = 304, + signalfd = 305, + timerfd_create = 306, + eventfd = 307, + sync_file_range2 = 308, + fallocate = 309, + subpage_prot = 310, + timerfd_settime = 311, + timerfd_gettime = 312, + signalfd4 = 313, + eventfd2 = 314, + epoll_create1 = 315, + dup3 = 316, + pipe2 = 317, + inotify_init1 = 318, + perf_event_open = 319, + preadv = 320, + pwritev = 321, + rt_tgsigqueueinfo = 322, + fanotify_init = 323, + fanotify_mark = 324, + prlimit64 = 325, + socket = 326, + bind = 327, + connect = 328, + listen = 329, + accept = 330, + getsockname = 331, + getpeername = 332, + socketpair = 333, + send = 334, + sendto = 335, + recv = 336, + recvfrom = 337, + shutdown = 338, + setsockopt = 339, + getsockopt = 340, + sendmsg = 341, + recvmsg = 342, + recvmmsg = 343, + accept4 = 344, + name_to_handle_at = 345, + open_by_handle_at = 346, + clock_adjtime = 347, + syncfs = 348, + sendmmsg = 349, + setns = 350, + process_vm_readv = 351, + process_vm_writev = 352, + finit_module = 353, + kcmp = 354, + sched_setattr = 355, + sched_getattr = 356, + renameat2 = 357, + seccomp = 358, + getrandom = 359, + memfd_create = 360, + bpf = 361, + execveat = 362, + switch_endian = 363, + userfaultfd = 364, + membarrier = 365, + mlock2 = 378, + copy_file_range = 379, + preadv2 = 380, + pwritev2 = 381, + kexec_file_load = 382, + statx = 383, + pkey_alloc = 384, + pkey_free = 385, + pkey_mprotect = 386, + rseq = 387, + io_pgetevents = 388, + semtimedop = 392, + semget = 393, + semctl = 394, + shmget = 395, + shmctl = 396, + shmat = 397, + shmdt = 398, + msgget = 399, + msgsnd = 400, + msgrcv = 401, + msgctl = 402, + pidfd_send_signal = 424, + io_uring_setup = 425, + io_uring_enter = 426, + io_uring_register = 427, + open_tree = 428, + move_mount = 429, + fsopen = 430, + fsconfig = 431, + fsmount = 432, + fspick = 433, + pidfd_open = 434, + clone3 = 435, + openat2 = 437, + pidfd_getfd = 438, + + _, +}; + +pub const O_CREAT = 0o100; +pub const O_EXCL = 0o200; +pub const O_NOCTTY = 0o400; +pub const O_TRUNC = 0o1000; +pub const O_APPEND = 0o2000; +pub const O_NONBLOCK = 0o4000; +pub const O_DSYNC = 0o10000; +pub const O_SYNC = 0o4010000; +pub const O_RSYNC = 0o4010000; +pub const O_DIRECTORY = 0o40000; +pub const O_NOFOLLOW = 0o100000; +pub const O_CLOEXEC = 0o2000000; + +pub const O_ASYNC = 0o20000; +pub const O_DIRECT = 0o400000; +pub const O_LARGEFILE = 0o200000; +pub const O_NOATIME = 0o1000000; +pub const O_PATH = 0o10000000; +pub const O_TMPFILE = 0o20200000; +pub const O_NDELAY = O_NONBLOCK; + +pub const F_DUPFD = 0; +pub const F_GETFD = 1; +pub const F_SETFD = 2; +pub const F_GETFL = 3; +pub const F_SETFL = 4; + +pub const F_SETOWN = 8; +pub const F_GETOWN = 9; +pub const F_SETSIG = 10; +pub const F_GETSIG = 11; + +pub const F_GETLK = 5; +pub const F_SETLK = 6; +pub const F_SETLKW = 7; + +pub const F_RDLCK = 0; +pub const F_WRLCK = 1; +pub const F_UNLCK = 2; + +pub const LOCK_SH = 1; +pub const LOCK_EX = 2; +pub const LOCK_UN = 8; +pub const LOCK_NB = 4; + +pub const F_SETOWN_EX = 15; +pub const F_GETOWN_EX = 16; + +pub const F_GETOWNER_UIDS = 17; + +/// stack-like segment +pub const MAP_GROWSDOWN = 0x0100; + +/// ETXTBSY +pub const MAP_DENYWRITE = 0x0800; + +/// mark it as an executable +pub const MAP_EXECUTABLE = 0x1000; + +/// pages are locked +pub const MAP_LOCKED = 0x0080; + +/// don't check for reservations +pub const MAP_NORESERVE = 0x0040; + +pub const VDSO_CGT_SYM = "__kernel_clock_gettime"; +pub const VDSO_CGT_VER = "LINUX_2.6.15"; + +pub const Flock = extern struct { + l_type: i16, + l_whence: i16, + l_start: off_t, + l_len: off_t, + l_pid: pid_t, + __unused: [4]u8, +}; + +pub const msghdr = extern struct { + msg_name: ?*sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec, + msg_iovlen: usize, + msg_control: ?*c_void, + msg_controllen: usize, + msg_flags: i32, +}; + +pub const msghdr_const = extern struct { + msg_name: ?*const sockaddr, + msg_namelen: socklen_t, + msg_iov: [*]iovec_const, + msg_iovlen: usize, + msg_control: ?*c_void, + msg_controllen: usize, + msg_flags: i32, +}; + +pub const blksize_t = i64; +pub const nlink_t = u64; +pub const time_t = i64; +pub const mode_t = u32; +pub const off_t = i64; +pub const ino_t = u64; +pub const dev_t = u64; +pub const blkcnt_t = i64; + +/// Renamed to Stat to not conflict with the stat function. +/// atime, mtime, and ctime have functions to return `timespec`, +/// because although this is a POSIX API, the layout and names of +/// the structs are inconsistent across operating systems, and +/// in C, macros are used to hide the differences. Here we use +/// methods to accomplish this. +pub const Stat = extern struct { + dev: dev_t, + ino: ino_t, + nlink: nlink_t, + mode: mode_t, + uid: uid_t, + gid: gid_t, + rdev: dev_t, + size: off_t, + blksize: blksize_t, + blocks: blkcnt_t, + atim: timespec, + mtim: timespec, + ctim: timespec, + __unused: [3]u64, + + pub fn atime(self: Stat) timespec { + return self.atim; + } + + pub fn mtime(self: Stat) timespec { + return self.mtim; + } + + pub fn ctime(self: Stat) timespec { + return self.ctim; + } +}; + +pub const timespec = extern struct { + tv_sec: time_t, + tv_nsec: isize, +}; + +pub const timeval = extern struct { + tv_sec: isize, + tv_usec: isize, +}; + +pub const timezone = extern struct { + tz_minuteswest: i32, + tz_dsttime: i32, +}; + +pub const greg_t = u64; +pub const gregset_t = [48]greg_t; +pub const fpregset_t = [33]f64; + +/// The position of the vscr register depends on endianness. +/// On C, macros are used to change vscr_word's offset to +/// account for this. Here we'll just define vscr_word_le +/// and vscr_word_be. Code must take care to use the correct one. +pub const vrregset = extern struct { + vrregs: [32][4]u32 align(16), + vscr_word_le: u32, + _pad1: [2]u32, + vscr_word_be: u32, + vrsave: u32, + _pad2: [3]u32, +}; +pub const vrregset_t = vrregset; + +pub const mcontext_t = extern struct { + __unused: [4]u64, + signal: i32, + _pad0: i32, + handler: u64, + oldmask: u64, + regs: ?*c_void, + gp_regs: gregset_t, + fp_regs: fpregset_t, + v_regs: *vrregset_t, + vmx_reserve: [34 + 34 + 32 + 1]i64, +}; + +pub const ucontext_t = extern struct { + flags: u32, + link: *ucontext_t, + stack: stack_t, + sigmask: sigset_t, + mcontext: mcontext_t, +}; + +pub const Elf_Symndx = u32; diff --git a/lib/std/os/bits/linux/prctl.zig b/lib/std/os/bits/linux/prctl.zig new file mode 100644 index 0000000000..7fa9969af4 --- /dev/null +++ b/lib/std/os/bits/linux/prctl.zig @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +pub const PR_SET_PDEATHSIG = 1; +pub const PR_GET_PDEATHSIG = 2; + +pub const PR_GET_DUMPABLE = 3; +pub const PR_SET_DUMPABLE = 4; + +pub const PR_GET_UNALIGN = 5; +pub const PR_SET_UNALIGN = 6; +pub const PR_UNALIGN_NOPRINT = 1; +pub const PR_UNALIGN_SIGBUS = 2; + +pub const PR_GET_KEEPCAPS = 7; +pub const PR_SET_KEEPCAPS = 8; + +pub const PR_GET_FPEMU = 9; +pub const PR_SET_FPEMU = 10; +pub const PR_FPEMU_NOPRINT = 1; +pub const PR_FPEMU_SIGFPE = 2; + +pub const PR_GET_FPEXC = 11; +pub const PR_SET_FPEXC = 12; +pub const PR_FP_EXC_SW_ENABLE = 0x80; +pub const PR_FP_EXC_DIV = 0x010000; +pub const PR_FP_EXC_OVF = 0x020000; +pub const PR_FP_EXC_UND = 0x040000; +pub const PR_FP_EXC_RES = 0x080000; +pub const PR_FP_EXC_INV = 0x100000; +pub const PR_FP_EXC_DISABLED = 0; +pub const PR_FP_EXC_NONRECOV = 1; +pub const PR_FP_EXC_ASYNC = 2; +pub const PR_FP_EXC_PRECISE = 3; + +pub const PR_GET_TIMING = 13; +pub const PR_SET_TIMING = 14; +pub const PR_TIMING_STATISTICAL = 0; +pub const PR_TIMING_TIMESTAMP = 1; + +pub const PR_SET_NAME = 15; +pub const PR_GET_NAME = 16; + +pub const PR_GET_ENDIAN = 19; +pub const PR_SET_ENDIAN = 20; +pub const PR_ENDIAN_BIG = 0; +pub const PR_ENDIAN_LITTLE = 1; +pub const PR_ENDIAN_PPC_LITTLE = 2; + +pub const PR_GET_SECCOMP = 21; +pub const PR_SET_SECCOMP = 22; + +pub const PR_CAPBSET_READ = 23; +pub const PR_CAPBSET_DROP = 24; + +pub const PR_GET_TSC = 25; +pub const PR_SET_TSC = 26; +pub const PR_TSC_ENABLE = 1; +pub const PR_TSC_SIGSEGV = 2; + +pub const PR_GET_SECUREBITS = 27; +pub const PR_SET_SECUREBITS = 28; + +pub const PR_SET_TIMERSLACK = 29; +pub const PR_GET_TIMERSLACK = 30; + +pub const PR_TASK_PERF_EVENTS_DISABLE = 31; +pub const PR_TASK_PERF_EVENTS_ENABLE = 32; + +pub const PR_MCE_KILL = 33; +pub const PR_MCE_KILL_CLEAR = 0; +pub const PR_MCE_KILL_SET = 1; + +pub const PR_MCE_KILL_LATE = 0; +pub const PR_MCE_KILL_EARLY = 1; +pub const PR_MCE_KILL_DEFAULT = 2; + +pub const PR_MCE_KILL_GET = 34; + +pub const PR_SET_MM = 35; +pub const PR_SET_MM_START_CODE = 1; +pub const PR_SET_MM_END_CODE = 2; +pub const PR_SET_MM_START_DATA = 3; +pub const PR_SET_MM_END_DATA = 4; +pub const PR_SET_MM_START_STACK = 5; +pub const PR_SET_MM_START_BRK = 6; +pub const PR_SET_MM_BRK = 7; +pub const PR_SET_MM_ARG_START = 8; +pub const PR_SET_MM_ARG_END = 9; +pub const PR_SET_MM_ENV_START = 10; +pub const PR_SET_MM_ENV_END = 11; +pub const PR_SET_MM_AUXV = 12; +pub const PR_SET_MM_EXE_FILE = 13; +pub const PR_SET_MM_MAP = 14; +pub const PR_SET_MM_MAP_SIZE = 15; + +pub const prctl_mm_map = extern struct { + start_code: u64, + end_code: u64, + start_data: u64, + end_data: u64, + start_brk: u64, + brk: u64, + start_stack: u64, + arg_start: u64, + arg_end: u64, + env_start: u64, + env_end: u64, + auxv: *u64, + auxv_size: u32, + exe_fd: u32, +}; + +pub const PR_SET_PTRACER = 0x59616d61; +pub const PR_SET_PTRACER_ANY = std.math.maxInt(c_ulong); + +pub const PR_SET_CHILD_SUBREAPER = 36; +pub const PR_GET_CHILD_SUBREAPER = 37; + +pub const PR_SET_NO_NEW_PRIVS = 38; +pub const PR_GET_NO_NEW_PRIVS = 39; + +pub const PR_GET_TID_ADDRESS = 40; + +pub const PR_SET_THP_DISABLE = 41; +pub const PR_GET_THP_DISABLE = 42; + +pub const PR_MPX_ENABLE_MANAGEMENT = 43; +pub const PR_MPX_DISABLE_MANAGEMENT = 44; + +pub const PR_SET_FP_MODE = 45; +pub const PR_GET_FP_MODE = 46; +pub const PR_FP_MODE_FR = 1 << 0; +pub const PR_FP_MODE_FRE = 1 << 1; + +pub const PR_CAP_AMBIENT = 47; +pub const PR_CAP_AMBIENT_IS_SET = 1; +pub const PR_CAP_AMBIENT_RAISE = 2; +pub const PR_CAP_AMBIENT_LOWER = 3; +pub const PR_CAP_AMBIENT_CLEAR_ALL = 4; + +pub const PR_SVE_SET_VL = 50; +pub const PR_SVE_SET_VL_ONEXEC = 1 << 18; +pub const PR_SVE_GET_VL = 51; +pub const PR_SVE_VL_LEN_MASK = 0xffff; +pub const PR_SVE_VL_INHERIT = 1 << 17; + +pub const PR_GET_SPECULATION_CTRL = 52; +pub const PR_SET_SPECULATION_CTRL = 53; +pub const PR_SPEC_STORE_BYPASS = 0; +pub const PR_SPEC_NOT_AFFECTED = 0; +pub const PR_SPEC_PRCTL = 1 << 0; +pub const PR_SPEC_ENABLE = 1 << 1; +pub const PR_SPEC_DISABLE = 1 << 2; +pub const PR_SPEC_FORCE_DISABLE = 1 << 3; diff --git a/lib/std/os/bits/linux/securebits.zig b/lib/std/os/bits/linux/securebits.zig new file mode 100644 index 0000000000..0086a694d9 --- /dev/null +++ b/lib/std/os/bits/linux/securebits.zig @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2020 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. + +fn issecure_mask(comptime x: comptime_int) comptime_int { + return 1 << x; +} + +pub const SECUREBITS_DEFAULT = 0x00000000; + +pub const SECURE_NOROOT = 0; +pub const SECURE_NOROOT_LOCKED = 1; + +pub const SECBIT_NOROOT = issecure_mask(SECURE_NOROOT); +pub const SECBIT_NOROOT_LOCKED = issecure_mask(SECURE_NOROOT_LOCKED); + +pub const SECURE_NO_SETUID_FIXUP = 2; +pub const SECURE_NO_SETUID_FIXUP_LOCKED = 3; + +pub const SECBIT_NO_SETUID_FIXUP = issecure_mask(SECURE_NO_SETUID_FIXUP); +pub const SECBIT_NO_SETUID_FIXUP_LOCKED = issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED); + +pub const SECURE_KEEP_CAPS = 4; +pub const SECURE_KEEP_CAPS_LOCKED = 5; + +pub const SECBIT_KEEP_CAPS = issecure_mask(SECURE_KEEP_CAPS); +pub const SECBIT_KEEP_CAPS_LOCKED = issecure_mask(SECURE_KEEP_CAPS_LOCKED); + +pub const SECURE_NO_CAP_AMBIENT_RAISE = 6; +pub const SECURE_NO_CAP_AMBIENT_RAISE_LOCKED = 7; + +pub const SECBIT_NO_CAP_AMBIENT_RAISE = issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE); +pub const SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED = issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED); + +pub const SECURE_ALL_BITS = issecure_mask(SECURE_NOROOT) | + issecure_mask(SECURE_NO_SETUID_FIXUP) | + issecure_mask(SECURE_KEEP_CAPS) | + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE); +pub const SECURE_ALL_LOCKS = SECURE_ALL_BITS << 1; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 8f697fb967..50d1e4ae78 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -25,6 +25,7 @@ pub usingnamespace switch (builtin.arch) { .arm => @import("linux/arm-eabi.zig"), .riscv64 => @import("linux/riscv64.zig"), .mips, .mipsel => @import("linux/mips.zig"), + .powerpc64, .powerpc64le => @import("linux/powerpc64.zig"), else => struct {}, }; pub usingnamespace @import("bits.zig"); @@ -1258,6 +1259,10 @@ pub fn fdatasync(fd: fd_t) usize { return syscall1(.fdatasync, @bitCast(usize, @as(isize, fd))); } +pub fn prctl(option: i32, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return syscall5(.prctl, @bitCast(usize, @as(isize, option)), arg2, arg3, arg4, arg5); +} + test "" { if (builtin.os.tag == .linux) { _ = @import("linux/test.zig"); diff --git a/lib/std/os/linux/powerpc64.zig b/lib/std/os/linux/powerpc64.zig new file mode 100644 index 0000000000..337a6aa30a --- /dev/null +++ b/lib/std/os/linux/powerpc64.zig @@ -0,0 +1,127 @@ +usingnamespace @import("../bits.zig"); + +pub fn syscall0(number: SYS) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall1(number: SYS, arg1: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4), + [arg5] "{r7}" (arg5) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +pub fn syscall6( + number: SYS, + arg1: usize, + arg2: usize, + arg3: usize, + arg4: usize, + arg5: usize, + arg6: usize, +) usize { + return asm volatile ( + \\ sc + \\ bns+ 1f + \\ neg 3, 3 + \\ 1: + : [ret] "={r3}" (-> usize) + : [number] "{r0}" (@enumToInt(number)), + [arg1] "{r3}" (arg1), + [arg2] "{r4}" (arg2), + [arg3] "{r5}" (arg3), + [arg4] "{r6}" (arg4), + [arg5] "{r7}" (arg5), + [arg6] "{r8}" (arg6) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} + +/// This matches the libc clone function. +pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: usize, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; + +pub const restore = restore_rt; + +pub fn restore_rt() callconv(.Naked) void { + return asm volatile ("sc" + : + : [number] "{r0}" (@enumToInt(SYS.rt_sigreturn)) + : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12" + ); +} diff --git a/lib/std/os/linux/tls.zig b/lib/std/os/linux/tls.zig index b10dae14d7..0330a4e410 100644 --- a/lib/std/os/linux/tls.zig +++ b/lib/std/os/linux/tls.zig @@ -53,7 +53,7 @@ const TLSVariant = enum { }; const tls_variant = switch (builtin.arch) { - .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel => TLSVariant.VariantI, + .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, .x86_64, .i386 => TLSVariant.VariantII, else => @compileError("undefined tls_variant for this architecture"), }; @@ -77,12 +77,12 @@ const tls_tp_points_past_tcb = switch (builtin.arch) { // make the generated code more efficient const tls_tp_offset = switch (builtin.arch) { - .mips, .mipsel => 0x7000, + .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x7000, else => 0, }; const tls_dtv_offset = switch (builtin.arch) { - .mips, .mipsel => 0x8000, + .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => 0x8000, .riscv32, .riscv64 => 0x800, else => 0, }; @@ -165,6 +165,13 @@ pub fn setThreadPointer(addr: usize) void { const rc = std.os.linux.syscall1(.set_thread_area, addr); assert(rc == 0); }, + .powerpc, .powerpc64, .powerpc64le => { + asm volatile ( + \\ mr 13, %[addr] + : + : [addr] "r" (addr) + ); + }, else => @compileError("Unsupported architecture"), } } diff --git a/lib/std/priority_queue.zig b/lib/std/priority_queue.zig index 1c0d230d4d..b9be9b70bf 100644 --- a/lib/std/priority_queue.zig +++ b/lib/std/priority_queue.zig @@ -195,7 +195,7 @@ pub fn PriorityQueue(comptime T: type) type { count: usize, pub fn next(it: *Iterator) ?T { - if (it.count > it.queue.len - 1) return null; + if (it.count >= it.queue.len) return null; const out = it.count; it.count += 1; return it.queue.items[out]; @@ -428,3 +428,12 @@ test "std.PriorityQueue: remove at index" { expectEqual(queue.remove(), 3); expectEqual(queue.removeOrNull(), null); } + +test "std.PriorityQueue: iterator while empty" { + var queue = PQ.init(testing.allocator, lessThan); + defer queue.deinit(); + + var it = queue.iterator(); + + expectEqual(it.next(), null); +} diff --git a/lib/std/process.zig b/lib/std/process.zig index 9cb571714c..2813d8cbab 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -593,8 +593,10 @@ pub fn getUserInfo(name: []const u8) !UserInfo { /// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else /// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`. pub fn posixGetUserInfo(name: []const u8) !UserInfo { - var reader = try io.Reader.open("/etc/passwd", null); - defer reader.close(); + const file = try std.fs.openFileAbsolute("/etc/passwd", .{}); + defer file.close(); + + const reader = file.reader(); const State = enum { Start, @@ -650,8 +652,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { '0'...'9' => byte - '0', else => return error.CorruptPasswordFile, }; - if (@mulWithOverflow(u32, uid, 10, *uid)) return error.CorruptPasswordFile; - if (@addWithOverflow(u32, uid, digit, *uid)) return error.CorruptPasswordFile; + if (@mulWithOverflow(u32, uid, 10, &uid)) return error.CorruptPasswordFile; + if (@addWithOverflow(u32, uid, digit, &uid)) return error.CorruptPasswordFile; }, }, .ReadGroupId => switch (byte) { @@ -666,8 +668,8 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo { '0'...'9' => byte - '0', else => return error.CorruptPasswordFile, }; - if (@mulWithOverflow(u32, gid, 10, *gid)) return error.CorruptPasswordFile; - if (@addWithOverflow(u32, gid, digit, *gid)) return error.CorruptPasswordFile; + if (@mulWithOverflow(u32, gid, 10, &gid)) return error.CorruptPasswordFile; + if (@addWithOverflow(u32, gid, digit, &gid)) return error.CorruptPasswordFile; }, }, } diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index ce8d1c29cc..53f7e1738d 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -394,6 +394,61 @@ fn clone() callconv(.Naked) void { \\ syscall ); }, + + .powerpc64, .powerpc64le => { + asm volatile ( + \\ # store non-volatile regs r30, r31 on stack in order to put our + \\ # start func and its arg there + \\ stwu 30, -16(1) + \\ stw 31, 4(1) + \\ # save r3 (func) into r30, and r6(arg) into r31 + \\ mr 30, 3 + \\ mr 31, 6 + \\ # create initial stack frame for new thread + \\ clrrwi 4, 4, 4 + \\ li 0, 0 + \\ stwu 0, -16(4) + \\ #move c into first arg + \\ mr 3, 5 + \\ mr 5, 7 + \\ mr 6, 8 + \\ mr 7, 9 + \\ # move syscall number into r0 + \\ li 0, 120 + \\ sc + + \\ # check for syscall error + \\ bns+ 1f # jump to label 1 if no summary overflow. + \\ #else + \\ neg 3, 3 #negate the result (errno) + \\1: + \\ # compare sc result with 0 + \\ cmpwi cr7, 3, 0 + + \\ # if not 0, jump to end + \\ bne cr7, 2f + + \\ #else: we're the child + \\ #call funcptr: move arg (d) into r3 + \\ mr 3, 31 + \\ #move r30 (funcptr) into CTR reg + \\ mtctr 30 + \\ # call CTR reg + \\ bctrl + \\ # mov SYS_exit into r0 (the exit param is already in r3) + \\ li 0, 1 + \\ sc + + \\2: + \\ # restore stack + \\ lwz 30, 0(1) + \\ lwz 31, 4(1) + \\ addi 1, 1, 16 + + \\ blr + ); + }, + else => @compileError("Implement clone() for this arch."), } } diff --git a/lib/std/start.zig b/lib/std/start.zig index c65cd08981..aea31a1531 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -121,6 +121,21 @@ fn _start() callconv(.Naked) noreturn { : [argc] "=r" (-> [*]usize) ); }, + .powerpc64le => { + // Before returning the stack pointer, we have to set up a backchain + // and a few other registers required by the ELFv2 ABI. + // TODO: Support powerpc64 (big endian) on ELFv2. + starting_stack_ptr = asm ( + \\ mr 4, 1 + \\ subi 1, 1, 32 + \\ li 5, 0 + \\ std 5, 0(1) + \\ mr %[argc], 4 + : [argc] "=r" (-> [*]usize) + : + : "r4", "r5" + ); + }, else => @compileError("unsupported arch"), } // If LLVM inlines stack variables into _start, they will overwrite |
