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.
This commit is contained in:
Andrew Kelley
2020-09-12 10:48:38 -07:00
34 changed files with 1680 additions and 119 deletions

View File

@@ -76,3 +76,21 @@ Hopefully this will be fixed upstream with LLVM 10.0.1.
##### Windows
See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
## License
The ultimate goal of the Zig project is to serve users. As a first-order
effect, this means users of the compiler, helping programmers to write better
code. Even more important, however, are the end users.
Zig is intended to be used to help end users accomplish their goals. For
example, it would be inappropriate and offensive to use Zig to implement
[dark patterns](https://en.wikipedia.org/wiki/Dark_pattern) and it would be
shameful to utilize Zig to exploit people instead of benefit them.
However, such problems are best solved with social norms, not with software
licenses. Any attempt to complicate the software license of Zig would risk
compromising the value Zig provides to users.
Therefore, Zig is available under the MIT (Expat) License, and comes with a
humble request: use it to make software better serve the needs of end users.

View File

@@ -65,6 +65,7 @@ pub fn build(b: *Builder) !void {
"README.md",
".z.0",
".z.9",
".gz",
"rfc1951.txt",
},
});

View File

@@ -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 {

View File

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

View File

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

View File

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

248
lib/std/compress/gzip.zig Normal file
View File

@@ -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,
}, ""),
);
}

Binary file not shown.

View File

@@ -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();

View File

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

View File

@@ -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),
}
}

View File

@@ -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();

View File

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

View File

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

View File

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

View File

@@ -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");

View File

@@ -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"
);
}

View File

@@ -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"),
}
}

View File

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

View File

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

View File

@@ -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."),
}
}

View File

@@ -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

View File

@@ -5899,6 +5899,10 @@ fn parseCPrimaryExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.N
saw_l_paren = true;
_ = m.next();
},
// (type)sizeof(x)
.Keyword_sizeof,
// (type)alignof(x)
.Keyword_alignof,
// (type)identifier
.Identifier => {},
// (type)integer
@@ -6309,6 +6313,40 @@ fn parseCPrefixOpExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.
node.rhs = try parseCPrefixOpExpr(c, m, scope);
return &node.base;
},
.Keyword_sizeof => {
const inner = if (m.peek().? == .LParen) blk: {
_ = m.next();
const inner = try parseCExpr(c, m, scope);
if (m.next().? != .RParen) {
try m.fail(c, "unable to translate C expr: expected ')'", .{});
return error.ParseError;
}
break :blk inner;
} else try parseCPrefixOpExpr(c, m, scope);
const builtin_call = try c.createBuiltinCall("@sizeOf", 1);
builtin_call.params()[0] = inner;
builtin_call.rparen_token = try appendToken(c, .RParen, ")");
return &builtin_call.base;
},
.Keyword_alignof => {
// TODO this won't work if using <stdalign.h>'s
// #define alignof _Alignof
if (m.next().? != .LParen) {
try m.fail(c, "unable to translate C expr: expected '('", .{});
return error.ParseError;
}
const inner = try parseCExpr(c, m, scope);
if (m.next().? != .RParen) {
try m.fail(c, "unable to translate C expr: expected ')'", .{});
return error.ParseError;
}
const builtin_call = try c.createBuiltinCall("@alignOf", 1);
builtin_call.params()[0] = inner;
builtin_call.rparen_token = try appendToken(c, .RParen, ")");
return &builtin_call.base;
},
else => {
m.i -= 1;
return try parseCSuffixOpExpr(c, m, scope);

View File

@@ -2265,6 +2265,7 @@ struct CodeGen {
Stage2LibCInstallation *libc;
bool is_versioned;
size_t version_major;
size_t version_minor;
size_t version_patch;

View File

@@ -1009,7 +1009,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
g->zig_target->arch == ZigLLVM_x86_64 ||
target_is_arm(g->zig_target) ||
target_is_riscv(g->zig_target) ||
target_is_wasm(g->zig_target))
target_is_wasm(g->zig_target) ||
target_is_ppc(g->zig_target))
{
X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type);
return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval;

View File

