diff --git a/README.md b/README.md index 70f12ae933..ca99d59bb8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ to find and inspect the patch diffs. * LLVM, LLD, Clang 19.1.0 * zlib 1.3.1 * zstd 1.5.2 - * zig 0.14.0-dev.1622+2ac543388 + * zig 0.14.0-dev.1876+41dbd0d0d For other versions, check the git tags of this repository. @@ -102,16 +102,17 @@ is more portable across Linux distributions. | `aarch64_be-linux-musl` | OK | | `arm-linux-gnueabi` | [#101](https://github.com/ziglang/zig-bootstrap/issues/101) | | `arm-linux-gnueabihf` | [#102](https://github.com/ziglang/zig-bootstrap/issues/102) | -| `arm-linux-musleabi` | [#103](https://github.com/ziglang/zig-bootstrap/issues/103) | -| `arm-linux-musleabihf` | [#183](https://github.com/ziglang/zig-bootstrap/issues/183) | +| `arm-linux-musleabi` | OK | +| `arm-linux-musleabihf` | OK | | `armeb-linux-gnueabi` | [#96](https://github.com/ziglang/zig-bootstrap/issues/96) | | `armeb-linux-gnueabihf` | [#97](https://github.com/ziglang/zig-bootstrap/issues/97) | -| `armeb-linux-musleabi` | [#98](https://github.com/ziglang/zig-bootstrap/issues/98) | -| `armeb-linux-musleabihf` | [#99](https://github.com/ziglang/zig-bootstrap/issues/99) | +| `armeb-linux-musleabi` | OK | +| `armeb-linux-musleabihf` | OK | | `loongarch64-linux-gnu` | OK | +| `loongarch64-linux-gnusf` | OK | | `loongarch64-linux-musl` | OK | -| `mips-linux-gnueabi` | OK | -| `mips-linux-gnueabihf` | OK | +| `mips-linux-gnueabi` | [#195](https://github.com/ziglang/zig-bootstrap/issues/195) | +| `mips-linux-gnueabihf` | [#196](https://github.com/ziglang/zig-bootstrap/issues/196) | | `mips-linux-musleabi` | OK | | `mips-linux-musleabihf` | OK | | `mips64-linux-gnuabi64` | OK | @@ -136,15 +137,15 @@ is more portable across Linux distributions. | `riscv32-linux-musl` | OK | | `riscv64-linux-gnu` | OK | | `riscv64-linux-musl` | OK | -| `s390x-linux-gnu` | [#116](https://github.com/ziglang/zig-bootstrap/issues/116) | -| `s390x-linux-musl` | [#52](https://github.com/ziglang/bootstrap/issues/52) | +| `s390x-linux-gnu` | OK | +| `s390x-linux-musl` | OK | | `sparc-linux-gnu` | [#117](https://github.com/ziglang/zig-bootstrap/issues/117) | | `sparc64-linux-gnu` | [#172](https://github.com/ziglang/zig-bootstrap/issues/172) | -| `thumb-linux-musleabi` | [#176](https://github.com/ziglang/zig-bootstrap/issues/176) | -| `thumb-linux-musleabihf` | [#175](https://github.com/ziglang/zig-bootstrap/issues/175) | -| `thumb-windows-gnu` | [#105](https://github.com/ziglang/zig-bootstrap/issues/105) | -| `thumbeb-linux-musleabi` | [#180](https://github.com/ziglang/zig-bootstrap/issues/180) | -| `thumbeb-linux-musleabihf` | [#179](https://github.com/ziglang/zig-bootstrap/issues/179) | +| `thumb-linux-musleabi` | OK | +| `thumb-linux-musleabihf` | OK | +| `thumb-windows-gnu` | OK | +| `thumbeb-linux-musleabi` | OK | +| `thumbeb-linux-musleabihf` | OK | | `x86-linux-gnu` | OK | | `x86-linux-musl` | OK | | `x86-windows-gnu` | OK | diff --git a/build b/build index cc5bd56008..b1c233233a 100755 --- a/build +++ b/build @@ -7,7 +7,7 @@ TARGET="$1" # Example: riscv64-linux-gnu MCPU="$2" # Examples: `baseline`, `native`, `generic+v7a`, or `arm1176jzf_s` ROOTDIR="$(pwd)" -ZIG_VERSION="0.14.0-dev.1622+2ac543388" +ZIG_VERSION="0.14.0-dev.1876+41dbd0d0d" TARGET_OS_AND_ABI=${TARGET#*-} # Example: linux-gnu diff --git a/build.bat b/build.bat index 609d7ce87f..331bd1d043 100644 --- a/build.bat +++ b/build.bat @@ -35,7 +35,7 @@ if "%VSCMD_ARG_HOST_ARCH%"=="x86" set OUTDIR=out-win-x86 set ROOTDIR=%~dp0 set "ROOTDIR_CMAKE=%ROOTDIR:\=/%" -set ZIG_VERSION="0.14.0-dev.1622+2ac543388" +set ZIG_VERSION="0.14.0-dev.1876+41dbd0d0d" set JOBS_ARG= pushd %ROOTDIR% diff --git a/zig/CMakeLists.txt b/zig/CMakeLists.txt index d7dfbfce81..e71f799b54 100644 --- a/zig/CMakeLists.txt +++ b/zig/CMakeLists.txt @@ -125,8 +125,8 @@ check_pie_supported( OUTPUT_VARIABLE ZIG_PIE_SUPPORTED_BY_CMAKE LANGUAGES C CXX ) -if(ZIG_PIE AND NOT ZIG_PIE_SUPPORTED_BY_CMAKE) - message(SEND_ERROR "ZIG_PIE was requested but CMake does not support it for \"zigcpp\" target") +if(ZIG_PIE AND NOT CMAKE_CXX_LINK_PIE_SUPPORTED) + message(SEND_ERROR "ZIG_PIE was requested but CMake does not support it for \"zigcpp\" target: ${ZIG_PIE_SUPPORTED_BY_CMAKE}") endif() @@ -894,9 +894,7 @@ set(BUILD_COMPILER_RT_ARGS --name compiler_rt -femit-bin="${ZIG_COMPILER_RT_C_SOURCE}" -target "${ZIG_HOST_TARGET_TRIPLE}" - --dep "build_options" "-Mroot=lib/compiler_rt.zig" - "-Mbuild_options=${ZIG_CONFIG_ZIG_OUT}" ) add_custom_command( diff --git a/zig/README.md b/zig/README.md index 865bd178b3..818a7d67f8 100644 --- a/zig/README.md +++ b/zig/README.md @@ -47,7 +47,7 @@ Ensure you have the required dependencies: * CMake >= 3.15 * System C/C++ Toolchain - * LLVM, Clang, LLD development libraries == 18.x + * LLVM, Clang, LLD development libraries == 19.x Then it is the standard CMake build process: diff --git a/zig/bootstrap.c b/zig/bootstrap.c index a373522de4..f341740a0e 100644 --- a/zig/bootstrap.c +++ b/zig/bootstrap.c @@ -123,7 +123,7 @@ int main(int argc, char **argv) { if (f == NULL) panic("unable to open config.zig for writing"); - const char *zig_version = "0.14.0-dev.1622+2ac543388"; + const char *zig_version = "0.14.0-dev.1876+41dbd0d0d"; int written = fprintf(f, "pub const have_llvm = false;\n" @@ -170,9 +170,7 @@ int main(int argc, char **argv) { "-ofmt=c", "-OReleaseSmall", "--name", "compiler_rt", "-femit-bin=compiler_rt.c", "-target", host_triple, - "--dep", "build_options", "-Mroot=lib/compiler_rt.zig", - "-Mbuild_options=config.zig", NULL, }; print_and_run(child_argv); diff --git a/zig/build.zig b/zig/build.zig index 731b825c07..a5f4cd5675 100644 --- a/zig/build.zig +++ b/zig/build.zig @@ -577,6 +577,10 @@ pub fn build(b: *std.Build) !void { } else { update_mingw_step.dependOn(&b.addFail("The -Dmingw-src=... option is required for this step").step); } + + const test_incremental_step = b.step("test-incremental", "Run the incremental compilation test cases"); + try tests.addIncrementalTests(b, test_incremental_step); + test_step.dependOn(test_incremental_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/zig/doc/langref.html.in b/zig/doc/langref.html.in index 9f12829349..54b923d0d9 100644 --- a/zig/doc/langref.html.in +++ b/zig/doc/langref.html.in @@ -4218,11 +4218,10 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void { {#header_close#} {#header_open|Atomics#} -

TODO: @fence()

TODO: @atomic rmw

TODO: builtin atomic memory ordering enum

- {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#} + {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#} {#header_close#} @@ -4307,7 +4306,7 @@ comptime { an integer or an enum.

{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.

- {#see_also|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#} + {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#} {#header_close#} {#header_open|@atomicRmw#} @@ -4322,7 +4321,7 @@ comptime {

{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.

{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.

- {#see_also|@atomicStore|@atomicLoad|@fence|@cmpxchgWeak|@cmpxchgStrong#} + {#see_also|@atomicStore|@atomicLoad|@cmpxchgWeak|@cmpxchgStrong#} {#header_close#} {#header_open|@atomicStore#} @@ -4335,7 +4334,7 @@ comptime { an integer or an enum.

{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.

- {#see_also|@atomicLoad|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#} + {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#} {#header_close#} {#header_open|@bitCast#} @@ -4568,7 +4567,7 @@ comptime {

{#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|@cmpxchgWeak#} + {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgWeak#} {#header_close#} {#header_open|@cmpxchgWeak#} @@ -4600,7 +4599,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val

{#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.

{#see_also|@intFromEnum#} @@ -4857,15 +4856,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val {#see_also|@export#} {#header_close#} - {#header_open|@fence#} -
{#syntax#}@fence(order: AtomicOrder) void{#endsyntax#}
-

- The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations. -

-

{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.

- {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#} - {#header_close#} - {#header_open|@field#}
{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}

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