{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
- {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@fence|@cmpxchgStrong#}
+ {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgStrong#}
{#header_close#}
{#header_open|@compileError#}
@@ -4766,10 +4765,10 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
Converts an integer into an {#link|enum#} value. The return type is the inferred result type.
- Attempting to convert an integer with no corresponding value in the enum invokes
+ Attempting to convert an integer with no corresponding value in the enum invokes
safety-checked {#link|Undefined Behavior#}.
Note that a {#link|non-exhaustive enum|Non-exhaustive enum#} has corresponding values for all
- integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all
+ integers in the enum's integer tag type: the {#syntax#}_{#endsyntax#} value represents all
the remaining unnamed integers in the enum's tag type.
Performs field access by a compile-time string. Works on both fields and declarations.
@@ -6241,11 +6231,13 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
Are you linking libc? In this case, {#syntax#}std.heap.c_allocator{#endsyntax#} is likely
the right choice, at least for your main allocator.
+
+ Need to use the same allocator in multiple threads? Use one of your choice
+ wrapped around {#syntax#}std.heap.ThreadSafeAllocator{#endsyntax#}
+
Is the maximum number of bytes that you will need bounded by a number known at
- {#link|comptime#}? In this case, use {#syntax#}std.heap.FixedBufferAllocator{#endsyntax#} or
- {#syntax#}std.heap.ThreadSafeFixedBufferAllocator{#endsyntax#} depending on whether you need
- thread-safety or not.
+ {#link|comptime#}? In this case, use {#syntax#}std.heap.FixedBufferAllocator{#endsyntax#}.
Is your program a command line application which runs from start to end without any fundamental
diff --git a/zig/lib/compiler/aro/aro/Compilation.zig b/zig/lib/compiler/aro/aro/Compilation.zig
index 22ca9c00ed..414cdb45f0 100644
--- a/zig/lib/compiler/aro/aro/Compilation.zig
+++ b/zig/lib/compiler/aro/aro/Compilation.zig
@@ -308,7 +308,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {
),
else => {},
}
- if (comp.target.abi == .android) {
+ if (comp.target.isAndroid()) {
try w.writeAll("#define __ANDROID__ 1\n");
}
diff --git a/zig/lib/compiler/aro/aro/target.zig b/zig/lib/compiler/aro/aro/target.zig
index b84788429a..c07935a420 100644
--- a/zig/lib/compiler/aro/aro/target.zig
+++ b/zig/lib/compiler/aro/aro/target.zig
@@ -482,7 +482,6 @@ pub fn get32BitArchVariant(target: std.Target) ?std.Target {
.spirv,
.spirv32,
.loongarch32,
- .dxil,
.xtensa,
=> {}, // Already 32 bit
@@ -509,7 +508,6 @@ pub fn get64BitArchVariant(target: std.Target) ?std.Target {
.arc,
.avr,
.csky,
- .dxil,
.hexagon,
.kalimba,
.lanai,
@@ -578,7 +576,6 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
.bpfel => "bpfel",
.bpfeb => "bpfeb",
.csky => "csky",
- .dxil => "dxil",
.hexagon => "hexagon",
.loongarch32 => "loongarch32",
.loongarch64 => "loongarch64",
@@ -655,7 +652,6 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
.tvos => "tvos",
.watchos => "watchos",
.driverkit => "driverkit",
- .shadermodel => "shadermodel",
.visionos => "xros",
.serenity => "serenity",
.bridgeos => "bridgeos",
@@ -693,6 +689,7 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
.eabi => "eabi",
.eabihf => "eabihf",
.android => "android",
+ .androideabi => "androideabi",
.musl => "musl",
.musleabi => "musleabi",
.musleabihf => "musleabihf",
@@ -702,22 +699,8 @@ pub fn toLLVMTriple(target: std.Target, buf: []u8) []const u8 {
.cygnus => "cygnus",
.simulator => "simulator",
.macabi => "macabi",
- .pixel => "pixel",
- .vertex => "vertex",
- .geometry => "geometry",
- .hull => "hull",
- .domain => "domain",
- .compute => "compute",
- .library => "library",
- .raygeneration => "raygeneration",
- .intersection => "intersection",
- .anyhit => "anyhit",
- .closesthit => "closesthit",
- .miss => "miss",
- .callable => "callable",
- .mesh => "mesh",
- .amplification => "amplification",
- .ohos => "openhos",
+ .ohos => "ohos",
+ .ohoseabi => "ohoseabi",
};
writer.writeAll(llvm_abi) catch unreachable;
return stream.getWritten();
diff --git a/zig/lib/compiler/fmt.zig b/zig/lib/compiler/fmt.zig
index c747addd72..5a4f112c34 100644
--- a/zig/lib/compiler/fmt.zig
+++ b/zig/lib/compiler/fmt.zig
@@ -207,6 +207,7 @@ const FmtError = error{
LockViolation,
NetNameDeleted,
InvalidArgument,
+ ProcessNotFound,
} || fs.File.OpenError;
fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool, dir: fs.Dir, sub_path: []const u8) FmtError!void {
diff --git a/zig/lib/compiler/objcopy.zig b/zig/lib/compiler/objcopy.zig
index ac609c94e5..9794671e6f 100644
--- a/zig/lib/compiler/objcopy.zig
+++ b/zig/lib/compiler/objcopy.zig
@@ -40,6 +40,9 @@ fn cmdObjCopy(
var only_keep_debug: bool = false;
var compress_debug_sections: bool = false;
var listen = false;
+ var add_section: ?AddSection = null;
+ var set_section_alignment: ?SetSectionAlignment = null;
+ var set_section_flags: ?SetSectionFlags = null;
while (i < args.len) : (i += 1) {
const arg = args[i];
if (!mem.startsWith(u8, arg, "-")) {
@@ -104,6 +107,37 @@ fn cmdObjCopy(
i += 1;
if (i >= args.len) fatal("expected another argument after '{s}'", .{arg});
opt_extract = args[i];
+ } else if (mem.eql(u8, arg, "--set-section-alignment")) {
+ i += 1;
+ if (i >= args.len) fatal("expected section name and alignment arguments after '{s}'", .{arg});
+
+ if (splitOption(args[i])) |split| {
+ const alignment = std.fmt.parseInt(u32, split.second, 10) catch |err| {
+ fatal("unable to parse alignment number: '{s}': {s}", .{ split.second, @errorName(err) });
+ };
+ if (!std.math.isPowerOfTwo(alignment)) fatal("alignment must be a power of two", .{});
+ set_section_alignment = .{ .section_name = split.first, .alignment = alignment };
+ } else {
+ fatal("unrecognized argument: '{s}', expecting =", .{args[i]});
+ }
+ } else if (mem.eql(u8, arg, "--set-section-flags")) {
+ i += 1;
+ if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
+
+ if (splitOption(args[i])) |split| {
+ set_section_flags = .{ .section_name = split.first, .flags = parseSectionFlags(split.second) };
+ } else {
+ fatal("unrecognized argument: '{s}', expecting =", .{args[i]});
+ }
+ } else if (mem.eql(u8, arg, "--add-section")) {
+ i += 1;
+ if (i >= args.len) fatal("expected section name and filename arguments after '{s}'", .{arg});
+
+ if (splitOption(args[i])) |split| {
+ add_section = .{ .section_name = split.first, .file_path = split.second };
+ } else {
+ fatal("unrecognized argument: '{s}', expecting =", .{args[i]});
+ }
} else {
fatal("unrecognized argument: '{s}'", .{arg});
}
@@ -151,6 +185,12 @@ fn cmdObjCopy(
fatal("zig objcopy: ELF to RAW or HEX copying does not support --strip", .{});
if (opt_extract != null)
fatal("zig objcopy: ELF to RAW or HEX copying does not support --extract-to", .{});
+ if (add_section != null)
+ fatal("zig objcopy: ELF to RAW or HEX copying does not support --add-section", .{});
+ if (set_section_alignment != null)
+ fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_alignment", .{});
+ if (set_section_flags != null)
+ fatal("zig objcopy: ELF to RAW or HEX copying does not support --set_section_flags", .{});
try emitElf(arena, in_file, out_file, elf_hdr, .{
.ofmt = out_fmt,
@@ -175,6 +215,9 @@ fn cmdObjCopy(
.add_debuglink = opt_add_debuglink,
.extract_to = opt_extract,
.compress_debug = compress_debug_sections,
+ .add_section = add_section,
+ .set_section_alignment = set_section_alignment,
+ .set_section_flags = set_section_flags,
});
return std.process.cleanExit();
},
@@ -217,18 +260,21 @@ const usage =
\\Usage: zig objcopy [options] input output
\\
\\Options:
- \\ -h, --help Print this help and exit
- \\ --output-target= Format of the output file
- \\ -O Alias for --output-target
- \\ --only-section= Remove all but
- \\ -j Alias for --only-section
- \\ --pad-to Pad the last section up to address
- \\ --strip-debug, -g Remove all debug sections from the output.
- \\ --strip-all, -S Remove all debug sections and symbol table from the output.
- \\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.
- \\ --add-gnu-debuglink= Creates a .gnu_debuglink section which contains a reference to and adds it to the output file.
- \\ --extract-to Extract the removed sections into , and add a .gnu-debuglink section.
- \\ --compress-debug-sections Compress DWARF debug sections with zlib
+ \\ -h, --help Print this help and exit
+ \\ --output-target= Format of the output file
+ \\ -O Alias for --output-target
+ \\ --only-section= Remove all but
+ \\ -j Alias for --only-section
+ \\ --pad-to Pad the last section up to address
+ \\ --strip-debug, -g Remove all debug sections from the output.
+ \\ --strip-all, -S Remove all debug sections and symbol table from the output.
+ \\ --only-keep-debug Strip a file, removing contents of any sections that would not be stripped by --strip-debug and leaving the debugging sections intact.
+ \\ --add-gnu-debuglink= Creates a .gnu_debuglink section which contains a reference to and adds it to the output file.
+ \\ --extract-to Extract the removed sections into , and add a .gnu-debuglink section.
+ \\ --compress-debug-sections Compress DWARF debug sections with zlib
+ \\ --set-section-alignment = Set alignment of section to bytes. Must be a power of two.
+ \\ --set-section-flags = Set flags of section to represented as a comma separated set of flags.
+ \\ --add-section = Add file content from with the a new section named .
\\
;
@@ -236,6 +282,24 @@ pub const EmitRawElfOptions = struct {
ofmt: std.Target.ObjectFormat,
only_section: ?[]const u8 = null,
pad_to: ?u64 = null,
+ add_section: ?AddSection = null,
+ set_section_alignment: ?SetSectionAlignment = null,
+ set_section_flags: ?SetSectionFlags = null,
+};
+
+const AddSection = struct {
+ section_name: []const u8,
+ file_path: []const u8,
+};
+
+const SetSectionAlignment = struct {
+ section_name: []const u8,
+ alignment: u32,
+};
+
+const SetSectionFlags = struct {
+ section_name: []const u8,
+ flags: SectionFlags,
};
fn emitElf(
@@ -392,7 +456,7 @@ const BinaryElfOutput = struct {
if (phdr.p_type == elf.PT_LOAD) {
const newSegment = try allocator.create(BinaryElfSegment);
- newSegment.physicalAddress = if (phdr.p_paddr != 0) phdr.p_paddr else phdr.p_vaddr;
+ newSegment.physicalAddress = phdr.p_paddr;
newSegment.virtualAddress = phdr.p_vaddr;
newSegment.fileSize = @intCast(phdr.p_filesz);
newSegment.elfOffset = phdr.p_offset;
@@ -678,6 +742,9 @@ const StripElfOptions = struct {
strip_debug: bool = false,
only_keep_debug: bool = false,
compress_debug: bool = false,
+ add_section: ?AddSection,
+ set_section_alignment: ?SetSectionAlignment,
+ set_section_flags: ?SetSectionFlags,
};
fn stripElf(
@@ -721,6 +788,14 @@ fn stripElf(
var elf_file = try ElfFile(is_64).parse(allocator, in_file, elf_hdr);
defer elf_file.deinit();
+ if (options.add_section) |user_section| {
+ for (elf_file.sections) |section| {
+ if (std.mem.eql(u8, section.name, user_section.section_name)) {
+ fatal("zig objcopy: unable to add section '{s}'. Section already exists in input", .{user_section.section_name});
+ }
+ }
+ }
+
if (filter_complement) |flt| {
// write the .dbg file and close it, so it can be read back to compute the debuglink checksum.
const path = options.extract_to.?;
@@ -733,7 +808,14 @@ fn stripElf(
}
const debuglink: ?DebugLink = if (debuglink_path) |path| ElfFileHelper.createDebugLink(path) else null;
- try elf_file.emit(allocator, out_file, in_file, .{ .section_filter = filter, .debuglink = debuglink, .compress_debug = options.compress_debug });
+ try elf_file.emit(allocator, out_file, in_file, .{
+ .section_filter = filter,
+ .debuglink = debuglink,
+ .compress_debug = options.compress_debug,
+ .add_section = options.add_section,
+ .set_section_alignment = options.set_section_alignment,
+ .set_section_flags = options.set_section_flags,
+ });
},
}
}
@@ -786,7 +868,7 @@ fn ElfFile(comptime is_64: bool) type {
// program header: list of segments
const program_segments = blk: {
if (@sizeOf(Elf_Phdr) != header.phentsize)
- fatal("zig objcopy: unsuported ELF file, unexpected phentsize ({d})", .{header.phentsize});
+ fatal("zig objcopy: unsupported ELF file, unexpected phentsize ({d})", .{header.phentsize});
const program_header = try allocator.alloc(Elf_Phdr, header.phnum);
const bytes_read = try in_file.preadAll(std.mem.sliceAsBytes(program_header), header.phoff);
@@ -798,7 +880,7 @@ fn ElfFile(comptime is_64: bool) type {
// section header
const sections = blk: {
if (@sizeOf(Elf_Shdr) != header.shentsize)
- fatal("zig objcopy: unsuported ELF file, unexpected shentsize ({d})", .{header.shentsize});
+ fatal("zig objcopy: unsupported ELF file, unexpected shentsize ({d})", .{header.shentsize});
const section_header = try allocator.alloc(Section, header.shnum);
@@ -896,6 +978,9 @@ fn ElfFile(comptime is_64: bool) type {
section_filter: Filter = .all,
debuglink: ?DebugLink = null,
compress_debug: bool = false,
+ add_section: ?AddSection = null,
+ set_section_alignment: ?SetSectionAlignment = null,
+ set_section_flags: ?SetSectionFlags = null,
};
fn emit(self: *const Self, gpa: Allocator, out_file: File, in_file: File, options: EmitElfOptions) !void {
var arena = std.heap.ArenaAllocator.init(gpa);
@@ -934,6 +1019,10 @@ fn ElfFile(comptime is_64: bool) type {
if (options.debuglink != null)
next_idx += 1;
+ if (options.add_section != null) {
+ next_idx += 1;
+ }
+
break :blk next_idx;
};
@@ -959,6 +1048,28 @@ fn ElfFile(comptime is_64: bool) type {
break :blk new_offset;
};
+ // add user section to the string table if needed
+ const user_section_name: u32 = blk: {
+ if (options.add_section == null) break :blk elf.SHN_UNDEF;
+ if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
+ fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
+
+ const strtab = &self.sections[self.raw_elf_header.e_shstrndx];
+ const update = §ions_update[self.raw_elf_header.e_shstrndx];
+
+ const name = options.add_section.?.section_name;
+ const new_offset: u32 = @intCast(strtab.payload.?.len);
+ const buf = try allocator.alignedAlloc(u8, section_memory_align, new_offset + name.len + 1);
+ @memcpy(buf[0..new_offset], strtab.payload.?);
+ @memcpy(buf[new_offset..][0..name.len], name);
+ buf[new_offset + name.len] = 0;
+
+ assert(update.action == .keep);
+ update.payload = buf;
+
+ break :blk new_offset;
+ };
+
// maybe compress .debug sections
if (options.compress_debug) {
for (self.sections[1..], sections_update[1..]) |section, *update| {
@@ -1018,7 +1129,7 @@ fn ElfFile(comptime is_64: bool) type {
if (section.section.sh_type == elf.SHT_NOBITS)
continue;
if (section.section.sh_offset < offset) {
- fatal("zig objcopy: unsuported ELF file", .{});
+ fatal("zig objcopy: unsupported ELF file", .{});
}
offset = section.section.sh_offset;
}
@@ -1134,10 +1245,100 @@ fn ElfFile(comptime is_64: bool) type {
eof_offset += @as(Elf_OffSize, @intCast(payload.len));
}
+ // --add-section
+ if (options.add_section) |add_section| {
+ var section_file = fs.cwd().openFile(add_section.file_path, .{}) catch |err|
+ fatal("unable to open '{s}': {s}", .{ add_section.file_path, @errorName(err) });
+ defer section_file.close();
+
+ const payload = try section_file.readToEndAlloc(arena.allocator(), std.math.maxInt(usize));
+
+ dest_sections[dest_section_idx] = Elf_Shdr{
+ .sh_name = user_section_name,
+ .sh_type = elf.SHT_PROGBITS,
+ .sh_flags = 0,
+ .sh_addr = 0,
+ .sh_offset = eof_offset,
+ .sh_size = @intCast(payload.len),
+ .sh_link = elf.SHN_UNDEF,
+ .sh_info = elf.SHN_UNDEF,
+ .sh_addralign = 4,
+ .sh_entsize = 0,
+ };
+ dest_section_idx += 1;
+
+ cmdbuf.appendAssumeCapacity(.{ .write_data = .{ .data = payload, .out_offset = eof_offset } });
+ eof_offset += @as(Elf_OffSize, @intCast(payload.len));
+ }
+
assert(dest_section_idx == new_shnum);
break :blk dest_sections;
};
+ // --set-section-alignment: overwrite alignment
+ if (options.set_section_alignment) |set_align| {
+ if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
+ fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
+
+ const strtab = §ions_update[self.raw_elf_header.e_shstrndx];
+ for (updated_section_header) |*section| {
+ const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
+ if (std.mem.eql(u8, section_name, set_align.section_name)) {
+ section.sh_addralign = set_align.alignment;
+ break;
+ }
+ } else std.log.warn("Skipping --set-section-alignment. Section '{s}' not found", .{set_align.section_name});
+ }
+
+ // --set-section-flags: overwrite flags
+ if (options.set_section_flags) |set_flags| {
+ if (self.raw_elf_header.e_shstrndx == elf.SHN_UNDEF)
+ fatal("zig objcopy: no strtab, cannot add the user section", .{}); // TODO add the section if needed?
+
+ const strtab = §ions_update[self.raw_elf_header.e_shstrndx];
+ for (updated_section_header) |*section| {
+ const section_name = std.mem.span(@as([*:0]const u8, @ptrCast(&strtab.payload.?[section.sh_name])));
+ if (std.mem.eql(u8, section_name, set_flags.section_name)) {
+ section.sh_flags = std.elf.SHF_WRITE; // default is writable cleared by "readonly"
+ const f = set_flags.flags;
+
+ // Supporting a subset of GNU and LLVM objcopy for ELF only
+ // GNU:
+ // alloc: add SHF_ALLOC
+ // contents: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
+ // load: if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
+ // noload: not ELF relevant
+ // readonly: clear default SHF_WRITE flag
+ // code: add SHF_EXECINSTR
+ // data: not ELF relevant
+ // rom: ignored
+ // exclude: add SHF_EXCLUDE
+ // share: not ELF relevant
+ // debug: not ELF relevant
+ // large: add SHF_X86_64_LARGE. Fatal error if target is not x86_64
+ if (f.alloc) section.sh_flags |= std.elf.SHF_ALLOC;
+ if (f.contents or f.load) {
+ if (section.sh_type == std.elf.SHT_NOBITS) section.sh_type = std.elf.SHT_PROGBITS;
+ }
+ if (f.readonly) section.sh_flags &= ~@as(@TypeOf(section.sh_type), std.elf.SHF_WRITE);
+ if (f.code) section.sh_flags |= std.elf.SHF_EXECINSTR;
+ if (f.exclude) section.sh_flags |= std.elf.SHF_EXCLUDE;
+ if (f.large) {
+ if (updated_elf_header.e_machine != std.elf.EM.X86_64)
+ fatal("zig objcopy: 'large' section flag is only supported on x86_64 targets", .{});
+ section.sh_flags |= std.elf.SHF_X86_64_LARGE;
+ }
+
+ // LLVM:
+ // merge: add SHF_MERGE
+ // strings: add SHF_STRINGS
+ if (f.merge) section.sh_flags |= std.elf.SHF_MERGE;
+ if (f.strings) section.sh_flags |= std.elf.SHF_STRINGS;
+ break;
+ }
+ } else std.log.warn("Skipping --set-section-flags. Section '{s}' not found", .{set_flags.section_name});
+ }
+
// write the section header at the tail
{
const offset = std.mem.alignForward(Elf_OffSize, eof_offset, @alignOf(Elf_Shdr));
@@ -1361,3 +1562,111 @@ const ElfFileHelper = struct {
return hasher.final();
}
};
+
+const SectionFlags = packed struct {
+ alloc: bool = false,
+ contents: bool = false,
+ load: bool = false,
+ noload: bool = false,
+ readonly: bool = false,
+ code: bool = false,
+ data: bool = false,
+ rom: bool = false,
+ exclude: bool = false,
+ shared: bool = false,
+ debug: bool = false,
+ large: bool = false,
+ merge: bool = false,
+ strings: bool = false,
+};
+
+fn parseSectionFlags(comma_separated_flags: []const u8) SectionFlags {
+ const P = struct {
+ fn parse(flags: *SectionFlags, string: []const u8) void {
+ if (string.len == 0) return;
+
+ if (std.mem.eql(u8, string, "alloc")) {
+ flags.alloc = true;
+ } else if (std.mem.eql(u8, string, "contents")) {
+ flags.contents = true;
+ } else if (std.mem.eql(u8, string, "load")) {
+ flags.load = true;
+ } else if (std.mem.eql(u8, string, "noload")) {
+ flags.noload = true;
+ } else if (std.mem.eql(u8, string, "readonly")) {
+ flags.readonly = true;
+ } else if (std.mem.eql(u8, string, "code")) {
+ flags.code = true;
+ } else if (std.mem.eql(u8, string, "data")) {
+ flags.data = true;
+ } else if (std.mem.eql(u8, string, "rom")) {
+ flags.rom = true;
+ } else if (std.mem.eql(u8, string, "exclude")) {
+ flags.exclude = true;
+ } else if (std.mem.eql(u8, string, "shared")) {
+ flags.shared = true;
+ } else if (std.mem.eql(u8, string, "debug")) {
+ flags.debug = true;
+ } else if (std.mem.eql(u8, string, "large")) {
+ flags.large = true;
+ } else if (std.mem.eql(u8, string, "merge")) {
+ flags.merge = true;
+ } else if (std.mem.eql(u8, string, "strings")) {
+ flags.strings = true;
+ } else {
+ std.log.warn("Skipping unrecognized section flag '{s}'", .{string});
+ }
+ }
+ };
+
+ var flags = SectionFlags{};
+ var offset: usize = 0;
+ for (comma_separated_flags, 0..) |c, i| {
+ if (c == ',') {
+ defer offset = i + 1;
+ const string = comma_separated_flags[offset..i];
+ P.parse(&flags, string);
+ }
+ }
+ P.parse(&flags, comma_separated_flags[offset..]);
+ return flags;
+}
+
+test "Parse section flags" {
+ const F = SectionFlags;
+ try std.testing.expectEqual(F{}, parseSectionFlags(""));
+ try std.testing.expectEqual(F{}, parseSectionFlags(","));
+ try std.testing.expectEqual(F{}, parseSectionFlags("abc"));
+ try std.testing.expectEqual(F{ .alloc = true }, parseSectionFlags("alloc"));
+ try std.testing.expectEqual(F{ .data = true }, parseSectionFlags("data,"));
+ try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code"));
+ try std.testing.expectEqual(F{ .alloc = true, .code = true }, parseSectionFlags("alloc,code,not_supported"));
+}
+
+const SplitResult = struct { first: []const u8, second: []const u8 };
+
+fn splitOption(option: []const u8) ?SplitResult {
+ const separator = '=';
+ if (option.len < 3) return null; // minimum "a=b"
+ for (1..option.len - 1) |i| {
+ if (option[i] == separator) return .{
+ .first = option[0..i],
+ .second = option[i + 1 ..],
+ };
+ }
+ return null;
+}
+
+test "Split option" {
+ {
+ const split = splitOption(".abc=123");
+ try std.testing.expect(split != null);
+ try std.testing.expectEqualStrings(".abc", split.?.first);
+ try std.testing.expectEqualStrings("123", split.?.second);
+ }
+
+ try std.testing.expectEqual(null, splitOption(""));
+ try std.testing.expectEqual(null, splitOption("=abc"));
+ try std.testing.expectEqual(null, splitOption("abc="));
+ try std.testing.expectEqual(null, splitOption("abc"));
+}
diff --git a/zig/lib/compiler_rt/aulldiv.zig b/zig/lib/compiler_rt/aulldiv.zig
index 21ec61722b..6d822b7b86 100644
--- a/zig/lib/compiler_rt/aulldiv.zig
+++ b/zig/lib/compiler_rt/aulldiv.zig
@@ -1,13 +1,14 @@
const std = @import("std");
const builtin = @import("builtin");
const arch = builtin.cpu.arch;
+const os = builtin.os.tag;
const abi = builtin.abi;
const common = @import("common.zig");
pub const panic = common.panic;
comptime {
- if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) {
+ if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and builtin.zig_backend != .stage2_c) {
// Don't let LLVM apply the stdcall name mangling on those MSVC builtins
@export(&_alldiv, .{ .name = "\x01__alldiv", .linkage = common.linkage, .visibility = common.visibility });
@export(&_aulldiv, .{ .name = "\x01__aulldiv", .linkage = common.linkage, .visibility = common.visibility });
diff --git a/zig/lib/compiler_rt/aullrem.zig b/zig/lib/compiler_rt/aullrem.zig
index c1578aeb8b..5c4d0588f7 100644
--- a/zig/lib/compiler_rt/aullrem.zig
+++ b/zig/lib/compiler_rt/aullrem.zig
@@ -1,13 +1,14 @@
const std = @import("std");
const builtin = @import("builtin");
const arch = builtin.cpu.arch;
+const os = builtin.os.tag;
const abi = builtin.abi;
const common = @import("common.zig");
pub const panic = common.panic;
comptime {
- if (arch == .x86 and abi == .msvc and builtin.zig_backend != .stage2_c) {
+ if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and builtin.zig_backend != .stage2_c) {
// Don't let LLVM apply the stdcall name mangling on those MSVC builtins
@export(&_allrem, .{ .name = "\x01__allrem", .linkage = common.linkage, .visibility = common.visibility });
@export(&_aullrem, .{ .name = "\x01__aullrem", .linkage = common.linkage, .visibility = common.visibility });
diff --git a/zig/lib/compiler_rt/common.zig b/zig/lib/compiler_rt/common.zig
index 1dfd4be07f..786dc7303a 100644
--- a/zig/lib/compiler_rt/common.zig
+++ b/zig/lib/compiler_rt/common.zig
@@ -1,8 +1,14 @@
const std = @import("std");
const builtin = @import("builtin");
const native_endian = builtin.cpu.arch.endian();
+const ofmt_c = builtin.object_format == .c;
-pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .internal else .weak;
+pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test)
+ .internal
+else if (ofmt_c)
+ .strong
+else
+ .weak;
/// Determines the symbol's visibility to other objects.
/// For WebAssembly this allows the symbol to be resolved to other modules, but will not
/// export it to the host runtime.
@@ -16,19 +22,22 @@ pub const want_aeabi = switch (builtin.abi) {
.gnueabi,
.gnueabihf,
.android,
+ .androideabi,
=> switch (builtin.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => true,
else => false,
},
else => false,
};
+pub const want_mingw_arm_abi = builtin.cpu.arch.isArmOrThumb() and builtin.target.isMinGW();
+
pub const want_ppc_abi = builtin.cpu.arch.isPowerPC();
pub const want_float_exceptions = !builtin.cpu.arch.isWasm();
// Libcalls that involve u128 on Windows x86-64 are expected by LLVM to use the
// calling convention of @Vector(2, u64), rather than what's standard.
-pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64 and @import("builtin").object_format != .c;
+pub const want_windows_v2u64_abi = builtin.os.tag == .windows and builtin.cpu.arch == .x86_64 and !ofmt_c;
/// This governs whether to use these symbol names for f16/f32 conversions
/// rather than the standard names:
@@ -67,13 +76,14 @@ pub const gnu_f16_abi = switch (builtin.cpu.arch) {
pub const want_sparc_abi = builtin.cpu.arch.isSPARC();
-// Avoid dragging in the runtime safety mechanisms into this .o file,
-// unless we're trying to test compiler-rt.
-pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
- _ = error_return_trace;
+// Avoid dragging in the runtime safety mechanisms into this .o file, unless
+// we're trying to test compiler-rt.
+pub const Panic = if (builtin.is_test) std.debug.FormattedPanic else struct {};
+
+/// To be deleted after zig1.wasm is updated.
+pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, ret_addr: ?usize) noreturn {
if (builtin.is_test) {
- @branchHint(.cold);
- std.debug.panic("{s}", .{msg});
+ std.debug.defaultPanic(msg, error_return_trace, ret_addr orelse @returnAddress());
} else {
unreachable;
}
diff --git a/zig/lib/compiler_rt/emutls.zig b/zig/lib/compiler_rt/emutls.zig
index 55927b8b37..b0244a14f5 100644
--- a/zig/lib/compiler_rt/emutls.zig
+++ b/zig/lib/compiler_rt/emutls.zig
@@ -18,7 +18,7 @@ const gcc_word = usize;
pub const panic = common.panic;
comptime {
- if (builtin.link_libc and (builtin.abi == .android or builtin.os.tag == .openbsd)) {
+ if (builtin.link_libc and (builtin.abi.isAndroid() or builtin.os.tag == .openbsd)) {
@export(&__emutls_get_address, .{ .name = "__emutls_get_address", .linkage = common.linkage, .visibility = common.visibility });
}
}
diff --git a/zig/lib/compiler_rt/fixdfdi.zig b/zig/lib/compiler_rt/fixdfdi.zig
index 78744b145d..b9bc5797b9 100644
--- a/zig/lib/compiler_rt/fixdfdi.zig
+++ b/zig/lib/compiler_rt/fixdfdi.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const intFromFloat = @import("./int_from_float.zig").intFromFloat;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__fixdfdi, .{ .name = "__fixdfdi", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__fixdfdi, .{ .name = "__dtoi64", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/fixsfdi.zig b/zig/lib/compiler_rt/fixsfdi.zig
index c75e401475..192614bd79 100644
--- a/zig/lib/compiler_rt/fixsfdi.zig
+++ b/zig/lib/compiler_rt/fixsfdi.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const intFromFloat = @import("./int_from_float.zig").intFromFloat;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__fixsfdi, .{ .name = "__fixsfdi", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__fixsfdi, .{ .name = "__stoi64", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/fixunsdfdi.zig b/zig/lib/compiler_rt/fixunsdfdi.zig
index 68a0c44ff9..86a4fa9de1 100644
--- a/zig/lib/compiler_rt/fixunsdfdi.zig
+++ b/zig/lib/compiler_rt/fixunsdfdi.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const intFromFloat = @import("./int_from_float.zig").intFromFloat;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__fixunsdfdi, .{ .name = "__dtou64", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/fixunssfdi.zig b/zig/lib/compiler_rt/fixunssfdi.zig
index 9157a71e2f..81d1c77f06 100644
--- a/zig/lib/compiler_rt/fixunssfdi.zig
+++ b/zig/lib/compiler_rt/fixunssfdi.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const intFromFloat = @import("./int_from_float.zig").intFromFloat;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__fixunssfdi, .{ .name = "__stou64", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/floatdidf.zig b/zig/lib/compiler_rt/floatdidf.zig
index 393fa95c19..fc145e836d 100644
--- a/zig/lib/compiler_rt/floatdidf.zig
+++ b/zig/lib/compiler_rt/floatdidf.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const floatFromInt = @import("./float_from_int.zig").floatFromInt;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__floatdidf, .{ .name = "__floatdidf", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__floatdidf, .{ .name = "__i64tod", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/floatdisf.zig b/zig/lib/compiler_rt/floatdisf.zig
index 4f3b42ef79..d1c9515f9a 100644
--- a/zig/lib/compiler_rt/floatdisf.zig
+++ b/zig/lib/compiler_rt/floatdisf.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const floatFromInt = @import("./float_from_int.zig").floatFromInt;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__floatdisf, .{ .name = "__floatdisf", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__floatdisf, .{ .name = "__i64tos", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/floatundidf.zig b/zig/lib/compiler_rt/floatundidf.zig
index 5cb1de0d35..3448f0cf20 100644
--- a/zig/lib/compiler_rt/floatundidf.zig
+++ b/zig/lib/compiler_rt/floatundidf.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const floatFromInt = @import("./float_from_int.zig").floatFromInt;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__floatundidf, .{ .name = "__floatundidf", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__floatundidf, .{ .name = "__u64tod", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/compiler_rt/floatundisf.zig b/zig/lib/compiler_rt/floatundisf.zig
index 17f9148575..9054982b54 100644
--- a/zig/lib/compiler_rt/floatundisf.zig
+++ b/zig/lib/compiler_rt/floatundisf.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const common = @import("./common.zig");
const floatFromInt = @import("./float_from_int.zig").floatFromInt;
@@ -8,6 +9,10 @@ comptime {
@export(&__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = common.linkage, .visibility = common.visibility });
} else {
@export(&__floatundisf, .{ .name = "__floatundisf", .linkage = common.linkage, .visibility = common.visibility });
+
+ if (common.want_mingw_arm_abi) {
+ @export(&__floatundisf, .{ .name = "__u64tos", .linkage = common.linkage, .visibility = common.visibility });
+ }
}
}
diff --git a/zig/lib/libc/glibc/abilists b/zig/lib/libc/glibc/abilists
index 4e61797327..3aed1e0f93 100644
Binary files a/zig/lib/libc/glibc/abilists and b/zig/lib/libc/glibc/abilists differ
diff --git a/zig/lib/libc/glibc/sysdeps/mips/mips32/crtn.S b/zig/lib/libc/glibc/sysdeps/mips/mips32/crtn.S
index 89ecbd9882..4fd4c745d9 100644
--- a/zig/lib/libc/glibc/sysdeps/mips/mips32/crtn.S
+++ b/zig/lib/libc/glibc/sysdeps/mips/mips32/crtn.S
@@ -42,7 +42,8 @@
lw $31,28($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
addiu $sp,$sp,32
.set macro
.set reorder
@@ -51,7 +52,8 @@
lw $31,28($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
addiu $sp,$sp,32
.set macro
.set reorder
diff --git a/zig/lib/libc/glibc/sysdeps/mips/mips64/n32/crtn.S b/zig/lib/libc/glibc/sysdeps/mips/mips64/n32/crtn.S
index 633d79cfad..f9a6c7ee4c 100644
--- a/zig/lib/libc/glibc/sysdeps/mips/mips64/n32/crtn.S
+++ b/zig/lib/libc/glibc/sysdeps/mips/mips64/n32/crtn.S
@@ -43,7 +43,8 @@
ld $28,0($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
addiu $sp,$sp,16
.set macro
.set reorder
@@ -53,7 +54,8 @@
ld $28,0($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
addiu $sp,$sp,16
.set macro
.set reorder
diff --git a/zig/lib/libc/glibc/sysdeps/mips/mips64/n64/crtn.S b/zig/lib/libc/glibc/sysdeps/mips/mips64/n64/crtn.S
index 99ed1e3263..2722b2812c 100644
--- a/zig/lib/libc/glibc/sysdeps/mips/mips64/n64/crtn.S
+++ b/zig/lib/libc/glibc/sysdeps/mips/mips64/n64/crtn.S
@@ -43,7 +43,8 @@
ld $28,0($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
daddiu $sp,$sp,16
.set macro
.set reorder
@@ -53,7 +54,8 @@
ld $28,0($sp)
.set noreorder
.set nomacro
- j $31
+ /* zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315 */
+ jr $31
daddiu $sp,$sp,16
.set macro
.set reorder
diff --git a/zig/lib/libc/glibc/sysdeps/unix/mips/sysdep.h b/zig/lib/libc/glibc/sysdeps/unix/mips/sysdep.h
index d1e0460260..54e92b26d0 100644
--- a/zig/lib/libc/glibc/sysdeps/unix/mips/sysdep.h
+++ b/zig/lib/libc/glibc/sysdeps/unix/mips/sysdep.h
@@ -39,7 +39,8 @@
.end function; \
.size function,.-function
-#define ret j ra ; nop
+// zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315
+#define ret jr ra ; nop
#undef PSEUDO_END
#define PSEUDO_END(sym) cfi_endproc; .end sym; .size sym,.-sym
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/endianness.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/endianness.h
new file mode 100644
index 0000000000..989463fb5d
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/endianness.h
@@ -0,0 +1,11 @@
+#ifndef _BITS_ENDIANNESS_H
+#define _BITS_ENDIANNESS_H 1
+
+#ifndef _BITS_ENDIAN_H
+#error "Never use directly; include instead."
+#endif
+
+/* LoongArch is little-endian. */
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+#endif /* bits/endianness.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fcntl.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fcntl.h
new file mode 100644
index 0000000000..bbbde65d43
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fcntl.h
@@ -0,0 +1,61 @@
+/* O_*, F_*, FD_* bit values for the generic Linux/LoongArch ABI.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _FCNTL_H
+#error "Never use directly; include instead."
+#endif
+
+#include
+
+/* In 64-bit ISA files are always with 64bit off_t and F_*LK64 are the same as
+ non-64-bit versions. It will need to be revised for 128-bit. */
+#if __WORDSIZE == 64
+#define __O_LARGEFILE 0
+
+#define F_GETLK64 5 /* Get record locking info. */
+#define F_SETLK64 6 /* Set record locking info (non-blocking). */
+#define F_SETLKW64 7 /* Set record locking info (blocking). */
+#endif
+
+struct flock
+{
+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
+#ifndef __USE_FILE_OFFSET64
+ __off_t l_start; /* Offset where the lock begins. */
+ __off_t l_len; /* Size of the locked area; zero means until EOF. */
+#else
+ __off64_t l_start; /* Offset where the lock begins. */
+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */
+#endif
+ __pid_t l_pid; /* Process holding the lock. */
+};
+
+#ifdef __USE_LARGEFILE64
+struct flock64
+{
+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
+ __off64_t l_start; /* Offset where the lock begins. */
+ __off64_t l_len; /* Size of the locked area; zero means until EOF. */
+ __pid_t l_pid; /* Process holding the lock. */
+};
+#endif
+
+/* Include generic Linux declarations. */
+#include
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fenv.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fenv.h
new file mode 100644
index 0000000000..92dc84011a
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/fenv.h
@@ -0,0 +1,90 @@
+/* Floating point environment.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _FENV_H
+#error "Never use directly; include instead."
+#endif
+
+/* Define bits representing the exception. We use the bit positions
+ of the appropriate bits in the FPU control word. */
+enum
+{
+ FE_INEXACT =
+#define FE_INEXACT 0x010000
+ FE_INEXACT,
+ FE_UNDERFLOW =
+#define FE_UNDERFLOW 0x020000
+ FE_UNDERFLOW,
+ FE_OVERFLOW =
+#define FE_OVERFLOW 0x040000
+ FE_OVERFLOW,
+ FE_DIVBYZERO =
+#define FE_DIVBYZERO 0x080000
+ FE_DIVBYZERO,
+ FE_INVALID =
+#define FE_INVALID 0x100000
+ FE_INVALID,
+};
+
+#define FE_ALL_EXCEPT \
+ (FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID)
+
+/* The LoongArch FPU supports all of the four defined rounding modes. We
+ use again the bit positions in the FPU control word as the values
+ for the appropriate macros. */
+enum
+{
+ FE_TONEAREST =
+#define FE_TONEAREST 0x000
+ FE_TONEAREST,
+ FE_TOWARDZERO =
+#define FE_TOWARDZERO 0x100
+ FE_TOWARDZERO,
+ FE_UPWARD =
+#define FE_UPWARD 0x200
+ FE_UPWARD,
+ FE_DOWNWARD =
+#define FE_DOWNWARD 0x300
+ FE_DOWNWARD
+};
+
+/* Type representing exception flags. */
+typedef unsigned int fexcept_t;
+
+/* Type representing floating-point environment. This function corresponds
+ to the layout of the block written by the `fstenv'. */
+typedef struct
+{
+ unsigned int __fp_control_register;
+} fenv_t;
+
+/* If the default argument is used we use this value. */
+#define FE_DFL_ENV ((const fenv_t *) -1)
+
+#ifdef __USE_GNU
+/* Floating-point environment where none of the exception is masked. */
+#define FE_NOMASK_ENV ((const fenv_t *) -257)
+#endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT_C23)
+/* Type representing floating-point control modes. */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes. */
+#define FE_DFL_MODE ((const femode_t *) -1L)
+#endif
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/hwcap.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/hwcap.h
new file mode 100644
index 0000000000..3b3d1ad463
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/hwcap.h
@@ -0,0 +1,38 @@
+/* Defines for bits in AT_HWCAP. LoongArch64 Linux version.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#if !defined (_SYS_AUXV_H)
+# error "Never include directly; use instead."
+#endif
+
+/* The following must match the kernel's . */
+/* HWCAP flags */
+#define HWCAP_LOONGARCH_CPUCFG (1 << 0)
+#define HWCAP_LOONGARCH_LAM (1 << 1)
+#define HWCAP_LOONGARCH_UAL (1 << 2)
+#define HWCAP_LOONGARCH_FPU (1 << 3)
+#define HWCAP_LOONGARCH_LSX (1 << 4)
+#define HWCAP_LOONGARCH_LASX (1 << 5)
+#define HWCAP_LOONGARCH_CRC32 (1 << 6)
+#define HWCAP_LOONGARCH_COMPLEX (1 << 7)
+#define HWCAP_LOONGARCH_CRYPTO (1 << 8)
+#define HWCAP_LOONGARCH_LVZ (1 << 9)
+#define HWCAP_LOONGARCH_LBT_X86 (1 << 10)
+#define HWCAP_LOONGARCH_LBT_ARM (1 << 11)
+#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12)
+#define HWCAP_LOONGARCH_PTW (1 << 13)
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link.h
new file mode 100644
index 0000000000..821a54fe54
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link.h
@@ -0,0 +1,76 @@
+/* Machine-specific declarations for dynamic linker interface.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _LINK_H
+#error "Never include directly; use instead."
+#endif
+
+#ifndef __loongarch_soft_float
+typedef float La_loongarch_vr
+ __attribute__ ((__vector_size__ (16), __aligned__ (16)));
+typedef float La_loongarch_xr
+ __attribute__ ((__vector_size__ (32), __aligned__ (16)));
+
+typedef union
+{
+ double fpreg[4];
+ La_loongarch_vr vr[2];
+ La_loongarch_xr xr[1];
+} La_loongarch_vector __attribute__ ((__aligned__ (16)));
+#endif
+
+typedef struct La_loongarch_regs
+{
+ unsigned long int lr_reg[8]; /* a0 - a7 */
+#ifndef __loongarch_soft_float
+ La_loongarch_vector lr_vec[8]; /* fa0 - fa7 or vr0 - vr7 or xr0 - xr7*/
+#endif
+ unsigned long int lr_ra;
+ unsigned long int lr_sp;
+} La_loongarch_regs;
+
+/* Return values for calls from PLT on LoongArch. */
+typedef struct La_loongarch_retval
+{
+ unsigned long int lrv_a0;
+ unsigned long int lrv_a1;
+#ifndef __loongarch_soft_float
+ La_loongarch_vector lrv_vec0;
+ La_loongarch_vector lrv_vec1;
+#endif
+} La_loongarch_retval;
+
+__BEGIN_DECLS
+
+extern ElfW (Addr) la_loongarch_gnu_pltenter (ElfW (Sym) *__sym,
+ unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ La_loongarch_regs *__regs,
+ unsigned int *__flags,
+ const char *__symname,
+ long int *__framesizep);
+extern unsigned int la_loongarch_gnu_pltexit (ElfW (Sym) *__sym,
+ unsigned int __ndx,
+ uintptr_t *__refcook,
+ uintptr_t *__defcook,
+ const La_loongarch_regs *__inregs,
+ La_loongarch_retval *__outregs,
+ const char *__symname);
+
+__END_DECLS
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link_lavcurrent.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link_lavcurrent.h
new file mode 100644
index 0000000000..36d637cd1f
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/link_lavcurrent.h
@@ -0,0 +1,25 @@
+/* Data structure for communication from the run-time dynamic linker for
+ loaded ELF shared objects. LAV_CURRENT definition.
+ Copyright (C) 2023-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _LINK_H
+# error "Never include directly; use instead."
+#endif
+
+/* Version numbers for la_version handshake interface. */
+#define LAV_CURRENT 3
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/long-double.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/long-double.h
new file mode 100644
index 0000000000..a83f6c746f
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/long-double.h
@@ -0,0 +1,21 @@
+/* Properties of long double type. ldbl-128 version.
+ Copyright (C) 2016-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+/* long double is distinct from double, so there is nothing to
+ define here. */
+#define __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI 0
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/procfs.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/procfs.h
new file mode 100644
index 0000000000..4371fd0a8f
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/procfs.h
@@ -0,0 +1,52 @@
+/* Types for registers for sys/procfs.h.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _SYS_PROCFS_H
+# error "Never include directly; use instead."
+#endif
+
+/* Type for a general-purpose register. */
+typedef __uint64_t elf_greg_t;
+
+/* And the whole bunch of them. We could have used `struct
+ pt_regs' directly in the typedef, but tradition says that
+ the register set is an array, which does have some peculiar
+ semantics, so leave it that way. */
+#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof (elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+#define ELF_NFPREG 34 /* 32 FPRs + 8-byte byte-vec for fcc + 4-byte FCR */
+typedef union
+{
+ double d;
+ float f;
+} elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+typedef union
+{
+ double d[2];
+ float f[4];
+} __attribute__ ((__aligned__ (16))) elf_lsxregset_t[32];
+
+typedef union
+{
+ double d[4];
+ float f[8];
+} __attribute__ ((__aligned__ (32))) elf_lasxregset_t[32];
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/pthread_stack_min.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/pthread_stack_min.h
new file mode 100644
index 0000000000..4a05d0d8a5
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/pthread_stack_min.h
@@ -0,0 +1,20 @@
+/* Definition of PTHREAD_STACK_MIN. LoongArch Linux version.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+/* Minimum size for a thread. At least two pages with 64k pages. */
+#define PTHREAD_STACK_MIN 131072
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/setjmp.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/setjmp.h
new file mode 100644
index 0000000000..59214222c8
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/setjmp.h
@@ -0,0 +1,42 @@
+/* Define the machine-dependent type `jmp_buf'.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _LOONGARCH_BITS_SETJMP_H
+#define _LOONGARCH_BITS_SETJMP_H
+
+typedef struct __jmp_buf_internal_tag
+{
+ /* Program counter. */
+ long int __pc;
+ /* Stack pointer. */
+ long int __sp;
+ /* Reserved */
+ long int __x;
+ /* Frame pointer. */
+ long int __fp;
+ /* Callee-saved registers. */
+ long int __regs[9];
+
+#ifndef __loongarch_soft_float
+ /* Callee-saved floating point registers. */
+ double __fpregs[8];
+#endif
+
+} __jmp_buf[1];
+
+#endif /* _LOONGARCH_BITS_SETJMP_H */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/shmlba.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/shmlba.h
new file mode 100644
index 0000000000..166f19c016
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/shmlba.h
@@ -0,0 +1,24 @@
+/* Define SHMLBA. LoongArch version.
+ Copyright (C) 2023-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _SYS_SHM_H
+# error "Never use directly; include instead."
+#endif
+
+/* Segment low boundary address multiple. */
+#define SHMLBA 0x10000
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/sigstack.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/sigstack.h
new file mode 100644
index 0000000000..af2933a8ce
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/sigstack.h
@@ -0,0 +1,32 @@
+/* sigstack, sigaltstack definitions.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _BITS_SIGSTACK_H
+#define _BITS_SIGSTACK_H 1
+
+#if !defined _SIGNAL_H && !defined _SYS_UCONTEXT_H
+# error "Never include this file directly. Use instead"
+#endif
+
+/* Minimum stack size for a signal handler. */
+#define MINSIGSTKSZ 4096
+
+/* System default stack size. */
+#define SIGSTKSZ 16384
+
+#endif /* bits/sigstack.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/struct_stat.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/struct_stat.h
new file mode 100644
index 0000000000..c8e2d78b57
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/struct_stat.h
@@ -0,0 +1,127 @@
+/* Definition for struct stat.
+ Copyright (C) 2020-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#if !defined _SYS_STAT_H && !defined _FCNTL_H
+# error "Never include directly; use instead."
+#endif
+
+#ifndef _BITS_STRUCT_STAT_H
+#define _BITS_STRUCT_STAT_H 1
+
+#include
+#include
+
+#if defined __USE_FILE_OFFSET64
+# define __field64(type, type64, name) type64 name
+#elif __WORDSIZE == 64 || defined __INO_T_MATCHES_INO64_T
+# if defined __INO_T_MATCHES_INO64_T && !defined __OFF_T_MATCHES_OFF64_T
+# error "ino_t and off_t must both be the same type"
+# endif
+# define __field64(type, type64, name) type name
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+# define __field64(type, type64, name) \
+ type name __attribute__((__aligned__ (__alignof__ (type64)))); int __##name##_pad
+#else
+# define __field64(type, type64, name) \
+ int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
+#endif
+
+struct stat
+ {
+ __dev_t st_dev; /* Device. */
+ __field64(__ino_t, __ino64_t, st_ino); /* File serial number. */
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Link count. */
+ __uid_t st_uid; /* User ID of the file's owner. */
+ __gid_t st_gid; /* Group ID of the file's group.*/
+ __dev_t st_rdev; /* Device number, if device. */
+ __dev_t __pad1;
+ __field64(__off_t, __off64_t, st_size); /* Size of file, in bytes. */
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
+ int __pad2;
+ __field64(__blkcnt_t, __blkcnt64_t, st_blocks); /* 512-byte blocks */
+#ifdef __USE_XOPEN2K8
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+ identifier 'timespec' to appear in the header.
+ Therefore we have to handle the use of this header in strictly
+ standard-compliant sources special. */
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+# define st_atime st_atim.tv_sec /* Backward compatibility. */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
+#else
+ __time_t st_atime; /* Time of last access. */
+ unsigned long int st_atimensec; /* Nscecs of last access. */
+ __time_t st_mtime; /* Time of last modification. */
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
+ __time_t st_ctime; /* Time of last status change. */
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
+#endif
+ int __glibc_reserved[2];
+ };
+
+#undef __field64
+
+#ifdef __USE_LARGEFILE64
+struct stat64
+ {
+ __dev_t st_dev; /* Device. */
+ __ino64_t st_ino; /* File serial number. */
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Link count. */
+ __uid_t st_uid; /* User ID of the file's owner. */
+ __gid_t st_gid; /* Group ID of the file's group.*/
+ __dev_t st_rdev; /* Device number, if device. */
+ __dev_t __pad1;
+ __off64_t st_size; /* Size of file, in bytes. */
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
+ int __pad2;
+ __blkcnt64_t st_blocks; /* Nr. 512-byte blocks allocated. */
+#ifdef __USE_XOPEN2K8
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+ identifier 'timespec' to appear in the header.
+ Therefore we have to handle the use of this header in strictly
+ standard-compliant sources special. */
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+#else
+ __time_t st_atime; /* Time of last access. */
+ unsigned long int st_atimensec; /* Nscecs of last access. */
+ __time_t st_mtime; /* Time of last modification. */
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
+ __time_t st_ctime; /* Time of last status change. */
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
+#endif
+ int __glibc_reserved[2];
+ };
+#endif
+
+/* Tell code we have these members. */
+#define _STATBUF_ST_BLKSIZE
+#define _STATBUF_ST_RDEV
+/* Nanosecond resolution time values are supported. */
+#define _STATBUF_ST_NSEC
+
+#endif /* _BITS_STRUCT_STAT_H */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/timesize.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/timesize.h
new file mode 100644
index 0000000000..17f828ecfe
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/timesize.h
@@ -0,0 +1,20 @@
+/* Bit size of the time_t type at glibc build time, general case.
+ Copyright (C) 2018-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+/* Size in bits of the 'time_t' type of the default ABI. */
+#define __TIMESIZE 64
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/bits/wordsize.h b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/wordsize.h
new file mode 100644
index 0000000000..98996fdf03
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/bits/wordsize.h
@@ -0,0 +1,19 @@
+/* Copyright (C) 1999-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#define __WORDSIZE 64
+#define __WORDSIZE_TIME64_COMPAT32 0
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/fpu_control.h b/zig/lib/libc/include/loongarch64-linux-gnusf/fpu_control.h
new file mode 100644
index 0000000000..d52d6d51cc
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/fpu_control.h
@@ -0,0 +1,119 @@
+/* FPU control word bits.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _FPU_CONTROL_H
+#define _FPU_CONTROL_H
+
+/* LoongArch FPU floating point control register bits.
+ *
+ * 31-29 -> reserved (read as 0, can not changed by software)
+ * 28 -> cause bit for invalid exception
+ * 27 -> cause bit for division by zero exception
+ * 26 -> cause bit for overflow exception
+ * 25 -> cause bit for underflow exception
+ * 24 -> cause bit for inexact exception
+ * 23-21 -> reserved (read as 0, can not changed by software)
+ * 20 -> flag invalid exception
+ * 19 -> flag division by zero exception
+ * 18 -> flag overflow exception
+ * 17 -> flag underflow exception
+ * 16 -> flag inexact exception
+ * 9-8 -> rounding control
+ * 7-5 -> reserved (read as 0, can not changed by software)
+ * 4 -> enable exception for invalid exception
+ * 3 -> enable exception for division by zero exception
+ * 2 -> enable exception for overflow exception
+ * 1 -> enable exception for underflow exception
+ * 0 -> enable exception for inexact exception
+ *
+ *
+ * Rounding Control:
+ * 00 - rounding ties to even (RNE)
+ * 01 - rounding toward zero (RZ)
+ * 10 - rounding (up) toward plus infinity (RP)
+ * 11 - rounding (down) toward minus infinity (RM)
+ */
+
+#include
+
+#ifdef __loongarch_soft_float
+
+#define _FPU_RESERVED 0xffffffff
+#define _FPU_DEFAULT 0x00000000
+typedef unsigned int fpu_control_t;
+#define _FPU_GETCW(cw) (cw) = 0
+#define _FPU_SETCW(cw) (void) (cw)
+extern fpu_control_t __fpu_control;
+
+#else /* __loongarch_soft_float */
+
+/* Masks for interrupts. */
+#define _FPU_MASK_V 0x10 /* Invalid operation */
+#define _FPU_MASK_Z 0x08 /* Division by zero */
+#define _FPU_MASK_O 0x04 /* Overflow */
+#define _FPU_MASK_U 0x02 /* Underflow */
+#define _FPU_MASK_I 0x01 /* Inexact operation */
+
+/* Flush denormalized numbers to zero. */
+#define _FPU_FLUSH_TZ 0x1000000
+
+/* Rounding control. */
+#define _FPU_RC_NEAREST 0x000 /* RECOMMENDED */
+#define _FPU_RC_ZERO 0x100
+#define _FPU_RC_UP 0x200
+#define _FPU_RC_DOWN 0x300
+/* Mask for rounding control. */
+#define _FPU_RC_MASK 0x300
+
+#define _FPU_RESERVED 0x0
+
+#define _FPU_DEFAULT 0x0
+#define _FPU_IEEE 0x1F
+
+/* Type of the control word. */
+typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
+
+/* Macros for accessing the hardware control word. */
+extern fpu_control_t __loongarch_fpu_getcw (void) __THROW;
+extern void __loongarch_fpu_setcw (fpu_control_t) __THROW;
+#define _FPU_GETCW(cw) __asm__ volatile ("movfcsr2gr %0,$fcsr0" : "=r"(cw))
+#define _FPU_SETCW(cw) __asm__ volatile ("movgr2fcsr $fcsr0,%0" : : "r"(cw))
+
+/* Default control word set at startup. */
+extern fpu_control_t __fpu_control;
+
+# define _FCLASS_SNAN (1 << 0)
+# define _FCLASS_QNAN (1 << 1)
+# define _FCLASS_MINF (1 << 2)
+# define _FCLASS_MNORM (1 << 3)
+# define _FCLASS_MSUBNORM (1 << 4)
+# define _FCLASS_MZERO (1 << 5)
+# define _FCLASS_PINF (1 << 6)
+# define _FCLASS_PNORM (1 << 7)
+# define _FCLASS_PSUBNORM (1 << 8)
+# define _FCLASS_PZERO (1 << 9)
+
+# define _FCLASS_ZERO (_FCLASS_MZERO | _FCLASS_PZERO)
+# define _FCLASS_SUBNORM (_FCLASS_MSUBNORM | _FCLASS_PSUBNORM)
+# define _FCLASS_NORM (_FCLASS_MNORM | _FCLASS_PNORM)
+# define _FCLASS_INF (_FCLASS_MINF | _FCLASS_PINF)
+# define _FCLASS_NAN (_FCLASS_SNAN | _FCLASS_QNAN)
+
+#endif /* __loongarch_soft_float */
+
+#endif /* fpu_control.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names-lp64s.h b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names-lp64s.h
new file mode 100644
index 0000000000..7c8b796194
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names-lp64s.h
@@ -0,0 +1,27 @@
+/* This file is automatically generated. */
+#ifndef __GNU_LIB_NAMES_H
+# error "Never use directly; include instead."
+#endif
+
+#define LD_LINUX_LOONGARCH_LP64S_SO "ld-linux-loongarch-lp64s.so.1"
+#define LD_SO "ld-linux-loongarch-lp64s.so.1"
+#define LIBANL_SO "libanl.so.1"
+#define LIBBROKENLOCALE_SO "libBrokenLocale.so.1"
+#define LIBC_MALLOC_DEBUG_SO "libc_malloc_debug.so.0"
+#define LIBC_SO "libc.so.6"
+#define LIBDL_SO "libdl.so.2"
+#define LIBGCC_S_SO "libgcc_s.so.1"
+#define LIBMVEC_SO "libmvec.so.1"
+#define LIBM_SO "libm.so.6"
+#define LIBNSL_SO "libnsl.so.1"
+#define LIBNSS_COMPAT_SO "libnss_compat.so.2"
+#define LIBNSS_DB_SO "libnss_db.so.2"
+#define LIBNSS_DNS_SO "libnss_dns.so.2"
+#define LIBNSS_FILES_SO "libnss_files.so.2"
+#define LIBNSS_HESIOD_SO "libnss_hesiod.so.2"
+#define LIBNSS_LDAP_SO "libnss_ldap.so.2"
+#define LIBPTHREAD_SO "libpthread.so.0"
+#define LIBRESOLV_SO "libresolv.so.2"
+#define LIBRT_SO "librt.so.1"
+#define LIBTHREAD_DB_SO "libthread_db.so.1"
+#define LIBUTIL_SO "libutil.so.1"
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names.h b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names.h
new file mode 100644
index 0000000000..c3eba41e09
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/lib-names.h
@@ -0,0 +1,16 @@
+/* This file is automatically generated.
+ It defines macros to allow user program to find the shared
+ library files which come as part of GNU libc. */
+#ifndef __GNU_LIB_NAMES_H
+#define __GNU_LIB_NAMES_H 1
+
+#include
+
+#if __WORDSIZE == 64 && defined __loongarch_soft_float
+# include
+#endif
+#if __WORDSIZE == 64 && defined __loongarch_double_float
+# include
+#endif
+
+#endif /* gnu/lib-names.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs-lp64s.h b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs-lp64s.h
new file mode 100644
index 0000000000..6ce02418e6
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs-lp64s.h
@@ -0,0 +1,38 @@
+/* This file is automatically generated.
+ It defines a symbol `__stub_FUNCTION' for each function
+ in the C library which is a stub, meaning it will fail
+ every time called, usually setting errno to ENOSYS. */
+
+#ifdef _LIBC
+ #error Applications may not define the macro _LIBC
+#endif
+
+#define __stub___compat_bdflush
+#define __stub___compat_create_module
+#define __stub___compat_get_kernel_syms
+#define __stub___compat_query_module
+#define __stub___compat_uselib
+#define __stub_chflags
+#define __stub_fchflags
+#define __stub_feclearexcept
+#define __stub_fedisableexcept
+#define __stub_feenableexcept
+#define __stub_fegetenv
+#define __stub_fegetexcept
+#define __stub_fegetexceptflag
+#define __stub_fegetmode
+#define __stub_fegetround
+#define __stub_feholdexcept
+#define __stub_feraiseexcept
+#define __stub_fesetenv
+#define __stub_fesetexcept
+#define __stub_fesetexceptflag
+#define __stub_fesetmode
+#define __stub_fesetround
+#define __stub_fetestexcept
+#define __stub_feupdateenv
+#define __stub_gtty
+#define __stub_revoke
+#define __stub_setlogin
+#define __stub_sigreturn
+#define __stub_stty
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs.h b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs.h
new file mode 100644
index 0000000000..ea3f10c421
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/gnu/stubs.h
@@ -0,0 +1,12 @@
+/* This file is automatically generated.
+ This file selects the right generated file of `__stub_FUNCTION' macros
+ based on the architecture being compiled for. */
+
+#include
+
+#if __WORDSIZE == 64 && defined __loongarch_soft_float
+# include
+#endif
+#if __WORDSIZE == 64 && defined __loongarch_double_float
+# include
+#endif
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/ieee754.h b/zig/lib/libc/include/loongarch64-linux-gnusf/ieee754.h
new file mode 100644
index 0000000000..b1e2ec7dc6
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/ieee754.h
@@ -0,0 +1,170 @@
+/* Copyright (C) 1992-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _IEEE754_H
+#define _IEEE754_H 1
+
+#include
+
+#include
+
+__BEGIN_DECLS
+
+union ieee754_float
+ {
+ float f;
+
+ /* This is the IEEE 754 single-precision format. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:8;
+ unsigned int mantissa:23;
+#endif /* Big endian. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned int mantissa:23;
+ unsigned int exponent:8;
+ unsigned int negative:1;
+#endif /* Little endian. */
+ } ieee;
+
+ /* This format makes it easier to see if a NaN is a signalling NaN. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:8;
+ unsigned int quiet_nan:1;
+ unsigned int mantissa:22;
+#endif /* Big endian. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ unsigned int mantissa:22;
+ unsigned int quiet_nan:1;
+ unsigned int exponent:8;
+ unsigned int negative:1;
+#endif /* Little endian. */
+ } ieee_nan;
+ };
+
+#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */
+
+
+union ieee754_double
+ {
+ double d;
+
+ /* This is the IEEE 754 double-precision format. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:11;
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa0:20;
+ unsigned int mantissa1:32;
+#endif /* Big endian. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa1:32;
+ unsigned int mantissa0:20;
+ unsigned int exponent:11;
+ unsigned int negative:1;
+#endif /* Little endian. */
+ } ieee;
+
+ /* This format makes it easier to see if a NaN is a signalling NaN. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:11;
+ unsigned int quiet_nan:1;
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa0:19;
+ unsigned int mantissa1:32;
+#else
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa1:32;
+ unsigned int mantissa0:19;
+ unsigned int quiet_nan:1;
+ unsigned int exponent:11;
+ unsigned int negative:1;
+#endif
+ } ieee_nan;
+ };
+
+#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */
+
+
+union ieee854_long_double
+ {
+ long double d;
+
+ /* This is the IEEE 854 quad-precision format. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:15;
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa0:16;
+ unsigned int mantissa1:32;
+ unsigned int mantissa2:32;
+ unsigned int mantissa3:32;
+#endif /* Big endian. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa3:32;
+ unsigned int mantissa2:32;
+ unsigned int mantissa1:32;
+ unsigned int mantissa0:16;
+ unsigned int exponent:15;
+ unsigned int negative:1;
+#endif /* Little endian. */
+ } ieee;
+
+ /* This format makes it easier to see if a NaN is a signalling NaN. */
+ struct
+ {
+#if __BYTE_ORDER == __BIG_ENDIAN
+ unsigned int negative:1;
+ unsigned int exponent:15;
+ unsigned int quiet_nan:1;
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa0:15;
+ unsigned int mantissa1:32;
+ unsigned int mantissa2:32;
+ unsigned int mantissa3:32;
+#else
+ /* Together these comprise the mantissa. */
+ unsigned int mantissa3:32;
+ unsigned int mantissa2:32;
+ unsigned int mantissa1:32;
+ unsigned int mantissa0:15;
+ unsigned int quiet_nan:1;
+ unsigned int exponent:15;
+ unsigned int negative:1;
+#endif
+ } ieee_nan;
+ };
+
+#define IEEE854_LONG_DOUBLE_BIAS 0x3fff /* Added to exponent. */
+
+__END_DECLS
+
+#endif /* ieee754.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/sys/asm.h b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/asm.h
new file mode 100644
index 0000000000..282831f10d
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/asm.h
@@ -0,0 +1,78 @@
+/* Miscellaneous macros.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+#ifndef _SYS_ASM_H
+#define _SYS_ASM_H
+
+#include
+#include
+
+/* Macros to handle different pointer/register sizes for 32/64-bit code. */
+#define SZREG 8
+#define SZFREG 8
+#define SZVREG 16
+#define SZXREG 32
+#define REG_L ld.d
+#define REG_S st.d
+#define SRLI srli.d
+#define SLLI slli.d
+#define ADDI addi.d
+#define ADD add.d
+#define SUB sub.d
+#define BSTRINS bstrins.d
+#define LI li.d
+#define FREG_L fld.d
+#define FREG_S fst.d
+
+/* Declare leaf routine.
+ The usage of macro LEAF/ENTRY is as follows:
+ 1. LEAF(fcn) -- the align value of fcn is .align 3 (default value)
+ 2. LEAF(fcn, 6) -- the align value of fcn is .align 6
+*/
+#define LEAF_IMPL(symbol, aln, ...) \
+ .text; \
+ .globl symbol; \
+ .align aln; \
+ .type symbol, @function; \
+symbol: \
+ cfi_startproc;
+
+
+#define LEAF(...) LEAF_IMPL(__VA_ARGS__, 3)
+#define ENTRY(...) LEAF(__VA_ARGS__)
+
+#define LEAF_NO_ALIGN(symbol) \
+ .text; \
+ .globl symbol; \
+ .type symbol, @function; \
+symbol: \
+ cfi_startproc;
+
+#define ENTRY_NO_ALIGN(symbol) LEAF_NO_ALIGN(symbol)
+
+
+/* Mark end of function. */
+#undef END
+#define END(function) \
+ cfi_endproc; \
+ .size function, .- function;
+
+/* Stack alignment. */
+#define ALMASK ~15
+
+#endif /* sys/asm.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/sys/ucontext.h b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/ucontext.h
new file mode 100644
index 0000000000..5db0d1e09e
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/ucontext.h
@@ -0,0 +1,64 @@
+/* struct ucontext definition.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library. If not, see
+ . */
+
+/* Don't rely on this, the interface is currently messed up and may need to
+ be broken to be fixed. */
+#ifndef _SYS_UCONTEXT_H
+#define _SYS_UCONTEXT_H 1
+
+#include
+
+#include
+#include
+
+#ifdef __USE_MISC
+#define LARCH_NGREG 32
+
+#define LARCH_REG_RA 1
+#define LARCH_REG_SP 3
+#define LARCH_REG_S0 23
+#define LARCH_REG_S1 24
+#define LARCH_REG_A0 4
+#define LARCH_REG_S2 25
+#define LARCH_REG_NARGS 8
+
+typedef unsigned long int greg_t;
+/* Container for all general registers. */
+typedef greg_t gregset_t[32];
+#endif
+
+typedef struct mcontext_t
+{
+ unsigned long long __pc;
+ unsigned long long __gregs[32];
+ unsigned int __flags;
+ unsigned long long __extcontext[0] __attribute__((__aligned__(16)));
+} mcontext_t;
+
+/* Userlevel context. */
+typedef struct ucontext_t
+{
+ unsigned long int __uc_flags;
+ struct ucontext_t *uc_link;
+ stack_t uc_stack;
+ sigset_t uc_sigmask;
+ mcontext_t uc_mcontext;
+} ucontext_t;
+
+#endif /* sys/ucontext.h */
\ No newline at end of file
diff --git a/zig/lib/libc/include/loongarch64-linux-gnusf/sys/user.h b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/user.h
new file mode 100644
index 0000000000..5dff8a5443
--- /dev/null
+++ b/zig/lib/libc/include/loongarch64-linux-gnusf/sys/user.h
@@ -0,0 +1,42 @@
+/* struct user_regs_struct definition for LoongArch.
+ Copyright (C) 2022-2024 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef _SYS_USER_H
+#define _SYS_USER_H 1
+
+#include
+
+struct user_regs_struct
+{
+ /* Saved main processor registers. */
+ uint64_t regs[32];
+
+ /* Saved special registers. */
+ uint64_t orig_a0;
+ uint64_t csr_era;
+ uint64_t csr_badv;
+ uint64_t reserved[10];
+};
+
+struct user_fp_struct {
+ uint64_t fpr[32];
+ uint64_t fcc;
+ uint32_t fcsr;
+};
+
+#endif /* _SYS_USER_H */
\ No newline at end of file
diff --git a/zig/lib/libc/musl/crt/arm/crti.s b/zig/lib/libc/musl/crt/arm/crti.s
index 18dc1e4197..cccda3eaef 100644
--- a/zig/lib/libc/musl/crt/arm/crti.s
+++ b/zig/lib/libc/musl/crt/arm/crti.s
@@ -3,11 +3,13 @@
.section .init
.global _init
.type _init,%function
+.align 2
_init:
push {r0,lr}
.section .fini
.global _fini
.type _fini,%function
+.align 2
_fini:
push {r0,lr}
diff --git a/zig/lib/libc/musl/crt/mips/crtn.s b/zig/lib/libc/musl/crt/mips/crtn.s
index 506a04b78c..5146d83a0e 100644
--- a/zig/lib/libc/musl/crt/mips/crtn.s
+++ b/zig/lib/libc/musl/crt/mips/crtn.s
@@ -3,11 +3,13 @@
.section .init
lw $gp,24($sp)
lw $ra,28($sp)
- j $ra
+ # zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315
+ jr $ra
addu $sp,$sp,32
.section .fini
lw $gp,24($sp)
lw $ra,28($sp)
- j $ra
+ # zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315
+ jr $ra
addu $sp,$sp,32
diff --git a/zig/lib/libc/musl/crt/mips64/crtn.s b/zig/lib/libc/musl/crt/mips64/crtn.s
index f3930b2406..dc4dbb03ad 100644
--- a/zig/lib/libc/musl/crt/mips64/crtn.s
+++ b/zig/lib/libc/musl/crt/mips64/crtn.s
@@ -3,11 +3,13 @@
.section .init
ld $gp,16($sp)
ld $ra,24($sp)
- j $ra
+ # zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315
+ jr $ra
daddu $sp,$sp,32
.section .fini
ld $gp,16($sp)
ld $ra,24($sp)
- j $ra
+ # zig patch: j -> jr for https://github.com/ziglang/zig/issues/21315
+ jr $ra
daddu $sp,$sp,32
diff --git a/zig/lib/libunwind/src/gcc_personality_v0.c b/zig/lib/libunwind/src/gcc_personality_v0.c
index c946497d75..1d9c7f4d17 100644
--- a/zig/lib/libunwind/src/gcc_personality_v0.c
+++ b/zig/lib/libunwind/src/gcc_personality_v0.c
@@ -20,6 +20,15 @@
#include
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#include
+#include
+
+EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
+ PDISPATCHER_CONTEXT,
+ _Unwind_Personality_Fn);
+#endif
+
// Pointer encodings documented at:
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
@@ -43,9 +52,9 @@
#define DW_EH_PE_indirect 0x80 // gcc extension
// read a uleb128 encoded value and advance pointer
-static uintptr_t readULEB128(const uint8_t **data) {
- uintptr_t result = 0;
- uintptr_t shift = 0;
+static size_t readULEB128(const uint8_t **data) {
+ size_t result = 0;
+ size_t shift = 0;
unsigned char byte;
const uint8_t *p = *data;
do {
@@ -133,7 +142,7 @@ static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
}
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
- !defined(__ARM_DWARF_EH__)
+ !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
#define USING_ARM_EHABI 1
_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *,
struct _Unwind_Context *);
@@ -168,6 +177,10 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(
COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
_Unwind_State state, struct _Unwind_Exception *exceptionObject,
struct _Unwind_Context *context)
+#elif defined(__SEH__)
+static _Unwind_Reason_Code __gcc_personality_imp(
+ int version, _Unwind_Action actions, uint64_t exceptionClass,
+ struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
#else
COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
int version, _Unwind_Action actions, uint64_t exceptionClass,
@@ -205,14 +218,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
}
// Walk call-site table looking for range that includes current PC.
uint8_t callSiteEncoding = *lsda++;
- uint32_t callSiteTableLength = readULEB128(&lsda);
+ size_t callSiteTableLength = readULEB128(&lsda);
const uint8_t *callSiteTableStart = lsda;
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
const uint8_t *p = callSiteTableStart;
while (p < callSiteTableEnd) {
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+ size_t length = readEncodedPointer(&p, callSiteEncoding);
+ size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
readULEB128(&p); // action value not used for C code
if (landingPad == 0)
continue; // no landing pad for this entry
@@ -232,3 +245,12 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
// No landing pad found, continue unwinding.
return continueUnwind(exceptionObject, context);
}
+
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+COMPILER_RT_ABI EXCEPTION_DISPOSITION
+__gcc_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
+ PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) {
+ return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
+ __gcc_personality_imp);
+}
+#endif
diff --git a/zig/lib/std/Build.zig b/zig/lib/std/Build.zig
index dbd96441b1..988a72c129 100644
--- a/zig/lib/std/Build.zig
+++ b/zig/lib/std/Build.zig
@@ -90,9 +90,6 @@ modules: std.StringArrayHashMap(*Module),
named_writefiles: std.StringArrayHashMap(*Step.WriteFile),
named_lazy_paths: std.StringArrayHashMap(LazyPath),
-/// A map from build root dirs to the corresponding `*Dependency`. This is shared with all child
-/// `Build`s.
-initialized_deps: *InitializedDepMap,
/// The hash of this instance's package. `""` means that this is the root package.
pkg_hash: []const u8,
/// A mapping from dependency names to package hashes.
@@ -125,6 +122,7 @@ pub const Graph = struct {
host: ResolvedTarget,
incremental: ?bool = null,
random_seed: u32 = 0,
+ dependency_cache: InitializedDepMap = .empty,
};
const AvailableDeps = []const struct { []const u8, []const u8 };
@@ -144,7 +142,7 @@ const SystemLibraryMode = enum {
declared_enabled,
};
-const InitializedDepMap = std.HashMap(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
+const InitializedDepMap = std.HashMapUnmanaged(InitializedDepKey, *Dependency, InitializedDepContext, std.hash_map.default_max_load_percentage);
const InitializedDepKey = struct {
build_root_string: []const u8,
user_input_options: UserInputOptionsMap,
@@ -219,6 +217,8 @@ const UserValue = union(enum) {
scalar: []const u8,
list: ArrayList([]const u8),
map: StringHashMap(*const UserValue),
+ lazy_path: LazyPath,
+ lazy_path_list: ArrayList(LazyPath),
};
const TypeId = enum {
@@ -230,6 +230,8 @@ const TypeId = enum {
string,
list,
build_id,
+ lazy_path,
+ lazy_path_list,
};
const TopLevelStep = struct {
@@ -252,8 +254,6 @@ pub fn create(
available_deps: AvailableDeps,
) !*Build {
const arena = graph.arena;
- const initialized_deps = try arena.create(InitializedDepMap);
- initialized_deps.* = InitializedDepMap.initContext(arena, .{ .allocator = arena });
const b = try arena.create(Build);
b.* = .{
@@ -304,7 +304,6 @@ pub fn create(
.modules = .init(arena),
.named_writefiles = .init(arena),
.named_lazy_paths = .init(arena),
- .initialized_deps = initialized_deps,
.pkg_hash = "",
.available_deps = available_deps,
.release_mode = .off,
@@ -398,7 +397,6 @@ fn createChildOnly(
.modules = .init(allocator),
.named_writefiles = .init(allocator),
.named_lazy_paths = .init(allocator),
- .initialized_deps = parent.initialized_deps,
.pkg_hash = pkg_hash,
.available_deps = pkg_deps,
.release_mode = parent.release_mode,
@@ -439,6 +437,22 @@ fn userInputOptionsFromArgs(allocator: Allocator, args: anytype) UserInputOption
.used = false,
}) catch @panic("OOM");
},
+ LazyPath => {
+ user_input_options.put(field.name, .{
+ .name = field.name,
+ .value = .{ .lazy_path = v.dupeInner(allocator) },
+ .used = false,
+ }) catch @panic("OOM");
+ },
+ []const LazyPath => {
+ var list = ArrayList(LazyPath).initCapacity(allocator, v.len) catch @panic("OOM");
+ for (v) |lp| list.appendAssumeCapacity(lp.dupeInner(allocator));
+ user_input_options.put(field.name, .{
+ .name = field.name,
+ .value = .{ .lazy_path_list = list },
+ .used = false,
+ }) catch @panic("OOM");
+ },
[]const u8 => {
user_input_options.put(field.name, .{
.name = field.name,
@@ -498,6 +512,8 @@ const OrderedUserValue = union(enum) {
scalar: []const u8,
list: ArrayList([]const u8),
map: ArrayList(Pair),
+ lazy_path: LazyPath,
+ lazy_path_list: ArrayList(LazyPath),
const Pair = struct {
name: []const u8,
@@ -508,6 +524,7 @@ const OrderedUserValue = union(enum) {
};
fn hash(val: OrderedUserValue, hasher: *std.hash.Wyhash) void {
+ hasher.update(&std.mem.toBytes(std.meta.activeTag(val)));
switch (val) {
.flag => {},
.scalar => |scalar| hasher.update(scalar),
@@ -518,6 +535,31 @@ const OrderedUserValue = union(enum) {
hasher.update(map_entry.name);
map_entry.value.hash(hasher);
},
+ .lazy_path => |lp| hashLazyPath(lp, hasher),
+ .lazy_path_list => |lp_list| for (lp_list.items) |lp| {
+ hashLazyPath(lp, hasher);
+ },
+ }
+ }
+
+ fn hashLazyPath(lp: LazyPath, hasher: *std.hash.Wyhash) void {
+ switch (lp) {
+ .src_path => |sp| {
+ hasher.update(sp.owner.pkg_hash);
+ hasher.update(sp.sub_path);
+ },
+ .generated => |gen| {
+ hasher.update(gen.file.step.owner.pkg_hash);
+ hasher.update(std.mem.asBytes(&gen.up));
+ hasher.update(gen.sub_path);
+ },
+ .cwd_relative => |rel_path| {
+ hasher.update(rel_path);
+ },
+ .dependency => |dep| {
+ hasher.update(dep.dependency.builder.pkg_hash);
+ hasher.update(dep.sub_path);
+ },
}
}
@@ -541,6 +583,8 @@ const OrderedUserValue = union(enum) {
.scalar => |scalar| .{ .scalar = scalar },
.list => |list| .{ .list = list },
.map => |map| .{ .map = OrderedUserValue.mapFromUnordered(allocator, map) },
+ .lazy_path => |lp| .{ .lazy_path = lp },
+ .lazy_path_list => |list| .{ .lazy_path_list = list },
};
}
};
@@ -1029,7 +1073,11 @@ pub fn addConfigHeader(
/// Allocator.dupe without the need to handle out of memory.
pub fn dupe(b: *Build, bytes: []const u8) []u8 {
- return b.allocator.dupe(u8, bytes) catch @panic("OOM");
+ return dupeInner(b.allocator, bytes);
+}
+
+pub fn dupeInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 {
+ return allocator.dupe(u8, bytes) catch @panic("OOM");
}
/// Duplicates an array of strings without the need to handle out of memory.
@@ -1041,7 +1089,11 @@ pub fn dupeStrings(b: *Build, strings: []const []const u8) [][]u8 {
/// Duplicates a path and converts all slashes to the OS's canonical path separator.
pub fn dupePath(b: *Build, bytes: []const u8) []u8 {
- const the_copy = b.dupe(bytes);
+ return dupePathInner(b.allocator, bytes);
+}
+
+fn dupePathInner(allocator: std.mem.Allocator, bytes: []const u8) []u8 {
+ const the_copy = dupeInner(allocator, bytes);
for (the_copy) |*byte| {
switch (byte.*) {
'/', '\\' => byte.* = fs.path.sep,
@@ -1155,7 +1207,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
return null;
}
},
- .list, .map => {
+ .list, .map, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be a boolean, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1164,7 +1216,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
},
.int => switch (option_ptr.value) {
- .flag, .list, .map => {
+ .flag, .list, .map, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be an integer, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1188,7 +1240,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
},
.float => switch (option_ptr.value) {
- .flag, .map, .list => {
+ .flag, .map, .list, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be a float, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1205,7 +1257,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
},
.@"enum" => switch (option_ptr.value) {
- .flag, .map, .list => {
+ .flag, .map, .list, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be an enum, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1223,7 +1275,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
},
.string => switch (option_ptr.value) {
- .flag, .list, .map => {
+ .flag, .list, .map, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be a string, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1233,7 +1285,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
.scalar => |s| return s,
},
.build_id => switch (option_ptr.value) {
- .flag, .map, .list => {
+ .flag, .map, .list, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be an enum, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1251,7 +1303,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
},
.list => switch (option_ptr.value) {
- .flag, .map => {
+ .flag, .map, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be a list, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1264,7 +1316,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
.list => |lst| return lst.items,
},
.enum_list => switch (option_ptr.value) {
- .flag, .map => {
+ .flag, .map, .lazy_path, .lazy_path_list => {
log.err("Expected -D{s} to be a list, but received a {s}.", .{
name, @tagName(option_ptr.value),
});
@@ -1282,19 +1334,48 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
},
.list => |lst| {
const Child = @typeInfo(T).pointer.child;
- var new_list = b.allocator.alloc(Child, lst.items.len) catch @panic("OOM");
- for (lst.items, 0..) |str, i| {
- const value = std.meta.stringToEnum(Child, str) orelse {
+ const new_list = b.allocator.alloc(Child, lst.items.len) catch @panic("OOM");
+ for (new_list, lst.items) |*new_item, str| {
+ new_item.* = std.meta.stringToEnum(Child, str) orelse {
log.err("Expected -D{s} to be of type {s}.", .{ name, @typeName(Child) });
b.markInvalidUserInput();
b.allocator.free(new_list);
return null;
};
- new_list[i] = value;
}
return new_list;
},
},
+ .lazy_path => switch (option_ptr.value) {
+ .scalar => |s| return .{ .cwd_relative = s },
+ .lazy_path => |lp| return lp,
+ .flag, .map, .list, .lazy_path_list => {
+ log.err("Expected -D{s} to be a path, but received a {s}.", .{
+ name, @tagName(option_ptr.value),
+ });
+ b.markInvalidUserInput();
+ return null;
+ },
+ },
+ .lazy_path_list => switch (option_ptr.value) {
+ .scalar => |s| return b.allocator.dupe(LazyPath, &[_]LazyPath{.{ .cwd_relative = s }}) catch @panic("OOM"),
+ .lazy_path => |lp| return b.allocator.dupe(LazyPath, &[_]LazyPath{lp}) catch @panic("OOM"),
+ .list => |lst| {
+ const new_list = b.allocator.alloc(LazyPath, lst.items.len) catch @panic("OOM");
+ for (new_list, lst.items) |*new_item, str| {
+ new_item.* = .{ .cwd_relative = str };
+ }
+ return new_list;
+ },
+ .lazy_path_list => |lp_list| return lp_list.items,
+ .flag, .map => {
+ log.err("Expected -D{s} to be a path, but received a {s}.", .{
+ name, @tagName(option_ptr.value),
+ });
+ b.markInvalidUserInput();
+ return null;
+ },
+ },
}
}
@@ -1514,6 +1595,10 @@ pub fn addUserInputOption(b: *Build, name_raw: []const u8, value_raw: []const u8
log.warn("TODO maps as command line arguments is not implemented yet.", .{});
return true;
},
+ .lazy_path, .lazy_path_list => {
+ log.warn("the lazy path value type isn't added from the CLI, but somehow '{s}' is a .{}", .{ name, std.zig.fmtId(@tagName(gop.value_ptr.value)) });
+ return true;
+ },
}
return false;
}
@@ -1536,10 +1621,15 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) !bool {
log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, s });
return true;
},
- .list, .map => {
+ .list, .map, .lazy_path_list => {
log.err("Flag '-D{s}' conflicts with multiple options of the same name.", .{name});
return true;
},
+ .lazy_path => |lp| {
+ log.err("Flag '-D{s}' conflicts with option '-D{s}={s}'.", .{ name, name, lp.getDisplayName() });
+ return true;
+ },
+
.flag => {},
}
return false;
@@ -1548,6 +1638,7 @@ pub fn addUserInputFlag(b: *Build, name_raw: []const u8) !bool {
fn typeToEnum(comptime T: type) TypeId {
return switch (T) {
std.zig.BuildId => .build_id,
+ LazyPath => .lazy_path,
else => return switch (@typeInfo(T)) {
.int => .int,
.float => .float,
@@ -1556,6 +1647,7 @@ fn typeToEnum(comptime T: type) TypeId {
.pointer => |pointer| switch (pointer.child) {
u8 => .string,
[]const u8 => .list,
+ LazyPath => .lazy_path_list,
else => switch (@typeInfo(pointer.child)) {
.@"enum" => .enum_list,
else => @compileError("Unsupported type: " ++ @typeName(T)),
@@ -2071,22 +2163,17 @@ pub fn dependencyFromBuildZig(
}
fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
+ if (std.meta.activeTag(lhs) != rhs) return false;
switch (lhs) {
.flag => {},
.scalar => |lhs_scalar| {
- const rhs_scalar = switch (rhs) {
- .scalar => |scalar| scalar,
- else => return false,
- };
+ const rhs_scalar = rhs.scalar;
if (!std.mem.eql(u8, lhs_scalar, rhs_scalar))
return false;
},
.list => |lhs_list| {
- const rhs_list = switch (rhs) {
- .list => |list| list,
- else => return false,
- };
+ const rhs_list = rhs.list;
if (lhs_list.items.len != rhs_list.items.len)
return false;
@@ -2097,10 +2184,7 @@ fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
}
},
.map => |lhs_map| {
- const rhs_map = switch (rhs) {
- .map => |map| map,
- else => return false,
- };
+ const rhs_map = rhs.map;
if (lhs_map.count() != rhs_map.count())
return false;
@@ -2112,11 +2196,54 @@ fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
return false;
}
},
+ .lazy_path => |lhs_lp| {
+ const rhs_lp = rhs.lazy_path;
+ return userLazyPathsAreTheSame(lhs_lp, rhs_lp);
+ },
+ .lazy_path_list => |lhs_lp_list| {
+ const rhs_lp_list = rhs.lazy_path_list;
+ if (lhs_lp_list.items.len != rhs_lp_list.items.len) return false;
+ for (lhs_lp_list.items, rhs_lp_list.items) |lhs_lp, rhs_lp| {
+ if (!userLazyPathsAreTheSame(lhs_lp, rhs_lp)) return false;
+ }
+ return true;
+ },
}
return true;
}
+fn userLazyPathsAreTheSame(lhs_lp: LazyPath, rhs_lp: LazyPath) bool {
+ if (std.meta.activeTag(lhs_lp) != rhs_lp) return false;
+ switch (lhs_lp) {
+ .src_path => |lhs_sp| {
+ const rhs_sp = rhs_lp.src_path;
+
+ if (lhs_sp.owner != rhs_sp.owner) return false;
+ if (std.mem.eql(u8, lhs_sp.sub_path, rhs_sp.sub_path)) return false;
+ },
+ .generated => |lhs_gen| {
+ const rhs_gen = rhs_lp.generated;
+
+ if (lhs_gen.file != rhs_gen.file) return false;
+ if (lhs_gen.up != rhs_gen.up) return false;
+ if (std.mem.eql(u8, lhs_gen.sub_path, rhs_gen.sub_path)) return false;
+ },
+ .cwd_relative => |lhs_rel_path| {
+ const rhs_rel_path = rhs_lp.cwd_relative;
+
+ if (!std.mem.eql(u8, lhs_rel_path, rhs_rel_path)) return false;
+ },
+ .dependency => |lhs_dep| {
+ const rhs_dep = rhs_lp.dependency;
+
+ if (lhs_dep.dependency != rhs_dep.dependency) return false;
+ if (!std.mem.eql(u8, lhs_dep.sub_path, rhs_dep.sub_path)) return false;
+ },
+ }
+ return true;
+}
+
fn dependencyInner(
b: *Build,
name: []const u8,
@@ -2127,10 +2254,10 @@ fn dependencyInner(
args: anytype,
) *Dependency {
const user_input_options = userInputOptionsFromArgs(b.allocator, args);
- if (b.initialized_deps.get(.{
+ if (b.graph.dependency_cache.getContext(.{
.build_root_string = build_root_string,
.user_input_options = user_input_options,
- })) |dep|
+ }, .{ .allocator = b.graph.arena })) |dep|
return dep;
const build_root: std.Build.Cache.Directory = .{
@@ -2155,10 +2282,10 @@ fn dependencyInner(
const dep = b.allocator.create(Dependency) catch @panic("OOM");
dep.* = .{ .builder = sub_builder };
- b.initialized_deps.put(.{
+ b.graph.dependency_cache.putContext(b.graph.arena, .{
.build_root_string = build_root_string,
.user_input_options = user_input_options,
- }, dep) catch @panic("OOM");
+ }, dep, .{ .allocator = b.graph.arena }) catch @panic("OOM");
return dep;
}
@@ -2441,16 +2568,20 @@ pub const LazyPath = union(enum) {
/// The `b` parameter is only used for its allocator. All *Build instances
/// share the same allocator.
pub fn dupe(lazy_path: LazyPath, b: *Build) LazyPath {
+ return lazy_path.dupeInner(b.allocator);
+ }
+
+ fn dupeInner(lazy_path: LazyPath, allocator: std.mem.Allocator) LazyPath {
return switch (lazy_path) {
.src_path => |sp| .{ .src_path = .{
.owner = sp.owner,
.sub_path = sp.owner.dupePath(sp.sub_path),
} },
- .cwd_relative => |p| .{ .cwd_relative = b.dupePath(p) },
+ .cwd_relative => |p| .{ .cwd_relative = dupePathInner(allocator, p) },
.generated => |gen| .{ .generated = .{
.file = gen.file,
.up = gen.up,
- .sub_path = b.dupePath(gen.sub_path),
+ .sub_path = dupePathInner(allocator, gen.sub_path),
} },
.dependency => |dep| .{ .dependency = dep },
};
diff --git a/zig/lib/std/Build/Cache.zig b/zig/lib/std/Build/Cache.zig
index 93908807eb..53f1dcff29 100644
--- a/zig/lib/std/Build/Cache.zig
+++ b/zig/lib/std/Build/Cache.zig
@@ -398,12 +398,19 @@ pub const Manifest = struct {
return gop.index;
}
+ /// Deprecated, use `addOptionalFilePath`.
pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
self.hash.add(optional_file_path != null);
const file_path = optional_file_path orelse return;
_ = try self.addFile(file_path, null);
}
+ pub fn addOptionalFilePath(self: *Manifest, optional_file_path: ?Path) !void {
+ self.hash.add(optional_file_path != null);
+ const file_path = optional_file_path orelse return;
+ _ = try self.addFilePath(file_path, null);
+ }
+
pub fn addListOfFiles(self: *Manifest, list_of_files: []const []const u8) !void {
self.hash.add(list_of_files.len);
for (list_of_files) |file_path| {
diff --git a/zig/lib/std/Build/Cache/Path.zig b/zig/lib/std/Build/Cache/Path.zig
index ee0666b70a..a14c6cd7a4 100644
--- a/zig/lib/std/Build/Cache/Path.zig
+++ b/zig/lib/std/Build/Cache/Path.zig
@@ -11,7 +11,11 @@ pub fn clone(p: Path, arena: Allocator) Allocator.Error!Path {
}
pub fn cwd() Path {
- return .{ .root_dir = Cache.Directory.cwd() };
+ return initCwd("");
+}
+
+pub fn initCwd(sub_path: []const u8) Path {
+ return .{ .root_dir = Cache.Directory.cwd(), .sub_path = sub_path };
}
pub fn join(p: Path, arena: Allocator, sub_path: []const u8) Allocator.Error!Path {
@@ -126,6 +130,14 @@ pub fn makePath(p: Path, sub_path: []const u8) !void {
return p.root_dir.handle.makePath(joined_path);
}
+pub fn toString(p: Path, allocator: Allocator) Allocator.Error![]u8 {
+ return std.fmt.allocPrint(allocator, "{}", .{p});
+}
+
+pub fn toStringZ(p: Path, allocator: Allocator) Allocator.Error![:0]u8 {
+ return std.fmt.allocPrintZ(allocator, "{}", .{p});
+}
+
pub fn format(
self: Path,
comptime fmt_string: []const u8,
@@ -137,7 +149,7 @@ pub fn format(
const stringEscape = std.zig.stringEscape;
const f = switch (fmt_string[0]) {
'q' => "",
- '\'' => '\'',
+ '\'' => "\'",
else => @compileError("unsupported format string: " ++ fmt_string),
};
if (self.root_dir.path) |p| {
@@ -182,6 +194,14 @@ pub fn subPathOrDot(self: Path) []const u8 {
return if (self.sub_path.len == 0) "." else self.sub_path;
}
+pub fn stem(p: Path) []const u8 {
+ return fs.path.stem(p.sub_path);
+}
+
+pub fn basename(p: Path) []const u8 {
+ return fs.path.basename(p.sub_path);
+}
+
/// Useful to make `Path` a key in `std.ArrayHashMap`.
pub const TableAdapter = struct {
pub const Hash = std.hash.Wyhash;
diff --git a/zig/lib/std/Build/Module.zig b/zig/lib/std/Build/Module.zig
index 635e6cc334..253945b3d7 100644
--- a/zig/lib/std/Build/Module.zig
+++ b/zig/lib/std/Build/Module.zig
@@ -135,6 +135,44 @@ pub const IncludeDir = union(enum) {
framework_path_system: LazyPath,
other_step: *Step.Compile,
config_header_step: *Step.ConfigHeader,
+
+ pub fn appendZigProcessFlags(
+ include_dir: IncludeDir,
+ b: *std.Build,
+ zig_args: *std.ArrayList([]const u8),
+ asking_step: ?*Step,
+ ) !void {
+ switch (include_dir) {
+ .path => |include_path| {
+ try zig_args.appendSlice(&.{ "-I", include_path.getPath2(b, asking_step) });
+ },
+ .path_system => |include_path| {
+ try zig_args.appendSlice(&.{ "-isystem", include_path.getPath2(b, asking_step) });
+ },
+ .path_after => |include_path| {
+ try zig_args.appendSlice(&.{ "-idirafter", include_path.getPath2(b, asking_step) });
+ },
+ .framework_path => |include_path| {
+ try zig_args.appendSlice(&.{ "-F", include_path.getPath2(b, asking_step) });
+ },
+ .framework_path_system => |include_path| {
+ try zig_args.appendSlice(&.{ "-iframework", include_path.getPath2(b, asking_step) });
+ },
+ .other_step => |other| {
+ if (other.generated_h) |header| {
+ try zig_args.appendSlice(&.{ "-isystem", std.fs.path.dirname(header.getPath()).? });
+ }
+ if (other.installed_headers_include_tree) |include_tree| {
+ try zig_args.appendSlice(&.{ "-I", include_tree.generated_directory.getPath() });
+ }
+ },
+ .config_header_step => |config_header| {
+ const full_file_path = config_header.output_file.getPath();
+ const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
+ try zig_args.appendSlice(&.{ "-I", header_dir_path });
+ },
+ }
+ }
};
pub const LinkFrameworkOptions = struct {
@@ -690,36 +728,7 @@ pub fn appendZigProcessFlags(
}
for (m.include_dirs.items) |include_dir| {
- switch (include_dir) {
- .path => |include_path| {
- try zig_args.appendSlice(&.{ "-I", include_path.getPath2(b, asking_step) });
- },
- .path_system => |include_path| {
- try zig_args.appendSlice(&.{ "-isystem", include_path.getPath2(b, asking_step) });
- },
- .path_after => |include_path| {
- try zig_args.appendSlice(&.{ "-idirafter", include_path.getPath2(b, asking_step) });
- },
- .framework_path => |include_path| {
- try zig_args.appendSlice(&.{ "-F", include_path.getPath2(b, asking_step) });
- },
- .framework_path_system => |include_path| {
- try zig_args.appendSlice(&.{ "-iframework", include_path.getPath2(b, asking_step) });
- },
- .other_step => |other| {
- if (other.generated_h) |header| {
- try zig_args.appendSlice(&.{ "-isystem", std.fs.path.dirname(header.getPath()).? });
- }
- if (other.installed_headers_include_tree) |include_tree| {
- try zig_args.appendSlice(&.{ "-I", include_tree.generated_directory.getPath() });
- }
- },
- .config_header_step => |config_header| {
- const full_file_path = config_header.output_file.getPath();
- const header_dir_path = full_file_path[0 .. full_file_path.len - config_header.include_path.len];
- try zig_args.appendSlice(&.{ "-I", header_dir_path });
- },
- }
+ try include_dir.appendZigProcessFlags(b, zig_args, asking_step);
}
try zig_args.appendSlice(m.c_macros.items);
diff --git a/zig/lib/std/Build/Step/CheckObject.zig b/zig/lib/std/Build/Step/CheckObject.zig
index 54f7bc7412..00ea5013de 100644
--- a/zig/lib/std/Build/Step/CheckObject.zig
+++ b/zig/lib/std/Build/Step/CheckObject.zig
@@ -557,15 +557,15 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
const check_object: *CheckObject = @fieldParentPtr("step", step);
try step.singleUnchangingWatchInput(check_object.source);
- const src_path = check_object.source.getPath2(b, step);
- const contents = fs.cwd().readFileAllocOptions(
+ const src_path = check_object.source.getPath3(b, step);
+ const contents = src_path.root_dir.handle.readFileAllocOptions(
gpa,
- src_path,
+ src_path.sub_path,
check_object.max_bytes,
null,
@alignOf(u64),
null,
- ) catch |err| return step.fail("unable to read '{s}': {s}", .{ src_path, @errorName(err) });
+ ) catch |err| return step.fail("unable to read '{'}': {s}", .{ src_path, @errorName(err) });
var vars = std.StringHashMap(u64).init(gpa);
for (check_object.checks.items) |chk| {
@@ -640,8 +640,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
\\{s}
\\========= but parsed file does not contain it: =======
\\{s}
- \\======================================================
- , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
+ \\========= file path: =================================
+ \\{}
+ , .{
+ fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
+ fmtMessageString(chk.kind, output),
+ src_path,
+ });
}
},
@@ -655,8 +660,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
\\*{s}*
\\========= but parsed file does not contain it: =======
\\{s}
- \\======================================================
- , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
+ \\========= file path: =================================
+ \\{}
+ , .{
+ fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
+ fmtMessageString(chk.kind, output),
+ src_path,
+ });
}
},
@@ -669,8 +679,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
\\{s}
\\========= but parsed file does contain it: ========
\\{s}
- \\===================================================
- , .{ fmtMessageString(chk.kind, act.phrase.resolve(b, step)), fmtMessageString(chk.kind, output) });
+ \\========= file path: ==============================
+ \\{}
+ , .{
+ fmtMessageString(chk.kind, act.phrase.resolve(b, step)),
+ fmtMessageString(chk.kind, output),
+ src_path,
+ });
}
},
@@ -684,8 +699,13 @@ fn make(step: *Step, make_options: Step.MakeOptions) !void {
\\{s}
\\========= but parsed file does not contain it: =======
\\{s}
- \\======================================================
- , .{ act.phrase.resolve(b, step), fmtMessageString(chk.kind, output) });
+ \\========= file path: ==============================
+ \\{}
+ , .{
+ act.phrase.resolve(b, step),
+ fmtMessageString(chk.kind, output),
+ src_path,
+ });
}
},
diff --git a/zig/lib/std/Build/Step/Compile.zig b/zig/lib/std/Build/Step/Compile.zig
index 0f0b5d3201..a977dc3056 100644
--- a/zig/lib/std/Build/Step/Compile.zig
+++ b/zig/lib/std/Build/Step/Compile.zig
@@ -235,6 +235,7 @@ sanitize_coverage_trace_pc_guard: ?bool = null,
pub const ExpectedCompileErrors = union(enum) {
contains: []const u8,
exact: []const []const u8,
+ starts_with: []const u8,
};
pub const Entry = union(enum) {
@@ -1958,6 +1959,17 @@ fn checkCompileErrors(compile: *Compile) !void {
// TODO merge this with the testing.expectEqualStrings logic, and also CheckFile
switch (expect_errors) {
+ .starts_with => |expect_starts_with| {
+ if (std.mem.startsWith(u8, actual_stderr, expect_starts_with)) return;
+ return compile.step.fail(
+ \\
+ \\========= should start with: ============
+ \\{s}
+ \\========= but not found: ================
+ \\{s}
+ \\=========================================
+ , .{ expect_starts_with, actual_stderr });
+ },
.contains => |expect_line| {
while (actual_line_it.next()) |actual_line| {
if (!matchCompileError(actual_line, expect_line)) continue;
diff --git a/zig/lib/std/Build/Step/ObjCopy.zig b/zig/lib/std/Build/Step/ObjCopy.zig
index 6ed23d3fb4..8f0f62e222 100644
--- a/zig/lib/std/Build/Step/ObjCopy.zig
+++ b/zig/lib/std/Build/Step/ObjCopy.zig
@@ -26,6 +26,50 @@ pub const Strip = enum {
debug_and_symbols,
};
+pub const SectionFlags = packed struct {
+ /// add SHF_ALLOC
+ alloc: bool = false,
+
+ /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing
+ contents: bool = false,
+
+ /// if section is SHT_NOBITS, set SHT_PROGBITS, otherwise do nothing (same as contents)
+ load: bool = false,
+
+ /// readonly: clear default SHF_WRITE flag
+ readonly: bool = false,
+
+ /// add SHF_EXECINSTR
+ code: bool = false,
+
+ /// add SHF_EXCLUDE
+ exclude: bool = false,
+
+ /// add SHF_X86_64_LARGE. Fatal error if target is not x86_64
+ large: bool = false,
+
+ /// add SHF_MERGE
+ merge: bool = false,
+
+ /// add SHF_STRINGS
+ strings: bool = false,
+};
+
+pub const AddSection = struct {
+ section_name: []const u8,
+ file_path: std.Build.LazyPath,
+};
+
+pub const SetSectionAlignment = struct {
+ section_name: []const u8,
+ alignment: u32,
+};
+
+pub const SetSectionFlags = struct {
+ section_name: []const u8,
+ flags: SectionFlags,
+};
+
step: Step,
input_file: std.Build.LazyPath,
basename: []const u8,
@@ -38,6 +82,10 @@ pad_to: ?u64,
strip: Strip,
compress_debug: bool,
+add_section: ?AddSection,
+set_section_alignment: ?SetSectionAlignment,
+set_section_flags: ?SetSectionFlags,
+
pub const Options = struct {
basename: ?[]const u8 = null,
format: ?RawFormat = null,
@@ -51,6 +99,10 @@ pub const Options = struct {
/// note: the `basename` is baked into the elf file to specify the link to the separate debug file.
/// see https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
extract_to_separate_file: bool = false,
+
+ add_section: ?AddSection = null,
+ set_section_alignment: ?SetSectionAlignment = null,
+ set_section_flags: ?SetSectionFlags = null,
};
pub fn create(
@@ -75,6 +127,9 @@ pub fn create(
.pad_to = options.pad_to,
.strip = options.strip,
.compress_debug = options.compress_debug,
+ .add_section = options.add_section,
+ .set_section_alignment = options.set_section_alignment,
+ .set_section_flags = options.set_section_flags,
};
input_file.addStepDependencies(&objcopy.step);
return objcopy;
@@ -155,6 +210,31 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
if (objcopy.output_file_debug != null) {
try argv.appendSlice(&.{b.fmt("--extract-to={s}", .{full_dest_path_debug})});
}
+ if (objcopy.add_section) |section| {
+ try argv.append("--add-section");
+ try argv.appendSlice(&.{b.fmt("{s}={s}", .{ section.section_name, section.file_path.getPath(b) })});
+ }
+ if (objcopy.set_section_alignment) |set_align| {
+ try argv.append("--set-section-alignment");
+ try argv.appendSlice(&.{b.fmt("{s}={d}", .{ set_align.section_name, set_align.alignment })});
+ }
+ if (objcopy.set_section_flags) |set_flags| {
+ const f = set_flags.flags;
+ // trailing comma is allowed
+ try argv.append("--set-section-flags");
+ try argv.appendSlice(&.{b.fmt("{s}={s}{s}{s}{s}{s}{s}{s}{s}{s}", .{
+ set_flags.section_name,
+ if (f.alloc) "alloc," else "",
+ if (f.contents) "contents," else "",
+ if (f.load) "load," else "",
+ if (f.readonly) "readonly," else "",
+ if (f.code) "code," else "",
+ if (f.exclude) "exclude," else "",
+ if (f.large) "large," else "",
+ if (f.merge) "merge," else "",
+ if (f.strings) "strings," else "",
+ })});
+ }
try argv.appendSlice(&.{ full_src_path, full_dest_path });
diff --git a/zig/lib/std/Build/Step/TranslateC.zig b/zig/lib/std/Build/Step/TranslateC.zig
index 9ef5f7acdf..13f4375999 100644
--- a/zig/lib/std/Build/Step/TranslateC.zig
+++ b/zig/lib/std/Build/Step/TranslateC.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const Step = std.Build.Step;
+const LazyPath = std.Build.LazyPath;
const fs = std.fs;
const mem = std.mem;
@@ -9,7 +10,7 @@ pub const base_id: Step.Id = .translate_c;
step: Step,
source: std.Build.LazyPath,
-include_dirs: std.ArrayList([]const u8),
+include_dirs: std.ArrayList(std.Build.Module.IncludeDir),
c_macros: std.ArrayList([]const u8),
out_basename: []const u8,
target: std.Build.ResolvedTarget,
@@ -37,7 +38,7 @@ pub fn create(owner: *std.Build, options: Options) *TranslateC {
.makeFn = make,
}),
.source = source,
- .include_dirs = std.ArrayList([]const u8).init(owner.allocator),
+ .include_dirs = std.ArrayList(std.Build.Module.IncludeDir).init(owner.allocator),
.c_macros = std.ArrayList([]const u8).init(owner.allocator),
.out_basename = undefined,
.target = options.target,
@@ -95,8 +96,45 @@ pub fn createModule(translate_c: *TranslateC) *std.Build.Module {
});
}
-pub fn addIncludeDir(translate_c: *TranslateC, include_dir: []const u8) void {
- translate_c.include_dirs.append(translate_c.step.owner.dupePath(include_dir)) catch @panic("OOM");
+pub fn addAfterIncludePath(translate_c: *TranslateC, lazy_path: LazyPath) void {
+ const b = translate_c.step.owner;
+ translate_c.include_dirs.append(.{ .path_after = lazy_path.dupe(b) }) catch
+ @panic("OOM");
+ lazy_path.addStepDependencies(&translate_c.step);
+}
+
+pub fn addSystemIncludePath(translate_c: *TranslateC, lazy_path: LazyPath) void {
+ const b = translate_c.step.owner;
+ translate_c.include_dirs.append(.{ .path_system = lazy_path.dupe(b) }) catch
+ @panic("OOM");
+ lazy_path.addStepDependencies(&translate_c.step);
+}
+
+pub fn addIncludePath(translate_c: *TranslateC, lazy_path: LazyPath) void {
+ const b = translate_c.step.owner;
+ translate_c.include_dirs.append(.{ .path = lazy_path.dupe(b) }) catch
+ @panic("OOM");
+ lazy_path.addStepDependencies(&translate_c.step);
+}
+
+pub fn addConfigHeader(translate_c: *TranslateC, config_header: *Step.ConfigHeader) void {
+ translate_c.include_dirs.append(.{ .config_header_step = config_header }) catch
+ @panic("OOM");
+ translate_c.step.dependOn(&config_header.step);
+}
+
+pub fn addSystemFrameworkPath(translate_c: *TranslateC, directory_path: LazyPath) void {
+ const b = translate_c.step.owner;
+ translate_c.include_dirs.append(.{ .framework_path_system = directory_path.dupe(b) }) catch
+ @panic("OOM");
+ directory_path.addStepDependencies(&translate_c.step);
+}
+
+pub fn addFrameworkPath(translate_c: *TranslateC, directory_path: LazyPath) void {
+ const b = translate_c.step.owner;
+ translate_c.include_dirs.append(.{ .framework_path = directory_path.dupe(b) }) catch
+ @panic("OOM");
+ directory_path.addStepDependencies(&translate_c.step);
}
pub fn addCheckFile(translate_c: *TranslateC, expected_matches: []const []const u8) *Step.CheckFile {
@@ -147,8 +185,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
}
for (translate_c.include_dirs.items) |include_dir| {
- try argv_list.append("-I");
- try argv_list.append(include_dir);
+ try include_dir.appendZigProcessFlags(b, &argv_list, step);
}
for (translate_c.c_macros.items) |c_macro| {
diff --git a/zig/lib/std/Build/Watch.zig b/zig/lib/std/Build/Watch.zig
index c1a9e80b8e..c8f6c0d64f 100644
--- a/zig/lib/std/Build/Watch.zig
+++ b/zig/lib/std/Build/Watch.zig
@@ -516,7 +516,7 @@ const Os = switch (builtin.os.tag) {
pub fn init() !Watch {
switch (builtin.os.tag) {
.linux => {
- const fan_fd = try std.posix.fanotify_init(.{
+ const fan_fd = std.posix.fanotify_init(.{
.CLASS = .NOTIF,
.CLOEXEC = true,
.NONBLOCK = true,
@@ -524,7 +524,10 @@ pub fn init() !Watch {
.REPORT_DIR_FID = true,
.REPORT_FID = true,
.REPORT_TARGET_FID = true,
- }, 0);
+ }, 0) catch |err| switch (err) {
+ error.UnsupportedFlags => fatal("fanotify_init failed due to old kernel; requires 5.17+", .{}),
+ else => |e| return e,
+ };
return .{
.dir_table = .{},
.os = switch (builtin.os.tag) {
diff --git a/zig/lib/std/Target.zig b/zig/lib/std/Target.zig
index 58fbaab8b1..efe8ad4809 100644
--- a/zig/lib/std/Target.zig
+++ b/zig/lib/std/Target.zig
@@ -66,13 +66,13 @@ pub const Os = struct {
nvcl,
opencl,
opengl,
- shadermodel,
vulkan,
// LLVM tags deliberately omitted:
// - darwin
// - kfreebsd
// - nacl
+ // - shadermodel
pub inline fn isDarwin(tag: Tag) bool {
return switch (tag) {
@@ -113,7 +113,7 @@ pub const Os = struct {
pub fn staticLibSuffix(tag: Tag, abi: Abi) [:0]const u8 {
return switch (abi) {
- .msvc => ".lib",
+ .msvc, .itanium => ".lib",
else => switch (tag) {
.windows, .uefi => ".lib",
else => ".a",
@@ -138,7 +138,7 @@ pub const Os = struct {
pub fn libPrefix(tag: Os.Tag, abi: Abi) [:0]const u8 {
return switch (abi) {
- .msvc => "",
+ .msvc, .itanium => "",
else => switch (tag) {
.windows, .uefi => "",
else => "lib",
@@ -178,7 +178,6 @@ pub const Os = struct {
.hermit,
.hurd,
.emscripten,
- .shadermodel,
.uefi,
.opencl, // TODO: OpenCL versions
.opengl, // TODO: GLSL versions
@@ -189,7 +188,9 @@ pub const Os = struct {
.other,
=> .none,
- .bridgeos,
+ // This should use semver once we determine the version history.
+ .bridgeos => .none,
+
.driverkit,
.freebsd,
.macos,
@@ -408,7 +409,6 @@ pub const Os = struct {
.hermit,
.hurd,
.emscripten,
- .shadermodel,
.uefi,
.opencl, // TODO: OpenCL versions
.opengl, // TODO: GLSL versions
@@ -613,7 +613,6 @@ pub const Os = struct {
.hurd,
.wasi,
.emscripten,
- .shadermodel,
.uefi,
.opencl,
.opengl,
@@ -633,6 +632,7 @@ pub const avr = @import("Target/avr.zig");
pub const bpf = @import("Target/bpf.zig");
pub const csky = @import("Target/csky.zig");
pub const hexagon = @import("Target/hexagon.zig");
+pub const lanai = @import("Target/lanai.zig");
pub const loongarch = @import("Target/loongarch.zig");
pub const m68k = @import("Target/m68k.zig");
pub const mips = @import("Target/mips.zig");
@@ -646,7 +646,9 @@ pub const s390x = @import("Target/s390x.zig");
pub const ve = @import("Target/ve.zig");
pub const wasm = @import("Target/wasm.zig");
pub const x86 = @import("Target/x86.zig");
+pub const xcore = @import("Target/xcore.zig");
pub const xtensa = @import("Target/xtensa.zig");
+pub const propeller = @import("Target/propeller.zig");
pub const Abi = enum {
none,
@@ -664,6 +666,7 @@ pub const Abi = enum {
eabihf,
ilp32,
android,
+ androideabi,
musl,
musleabi,
musleabihf,
@@ -673,75 +676,136 @@ pub const Abi = enum {
cygnus,
simulator,
macabi,
- pixel,
- vertex,
- geometry,
- hull,
- domain,
- compute,
- library,
- raygeneration,
- intersection,
- anyhit,
- closesthit,
- miss,
- callable,
- mesh,
- amplification,
ohos,
+ ohoseabi,
// LLVM tags deliberately omitted:
- // - gnuf64
+ // - amplification
+ // - anyhit
+ // - callable
+ // - closesthit
+ // - compute
// - coreclr
+ // - domain
+ // - geometry
+ // - gnuf64
+ // - hull
+ // - intersection
+ // - library
+ // - mesh
+ // - miss
+ // - pixel
+ // - raygeneration
+ // - vertex
pub fn default(arch: Cpu.Arch, os: Os) Abi {
return if (arch.isWasm()) .musl else switch (os.tag) {
.freestanding,
- .dragonfly,
- .ps3,
- .zos,
- .rtems,
- .aix,
- .cuda,
- .nvcl,
- .amdhsa,
- .ps4,
- .ps5,
- .elfiamcu,
- .mesa3d,
- .contiki,
- .amdpal,
- .hermit,
.other,
- => .eabi,
- .openbsd,
- .freebsd,
- .fuchsia,
- .netbsd,
- .hurd,
- .haiku,
- .windows,
- => .gnu,
- .uefi => .msvc,
+ => switch (arch) {
+ // Soft float is usually a sane default for freestanding.
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .csky,
+ .mips,
+ .mipsel,
+ .powerpc,
+ .powerpcle,
+ => .eabi,
+ else => .none,
+ },
+ .aix,
+ => if (arch == .powerpc) .eabihf else .none,
.linux,
.wasi,
.emscripten,
=> .musl,
- .bridgeos,
- .opencl,
- .opengl,
- .vulkan,
- .plan9, // TODO specify abi
- .macos,
+ .rtems,
+ => switch (arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .mips,
+ .mipsel,
+ => .eabi,
+ .powerpc,
+ => .eabihf,
+ else => .none,
+ },
+ .hurd,
+ .windows,
+ => .gnu,
+ .freebsd,
+ => switch (arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .powerpc,
+ => .eabihf,
+ .mips,
+ .mipsel,
+ => .eabi,
+ else => .none,
+ },
+ .netbsd,
+ => switch (arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .powerpc,
+ => .eabihf,
+ .mips,
+ .mipsel,
+ => .eabi,
+ else => .none,
+ },
+ .openbsd,
+ => switch (arch) {
+ .arm,
+ .thumb,
+ => .eabi,
+ .powerpc,
+ => .eabihf,
+ else => .none,
+ },
.ios,
+ => if (arch == .x86_64) .macabi else .none,
.tvos,
- .watchos,
.visionos,
+ => if (arch == .x86_64) .simulator else .none,
+ .uefi,
+ => .msvc,
+ .contiki,
+ .elfiamcu,
+ .fuchsia,
+ .hermit,
+ .haiku,
+ .plan9,
+ .serenity,
+ .zos,
+ .dragonfly,
+ .bridgeos,
.driverkit,
- .shadermodel,
- .solaris,
+ .macos,
+ .watchos,
.illumos,
- .serenity,
+ .solaris,
+ .ps3,
+ .ps4,
+ .ps5,
+ .amdhsa,
+ .amdpal,
+ .cuda,
+ .mesa3d,
+ .nvcl,
+ .opencl,
+ .opengl,
+ .vulkan,
=> .none,
};
}
@@ -764,19 +828,37 @@ pub const Abi = enum {
pub inline fn isMusl(abi: Abi) bool {
return switch (abi) {
- .musl, .musleabi, .musleabihf, .muslx32 => true,
- .ohos => true,
+ .musl,
+ .musleabi,
+ .musleabihf,
+ .muslx32,
+ => true,
+ else => abi.isOpenHarmony(),
+ };
+ }
+
+ pub inline fn isOpenHarmony(abi: Abi) bool {
+ return switch (abi) {
+ .ohos, .ohoseabi => true,
+ else => false,
+ };
+ }
+
+ pub inline fn isAndroid(abi: Abi) bool {
+ return switch (abi) {
+ .android, .androideabi => true,
else => false,
};
}
pub inline fn floatAbi(abi: Abi) FloatAbi {
return switch (abi) {
+ .androideabi,
.eabi,
.gnueabi,
.musleabi,
.gnusf,
- .ohos,
+ .ohoseabi,
=> .soft,
else => .hard,
};
@@ -788,8 +870,6 @@ pub const ObjectFormat = enum {
c,
/// The Common Object File Format used by Windows and UEFI.
coff,
- /// The DirectX Container format containing either DXIL or DXBC.
- dxcontainer,
/// The Executable and Linkable Format used by many Unixes.
elf,
/// The Generalized Object File Format used by z/OS.
@@ -811,11 +891,13 @@ pub const ObjectFormat = enum {
/// The eXtended Common Object File Format used by AIX.
xcoff,
+ // LLVM tags deliberately omitted:
+ // - dxcontainer
+
pub fn fileExt(of: ObjectFormat, arch: Cpu.Arch) [:0]const u8 {
return switch (of) {
.c => ".c",
.coff => ".obj",
- .dxcontainer => ".dxil",
.elf, .goff, .macho, .wasm, .xcoff => ".o",
.hex => ".ihex",
.nvptx => ".ptx",
@@ -833,7 +915,6 @@ pub const ObjectFormat = enum {
.uefi, .windows => .coff,
.zos => .goff,
else => switch (arch) {
- .dxil => .dxcontainer,
.nvptx, .nvptx64 => .nvptx,
.spirv, .spirv32, .spirv64 => .spirv,
.wasm32, .wasm64 => .wasm,
@@ -848,7 +929,7 @@ pub fn toElfMachine(target: Target) std.elf.EM {
return switch (target.cpu.arch) {
.amdgcn => .AMDGPU,
- .arc => .ARC_COMPACT2,
+ .arc => .ARC_COMPACT,
.arm, .armeb, .thumb, .thumbeb => .ARM,
.aarch64, .aarch64_be => .AARCH64,
.avr => .AVR,
@@ -868,18 +949,20 @@ pub fn toElfMachine(target: Target) std.elf.EM {
.sparc => if (Target.sparc.featureSetHas(target.cpu.features, .v9)) .SPARC32PLUS else .SPARC,
.sparc64 => .SPARCV9,
.spu_2 => .SPU_2,
+ .ve => .VE,
.x86 => .@"386",
.x86_64 => .X86_64,
.xcore => .XCORE,
.xtensa => .XTENSA,
- .dxil,
+ .propeller1 => .PROPELLER,
+ .propeller2 => .PROPELLER2,
+
.nvptx,
.nvptx64,
.spirv,
.spirv32,
.spirv64,
- .ve,
.wasm32,
.wasm64,
=> .NONE,
@@ -907,7 +990,6 @@ pub fn toCoffMachine(target: Target) std.coff.MachineType {
.bpfel,
.bpfeb,
.csky,
- .dxil,
.hexagon,
.kalimba,
.lanai,
@@ -935,6 +1017,8 @@ pub fn toCoffMachine(target: Target) std.coff.MachineType {
.wasm64,
.xcore,
.xtensa,
+ .propeller1,
+ .propeller2,
=> .UNKNOWN,
};
}
@@ -1133,7 +1217,6 @@ pub const Cpu = struct {
bpfel,
bpfeb,
csky,
- dxil,
hexagon,
kalimba,
lanai,
@@ -1151,6 +1234,8 @@ pub const Cpu = struct {
powerpcle,
powerpc64,
powerpc64le,
+ propeller1,
+ propeller2,
riscv32,
riscv64,
s390x,
@@ -1172,6 +1257,7 @@ pub const Cpu = struct {
// - aarch64_32
// - amdil
// - amdil64
+ // - dxil
// - le32
// - le64
// - r600
@@ -1303,6 +1389,14 @@ pub const Cpu = struct {
};
}
+ /// Returns if the architecture is a Parallax propeller architecture.
+ pub inline fn isPropeller(arch: Arch) bool {
+ return switch (arch) {
+ .propeller1, .propeller2 => true,
+ else => false,
+ };
+ }
+
pub fn parseCpuModel(arch: Arch, cpu_name: []const u8) !*const Cpu.Model {
for (arch.allCpuModels()) |cpu| {
if (std.mem.eql(u8, cpu_name, cpu.name)) {
@@ -1344,10 +1438,11 @@ pub const Cpu = struct {
.spirv,
.spirv32,
.spirv64,
- .dxil,
.loongarch32,
.loongarch64,
.arc,
+ .propeller1,
+ .propeller2,
=> .little,
.armeb,
@@ -1380,6 +1475,10 @@ pub const Cpu = struct {
.input, .output, .uniform => is_spirv,
// TODO this should also check how many flash banks the cpu has
.flash, .flash1, .flash2, .flash3, .flash4, .flash5 => arch == .avr,
+
+ // Propeller address spaces:
+ .cog, .hub => arch.isPropeller(),
+ .lut => (arch == .propeller2),
};
}
@@ -1400,6 +1499,7 @@ pub const Cpu = struct {
.nvptx, .nvptx64 => "nvptx",
.wasm32, .wasm64 => "wasm",
.spirv, .spirv32, .spirv64 => "spirv",
+ .propeller1, .propeller2 => "propeller",
else => @tagName(arch),
};
}
@@ -1414,6 +1514,7 @@ pub const Cpu = struct {
.bpfel, .bpfeb => &bpf.all_features,
.csky => &csky.all_features,
.hexagon => &hexagon.all_features,
+ .lanai => &lanai.all_features,
.loongarch32, .loongarch64 => &loongarch.all_features,
.m68k => &m68k.all_features,
.mips, .mipsel, .mips64, .mips64el => &mips.all_features,
@@ -1425,6 +1526,7 @@ pub const Cpu = struct {
.spirv, .spirv32, .spirv64 => &spirv.all_features,
.s390x => &s390x.all_features,
.x86, .x86_64 => &x86.all_features,
+ .xcore => &xcore.all_features,
.xtensa => &xtensa.all_features,
.nvptx, .nvptx64 => &nvptx.all_features,
.ve => &ve.all_features,
@@ -1444,6 +1546,7 @@ pub const Cpu = struct {
.bpfel, .bpfeb => comptime allCpusFromDecls(bpf.cpu),
.csky => comptime allCpusFromDecls(csky.cpu),
.hexagon => comptime allCpusFromDecls(hexagon.cpu),
+ .lanai => comptime allCpusFromDecls(lanai.cpu),
.loongarch32, .loongarch64 => comptime allCpusFromDecls(loongarch.cpu),
.m68k => comptime allCpusFromDecls(m68k.cpu),
.mips, .mipsel, .mips64, .mips64el => comptime allCpusFromDecls(mips.cpu),
@@ -1455,6 +1558,7 @@ pub const Cpu = struct {
.spirv, .spirv32, .spirv64 => comptime allCpusFromDecls(spirv.cpu),
.s390x => comptime allCpusFromDecls(s390x.cpu),
.x86, .x86_64 => comptime allCpusFromDecls(x86.cpu),
+ .xcore => comptime allCpusFromDecls(xcore.cpu),
.xtensa => comptime allCpusFromDecls(xtensa.cpu),
.nvptx, .nvptx64 => comptime allCpusFromDecls(nvptx.cpu),
.ve => comptime allCpusFromDecls(ve.cpu),
@@ -1524,11 +1628,14 @@ pub const Cpu = struct {
};
};
return switch (arch) {
+ .arc => &arc.cpu.generic,
.arm, .armeb, .thumb, .thumbeb => &arm.cpu.generic,
.aarch64, .aarch64_be => &aarch64.cpu.generic,
.avr => &avr.cpu.avr2,
.bpfel, .bpfeb => &bpf.cpu.generic,
+ .csky => &csky.cpu.generic,
.hexagon => &hexagon.cpu.generic,
+ .lanai => &lanai.cpu.generic,
.loongarch32 => &loongarch.cpu.generic_la32,
.loongarch64 => &loongarch.cpu.generic_la64,
.m68k => &m68k.cpu.generic,
@@ -1539,6 +1646,8 @@ pub const Cpu = struct {
.powerpcle => &powerpc.cpu.ppc,
.powerpc64 => &powerpc.cpu.ppc64,
.powerpc64le => &powerpc.cpu.ppc64le,
+ .propeller1 => &propeller.cpu.generic,
+ .propeller2 => &propeller.cpu.generic,
.amdgcn => &amdgpu.cpu.generic,
.riscv32 => &riscv.cpu.generic_rv32,
.riscv64 => &riscv.cpu.generic_rv64,
@@ -1551,8 +1660,12 @@ pub const Cpu = struct {
.nvptx, .nvptx64 => &nvptx.cpu.sm_20,
.ve => &ve.cpu.generic,
.wasm32, .wasm64 => &wasm.cpu.generic,
+ .xcore => &xcore.cpu.generic,
+ .xtensa => &xtensa.cpu.generic,
- else => &S.generic_model,
+ .kalimba,
+ .spu_2,
+ => &S.generic_model,
};
}
@@ -1621,7 +1734,7 @@ pub inline fn isMusl(target: Target) bool {
}
pub inline fn isAndroid(target: Target) bool {
- return target.abi == .android;
+ return target.abi.isAndroid();
}
pub inline fn isWasm(target: Target) bool {
@@ -1727,156 +1840,332 @@ pub const DynamicLinker = struct {
return std.mem.eql(u8, lhs.buffer[0..lhs.len], rhs.buffer[0..rhs.len]);
}
- pub fn standard(cpu: Cpu, os_tag: Os.Tag, abi: Abi) DynamicLinker {
- return if (abi == .android) initFmt("/system/bin/linker{s}", .{
- if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else "",
- }) catch unreachable else if (abi.isMusl()) return initFmt("/lib/ld-musl-{s}{s}.so.1", .{
- @tagName(switch (cpu.arch) {
- .thumb => .arm,
- .thumbeb => .armeb,
- else => cpu.arch,
- }),
- if (cpu.arch.isArmOrThumb() and abi.floatAbi() == .hard) "hf" else "",
- }) catch unreachable else switch (os_tag) {
- .freebsd => init("/libexec/ld-elf.so.1"),
- .netbsd => init("/libexec/ld.elf_so"),
- .openbsd => init("/usr/libexec/ld.so"),
- .dragonfly => init("/libexec/ld-elf.so.2"),
- .solaris, .illumos => init("/lib/64/ld.so.1"),
- .linux => switch (cpu.arch) {
- .x86,
- .sparc,
- => init("/lib/ld-linux.so.2"),
+ pub fn standard(cpu: Cpu, os: Os, abi: Abi) DynamicLinker {
+ return switch (os.tag) {
+ .fuchsia => init("ld.so.1"), // Fuchsia is unusual in that `DT_INTERP` is just a basename.
+
+ .haiku => init("/system/runtime_loader"),
+
+ .hurd => switch (cpu.arch) {
+ .aarch64,
+ .aarch64_be,
+ => |arch| initFmt("/lib/ld-{s}{s}.so.1", .{
+ @tagName(arch),
+ if (abi == .gnuilp32) "_ilp32" else "",
+ }),
- .aarch64 => init("/lib/ld-linux-aarch64.so.1"),
- .aarch64_be => init("/lib/ld-linux-aarch64_be.so.1"),
+ .x86 => init("/lib/ld.so.1"),
+ .x86_64 => initFmt("/lib/ld-{s}.so.1", .{if (abi == .gnux32) "x32" else "x86-64"}),
+ // These are unsupported by Hurd/glibc.
+ .amdgcn,
+ .arc,
.arm,
.armeb,
.thumb,
.thumbeb,
- => initFmt("/lib/ld-linux{s}.so.3", .{switch (abi.floatAbi()) {
- .hard => "-armhf",
- else => "",
- }}) catch unreachable,
-
- .loongarch64 => init("/lib64/ld-linux-loongarch-lp64d.so.1"),
-
+ .avr,
+ .bpfel,
+ .bpfeb,
+ .csky,
+ .hexagon,
+ .kalimba,
+ .lanai,
+ .loongarch32,
+ .loongarch64,
+ .m68k,
.mips,
.mipsel,
.mips64,
.mips64el,
- => initFmt("/lib{s}/{s}", .{
- switch (abi) {
- .gnuabin32, .gnux32 => "32",
- .gnuabi64 => "64",
- else => "",
- },
- if (mips.featureSetHas(cpu.features, .nan2008))
- "ld-linux-mipsn8.so.1"
- else
- "ld.so.1",
- }) catch unreachable,
-
- .powerpc, .powerpcle => init("/lib/ld.so.1"),
- .powerpc64, .powerpc64le => init("/lib64/ld64.so.2"),
- .s390x => init("/lib64/ld64.so.1"),
- .sparc64 => init("/lib64/ld-linux.so.2"),
- .x86_64 => init(switch (abi) {
- .gnux32 => "/libx32/ld-linux-x32.so.2",
- else => "/lib64/ld-linux-x86-64.so.2",
- }),
-
- .riscv32 => init("/lib/ld-linux-riscv32-ilp32d.so.1"),
- .riscv64 => init("/lib/ld-linux-riscv64-lp64d.so.1"),
-
- // Architectures in this list have been verified as not having a standard
- // dynamic linker path.
- .wasm32,
- .wasm64,
- .bpfel,
- .bpfeb,
+ .msp430,
.nvptx,
.nvptx64,
- .spu_2,
- .avr,
+ .powerpc,
+ .powerpcle,
+ .powerpc64,
+ .powerpc64le,
+ .propeller1,
+ .propeller2,
+ .riscv32,
+ .riscv64,
+ .s390x,
+ .sparc,
+ .sparc64,
.spirv,
.spirv32,
.spirv64,
- => none,
-
- // TODO go over each item in this list and either move it to the above list, or
- // implement the standard dynamic linker path code for it.
- .arc,
- .csky,
- .hexagon,
- .m68k,
- .msp430,
- .amdgcn,
- .xcore,
- .kalimba,
- .lanai,
+ .spu_2,
.ve,
- .dxil,
- .loongarch32,
+ .wasm32,
+ .wasm64,
+ .xcore,
.xtensa,
=> none,
},
+ .linux => if (abi.isAndroid())
+ initFmt("/system/bin/linker{s}", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64" else ""})
+ else if (abi.isMusl())
+ switch (cpu.arch) {
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ .aarch64,
+ .aarch64_be,
+ .loongarch64,
+ .m68k,
+ .powerpc,
+ .powerpc64,
+ .powerpc64le,
+ .riscv32,
+ .riscv64,
+ .s390x,
+ .x86,
+ .x86_64,
+ => |arch| initFmt("/lib/ld-musl-{s}{s}.so.1", .{
+ switch (arch) {
+ .thumb => "arm",
+ .thumbeb => "armeb",
+ .x86 => "i386",
+ .x86_64 => if (abi == .muslx32) "x32" else "x86_64",
+ else => @tagName(arch),
+ },
+ switch (arch) {
+ .arm, .armeb, .thumb, .thumbeb => if (abi.floatAbi() == .hard) "hf" else "",
+ .aarch64, .aarch64_be => if (abi == .gnuilp32) "_ilp32" else "",
+ .riscv32, .riscv64 => if (std.Target.riscv.featureSetHas(cpu.features, .d))
+ ""
+ else if (std.Target.riscv.featureSetHas(cpu.features, .f))
+ "-sp"
+ else
+ "-sf",
+ else => if (abi.floatAbi() == .soft) "-sf" else "",
+ },
+ }),
+
+ // The naming scheme for MIPS is a bit irregular.
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ => |arch| initFmt("/lib/ld-musl-mips{s}{s}{s}{s}.so.1", .{
+ if (arch.isMIPS64()) "64" else "", // TODO: `n32` ABI support in LLVM 20.
+ if (mips.featureSetHas(cpu.features, if (arch.isMIPS64()) .mips64r6 else .mips32r6)) "r6" else "",
+ if (arch.endian() == .little) "el" else "",
+ if (abi.floatAbi() == .soft) "-sf" else "",
+ }),
+
+ // These are unsupported by musl.
+ .amdgcn,
+ .arc,
+ .avr,
+ .csky,
+ .bpfel,
+ .bpfeb,
+ .hexagon,
+ .kalimba,
+ .lanai,
+ .loongarch32,
+ .msp430,
+ .nvptx,
+ .nvptx64,
+ .powerpcle,
+ .propeller1,
+ .propeller2,
+ .sparc,
+ .sparc64,
+ .spirv,
+ .spirv32,
+ .spirv64,
+ .spu_2,
+ .ve,
+ .wasm32,
+ .wasm64,
+ .xcore,
+ .xtensa,
+ => none,
+ }
+ else if (abi.isGnu())
+ switch (cpu.arch) {
+ // TODO: `eb` architecture support.
+ // TODO: `700` ABI support.
+ .arc => init("/lib/ld-linux-arc.so.2"),
+
+ // TODO: OABI support (`/lib/ld-linux.so.2`).
+ .arm,
+ .armeb,
+ .thumb,
+ .thumbeb,
+ => initFmt("/lib/ld-linux{s}.so.3", .{if (abi.floatAbi() == .hard) "-armhf" else ""}),
+
+ .aarch64,
+ .aarch64_be,
+ => |arch| initFmt("/lib/ld-linux-{s}{s}.so.1", .{
+ @tagName(arch),
+ if (abi == .gnuilp32) "_ilp32" else "",
+ }),
+
+ // TODO: `-be` architecture support.
+ .csky => initFmt("/lib/ld-linux-cskyv2{s}.so.1", .{if (abi.floatAbi() == .hard) "-hf" else ""}),
+
+ .loongarch64 => initFmt("/lib64/ld-linux-loongarch-{s}.so.1", .{switch (abi) {
+ .gnuf32 => "lp64f",
+ .gnusf => "lp64s",
+ else => "lp64d",
+ }}),
+
+ .m68k => init("/lib/ld.so.1"),
+
+ .mips,
+ .mipsel,
+ .mips64,
+ .mips64el,
+ => initFmt("/lib{s}/ld{s}.so.1", .{
+ switch (abi) {
+ .gnuabin32 => "32",
+ .gnuabi64 => "64",
+ else => "",
+ },
+ if (mips.featureSetHas(cpu.features, .nan2008)) "-linux-mipsn8" else "",
+ }),
+
+ .powerpc => init("/lib/ld.so.1"),
+ // TODO: ELFv2 ABI opt-in support.
+ .powerpc64 => init("/lib64/ld64.so.1"),
+ .powerpc64le => init("/lib64/ld64.so.2"),
+
+ .riscv32,
+ .riscv64,
+ => |arch| initFmt("/lib/ld-linux-{s}-{s}{s}.so.1", .{
+ @tagName(arch),
+ switch (arch) {
+ .riscv32 => "ilp32",
+ .riscv64 => "lp64",
+ else => unreachable,
+ },
+ if (riscv.featureSetHas(cpu.features, .d))
+ "d"
+ else if (riscv.featureSetHas(cpu.features, .f))
+ "f"
+ else
+ "",
+ }),
+
+ .s390x => init("/lib/ld64.so.1"),
+
+ .sparc => init("/lib/ld-linux.so.2"),
+ .sparc64 => init("/lib64/ld-linux.so.2"),
+
+ .x86 => init("/lib/ld-linux.so.2"),
+ .x86_64 => init(if (abi == .gnux32) "/libx32/ld-linux-x32.so.2" else "/lib64/ld-linux-x86-64.so.2"),
+
+ .xtensa => init("/lib/ld.so.1"),
+
+ // These are unsupported by glibc.
+ .amdgcn,
+ .avr,
+ .bpfeb,
+ .bpfel,
+ .hexagon,
+ .kalimba,
+ .lanai,
+ .loongarch32,
+ .msp430,
+ .nvptx,
+ .nvptx64,
+ .powerpcle,
+ .propeller1,
+ .propeller2,
+ .spirv,
+ .spirv32,
+ .spirv64,
+ .spu_2,
+ .ve,
+ .wasm32,
+ .wasm64,
+ .xcore,
+ => none,
+ }
+ else
+ none, // Not a known Linux libc.
+
+ .serenity => init("/usr/lib/Loader.so"),
+
+ .dragonfly => initFmt("{s}/libexec/ld-elf.so.2", .{
+ if (os.version_range.semver.isAtLeast(.{ .major = 3, .minor = 8, .patch = 0 }) orelse false)
+ ""
+ else
+ "/usr",
+ }),
+
+ .freebsd => initFmt("{s}/libexec/ld-elf.so.1", .{
+ if (os.version_range.semver.isAtLeast(.{ .major = 6, .minor = 0, .patch = 0 }) orelse false)
+ ""
+ else
+ "/usr",
+ }),
+
+ .netbsd => init("/libexec/ld.elf_so"),
+
+ .openbsd => init("/usr/libexec/ld.so"),
+
.bridgeos,
.driverkit,
.ios,
- .tvos,
- .watchos,
.macos,
+ .tvos,
.visionos,
+ .watchos,
=> init("/usr/lib/dyld"),
- .serenity => init("/usr/lib/Loader.so"),
+ .illumos,
+ .solaris,
+ => initFmt("/lib/{s}ld.so.1", .{if (ptrBitWidth_cpu_abi(cpu, abi) == 64) "64/" else ""}),
// Operating systems in this list have been verified as not having a standard
// dynamic linker path.
.freestanding,
+ .other,
+
+ .contiki,
+ .elfiamcu,
+ .hermit,
+
+ .aix,
+ .plan9,
+ .rtems,
+ .zos,
+
.uefi,
.windows,
+
.emscripten,
.wasi,
+
+ .amdhsa,
+ .amdpal,
+ .cuda,
+ .mesa3d,
+ .nvcl,
.opencl,
.opengl,
.vulkan,
- .other,
- .plan9,
=> none,
- // TODO revisit when multi-arch for Haiku is available
- .haiku => init("/system/runtime_loader"),
-
// TODO go over each item in this list and either move it to the above list, or
// implement the standard dynamic linker path code for it.
- .fuchsia,
.ps3,
- .zos,
- .rtems,
- .aix,
- .cuda,
- .nvcl,
- .amdhsa,
.ps4,
.ps5,
- .elfiamcu,
- .mesa3d,
- .contiki,
- .amdpal,
- .hermit,
- .hurd,
- .shadermodel,
=> none,
- };
+ } catch unreachable;
}
};
pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
- return DynamicLinker.standard(target.cpu, target.os.tag, target.abi);
+ return DynamicLinker.standard(target.cpu, target.os, target.abi);
}
pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
@@ -1913,8 +2202,9 @@ pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
.sparc,
.spirv32,
.loongarch32,
- .dxil,
.xtensa,
+ .propeller1,
+ .propeller2,
=> 32,
.aarch64,
@@ -2363,7 +2653,6 @@ pub fn cTypeBitSize(target: Target, c_type: CType) u16 {
.hermit,
.hurd,
.opengl,
- .shadermodel,
=> @panic("TODO specify the C integer and float type sizes for this OS"),
}
}
@@ -2397,6 +2686,7 @@ pub fn cTypeAlignment(target: Target, c_type: CType) u16 {
.eabi,
.eabihf,
.android,
+ .androideabi,
.musleabi,
.musleabihf,
=> 8,
@@ -2408,18 +2698,18 @@ pub fn cTypeAlignment(target: Target, c_type: CType) u16 {
},
.msp430,
- .avr,
=> 2,
.arc,
.csky,
.x86,
.xcore,
- .dxil,
.loongarch32,
.kalimba,
.spu_2,
.xtensa,
+ .propeller1,
+ .propeller2,
=> 4,
.amdgcn,
@@ -2456,6 +2746,9 @@ pub fn cTypeAlignment(target: Target, c_type: CType) u16 {
.wasm32,
.wasm64,
=> 16,
+
+ .avr,
+ => unreachable, // Handled above.
}),
);
}
@@ -2470,6 +2763,7 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
.eabi,
.eabihf,
.android,
+ .androideabi,
.musleabi,
.musleabihf,
=> {},
@@ -2489,12 +2783,7 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
.longdouble => return 4,
else => {},
},
- .avr => switch (c_type) {
- .char, .int, .uint, .long, .ulong, .float, .longdouble => return 1,
- .short, .ushort => return 2,
- .double => return 4,
- .longlong, .ulonglong => return 8,
- },
+ .avr => return 1,
.x86 => switch (target.os.tag) {
.windows, .uefi => switch (c_type) {
.longdouble => switch (target.abi) {
@@ -2519,17 +2808,17 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
.csky,
.xcore,
- .dxil,
.loongarch32,
.kalimba,
.spu_2,
.xtensa,
+ .propeller1,
+ .propeller2,
=> 4,
.arc,
.arm,
.armeb,
- .avr,
.thumb,
.thumbeb,
.amdgcn,
@@ -2567,6 +2856,9 @@ pub fn cTypePreferredAlignment(target: Target, c_type: CType) u16 {
.wasm32,
.wasm64,
=> 16,
+
+ .avr,
+ => unreachable, // Handled above.
}),
);
}
diff --git a/zig/lib/std/Target/Query.zig b/zig/lib/std/Target/Query.zig
index f18d211853..e22fbcbf53 100644
--- a/zig/lib/std/Target/Query.zig
+++ b/zig/lib/std/Target/Query.zig
@@ -374,7 +374,7 @@ pub fn canDetectLibC(self: Query) bool {
if (self.isNativeOs()) return true;
if (self.os_tag) |os| {
if (builtin.os.tag == .macos and os.isDarwin()) return true;
- if (os == .linux and self.abi == .android) return true;
+ if (os == .linux and self.abi.isAndroid()) return true;
}
return false;
}
diff --git a/zig/lib/std/Target/aarch64.zig b/zig/lib/std/Target/aarch64.zig
index ac7dba124e..8b501e2dc2 100644
--- a/zig/lib/std/Target/aarch64.zig
+++ b/zig/lib/std/Target/aarch64.zig
@@ -1373,6 +1373,7 @@ pub const all_features = blk: {
.llvm_name = "v8.3a",
.description = "Support ARM v8.3a architecture",
.dependencies = featureSet(&[_]Feature{
+ .ccidx,
.complxnum,
.jsconv,
.pauth,
@@ -1409,6 +1410,7 @@ pub const all_features = blk: {
.predres,
.sb,
.specrestrict,
+ .ssbs,
.v8_4a,
}),
};
@@ -1470,18 +1472,26 @@ pub const all_features = blk: {
.llvm_name = "v8r",
.description = "Support ARM v8r architecture",
.dependencies = featureSet(&[_]Feature{
+ .ccidx,
.ccpp,
+ .complxnum,
.contextidr_el2,
.crc,
.dit,
+ .dotprod,
.flagm,
+ .fp16fml,
+ .jsconv,
.lse,
.pan_rwv,
.pauth,
.ras,
.rcpc_immo,
+ .rdm,
+ .sb,
.sel2,
.specrestrict,
+ .ssbs,
.tlb_rmi,
.tracev8_4,
.uaops,
@@ -1491,6 +1501,7 @@ pub const all_features = blk: {
.llvm_name = "v9.1a",
.description = "Support ARM v9.1a architecture",
.dependencies = featureSet(&[_]Feature{
+ .rme,
.v8_6a,
.v9a,
}),
@@ -1499,6 +1510,7 @@ pub const all_features = blk: {
.llvm_name = "v9.2a",
.description = "Support ARM v9.2a architecture",
.dependencies = featureSet(&[_]Feature{
+ .mec,
.v8_7a,
.v9_1a,
}),
@@ -1524,6 +1536,8 @@ pub const all_features = blk: {
.description = "Support ARM v9.5a architecture",
.dependencies = featureSet(&[_]Feature{
.cpa,
+ .faminmax,
+ .lut,
.v9_4a,
}),
};
@@ -1531,6 +1545,7 @@ pub const all_features = blk: {
.llvm_name = "v9a",
.description = "Support ARM v9a architecture",
.dependencies = featureSet(&[_]Feature{
+ .sve2,
.v8_5a,
}),
};
@@ -1607,7 +1622,6 @@ pub const cpu = struct {
.aggressive_fma,
.alu_lsl_fast,
.arith_bcc_fusion,
- .ccidx,
.cmp_bcc_fusion,
.fullfp16,
.fuse_address,
@@ -1618,7 +1632,6 @@ pub const cpu = struct {
.perfmon,
.rand,
.sha3,
- .ssbs,
.store_pair_suppress,
.stp_aligned_only,
.use_postra_scheduler,
@@ -1633,7 +1646,6 @@ pub const cpu = struct {
.aggressive_fma,
.alu_lsl_fast,
.arith_bcc_fusion,
- .ccidx,
.cmp_bcc_fusion,
.fullfp16,
.fuse_address,
@@ -1647,7 +1659,6 @@ pub const cpu = struct {
.rand,
.sha3,
.sm4,
- .ssbs,
.store_pair_suppress,
.stp_aligned_only,
.use_postra_scheduler,
@@ -1662,7 +1673,6 @@ pub const cpu = struct {
.aggressive_fma,
.alu_lsl_fast,
.arith_bcc_fusion,
- .ccidx,
.cmp_bcc_fusion,
.cssc,
.enable_select_opt,
@@ -1678,7 +1688,6 @@ pub const cpu = struct {
.rand,
.sha3,
.sm4,
- .ssbs,
.store_pair_suppress,
.stp_aligned_only,
.use_postra_scheduler,
@@ -1819,7 +1828,6 @@ pub const cpu = struct {
.fuse_literals,
.perfmon,
.sha3,
- .ssbs,
.store_pair_suppress,
.v8_6a,
.zcm,
@@ -1846,7 +1854,6 @@ pub const cpu = struct {
.hcx,
.perfmon,
.sha3,
- .ssbs,
.store_pair_suppress,
.v8_6a,
.zcm,
@@ -1873,7 +1880,6 @@ pub const cpu = struct {
.hcx,
.perfmon,
.sha3,
- .ssbs,
.store_pair_suppress,
.v8_6a,
.zcm,
@@ -1990,7 +1996,6 @@ pub const cpu = struct {
.fuse_literals,
.perfmon,
.sha3,
- .ssbs,
.store_pair_suppress,
.v8_6a,
.zcm,
@@ -2017,7 +2022,6 @@ pub const cpu = struct {
.hcx,
.perfmon,
.sha3,
- .ssbs,
.store_pair_suppress,
.v8_6a,
.zcm,
@@ -2106,7 +2110,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -2116,7 +2119,6 @@ pub const cpu = struct {
.mte,
.perfmon,
.predictable_select_expensive,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2149,7 +2151,6 @@ pub const cpu = struct {
.llvm_name = "cortex-a510",
.features = featureSet(&[_]Feature{
.bf16,
- .ccidx,
.ete,
.fp16fml,
.fuse_adrp_add,
@@ -2157,7 +2158,6 @@ pub const cpu = struct {
.i8mm,
.mte,
.perfmon,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2167,14 +2167,12 @@ pub const cpu = struct {
.name = "cortex_a520",
.llvm_name = "cortex-a520",
.features = featureSet(&[_]Feature{
- .ccidx,
.ete,
.fp16fml,
.fuse_adrp_add,
.fuse_aes,
.mte,
.perfmon,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2184,14 +2182,12 @@ pub const cpu = struct {
.name = "cortex_a520ae",
.llvm_name = "cortex-a520ae",
.features = featureSet(&[_]Feature{
- .ccidx,
.ete,
.fp16fml,
.fuse_adrp_add,
.fuse_aes,
.mte,
.perfmon,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2294,7 +2290,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2305,7 +2300,6 @@ pub const cpu = struct {
.mte,
.perfmon,
.predictable_select_expensive,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2317,7 +2311,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2329,7 +2322,6 @@ pub const cpu = struct {
.perfmon,
.predictable_select_expensive,
.spe,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2357,7 +2349,6 @@ pub const cpu = struct {
.llvm_name = "cortex-a720",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2369,7 +2360,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2380,7 +2370,6 @@ pub const cpu = struct {
.llvm_name = "cortex-a720ae",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2392,7 +2381,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2403,7 +2391,6 @@ pub const cpu = struct {
.llvm_name = "cortex-a725",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2415,7 +2402,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2592,15 +2578,8 @@ pub const cpu = struct {
.llvm_name = "cortex-r82",
.features = featureSet(&[_]Feature{
.ccdp,
- .complxnum,
- .dotprod,
- .fp16fml,
- .jsconv,
.perfmon,
.predres,
- .rdm,
- .sb,
- .ssbs,
.use_postra_scheduler,
.v8r,
}),
@@ -2610,15 +2589,8 @@ pub const cpu = struct {
.llvm_name = "cortex-r82ae",
.features = featureSet(&[_]Feature{
.ccdp,
- .complxnum,
- .dotprod,
- .fp16fml,
- .jsconv,
.perfmon,
.predres,
- .rdm,
- .sb,
- .ssbs,
.use_postra_scheduler,
.v8r,
}),
@@ -2678,7 +2650,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2689,7 +2660,6 @@ pub const cpu = struct {
.mte,
.perfmon,
.predictable_select_expensive,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2701,7 +2671,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -2712,7 +2681,6 @@ pub const cpu = struct {
.perfmon,
.predictable_select_expensive,
.spe,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -2723,7 +2691,6 @@ pub const cpu = struct {
.llvm_name = "cortex-x4",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -2734,7 +2701,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2745,7 +2711,6 @@ pub const cpu = struct {
.llvm_name = "cortex-x925",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -2756,7 +2721,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -2935,7 +2899,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -2948,7 +2911,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.rand,
.spe,
- .ssbs,
.sve2_bitperm,
.use_fixed_over_scalable_if_equal_cost,
.use_postra_scheduler,
@@ -2979,7 +2941,6 @@ pub const cpu = struct {
.alu_lsl_fast,
.bf16,
.ccdp,
- .ccidx,
.enable_select_opt,
.fp16fml,
.fuse_adrp_add,
@@ -3042,7 +3003,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -3052,7 +3012,6 @@ pub const cpu = struct {
.mte,
.perfmon,
.predictable_select_expensive,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9a,
@@ -3063,7 +3022,6 @@ pub const cpu = struct {
.llvm_name = "neoverse-n3",
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -3075,7 +3033,6 @@ pub const cpu = struct {
.rand,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -3090,7 +3047,6 @@ pub const cpu = struct {
.alu_lsl_fast,
.bf16,
.ccdp,
- .ccidx,
.enable_select_opt,
.fp16fml,
.fuse_adrp_add,
@@ -3115,7 +3071,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.bf16,
- .ccidx,
.cmp_bcc_fusion,
.enable_select_opt,
.ete,
@@ -3128,7 +3083,6 @@ pub const cpu = struct {
.predictable_select_expensive,
.rand,
.spe,
- .ssbs,
.sve2_bitperm,
.use_fixed_over_scalable_if_equal_cost,
.use_postra_scheduler,
@@ -3141,7 +3095,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.brbe,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -3152,10 +3105,8 @@ pub const cpu = struct {
.perfmon,
.predictable_select_expensive,
.rand,
- .rme,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -3167,7 +3118,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.alu_lsl_fast,
.brbe,
- .ccidx,
.enable_select_opt,
.ete,
.fp16fml,
@@ -3178,10 +3128,8 @@ pub const cpu = struct {
.perfmon,
.predictable_select_expensive,
.rand,
- .rme,
.spe,
.spe_eef,
- .ssbs,
.sve2_bitperm,
.use_postra_scheduler,
.v9_2a,
@@ -3192,7 +3140,6 @@ pub const cpu = struct {
.llvm_name = "oryon-1",
.features = featureSet(&[_]Feature{
.aes,
- .ccidx,
.enable_select_opt,
.fp16fml,
.fuse_address,
@@ -3204,7 +3151,6 @@ pub const cpu = struct {
.sha3,
.sm4,
.spe,
- .ssbs,
.use_postra_scheduler,
.v8_6a,
}),
@@ -3215,7 +3161,6 @@ pub const cpu = struct {
.features = featureSet(&[_]Feature{
.aes,
.alu_lsl_fast,
- .ccidx,
.perfmon,
.predictable_select_expensive,
.sha2,
@@ -3262,7 +3207,6 @@ pub const cpu = struct {
.aggressive_fma,
.arith_bcc_fusion,
.balance_fp_ops,
- .ccidx,
.perfmon,
.predictable_select_expensive,
.sha2,
diff --git a/zig/lib/std/Target/arm.zig b/zig/lib/std/Target/arm.zig
index aa0e1e4603..9e4e72a05a 100644
--- a/zig/lib/std/Target/arm.zig
+++ b/zig/lib/std/Target/arm.zig
@@ -2254,7 +2254,6 @@ pub const cpu = struct {
.llvm_name = "cortex-m85",
.features = featureSet(&[_]Feature{
.dsp,
- .trustzone,
.use_misched,
.v8_1m_main,
}),
diff --git a/zig/lib/std/Target/lanai.zig b/zig/lib/std/Target/lanai.zig
new file mode 100644
index 0000000000..041934b6d4
--- /dev/null
+++ b/zig/lib/std/Target/lanai.zig
@@ -0,0 +1,37 @@
+//! This file is auto-generated by tools/update_cpu_features.zig.
+
+const std = @import("../std.zig");
+const CpuFeature = std.Target.Cpu.Feature;
+const CpuModel = std.Target.Cpu.Model;
+
+pub const Feature = enum {};
+
+pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
+pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas;
+pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny;
+pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll;
+
+pub const all_features = blk: {
+ const len = @typeInfo(Feature).@"enum".fields.len;
+ std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
+ var result: [len]CpuFeature = undefined;
+ const ti = @typeInfo(Feature);
+ for (&result, 0..) |*elem, i| {
+ elem.index = i;
+ elem.name = ti.@"enum".fields[i].name;
+ }
+ break :blk result;
+};
+
+pub const cpu = struct {
+ pub const generic = CpuModel{
+ .name = "generic",
+ .llvm_name = "generic",
+ .features = featureSet(&[_]Feature{}),
+ };
+ pub const v11 = CpuModel{
+ .name = "v11",
+ .llvm_name = "v11",
+ .features = featureSet(&[_]Feature{}),
+ };
+};
diff --git a/zig/lib/std/Target/propeller.zig b/zig/lib/std/Target/propeller.zig
new file mode 100644
index 0000000000..929e3ff74c
--- /dev/null
+++ b/zig/lib/std/Target/propeller.zig
@@ -0,0 +1,20 @@
+const std = @import("../std.zig");
+const CpuFeature = std.Target.Cpu.Feature;
+const CpuModel = std.Target.Cpu.Model;
+
+pub const Feature = enum {};
+
+pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
+pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas;
+pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny;
+pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll;
+
+pub const all_features: [0]CpuFeature = .{};
+
+pub const cpu = struct {
+ pub const generic = CpuModel{
+ .name = "generic",
+ .llvm_name = null,
+ .features = featureSet(&[_]Feature{}),
+ };
+};
diff --git a/zig/lib/std/Target/xcore.zig b/zig/lib/std/Target/xcore.zig
new file mode 100644
index 0000000000..4069620849
--- /dev/null
+++ b/zig/lib/std/Target/xcore.zig
@@ -0,0 +1,37 @@
+//! This file is auto-generated by tools/update_cpu_features.zig.
+
+const std = @import("../std.zig");
+const CpuFeature = std.Target.Cpu.Feature;
+const CpuModel = std.Target.Cpu.Model;
+
+pub const Feature = enum {};
+
+pub const featureSet = CpuFeature.FeatureSetFns(Feature).featureSet;
+pub const featureSetHas = CpuFeature.FeatureSetFns(Feature).featureSetHas;
+pub const featureSetHasAny = CpuFeature.FeatureSetFns(Feature).featureSetHasAny;
+pub const featureSetHasAll = CpuFeature.FeatureSetFns(Feature).featureSetHasAll;
+
+pub const all_features = blk: {
+ const len = @typeInfo(Feature).@"enum".fields.len;
+ std.debug.assert(len <= CpuFeature.Set.needed_bit_count);
+ var result: [len]CpuFeature = undefined;
+ const ti = @typeInfo(Feature);
+ for (&result, 0..) |*elem, i| {
+ elem.index = i;
+ elem.name = ti.@"enum".fields[i].name;
+ }
+ break :blk result;
+};
+
+pub const cpu = struct {
+ pub const generic = CpuModel{
+ .name = "generic",
+ .llvm_name = "generic",
+ .features = featureSet(&[_]Feature{}),
+ };
+ pub const xs1b_generic = CpuModel{
+ .name = "xs1b_generic",
+ .llvm_name = "xs1b-generic",
+ .features = featureSet(&[_]Feature{}),
+ };
+};
diff --git a/zig/lib/std/Thread.zig b/zig/lib/std/Thread.zig
index 446b629cc6..a5c03138f7 100644
--- a/zig/lib/std/Thread.zig
+++ b/zig/lib/std/Thread.zig
@@ -22,6 +22,83 @@ pub const WaitGroup = @import("Thread/WaitGroup.zig");
pub const use_pthreads = native_os != .windows and native_os != .wasi and builtin.link_libc;
+/// Spurious wakeups are possible and no precision of timing is guaranteed.
+pub fn sleep(nanoseconds: u64) void {
+ if (builtin.os.tag == .windows) {
+ const big_ms_from_ns = nanoseconds / std.time.ns_per_ms;
+ const ms = math.cast(windows.DWORD, big_ms_from_ns) orelse math.maxInt(windows.DWORD);
+ windows.kernel32.Sleep(ms);
+ return;
+ }
+
+ if (builtin.os.tag == .wasi) {
+ const w = std.os.wasi;
+ const userdata: w.userdata_t = 0x0123_45678;
+ const clock: w.subscription_clock_t = .{
+ .id = .MONOTONIC,
+ .timeout = nanoseconds,
+ .precision = 0,
+ .flags = 0,
+ };
+ const in: w.subscription_t = .{
+ .userdata = userdata,
+ .u = .{
+ .tag = .CLOCK,
+ .u = .{ .clock = clock },
+ },
+ };
+
+ var event: w.event_t = undefined;
+ var nevents: usize = undefined;
+ _ = w.poll_oneoff(&in, &event, 1, &nevents);
+ return;
+ }
+
+ if (builtin.os.tag == .uefi) {
+ const boot_services = std.os.uefi.system_table.boot_services.?;
+ const us_from_ns = nanoseconds / std.time.ns_per_us;
+ const us = math.cast(usize, us_from_ns) orelse math.maxInt(usize);
+ _ = boot_services.stall(us);
+ return;
+ }
+
+ const s = nanoseconds / std.time.ns_per_s;
+ const ns = nanoseconds % std.time.ns_per_s;
+
+ // Newer kernel ports don't have old `nanosleep()` and `clock_nanosleep()` has been around
+ // since Linux 2.6 and glibc 2.1 anyway.
+ if (builtin.os.tag == .linux) {
+ const linux = std.os.linux;
+
+ var req: linux.timespec = .{
+ .sec = std.math.cast(linux.time_t, s) orelse std.math.maxInt(linux.time_t),
+ .nsec = std.math.cast(linux.time_t, ns) orelse std.math.maxInt(linux.time_t),
+ };
+ var rem: linux.timespec = undefined;
+
+ while (true) {
+ switch (linux.E.init(linux.clock_nanosleep(.MONOTONIC, .{ .ABSTIME = false }, &req, &rem))) {
+ .SUCCESS => return,
+ .INTR => {
+ req = rem;
+ continue;
+ },
+ .FAULT,
+ .INVAL,
+ .OPNOTSUPP,
+ => unreachable,
+ else => return,
+ }
+ }
+ }
+
+ posix.nanosleep(s, ns);
+}
+
+test sleep {
+ sleep(1);
+}
+
const Thread = @This();
const Impl = if (native_os == .windows)
WindowsThreadImpl
diff --git a/zig/lib/std/Thread/Futex.zig b/zig/lib/std/Thread/Futex.zig
index fe22fa2011..da3fb916c6 100644
--- a/zig/lib/std/Thread/Futex.zig
+++ b/zig/lib/std/Thread/Futex.zig
@@ -794,9 +794,8 @@ const PosixImpl = struct {
// - T1: bumps pending waiters (was reordered after the ptr == expect check)
// - T1: goes to sleep and misses both the ptr change and T2's wake up
//
- // seq_cst as Acquire barrier to ensure the announcement happens before the ptr check below.
- // seq_cst as shared modification order to form a happens-before edge with the fence(.seq_cst)+load() in wake().
- var pending = bucket.pending.fetchAdd(1, .seq_cst);
+ // acquire barrier to ensure the announcement happens before the ptr check below.
+ var pending = bucket.pending.fetchAdd(1, .acquire);
assert(pending < std.math.maxInt(usize));
// If the wait gets cancelled, remove the pending count we previously added.
@@ -858,15 +857,8 @@ const PosixImpl = struct {
//
// What we really want here is a Release load, but that doesn't exist under the C11 memory model.
// We could instead do `bucket.pending.fetchAdd(0, Release) == 0` which achieves effectively the same thing,
- // but the RMW operation unconditionally marks the cache-line as modified for others causing unnecessary fetching/contention.
- //
- // Instead we opt to do a full-fence + load instead which avoids taking ownership of the cache-line.
- // fence(seq_cst) effectively converts the ptr update to seq_cst and the pending load to seq_cst: creating a Store-Load barrier.
- //
- // The pending count increment in wait() must also now use seq_cst for the update + this pending load
- // to be in the same modification order as our load isn't using release/acquire to guarantee it.
- bucket.pending.fence(.seq_cst);
- if (bucket.pending.load(.monotonic) == 0) {
+ // LLVM lowers the fetchAdd(0, .release) into an mfence+load which avoids gaining ownership of the cache-line.
+ if (bucket.pending.fetchAdd(0, .release) == 0) {
return;
}
@@ -979,15 +971,14 @@ test "broadcasting" {
fn wait(self: *@This()) !void {
// Decrement the counter.
// Release ensures stuff before this barrier.wait() happens before the last one.
- const count = self.count.fetchSub(1, .release);
+ // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
+ const count = self.count.fetchSub(1, .acq_rel);
try testing.expect(count <= num_threads);
try testing.expect(count > 0);
// First counter to reach zero wakes all other threads.
- // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
// Release on futex update ensures stuff before all barrier.wait()'s happens before they all return.
if (count - 1 == 0) {
- _ = self.count.load(.acquire); // TODO: could be fence(acquire) if not for TSAN
self.futex.store(1, .release);
Futex.wake(&self.futex, num_threads - 1);
return;
diff --git a/zig/lib/std/Thread/ResetEvent.zig b/zig/lib/std/Thread/ResetEvent.zig
index cbc5a2a31c..47a9b0c038 100644
--- a/zig/lib/std/Thread/ResetEvent.zig
+++ b/zig/lib/std/Thread/ResetEvent.zig
@@ -112,9 +112,9 @@ const FutexImpl = struct {
// Try to set the state from `unset` to `waiting` to indicate
// to the set() thread that others are blocked on the ResetEvent.
// We avoid using any strict barriers until the end when we know the ResetEvent is set.
- var state = self.state.load(.monotonic);
+ var state = self.state.load(.acquire);
if (state == unset) {
- state = self.state.cmpxchgStrong(state, waiting, .monotonic, .monotonic) orelse waiting;
+ state = self.state.cmpxchgStrong(state, waiting, .acquire, .acquire) orelse waiting;
}
// Wait until the ResetEvent is set since the state is waiting.
@@ -124,7 +124,7 @@ const FutexImpl = struct {
const wait_result = futex_deadline.wait(&self.state, waiting);
// Check if the ResetEvent was set before possibly reporting error.Timeout below.
- state = self.state.load(.monotonic);
+ state = self.state.load(.acquire);
if (state != waiting) {
break;
}
@@ -133,9 +133,7 @@ const FutexImpl = struct {
}
}
- // Acquire barrier ensures memory accesses before set() happen before we return.
assert(state == is_set);
- self.state.fence(.acquire);
}
fn set(self: *Impl) void {
diff --git a/zig/lib/std/Thread/WaitGroup.zig b/zig/lib/std/Thread/WaitGroup.zig
index cff474c863..bdc49587bf 100644
--- a/zig/lib/std/Thread/WaitGroup.zig
+++ b/zig/lib/std/Thread/WaitGroup.zig
@@ -15,11 +15,10 @@ pub fn start(self: *WaitGroup) void {
}
pub fn finish(self: *WaitGroup) void {
- const state = self.state.fetchSub(one_pending, .release);
+ const state = self.state.fetchSub(one_pending, .acq_rel);
assert((state / one_pending) > 0);
if (state == (one_pending | is_waiting)) {
- self.state.fence(.acquire);
self.event.set();
}
}
diff --git a/zig/lib/std/atomic.zig b/zig/lib/std/atomic.zig
index 0f25bd448a..e1a6767590 100644
--- a/zig/lib/std/atomic.zig
+++ b/zig/lib/std/atomic.zig
@@ -10,31 +10,7 @@ pub fn Value(comptime T: type) type {
return .{ .raw = value };
}
- /// Perform an atomic fence which uses the atomic value as a hint for
- /// the modification order. Use this when you want to imply a fence on
- /// an atomic variable without necessarily performing a memory access.
- pub inline fn fence(self: *Self, comptime order: AtomicOrder) void {
- // LLVM's ThreadSanitizer doesn't support the normal fences so we specialize for it.
- if (builtin.sanitize_thread) {
- const tsan = struct {
- extern "c" fn __tsan_acquire(addr: *anyopaque) void;
- extern "c" fn __tsan_release(addr: *anyopaque) void;
- };
-
- const addr: *anyopaque = self;
- return switch (order) {
- .unordered, .monotonic => @compileError(@tagName(order) ++ " only applies to atomic loads and stores"),
- .acquire => tsan.__tsan_acquire(addr),
- .release => tsan.__tsan_release(addr),
- .acq_rel, .seq_cst => {
- tsan.__tsan_acquire(addr);
- tsan.__tsan_release(addr);
- },
- };
- }
-
- return @fence(order);
- }
+ pub const fence = @compileError("@fence is deprecated, use other atomics to establish ordering");
pub inline fn load(self: *const Self, comptime order: AtomicOrder) T {
return @atomicLoad(T, &self.raw, order);
@@ -148,21 +124,19 @@ test Value {
const RefCount = @This();
fn ref(rc: *RefCount) void {
- // No ordering necessary; just updating a counter.
+ // no synchronization necessary; just updating a counter.
_ = rc.count.fetchAdd(1, .monotonic);
}
fn unref(rc: *RefCount) void {
- // Release ensures code before unref() happens-before the
+ // release ensures code before unref() happens-before the
// count is decremented as dropFn could be called by then.
if (rc.count.fetchSub(1, .release) == 1) {
- // acquire ensures count decrement and code before
- // previous unrefs()s happens-before we call dropFn
- // below.
- // Another alternative is to use .acq_rel on the
- // fetchSub count decrement but it's extra barrier in
- // possibly hot path.
- rc.count.fence(.acquire);
+ // seeing 1 in the counter means that other unref()s have happened,
+ // but it doesn't mean that uses before each unref() are visible.
+ // The load acquires the release-sequence created by previous unref()s
+ // in order to ensure visibility of uses before dropping.
+ _ = rc.count.load(.acquire);
(rc.dropFn)(rc);
}
}
@@ -459,18 +433,20 @@ pub const cache_line = switch (builtin.cpu.arch) {
.powerpc64le,
=> 128,
+ // https://github.com/llvm/llvm-project/blob/e379094328e49731a606304f7e3559d4f1fa96f9/clang/lib/Basic/Targets/Hexagon.h#L145-L151
+ .hexagon,
+ => if (std.Target.hexagon.featureSetHas(builtin.target.cpu.features, .v73)) 64 else 32,
+
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_arm.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mipsle.go#L7
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_mips64x.go#L9
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_riscv64.go#L7
- // - https://github.com/torvalds/linux/blob/3a7e02c040b130b5545e4b115aada7bacd80a2b6/arch/hexagon/include/asm/cache.h#L13
// - https://github.com/torvalds/linux/blob/3a7e02c040b130b5545e4b115aada7bacd80a2b6/arch/sparc/include/asm/cache.h#L14
.arm,
.armeb,
.thumb,
.thumbeb,
- .hexagon,
.mips,
.mipsel,
.mips64,
diff --git a/zig/lib/std/bit_set.zig b/zig/lib/std/bit_set.zig
index 1e2a0179ef..7ff97cfa9d 100644
--- a/zig/lib/std/bit_set.zig
+++ b/zig/lib/std/bit_set.zig
@@ -1043,10 +1043,7 @@ pub const DynamicBitSet = struct {
/// The integer type used to shift a mask in this bit set
pub const ShiftInt = std.math.Log2Int(MaskInt);
- /// The allocator used by this bit set
allocator: Allocator,
-
- /// The number of valid items in this bit set
unmanaged: DynamicBitSetUnmanaged = .{},
/// Creates a bit set with no elements present.
diff --git a/zig/lib/std/builtin.zig b/zig/lib/std/builtin.zig
index ccd46d874d..628b736d82 100644
--- a/zig/lib/std/builtin.zig
+++ b/zig/lib/std/builtin.zig
@@ -236,6 +236,17 @@ pub const AddressSpace = enum(u5) {
flash3,
flash4,
flash5,
+
+ // Propeller address spaces.
+
+ /// This address space only addresses the cog-local ram.
+ cog,
+
+ /// This address space only addresses shared hub ram.
+ hub,
+
+ /// This address space only addresses the "lookup" ram
+ lut,
};
/// This data structure is used by the Zig language code generation and
@@ -609,6 +620,7 @@ pub const VaList = switch (builtin.cpu.arch) {
.avr => *anyopaque,
.bpfel, .bpfeb => *anyopaque,
.hexagon => if (builtin.target.isMusl()) VaListHexagon else *u8,
+ .loongarch32, .loongarch64 => *anyopaque,
.mips, .mipsel, .mips64, .mips64el => *anyopaque,
.riscv32, .riscv64 => *anyopaque,
.powerpc, .powerpcle => switch (builtin.os.tag) {
@@ -761,201 +773,54 @@ pub const TestFn = struct {
func: *const fn () anyerror!void,
};
-/// This function type is used by the Zig language code generation and
-/// therefore must be kept in sync with the compiler implementation.
+/// Deprecated, use the `Panic` namespace instead.
+/// To be deleted after 0.14.0 is released.
pub const PanicFn = fn ([]const u8, ?*StackTrace, ?usize) noreturn;
-
-/// This function is used by the Zig language code generation and
-/// therefore must be kept in sync with the compiler implementation.
-pub const panic: PanicFn = if (@hasDecl(root, "panic"))
- root.panic
-else if (@hasDecl(root, "os") and @hasDecl(root.os, "panic"))
- root.os.panic
+/// Deprecated, use the `Panic` namespace instead.
+/// To be deleted after 0.14.0 is released.
+pub const panic: PanicFn = Panic.call;
+
+/// This namespace is used by the Zig compiler to emit various kinds of safety
+/// panics. These can be overridden by making a public `Panic` namespace in the
+/// root source file.
+pub const Panic: type = if (@hasDecl(root, "Panic"))
+ root.Panic
+else if (@hasDecl(root, "panic")) // Deprecated, use `Panic` instead.
+ DeprecatedPanic
+else if (builtin.zig_backend == .stage2_riscv64)
+ std.debug.SimplePanic // https://github.com/ziglang/zig/issues/21519
else
- default_panic;
-
-/// This function is used by the Zig language code generation and
-/// therefore must be kept in sync with the compiler implementation.
-pub fn default_panic(msg: []const u8, error_return_trace: ?*StackTrace, ret_addr: ?usize) noreturn {
- @branchHint(.cold);
-
- // For backends that cannot handle the language features depended on by the
- // default panic handler, we have a simpler panic handler:
- if (builtin.zig_backend == .stage2_wasm or
- builtin.zig_backend == .stage2_arm or
- builtin.zig_backend == .stage2_aarch64 or
- builtin.zig_backend == .stage2_x86 or
- (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
- builtin.zig_backend == .stage2_sparc64 or
- builtin.zig_backend == .stage2_spirv64)
- {
- while (true) {
- @breakpoint();
- }
- }
-
- if (builtin.zig_backend == .stage2_riscv64) {
- std.debug.print("panic: {s}\n", .{msg});
- @breakpoint();
- std.posix.exit(127);
- }
-
- switch (builtin.os.tag) {
- .freestanding => {
- while (true) {
- @breakpoint();
- }
- },
- .wasi => {
- std.debug.print("{s}", .{msg});
- std.posix.abort();
- },
- .uefi => {
- const uefi = std.os.uefi;
-
- const Formatter = struct {
- pub fn fmt(exit_msg: []const u8, out: []u16) ![:0]u16 {
- var u8_buf: [256]u8 = undefined;
- const slice = try std.fmt.bufPrint(&u8_buf, "err: {s}\r\n", .{exit_msg});
- // We pass len - 1 because we need to add a null terminator after
- const len = try std.unicode.utf8ToUtf16Le(out[0 .. out.len - 1], slice);
-
- out[len] = 0;
-
- return out[0..len :0];
- }
- };
-
- const ExitData = struct {
- pub fn create_exit_data(exit_msg: [:0]u16, exit_size: *usize) ![*:0]u16 {
- // Need boot services for pool allocation
- if (uefi.system_table.boot_services == null) {
- return error.BootServicesUnavailable;
- }
-
- // ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
- const exit_data: []u16 = try uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1);
-
- @memcpy(exit_data[0 .. exit_msg.len + 1], exit_msg[0 .. exit_msg.len + 1]);
- exit_size.* = exit_msg.len + 1;
-
- return @as([*:0]u16, @ptrCast(exit_data.ptr));
- }
- };
-
- var buf: [256]u16 = undefined;
- const utf16 = Formatter.fmt(msg, &buf) catch null;
-
- var exit_size: usize = 0;
- const exit_data = if (utf16) |u|
- ExitData.create_exit_data(u, &exit_size) catch null
- else
- null;
-
- if (utf16) |str| {
- // Output to both std_err and con_out, as std_err is easier
- // to read in stuff like QEMU at times, but, unlike con_out,
- // isn't visible on actual hardware if directly booted into
- inline for ([_]?*uefi.protocol.SimpleTextOutput{ uefi.system_table.std_err, uefi.system_table.con_out }) |o| {
- if (o) |out| {
- _ = out.setAttribute(uefi.protocol.SimpleTextOutput.red);
- _ = out.outputString(str);
- _ = out.setAttribute(uefi.protocol.SimpleTextOutput.white);
- }
- }
- }
-
- if (uefi.system_table.boot_services) |bs| {
- _ = bs.exit(uefi.handle, .Aborted, exit_size, exit_data);
- }
-
- // Didn't have boot_services, just fallback to whatever.
- std.posix.abort();
- },
- .cuda, .amdhsa => std.posix.abort(),
- .plan9 => {
- var status: [std.os.plan9.ERRMAX]u8 = undefined;
- const len = @min(msg.len, status.len - 1);
- @memcpy(status[0..len], msg[0..len]);
- status[len] = 0;
- std.os.plan9.exits(status[0..len :0]);
- },
- else => {
- const first_trace_addr = ret_addr orelse @returnAddress();
- std.debug.panicImpl(error_return_trace, first_trace_addr, msg);
- },
- }
-}
-
-pub fn checkNonScalarSentinel(expected: anytype, actual: @TypeOf(expected)) void {
- if (!std.meta.eql(expected, actual)) {
- panicSentinelMismatch(expected, actual);
- }
-}
-
-pub fn panicSentinelMismatch(expected: anytype, actual: @TypeOf(expected)) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{ expected, actual });
-}
-
-pub fn panicUnwrapError(st: ?*StackTrace, err: anyerror) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(st, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
-}
-
-pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
-}
-
-pub fn panicStartGreaterThanEnd(start: usize, end: usize) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
-}
-
-pub fn panicInactiveUnionField(active: anytype, wanted: @TypeOf(active)) noreturn {
- @branchHint(.cold);
- std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{ @tagName(wanted), @tagName(active) });
-}
-
-pub const panic_messages = struct {
- pub const unreach = "reached unreachable code";
- pub const unwrap_null = "attempt to use null value";
- pub const cast_to_null = "cast causes pointer to be null";
- pub const incorrect_alignment = "incorrect alignment";
- pub const invalid_error_code = "invalid error code";
- pub const cast_truncated_data = "integer cast truncated bits";
- pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer";
- pub const integer_overflow = "integer overflow";
- pub const shl_overflow = "left shift overflowed bits";
- pub const shr_overflow = "right shift overflowed bits";
- pub const divide_by_zero = "division by zero";
- pub const exact_division_remainder = "exact division produced remainder";
- pub const inactive_union_field = "access of inactive union field";
- pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds";
- pub const corrupt_switch = "switch on corrupt value";
- pub const shift_rhs_too_big = "shift amount is greater than the type size";
- pub const invalid_enum_value = "invalid enum value";
- pub const sentinel_mismatch = "sentinel mismatch";
- pub const unwrap_error = "attempt to unwrap error";
- pub const index_out_of_bounds = "index out of bounds";
- pub const start_index_greater_than_end = "start index is larger than end index";
- pub const for_len_mismatch = "for loop over objects with non-equal lengths";
- pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
- pub const memcpy_alias = "@memcpy arguments alias";
- pub const noreturn_returned = "'noreturn' function returned";
-};
+ std.debug.FormattedPanic;
+
+/// To be deleted after 0.14.0 is released.
+const DeprecatedPanic = struct {
+ pub const call = root.panic;
+ pub const sentinelMismatch = std.debug.FormattedPanic.sentinelMismatch;
+ pub const unwrapError = std.debug.FormattedPanic.unwrapError;
+ pub const outOfBounds = std.debug.FormattedPanic.outOfBounds;
+ pub const startGreaterThanEnd = std.debug.FormattedPanic.startGreaterThanEnd;
+ pub const inactiveUnionField = std.debug.FormattedPanic.inactiveUnionField;
+ pub const messages = std.debug.FormattedPanic.messages;
+};
+
+/// To be deleted after zig1.wasm is updated.
+pub const panicSentinelMismatch = Panic.sentinelMismatch;
+/// To be deleted after zig1.wasm is updated.
+pub const panicUnwrapError = Panic.unwrapError;
+/// To be deleted after zig1.wasm is updated.
+pub const panicOutOfBounds = Panic.outOfBounds;
+/// To be deleted after zig1.wasm is updated.
+pub const panicStartGreaterThanEnd = Panic.startGreaterThanEnd;
+/// To be deleted after zig1.wasm is updated.
+pub const panicInactiveUnionField = Panic.inactiveUnionField;
+/// To be deleted after zig1.wasm is updated.
+pub const panic_messages = Panic.messages;
pub noinline fn returnError(st: *StackTrace) void {
- @branchHint(.cold);
+ @branchHint(.unlikely);
@setRuntimeSafety(false);
- addErrRetTraceAddr(st, @returnAddress());
-}
-
-pub inline fn addErrRetTraceAddr(st: *StackTrace, addr: usize) void {
if (st.index < st.instruction_addresses.len)
- st.instruction_addresses[st.index] = addr;
-
+ st.instruction_addresses[st.index] = @returnAddress();
st.index += 1;
}
diff --git a/zig/lib/std/c.zig b/zig/lib/std/c.zig
index 12524667d2..d28f5b0ac4 100644
--- a/zig/lib/std/c.zig
+++ b/zig/lib/std/c.zig
@@ -134,7 +134,7 @@ pub const mode_t = switch (native_os) {
.linux => linux.mode_t,
.emscripten => emscripten.mode_t,
.openbsd, .haiku, .netbsd, .solaris, .illumos, .wasi => u32,
- .freebsd, .macos, .ios, .tvos, .watchos, .visionos => u16,
+ .freebsd, .macos, .ios, .tvos, .watchos, .visionos, .dragonfly => u16,
else => u0,
};
@@ -2753,6 +2753,19 @@ pub const Sigaction = switch (native_os) {
restorer: ?*const fn () callconv(.C) void = null,
__resv: [1]c_int = .{0},
},
+ .s390x => if (builtin.abi == .gnu) extern struct {
+ pub const handler_fn = *align(1) const fn (i32) callconv(.C) void;
+ pub const sigaction_fn = *const fn (i32, *const siginfo_t, ?*anyopaque) callconv(.C) void;
+
+ handler: extern union {
+ handler: ?handler_fn,
+ sigaction: ?sigaction_fn,
+ },
+ __glibc_reserved0: c_int = 0,
+ flags: c_uint,
+ restorer: ?*const fn () callconv(.C) void = null,
+ mask: sigset_t,
+ } else linux.Sigaction,
else => linux.Sigaction,
},
.emscripten => emscripten.Sigaction,
@@ -3137,6 +3150,72 @@ pub const T = switch (native_os) {
pub const IOCUCNTL = 0x80047466;
pub const IOCXMTFRAME = 0x80087444;
},
+ .dragonfly => struct {
+ pub const IOCMODG = 0x40047403;
+ pub const IOCMODS = 0x80047404;
+ pub const IOCM_LE = 0x00000001;
+ pub const IOCM_DTR = 0x00000002;
+ pub const IOCM_RTS = 0x00000004;
+ pub const IOCM_ST = 0x00000008;
+ pub const IOCM_SR = 0x00000010;
+ pub const IOCM_CTS = 0x00000020;
+ pub const IOCM_CAR = 0x00000040;
+ pub const IOCM_CD = 0x00000040;
+ pub const IOCM_RNG = 0x00000080;
+ pub const IOCM_RI = 0x00000080;
+ pub const IOCM_DSR = 0x00000100;
+ pub const IOCEXCL = 0x2000740d;
+ pub const IOCNXCL = 0x2000740e;
+ pub const IOCFLUSH = 0x80047410;
+ pub const IOCGETA = 0x402c7413;
+ pub const IOCSETA = 0x802c7414;
+ pub const IOCSETAW = 0x802c7415;
+ pub const IOCSETAF = 0x802c7416;
+ pub const IOCGETD = 0x4004741a;
+ pub const IOCSETD = 0x8004741b;
+ pub const IOCSBRK = 0x2000747b;
+ pub const IOCCBRK = 0x2000747a;
+ pub const IOCSDTR = 0x20007479;
+ pub const IOCCDTR = 0x20007478;
+ pub const IOCGPGRP = 0x40047477;
+ pub const IOCSPGRP = 0x80047476;
+ pub const IOCOUTQ = 0x40047473;
+ pub const IOCSTI = 0x80017472;
+ pub const IOCNOTTY = 0x20007471;
+ pub const IOCPKT = 0x80047470;
+ pub const IOCPKT_DATA = 0x00000000;
+ pub const IOCPKT_FLUSHREAD = 0x00000001;
+ pub const IOCPKT_FLUSHWRITE = 0x00000002;
+ pub const IOCPKT_STOP = 0x00000004;
+ pub const IOCPKT_START = 0x00000008;
+ pub const IOCPKT_NOSTOP = 0x00000010;
+ pub const IOCPKT_DOSTOP = 0x00000020;
+ pub const IOCPKT_IOCTL = 0x00000040;
+ pub const IOCSTOP = 0x2000746f;
+ pub const IOCSTART = 0x2000746e;
+ pub const IOCMSET = 0x8004746d;
+ pub const IOCMBIS = 0x8004746c;
+ pub const IOCMBIC = 0x8004746b;
+ pub const IOCMGET = 0x4004746a;
+ pub const IOCREMOTE = 0x80047469;
+ pub const IOCGWINSZ = 0x40087468;
+ pub const IOCSWINSZ = 0x80087467;
+ pub const IOCUCNTL = 0x80047466;
+ pub const IOCSTAT = 0x20007465;
+ pub const IOCGSID = 0x40047463;
+ pub const IOCCONS = 0x80047462;
+ pub const IOCSCTTY = 0x20007461;
+ pub const IOCEXT = 0x80047460;
+ pub const IOCSIG = 0x2000745f;
+ pub const IOCDRAIN = 0x2000745e;
+ pub const IOCMSDTRWAIT = 0x8004745b;
+ pub const IOCMGDTRWAIT = 0x4004745a;
+ pub const IOCTIMESTAMP = 0x40107459;
+ pub const IOCDCDTIMESTAMP = 0x40107458;
+ pub const IOCSDRAINWAIT = 0x80047457;
+ pub const IOCGDRAINWAIT = 0x40047456;
+ pub const IOCISPTMASTER = 0x20007455;
+ },
else => void,
};
pub const IOCPARM_MASK = switch (native_os) {
@@ -5946,7 +6025,7 @@ pub const PR = switch (native_os) {
};
pub const _errno = switch (native_os) {
.linux => switch (native_abi) {
- .android => private.__errno,
+ .android, .androideabi => private.__errno,
else => private.__errno_location,
},
.emscripten => private.__errno_location,
@@ -6389,14 +6468,14 @@ pub const Stat = switch (native_os) {
return self.ctim;
}
} else extern struct {
- dev: dev_t,
+ dev: u32,
__pad0: [3]u32,
ino: ino_t,
mode: mode_t,
nlink: nlink_t,
uid: uid_t,
gid: gid_t,
- rdev: dev_t,
+ rdev: u32,
__pad1: [3]u32,
size: off_t,
atim: timespec,
@@ -6754,7 +6833,7 @@ pub const pthread_mutex_t = switch (native_os) {
.mips64, .powerpc64, .powerpc64le, .sparc64 => 40,
else => if (@sizeOf(usize) == 8) 40 else 24,
},
- .android => if (@sizeOf(usize) == 8) 40 else 4,
+ .android, .androideabi => if (@sizeOf(usize) == 8) 40 else 4,
else => @compileError("unsupported ABI"),
};
},
@@ -6848,7 +6927,7 @@ pub const pthread_cond_t = switch (native_os) {
pub const pthread_rwlock_t = switch (native_os) {
.linux => switch (native_abi) {
- .android => switch (@sizeOf(usize)) {
+ .android, .androideabi => switch (@sizeOf(usize)) {
4 => extern struct {
data: [40]u8 align(@alignOf(usize)) = [_]u8{0} ** 40,
},
@@ -9450,7 +9529,7 @@ pub extern "c" fn pthread_rwlock_unlock(rwl: *pthread_rwlock_t) callconv(.C) E;
pub const pthread_t = *opaque {};
pub const FILE = opaque {};
-pub extern "c" fn dlopen(path: [*:0]const u8, mode: RTLD) ?*anyopaque;
+pub extern "c" fn dlopen(path: ?[*:0]const u8, mode: RTLD) ?*anyopaque;
pub extern "c" fn dlclose(handle: *anyopaque) c_int;
pub extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*:0]const u8) ?*anyopaque;
pub extern "c" fn dlerror() ?[*:0]u8;
@@ -9506,7 +9585,7 @@ else if (native_os == .linux and builtin.target.isMusl())
else
private.getcontext;
-pub const max_align_t = if (native_abi == .msvc)
+pub const max_align_t = if (native_abi == .msvc or native_abi == .itanium)
f64
else if (builtin.target.isDarwin())
c_longdouble
@@ -9796,6 +9875,10 @@ pub const _ksiginfo = netbsd._ksiginfo;
pub const _lwp_self = netbsd._lwp_self;
pub const lwpid_t = netbsd.lwpid_t;
+pub const lwp_gettid = dragonfly.lwp_gettid;
+pub const umtx_sleep = dragonfly.umtx_sleep;
+pub const umtx_wakeup = dragonfly.umtx_wakeup;
+
/// External definitions shared by two or more operating systems.
const private = struct {
extern "c" fn close(fd: fd_t) c_int;
diff --git a/zig/lib/std/c/darwin.zig b/zig/lib/std/c/darwin.zig
index 60a349868e..573f29150d 100644
--- a/zig/lib/std/c/darwin.zig
+++ b/zig/lib/std/c/darwin.zig
@@ -10,7 +10,7 @@ const mode_t = std.c.mode_t;
const off_t = std.c.off_t;
const pid_t = std.c.pid_t;
const pthread_attr_t = std.c.pthread_attr_t;
-const sigset_t = std.c.segset_t;
+const sigset_t = std.c.sigset_t;
const timespec = std.c.timespec;
const sf_hdtr = std.c.sf_hdtr;
@@ -23,6 +23,7 @@ pub const mach_port_t = c_uint;
pub const THREAD_STATE_NONE = switch (native_arch) {
.aarch64 => 5,
.x86_64 => 13,
+ else => @compileError("unsupported arch"),
};
pub const EXC = enum(exception_type_t) {
diff --git a/zig/lib/std/crypto/tls.zig b/zig/lib/std/crypto/tls.zig
index b3d0dcb59f..fb1b550e42 100644
--- a/zig/lib/std/crypto/tls.zig
+++ b/zig/lib/std/crypto/tls.zig
@@ -279,8 +279,8 @@ pub const NamedGroup = enum(u16) {
ffdhe8192 = 0x0104,
// Hybrid post-quantum key agreements
- x25519_kyber512d00 = 0xFE30,
- x25519_kyber768d00 = 0x6399,
+ secp256r1_ml_kem256 = 0x11EB,
+ x25519_ml_kem768 = 0x11EC,
_,
};
diff --git a/zig/lib/std/crypto/tls/Client.zig b/zig/lib/std/crypto/tls/Client.zig
index 452ef5d0c5..84dbb2167a 100644
--- a/zig/lib/std/crypto/tls/Client.zig
+++ b/zig/lib/std/crypto/tls/Client.zig
@@ -158,7 +158,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
// Only possible to happen if the private key is all zeroes.
error.IdentityElement => return error.InsufficientEntropy,
};
- const kyber768_kp = crypto.kem.kyber_d00.Kyber768.KeyPair.create(null) catch {};
+ const ml_kem768_kp = crypto.kem.ml_kem.MLKem768.KeyPair.create(null) catch {};
const extensions_payload =
tls.extension(.supported_versions, [_]u8{
@@ -172,7 +172,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
.rsa_pss_rsae_sha512,
.ed25519,
})) ++ tls.extension(.supported_groups, enum_array(tls.NamedGroup, &.{
- .x25519_kyber768d00,
+ .x25519_ml_kem768,
.secp256r1,
.x25519,
})) ++ tls.extension(
@@ -181,8 +181,8 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
array(1, x25519_kp.public_key) ++
int2(@intFromEnum(tls.NamedGroup.secp256r1)) ++
array(1, secp256r1_kp.public_key.toUncompressedSec1()) ++
- int2(@intFromEnum(tls.NamedGroup.x25519_kyber768d00)) ++
- array(1, x25519_kp.public_key ++ kyber768_kp.public_key.toBytes())),
+ int2(@intFromEnum(tls.NamedGroup.x25519_ml_kem768)) ++
+ array(1, x25519_kp.public_key ++ ml_kem768_kp.public_key.toBytes())),
) ++
int2(@intFromEnum(tls.ExtensionType.server_name)) ++
int2(host_len + 5) ++ // byte length of this extension payload
@@ -298,9 +298,9 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
const key_size = extd.decode(u16);
try extd.ensure(key_size);
switch (named_group) {
- .x25519_kyber768d00 => {
+ .x25519_ml_kem768 => {
const xksl = crypto.dh.X25519.public_length;
- const hksl = xksl + crypto.kem.kyber_d00.Kyber768.ciphertext_length;
+ const hksl = xksl + crypto.kem.ml_kem.MLKem768.ciphertext_length;
if (key_size != hksl)
return error.TlsIllegalParameter;
const server_ks = extd.array(hksl);
@@ -308,7 +308,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
shared_key = &((crypto.dh.X25519.scalarmult(
x25519_kp.secret_key,
server_ks[0..xksl].*,
- ) catch return error.TlsDecryptFailure) ++ (kyber768_kp.secret_key.decaps(
+ ) catch return error.TlsDecryptFailure) ++ (ml_kem768_kp.secret_key.decaps(
server_ks[xksl..hksl],
) catch return error.TlsDecryptFailure));
},
diff --git a/zig/lib/std/debug.zig b/zig/lib/std/debug.zig
index fd6676504f..23b005ad49 100644
--- a/zig/lib/std/debug.zig
+++ b/zig/lib/std/debug.zig
@@ -21,6 +21,9 @@ pub const SelfInfo = @import("debug/SelfInfo.zig");
pub const Info = @import("debug/Info.zig");
pub const Coverage = @import("debug/Coverage.zig");
+pub const FormattedPanic = @import("debug/FormattedPanic.zig");
+pub const SimplePanic = @import("debug/SimplePanic.zig");
+
/// Unresolved source locations can be represented with a single `usize` that
/// corresponds to a virtual memory address of the program counter. Combined
/// with debug information, those values can be converted into a resolved
@@ -58,6 +61,7 @@ pub const sys_can_stack_trace = switch (builtin.cpu.arch) {
.mipsel,
.mips64,
.mips64el,
+ .s390x,
=> false,
// `@returnAddress()` in LLVM 10 gives
@@ -408,14 +412,21 @@ pub fn assertReadable(slice: []const volatile u8) void {
for (slice) |*byte| _ = byte.*;
}
+/// By including a call to this function, the caller gains an error return trace
+/// secret parameter, making `@errorReturnTrace()` more useful. This is not
+/// necessary if the function already contains a call to an errorable function
+/// elsewhere.
+pub fn errorReturnTraceHelper() anyerror!void {}
+
+/// Equivalent to `@panic` but with a formatted message.
pub fn panic(comptime format: []const u8, args: anytype) noreturn {
@branchHint(.cold);
-
+ errorReturnTraceHelper() catch unreachable;
panicExtra(@errorReturnTrace(), @returnAddress(), format, args);
}
-/// `panicExtra` is useful when you want to print out an `@errorReturnTrace`
-/// and also print out some values.
+/// Equivalent to `@panic` but with a formatted message, and with an explicitly
+/// provided `@errorReturnTrace` and return address.
pub fn panicExtra(
trace: ?*std.builtin.StackTrace,
ret_addr: ?usize,
@@ -436,7 +447,7 @@ pub fn panicExtra(
break :blk &buf;
},
};
- std.builtin.panic(msg, trace, ret_addr);
+ std.builtin.Panic.call(msg, trace, ret_addr);
}
/// Non-zero whenever the program triggered a panic.
@@ -447,11 +458,70 @@ var panicking = std.atomic.Value(u8).init(0);
/// This is used to catch and handle panics triggered by the panic handler.
threadlocal var panic_stage: usize = 0;
-// `panicImpl` could be useful in implementing a custom panic handler which
-// calls the default handler (on supported platforms)
-pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize, msg: []const u8) noreturn {
+/// Dumps a stack trace to standard error, then aborts.
+pub fn defaultPanic(
+ msg: []const u8,
+ error_return_trace: ?*const std.builtin.StackTrace,
+ first_trace_addr: ?usize,
+) noreturn {
@branchHint(.cold);
+ // For backends that cannot handle the language features depended on by the
+ // default panic handler, we have a simpler panic handler:
+ if (builtin.zig_backend == .stage2_wasm or
+ builtin.zig_backend == .stage2_arm or
+ builtin.zig_backend == .stage2_aarch64 or
+ builtin.zig_backend == .stage2_x86 or
+ (builtin.zig_backend == .stage2_x86_64 and (builtin.target.ofmt != .elf and builtin.target.ofmt != .macho)) or
+ builtin.zig_backend == .stage2_sparc64 or
+ builtin.zig_backend == .stage2_spirv64)
+ {
+ @trap();
+ }
+
+ switch (builtin.os.tag) {
+ .freestanding => {
+ @trap();
+ },
+ .uefi => {
+ const uefi = std.os.uefi;
+
+ var utf16_buffer: [1000]u16 = undefined;
+ const len_minus_3 = std.unicode.utf8ToUtf16Le(&utf16_buffer, msg) catch 0;
+ utf16_buffer[len_minus_3..][0..3].* = .{ '\r', '\n', 0 };
+ const len = len_minus_3 + 3;
+ const exit_msg = utf16_buffer[0 .. len - 1 :0];
+
+ // Output to both std_err and con_out, as std_err is easier
+ // to read in stuff like QEMU at times, but, unlike con_out,
+ // isn't visible on actual hardware if directly booted into
+ inline for ([_]?*uefi.protocol.SimpleTextOutput{ uefi.system_table.std_err, uefi.system_table.con_out }) |o| {
+ if (o) |out| {
+ _ = out.setAttribute(uefi.protocol.SimpleTextOutput.red);
+ _ = out.outputString(exit_msg);
+ _ = out.setAttribute(uefi.protocol.SimpleTextOutput.white);
+ }
+ }
+
+ if (uefi.system_table.boot_services) |bs| {
+ // ExitData buffer must be allocated using boot_services.allocatePool (spec: page 220)
+ const exit_data: []u16 = uefi.raw_pool_allocator.alloc(u16, exit_msg.len + 1) catch @trap();
+ @memcpy(exit_data, exit_msg[0..exit_data.len]); // Includes null terminator.
+ _ = bs.exit(uefi.handle, .Aborted, exit_data.len, exit_data.ptr);
+ }
+ @trap();
+ },
+ .cuda, .amdhsa => std.posix.abort(),
+ .plan9 => {
+ var status: [std.os.plan9.ERRMAX]u8 = undefined;
+ const len = @min(msg.len, status.len - 1);
+ @memcpy(status[0..len], msg[0..len]);
+ status[len] = 0;
+ std.os.plan9.exits(status[0..len :0]);
+ },
+ else => {},
+ }
+
if (enable_segfault_handler) {
// If a segfault happens while panicking, we want it to actually segfault, not trigger
// the handler.
@@ -465,7 +535,6 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
_ = panicking.fetchAdd(1, .seq_cst);
- // Make sure to release the mutex when done
{
lockStdErr();
defer unlockStdErr();
@@ -478,10 +547,9 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
stderr.print("thread {} panic: ", .{current_thread_id}) catch posix.abort();
}
stderr.print("{s}\n", .{msg}) catch posix.abort();
- if (trace) |t| {
- dumpStackTrace(t.*);
- }
- dumpCurrentStackTrace(first_trace_addr);
+
+ if (error_return_trace) |t| dumpStackTrace(t.*);
+ dumpCurrentStackTrace(first_trace_addr orelse @returnAddress());
}
waitForOtherThreadToFinishPanicking();
@@ -489,15 +557,12 @@ pub fn panicImpl(trace: ?*const std.builtin.StackTrace, first_trace_addr: ?usize
1 => {
panic_stage = 2;
- // A panic happened while trying to print a previous panic message,
- // we're still holding the mutex but that's fine as we're going to
- // call abort()
- const stderr = io.getStdErr().writer();
- stderr.print("Panicked during a panic. Aborting.\n", .{}) catch posix.abort();
- },
- else => {
- // Panicked while printing "Panicked during a panic."
+ // A panic happened while trying to print a previous panic message.
+ // We're still holding the mutex but that's fine as we're going to
+ // call abort().
+ io.getStdErr().writeAll("aborting due to recursive panic\n") catch {};
},
+ else => {}, // Panicked while printing the recursive panic message.
};
posix.abort();
@@ -1157,7 +1222,7 @@ pub const default_enable_segfault_handler = runtime_safety and have_segfault_han
pub fn maybeEnableSegfaultHandler() void {
if (enable_segfault_handler) {
- std.debug.attachSegfaultHandler();
+ attachSegfaultHandler();
}
}
@@ -1289,46 +1354,29 @@ fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(windows.WIN
}
}
-fn handleSegfaultWindowsExtra(
- info: *windows.EXCEPTION_POINTERS,
- msg: u8,
- label: ?[]const u8,
-) noreturn {
- const exception_address = @intFromPtr(info.ExceptionRecord.ExceptionAddress);
- if (windows.CONTEXT != void) {
- nosuspend switch (panic_stage) {
- 0 => {
- panic_stage = 1;
- _ = panicking.fetchAdd(1, .seq_cst);
-
- {
- lockStdErr();
- defer unlockStdErr();
-
- dumpSegfaultInfoWindows(info, msg, label);
- }
+fn handleSegfaultWindowsExtra(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) noreturn {
+ comptime assert(windows.CONTEXT != void);
+ nosuspend switch (panic_stage) {
+ 0 => {
+ panic_stage = 1;
+ _ = panicking.fetchAdd(1, .seq_cst);
+
+ {
+ lockStdErr();
+ defer unlockStdErr();
- waitForOtherThreadToFinishPanicking();
- },
- else => {
- // panic mutex already locked
dumpSegfaultInfoWindows(info, msg, label);
- },
- };
- posix.abort();
- } else {
- switch (msg) {
- 0 => panicImpl(null, exception_address, "{s}", label.?),
- 1 => {
- const format_item = "Segmentation fault at address 0x{x}";
- var buf: [format_item.len + 64]u8 = undefined; // 64 is arbitrary, but sufficiently large
- const to_print = std.fmt.bufPrint(buf[0..buf.len], format_item, .{info.ExceptionRecord.ExceptionInformation[1]}) catch unreachable;
- panicImpl(null, exception_address, to_print);
- },
- 2 => panicImpl(null, exception_address, "Illegal Instruction"),
- else => unreachable,
- }
- }
+ }
+
+ waitForOtherThreadToFinishPanicking();
+ },
+ 1 => {
+ panic_stage = 2;
+ io.getStdErr().writeAll("aborting due to recursive panic\n") catch {};
+ },
+ else => {},
+ };
+ posix.abort();
}
fn dumpSegfaultInfoWindows(info: *windows.EXCEPTION_POINTERS, msg: u8, label: ?[]const u8) void {
@@ -1347,7 +1395,7 @@ pub fn dumpStackPointerAddr(prefix: []const u8) void {
const sp = asm (""
: [argc] "={rsp}" (-> usize),
);
- std.debug.print("{s} sp = 0x{x}\n", .{ prefix, sp });
+ print("{s} sp = 0x{x}\n", .{ prefix, sp });
}
test "manage resources correctly" {
diff --git a/zig/lib/std/debug/FormattedPanic.zig b/zig/lib/std/debug/FormattedPanic.zig
new file mode 100644
index 0000000000..0ad6ea696c
--- /dev/null
+++ b/zig/lib/std/debug/FormattedPanic.zig
@@ -0,0 +1,45 @@
+//! This namespace is the default one used by the Zig compiler to emit various
+//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
+//!
+//! Since Zig does not have interfaces, this file serves as an example template
+//! for users to provide their own alternative panic handling.
+//!
+//! As an alternative, see `std.debug.SimplePanic`.
+
+const std = @import("../std.zig");
+
+/// Dumps a stack trace to standard error, then aborts.
+///
+/// Explicit calls to `@panic` lower to calling this function.
+pub const call: fn ([]const u8, ?*std.builtin.StackTrace, ?usize) noreturn = std.debug.defaultPanic;
+
+pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "sentinel mismatch: expected {any}, found {any}", .{
+ expected, found,
+ });
+}
+
+pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(ert, @returnAddress(), "attempt to unwrap error: {s}", .{@errorName(err)});
+}
+
+pub fn outOfBounds(index: usize, len: usize) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "index out of bounds: index {d}, len {d}", .{ index, len });
+}
+
+pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "start index {d} is larger than end index {d}", .{ start, end });
+}
+
+pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
+ @branchHint(.cold);
+ std.debug.panicExtra(null, @returnAddress(), "access of union field '{s}' while field '{s}' is active", .{
+ @tagName(accessed), @tagName(active),
+ });
+}
+
+pub const messages = std.debug.SimplePanic.messages;
diff --git a/zig/lib/std/debug/SimplePanic.zig b/zig/lib/std/debug/SimplePanic.zig
new file mode 100644
index 0000000000..9685642a5c
--- /dev/null
+++ b/zig/lib/std/debug/SimplePanic.zig
@@ -0,0 +1,86 @@
+//! This namespace is the default one used by the Zig compiler to emit various
+//! kinds of safety panics, due to the logic in `std.builtin.Panic`.
+//!
+//! Since Zig does not have interfaces, this file serves as an example template
+//! for users to provide their own alternative panic handling.
+//!
+//! As an alternative, see `std.debug.FormattedPanic`.
+
+const std = @import("../std.zig");
+
+/// Prints the message to stderr without a newline and then traps.
+///
+/// Explicit calls to `@panic` lower to calling this function.
+pub fn call(msg: []const u8, ert: ?*std.builtin.StackTrace, ra: ?usize) noreturn {
+ @branchHint(.cold);
+ _ = ert;
+ _ = ra;
+ std.debug.lockStdErr();
+ const stderr = std.io.getStdErr();
+ stderr.writeAll(msg) catch {};
+ @trap();
+}
+
+pub fn sentinelMismatch(expected: anytype, found: @TypeOf(expected)) noreturn {
+ _ = found;
+ call("sentinel mismatch", null, null);
+}
+
+pub fn unwrapError(ert: ?*std.builtin.StackTrace, err: anyerror) noreturn {
+ _ = ert;
+ _ = &err;
+ call("attempt to unwrap error", null, null);
+}
+
+pub fn outOfBounds(index: usize, len: usize) noreturn {
+ _ = index;
+ _ = len;
+ call("index out of bounds", null, null);
+}
+
+pub fn startGreaterThanEnd(start: usize, end: usize) noreturn {
+ _ = start;
+ _ = end;
+ call("start index is larger than end index", null, null);
+}
+
+pub fn inactiveUnionField(active: anytype, accessed: @TypeOf(active)) noreturn {
+ _ = accessed;
+ call("access of inactive union field", null, null);
+}
+
+pub const messages = struct {
+ pub const reached_unreachable = "reached unreachable code";
+ pub const unwrap_null = "attempt to use null value";
+ pub const cast_to_null = "cast causes pointer to be null";
+ pub const incorrect_alignment = "incorrect alignment";
+ pub const invalid_error_code = "invalid error code";
+ pub const cast_truncated_data = "integer cast truncated bits";
+ pub const negative_to_unsigned = "attempt to cast negative value to unsigned integer";
+ pub const integer_overflow = "integer overflow";
+ pub const shl_overflow = "left shift overflowed bits";
+ pub const shr_overflow = "right shift overflowed bits";
+ pub const divide_by_zero = "division by zero";
+ pub const exact_division_remainder = "exact division produced remainder";
+ pub const integer_part_out_of_bounds = "integer part of floating point value out of bounds";
+ pub const corrupt_switch = "switch on corrupt value";
+ pub const shift_rhs_too_big = "shift amount is greater than the type size";
+ pub const invalid_enum_value = "invalid enum value";
+ pub const for_len_mismatch = "for loop over objects with non-equal lengths";
+ pub const memcpy_len_mismatch = "@memcpy arguments have non-equal lengths";
+ pub const memcpy_alias = "@memcpy arguments alias";
+ pub const noreturn_returned = "'noreturn' function returned";
+
+ /// To be deleted after zig1.wasm is updated.
+ pub const inactive_union_field = "access of inactive union field";
+ /// To be deleted after zig1.wasm is updated.
+ pub const sentinel_mismatch = "sentinel mismatch";
+ /// To be deleted after zig1.wasm is updated.
+ pub const unwrap_error = "attempt to unwrap error";
+ /// To be deleted after zig1.wasm is updated.
+ pub const index_out_of_bounds = "index out of bounds";
+ /// To be deleted after zig1.wasm is updated.
+ pub const start_index_greater_than_end = "start index is larger than end index";
+ /// To be deleted after zig1.wasm is updated.
+ pub const unreach = reached_unreachable;
+};
diff --git a/zig/lib/std/elf.zig b/zig/lib/std/elf.zig
index d92973c314..792694dffb 100644
--- a/zig/lib/std/elf.zig
+++ b/zig/lib/std/elf.zig
@@ -453,18 +453,27 @@ pub const ET = enum(u16) {
/// Core file
CORE = 4,
+ /// Beginning of OS-specific codes
+ pub const LOOS = 0xfe00;
+
+ /// End of OS-specific codes
+ pub const HIOS = 0xfeff;
+
/// Beginning of processor-specific codes
pub const LOPROC = 0xff00;
- /// Processor-specific
+ /// End of processor-specific codes
pub const HIPROC = 0xffff;
};
/// All integers are native endian.
pub const Header = struct {
+ is_64: bool,
endian: std.builtin.Endian,
+ os_abi: OSABI,
+ abi_version: u8,
+ type: ET,
machine: EM,
- is_64: bool,
entry: u64,
phoff: u64,
shoff: u64,
@@ -501,6 +510,12 @@ pub const Header = struct {
if (!mem.eql(u8, hdr32.e_ident[0..4], MAGIC)) return error.InvalidElfMagic;
if (hdr32.e_ident[EI_VERSION] != 1) return error.InvalidElfVersion;
+ const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
+ ELFCLASS32 => false,
+ ELFCLASS64 => true,
+ else => return error.InvalidElfClass,
+ };
+
const endian: std.builtin.Endian = switch (hdr32.e_ident[EI_DATA]) {
ELFDATA2LSB => .little,
ELFDATA2MSB => .big,
@@ -508,11 +523,15 @@ pub const Header = struct {
};
const need_bswap = endian != native_endian;
- const is_64 = switch (hdr32.e_ident[EI_CLASS]) {
- ELFCLASS32 => false,
- ELFCLASS64 => true,
- else => return error.InvalidElfClass,
- };
+ const os_abi: OSABI = @enumFromInt(hdr32.e_ident[EI_OSABI]);
+
+ // The meaning of this value depends on `os_abi` so just make it available as `u8`.
+ const abi_version = hdr32.e_ident[EI_ABIVERSION];
+
+ const @"type" = if (need_bswap) blk: {
+ const value = @intFromEnum(hdr32.e_type);
+ break :blk @as(ET, @enumFromInt(@byteSwap(value)));
+ } else hdr32.e_type;
const machine = if (need_bswap) blk: {
const value = @intFromEnum(hdr32.e_machine);
@@ -520,9 +539,12 @@ pub const Header = struct {
} else hdr32.e_machine;
return @as(Header, .{
+ .is_64 = is_64,
.endian = endian,
+ .os_abi = os_abi,
+ .abi_version = abi_version,
+ .type = @"type",
.machine = machine,
- .is_64 = is_64,
.entry = int(is_64, need_bswap, hdr32.e_entry, hdr64.e_entry),
.phoff = int(is_64, need_bswap, hdr32.e_phoff, hdr64.e_phoff),
.shoff = int(is_64, need_bswap, hdr32.e_shoff, hdr64.e_shoff),
@@ -637,7 +659,7 @@ pub fn SectionHeaderIterator(comptime ParseSource: anytype) type {
};
}
-pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
+fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @TypeOf(int_64) {
if (is_64) {
if (need_bswap) {
return @byteSwap(int_64);
@@ -649,7 +671,7 @@ pub fn int(is_64: bool, need_bswap: bool, int_32: anytype, int_64: anytype) @Typ
}
}
-pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
+fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
if (need_bswap) {
return @byteSwap(int_32);
} else {
@@ -657,21 +679,24 @@ pub fn int32(need_bswap: bool, int_32: anytype, comptime Int64: anytype) Int64 {
}
}
-pub const EI_NIDENT = 16;
-
-pub const EI_CLASS = 4;
pub const ELFCLASSNONE = 0;
pub const ELFCLASS32 = 1;
pub const ELFCLASS64 = 2;
pub const ELFCLASSNUM = 3;
-pub const EI_DATA = 5;
pub const ELFDATANONE = 0;
pub const ELFDATA2LSB = 1;
pub const ELFDATA2MSB = 2;
pub const ELFDATANUM = 3;
+pub const EI_CLASS = 4;
+pub const EI_DATA = 5;
pub const EI_VERSION = 6;
+pub const EI_OSABI = 7;
+pub const EI_ABIVERSION = 8;
+pub const EI_PAD = 9;
+
+pub const EI_NIDENT = 16;
pub const Elf32_Half = u16;
pub const Elf64_Half = u16;
@@ -1094,6 +1119,57 @@ pub const Addr = switch (@sizeOf(usize)) {
};
pub const Half = u16;
+pub const OSABI = enum(u8) {
+ /// UNIX System V ABI
+ NONE = 0,
+ /// HP-UX operating system
+ HPUX = 1,
+ /// NetBSD
+ NETBSD = 2,
+ /// GNU (Hurd/Linux)
+ GNU = 3,
+ /// Solaris
+ SOLARIS = 6,
+ /// AIX
+ AIX = 7,
+ /// IRIX
+ IRIX = 8,
+ /// FreeBSD
+ FREEBSD = 9,
+ /// TRU64 UNIX
+ TRU64 = 10,
+ /// Novell Modesto
+ MODESTO = 11,
+ /// OpenBSD
+ OPENBSD = 12,
+ /// OpenVMS
+ OPENVMS = 13,
+ /// Hewlett-Packard Non-Stop Kernel
+ NSK = 14,
+ /// AROS
+ AROS = 15,
+ /// FenixOS
+ FENIXOS = 16,
+ /// Nuxi CloudABI
+ CLOUDABI = 17,
+ /// Stratus Technologies OpenVOS
+ OPENVOS = 18,
+ /// NVIDIA CUDA architecture
+ CUDA = 51,
+ /// AMD HSA Runtime
+ AMDGPU_HSA = 64,
+ /// AMD PAL Runtime
+ AMDGPU_PAL = 65,
+ /// AMD Mesa3D Runtime
+ AMDGPU_MESA3D = 66,
+ /// ARM
+ ARM = 97,
+ /// Standalone (embedded) application
+ STANDALONE = 255,
+
+ _,
+};
+
/// Machine architectures.
///
/// See current registered ELF machine architectures at:
@@ -1552,6 +1628,14 @@ pub const EM = enum(u16) {
/// Adapteva's Epiphany architecture
ADAPTEVA_EPIPHANY = 0x1223,
+ /// Parallax Propeller (P1)
+ /// This value is an unofficial ELF value used in: https://github.com/parallaxinc/propgcc
+ PROPELLER = 0x5072,
+
+ /// Parallax Propeller 2 (P2)
+ /// This value is an unofficial ELF value used in: https://github.com/ne75/llvm-project
+ PROPELLER2 = 300,
+
_,
};
diff --git a/zig/lib/std/fmt.zig b/zig/lib/std/fmt.zig
index 12504b6872..123122fd56 100644
--- a/zig/lib/std/fmt.zig
+++ b/zig/lib/std/fmt.zig
@@ -1197,7 +1197,7 @@ pub fn formatInt(
if (base == 10) {
while (a >= 100) : (a = @divTrunc(a, 100)) {
index -= 2;
- buf[index..][0..2].* = digits2(@as(usize, @intCast(a % 100)));
+ buf[index..][0..2].* = digits2(@intCast(a % 100));
}
if (a < 10) {
@@ -1205,13 +1205,13 @@ pub fn formatInt(
buf[index] = '0' + @as(u8, @intCast(a));
} else {
index -= 2;
- buf[index..][0..2].* = digits2(@as(usize, @intCast(a)));
+ buf[index..][0..2].* = digits2(@intCast(a));
}
} else {
while (true) {
const digit = a % base;
index -= 1;
- buf[index] = digitToChar(@as(u8, @intCast(digit)), case);
+ buf[index] = digitToChar(@intCast(digit), case);
a /= base;
if (a == 0) break;
}
@@ -1242,11 +1242,7 @@ pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options
// Converts values in the range [0, 100) to a string.
pub fn digits2(value: usize) [2]u8 {
- return ("0001020304050607080910111213141516171819" ++
- "2021222324252627282930313233343536373839" ++
- "4041424344454647484950515253545556575859" ++
- "6061626364656667686970717273747576777879" ++
- "8081828384858687888990919293949596979899")[value * 2 ..][0..2].*;
+ return "00010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899"[value * 2 ..][0..2].*;
}
const FormatDurationData = struct {
diff --git a/zig/lib/std/fs/Dir.zig b/zig/lib/std/fs/Dir.zig
index 2e84d1097f..d504ecb0c4 100644
--- a/zig/lib/std/fs/Dir.zig
+++ b/zig/lib/std/fs/Dir.zig
@@ -804,11 +804,14 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
}
if (native_os == .wasi and !builtin.link_libc) {
var base: std.os.wasi.rights_t = .{};
+ // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or FD_WRITE
+ // is also set.
if (flags.isRead()) {
base.FD_READ = true;
base.FD_TELL = true;
base.FD_SEEK = true;
base.FD_FILESTAT_GET = true;
+ base.POLL_FD_READWRITE = true;
}
if (flags.isWrite()) {
base.FD_WRITE = true;
@@ -821,6 +824,7 @@ pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.Ope
base.FD_ADVISE = true;
base.FD_FILESTAT_SET_TIMES = true;
base.FD_FILESTAT_SET_SIZE = true;
+ base.POLL_FD_READWRITE = true;
}
const fd = try posix.openatWasi(self.fd, sub_path, .{}, .{}, .{}, base, .{});
return .{ .handle = fd };
@@ -982,6 +986,9 @@ pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File
.FD_FILESTAT_SET_TIMES = true,
.FD_FILESTAT_SET_SIZE = true,
.FD_FILESTAT_GET = true,
+ // POLL_FD_READWRITE only grants extra rights if the corresponding FD_READ and/or
+ // FD_WRITE is also set.
+ .POLL_FD_READWRITE = true,
}, .{}),
};
}
diff --git a/zig/lib/std/fs/test.zig b/zig/lib/std/fs/test.zig
index b0810f81a5..618323dce3 100644
--- a/zig/lib/std/fs/test.zig
+++ b/zig/lib/std/fs/test.zig
@@ -1647,6 +1647,36 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" {
try testing.expectError(error.WouldBlock, file2);
}
+test "read from locked file" {
+ try testWithAllSupportedPathTypes(struct {
+ fn impl(ctx: *TestContext) !void {
+ const filename = try ctx.transformPath("read_lock_file_test.txt");
+
+ {
+ const f = try ctx.dir.createFile(filename, .{ .read = true });
+ defer f.close();
+ var buffer: [1]u8 = undefined;
+ _ = try f.readAll(&buffer);
+ }
+ {
+ const f = try ctx.dir.createFile(filename, .{
+ .read = true,
+ .lock = .exclusive,
+ });
+ defer f.close();
+ const f2 = try ctx.dir.openFile(filename, .{});
+ defer f2.close();
+ var buffer: [1]u8 = undefined;
+ if (builtin.os.tag == .windows) {
+ try std.testing.expectError(error.LockViolation, f2.readAll(&buffer));
+ } else {
+ try std.testing.expectEqual(0, f2.readAll(&buffer));
+ }
+ }
+ }
+ }.impl);
+}
+
test "walker" {
if (native_os == .wasi and builtin.link_libc) return error.SkipZigTest;
diff --git a/zig/lib/std/heap.zig b/zig/lib/std/heap.zig
index 18332c79a8..3d19d8daa6 100644
--- a/zig/lib/std/heap.zig
+++ b/zig/lib/std/heap.zig
@@ -501,8 +501,6 @@ pub const FixedBufferAllocator = struct {
}
};
-pub const ThreadSafeFixedBufferAllocator = @compileError("ThreadSafeFixedBufferAllocator has been replaced with `threadSafeAllocator` on FixedBufferAllocator");
-
/// Returns a `StackFallbackAllocator` allocating using either a
/// `FixedBufferAllocator` on an array of size `size` and falling back to
/// `fallback_allocator` if that fails.
diff --git a/zig/lib/std/http/test.zig b/zig/lib/std/http/test.zig
index caeed0e1ea..dc944fbabb 100644
--- a/zig/lib/std/http/test.zig
+++ b/zig/lib/std/http/test.zig
@@ -230,6 +230,11 @@ test "echo content server" {
}
test "Server.Request.respondStreaming non-chunked, unknown content-length" {
+ if (builtin.os.tag == .windows) {
+ // https://github.com/ziglang/zig/issues/21457
+ return error.SkipZigTest;
+ }
+
// In this case, the response is expected to stream until the connection is
// closed, indicating the end of the body.
const test_server = try createTestServer(struct {
diff --git a/zig/lib/std/io.zig b/zig/lib/std/io.zig
index 6455693d67..0a9b2bf867 100644
--- a/zig/lib/std/io.zig
+++ b/zig/lib/std/io.zig
@@ -442,6 +442,7 @@ pub fn poll(
.overlapped = [1]windows.OVERLAPPED{
mem.zeroes(windows.OVERLAPPED),
} ** enum_fields.len,
+ .small_bufs = undefined,
.active = .{
.count = 0,
.handles_buf = undefined,
@@ -481,6 +482,7 @@ pub fn Poller(comptime StreamEnum: type) type {
windows: if (is_windows) struct {
first_read_done: bool,
overlapped: [enum_fields.len]windows.OVERLAPPED,
+ small_bufs: [enum_fields.len][128]u8,
active: struct {
count: math.IntFittingRange(0, enum_fields.len),
handles_buf: [enum_fields.len]windows.HANDLE,
@@ -534,24 +536,31 @@ pub fn Poller(comptime StreamEnum: type) type {
const bump_amt = 512;
if (!self.windows.first_read_done) {
- // Windows Async IO requires an initial call to ReadFile before waiting on the handle
+ var already_read_data = false;
for (0..enum_fields.len) |i| {
const handle = self.windows.active.handles_buf[i];
- switch (try windowsAsyncRead(
+ switch (try windowsAsyncReadToFifoAndQueueSmallRead(
handle,
&self.windows.overlapped[i],
&self.fifos[i],
+ &self.windows.small_bufs[i],
bump_amt,
)) {
- .pending => {
+ .populated, .empty => |state| {
+ if (state == .populated) already_read_data = true;
self.windows.active.handles_buf[self.windows.active.count] = handle;
self.windows.active.stream_map[self.windows.active.count] = @as(StreamEnum, @enumFromInt(i));
self.windows.active.count += 1;
},
.closed => {}, // don't add to the wait_objects list
+ .closed_populated => {
+ // don't add to the wait_objects list, but we did already get data
+ already_read_data = true;
+ },
}
}
self.windows.first_read_done = true;
+ if (already_read_data) return true;
}
while (true) {
@@ -576,32 +585,35 @@ pub fn Poller(comptime StreamEnum: type) type {
const active_idx = status - windows.WAIT_OBJECT_0;
- const handle = self.windows.active.handles_buf[active_idx];
const stream_idx = @intFromEnum(self.windows.active.stream_map[active_idx]);
- var read_bytes: u32 = undefined;
- if (0 == windows.kernel32.GetOverlappedResult(
- handle,
- &self.windows.overlapped[stream_idx],
- &read_bytes,
- 0,
- )) switch (windows.GetLastError()) {
- .BROKEN_PIPE => {
+ const handle = self.windows.active.handles_buf[active_idx];
+
+ const overlapped = &self.windows.overlapped[stream_idx];
+ const stream_fifo = &self.fifos[stream_idx];
+ const small_buf = &self.windows.small_bufs[stream_idx];
+
+ const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
+ .success => |n| n,
+ .closed => {
self.windows.active.removeAt(active_idx);
continue;
},
- else => |err| return windows.unexpectedError(err),
+ .aborted => unreachable,
};
+ try stream_fifo.write(small_buf[0..num_bytes_read]);
- self.fifos[stream_idx].update(read_bytes);
-
- switch (try windowsAsyncRead(
+ switch (try windowsAsyncReadToFifoAndQueueSmallRead(
handle,
- &self.windows.overlapped[stream_idx],
- &self.fifos[stream_idx],
+ overlapped,
+ stream_fifo,
+ small_buf,
bump_amt,
)) {
- .pending => {},
- .closed => self.windows.active.removeAt(active_idx),
+ .empty => {}, // irrelevant, we already got data from the small buffer
+ .populated => {},
+ .closed,
+ .closed_populated, // identical, since we already got data from the small buffer
+ => self.windows.active.removeAt(active_idx),
}
return true;
}
@@ -654,25 +666,145 @@ pub fn Poller(comptime StreamEnum: type) type {
};
}
-fn windowsAsyncRead(
+/// The `ReadFile` docuementation states that `lpNumberOfBytesRead` does not have a meaningful
+/// result when using overlapped I/O, but also that it cannot be `null` on Windows 7. For
+/// compatibility, we point it to this dummy variables, which we never otherwise access.
+/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
+var win_dummy_bytes_read: u32 = undefined;
+
+/// Read as much data as possible from `handle` with `overlapped`, and write it to the FIFO. Before
+/// returning, queue a read into `small_buf` so that `WaitForMultipleObjects` returns when more data
+/// is available. `handle` must have no pending asynchronous operation.
+fn windowsAsyncReadToFifoAndQueueSmallRead(
handle: windows.HANDLE,
overlapped: *windows.OVERLAPPED,
fifo: *PollFifo,
+ small_buf: *[128]u8,
bump_amt: usize,
-) !enum { pending, closed } {
+) !enum { empty, populated, closed_populated, closed } {
+ var read_any_data = false;
while (true) {
- const buf = try fifo.writableWithSize(bump_amt);
- var read_bytes: u32 = undefined;
- const read_result = windows.kernel32.ReadFile(handle, buf.ptr, math.cast(u32, buf.len) orelse math.maxInt(u32), &read_bytes, overlapped);
- if (read_result == 0) return switch (windows.GetLastError()) {
- .IO_PENDING => .pending,
- .BROKEN_PIPE => .closed,
- else => |err| windows.unexpectedError(err),
+ const fifo_read_pending = while (true) {
+ const buf = try fifo.writableWithSize(bump_amt);
+ const buf_len = math.cast(u32, buf.len) orelse math.maxInt(u32);
+
+ if (0 == windows.kernel32.ReadFile(
+ handle,
+ buf.ptr,
+ buf_len,
+ &win_dummy_bytes_read,
+ overlapped,
+ )) switch (windows.GetLastError()) {
+ .IO_PENDING => break true,
+ .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
+ else => |err| return windows.unexpectedError(err),
+ };
+
+ const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
+ .success => |n| n,
+ .closed => return if (read_any_data) .closed_populated else .closed,
+ .aborted => unreachable,
+ };
+
+ read_any_data = true;
+ fifo.update(num_bytes_read);
+
+ if (num_bytes_read == buf_len) {
+ // We filled the buffer, so there's probably more data available.
+ continue;
+ } else {
+ // We didn't fill the buffer, so assume we're out of data.
+ // There is no pending read.
+ break false;
+ }
};
- fifo.update(read_bytes);
+
+ if (fifo_read_pending) cancel_read: {
+ // Cancel the pending read into the FIFO.
+ _ = windows.kernel32.CancelIo(handle);
+
+ // We have to wait for the handle to be signalled, i.e. for the cancellation to complete.
+ switch (windows.kernel32.WaitForSingleObject(handle, windows.INFINITE)) {
+ windows.WAIT_OBJECT_0 => {},
+ windows.WAIT_FAILED => return windows.unexpectedError(windows.GetLastError()),
+ else => unreachable,
+ }
+
+ // If it completed before we canceled, make sure to tell the FIFO!
+ const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, true)) {
+ .success => |n| n,
+ .closed => return if (read_any_data) .closed_populated else .closed,
+ .aborted => break :cancel_read,
+ };
+ read_any_data = true;
+ fifo.update(num_bytes_read);
+ }
+
+ // Try to queue the 1-byte read.
+ if (0 == windows.kernel32.ReadFile(
+ handle,
+ small_buf,
+ small_buf.len,
+ &win_dummy_bytes_read,
+ overlapped,
+ )) switch (windows.GetLastError()) {
+ .IO_PENDING => {
+ // 1-byte read pending as intended
+ return if (read_any_data) .populated else .empty;
+ },
+ .BROKEN_PIPE => return if (read_any_data) .closed_populated else .closed,
+ else => |err| return windows.unexpectedError(err),
+ };
+
+ // We got data back this time. Write it to the FIFO and run the main loop again.
+ const num_bytes_read = switch (try windowsGetReadResult(handle, overlapped, false)) {
+ .success => |n| n,
+ .closed => return if (read_any_data) .closed_populated else .closed,
+ .aborted => unreachable,
+ };
+ try fifo.write(small_buf[0..num_bytes_read]);
+ read_any_data = true;
}
}
+/// Simple wrapper around `GetOverlappedResult` to determine the result of a `ReadFile` operation.
+/// If `!allow_aborted`, then `aborted` is never returned (`OPERATION_ABORTED` is considered unexpected).
+///
+/// The `ReadFile` documentation states that the number of bytes read by an overlapped `ReadFile` must be determined using `GetOverlappedResult`, even if the
+/// operation immediately returns data:
+/// "Use NULL for [lpNumberOfBytesRead] if this is an asynchronous operation to avoid potentially
+/// erroneous results."
+/// "If `hFile` was opened with `FILE_FLAG_OVERLAPPED`, the following conditions are in effect: [...]
+/// The lpNumberOfBytesRead parameter should be set to NULL. Use the GetOverlappedResult function to
+/// get the actual number of bytes read."
+/// See: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile
+fn windowsGetReadResult(
+ handle: windows.HANDLE,
+ overlapped: *windows.OVERLAPPED,
+ allow_aborted: bool,
+) !union(enum) {
+ success: u32,
+ closed,
+ aborted,
+} {
+ var num_bytes_read: u32 = undefined;
+ if (0 == windows.kernel32.GetOverlappedResult(
+ handle,
+ overlapped,
+ &num_bytes_read,
+ 0,
+ )) switch (windows.GetLastError()) {
+ .BROKEN_PIPE => return .closed,
+ .OPERATION_ABORTED => |err| if (allow_aborted) {
+ return .aborted;
+ } else {
+ return windows.unexpectedError(err);
+ },
+ else => |err| return windows.unexpectedError(err),
+ };
+ return .{ .success = num_bytes_read };
+}
+
/// Given an enum, returns a struct with fields of that enum, each field
/// representing an I/O stream for polling.
pub fn PollFiles(comptime StreamEnum: type) type {
diff --git a/zig/lib/std/io/Reader/test.zig b/zig/lib/std/io/Reader/test.zig
index e92d1ec4db..30f0e1269c 100644
--- a/zig/lib/std/io/Reader/test.zig
+++ b/zig/lib/std/io/Reader/test.zig
@@ -1,3 +1,4 @@
+const builtin = @import("builtin");
const std = @import("../../std.zig");
const testing = std.testing;
@@ -11,7 +12,7 @@ test "Reader" {
b = 99,
c = 2,
d = 3,
- }, undefined)) == .c);
+ }, builtin.cpu.arch.endian())) == .c);
try testing.expectError(error.EndOfStream, reader.readByte());
}
diff --git a/zig/lib/std/io/buffered_reader.zig b/zig/lib/std/io/buffered_reader.zig
index ca132202a7..bcf54fb882 100644
--- a/zig/lib/std/io/buffered_reader.zig
+++ b/zig/lib/std/io/buffered_reader.zig
@@ -17,26 +17,27 @@ pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) ty
const Self = @This();
pub fn read(self: *Self, dest: []u8) Error!usize {
- var dest_index: usize = 0;
-
- while (dest_index < dest.len) {
- const written = @min(dest.len - dest_index, self.end - self.start);
- @memcpy(dest[dest_index..][0..written], self.buf[self.start..][0..written]);
- if (written == 0) {
- // buf empty, fill it
- const n = try self.unbuffered_reader.read(self.buf[0..]);
- if (n == 0) {
- // reading from the unbuffered stream returned nothing
- // so we have nothing left to read.
- return dest_index;
- }
- self.start = 0;
- self.end = n;
- }
- self.start += written;
- dest_index += written;
+ // First try reading from the already buffered data onto the destination.
+ const current = self.buf[self.start..self.end];
+ if (current.len != 0) {
+ const to_transfer = @min(current.len, dest.len);
+ @memcpy(dest[0..to_transfer], current[0..to_transfer]);
+ self.start += to_transfer;
+ return to_transfer;
}
- return dest.len;
+
+ // If dest is large, read from the unbuffered reader directly into the destination.
+ if (dest.len >= buffer_size) {
+ return self.unbuffered_reader.read(dest);
+ }
+
+ // If dest is small, read from the unbuffered reader into our own internal buffer,
+ // and then transfer to destination.
+ self.end = try self.unbuffered_reader.read(&self.buf);
+ const to_transfer = @min(self.end, dest.len);
+ @memcpy(dest[0..to_transfer], self.buf[0..to_transfer]);
+ self.start = to_transfer;
+ return to_transfer;
}
pub fn reader(self: *Self) Reader {
@@ -134,12 +135,13 @@ test "Block" {
var test_buf_reader: BufferedReader(4, BlockReader) = .{
.unbuffered_reader = BlockReader.init(block, 2),
};
+ const reader = test_buf_reader.reader();
var out_buf: [4]u8 = undefined;
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, block);
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, block);
- try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
+ try testing.expectEqual(try reader.readAll(&out_buf), 0);
}
// len out < block
@@ -147,14 +149,15 @@ test "Block" {
var test_buf_reader: BufferedReader(4, BlockReader) = .{
.unbuffered_reader = BlockReader.init(block, 2),
};
+ const reader = test_buf_reader.reader();
var out_buf: [3]u8 = undefined;
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, "012");
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, "301");
- const n = try test_buf_reader.read(&out_buf);
+ const n = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, out_buf[0..n], "23");
- try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
+ try testing.expectEqual(try reader.readAll(&out_buf), 0);
}
// len out > block
@@ -162,12 +165,13 @@ test "Block" {
var test_buf_reader: BufferedReader(4, BlockReader) = .{
.unbuffered_reader = BlockReader.init(block, 2),
};
+ const reader = test_buf_reader.reader();
var out_buf: [5]u8 = undefined;
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, "01230");
- const n = try test_buf_reader.read(&out_buf);
+ const n = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, out_buf[0..n], "123");
- try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
+ try testing.expectEqual(try reader.readAll(&out_buf), 0);
}
// len out == 0
@@ -175,8 +179,9 @@ test "Block" {
var test_buf_reader: BufferedReader(4, BlockReader) = .{
.unbuffered_reader = BlockReader.init(block, 2),
};
+ const reader = test_buf_reader.reader();
var out_buf: [0]u8 = undefined;
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, "");
}
@@ -185,11 +190,12 @@ test "Block" {
var test_buf_reader: BufferedReader(5, BlockReader) = .{
.unbuffered_reader = BlockReader.init(block, 2),
};
+ const reader = test_buf_reader.reader();
var out_buf: [4]u8 = undefined;
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, block);
- _ = try test_buf_reader.read(&out_buf);
+ _ = try reader.readAll(&out_buf);
try testing.expectEqualSlices(u8, &out_buf, block);
- try testing.expectEqual(try test_buf_reader.read(&out_buf), 0);
+ try testing.expectEqual(try reader.readAll(&out_buf), 0);
}
}
diff --git a/zig/lib/std/math/float.zig b/zig/lib/std/math/float.zig
index a10332f863..b7269b3ba9 100644
--- a/zig/lib/std/math/float.zig
+++ b/zig/lib/std/math/float.zig
@@ -172,9 +172,6 @@ test nan {
}
test snan {
- // TODO: https://github.com/ziglang/zig/issues/14366
- if (builtin.zig_backend == .stage2_llvm and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
-
const snan_u16: u16 = 0x7D00;
const snan_u32: u32 = 0x7FA00000;
const snan_u64: u64 = 0x7FF4000000000000;
diff --git a/zig/lib/std/math/gcd.zig b/zig/lib/std/math/gcd.zig
index 36ba8e3614..16ca7846f1 100644
--- a/zig/lib/std/math/gcd.zig
+++ b/zig/lib/std/math/gcd.zig
@@ -1,41 +1,50 @@
//! Greatest common divisor (https://mathworld.wolfram.com/GreatestCommonDivisor.html)
const std = @import("std");
-const expectEqual = std.testing.expectEqual;
-/// Returns the greatest common divisor (GCD) of two unsigned integers (a and b) which are not both zero.
-/// For example, the GCD of 8 and 12 is 4, that is, gcd(8, 12) == 4.
+/// Returns the greatest common divisor (GCD) of two unsigned integers (`a` and `b`) which are not both zero.
+/// For example, the GCD of `8` and `12` is `4`, that is, `gcd(8, 12) == 4`.
pub fn gcd(a: anytype, b: anytype) @TypeOf(a, b) {
-
- // only unsigned integers are allowed and not both must be zero
- comptime switch (@typeInfo(@TypeOf(a, b))) {
- .int => |int| std.debug.assert(int.signedness == .unsigned),
- .comptime_int => {
- std.debug.assert(a >= 0);
- std.debug.assert(b >= 0);
- },
- else => unreachable,
+ const N = switch (@TypeOf(a, b)) {
+ // convert comptime_int to some sized int type for @ctz
+ comptime_int => std.math.IntFittingRange(@min(a, b), @max(a, b)),
+ else => |T| T,
};
+ if (@typeInfo(N) != .int or @typeInfo(N).int.signedness != .unsigned) {
+ @compileError("`a` and `b` must be usigned integers");
+ }
+
+ // using an optimised form of Stein's algorithm:
+ // https://en.wikipedia.org/wiki/Binary_GCD_algorithm
std.debug.assert(a != 0 or b != 0);
- // if one of them is zero, the other is returned
if (a == 0) return b;
if (b == 0) return a;
- // init vars
- var x: @TypeOf(a, b) = a;
- var y: @TypeOf(a, b) = b;
- var m: @TypeOf(a, b) = a;
+ var x: N = a;
+ var y: N = b;
- // using the Euclidean algorithm (https://mathworld.wolfram.com/EuclideanAlgorithm.html)
- while (y != 0) {
- m = x % y;
- x = y;
- y = m;
+ const xz = @ctz(x);
+ const yz = @ctz(y);
+ const shift = @min(xz, yz);
+ x >>= @intCast(xz);
+ y >>= @intCast(yz);
+
+ var diff = y -% x;
+ while (diff != 0) : (diff = y -% x) {
+ // ctz is invariant under negation, we
+ // put it here to ease data dependencies,
+ // makes the CPU happy.
+ const zeros = @ctz(diff);
+ if (x > y) diff = -%diff;
+ y = @min(x, y);
+ x = diff >> @intCast(zeros);
}
- return x;
+ return y << @intCast(shift);
}
-test "gcd" {
+test gcd {
+ const expectEqual = std.testing.expectEqual;
+
try expectEqual(gcd(0, 5), 5);
try expectEqual(gcd(5, 0), 5);
try expectEqual(gcd(8, 12), 4);
@@ -45,4 +54,6 @@ test "gcd" {
try expectEqual(gcd(49865, 69811), 9973);
try expectEqual(gcd(300_000, 2_300_000), 100_000);
try expectEqual(gcd(90000000_000_000_000_000_000, 2), 2);
+ try expectEqual(gcd(@as(u80, 90000000_000_000_000_000_000), 2), 2);
+ try expectEqual(gcd(300_000, @as(u32, 2_300_000)), 100_000);
}
diff --git a/zig/lib/std/math/isnan.zig b/zig/lib/std/math/isnan.zig
index cb929e5890..a85100ba90 100644
--- a/zig/lib/std/math/isnan.zig
+++ b/zig/lib/std/math/isnan.zig
@@ -32,7 +32,13 @@ test isSignalNan {
// TODO: Signalling NaN values get converted to quiet NaN values in
// some cases where they shouldn't such that this can fail.
// See https://github.com/ziglang/zig/issues/14366
- // try expect(isSignalNan(math.snan(T)));
+ if (!builtin.cpu.arch.isArmOrThumb() and
+ !builtin.cpu.arch.isAARCH64() and
+ !builtin.cpu.arch.isPowerPC() and
+ builtin.zig_backend != .stage2_c)
+ {
+ try expect(isSignalNan(math.snan(T)));
+ }
try expect(!isSignalNan(math.nan(T)));
try expect(!isSignalNan(@as(T, 1.0)));
try expect(!isSignalNan(math.inf(T)));
diff --git a/zig/lib/std/mem.zig b/zig/lib/std/mem.zig
index b4580b1aa4..d458e26989 100644
--- a/zig/lib/std/mem.zig
+++ b/zig/lib/std/mem.zig
@@ -4334,8 +4334,6 @@ pub fn alignForwardLog2(addr: usize, log2_alignment: u8) usize {
return alignForward(usize, addr, alignment);
}
-pub const alignForwardGeneric = @compileError("renamed to alignForward");
-
/// Force an evaluation of the expression; this tries to prevent
/// the compiler from optimizing the computation away even if the
/// result eventually gets discarded.
@@ -4459,8 +4457,6 @@ pub fn alignBackward(comptime T: type, addr: T, alignment: T) T {
return addr & ~(alignment - 1);
}
-pub const alignBackwardGeneric = @compileError("renamed to alignBackward");
-
/// Returns whether `alignment` is a valid alignment, meaning it is
/// a positive power of 2.
pub fn isValidAlign(alignment: usize) bool {
diff --git a/zig/lib/std/meta.zig b/zig/lib/std/meta.zig
index e7ea5b5f0e..ea81c87648 100644
--- a/zig/lib/std/meta.zig
+++ b/zig/lib/std/meta.zig
@@ -240,8 +240,6 @@ pub fn Sentinel(comptime T: type, comptime sentinel_val: Elem(T)) type {
@compileError("Unable to derive a sentinel pointer type from " ++ @typeName(T));
}
-pub const assumeSentinel = @compileError("This function has been removed, consider using std.mem.sliceTo() or if needed a @ptrCast()");
-
pub fn containerLayout(comptime T: type) Type.ContainerLayout {
return switch (@typeInfo(T)) {
.@"struct" => |info| info.layout,
@@ -628,7 +626,7 @@ pub fn DeclEnum(comptime T: type) type {
}
return @Type(.{
.@"enum" = .{
- .tag_type = std.math.IntFittingRange(0, fieldInfos.len - 1),
+ .tag_type = std.math.IntFittingRange(0, if (fieldInfos.len == 0) 0 else fieldInfos.len - 1),
.fields = &enumDecls,
.decls = &decls,
.is_exhaustive = true,
@@ -654,9 +652,12 @@ test DeclEnum {
pub const b: void = {};
pub const c: f32 = 0;
};
+ const D = struct {};
+
try expectEqualEnum(enum { a }, DeclEnum(A));
try expectEqualEnum(enum { a, b, c }, DeclEnum(B));
try expectEqualEnum(enum { a, b, c }, DeclEnum(C));
+ try expectEqualEnum(enum {}, DeclEnum(D));
}
pub fn Tag(comptime T: type) type {
@@ -930,8 +931,6 @@ pub fn fieldIndex(comptime T: type, comptime name: []const u8) ?comptime_int {
return null;
}
-pub const refAllDecls = @compileError("refAllDecls has been moved from std.meta to std.testing");
-
/// Returns a slice of pointers to public declarations of a namespace.
pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const Decl {
const S = struct {
@@ -951,8 +950,6 @@ pub fn declList(comptime Namespace: type, comptime Decl: type) []const *const De
}
}
-pub const IntType = @compileError("replaced by std.meta.Int");
-
pub fn Int(comptime signedness: std.builtin.Signedness, comptime bit_count: u16) type {
return @Type(.{
.int = .{
diff --git a/zig/lib/std/os/linux.zig b/zig/lib/std/os/linux.zig
index 9039acedee..03eef2bb8e 100644
--- a/zig/lib/std/os/linux.zig
+++ b/zig/lib/std/os/linux.zig
@@ -29,16 +29,12 @@ test {
}
}
-const syscall_bits = switch (native_arch) {
- .thumb => @import("linux/thumb.zig"),
- else => arch_bits,
-};
-
const arch_bits = switch (native_arch) {
.x86 => @import("linux/x86.zig"),
.x86_64 => @import("linux/x86_64.zig"),
- .aarch64, .aarch64_be => @import("linux/arm64.zig"),
- .arm, .armeb, .thumb, .thumbeb => @import("linux/arm-eabi.zig"),
+ .aarch64, .aarch64_be => @import("linux/aarch64.zig"),
+ .arm, .armeb, .thumb, .thumbeb => @import("linux/arm.zig"),
+ .hexagon => @import("linux/hexagon.zig"),
.riscv32 => @import("linux/riscv32.zig"),
.riscv64 => @import("linux/riscv64.zig"),
.sparc64 => @import("linux/sparc64.zig"),
@@ -47,11 +43,15 @@ const arch_bits = switch (native_arch) {
.mips64, .mips64el => @import("linux/mips64.zig"),
.powerpc, .powerpcle => @import("linux/powerpc.zig"),
.powerpc64, .powerpc64le => @import("linux/powerpc64.zig"),
+ .s390x => @import("linux/s390x.zig"),
else => struct {
pub const ucontext_t = void;
pub const getcontext = {};
},
};
+
+const syscall_bits = if (native_arch.isThumb()) @import("linux/thumb.zig") else arch_bits;
+
pub const syscall0 = syscall_bits.syscall0;
pub const syscall1 = syscall_bits.syscall1;
pub const syscall2 = syscall_bits.syscall2;
@@ -115,7 +115,7 @@ pub const user_desc = arch_bits.user_desc;
pub const getcontext = arch_bits.getcontext;
pub const tls = @import("linux/tls.zig");
-pub const pie = @import("linux/start_pie.zig");
+pub const pie = @import("linux/pie.zig");
pub const BPF = @import("linux/bpf.zig");
pub const IOCTL = @import("linux/ioctl.zig");
pub const SECCOMP = @import("linux/seccomp.zig");
@@ -276,6 +276,29 @@ pub const MAP = switch (native_arch) {
UNINITIALIZED: bool = false,
_: u5 = 0,
},
+ .hexagon, .s390x => packed struct(u32) {
+ TYPE: MAP_TYPE,
+ FIXED: bool = false,
+ ANONYMOUS: bool = false,
+ _4: u1 = 0,
+ _5: u1 = 0,
+ GROWSDOWN: bool = false,
+ _7: u1 = 0,
+ _8: u1 = 0,
+ DENYWRITE: bool = false,
+ EXECUTABLE: bool = false,
+ LOCKED: bool = false,
+ NORESERVE: bool = false,
+ POPULATE: bool = false,
+ NONBLOCK: bool = false,
+ STACK: bool = false,
+ HUGETLB: bool = false,
+ SYNC: bool = false,
+ FIXED_NOREPLACE: bool = false,
+ _19: u5 = 0,
+ UNINITIALIZED: bool = false,
+ _: u5 = 0,
+ },
else => @compileError("missing std.os.linux.MAP constants for this architecture"),
};
@@ -417,6 +440,32 @@ pub const O = switch (native_arch) {
TMPFILE: bool = false,
_: u9 = 0,
},
+ .hexagon, .s390x => packed struct(u32) {
+ ACCMODE: ACCMODE = .RDONLY,
+ _2: u4 = 0,
+ CREAT: bool = false,
+ EXCL: bool = false,
+ NOCTTY: bool = false,
+ TRUNC: bool = false,
+ APPEND: bool = false,
+ NONBLOCK: bool = false,
+ DSYNC: bool = false,
+ ASYNC: bool = false,
+ DIRECT: bool = false,
+ LARGEFILE: bool = false,
+ DIRECTORY: bool = false,
+ NOFOLLOW: bool = false,
+ NOATIME: bool = false,
+ CLOEXEC: bool = false,
+ _17: u1 = 0,
+ PATH: bool = false,
+ _: u10 = 0,
+
+ // #define O_RSYNC 04010000
+ // #define O_SYNC 04010000
+ // #define O_TMPFILE 020200000
+ // #define O_NDELAY O_NONBLOCK
+ },
else => @compileError("missing std.os.linux.O constants for this architecture"),
};
@@ -854,7 +903,19 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: MAP, fd: i32, of
@truncate(@as(u64, @bitCast(offset)) / MMAP2_UNIT),
);
} else {
- return syscall6(
+ // The s390x mmap() syscall existed before Linux supported syscalls with 5+ parameters, so
+ // it takes a single pointer to an array of arguments instead.
+ return if (native_arch == .s390x) syscall1(
+ .mmap,
+ @intFromPtr(&[_]usize{
+ @intFromPtr(address),
+ length,
+ prot,
+ @as(u32, @bitCast(flags)),
+ @bitCast(@as(isize, fd)),
+ @as(u64, @bitCast(offset)),
+ }),
+ ) else syscall6(
.mmap,
@intFromPtr(address),
length,
@@ -6501,12 +6562,12 @@ pub const tc_oflag_t = if (is_ppc) packed struct(tcflag_t) {
ONLRET: bool = false,
OFILL: bool = false,
OFDEL: bool = false,
- NLDLY: NLDLY = 0,
- TABDLY: TABDLY = 0,
- CRDLY: CRDLY = 0,
- FFDLY: FFDLY = 0,
- BSDLY: BSDLY = 0,
- VTDLY: VTDLY = 0,
+ NLDLY: NLDLY = .NL0,
+ TABDLY: TABDLY = .TAB0,
+ CRDLY: CRDLY = .CR0,
+ FFDLY: FFDLY = .FF0,
+ BSDLY: BSDLY = .BS0,
+ VTDLY: VTDLY = .VT0,
_17: u15 = 0,
} else if (is_sparc) packed struct(tcflag_t) {
OPOST: bool = false,
@@ -8014,11 +8075,33 @@ pub const rtattr = extern struct {
len: c_ushort,
/// Type of option
- type: IFLA,
+ type: extern union {
+ /// IFLA_* from linux/if_link.h
+ link: IFLA,
+ /// IFA_* from linux/if_addr.h
+ addr: IFA,
+ },
pub const ALIGNTO = 4;
};
+pub const IFA = enum(c_ushort) {
+ UNSPEC,
+ ADDRESS,
+ LOCAL,
+ LABEL,
+ BROADCAST,
+ ANYCAST,
+ CACHEINFO,
+ MULTICAST,
+ FLAGS,
+ RT_PRIORITY,
+ TARGET_NETNSID,
+ PROTO,
+
+ _,
+};
+
pub const IFLA = enum(c_ushort) {
UNSPEC,
ADDRESS,
diff --git a/zig/lib/std/os/linux/IoUring.zig b/zig/lib/std/os/linux/IoUring.zig
index c7717524a9..731877e5ae 100644
--- a/zig/lib/std/os/linux/IoUring.zig
+++ b/zig/lib/std/os/linux/IoUring.zig
@@ -3886,7 +3886,13 @@ inline fn skipKernelLessThan(required: std.SemanticVersion) !void {
}
const release = mem.sliceTo(&uts.release, 0);
- var current = try std.SemanticVersion.parse(release);
+ // Strips potential extra, as kernel version might not be semver compliant, example "6.8.9-300.fc40.x86_64"
+ const extra_index = std.mem.indexOfAny(u8, release, "-+");
+ const stripped = release[0..(extra_index orelse release.len)];
+ // Make sure the input don't rely on the extra we just stripped
+ try testing.expect(required.pre == null and required.build == null);
+
+ var current = try std.SemanticVersion.parse(stripped);
current.pre = null; // don't check pre field
if (required.order(current) == .gt) return error.SkipZigTest;
}
diff --git a/zig/lib/std/os/linux/arm64.zig b/zig/lib/std/os/linux/aarch64.zig
similarity index 100%
rename from zig/lib/std/os/linux/arm64.zig
rename to zig/lib/std/os/linux/aarch64.zig
diff --git a/zig/lib/std/os/linux/arm-eabi.zig b/zig/lib/std/os/linux/arm.zig
similarity index 100%
rename from zig/lib/std/os/linux/arm-eabi.zig
rename to zig/lib/std/os/linux/arm.zig
diff --git a/zig/lib/std/os/linux/hexagon.zig b/zig/lib/std/os/linux/hexagon.zig
new file mode 100644
index 0000000000..e9bf9ab57c
--- /dev/null
+++ b/zig/lib/std/os/linux/hexagon.zig
@@ -0,0 +1,254 @@
+const std = @import("../../std.zig");
+const iovec = std.posix.iovec;
+const iovec_const = std.posix.iovec_const;
+const linux = std.os.linux;
+const SYS = linux.SYS;
+const uid_t = std.os.linux.uid_t;
+const gid_t = std.os.linux.gid_t;
+const pid_t = std.os.linux.pid_t;
+const sockaddr = linux.sockaddr;
+const socklen_t = linux.socklen_t;
+const timespec = std.os.linux.timespec;
+
+pub fn syscall0(number: SYS) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ : "memory"
+ );
+}
+
+pub fn syscall1(number: SYS, arg1: usize) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ : "memory"
+ );
+}
+
+pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ [arg2] "{r1}" (arg2),
+ : "memory"
+ );
+}
+
+pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ [arg2] "{r1}" (arg2),
+ [arg3] "{r2}" (arg3),
+ : "memory"
+ );
+}
+
+pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ [arg2] "{r1}" (arg2),
+ [arg3] "{r2}" (arg3),
+ [arg4] "{r3}" (arg4),
+ : "memory"
+ );
+}
+
+pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ [arg2] "{r1}" (arg2),
+ [arg3] "{r2}" (arg3),
+ [arg4] "{r3}" (arg4),
+ [arg5] "{r4}" (arg5),
+ : "memory"
+ );
+}
+
+pub fn syscall6(
+ number: SYS,
+ arg1: usize,
+ arg2: usize,
+ arg3: usize,
+ arg4: usize,
+ arg5: usize,
+ arg6: usize,
+) usize {
+ return asm volatile ("trap0(#1)"
+ : [ret] "={r0}" (-> usize),
+ : [number] "{r6}" (@intFromEnum(number)),
+ [arg1] "{r0}" (arg1),
+ [arg2] "{r1}" (arg2),
+ [arg3] "{r2}" (arg3),
+ [arg4] "{r3}" (arg4),
+ [arg5] "{r4}" (arg5),
+ [arg6] "{r5}" (arg6),
+ : "memory"
+ );
+}
+
+pub fn clone() callconv(.Naked) usize {
+ // __clone(func, stack, flags, arg, ptid, tls, ctid)
+ // r0, r1, r2, r3, r4, r5, +0
+ //
+ // syscall(SYS_clone, flags, stack, ptid, ctid, tls)
+ // r6 r0, r1, r2, r3, r4
+ asm volatile (
+ \\ allocframe(#8)
+ \\
+ \\ r11 = r0
+ \\ r10 = r3
+ \\
+ \\ r6 = #220 // SYS_clone
+ \\ r0 = r2
+ \\ r1 = and(r1, #-8)
+ \\ r2 = r4
+ \\ r3 = memw(r30 + #8)
+ \\ r4 = r5
+ \\ trap0(#1)
+ \\
+ \\ p0 = cmp.eq(r0, #0)
+ \\ if (!p0) dealloc_return
+ \\
+ \\ r0 = r10
+ \\ callr r11
+ \\
+ \\ r6 = #93 // SYS_exit
+ \\ r0 = #0
+ \\ trap0(#1)
+ );
+}
+
+pub const restore = restore_rt;
+
+pub fn restore_rt() callconv(.Naked) noreturn {
+ asm volatile (
+ \\ trap0(#0)
+ :
+ : [number] "{r6}" (@intFromEnum(SYS.rt_sigreturn)),
+ : "memory"
+ );
+}
+
+pub const F = struct {
+ pub const DUPFD = 0;
+ pub const GETFD = 1;
+ pub const SETFD = 2;
+ pub const GETFL = 3;
+ pub const SETFL = 4;
+ pub const GETLK = 5;
+ pub const SETLK = 6;
+ pub const SETLKW = 7;
+ pub const SETOWN = 8;
+ pub const GETOWN = 9;
+ pub const SETSIG = 10;
+ pub const GETSIG = 11;
+
+ pub const RDLCK = 0;
+ pub const WRLCK = 1;
+ pub const UNLCK = 2;
+
+ pub const SETOWN_EX = 15;
+ pub const GETOWN_EX = 16;
+
+ pub const GETOWNER_UIDS = 17;
+};
+
+pub const timeval = extern struct {
+ sec: time_t,
+ usec: i32,
+};
+
+pub const Flock = extern struct {
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ __unused: [4]u8,
+};
+
+pub const msghdr = extern struct {
+ name: ?*sockaddr,
+ namelen: socklen_t,
+ iov: [*]iovec,
+ iovlen: i32,
+ __pad1: i32 = 0,
+ control: ?*anyopaque,
+ controllen: socklen_t,
+ __pad2: socklen_t = 0,
+ flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ name: ?*const sockaddr,
+ namelen: socklen_t,
+ iov: [*]const iovec_const,
+ iovlen: i32,
+ __pad1: i32 = 0,
+ control: ?*const anyopaque,
+ controllen: socklen_t,
+ __pad2: socklen_t = 0,
+ flags: i32,
+};
+
+pub const blksize_t = i32;
+pub const nlink_t = u32;
+pub const time_t = i32;
+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;
+
+// The `stat` definition used by the Linux kernel.
+pub const Stat = extern struct {
+ dev: dev_t,
+ ino: ino_t,
+ mode: mode_t,
+ nlink: nlink_t,
+ uid: uid_t,
+ gid: gid_t,
+ rdev: dev_t,
+ __pad: u32,
+ size: off_t,
+ blksize: blksize_t,
+ __pad2: i32,
+ blocks: blkcnt_t,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ __unused: [2]u32,
+
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
+ }
+};
+
+pub const Elf_Symndx = u32;
+
+pub const MMAP2_UNIT = 4096;
+
+pub const VDSO = void;
+
+/// TODO
+pub const ucontext_t = void;
+
+/// TODO
+pub const getcontext = {};
diff --git a/zig/lib/std/os/linux/start_pie.zig b/zig/lib/std/os/linux/pie.zig
similarity index 100%
rename from zig/lib/std/os/linux/start_pie.zig
rename to zig/lib/std/os/linux/pie.zig
diff --git a/zig/lib/std/os/linux/powerpc64.zig b/zig/lib/std/os/linux/powerpc64.zig
index 04936a113d..06b67c17f1 100644
--- a/zig/lib/std/os/linux/powerpc64.zig
+++ b/zig/lib/std/os/linux/powerpc64.zig
@@ -48,7 +48,7 @@ pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
: [number] "{r0}" (@intFromEnum(number)),
[arg1] "{r3}" (arg1),
[arg2] "{r4}" (arg2),
- : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+ : "memory", "cr0", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
);
}
@@ -63,7 +63,7 @@ pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
[arg1] "{r3}" (arg1),
[arg2] "{r4}" (arg2),
[arg3] "{r5}" (arg3),
- : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+ : "memory", "cr0", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
);
}
@@ -79,7 +79,7 @@ pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize)
[arg2] "{r4}" (arg2),
[arg3] "{r5}" (arg3),
[arg4] "{r6}" (arg4),
- : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+ : "memory", "cr0", "r7", "r8", "r9", "r10", "r11", "r12"
);
}
@@ -96,7 +96,7 @@ pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize,
[arg3] "{r5}" (arg3),
[arg4] "{r6}" (arg4),
[arg5] "{r7}" (arg5),
- : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+ : "memory", "cr0", "r8", "r9", "r10", "r11", "r12"
);
}
@@ -122,7 +122,7 @@ pub fn syscall6(
[arg4] "{r6}" (arg4),
[arg5] "{r7}" (arg5),
[arg6] "{r8}" (arg6),
- : "memory", "cr0", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12"
+ : "memory", "cr0", "r9", "r10", "r11", "r12"
);
}
diff --git a/zig/lib/std/os/linux/s390x.zig b/zig/lib/std/os/linux/s390x.zig
new file mode 100644
index 0000000000..efc48af4ff
--- /dev/null
+++ b/zig/lib/std/os/linux/s390x.zig
@@ -0,0 +1,276 @@
+const std = @import("../../std.zig");
+const iovec = std.posix.iovec;
+const iovec_const = std.posix.iovec_const;
+const linux = std.os.linux;
+const SYS = linux.SYS;
+const uid_t = std.os.linux.uid_t;
+const gid_t = std.os.linux.gid_t;
+const pid_t = std.os.linux.pid_t;
+const sockaddr = linux.sockaddr;
+const socklen_t = linux.socklen_t;
+const timespec = std.os.linux.timespec;
+const stack_t = std.os.linux.stack_t;
+const sigset_t = std.os.linux.sigset_t;
+
+pub fn syscall0(number: SYS) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ : "memory"
+ );
+}
+
+pub fn syscall1(number: SYS, arg1: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ : "memory"
+ );
+}
+
+pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ [arg2] "{r3}" (arg2),
+ : "memory"
+ );
+}
+
+pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ [arg2] "{r3}" (arg2),
+ [arg3] "{r4}" (arg3),
+ : "memory"
+ );
+}
+
+pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ [arg2] "{r3}" (arg2),
+ [arg3] "{r4}" (arg3),
+ [arg4] "{r5}" (arg4),
+ : "memory"
+ );
+}
+
+pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ [arg2] "{r3}" (arg2),
+ [arg3] "{r4}" (arg3),
+ [arg4] "{r5}" (arg4),
+ [arg5] "{r6}" (arg5),
+ : "memory"
+ );
+}
+
+pub fn syscall6(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize, arg6: usize) usize {
+ return asm volatile ("svc 0"
+ : [ret] "={r2}" (-> usize),
+ : [number] "{r1}" (@intFromEnum(number)),
+ [arg1] "{r2}" (arg1),
+ [arg2] "{r3}" (arg2),
+ [arg3] "{r4}" (arg3),
+ [arg4] "{r5}" (arg4),
+ [arg5] "{r6}" (arg5),
+ [arg6] "{r7}" (arg6),
+ : "memory"
+ );
+}
+
+pub fn clone() callconv(.Naked) usize {
+ asm volatile (
+ \\# int clone(
+ \\# fn, a = r2
+ \\# stack, b = r3
+ \\# flags, c = r4
+ \\# arg, d = r5
+ \\# ptid, e = r6
+ \\# tls, f = *(r15+160)
+ \\# ctid) g = *(r15+168)
+ \\#
+ \\# pseudo C code:
+ \\# tid = syscall(SYS_clone,b,c,e,g,f);
+ \\# if (!tid) syscall(SYS_exit, a(d));
+ \\# return tid;
+ \\
+ \\# preserve call-saved register used as syscall arg
+ \\stg %%r6, 48(%%r15)
+ \\
+ \\# create initial stack frame for new thread
+ \\nill %%r3, 0xfff8
+ \\aghi %%r3, -160
+ \\lghi %%r0, 0
+ \\stg %%r0, 0(%%r3)
+ \\
+ \\# save fn and arg to child stack
+ \\stg %%r2, 8(%%r3)
+ \\stg %%r5, 16(%%r3)
+ \\
+ \\# shuffle args into correct registers and call SYS_clone
+ \\lgr %%r2, %%r3
+ \\lgr %%r3, %%r4
+ \\lgr %%r4, %%r6
+ \\lg %%r5, 168(%%r15)
+ \\lg %%r6, 160(%%r15)
+ \\svc 120
+ \\
+ \\# restore call-saved register
+ \\lg %%r6, 48(%%r15)
+ \\
+ \\# if error or if we're the parent, return
+ \\ltgr %%r2, %%r2
+ \\bnzr %%r14
+ \\
+ \\# we're the child. call fn(arg)
+ \\lg %%r1, 8(%%r15)
+ \\lg %%r2, 16(%%r15)
+ \\basr %%r14, %%r1
+ \\
+ \\# call SYS_exit. exit code is already in r2 from fn return value
+ \\svc 1
+ \\
+ );
+}
+
+pub const restore = restore_rt;
+
+pub fn restore_rt() callconv(.Naked) noreturn {
+ asm volatile (
+ \\svc 0
+ :
+ : [number] "{r1}" (@intFromEnum(SYS.rt_sigreturn)),
+ : "memory"
+ );
+}
+
+pub const F = struct {
+ pub const DUPFD = 0;
+ pub const GETFD = 1;
+ pub const SETFD = 2;
+ pub const GETFL = 3;
+ pub const SETFL = 4;
+ pub const GETLK = 5;
+ pub const SETLK = 6;
+ pub const SETLKW = 7;
+ pub const SETOWN = 8;
+ pub const GETOWN = 9;
+ pub const SETSIG = 10;
+ pub const GETSIG = 11;
+
+ pub const SETOWN_EX = 15;
+ pub const GETOWN_EX = 16;
+
+ pub const GETOWNER_UIDS = 17;
+};
+
+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;
+
+pub const timeval = extern struct {
+ sec: time_t,
+ usec: i64,
+};
+
+pub const Flock = extern struct {
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+};
+
+pub const msghdr = extern struct {
+ name: ?*sockaddr,
+ namelen: socklen_t,
+ iov: [*]iovec,
+ __pad1: i32 = 0,
+ iovlen: i32,
+ control: ?*anyopaque,
+ __pad2: i32 = 0,
+ controllen: socklen_t,
+ flags: i32,
+};
+
+pub const msghdr_const = extern struct {
+ name: ?*const sockaddr,
+ namelen: socklen_t,
+ iov: [*]const iovec_const,
+ __pad1: i32 = 0,
+ iovlen: i32,
+ control: ?*const anyopaque,
+ __pad2: i32 = 0,
+ controllen: socklen_t,
+ flags: i32,
+};
+
+// The `stat` definition used by the Linux kernel.
+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,
+ atim: timespec,
+ mtim: timespec,
+ ctim: timespec,
+ blksize: blksize_t,
+ blocks: blkcnt_t,
+ __unused: [3]c_ulong,
+
+ pub fn atime(self: @This()) timespec {
+ return self.atim;
+ }
+
+ pub fn mtime(self: @This()) timespec {
+ return self.mtim;
+ }
+
+ pub fn ctime(self: @This()) timespec {
+ return self.ctim;
+ }
+};
+
+pub const Elf_Symndx = u64;
+
+pub const VDSO = struct {
+ pub const CGT_SYM = "__kernel_clock_gettime";
+ pub const CGT_VER = "LINUX_2.6.29";
+};
+
+pub const ucontext_t = extern struct {
+ flags: u64,
+ link: ?*ucontext_t,
+ stack: stack_t,
+ mcontext: mcontext_t,
+ sigmask: sigset_t,
+};
+
+pub const mcontext_t = extern struct {
+ __regs1: [18]u64,
+ __regs2: [18]u32,
+ __regs3: [16]f64,
+};
+
+/// TODO
+pub const getcontext = {};
diff --git a/zig/lib/std/os/linux/syscalls.zig b/zig/lib/std/os/linux/syscalls.zig
index d08a77b47c..ef04387ea6 100644
--- a/zig/lib/std/os/linux/syscalls.zig
+++ b/zig/lib/std/os/linux/syscalls.zig
@@ -6852,7 +6852,7 @@ pub const Arc = enum(usize) {
keyctl = 219,
clone = 220,
execve = 221,
- mmap_pgoff = 222,
+ mmap2 = 222,
fadvise64_64 = 223,
swapon = 224,
swapoff = 225,
@@ -7538,7 +7538,7 @@ pub const Hexagon = enum(usize) {
keyctl = 219,
clone = 220,
execve = 221,
- mmap_pgoff = 222,
+ mmap2 = 222,
fadvise64_64 = 223,
swapon = 224,
swapoff = 225,
diff --git a/zig/lib/std/os/linux/thumb.zig b/zig/lib/std/os/linux/thumb.zig
index baaf130578..a464030858 100644
--- a/zig/lib/std/os/linux/thumb.zig
+++ b/zig/lib/std/os/linux/thumb.zig
@@ -141,7 +141,7 @@ pub fn syscall6(
);
}
-pub const clone = @import("arm-eabi.zig").clone;
+pub const clone = @import("arm.zig").clone;
pub fn restore() callconv(.Naked) noreturn {
asm volatile (
diff --git a/zig/lib/std/os/linux/tls.zig b/zig/lib/std/os/linux/tls.zig
index 7dab38024c..d1292e86dd 100644
--- a/zig/lib/std/os/linux/tls.zig
+++ b/zig/lib/std/os/linux/tls.zig
@@ -541,7 +541,19 @@ inline fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: linux.MAP, fd
@as(usize, @truncate(@as(u64, @bitCast(offset)) / linux.MMAP2_UNIT)),
});
} else {
- return @call(.always_inline, linux.syscall6, .{
+ // The s390x mmap() syscall existed before Linux supported syscalls with 5+ parameters, so
+ // it takes a single pointer to an array of arguments instead.
+ return if (native_arch == .s390x) @call(.always_inline, linux.syscall1, .{
+ .mmap,
+ @intFromPtr(&[_]usize{
+ @intFromPtr(address),
+ length,
+ prot,
+ @as(u32, @bitCast(flags)),
+ @as(usize, @bitCast(@as(isize, fd))),
+ @as(u64, @bitCast(offset)),
+ }),
+ }) else @call(.always_inline, linux.syscall6, .{
.mmap,
@intFromPtr(address),
length,
diff --git a/zig/lib/std/os/uefi/pool_allocator.zig b/zig/lib/std/os/uefi/pool_allocator.zig
index aa9798c6e5..f7962f22aa 100644
--- a/zig/lib/std/os/uefi/pool_allocator.zig
+++ b/zig/lib/std/os/uefi/pool_allocator.zig
@@ -48,11 +48,9 @@ const UefiPoolAllocator = struct {
ret_addr: usize,
) bool {
_ = ret_addr;
+ _ = log2_old_ptr_align;
if (new_len > buf.len) return false;
-
- _ = mem.alignAllocLen(buf.len, new_len, log2_old_ptr_align);
-
return true;
}
@@ -121,9 +119,6 @@ fn uefi_resize(
std.debug.assert(log2_old_ptr_align <= 3);
if (new_len > buf.len) return false;
-
- _ = mem.alignAllocLen(buf.len, new_len, 8);
-
return true;
}
diff --git a/zig/lib/std/os/wasi.zig b/zig/lib/std/os/wasi.zig
index 2c7d0d3272..5ffde3c1f6 100644
--- a/zig/lib/std/os/wasi.zig
+++ b/zig/lib/std/os/wasi.zig
@@ -315,35 +315,77 @@ pub const SOCK = struct {
};
pub const rights_t = packed struct(u64) {
+ /// The right to invoke fd_datasync. If PATH_OPEN is set, includes the right to invoke
+ /// path_open with fdflags_t.dsync.
FD_DATASYNC: bool = false,
+ /// The right to invoke fd_read and sock_recv. If FD_SEEK is set, includes the right to invoke
+ /// fd_pread.
FD_READ: bool = false,
+ /// The right to invoke fd_seek. This flag implies FD_TELL.
FD_SEEK: bool = false,
+ /// The right to invoke fd_fdstat_set_flags.
FD_FDSTAT_SET_FLAGS: bool = false,
+ /// The right to invoke fd_sync. If PATH_OPEN is set, includes the right to invoke path_open
+ /// with fdflags_t.RSYNC and fdflags_t.DSYNC.
FD_SYNC: bool = false,
+ /// The right to invoke fd_seek in such a way that the file offset remains unaltered (i.e.
+ /// whence_t.CUR with offset zero), or to invoke fd_tell.
FD_TELL: bool = false,
+ /// The right to invoke fd_write and sock_send. If FD_SEEK is set, includes the right to invoke
+ /// fd_pwrite.
FD_WRITE: bool = false,
+ /// The right to invoke fd_advise.
FD_ADVISE: bool = false,
+ /// The right to invoke fd_allocate.
FD_ALLOCATE: bool = false,
+ /// The right to invoke path_create_directory.
PATH_CREATE_DIRECTORY: bool = false,
+ /// If PATH_OPEN is set, the right to invoke path_open with oflags_t.CREAT.
PATH_CREATE_FILE: bool = false,
+ /// The right to invoke path_link with the file descriptor as the source directory.
PATH_LINK_SOURCE: bool = false,
+ /// The right to invoke path_link with the file descriptor as the target directory.
PATH_LINK_TARGET: bool = false,
+ /// The right to invoke path_open.
PATH_OPEN: bool = false,
+ /// The right to invoke fd_readdir.
FD_READDIR: bool = false,
+ /// The right to invoke path_readlink.
PATH_READLINK: bool = false,
+ /// The right to invoke path_rename with the file descriptor as the source directory.
PATH_RENAME_SOURCE: bool = false,
+ /// The right to invoke path_rename with the file descriptor as the target directory.
PATH_RENAME_TARGET: bool = false,
+ /// The right to invoke path_filestat_get.
PATH_FILESTAT_GET: bool = false,
+ /// The right to change a file's size. If PATH_OPEN is set, includes the right to invoke
+ /// path_open with oflags_t.TRUNC. Note: there is no function named path_filestat_set_size.
+ /// This follows POSIX design, which only has ftruncate and does not provide ftruncateat. While
+ /// such function would be desirable from the API design perspective, there are virtually no
+ /// use cases for it since no code written for POSIX systems would use it. Moreover,
+ /// implementing it would require multiple syscalls, leading to inferior performance.
PATH_FILESTAT_SET_SIZE: bool = false,
+ /// The right to invoke path_filestat_set_times.
PATH_FILESTAT_SET_TIMES: bool = false,
+ /// The right to invoke fd_filestat_get.
FD_FILESTAT_GET: bool = false,
+ /// The right to invoke fd_filestat_set_size.
FD_FILESTAT_SET_SIZE: bool = false,
+ /// The right to invoke fd_filestat_set_times.
FD_FILESTAT_SET_TIMES: bool = false,
+ /// The right to invoke path_symlink.
PATH_SYMLINK: bool = false,
+ /// The right to invoke path_remove_directory.
PATH_REMOVE_DIRECTORY: bool = false,
+ /// The right to invoke path_unlink_file.
PATH_UNLINK_FILE: bool = false,
+ /// If FD_READ is set, includes the right to invoke poll_oneoff to subscribe to
+ /// eventtype_t.FD_READ. If FD_WRITE is set, includes the right to invoke poll_oneoff to
+ /// subscribe to eventtype_t.FD_WRITE.
POLL_FD_READWRITE: bool = false,
+ /// The right to invoke sock_shutdown.
SOCK_SHUTDOWN: bool = false,
+ /// The right to invoke sock_accept.
SOCK_ACCEPT: bool = false,
_: u34 = 0,
};
diff --git a/zig/lib/std/os/windows.zig b/zig/lib/std/os/windows.zig
index d277361352..7f4d3290dc 100644
--- a/zig/lib/std/os/windows.zig
+++ b/zig/lib/std/os/windows.zig
@@ -599,6 +599,8 @@ pub const ReadFileError = error{
/// The specified network name is no longer available.
ConnectionResetByPeer,
OperationAborted,
+ /// Unable to read file due to lock.
+ LockViolation,
Unexpected,
};
@@ -630,6 +632,7 @@ pub fn ReadFile(in_hFile: HANDLE, buffer: []u8, offset: ?u64) ReadFileError!usiz
.BROKEN_PIPE => return 0,
.HANDLE_EOF => return 0,
.NETNAME_DELETED => return error.ConnectionResetByPeer,
+ .LOCK_VIOLATION => return error.LockViolation,
else => |err| return unexpectedError(err),
}
}
diff --git a/zig/lib/std/os/windows/tls.zig b/zig/lib/std/os/windows/tls.zig
index f98e22b620..4723b31011 100644
--- a/zig/lib/std/os/windows/tls.zig
+++ b/zig/lib/std/os/windows/tls.zig
@@ -9,7 +9,7 @@ export var __xl_a: windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null;
export var __xl_z: windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null;
comptime {
- if (builtin.cpu.arch == .x86 and builtin.abi == .msvc and builtin.zig_backend != .stage2_c) {
+ if (builtin.cpu.arch == .x86 and !builtin.abi.isGnu() and builtin.zig_backend != .stage2_c) {
// The __tls_array is the offset of the ThreadLocalStoragePointer field
// in the TEB block whose base address held in the %fs segment.
asm (
diff --git a/zig/lib/std/posix.zig b/zig/lib/std/posix.zig
index 94b37a0878..bb21a79690 100644
--- a/zig/lib/std/posix.zig
+++ b/zig/lib/std/posix.zig
@@ -798,6 +798,13 @@ pub const ReadError = error{
/// In WASI, this error occurs when the file descriptor does
/// not hold the required rights to read from it.
AccessDenied,
+
+ /// This error occurs in Linux if the process to be read from
+ /// no longer exists.
+ ProcessNotFound,
+
+ /// Unable to read file due to lock.
+ LockViolation,
} || UnexpectedError;
/// Returns the number of bytes that were read, which can be less than
@@ -854,6 +861,7 @@ pub fn read(fd: fd_t, buf: []u8) ReadError!usize {
.INTR => continue,
.INVAL => unreachable,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.CANCELED => return error.Canceled,
.BADF => return error.NotOpenForReading, // Can be a race condition.
@@ -917,6 +925,7 @@ pub fn readv(fd: fd_t, iov: []const iovec) ReadError!usize {
.INTR => continue,
.INVAL => unreachable,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForReading, // can be a race condition
.IO => return error.InputOutput,
@@ -996,6 +1005,7 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
.INTR => continue,
.INVAL => unreachable,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForReading, // Can be a race condition.
.IO => return error.InputOutput,
@@ -1133,6 +1143,7 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
.INTR => continue,
.INVAL => unreachable,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForReading, // can be a race condition
.IO => return error.InputOutput,
@@ -1176,6 +1187,10 @@ pub const WriteError = error{
/// Connection reset by peer.
ConnectionResetByPeer,
+
+ /// This error occurs in Linux if the process being written to
+ /// no longer exists.
+ ProcessNotFound,
} || UnexpectedError;
/// Write to a file descriptor.
@@ -1243,6 +1258,7 @@ pub fn write(fd: fd_t, bytes: []const u8) WriteError!usize {
.INTR => continue,
.INVAL => return error.InvalidArgument,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForWriting, // can be a race condition.
.DESTADDRREQ => unreachable, // `connect` was never called.
@@ -1315,6 +1331,7 @@ pub fn writev(fd: fd_t, iov: []const iovec_const) WriteError!usize {
.INTR => continue,
.INVAL => return error.InvalidArgument,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForWriting, // Can be a race condition.
.DESTADDRREQ => unreachable, // `connect` was never called.
@@ -1404,6 +1421,7 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
.INTR => continue,
.INVAL => return error.InvalidArgument,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForWriting, // Can be a race condition.
.DESTADDRREQ => unreachable, // `connect` was never called.
@@ -1488,6 +1506,7 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
.INTR => continue,
.INVAL => return error.InvalidArgument,
.FAULT => unreachable,
+ .NOENT => return error.ProcessNotFound,
.AGAIN => return error.WouldBlock,
.BADF => return error.NotOpenForWriting, // Can be a race condition.
.DESTADDRREQ => unreachable, // `connect` was never called.
@@ -4544,13 +4563,16 @@ pub const FanotifyInitError = error{
SystemFdQuotaExceeded,
SystemResources,
PermissionDenied,
+ /// The kernel does not recognize the flags passed, likely because it is an
+ /// older version.
+ UnsupportedFlags,
} || UnexpectedError;
pub fn fanotify_init(flags: std.os.linux.fanotify.InitFlags, event_f_flags: u32) FanotifyInitError!i32 {
const rc = system.fanotify_init(flags, event_f_flags);
switch (errno(rc)) {
.SUCCESS => return @intCast(rc),
- .INVAL => unreachable,
+ .INVAL => return error.UnsupportedFlags,
.MFILE => return error.ProcessFdQuotaExceeded,
.NFILE => return error.SystemFdQuotaExceeded,
.NOMEM => return error.SystemResources,
@@ -6763,6 +6785,7 @@ pub const MemFdCreateError = error{
OutOfMemory,
/// Either the name provided exceeded `NAME_MAX`, or invalid flags were passed.
NameTooLong,
+ SystemOutdated,
} || UnexpectedError;
pub fn memfd_createZ(name: [*:0]const u8, flags: u32) MemFdCreateError!fd_t {
diff --git a/zig/lib/std/posix/test.zig b/zig/lib/std/posix/test.zig
index e62ffa39ca..dba7dcde6d 100644
--- a/zig/lib/std/posix/test.zig
+++ b/zig/lib/std/posix/test.zig
@@ -368,6 +368,11 @@ test "fstatat" {
// now repeat but using `fstatat` instead
const flags = if (native_os == .wasi) 0x0 else posix.AT.SYMLINK_NOFOLLOW;
const statat = try posix.fstatat(tmp.dir.fd, "file.txt", flags);
+
+ // s390x-linux does not have nanosecond precision for fstat(), but it does for fstatat(). As a
+ // result, comparing the two structures is doomed to fail.
+ if (builtin.cpu.arch == .s390x and builtin.os.tag == .linux) return error.SkipZigTest;
+
try expectEqual(stat, statat);
}
diff --git a/zig/lib/std/process/Child.zig b/zig/lib/std/process/Child.zig
index 3a54ede2ad..bd0a91ce77 100644
--- a/zig/lib/std/process/Child.zig
+++ b/zig/lib/std/process/Child.zig
@@ -316,9 +316,7 @@ pub const RunResult = struct {
};
fn fifoToOwnedArrayList(fifo: *std.io.PollFifo) std.ArrayList(u8) {
- if (fifo.head > 0) {
- @memcpy(fifo.buf[0..fifo.count], fifo.buf[fifo.head..][0..fifo.count]);
- }
+ if (fifo.head != 0) fifo.realign();
const result = std.ArrayList(u8){
.items = fifo.buf[0..fifo.count],
.capacity = fifo.buf.len,
diff --git a/zig/lib/std/sort.zig b/zig/lib/std/sort.zig
index 23707f1385..8705d24017 100644
--- a/zig/lib/std/sort.zig
+++ b/zig/lib/std/sort.zig
@@ -769,10 +769,38 @@ pub fn equalRange(
context: anytype,
comptime compareFn: fn (@TypeOf(context), T) std.math.Order,
) struct { usize, usize } {
- return .{
- lowerBound(T, items, context, compareFn),
- upperBound(T, items, context, compareFn),
- };
+ var low: usize = 0;
+ var high: usize = items.len;
+
+ while (low < high) {
+ const mid = low + (high - low) / 2;
+ switch (compareFn(context, items[mid])) {
+ .gt => {
+ low = mid + 1;
+ },
+ .lt => {
+ high = mid;
+ },
+ .eq => {
+ return .{
+ low + std.sort.lowerBound(
+ T,
+ items[low..mid],
+ context,
+ compareFn,
+ ),
+ mid + std.sort.upperBound(
+ T,
+ items[mid..high],
+ context,
+ compareFn,
+ ),
+ };
+ },
+ }
+ }
+
+ return .{ low, low };
}
test equalRange {
@@ -800,6 +828,7 @@ test equalRange {
try std.testing.expectEqual(.{ 6, 6 }, equalRange(i32, &[_]i32{ 2, 4, 8, 16, 32, 64 }, @as(i32, 100), S.orderI32));
try std.testing.expectEqual(.{ 2, 6 }, equalRange(i32, &[_]i32{ 2, 4, 8, 8, 8, 8, 15, 22 }, @as(i32, 8), S.orderI32));
try std.testing.expectEqual(.{ 2, 2 }, equalRange(u32, &[_]u32{ 2, 4, 8, 16, 32, 64 }, @as(u32, 5), S.orderU32));
+ try std.testing.expectEqual(.{ 3, 5 }, equalRange(u32, &[_]u32{ 2, 3, 4, 5, 5 }, @as(u32, 5), S.orderU32));
try std.testing.expectEqual(.{ 1, 1 }, equalRange(f32, &[_]f32{ -54.2, -26.7, 0.0, 56.55, 100.1, 322.0 }, @as(f32, -33.4), S.orderF32));
try std.testing.expectEqual(.{ 3, 5 }, equalRange(
[]const u8,
diff --git a/zig/lib/std/start.zig b/zig/lib/std/start.zig
index a8109f7ed9..01a33522d0 100644
--- a/zig/lib/std/start.zig
+++ b/zig/lib/std/start.zig
@@ -271,8 +271,8 @@ fn _start() callconv(.Naked) noreturn {
\\ b %[posixCallMainAndExit]
,
.arc =>
- // The `arc` tag currently means ARCv2, which has an unusually low stack alignment
- // requirement. ARCv3 increases it from 4 to 16, but we don't support ARCv3 yet.
+ // The `arc` tag currently means ARC v1 and v2, which have an unusually low stack
+ // alignment requirement. ARC v3 increases it from 4 to 16, but we don't support v3 yet.
\\ mov fp, 0
\\ mov blink, 0
\\ mov r0, sp
@@ -391,6 +391,7 @@ fn _start() callconv(.Naked) noreturn {
\\ stdu 0, -32(1)
\\ mtlr 0
\\ b %[posixCallMainAndExit]
+ \\ nop
,
.s390x =>
// Set up the stack frame (register save area and cleared back-chain slot).
@@ -539,6 +540,7 @@ fn expandStackSize(phdrs: []elf.Phdr) void {
for (phdrs) |*phdr| {
switch (phdr.p_type) {
elf.PT_GNU_STACK => {
+ if (phdr.p_memsz == 0) break;
assert(phdr.p_memsz % std.mem.page_size == 0);
// Silently fail if we are unable to get limits.
diff --git a/zig/lib/std/tar.zig b/zig/lib/std/tar.zig
index f15a5e8c8a..060b802f19 100644
--- a/zig/lib/std/tar.zig
+++ b/zig/lib/std/tar.zig
@@ -848,6 +848,7 @@ test PaxIterator {
test {
_ = @import("tar/test.zig");
+ _ = @import("tar/writer.zig");
_ = Diagnostics;
}
diff --git a/zig/lib/std/tar/writer.zig b/zig/lib/std/tar/writer.zig
index e75e6c42d6..4ced287eec 100644
--- a/zig/lib/std/tar/writer.zig
+++ b/zig/lib/std/tar/writer.zig
@@ -84,7 +84,7 @@ pub fn Writer(comptime WriterType: type) type {
/// Writes fs.Dir.WalkerEntry. Uses `mtime` from file system entry and
/// default for entry mode .
- pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.WalkerEntry) !void {
+ pub fn writeEntry(self: *Self, entry: std.fs.Dir.Walker.Entry) !void {
switch (entry.kind) {
.directory => {
try self.writeDir(entry.path, .{ .mtime = try entryMtime(entry) });
@@ -95,7 +95,7 @@ pub fn Writer(comptime WriterType: type) type {
try self.writeFile(entry.path, file);
},
.sym_link => {
- var link_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
const link_name = try entry.dir.readLink(entry.basename, &link_name_buffer);
try self.writeLink(entry.path, link_name, .{ .mtime = try entryMtime(entry) });
},
@@ -133,7 +133,7 @@ pub fn Writer(comptime WriterType: type) type {
return self.mtime_now;
}
- fn entryMtime(entry: std.fs.Dir.Walker.WalkerEntry) !u64 {
+ fn entryMtime(entry: std.fs.Dir.Walker.Entry) !u64 {
const stat = try entry.dir.statFile(entry.basename);
return @intCast(@divFloor(stat.mtime, std.time.ns_per_s));
}
@@ -424,8 +424,8 @@ test "write files" {
.{ .path = "e123456789" ** 11, .content = "e" },
};
- var file_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- var link_name_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var file_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
+ var link_name_buffer: [std.fs.max_path_bytes]u8 = undefined;
// with root
{
diff --git a/zig/lib/std/time.zig b/zig/lib/std/time.zig
index a80a2477ac..d253b63512 100644
--- a/zig/lib/std/time.zig
+++ b/zig/lib/std/time.zig
@@ -8,82 +8,8 @@ const posix = std.posix;
pub const epoch = @import("time/epoch.zig");
-/// Spurious wakeups are possible and no precision of timing is guaranteed.
-pub fn sleep(nanoseconds: u64) void {
- if (builtin.os.tag == .windows) {
- const big_ms_from_ns = nanoseconds / ns_per_ms;
- const ms = math.cast(windows.DWORD, big_ms_from_ns) orelse math.maxInt(windows.DWORD);
- windows.kernel32.Sleep(ms);
- return;
- }
-
- if (builtin.os.tag == .wasi) {
- const w = std.os.wasi;
- const userdata: w.userdata_t = 0x0123_45678;
- const clock: w.subscription_clock_t = .{
- .id = .MONOTONIC,
- .timeout = nanoseconds,
- .precision = 0,
- .flags = 0,
- };
- const in: w.subscription_t = .{
- .userdata = userdata,
- .u = .{
- .tag = .CLOCK,
- .u = .{ .clock = clock },
- },
- };
-
- var event: w.event_t = undefined;
- var nevents: usize = undefined;
- _ = w.poll_oneoff(&in, &event, 1, &nevents);
- return;
- }
-
- if (builtin.os.tag == .uefi) {
- const boot_services = std.os.uefi.system_table.boot_services.?;
- const us_from_ns = nanoseconds / ns_per_us;
- const us = math.cast(usize, us_from_ns) orelse math.maxInt(usize);
- _ = boot_services.stall(us);
- return;
- }
-
- const s = nanoseconds / ns_per_s;
- const ns = nanoseconds % ns_per_s;
-
- // Newer kernel ports don't have old `nanosleep()` and `clock_nanosleep()` has been around
- // since Linux 2.6 and glibc 2.1 anyway.
- if (builtin.os.tag == .linux) {
- const linux = std.os.linux;
-
- var req: linux.timespec = .{
- .sec = std.math.cast(linux.time_t, s) orelse std.math.maxInt(linux.time_t),
- .nsec = std.math.cast(linux.time_t, ns) orelse std.math.maxInt(linux.time_t),
- };
- var rem: linux.timespec = undefined;
-
- while (true) {
- switch (linux.E.init(linux.clock_nanosleep(.MONOTONIC, .{ .ABSTIME = false }, &req, &rem))) {
- .SUCCESS => return,
- .INTR => {
- req = rem;
- continue;
- },
- .FAULT,
- .INVAL,
- .OPNOTSUPP,
- => unreachable,
- else => return,
- }
- }
- }
-
- posix.nanosleep(s, ns);
-}
-
-test sleep {
- sleep(1);
-}
+/// Deprecated: moved to std.Thread.sleep
+pub const sleep = std.Thread.sleep;
/// Get a calendar timestamp, in seconds, relative to UTC 1970-01-01.
/// Precision of timing depends on the hardware and operating system.
@@ -155,7 +81,7 @@ test milliTimestamp {
const margin = ns_per_ms * 50;
const time_0 = milliTimestamp();
- sleep(ns_per_ms);
+ std.Thread.sleep(ns_per_ms);
const time_1 = milliTimestamp();
const interval = time_1 - time_0;
try testing.expect(interval > 0);
@@ -359,7 +285,7 @@ test Timer {
const margin = ns_per_ms * 150;
var timer = try Timer.start();
- sleep(10 * ns_per_ms);
+ std.Thread.sleep(10 * ns_per_ms);
const time_0 = timer.read();
try testing.expect(time_0 > 0);
// Tests should not depend on timings: skip test if outside margin.
diff --git a/zig/lib/std/zig.zig b/zig/lib/std/zig.zig
index 325b7bea90..c3ce106634 100644
--- a/zig/lib/std/zig.zig
+++ b/zig/lib/std/zig.zig
@@ -233,7 +233,6 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
}),
},
.nvptx => return std.fmt.allocPrint(allocator, "{s}.ptx", .{root_name}),
- .dxcontainer => return std.fmt.allocPrint(allocator, "{s}.dxil", .{root_name}),
}
}
diff --git a/zig/lib/std/zig/AstGen.zig b/zig/lib/std/zig/AstGen.zig
index 14902a6726..7e11f8d44b 100644
--- a/zig/lib/std/zig/AstGen.zig
+++ b/zig/lib/std/zig/AstGen.zig
@@ -2716,7 +2716,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.array_type_sentinel,
.elem_type,
.indexable_ptr_elem_type,
- .vector_elem_type,
+ .vec_arr_elem_type,
.vector_type,
.indexable_ptr_len,
.anyframe_type,
@@ -2901,7 +2901,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
.breakpoint,
.disable_instrumentation,
- .fence,
.set_float_mode,
.set_align_stack,
.branch_hint,
@@ -3156,6 +3155,9 @@ fn deferStmt(
const have_err_code = scope_tag == .defer_error and payload_token != 0;
const sub_scope = if (!have_err_code) &defer_gen.base else blk: {
const ident_name = try gz.astgen.identAsString(payload_token);
+ if (std.mem.eql(u8, tree.tokenSlice(payload_token), "_")) {
+ return gz.astgen.failTok(payload_token, "discard of error capture; omit it instead", .{});
+ }
const remapped_err_code: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
opt_remapped_err_code = remapped_err_code.toOptional();
try gz.astgen.instructions.append(gz.astgen.gpa, .{
@@ -9139,7 +9141,7 @@ fn minMax(
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
if (args.len < 2) {
- return astgen.failNode(node, "expected at least 2 arguments, found 0", .{});
+ return astgen.failNode(node, "expected at least 2 arguments, found {}", .{args.len});
}
if (args.len == 2) {
const tag: Zir.Inst.Tag = switch (op) {
@@ -9304,15 +9306,6 @@ fn builtinCall(
});
return rvalue(gz, ri, result, node);
},
- .fence => {
- const atomic_order_ty = try gz.addBuiltinValue(node, .atomic_order);
- const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = atomic_order_ty } }, params[0]);
- _ = try gz.addExtendedPayload(.fence, Zir.Inst.UnNode{
- .node = gz.nodeIndexToRelative(node),
- .operand = order,
- });
- return rvalue(gz, ri, .void_value, node);
- },
.set_float_mode => {
const float_mode_ty = try gz.addBuiltinValue(node, .float_mode);
const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_mode_ty } }, params[0]);
@@ -9536,7 +9529,7 @@ fn builtinCall(
.splat => {
const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
- const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
+ const elem_type = try gz.addUnNode(.vec_arr_elem_type, result_type, node);
const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
.lhs = result_type,
diff --git a/zig/lib/std/zig/AstRlAnnotate.zig b/zig/lib/std/zig/AstRlAnnotate.zig
index 597baa2936..104cea1154 100644
--- a/zig/lib/std/zig/AstRlAnnotate.zig
+++ b/zig/lib/std/zig/AstRlAnnotate.zig
@@ -908,7 +908,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.c_include,
.wasm_memory_size,
.splat,
- .fence,
.set_float_mode,
.set_align_stack,
.type_info,
diff --git a/zig/lib/std/zig/BuiltinFn.zig b/zig/lib/std/zig/BuiltinFn.zig
index 95c6c7be12..6b0d0cc0a2 100644
--- a/zig/lib/std/zig/BuiltinFn.zig
+++ b/zig/lib/std/zig/BuiltinFn.zig
@@ -48,7 +48,6 @@ pub const Tag = enum {
error_cast,
@"export",
@"extern",
- fence,
field,
field_parent_ptr,
float_cast,
@@ -500,13 +499,6 @@ pub const list = list: {
.param_count = 2,
},
},
- .{
- "@fence",
- .{
- .tag = .fence,
- .param_count = 1,
- },
- },
.{
"@field",
.{
diff --git a/zig/lib/std/zig/LibCDirs.zig b/zig/lib/std/zig/LibCDirs.zig
index 8fb961c187..8b8a3a8d42 100644
--- a/zig/lib/std/zig/LibCDirs.zig
+++ b/zig/lib/std/zig/LibCDirs.zig
@@ -69,7 +69,7 @@ pub fn detect(
// On windows, instead of the native (mingw) abi, we want to check
// for the MSVC abi as a fallback.
const use_system_abi = if (builtin.os.tag == .windows)
- target.abi == .msvc
+ target.abi == .msvc or target.abi == .itanium
else
is_native_abi;
@@ -242,35 +242,20 @@ fn libCGenericName(target: std.Target) [:0]const u8 {
.muslx32,
.none,
.ohos,
+ .ohoseabi,
=> return "musl",
.code16,
.eabi,
.eabihf,
.ilp32,
.android,
+ .androideabi,
.msvc,
.itanium,
.cygnus,
.simulator,
.macabi,
=> unreachable,
-
- .pixel,
- .vertex,
- .geometry,
- .hull,
- .domain,
- .compute,
- .library,
- .raygeneration,
- .intersection,
- .anyhit,
- .closesthit,
- .miss,
- .callable,
- .mesh,
- .amplification,
- => unreachable,
}
}
diff --git a/zig/lib/std/zig/LibCInstallation.zig b/zig/lib/std/zig/LibCInstallation.zig
index 686471bde5..3d163532d1 100644
--- a/zig/lib/std/zig/LibCInstallation.zig
+++ b/zig/lib/std/zig/LibCInstallation.zig
@@ -86,14 +86,14 @@ pub fn parse(
return error.ParseError;
}
- if (self.msvc_lib_dir == null and os_tag == .windows and target.abi == .msvc) {
+ if (self.msvc_lib_dir == null and os_tag == .windows and (target.abi == .msvc or target.abi == .itanium)) {
log.err("msvc_lib_dir may not be empty for {s}-{s}", .{
@tagName(os_tag),
@tagName(target.abi),
});
return error.ParseError;
}
- if (self.kernel32_lib_dir == null and os_tag == .windows and target.abi == .msvc) {
+ if (self.kernel32_lib_dir == null and os_tag == .windows and (target.abi == .msvc or target.abi == .itanium)) {
log.err("kernel32_lib_dir may not be empty for {s}-{s}", .{
@tagName(os_tag),
@tagName(target.abi),
@@ -690,12 +690,340 @@ fn appendCcExe(args: *std.ArrayList([]const u8), skip_cc_env_var: bool) !void {
}
}
+/// These are basenames. This data is produced with a pure function. See also
+/// `CsuPaths`.
+pub const CrtBasenames = struct {
+ crt0: ?[]const u8 = null,
+ crti: ?[]const u8 = null,
+ crtbegin: ?[]const u8 = null,
+ crtend: ?[]const u8 = null,
+ crtn: ?[]const u8 = null,
+
+ pub const GetArgs = struct {
+ target: std.Target,
+ link_libc: bool,
+ output_mode: std.builtin.OutputMode,
+ link_mode: std.builtin.LinkMode,
+ pie: bool,
+ };
+
+ /// Determine file system path names of C runtime startup objects for supported
+ /// link modes.
+ pub fn get(args: GetArgs) CrtBasenames {
+ // crt objects are only required for libc.
+ if (!args.link_libc) return .{};
+
+ // Flatten crt cases.
+ const mode: enum {
+ dynamic_lib,
+ dynamic_exe,
+ dynamic_pie,
+ static_exe,
+ static_pie,
+ } = switch (args.output_mode) {
+ .Obj => return .{},
+ .Lib => switch (args.link_mode) {
+ .dynamic => .dynamic_lib,
+ .static => return .{},
+ },
+ .Exe => switch (args.link_mode) {
+ .dynamic => if (args.pie) .dynamic_pie else .dynamic_exe,
+ .static => if (args.pie) .static_pie else .static_exe,
+ },
+ };
+
+ const target = args.target;
+
+ if (target.isAndroid()) return switch (mode) {
+ .dynamic_lib => .{
+ .crtbegin = "crtbegin_so.o",
+ .crtend = "crtend_so.o",
+ },
+ .dynamic_exe, .dynamic_pie => .{
+ .crtbegin = "crtbegin_dynamic.o",
+ .crtend = "crtend_android.o",
+ },
+ .static_exe, .static_pie => .{
+ .crtbegin = "crtbegin_static.o",
+ .crtend = "crtend_android.o",
+ },
+ };
+
+ return switch (target.os.tag) {
+ .linux => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_pie => .{
+ .crt0 = "Scrt1.o",
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .static_pie => .{
+ .crt0 = "rcrt1.o",
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ },
+ .dragonfly => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_pie => .{
+ .crt0 = "Scrt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .static_pie => .{
+ .crt0 = "Scrt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ },
+ .freebsd => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_pie => .{
+ .crt0 = "Scrt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginT.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .static_pie => .{
+ .crt0 = "Scrt1.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ },
+ .netbsd => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe => .{
+ .crt0 = "crt0.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_pie => .{
+ .crt0 = "crt0.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe => .{
+ .crt0 = "crt0.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginT.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .static_pie => .{
+ .crt0 = "crt0.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginT.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ },
+ .openbsd => switch (mode) {
+ .dynamic_lib => .{
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ },
+ .dynamic_exe, .dynamic_pie => .{
+ .crt0 = "crt0.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ },
+ .static_exe, .static_pie => .{
+ .crt0 = "rcrt0.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ },
+ },
+ .haiku => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe => .{
+ .crt0 = "start_dyn.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_pie => .{
+ .crt0 = "start_dyn.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe => .{
+ .crt0 = "start_dyn.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbegin.o",
+ .crtend = "crtend.o",
+ .crtn = "crtn.o",
+ },
+ .static_pie => .{
+ .crt0 = "start_dyn.o",
+ .crti = "crti.o",
+ .crtbegin = "crtbeginS.o",
+ .crtend = "crtendS.o",
+ .crtn = "crtn.o",
+ },
+ },
+ .solaris, .illumos => switch (mode) {
+ .dynamic_lib => .{
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .dynamic_exe, .dynamic_pie => .{
+ .crt0 = "crt1.o",
+ .crti = "crti.o",
+ .crtn = "crtn.o",
+ },
+ .static_exe, .static_pie => .{},
+ },
+ else => .{},
+ };
+ }
+};
+
+pub const CrtPaths = struct {
+ crt0: ?Path = null,
+ crti: ?Path = null,
+ crtbegin: ?Path = null,
+ crtend: ?Path = null,
+ crtn: ?Path = null,
+};
+
+pub fn resolveCrtPaths(
+ lci: LibCInstallation,
+ arena: Allocator,
+ crt_basenames: CrtBasenames,
+ target: std.Target,
+) error{ OutOfMemory, LibCInstallationMissingCrtDir }!CrtPaths {
+ const crt_dir_path: Path = .{
+ .root_dir = std.Build.Cache.Directory.cwd(),
+ .sub_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir,
+ };
+ switch (target.os.tag) {
+ .dragonfly => {
+ const gccv: []const u8 = if (target.os.version_range.semver.isAtLeast(.{
+ .major = 5,
+ .minor = 4,
+ .patch = 0,
+ }) orelse true) "gcc80" else "gcc54";
+ return .{
+ .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crtbegin = if (crt_basenames.crtbegin) |basename| .{
+ .root_dir = crt_dir_path.root_dir,
+ .sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
+ } else null,
+ .crtend = if (crt_basenames.crtend) |basename| .{
+ .root_dir = crt_dir_path.root_dir,
+ .sub_path = try fs.path.join(arena, &.{ crt_dir_path.sub_path, gccv, basename }),
+ } else null,
+ .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
+ };
+ },
+ .haiku => {
+ const gcc_dir_path: Path = .{
+ .root_dir = std.Build.Cache.Directory.cwd(),
+ .sub_path = lci.gcc_dir orelse return error.LibCInstallationMissingCrtDir,
+ };
+ return .{
+ .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crtbegin = if (crt_basenames.crtbegin) |basename| try gcc_dir_path.join(arena, basename) else null,
+ .crtend = if (crt_basenames.crtend) |basename| try gcc_dir_path.join(arena, basename) else null,
+ .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
+ };
+ },
+ else => {
+ return .{
+ .crt0 = if (crt_basenames.crt0) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crti = if (crt_basenames.crti) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crtbegin = if (crt_basenames.crtbegin) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crtend = if (crt_basenames.crtend) |basename| try crt_dir_path.join(arena, basename) else null,
+ .crtn = if (crt_basenames.crtn) |basename| try crt_dir_path.join(arena, basename) else null,
+ };
+ },
+ }
+}
+
const LibCInstallation = @This();
const std = @import("std");
const builtin = @import("builtin");
const Target = std.Target;
const fs = std.fs;
const Allocator = std.mem.Allocator;
+const Path = std.Build.Cache.Path;
const is_darwin = builtin.target.isDarwin();
const is_windows = builtin.target.os.tag == .windows;
diff --git a/zig/lib/std/zig/Zir.zig b/zig/lib/std/zig/Zir.zig
index dda7e7bbd0..9c76f72663 100644
--- a/zig/lib/std/zig/Zir.zig
+++ b/zig/lib/std/zig/Zir.zig
@@ -247,9 +247,9 @@ pub const Inst = struct {
/// element type. Emits a compile error if the type is not an indexable pointer.
/// Uses the `un_node` field.
indexable_ptr_elem_type,
- /// Given a vector type, returns its element type.
+ /// Given a vector or array type, returns its element type.
/// Uses the `un_node` field.
- vector_elem_type,
+ vec_arr_elem_type,
/// Given a pointer to an indexable object, returns the len property. This is
/// used by for loops. This instruction also emits a for-loop specific compile
/// error if the indexable object is not indexable.
@@ -1065,7 +1065,7 @@ pub const Inst = struct {
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
- .vector_elem_type,
+ .vec_arr_elem_type,
.indexable_ptr_len,
.anyframe_type,
.as_node,
@@ -1375,7 +1375,7 @@ pub const Inst = struct {
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
- .vector_elem_type,
+ .vec_arr_elem_type,
.indexable_ptr_len,
.anyframe_type,
.as_node,
@@ -1575,7 +1575,7 @@ pub const Inst = struct {
=> false,
.extended => switch (data.extended.opcode) {
- .fence, .branch_hint, .breakpoint, .disable_instrumentation => true,
+ .branch_hint, .breakpoint, .disable_instrumentation => true,
else => false,
},
};
@@ -1607,7 +1607,7 @@ pub const Inst = struct {
.vector_type = .pl_node,
.elem_type = .un_node,
.indexable_ptr_elem_type = .un_node,
- .vector_elem_type = .un_node,
+ .vec_arr_elem_type = .un_node,
.indexable_ptr_len = .un_node,
.anyframe_type = .un_node,
.as_node = .pl_node,
@@ -1979,9 +1979,6 @@ pub const Inst = struct {
/// The `@prefetch` builtin.
/// `operand` is payload index to `BinNode`.
prefetch,
- /// Implements the `@fence` builtin.
- /// `operand` is payload index to `UnNode`.
- fence,
/// Implement builtin `@setFloatMode`.
/// `operand` is payload index to `UnNode`.
set_float_mode,
@@ -3784,7 +3781,7 @@ fn findDeclsInner(
.vector_type,
.elem_type,
.indexable_ptr_elem_type,
- .vector_elem_type,
+ .vec_arr_elem_type,
.indexable_ptr_len,
.anyframe_type,
.as_node,
@@ -4014,7 +4011,6 @@ fn findDeclsInner(
.wasm_memory_size,
.wasm_memory_grow,
.prefetch,
- .fence,
.set_float_mode,
.set_align_stack,
.error_cast,
diff --git a/zig/lib/std/zig/system.zig b/zig/lib/std/zig/system.zig
index 046bd3854e..5feb08ab28 100644
--- a/zig/lib/std/zig/system.zig
+++ b/zig/lib/std/zig/system.zig
@@ -172,6 +172,7 @@ pub const DetectError = error{
DeviceBusy,
OSVersionDetectionFail,
Unexpected,
+ ProcessNotFound,
};
/// Given a `Target.Query`, which specifies in detail which parts of the
@@ -385,6 +386,16 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
query.cpu_features_sub,
);
+ if (cpu_arch == .hexagon) {
+ // Both LLVM and LLD have broken support for the small data area. Yet LLVM has the feature
+ // on by default for all Hexagon CPUs. Clang sort of solves this by defaulting the `-gpsize`
+ // command line parameter for the Hexagon backend to 0, so that no constants get placed in
+ // the SDA. (This of course breaks down if the user passes `-G ` to Clang...) We can't do
+ // the `-gpsize` hack because we can have multiple concurrent LLVM emit jobs, and command
+ // line options in LLVM are shared globally. So just force this feature off. Lovely stuff.
+ result.cpu.features.removeFeature(@intFromEnum(Target.hexagon.Feature.small_data));
+ }
+
// https://github.com/llvm/llvm-project/issues/105978
if (result.cpu.arch.isArmOrThumb() and result.floatAbi() == .soft) {
result.cpu.features.removeFeature(@intFromEnum(Target.arm.Feature.vfp2));
@@ -443,6 +454,7 @@ pub const AbiAndDynamicLinkerFromFileError = error{
Unexpected,
UnexpectedEndOfFile,
NameTooLong,
+ ProcessNotFound,
};
pub fn abiAndDynamicLinkerFromFile(
@@ -831,6 +843,7 @@ fn glibcVerFromRPath(rpath: []const u8) !std.SemanticVersion {
error.UnableToReadElfFile,
error.Unexpected,
error.FileSystem,
+ error.ProcessNotFound,
=> |e| return e,
};
}
@@ -1077,6 +1090,7 @@ fn detectAbiAndDynamicLinker(
const len = preadAtLeast(file, &buffer, 0, min_len) catch |err| switch (err) {
error.UnexpectedEndOfFile,
error.UnableToReadElfFile,
+ error.ProcessNotFound,
=> return defaultAbiAndDynamicLinker(cpu, os, query),
else => |e| return e,
@@ -1120,6 +1134,7 @@ fn detectAbiAndDynamicLinker(
error.SymLinkLoop,
error.ProcessFdQuotaExceeded,
error.SystemFdQuotaExceeded,
+ error.ProcessNotFound,
=> |e| return e,
error.UnableToReadElfFile,
@@ -1147,7 +1162,7 @@ fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Quer
.abi = abi,
.ofmt = query.ofmt orelse Target.ObjectFormat.default(os.tag, cpu.arch),
.dynamic_linker = if (query.dynamic_linker.get() == null)
- Target.DynamicLinker.standard(cpu, os.tag, abi)
+ Target.DynamicLinker.standard(cpu, os, abi)
else
query.dynamic_linker,
};
@@ -1176,6 +1191,8 @@ fn preadAtLeast(file: fs.File, buf: []u8, offset: u64, min_read_len: usize) !usi
error.Unexpected => return error.Unexpected,
error.InputOutput => return error.FileSystem,
error.AccessDenied => return error.Unexpected,
+ error.ProcessNotFound => return error.ProcessNotFound,
+ error.LockViolation => return error.UnableToReadElfFile,
};
if (len == 0) return error.UnexpectedEndOfFile;
i += len;
diff --git a/zig/lib/std/zig/target.zig b/zig/lib/std/zig/target.zig
index b60586da85..59fccc582c 100644
--- a/zig/lib/std/zig/target.zig
+++ b/zig/lib/std/zig/target.zig
@@ -35,6 +35,7 @@ pub const available_libcs = [_]ArchOsAbi{
.{ .arch = .x86, .os = .linux, .abi = .musl },
.{ .arch = .x86, .os = .windows, .abi = .gnu },
.{ .arch = .loongarch64, .os = .linux, .abi = .gnu, .glibc_min = .{ .major = 2, .minor = 36, .patch = 0 } },
+ .{ .arch = .loongarch64, .os = .linux, .abi = .gnusf, .glibc_min = .{ .major = 2, .minor = 36, .patch = 0 } },
.{ .arch = .loongarch64, .os = .linux, .abi = .musl },
.{ .arch = .m68k, .os = .linux, .abi = .gnu },
.{ .arch = .m68k, .os = .linux, .abi = .musl },
diff --git a/zig/lib/std/zig/tokenizer.zig b/zig/lib/std/zig/tokenizer.zig
index db69693a93..7f82db786f 100644
--- a/zig/lib/std/zig/tokenizer.zig
+++ b/zig/lib/std/zig/tokenizer.zig
@@ -535,6 +535,8 @@ pub const Tokenizer = struct {
switch (self.buffer[self.index]) {
0 => if (self.index == self.buffer.len) {
result.tag = .invalid;
+ } else {
+ continue :state .invalid;
},
'\n' => result.tag = .invalid,
else => continue :state .invalid,
@@ -1250,6 +1252,7 @@ test "invalid token characters" {
test "invalid literal/comment characters" {
try testTokenize("\"\x00\"", &.{.invalid});
+ try testTokenize("`\x00`", &.{.invalid});
try testTokenize("//\x00", &.{.invalid});
try testTokenize("//\x1f", &.{.invalid});
try testTokenize("//\x7f", &.{.invalid});
diff --git a/zig/lib/tsan/builtins/assembly.h b/zig/lib/tsan/builtins/assembly.h
new file mode 100644
index 0000000000..8c42fc7734
--- /dev/null
+++ b/zig/lib/tsan/builtins/assembly.h
@@ -0,0 +1,293 @@
+//===-- assembly.h - compiler-rt assembler support macros -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines macros for use in compiler-rt assembler source.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef COMPILERRT_ASSEMBLY_H
+#define COMPILERRT_ASSEMBLY_H
+
+#if defined(__linux__) && defined(__CET__)
+#if __has_include()
+#include
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR %%
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN(name) .private_extern name
+#define LOCAL_LABEL(name) L_##name
+// tell linker it can break up file at label boundaries
+#define FILE_LEVEL_DIRECTIVE .subsections_via_symbols
+#define SYMBOL_IS_FUNC(name)
+#define CONST_SECTION .const
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__ELF__)
+
+#define HIDDEN(name) .hidden name
+#define LOCAL_LABEL(name) .L_##name
+#define FILE_LEVEL_DIRECTIVE
+#if defined(__arm__) || defined(__aarch64__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#define CONST_SECTION .section .rodata
+
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+ defined(__linux__)
+#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
+#else
+#define NO_EXEC_STACK_DIRECTIVE
+#endif
+
+#else // !__APPLE__ && !__ELF__
+
+#define HIDDEN(name)
+#define LOCAL_LABEL(name) .L ## name
+#define FILE_LEVEL_DIRECTIVE
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#define CONST_SECTION .section .rdata,"rd"
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define FUNC_ALIGN \
+ .text SEPARATOR \
+ .balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value) \
+ .pushsection .note.gnu.property, "a" SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .word 4 SEPARATOR \
+ .word 16 SEPARATOR \
+ .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
+ .asciz "GNU" SEPARATOR \
+ .word type SEPARATOR \
+ .word 4 SEPARATOR \
+ .word value SEPARATOR \
+ .word 0 SEPARATOR \
+ .popsection
+
+#if BTI_FLAG != 0
+#define BTI_C hint #34
+#define BTI_J hint #36
+#else
+#define BTI_C
+#define BTI_J
+#endif
+
+#if (BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC \
+ GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
+#endif
+
+#if defined(__arm__)
+
+// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+// - for '-mthumb -march=armv6' compiler defines '__thumb__'
+// - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
+ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
+#define __ARM_FEATURE_CLZ
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#define JMPc(r, c) bx##c r
+#else
+#define JMP(r) mov pc, r
+#define JMPc(r, c) mov##c pc, r
+#endif
+
+// pop {pc} can't switch Thumb mode on ARMv4T
+#if __ARM_ARCH >= 5
+#define POP_PC() pop {pc}
+#else
+#define POP_PC() \
+ pop {ip}; \
+ JMP(ip)
+#endif
+
+#if defined(USE_THUMB_2)
+#define WIDE(op) op.w
+#else
+#define WIDE(op) op
+#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
+#endif
+
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#ifdef VISIBILITY_HIDDEN
+#define DECLARE_SYMBOL_VISIBILITY(name) \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
+ HIDDEN(name) SEPARATOR
+#else
+#define DECLARE_SYMBOL_VISIBILITY(name)
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
+#endif
+
+#define DEFINE_COMPILERRT_FUNCTION(name) \
+ DEFINE_CODE_STATE \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) \
+ DECLARE_FUNC_ENCODING \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ DEFINE_CODE_STATE \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .thumb_func SEPARATOR \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ DEFINE_CODE_STATE \
+ FILE_LEVEL_DIRECTIVE SEPARATOR \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ SYMBOL_NAME(name):
+
+#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ HIDDEN(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name:
+
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ FUNC_ALIGN \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name: \
+ SEPARATOR CFI_START \
+ SEPARATOR BTI_C
+
+#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
+ .globl SYMBOL_NAME(name) SEPARATOR \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \
+ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
+
+#if defined(__ARM_EABI__)
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \
+ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name)
+#else
+#define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name)
+#endif
+
+#ifdef __ELF__
+#define END_COMPILERRT_FUNCTION(name) \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END SEPARATOR \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#else
+#define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END
+#endif
+
+#endif // COMPILERRT_ASSEMBLY_H
diff --git a/zig/lib/tsan/interception/interception.h b/zig/lib/tsan/interception/interception.h
index 069f73d276..38c152952e 100644
--- a/zig/lib/tsan/interception/interception.h
+++ b/zig/lib/tsan/interception/interception.h
@@ -185,6 +185,11 @@ const interpose_substitution substitution_##func_name[] \
# else
# define __ASM_WEAK_WRAPPER(func) ".weak " #func "\n"
# endif // SANITIZER_FREEBSD || SANITIZER_NETBSD
+# if defined(__arm__) || defined(__aarch64__)
+# define ASM_TYPE_FUNCTION_STR "%function"
+# else
+# define ASM_TYPE_FUNCTION_STR "@function"
+# endif
// Keep trampoline implementation in sync with sanitizer_common/sanitizer_asm.h
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__); \
@@ -196,12 +201,14 @@ const interpose_substitution substitution_##func_name[] \
__ASM_WEAK_WRAPPER(func) \
".set " #func ", " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \
".globl " SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \
- ".type " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", %function\n" \
+ ".type " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \
+ ASM_TYPE_FUNCTION_STR "\n" \
SANITIZER_STRINGIFY(TRAMPOLINE(func)) ":\n" \
- SANITIZER_STRINGIFY(CFI_STARTPROC) "\n" \
- SANITIZER_STRINGIFY(ASM_TAIL_CALL) " __interceptor_" \
- SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(func)) "\n" \
- SANITIZER_STRINGIFY(CFI_ENDPROC) "\n" \
+ C_ASM_STARTPROC "\n" \
+ C_ASM_TAIL_CALL(SANITIZER_STRINGIFY(TRAMPOLINE(func)), \
+ "__interceptor_" \
+ SANITIZER_STRINGIFY(ASM_PREEMPTIBLE_SYM(func))) "\n" \
+ C_ASM_ENDPROC "\n" \
".size " SANITIZER_STRINGIFY(TRAMPOLINE(func)) ", " \
".-" SANITIZER_STRINGIFY(TRAMPOLINE(func)) "\n" \
);
@@ -341,6 +348,18 @@ typedef unsigned long long uptr;
#else
typedef unsigned long uptr;
#endif // _WIN64
+
+#if defined(__ELF__) && !SANITIZER_FUCHSIA
+// The use of interceptors makes many sanitizers unusable for static linking.
+// Define a function, if called, will cause a linker error (undefined _DYNAMIC).
+// However, -static-pie (which is not common) cannot be detected at link time.
+extern uptr kDynamic[] asm("_DYNAMIC");
+inline void DoesNotSupportStaticLinking() {
+ [[maybe_unused]] volatile auto x = &kDynamic;
+}
+#else
+inline void DoesNotSupportStaticLinking() {}
+#endif
} // namespace __interception
#define INCLUDED_FROM_INTERCEPTION_LIB
diff --git a/zig/lib/tsan/interception/interception_linux.h b/zig/lib/tsan/interception/interception_linux.h
index 433a3d9bd7..2e01ff4457 100644
--- a/zig/lib/tsan/interception/interception_linux.h
+++ b/zig/lib/tsan/interception/interception_linux.h
@@ -28,12 +28,14 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
uptr func, uptr trampoline);
} // namespace __interception
-#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
- ::__interception::InterceptFunction( \
- #func, \
- (::__interception::uptr *)&REAL(func), \
- (::__interception::uptr)&(func), \
- (::__interception::uptr)&TRAMPOLINE(func))
+// Cast func to type of REAL(func) before casting to uptr in case it is an
+// overloaded function, which is the case for some glibc functions when
+// _FORTIFY_SOURCE is used. This disambiguates which overload to use.
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
+ ::__interception::InterceptFunction( \
+ #func, (::__interception::uptr *)&REAL(func), \
+ (::__interception::uptr)(decltype(REAL(func)))&(func), \
+ (::__interception::uptr) &TRAMPOLINE(func))
// dlvsym is a GNU extension supported by some other platforms.
#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
@@ -41,7 +43,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
::__interception::InterceptFunction( \
#func, symver, \
(::__interception::uptr *)&REAL(func), \
- (::__interception::uptr)&(func), \
+ (::__interception::uptr)(decltype(REAL(func)))&(func), \
(::__interception::uptr)&TRAMPOLINE(func))
#else
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
diff --git a/zig/lib/tsan/interception/interception_win.cpp b/zig/lib/tsan/interception/interception_win.cpp
index 00c317510e..a638e66ecc 100644
--- a/zig/lib/tsan/interception/interception_win.cpp
+++ b/zig/lib/tsan/interception/interception_win.cpp
@@ -1,4 +1,4 @@
-//===-- interception_linux.cpp ----------------------------------*- C++ -*-===//
+//===-- interception_win.cpp ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -339,7 +339,7 @@ struct TrampolineMemoryRegion {
uptr max_size;
};
-UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31; // 2 gig
+UNUSED static const uptr kTrampolineScanLimitRange = 1ull << 31; // 2 gig
static const int kMaxTrampolineRegion = 1024;
static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
@@ -431,7 +431,8 @@ static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
// The following prologues cannot be patched because of the short jump
// jumping to the patching region.
-#if SANITIZER_WINDOWS64
+// Short jump patterns below are only for x86_64.
+# if SANITIZER_WINDOWS_x64
// ntdll!wcslen in Win11
// 488bc1 mov rax,rcx
// 0fb710 movzx edx,word ptr [rax]
@@ -457,7 +458,12 @@ static const u8 kPrologueWithShortJump2[] = {
// Returns 0 on error.
static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
-#if SANITIZER_WINDOWS64
+#if SANITIZER_ARM64
+ // An ARM64 instruction is 4 bytes long.
+ return 4;
+#endif
+
+# if SANITIZER_WINDOWS_x64
if (memcmp((u8*)address, kPrologueWithShortJump1,
sizeof(kPrologueWithShortJump1)) == 0 ||
memcmp((u8*)address, kPrologueWithShortJump2,
@@ -473,6 +479,8 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
switch (*(u8*)address) {
case 0x90: // 90 : nop
+ case 0xC3: // C3 : ret (for small/empty function interception
+ case 0xCC: // CC : int 3 i.e. registering weak functions)
return 1;
case 0x50: // push eax / rax
@@ -496,7 +504,6 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
// Cannot overwrite control-instruction. Return 0 to indicate failure.
case 0xE9: // E9 XX XX XX XX : jmp