@@ -90,7 +90,8 @@ void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {
g->test_name_prefix = prefix;
}
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch) {
void codegen_set_lib_version(CodeGen *g, bool is_versioned, size_t major, size_t minor, size_t patch) {
g->is_versioned = is_versioned;
g->version_major = major;
g->version_minor = minor;
g->version_patch = patch;
@@ -10823,6 +10824,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) {
cache_bool(ch, g->emit_bin);
cache_bool(ch, g->emit_llvm_ir);
cache_bool(ch, g->emit_asm);
cache_bool(ch, g->is_versioned);
cache_usize(ch, g->version_major);
cache_usize(ch, g->version_minor);
cache_usize(ch, g->version_patch);
@@ -10893,7 +10895,7 @@ static void resolve_out_paths(CodeGen *g) {
buf_resize(out_basename, 0);
buf_append_str(out_basename, target_lib_file_prefix(g->zig_target));
buf_append_buf(out_basename, g->root_out_name);
buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic,
buf_append_str(out_basename, target_lib_file_ext(g->zig_target, !g->is_dynamic, g->is_versioned,
g->version_major, g->version_minor, g->version_patch));
break;
}

View File

@@ -38,7 +38,7 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
void codegen_set_linker_script(CodeGen *g, const char *linker_script);
void codegen_set_test_filter(CodeGen *g, Buf *filter);
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
void codegen_set_lib_version(CodeGen *g, bool is_versioned, size_t major, size_t minor, size_t patch);
void codegen_add_time_event(CodeGen *g, const char *name);
void codegen_print_timing_report(CodeGen *g, FILE *f);
void codegen_link(CodeGen *g);

View File

@@ -335,7 +335,7 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con
bool is_ld = (strcmp(lib->name, "ld") == 0);
CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr, lib->name, progress_node);
codegen_set_lib_version(child_gen, lib->sover, 0, 0);
codegen_set_lib_version(child_gen, true, lib->sover, 0, 0);
child_gen->is_dynamic = true;
child_gen->is_dummy_so = true;
child_gen->version_script_path = map_file_path;

View File

@@ -415,6 +415,7 @@ static int main0(int argc, char **argv) {
const char *test_filter = nullptr;
const char *test_name_prefix = nullptr;
bool test_evented_io = false;
bool is_versioned = false;
size_t ver_major = 0;
size_t ver_minor = 0;
size_t ver_patch = 0;
@@ -870,10 +871,13 @@ static int main0(int argc, char **argv) {
} else if (strcmp(arg, "--test-name-prefix") == 0) {
test_name_prefix = argv[i];
} else if (strcmp(arg, "--ver-major") == 0) {
is_versioned = true;
ver_major = atoi(argv[i]);
} else if (strcmp(arg, "--ver-minor") == 0) {
is_versioned = true;
ver_minor = atoi(argv[i]);
} else if (strcmp(arg, "--ver-patch") == 0) {
is_versioned = true;
ver_patch = atoi(argv[i]);
} else if (strcmp(arg, "--test-cmd") == 0) {
test_exec_args.append(argv[i]);
@@ -1223,7 +1227,7 @@ static int main0(int argc, char **argv) {
g->emit_llvm_ir = emit_llvm_ir;
codegen_set_out_name(g, buf_out_name);
codegen_set_lib_version(g, ver_major, ver_minor, ver_patch);
codegen_set_lib_version(g, is_versioned, ver_major, ver_minor, ver_patch);
g->want_single_threaded = want_single_threaded;
codegen_set_linker_script(g, linker_script);
g->version_script_path = version_script;

View File

@@ -779,7 +779,7 @@ const char *target_lib_file_prefix(const ZigTarget *target) {
}
}
const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
const char *target_lib_file_ext(const ZigTarget *target, bool is_static, bool is_versioned,
size_t version_major, size_t version_minor, size_t version_patch)
{
if (target_is_wasm(target)) {
@@ -799,11 +799,19 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
if (is_static) {
return ".a";
} else if (target_os_is_darwin(target->os)) {
return buf_ptr(buf_sprintf(".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
version_major, version_minor, version_patch));
if (is_versioned) {
return buf_ptr(buf_sprintf(".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
version_major, version_minor, version_patch));
} else {
return ".dylib";
}
} else {
return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
version_major, version_minor, version_patch));
if (is_versioned) {
return buf_ptr(buf_sprintf(".so.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
version_major, version_minor, version_patch));
} else {
return ".so";
}
}
}
}
@@ -853,6 +861,9 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
case ZigLLVM_riscv32:
case ZigLLVM_riscv64:
case ZigLLVM_mipsel:
case ZigLLVM_ppc:
case ZigLLVM_ppc64:
case ZigLLVM_ppc64le:
return "sp";
case ZigLLVM_wasm32:
@@ -879,7 +890,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
case ZigLLVM_msp430:
case ZigLLVM_nvptx:
case ZigLLVM_nvptx64:
case ZigLLVM_ppc64le:
case ZigLLVM_r600:
case ZigLLVM_renderscript32:
case ZigLLVM_renderscript64:
@@ -893,8 +903,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) {
case ZigLLVM_tce:
case ZigLLVM_tcele:
case ZigLLVM_xcore:
case ZigLLVM_ppc:
case ZigLLVM_ppc64:
case ZigLLVM_ve:
zig_panic("TODO populate this table with stack pointer register name for this CPU architecture");
}
@@ -1325,6 +1333,11 @@ bool target_is_mips(const ZigTarget *target) {
target->arch == ZigLLVM_mips64 || target->arch == ZigLLVM_mips64el;
}
bool target_is_ppc(const ZigTarget *target) {
return target->arch == ZigLLVM_ppc || target->arch == ZigLLVM_ppc64 ||
target->arch == ZigLLVM_ppc64le;
}
unsigned target_fn_align(const ZigTarget *target) {
return 16;
}

View File

@@ -87,7 +87,7 @@ const char *target_asm_file_ext(const ZigTarget *target);
const char *target_llvm_ir_file_ext(const ZigTarget *target);
const char *target_exe_file_ext(const ZigTarget *target);
const char *target_lib_file_prefix(const ZigTarget *target);
const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
const char *target_lib_file_ext(const ZigTarget *target, bool is_static, bool is_versioned,
size_t version_major, size_t version_minor, size_t version_patch);
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
@@ -95,6 +95,7 @@ ZigLLVM_OSType get_llvm_os_type(Os os_type);
bool target_is_arm(const ZigTarget *target);
bool target_is_mips(const ZigTarget *target);
bool target_is_ppc(const ZigTarget *target);
bool target_allows_addr_zero(const ZigTarget *target);
bool target_has_valgrind_support(const ZigTarget *target);
bool target_os_is_darwin(Os os);

View File

@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
\\source.zig:10:8: [address] in main (test)
\\ foo();
\\ ^
\\start.zig:254:29: [address] in std.start.posixCallMainAndExit (test)
\\start.zig:269:29: [address] in std.start.posixCallMainAndExit (test)
\\ return root.main();
\\ ^
\\start.zig:128:5: [address] in std.start._start (test)
\\start.zig:143:5: [address] in std.start._start (test)
\\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
\\ ^
\\
@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
switch (std.Target.current.cpu.arch) {
.aarch64 => "", // TODO disabled; results in segfault
else =>
\\start.zig:128:5: [address] in std.start._start (test)
\\start.zig:143:5: [address] in std.start._start (test)
\\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
\\ ^
\\

View File

@@ -6,4 +6,7 @@ typedef struct Color {
unsigned char a;
} Color;
#define CLITERAL(type) (type)
#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
#define LIGHTGRAY CLITERAL(Color){ 200, 200, 200, 255 } // Light Gray
#define MY_SIZEOF(x) ((int)sizeof(x))
#define MY_SIZEOF2(x) ((int)sizeof x)

View File

@@ -1,12 +1,18 @@
const expect = @import("std").testing.expect;
const expectEqual = @import("std").testing.expectEqual;
const h = @cImport(@cInclude("stage1/behavior/translate_c_macros.h"));
test "initializer list expression" {
@import("std").testing.expectEqual(h.Color{
expectEqual(h.Color{
.r = 200,
.g = 200,
.b = 200,
.a = 255,
}, h.LIGHTGRAY);
}
test "sizeof in macros" {
expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF(u32));
expectEqual(@as(c_int, @sizeOf(u32)), h.MY_SIZEOF2(u32));
}