| ... | @@ -0,0 +1,6888 @@ |
| 1 | :100644 100644 41bc62cead176f9307835337b00615e2e1f74f6b d21ea2791c62f3b912f586e56882346c00321647 M	CMakeLists.txt |
| 2 | :100644 100644 0466b79bf2dbeb803d653eff2f2a48880da3669b e8d54cc0cd314cc8a7e8e2cf2fb1c20106b33078 M	build.zig |
| 3 | :100644 100755 0a7ba5d277c3ccdc6357f92807b80bb7eb855bc7 0a7ba5d277c3ccdc6357f92807b80bb7eb855bc7 M	ci/x86_64-linux-debug-llvm.sh |
| 4 | :100644 100644 578139c5ac08a4d7eb4e298ea3354e4b9c1ee72d 79a120d5a2ccdde4c037297e677420b065a24b04 M	lib/compiler_rt/fma.zig |
| 5 | :100644 100644 dad60b725bc267a906e5c88abeb1ee342f818160 0f47a0b64781e423ec680cb162eb33e3ec51eddb M	lib/std/Build/Step/Compile.zig |
| 6 | :100644 100644 bef80d782b20e759701c73a3fe85909985415f42 43b542c09e047ff0ae723f710750f396e18bbf08 M	lib/std/elf.zig |
| 7 | :100644 100644 b2116c1a7429b5791d8e39d66dd7e66ad64337e0 55f1fd14cb6cfa8421a142a142802710c9944bd5 M	lib/std/zig/system.zig |
| 8 | :100644 100644 34953ed11a12e334a1ecd995de399421a896a5bb bf7246b8d8b8fe3df2c4ac1c4fb6124fe55e134b M	src/Compilation.zig |
| 9 | :100644 100644 d8751251da9e24db98c79f7964e0ea1a9bde78c8 45f7e509de609a4ab10651d27e49a1cb645eb2b6 M	src/Compilation/Config.zig |
| 10 | :100644 100644 996549774294455b642ef3286d3d20be0bd404f5 f4344af86d46be017beacf31e90c581493517b0f M	src/InternPool.zig |
| 11 | :100644 100644 946e890ea3566e0cc1ab2aae453d389ecfab702b d0576de33d4d3077f7fa177ba4e0b8e9b438ee69 M	src/Sema.zig |
| 12 | :100644 100644 8de562176107ae28fb15ce2e6ed241aa7f176e16 381eacf45ab2389c950aad0dd9f0ed886e9a8bcb M	src/Value.zig |
| 13 | :100644 100644 706bdb51655409a6e2c23e36d580d0c81c01f350 8e9e9c29025c4e82af1d14ece0eca9b7d9bd06e4 M	src/Zcu.zig |
| 14 | :100644 100644 77cddb204e82eeeba3b349b0ed2216974d06f14c 32782e7e8952462d2991ff0b3bf3bbe8e0b72c64 M	src/Zcu/PerThread.zig |
| 15 | :100644 100644 7b13cfc90d68b760251c236bd43890858a088dd9 fe40ba4bbb16ffcbcc2768af9a6f8a57600c1e4f M	src/arch/riscv64/CodeGen.zig |
| 16 | :100644 100644 2e72aff941072c7e5d7164eace99b5d919dc4ece 64a476007cf9881e5101c5c945158252b1ba5b86 M	src/arch/riscv64/Emit.zig |
| 17 | :100644 100644 6fb8e23a98c3b0e89ee5139429fc11626fb2ecc7 204ab6a3c06226635b1619b60c205f02f8447884 M	src/arch/riscv64/Mir.zig |
| 18 | :100644 100644 d41f1cdf07aa54b3c55a9917826a7b55a7da23b0 26282b09ab4f5c831cea32e9c9dbf8d6e0b2256a M	src/arch/sparc64/Emit.zig |
| 19 | :100644 100644 842ac10fed1af8fbaeadb7b2c0404a20f806abc0 41d135eb831fefe51afd3fde7925596fce9d441b M	src/arch/sparc64/Mir.zig |
| 20 | :100644 100644 b5760c95ac2b54f5e03c32e3d61a4c32e01f3a46 1827b50d61a06e05f525461fb8261922f36920bf M	src/arch/x86_64/CodeGen.zig |
| 21 | :100644 100644 84bb325322ac20c100da1e85c715a99f7e251deb c2b38d8e6d45b3439d2f8bb6cf9e518ac17784cc M	src/arch/x86_64/Emit.zig |
| 22 | :100644 100644 e70018850d621aff1a360044014f1ea1e8516a44 caf41ffb392d07b8a455f09181c77ffb8a679d7e M	src/arch/x86_64/Mir.zig |
| 23 | :100644 100644 835093d11ab8d38f622252233101c1a3c9d8904d 05048109335e0256d91c5f350d7fa900ce08e402 M	src/arch/x86_64/bits.zig |
| 24 | :100644 100644 03ff7134f62d04025081f06b50248545433130ec 1d9c67175ef204933a5463393cad189d0e59e7fa M	src/arch/x86_64/encoder.zig |
| 25 | :100644 100644 56e6e7c99fb3bd8208ce92e912c03f3d2404f2c1 4cbf3f56169ec9227f961a72720898cc23df3f96 M	src/codegen.zig |
| 26 | :100644 100644 318a51da95bfe1c047447f96cde8a83f993c9f80 be6478eae896f3d70d874e609d3c3d263946872a M	src/codegen/aarch64/Mir.zig |
| 27 | :100644 100644 ac30cedecd8318da8f38e96e45d763fc2d70bc1f 266796a2dc2dda022bd7c4c3027c950a446d9dc9 M	src/dev.zig |
| 28 | :100644 100644 27cd6620e359284f0a6398aa23a5f8ade66446d7 277013efb3094cee331db13b15fd1e5d2d08d7e4 M	src/link.zig |
| 29 | :100644 100644 e016473531aede3998c41f42a85745fbf017c63c f3e3b3d0b530d498f1b8d4518c1d9c06d4a69baa M	src/link/Coff.zig |
| 30 | :100644 100644 f4af5f4148ad11f2eeb0688ccd11a39120404d6b 595e3583d5d540bdd0fe0ce1727d0a25eed72f50 M	src/link/Dwarf.zig |
| 31 | :100644 100644 b74406c368d5cc4eb3da41365236bc79387bf7c2 d7e3cf62f3a378970682797fb538227d9c70795d M	src/link/Elf/LinkerDefined.zig |
| 32 | :100644 100644 8c79def16bff14a9878ab22cea2ee6e1aca7c160 4dce40e37094e9a48db41d35ce189af38b63c287 M	src/link/Elf/SharedObject.zig |
| 33 | :100644 100644 bf65d04e4a13b3980749bfcc1af24f52d4ac3b49 a3ede11dc4003cd0f9d1f671dfccc5c095b16a82 M	src/link/Elf/ZigObject.zig |
| 34 | :000000 100644 0000000000000000000000000000000000000000 e43ebf2639ad88db8d125d2a79877173d771f73d A	src/link/Elf2.zig |
| 35 | :100644 100644 b1fc6528d5808663942b0428869f0c72efda1931 5a0a71f380c8a83c66b4f4e5391e4ec54469033e M	src/link/MachO/ZigObject.zig |
| 36 | :000000 100644 0000000000000000000000000000000000000000 d04a8d533a03f8934a8546311007b867bde353d0 A	src/link/MappedFile.zig |
| 37 | :100644 100644 9f4535e1fe4ef7c6458ee94b571b4157ba422dc8 742b4664f178955b4668f130ebbacab0b9ac2550 M	src/link/Queue.zig |
| 38 | :100644 100644 a125a70aae790e7b750c96304bae1bdb3c86376c d60b91c30f93695076b8299c7e92d8f734812d32 M	src/link/Wasm.zig |
| 39 | :100644 100644 26d44c4463be802e0e7dea899980b28010b8ffc7 9d43e47ea2dbd949122ab7abfdf285ade21bc987 M	src/main.zig |
| 40 | :100644 100644 e999d2ae22663bcd84a9eb1fc112a317b12a9c02 1cf5c9b08274a55f6cd956ae433e4fb7141e1abd M	src/target.zig |
| 41 | :100644 100644 01605bdeeb36e4d51e986526e94c9a36e2cf07fa e492930031e7fb5d22d68402bc3e59299a084402 M	test/incremental/change_exports |
| 42 | :100644 100644 3e400b854eb60b4a81a3c9b2f0e3511e11ec3b26 699134100eec6942bc2414d29ab7188332f3a45a M	test/incremental/change_panic_handler |
| 43 | :100644 100644 9f7eb6c12f10b42d80e998f352ac9a0a1d5d0842 2d068d593eeb77a07b9c249fc0d7542f1cee4c6c M	test/incremental/change_panic_handler_explicit |
| 44 | :100644 100644 97049a1fc03ae2d9dfbdd07e6c06a9e756f133aa f3bfbbdd6922a0266e42c41f8e92cc96e15bc9fc M	test/incremental/change_struct_same_fields |
| 45 | :100644 100644 5c5d3329750eadc813f892bce6e05234ad563242 3bcae1cd211281cc29d4b970240174c40613fdd6 M	test/incremental/type_becomes_comptime_only |
| 46 | |
| 47 | diff --git a/CMakeLists.txt b/CMakeLists.txt |
| 48 | index 41bc62cead..d21ea2791c 100644 |
| 49 | --- a/CMakeLists.txt |
| 50 | +++ b/CMakeLists.txt |
| 51 | @@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES |
| 52 | src/link/Elf/relocatable.zig |
| 53 | src/link/Elf/relocation.zig |
| 54 | src/link/Elf/synthetic_sections.zig |
| 55 | + src/link/Elf2.zig |
| 56 | src/link/Goff.zig |
| 57 | src/link/LdScript.zig |
| 58 | src/link/Lld.zig |
| 59 | @@ -612,6 +613,7 @@ set(ZIG_STAGE2_SOURCES |
| 60 | src/link/MachO/synthetic.zig |
| 61 | src/link/MachO/Thunk.zig |
| 62 | src/link/MachO/uuid.zig |
| 63 | + src/link/MappedFile.zig |
| 64 | src/link/Queue.zig |
| 65 | src/link/StringTable.zig |
| 66 | src/link/Wasm.zig |
| 67 | diff --git a/build.zig b/build.zig |
| 68 | index 0466b79bf2..e8d54cc0cd 100644 |
| 69 | --- a/build.zig |
| 70 | +++ b/build.zig |
| 71 | @@ -202,6 +202,7 @@ pub fn build(b: *std.Build) !void { |
| 72 | }); |
| 73 | exe.pie = pie; |
| 74 | exe.entitlements = entitlements; |
| 75 | + exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); |
| 76 | |
| 77 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); |
| 78 | exe.use_llvm = use_llvm; |
| 79 | diff --git a/ci/x86_64-linux-debug-llvm.sh b/ci/x86_64-linux-debug-llvm.sh |
| 80 | old mode 100644 |
| 81 | new mode 100755 |
| 82 | diff --git a/lib/compiler_rt/fma.zig b/lib/compiler_rt/fma.zig |
| 83 | index 578139c5ac..79a120d5a2 100644 |
| 84 | --- a/lib/compiler_rt/fma.zig |
| 85 | +++ b/lib/compiler_rt/fma.zig |
| 86 | @@ -203,7 +203,7 @@ fn add_adjusted(a: f64, b: f64) f64 { |
| 87 | if (uhii & 1 == 0) { |
| 88 | // hibits += copysign(1.0, sum.hi, sum.lo) |
| 89 | const uloi: u64 = @bitCast(sum.lo); |
| 90 | - uhii += 1 - ((uhii ^ uloi) >> 62); |
| 91 | + uhii = uhii + 1 - ((uhii ^ uloi) >> 62); |
| 92 | sum.hi = @bitCast(uhii); |
| 93 | } |
| 94 | } |
| 95 | @@ -217,7 +217,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { |
| 96 | const bits_lost = -@as(i32, @intCast((uhii >> 52) & 0x7FF)) - scale + 1; |
| 97 | if ((bits_lost != 1) == (uhii & 1 != 0)) { |
| 98 | const uloi: u64 = @bitCast(sum.lo); |
| 99 | - uhii += 1 - (((uhii ^ uloi) >> 62) & 2); |
| 100 | + uhii = uhii + 1 - (((uhii ^ uloi) >> 62) & 2); |
| 101 | sum.hi = @bitCast(uhii); |
| 102 | } |
| 103 | } |
| 104 | @@ -259,7 +259,7 @@ fn add_adjusted128(a: f128, b: f128) f128 { |
| 105 | if (uhii & 1 == 0) { |
| 106 | // hibits += copysign(1.0, sum.hi, sum.lo) |
| 107 | const uloi: u128 = @bitCast(sum.lo); |
| 108 | - uhii += 1 - ((uhii ^ uloi) >> 126); |
| 109 | + uhii = uhii + 1 - ((uhii ^ uloi) >> 126); |
| 110 | sum.hi = @bitCast(uhii); |
| 111 | } |
| 112 | } |
| 113 | @@ -284,7 +284,7 @@ fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 { |
| 114 | const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1; |
| 115 | if ((bits_lost != 1) == (uhii & 1 != 0)) { |
| 116 | const uloi: u128 = @bitCast(sum.lo); |
| 117 | - uhii += 1 - (((uhii ^ uloi) >> 126) & 2); |
| 118 | + uhii = uhii + 1 - (((uhii ^ uloi) >> 126) & 2); |
| 119 | sum.hi = @bitCast(uhii); |
| 120 | } |
| 121 | } |
| 122 | diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig |
| 123 | index dad60b725b..0f47a0b647 100644 |
| 124 | --- a/lib/std/Build/Step/Compile.zig |
| 125 | +++ b/lib/std/Build/Step/Compile.zig |
| 126 | @@ -192,6 +192,7 @@ want_lto: ?bool = null, |
| 127 | |
| 128 | use_llvm: ?bool, |
| 129 | use_lld: ?bool, |
| 130 | +use_new_linker: ?bool, |
| 131 | |
| 132 | /// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI |
| 133 | /// flags, overriding the global user setting provided to the `zig build` |
| 134 | @@ -441,6 +442,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 135 | |
| 136 | .use_llvm = options.use_llvm, |
| 137 | .use_lld = options.use_lld, |
| 138 | + .use_new_linker = null, |
| 139 | |
| 140 | .zig_process = null, |
| 141 | }; |
| 142 | @@ -1096,6 +1098,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 143 | |
| 144 | try addFlag(&zig_args, "llvm", compile.use_llvm); |
| 145 | try addFlag(&zig_args, "lld", compile.use_lld); |
| 146 | + try addFlag(&zig_args, "new-linker", compile.use_new_linker); |
| 147 | |
| 148 | if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| { |
| 149 | try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)})); |
| 150 | diff --git a/lib/std/elf.zig b/lib/std/elf.zig |
| 151 | index bef80d782b..43b542c09e 100644 |
| 152 | --- a/lib/std/elf.zig |
| 153 | +++ b/lib/std/elf.zig |
| 154 | @@ -323,6 +323,8 @@ pub const PT_LOPROC = 0x70000000; |
| 155 | /// End of processor-specific |
| 156 | pub const PT_HIPROC = 0x7fffffff; |
| 157 | |
| 158 | +pub const PN_XNUM = 0xffff; |
| 159 | + |
| 160 | /// Section header table entry unused |
| 161 | pub const SHT_NULL = 0; |
| 162 | /// Program data |
| 163 | @@ -385,63 +387,149 @@ pub const SHT_HIUSER = 0xffffffff; |
| 164 | // Note type for .note.gnu.build_id |
| 165 | pub const NT_GNU_BUILD_ID = 3; |
| 166 | |
| 167 | -/// Local symbol |
| 168 | -pub const STB_LOCAL = 0; |
| 169 | -/// Global symbol |
| 170 | -pub const STB_GLOBAL = 1; |
| 171 | -/// Weak symbol |
| 172 | -pub const STB_WEAK = 2; |
| 173 | -/// Number of defined types |
| 174 | -pub const STB_NUM = 3; |
| 175 | -/// Start of OS-specific |
| 176 | -pub const STB_LOOS = 10; |
| 177 | -/// Unique symbol |
| 178 | -pub const STB_GNU_UNIQUE = 10; |
| 179 | -/// End of OS-specific |
| 180 | -pub const STB_HIOS = 12; |
| 181 | -/// Start of processor-specific |
| 182 | -pub const STB_LOPROC = 13; |
| 183 | -/// End of processor-specific |
| 184 | -pub const STB_HIPROC = 15; |
| 185 | - |
| 186 | -pub const STB_MIPS_SPLIT_COMMON = 13; |
| 187 | - |
| 188 | -/// Symbol type is unspecified |
| 189 | -pub const STT_NOTYPE = 0; |
| 190 | -/// Symbol is a data object |
| 191 | -pub const STT_OBJECT = 1; |
| 192 | -/// Symbol is a code object |
| 193 | -pub const STT_FUNC = 2; |
| 194 | -/// Symbol associated with a section |
| 195 | -pub const STT_SECTION = 3; |
| 196 | -/// Symbol's name is file name |
| 197 | -pub const STT_FILE = 4; |
| 198 | -/// Symbol is a common data object |
| 199 | -pub const STT_COMMON = 5; |
| 200 | -/// Symbol is thread-local data object |
| 201 | -pub const STT_TLS = 6; |
| 202 | -/// Number of defined types |
| 203 | -pub const STT_NUM = 7; |
| 204 | -/// Start of OS-specific |
| 205 | -pub const STT_LOOS = 10; |
| 206 | -/// Symbol is indirect code object |
| 207 | -pub const STT_GNU_IFUNC = 10; |
| 208 | -/// End of OS-specific |
| 209 | -pub const STT_HIOS = 12; |
| 210 | -/// Start of processor-specific |
| 211 | -pub const STT_LOPROC = 13; |
| 212 | -/// End of processor-specific |
| 213 | -pub const STT_HIPROC = 15; |
| 214 | +/// Deprecated, use `@intFromEnum(std.elf.STB.LOCAL)` |
| 215 | +pub const STB_LOCAL = @intFromEnum(STB.LOCAL); |
| 216 | +/// Deprecated, use `@intFromEnum(std.elf.STB.GLOBAL)` |
| 217 | +pub const STB_GLOBAL = @intFromEnum(STB.GLOBAL); |
| 218 | +/// Deprecated, use `@intFromEnum(std.elf.STB.WEAK)` |
| 219 | +pub const STB_WEAK = @intFromEnum(STB.WEAK); |
| 220 | +/// Deprecated, use `std.elf.STB.NUM` |
| 221 | +pub const STB_NUM = STB.NUM; |
| 222 | +/// Deprecated, use `@intFromEnum(std.elf.STB.LOOS)` |
| 223 | +pub const STB_LOOS = @intFromEnum(STB.LOOS); |
| 224 | +/// Deprecated, use `@intFromEnum(std.elf.STB.GNU_UNIQUE)` |
| 225 | +pub const STB_GNU_UNIQUE = @intFromEnum(STB.GNU_UNIQUE); |
| 226 | +/// Deprecated, use `@intFromEnum(std.elf.STB.HIOS)` |
| 227 | +pub const STB_HIOS = @intFromEnum(STB.HIOS); |
| 228 | +/// Deprecated, use `@intFromEnum(std.elf.STB.LOPROC)` |
| 229 | +pub const STB_LOPROC = @intFromEnum(STB.LOPROC); |
| 230 | +/// Deprecated, use `@intFromEnum(std.elf.STB.HIPROC)` |
| 231 | +pub const STB_HIPROC = @intFromEnum(STB.HIPROC); |
| 232 | + |
| 233 | +/// Deprecated, use `@intFromEnum(std.elf.STB.MIPS_SPLIT_COMMON)` |
| 234 | +pub const STB_MIPS_SPLIT_COMMON = @intFromEnum(STB.MIBS_SPLIT_COMMON); |
| 235 | + |
| 236 | +/// Deprecated, use `@intFromEnum(std.elf.STT.NOTYPE)` |
| 237 | +pub const STT_NOTYPE = @intFromEnum(STT.NOTYPE); |
| 238 | +/// Deprecated, use `@intFromEnum(std.elf.STT.OBJECT)` |
| 239 | +pub const STT_OBJECT = @intFromEnum(STT.OBJECT); |
| 240 | +/// Deprecated, use `@intFromEnum(std.elf.STT.FUNC)` |
| 241 | +pub const STT_FUNC = @intFromEnum(STT.FUNC); |
| 242 | +/// Deprecated, use `@intFromEnum(std.elf.STT.SECTION)` |
| 243 | +pub const STT_SECTION = @intFromEnum(STT.SECTION); |
| 244 | +/// Deprecated, use `@intFromEnum(std.elf.STT.FILE)` |
| 245 | +pub const STT_FILE = @intFromEnum(STT.FILE); |
| 246 | +/// Deprecated, use `@intFromEnum(std.elf.STT.COMMON)` |
| 247 | +pub const STT_COMMON = @intFromEnum(STT.COMMON); |
| 248 | +/// Deprecated, use `@intFromEnum(std.elf.STT.TLS)` |
| 249 | +pub const STT_TLS = @intFromEnum(STT.TLS); |
| 250 | +/// Deprecated, use `std.elf.STT.NUM` |
| 251 | +pub const STT_NUM = STT.NUM; |
| 252 | +/// Deprecated, use `@intFromEnum(std.elf.STT.LOOS)` |
| 253 | +pub const STT_LOOS = @intFromEnum(STT.LOOS); |
| 254 | +/// Deprecated, use `@intFromEnum(std.elf.STT.GNU_IFUNC)` |
| 255 | +pub const STT_GNU_IFUNC = @intFromEnum(STT.GNU_IFUNC); |
| 256 | +/// Deprecated, use `@intFromEnum(std.elf.STT.HIOS)` |
| 257 | +pub const STT_HIOS = @intFromEnum(STT.HIOS); |
| 258 | +/// Deprecated, use `@intFromEnum(std.elf.STT.LOPROC)` |
| 259 | +pub const STT_LOPROC = @intFromEnum(STT.LOPROC); |
| 260 | +/// Deprecated, use `@intFromEnum(std.elf.STT.HIPROC)` |
| 261 | +pub const STT_HIPROC = @intFromEnum(STT.HIPROC); |
| 262 | + |
| 263 | +/// Deprecated, use `@intFromEnum(std.elf.STT.SPARC_REGISTER)` |
| 264 | +pub const STT_SPARC_REGISTER = @intFromEnum(STT.SPARC_REGISTER); |
| 265 | + |
| 266 | +/// Deprecated, use `@intFromEnum(std.elf.STT.PARISC_MILLICODE)` |
| 267 | +pub const STT_PARISC_MILLICODE = @intFromEnum(STT.PARISC_MILLICODE); |
| 268 | + |
| 269 | +/// Deprecated, use `@intFromEnum(std.elf.STT.HP_OPAQUE)` |
| 270 | +pub const STT_HP_OPAQUE = @intFromEnum(STT.HP_OPAQUE); |
| 271 | +/// Deprecated, use `@intFromEnum(std.elf.STT.HP_STUB)` |
| 272 | +pub const STT_HP_STUB = @intFromEnum(STT.HP_STUB); |
| 273 | + |
| 274 | +/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_TFUNC)` |
| 275 | +pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC); |
| 276 | +/// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)` |
| 277 | +pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT); |
| 278 | + |
| 279 | +pub const STB = enum(u4) { |
| 280 | + /// Local symbol |
| 281 | + LOCAL = 0, |
| 282 | + /// Global symbol |
| 283 | + GLOBAL = 1, |
| 284 | + /// Weak symbol |
| 285 | + WEAK = 2, |
| 286 | + _, |
| 287 | + |
| 288 | + /// Number of defined types |
| 289 | + pub const NUM = @typeInfo(STB).@"enum".fields.len; |
| 290 | + |
| 291 | + /// Start of OS-specific |
| 292 | + pub const LOOS: STB = @enumFromInt(10); |
| 293 | + /// End of OS-specific |
| 294 | + pub const HIOS: STB = @enumFromInt(12); |
| 295 | + |
| 296 | + /// Unique symbol |
| 297 | + pub const GNU_UNIQUE: STB = @enumFromInt(@intFromEnum(LOOS) + 0); |
| 298 | + |
| 299 | + /// Start of processor-specific |
| 300 | + pub const LOPROC: STB = @enumFromInt(13); |
| 301 | + /// End of processor-specific |
| 302 | + pub const HIPROC: STB = @enumFromInt(15); |
| 303 | + |
| 304 | + pub const MIPS_SPLIT_COMMON: STB = @enumFromInt(@intFromEnum(LOPROC) + 0); |
| 305 | +}; |
| 306 | + |
| 307 | +pub const STT = enum(u4) { |
| 308 | + /// Symbol type is unspecified |
| 309 | + NOTYPE = 0, |
| 310 | + /// Symbol is a data object |
| 311 | + OBJECT = 1, |
| 312 | + /// Symbol is a code object |
| 313 | + FUNC = 2, |
| 314 | + /// Symbol associated with a section |
| 315 | + SECTION = 3, |
| 316 | + /// Symbol's name is file name |
| 317 | + FILE = 4, |
| 318 | + /// Symbol is a common data object |
| 319 | + COMMON = 5, |
| 320 | + /// Symbol is thread-local data object |
| 321 | + TLS = 6, |
| 322 | + _, |
| 323 | + |
| 324 | + /// Number of defined types |
| 325 | + pub const NUM = @typeInfo(STT).@"enum".fields.len; |
| 326 | + |
| 327 | + /// Start of OS-specific |
| 328 | + pub const LOOS: STT = @enumFromInt(10); |
| 329 | + /// End of OS-specific |
| 330 | + pub const HIOS: STT = @enumFromInt(12); |
| 331 | |
| 332 | -pub const STT_SPARC_REGISTER = 13; |
| 333 | + /// Symbol is indirect code object |
| 334 | + pub const GNU_IFUNC: STT = @enumFromInt(@intFromEnum(LOOS) + 0); |
| 335 | |
| 336 | -pub const STT_PARISC_MILLICODE = 13; |
| 337 | + pub const HP_OPAQUE: STT = @enumFromInt(@intFromEnum(LOOS) + 1); |
| 338 | + pub const HP_STUB: STT = @enumFromInt(@intFromEnum(LOOS) + 2); |
| 339 | |
| 340 | -pub const STT_HP_OPAQUE = (STT_LOOS + 0x1); |
| 341 | -pub const STT_HP_STUB = (STT_LOOS + 0x2); |
| 342 | + /// Start of processor-specific |
| 343 | + pub const LOPROC: STT = @enumFromInt(13); |
| 344 | + /// End of processor-specific |
| 345 | + pub const HIPROC: STT = @enumFromInt(15); |
| 346 | |
| 347 | -pub const STT_ARM_TFUNC = STT_LOPROC; |
| 348 | -pub const STT_ARM_16BIT = STT_HIPROC; |
| 349 | + pub const SPARC_REGISTER: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); |
| 350 | + |
| 351 | + pub const PARISC_MILLICODE: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); |
| 352 | + |
| 353 | + pub const ARM_TFUNC: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); |
| 354 | + pub const ARM_16BIT: STT = @enumFromInt(@intFromEnum(HIPROC) + 2); |
| 355 | +}; |
| 356 | + |
| 357 | +pub const STV = enum(u3) { |
| 358 | + DEFAULT = 0, |
| 359 | + INTERNAL = 1, |
| 360 | + HIDDEN = 2, |
| 361 | + PROTECTED = 3, |
| 362 | +}; |
| 363 | |
| 364 | pub const MAGIC = "\x7fELF"; |
| 365 | |
| 366 | @@ -534,15 +622,15 @@ pub const Header = struct { |
| 367 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); |
| 368 | |
| 369 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; |
| 370 | - if (buf[EI_VERSION] != 1) return error.InvalidElfVersion; |
| 371 | + if (buf[EI.VERSION] != 1) return error.InvalidElfVersion; |
| 372 | |
| 373 | - const endian: std.builtin.Endian = switch (buf[EI_DATA]) { |
| 374 | + const endian: std.builtin.Endian = switch (buf[EI.DATA]) { |
| 375 | ELFDATA2LSB => .little, |
| 376 | ELFDATA2MSB => .big, |
| 377 | else => return error.InvalidElfEndian, |
| 378 | }; |
| 379 | |
| 380 | - return switch (buf[EI_CLASS]) { |
| 381 | + return switch (buf[EI.CLASS]) { |
| 382 | ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian), |
| 383 | ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian), |
| 384 | else => return error.InvalidElfClass, |
| 385 | @@ -559,8 +647,8 @@ pub const Header = struct { |
| 386 | else => @compileError("bad type"), |
| 387 | }, |
| 388 | .endian = endian, |
| 389 | - .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]), |
| 390 | - .abi_version = hdr.e_ident[EI_ABIVERSION], |
| 391 | + .os_abi = @enumFromInt(hdr.e_ident[EI.OSABI]), |
| 392 | + .abi_version = hdr.e_ident[EI.ABIVERSION], |
| 393 | .type = hdr.e_type, |
| 394 | .machine = hdr.e_machine, |
| 395 | .entry = hdr.e_entry, |
| 396 | @@ -683,38 +771,200 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { |
| 397 | }; |
| 398 | } |
| 399 | |
| 400 | -pub const ELFCLASSNONE = 0; |
| 401 | -pub const ELFCLASS32 = 1; |
| 402 | -pub const ELFCLASS64 = 2; |
| 403 | -pub const ELFCLASSNUM = 3; |
| 404 | - |
| 405 | -pub const ELFDATANONE = 0; |
| 406 | -pub const ELFDATA2LSB = 1; |
| 407 | -pub const ELFDATA2MSB = 2; |
| 408 | -pub const ELFDATANUM = 3; |
| 409 | - |
| 410 | -pub const EI_CLASS = 4; |
| 411 | -pub const EI_DATA = 5; |
| 412 | -pub const EI_VERSION = 6; |
| 413 | -pub const EI_OSABI = 7; |
| 414 | -pub const EI_ABIVERSION = 8; |
| 415 | -pub const EI_PAD = 9; |
| 416 | - |
| 417 | -pub const EI_NIDENT = 16; |
| 418 | +pub const EI = struct { |
| 419 | + pub const CLASS = 4; |
| 420 | + pub const DATA = 5; |
| 421 | + pub const VERSION = 6; |
| 422 | + pub const OSABI = 7; |
| 423 | + pub const ABIVERSION = 8; |
| 424 | + pub const PAD = 9; |
| 425 | + pub const NIDENT = 16; |
| 426 | +}; |
| 427 | + |
| 428 | +/// Deprecated, use `std.elf.EI.CLASS` |
| 429 | +pub const EI_CLASS = EI.CLASS; |
| 430 | +/// Deprecated, use `std.elf.EI.DATA` |
| 431 | +pub const EI_DATA = EI.DATA; |
| 432 | +/// Deprecated, use `std.elf.EI.VERSION` |
| 433 | +pub const EI_VERSION = EI.VERSION; |
| 434 | +/// Deprecated, use `std.elf.EI.OSABI` |
| 435 | +pub const EI_OSABI = EI.OSABI; |
| 436 | +/// Deprecated, use `std.elf.EI.ABIVERSION` |
| 437 | +pub const EI_ABIVERSION = EI.ABIVERSION; |
| 438 | +/// Deprecated, use `std.elf.EI.PAD` |
| 439 | +pub const EI_PAD = EI.PAD; |
| 440 | +/// Deprecated, use `std.elf.EI.NIDENT` |
| 441 | +pub const EI_NIDENT = EI.NIDENT; |
| 442 | |
| 443 | pub const Half = u16; |
| 444 | pub const Word = u32; |
| 445 | pub const Sword = i32; |
| 446 | -pub const Elf32_Xword = u64; |
| 447 | -pub const Elf32_Sxword = i64; |
| 448 | -pub const Elf64_Xword = u64; |
| 449 | +pub const Xword = u64; |
| 450 | +pub const Sxword = i64; |
| 451 | +pub const Section = u16; |
| 452 | +pub const Elf32 = struct { |
| 453 | + pub const Addr = u32; |
| 454 | + pub const Off = u32; |
| 455 | + pub const Ehdr = extern struct { |
| 456 | + ident: [EI.NIDENT]u8, |
| 457 | + type: ET, |
| 458 | + machine: EM, |
| 459 | + version: Word, |
| 460 | + entry: Elf32.Addr, |
| 461 | + phoff: Elf32.Off, |
| 462 | + shoff: Elf32.Off, |
| 463 | + flags: Word, |
| 464 | + ehsize: Half, |
| 465 | + phentsize: Half, |
| 466 | + phnum: Half, |
| 467 | + shentsize: Half, |
| 468 | + shnum: Half, |
| 469 | + shstrndx: Half, |
| 470 | + }; |
| 471 | + pub const Phdr = extern struct { |
| 472 | + type: Word, |
| 473 | + offset: Elf32.Off, |
| 474 | + vaddr: Elf32.Addr, |
| 475 | + paddr: Elf32.Addr, |
| 476 | + filesz: Word, |
| 477 | + memsz: Word, |
| 478 | + flags: PF, |
| 479 | + @"align": Word, |
| 480 | + }; |
| 481 | + pub const Shdr = extern struct { |
| 482 | + name: Word, |
| 483 | + type: Word, |
| 484 | + flags: packed struct { shf: SHF }, |
| 485 | + addr: Elf32.Addr, |
| 486 | + offset: Elf32.Off, |
| 487 | + size: Word, |
| 488 | + link: Word, |
| 489 | + info: Word, |
| 490 | + addralign: Word, |
| 491 | + entsize: Word, |
| 492 | + }; |
| 493 | + pub const Chdr = extern struct { |
| 494 | + type: COMPRESS, |
| 495 | + size: Word, |
| 496 | + addralign: Word, |
| 497 | + }; |
| 498 | + pub const Sym = extern struct { |
| 499 | + name: Word, |
| 500 | + value: Elf32.Addr, |
| 501 | + size: Word, |
| 502 | + info: Info, |
| 503 | + other: Other, |
| 504 | + shndx: Section, |
| 505 | + |
| 506 | + pub const Info = packed struct(u8) { |
| 507 | + type: STT, |
| 508 | + bind: STB, |
| 509 | + }; |
| 510 | + |
| 511 | + pub const Other = packed struct(u8) { |
| 512 | + visibility: STV, |
| 513 | + unused: u5 = 0, |
| 514 | + }; |
| 515 | + }; |
| 516 | + comptime { |
| 517 | + assert(@sizeOf(Elf32.Ehdr) == 52); |
| 518 | + assert(@sizeOf(Elf32.Phdr) == 32); |
| 519 | + assert(@sizeOf(Elf32.Shdr) == 40); |
| 520 | + assert(@sizeOf(Elf32.Sym) == 16); |
| 521 | + } |
| 522 | +}; |
| 523 | +pub const Elf64 = struct { |
| 524 | + pub const Addr = u64; |
| 525 | + pub const Off = u64; |
| 526 | + pub const Ehdr = extern struct { |
| 527 | + ident: [EI.NIDENT]u8, |
| 528 | + type: ET, |
| 529 | + machine: EM, |
| 530 | + version: Word, |
| 531 | + entry: Elf64.Addr, |
| 532 | + phoff: Elf64.Off, |
| 533 | + shoff: Elf64.Off, |
| 534 | + flags: Word, |
| 535 | + ehsize: Half, |
| 536 | + phentsize: Half, |
| 537 | + phnum: Half, |
| 538 | + shentsize: Half, |
| 539 | + shnum: Half, |
| 540 | + shstrndx: Half, |
| 541 | + }; |
| 542 | + pub const Phdr = extern struct { |
| 543 | + type: Word, |
| 544 | + flags: PF, |
| 545 | + offset: Elf64.Off, |
| 546 | + vaddr: Elf64.Addr, |
| 547 | + paddr: Elf64.Addr, |
| 548 | + filesz: Xword, |
| 549 | + memsz: Xword, |
| 550 | + @"align": Xword, |
| 551 | + }; |
| 552 | + pub const Shdr = extern struct { |
| 553 | + name: Word, |
| 554 | + type: Word, |
| 555 | + flags: packed struct { shf: SHF, unused: Word = 0 }, |
| 556 | + addr: Elf64.Addr, |
| 557 | + offset: Elf64.Off, |
| 558 | + size: Xword, |
| 559 | + link: Word, |
| 560 | + info: Word, |
| 561 | + addralign: Xword, |
| 562 | + entsize: Xword, |
| 563 | + }; |
| 564 | + pub const Chdr = extern struct { |
| 565 | + type: COMPRESS, |
| 566 | + reserved: Word = 0, |
| 567 | + size: Xword, |
| 568 | + addralign: Xword, |
| 569 | + }; |
| 570 | + pub const Sym = extern struct { |
| 571 | + name: Word, |
| 572 | + info: Info, |
| 573 | + other: Other, |
| 574 | + shndx: Section, |
| 575 | + value: Elf64.Addr, |
| 576 | + size: Xword, |
| 577 | + |
| 578 | + pub const Info = Elf32.Sym.Info; |
| 579 | + pub const Other = Elf32.Sym.Other; |
| 580 | + }; |
| 581 | + comptime { |
| 582 | + assert(@sizeOf(Elf64.Ehdr) == 64); |
| 583 | + assert(@sizeOf(Elf64.Phdr) == 56); |
| 584 | + assert(@sizeOf(Elf64.Shdr) == 64); |
| 585 | + assert(@sizeOf(Elf64.Sym) == 24); |
| 586 | + } |
| 587 | +}; |
| 588 | +pub const ElfN = switch (@sizeOf(usize)) { |
| 589 | + 4 => Elf32, |
| 590 | + 8 => Elf64, |
| 591 | + else => @compileError("expected pointer size of 32 or 64"), |
| 592 | +}; |
| 593 | + |
| 594 | +/// Deprecated, use `std.elf.Xword` |
| 595 | +pub const Elf32_Xword = Xword; |
| 596 | +/// Deprecated, use `std.elf.Sxword` |
| 597 | +pub const Elf32_Sxword = Sxword; |
| 598 | +/// Deprecated, use `std.elf.Xword` |
| 599 | +pub const Elf64_Xword = Xword; |
| 600 | +/// Deprecated, use `std.elf.Sxword` |
| 601 | pub const Elf64_Sxword = i64; |
| 602 | +/// Deprecated, use `std.elf.Elf32.Addr` |
| 603 | pub const Elf32_Addr = u32; |
| 604 | +/// Deprecated, use `std.elf.Elf64.Addr` |
| 605 | pub const Elf64_Addr = u64; |
| 606 | +/// Deprecated, use `std.elf.Elf32.Off` |
| 607 | pub const Elf32_Off = u32; |
| 608 | +/// Deprecated, use `std.elf.Elf64.Off` |
| 609 | pub const Elf64_Off = u64; |
| 610 | +/// Deprecated, use `std.elf.Section` |
| 611 | pub const Elf32_Section = u16; |
| 612 | +/// Deprecated, use `std.elf.Section` |
| 613 | pub const Elf64_Section = u16; |
| 614 | +/// Deprecated, use `std.elf.Elf32.Ehdr` |
| 615 | pub const Elf32_Ehdr = extern struct { |
| 616 | e_ident: [EI_NIDENT]u8, |
| 617 | e_type: ET, |
| 618 | @@ -731,8 +981,9 @@ pub const Elf32_Ehdr = extern struct { |
| 619 | e_shnum: Half, |
| 620 | e_shstrndx: Half, |
| 621 | }; |
| 622 | +/// Deprecated, use `std.elf.Elf64.Ehdr` |
| 623 | pub const Elf64_Ehdr = extern struct { |
| 624 | - e_ident: [EI_NIDENT]u8, |
| 625 | + e_ident: [EI.NIDENT]u8, |
| 626 | e_type: ET, |
| 627 | e_machine: EM, |
| 628 | e_version: Word, |
| 629 | @@ -747,6 +998,7 @@ pub const Elf64_Ehdr = extern struct { |
| 630 | e_shnum: Half, |
| 631 | e_shstrndx: Half, |
| 632 | }; |
| 633 | +/// Deprecated, use `std.elf.Elf32.Phdr` |
| 634 | pub const Elf32_Phdr = extern struct { |
| 635 | p_type: Word, |
| 636 | p_offset: Elf32_Off, |
| 637 | @@ -757,6 +1009,7 @@ pub const Elf32_Phdr = extern struct { |
| 638 | p_flags: Word, |
| 639 | p_align: Word, |
| 640 | }; |
| 641 | +/// Deprecated, use `std.elf.Elf64.Phdr` |
| 642 | pub const Elf64_Phdr = extern struct { |
| 643 | p_type: Word, |
| 644 | p_flags: Word, |
| 645 | @@ -767,6 +1020,7 @@ pub const Elf64_Phdr = extern struct { |
| 646 | p_memsz: Elf64_Xword, |
| 647 | p_align: Elf64_Xword, |
| 648 | }; |
| 649 | +/// Deprecated, use `std.elf.Elf32.Shdr` |
| 650 | pub const Elf32_Shdr = extern struct { |
| 651 | sh_name: Word, |
| 652 | sh_type: Word, |
| 653 | @@ -779,6 +1033,7 @@ pub const Elf32_Shdr = extern struct { |
| 654 | sh_addralign: Word, |
| 655 | sh_entsize: Word, |
| 656 | }; |
| 657 | +/// Deprecated, use `std.elf.Elf64.Shdr` |
| 658 | pub const Elf64_Shdr = extern struct { |
| 659 | sh_name: Word, |
| 660 | sh_type: Word, |
| 661 | @@ -791,17 +1046,20 @@ pub const Elf64_Shdr = extern struct { |
| 662 | sh_addralign: Elf64_Xword, |
| 663 | sh_entsize: Elf64_Xword, |
| 664 | }; |
| 665 | +/// Deprecated, use `std.elf.Elf32.Chdr` |
| 666 | pub const Elf32_Chdr = extern struct { |
| 667 | ch_type: COMPRESS, |
| 668 | ch_size: Word, |
| 669 | ch_addralign: Word, |
| 670 | }; |
| 671 | +/// Deprecated, use `std.elf.Elf64.Chdr` |
| 672 | pub const Elf64_Chdr = extern struct { |
| 673 | ch_type: COMPRESS, |
| 674 | ch_reserved: Word = 0, |
| 675 | ch_size: Elf64_Xword, |
| 676 | ch_addralign: Elf64_Xword, |
| 677 | }; |
| 678 | +/// Deprecated, use `std.elf.Elf32.Sym` |
| 679 | pub const Elf32_Sym = extern struct { |
| 680 | st_name: Word, |
| 681 | st_value: Elf32_Addr, |
| 682 | @@ -817,6 +1075,7 @@ pub const Elf32_Sym = extern struct { |
| 683 | return @truncate(self.st_info >> 4); |
| 684 | } |
| 685 | }; |
| 686 | +/// Deprecated, use `std.elf.Elf64.Sym` |
| 687 | pub const Elf64_Sym = extern struct { |
| 688 | st_name: Word, |
| 689 | st_info: u8, |
| 690 | @@ -1020,27 +1279,18 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct { |
| 691 | flags2: Word, |
| 692 | }; |
| 693 | |
| 694 | -comptime { |
| 695 | - assert(@sizeOf(Elf32_Ehdr) == 52); |
| 696 | - assert(@sizeOf(Elf64_Ehdr) == 64); |
| 697 | - |
| 698 | - assert(@sizeOf(Elf32_Phdr) == 32); |
| 699 | - assert(@sizeOf(Elf64_Phdr) == 56); |
| 700 | - |
| 701 | - assert(@sizeOf(Elf32_Shdr) == 40); |
| 702 | - assert(@sizeOf(Elf64_Shdr) == 64); |
| 703 | -} |
| 704 | - |
| 705 | pub const Auxv = switch (@sizeOf(usize)) { |
| 706 | 4 => Elf32_auxv_t, |
| 707 | 8 => Elf64_auxv_t, |
| 708 | else => @compileError("expected pointer size of 32 or 64"), |
| 709 | }; |
| 710 | +/// Deprecated, use `std.elf.ElfN.Ehdr` |
| 711 | pub const Ehdr = switch (@sizeOf(usize)) { |
| 712 | 4 => Elf32_Ehdr, |
| 713 | 8 => Elf64_Ehdr, |
| 714 | else => @compileError("expected pointer size of 32 or 64"), |
| 715 | }; |
| 716 | +/// Deprecated, use `std.elf.ElfN.Phdr` |
| 717 | pub const Phdr = switch (@sizeOf(usize)) { |
| 718 | 4 => Elf32_Phdr, |
| 719 | 8 => Elf64_Phdr, |
| 720 | @@ -1071,20 +1321,53 @@ pub const Shdr = switch (@sizeOf(usize)) { |
| 721 | 8 => Elf64_Shdr, |
| 722 | else => @compileError("expected pointer size of 32 or 64"), |
| 723 | }; |
| 724 | +/// Deprecated, use `std.elf.ElfN.Chdr` |
| 725 | pub const Chdr = switch (@sizeOf(usize)) { |
| 726 | 4 => Elf32_Chdr, |
| 727 | 8 => Elf64_Chdr, |
| 728 | else => @compileError("expected pointer size of 32 or 64"), |
| 729 | }; |
| 730 | +/// Deprecated, use `std.elf.ElfN.Sym` |
| 731 | pub const Sym = switch (@sizeOf(usize)) { |
| 732 | 4 => Elf32_Sym, |
| 733 | 8 => Elf64_Sym, |
| 734 | else => @compileError("expected pointer size of 32 or 64"), |
| 735 | }; |
| 736 | -pub const Addr = switch (@sizeOf(usize)) { |
| 737 | - 4 => Elf32_Addr, |
| 738 | - 8 => Elf64_Addr, |
| 739 | - else => @compileError("expected pointer size of 32 or 64"), |
| 740 | +/// Deprecated, use `std.elf.ElfN.Addr` |
| 741 | +pub const Addr = ElfN.Addr; |
| 742 | + |
| 743 | +/// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)` |
| 744 | +pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE); |
| 745 | +/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")` |
| 746 | +pub const ELFCLASS32 = @intFromEnum(CLASS.@"32"); |
| 747 | +/// Deprecated, use `@intFromEnum(std.elf.CLASS.@"64")` |
| 748 | +pub const ELFCLASS64 = @intFromEnum(CLASS.@"64"); |
| 749 | +/// Deprecated, use `@intFromEnum(std.elf.CLASS.NUM)` |
| 750 | +pub const ELFCLASSNUM = CLASS.NUM; |
| 751 | +pub const CLASS = enum(u8) { |
| 752 | + NONE = 0, |
| 753 | + @"32" = 1, |
| 754 | + @"64" = 2, |
| 755 | + _, |
| 756 | + |
| 757 | + pub const NUM = @typeInfo(CLASS).@"enum".fields.len; |
| 758 | +}; |
| 759 | + |
| 760 | +/// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)` |
| 761 | +pub const ELFDATANONE = @intFromEnum(DATA.NONE); |
| 762 | +/// Deprecated, use `@intFromEnum(std.elf.DATA.@"2LSB")` |
| 763 | +pub const ELFDATA2LSB = @intFromEnum(DATA.@"2LSB"); |
| 764 | +/// Deprecated, use `@intFromEnum(std.elf.DATA.@"2MSB")` |
| 765 | +pub const ELFDATA2MSB = @intFromEnum(DATA.@"2MSB"); |
| 766 | +/// Deprecated, use `@intFromEnum(std.elf.DATA.NUM)` |
| 767 | +pub const ELFDATANUM = DATA.NUM; |
| 768 | +pub const DATA = enum(u8) { |
| 769 | + NONE = 0, |
| 770 | + @"2LSB" = 1, |
| 771 | + @"2MSB" = 2, |
| 772 | + _, |
| 773 | + |
| 774 | + pub const NUM = @typeInfo(DATA).@"enum".fields.len; |
| 775 | }; |
| 776 | |
| 777 | pub const OSABI = enum(u8) { |
| 778 | @@ -1718,6 +2001,108 @@ pub const SHF_MIPS_STRING = 0x80000000; |
| 779 | /// Make code section unreadable when in execute-only mode |
| 780 | pub const SHF_ARM_PURECODE = 0x2000000; |
| 781 | |
| 782 | +pub const SHF = packed struct(Word) { |
| 783 | + /// Section data should be writable during execution. |
| 784 | + WRITE: bool = false, |
| 785 | + /// Section occupies memory during program execution. |
| 786 | + ALLOC: bool = false, |
| 787 | + /// Section contains executable machine instructions. |
| 788 | + EXECINSTR: bool = false, |
| 789 | + unused3: u1 = 0, |
| 790 | + /// The data in this section may be merged. |
| 791 | + MERGE: bool = false, |
| 792 | + /// The data in this section is null-terminated strings. |
| 793 | + STRINGS: bool = false, |
| 794 | + /// A field in this section holds a section header table index. |
| 795 | + INFO_LINK: bool = false, |
| 796 | + /// Adds special ordering requirements for link editors. |
| 797 | + LINK_ORDER: bool = false, |
| 798 | + /// This section requires special OS-specific processing to avoid incorrect behavior. |
| 799 | + OS_NONCONFORMING: bool = false, |
| 800 | + /// This section is a member of a section group. |
| 801 | + GROUP: bool = false, |
| 802 | + /// This section holds Thread-Local Storage. |
| 803 | + TLS: bool = false, |
| 804 | + /// Identifies a section containing compressed data. |
| 805 | + COMPRESSED: bool = false, |
| 806 | + unused12: u8 = 0, |
| 807 | + OS: packed union { |
| 808 | + MASK: u8, |
| 809 | + GNU: packed struct(u8) { |
| 810 | + unused0: u1 = 0, |
| 811 | + /// Not to be GCed by the linker |
| 812 | + RETAIN: bool = false, |
| 813 | + unused2: u6 = 0, |
| 814 | + }, |
| 815 | + MIPS: packed struct(u8) { |
| 816 | + unused0: u4 = 0, |
| 817 | + /// Section contains text/data which may be replicated in other sections. |
| 818 | + /// Linker must retain only one copy. |
| 819 | + NODUPES: bool = false, |
| 820 | + /// Linker must generate implicit hidden weak names. |
| 821 | + NAMES: bool = false, |
| 822 | + /// Section data local to process. |
| 823 | + LOCAL: bool = false, |
| 824 | + /// Do not strip this section. |
| 825 | + NOSTRIP: bool = false, |
| 826 | + }, |
| 827 | + ARM: packed struct(u8) { |
| 828 | + unused0: u5 = 0, |
| 829 | + /// Make code section unreadable when in execute-only mode |
| 830 | + PURECODE: bool = false, |
| 831 | + unused6: u2 = 0, |
| 832 | + }, |
| 833 | + } = .{ .MASK = 0 }, |
| 834 | + PROC: packed union { |
| 835 | + MASK: u4, |
| 836 | + XCORE: packed struct(u4) { |
| 837 | + /// All sections with the "d" flag are grouped together by the linker to form |
| 838 | + /// the data section and the dp register is set to the start of the section by |
| 839 | + /// the boot code. |
| 840 | + DP_SECTION: bool = false, |
| 841 | + /// All sections with the "c" flag are grouped together by the linker to form |
| 842 | + /// the constant pool and the cp register is set to the start of the constant |
| 843 | + /// pool by the boot code. |
| 844 | + CP_SECTION: bool = false, |
| 845 | + unused2: u1 = 0, |
| 846 | + /// This section is excluded from the final executable or shared library. |
| 847 | + EXCLUDE: bool = false, |
| 848 | + }, |
| 849 | + X86_64: packed struct(u4) { |
| 850 | + /// If an object file section does not have this flag set, then it may not hold |
| 851 | + /// more than 2GB and can be freely referred to in objects using smaller code |
| 852 | + /// models. Otherwise, only objects using larger code models can refer to them. |
| 853 | + /// For example, a medium code model object can refer to data in a section that |
| 854 | + /// sets this flag besides being able to refer to data in a section that does |
| 855 | + /// not set it; likewise, a small code model object can refer only to code in a |
| 856 | + /// section that does not set this flag. |
| 857 | + LARGE: bool = false, |
| 858 | + unused1: u2 = 0, |
| 859 | + /// This section is excluded from the final executable or shared library. |
| 860 | + EXCLUDE: bool = false, |
| 861 | + }, |
| 862 | + HEX: packed struct(u4) { |
| 863 | + /// All sections with the GPREL flag are grouped into a global data area |
| 864 | + /// for faster accesses |
| 865 | + GPREL: bool = false, |
| 866 | + unused1: u2 = 0, |
| 867 | + /// This section is excluded from the final executable or shared library. |
| 868 | + EXCLUDE: bool = false, |
| 869 | + }, |
| 870 | + MIPS: packed struct(u4) { |
| 871 | + /// All sections with the GPREL flag are grouped into a global data area |
| 872 | + /// for faster accesses |
| 873 | + GPREL: bool = false, |
| 874 | + /// This section should be merged. |
| 875 | + MERGE: bool = false, |
| 876 | + /// Address size to be inferred from section entry size. |
| 877 | + ADDR: bool = false, |
| 878 | + /// Section data is string data by default. |
| 879 | + STRING: bool = false, |
| 880 | + }, |
| 881 | + } = .{ .MASK = 0 }, |
| 882 | +}; |
| 883 | + |
| 884 | /// Execute |
| 885 | pub const PF_X = 1; |
| 886 | |
| 887 | @@ -1733,6 +2118,19 @@ pub const PF_MASKOS = 0x0ff00000; |
| 888 | /// Bits for processor-specific semantics. |
| 889 | pub const PF_MASKPROC = 0xf0000000; |
| 890 | |
| 891 | +pub const PF = packed struct(Word) { |
| 892 | + X: bool = false, |
| 893 | + W: bool = false, |
| 894 | + R: bool = false, |
| 895 | + unused3: u17 = 0, |
| 896 | + OS: packed union { |
| 897 | + MASK: u8, |
| 898 | + } = .{ .MASK = 0 }, |
| 899 | + PROC: packed union { |
| 900 | + MASK: u4, |
| 901 | + } = .{ .MASK = 0 }, |
| 902 | +}; |
| 903 | + |
| 904 | /// Undefined section |
| 905 | pub const SHN_UNDEF = 0; |
| 906 | /// Start of reserved indices |
| 907 | @@ -2303,13 +2701,6 @@ pub const R_PPC64 = enum(u32) { |
| 908 | _, |
| 909 | }; |
| 910 | |
| 911 | -pub const STV = enum(u3) { |
| 912 | - DEFAULT = 0, |
| 913 | - INTERNAL = 1, |
| 914 | - HIDDEN = 2, |
| 915 | - PROTECTED = 3, |
| 916 | -}; |
| 917 | - |
| 918 | pub const ar_hdr = extern struct { |
| 919 | /// Member file name, sometimes / terminated. |
| 920 | ar_name: [16]u8, |
| 921 | diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig |
| 922 | index b2116c1a74..55f1fd14cb 100644 |
| 923 | --- a/lib/std/zig/system.zig |
| 924 | +++ b/lib/std/zig/system.zig |
| 925 | @@ -516,15 +516,15 @@ pub fn abiAndDynamicLinkerFromFile( |
| 926 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); |
| 927 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); |
| 928 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
| 929 | - const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) { |
| 930 | + const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { |
| 931 | elf.ELFDATA2LSB => .little, |
| 932 | elf.ELFDATA2MSB => .big, |
| 933 | else => return error.InvalidElfEndian, |
| 934 | }; |
| 935 | const need_bswap = elf_endian != native_endian; |
| 936 | - if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; |
| 937 | + if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; |
| 938 | |
| 939 | - const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { |
| 940 | + const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { |
| 941 | elf.ELFCLASS32 => false, |
| 942 | elf.ELFCLASS64 => true, |
| 943 | else => return error.InvalidElfClass, |
| 944 | @@ -920,15 +920,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 945 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); |
| 946 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); |
| 947 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
| 948 | - const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) { |
| 949 | + const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { |
| 950 | elf.ELFDATA2LSB => .little, |
| 951 | elf.ELFDATA2MSB => .big, |
| 952 | else => return error.InvalidElfEndian, |
| 953 | }; |
| 954 | const need_bswap = elf_endian != native_endian; |
| 955 | - if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; |
| 956 | + if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; |
| 957 | |
| 958 | - const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { |
| 959 | + const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { |
| 960 | elf.ELFCLASS32 => false, |
| 961 | elf.ELFCLASS64 => true, |
| 962 | else => return error.InvalidElfClass, |
| 963 | diff --git a/src/Compilation.zig b/src/Compilation.zig |
| 964 | index 34953ed11a..bf7246b8d8 100644 |
| 965 | --- a/src/Compilation.zig |
| 966 | +++ b/src/Compilation.zig |
| 967 | @@ -177,7 +177,6 @@ debug_compiler_runtime_libs: bool, |
| 968 | debug_compile_errors: bool, |
| 969 | /// Do not check this field directly. Instead, use the `debugIncremental` wrapper function. |
| 970 | debug_incremental: bool, |
| 971 | -incremental: bool, |
| 972 | alloc_failure_occurred: bool = false, |
| 973 | last_update_was_cache_hit: bool = false, |
| 974 | |
| 975 | @@ -256,7 +255,9 @@ mutex: if (builtin.single_threaded) struct { |
| 976 | test_filters: []const []const u8, |
| 977 | |
| 978 | link_task_wait_group: WaitGroup = .{}, |
| 979 | -link_prog_node: std.Progress.Node = std.Progress.Node.none, |
| 980 | +link_prog_node: std.Progress.Node = .none, |
| 981 | +link_uav_prog_node: std.Progress.Node = .none, |
| 982 | +link_lazy_prog_node: std.Progress.Node = .none, |
| 983 | |
| 984 | llvm_opt_bisect_limit: c_int, |
| 985 | |
| 986 | @@ -1746,7 +1747,6 @@ pub const CreateOptions = struct { |
| 987 | debug_compiler_runtime_libs: bool = false, |
| 988 | debug_compile_errors: bool = false, |
| 989 | debug_incremental: bool = false, |
| 990 | - incremental: bool = false, |
| 991 | /// Normally when you create a `Compilation`, Zig will automatically build |
| 992 | /// and link in required dependencies, such as compiler-rt and libc. When |
| 993 | /// building such dependencies themselves, this flag must be set to avoid |
| 994 | @@ -1982,6 +1982,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 995 | }; |
| 996 | if (have_zcu and (!need_llvm or use_llvm)) { |
| 997 | if (output_mode == .Obj) break :s .zcu; |
| 998 | + if (options.config.use_new_linker) break :s .zcu; |
| 999 | switch (target_util.zigBackend(target, use_llvm)) { |
| 1000 | else => {}, |
| 1001 | .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { |
| 1002 | @@ -2188,8 +2189,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 1003 | .inherited = .{}, |
| 1004 | .global = options.config, |
| 1005 | .parent = options.root_mod, |
| 1006 | - }) catch |err| return switch (err) { |
| 1007 | - error.OutOfMemory => |e| return e, |
| 1008 | + }) catch |err| switch (err) { |
| 1009 | + error.OutOfMemory => return error.OutOfMemory, |
| 1010 | // None of these are possible because the configuration matches the root module |
| 1011 | // which already passed these checks. |
| 1012 | error.ValgrindUnsupportedOnTarget => unreachable, |
| 1013 | @@ -2266,7 +2267,6 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 1014 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 1015 | .debug_compile_errors = options.debug_compile_errors, |
| 1016 | .debug_incremental = options.debug_incremental, |
| 1017 | - .incremental = options.incremental, |
| 1018 | .root_name = root_name, |
| 1019 | .sysroot = sysroot, |
| 1020 | .windows_libs = .empty, |
| 1021 | @@ -2409,6 +2409,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 1022 | // Synchronize with other matching comments: ZigOnlyHashStuff |
| 1023 | hash.add(use_llvm); |
| 1024 | hash.add(options.config.use_lib_llvm); |
| 1025 | + hash.add(options.config.use_lld); |
| 1026 | + hash.add(options.config.use_new_linker); |
| 1027 | hash.add(options.config.dll_export_fns); |
| 1028 | hash.add(options.config.is_test); |
| 1029 | hash.addListOfBytes(options.test_filters); |
| 1030 | @@ -3075,14 +3077,29 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 1031 | |
| 1032 | // The linker progress node is set up here instead of in `performAllTheWork`, because |
| 1033 | // we also want it around during `flush`. |
| 1034 | - const have_link_node = comp.bin_file != null; |
| 1035 | - if (have_link_node) { |
| 1036 | + if (comp.bin_file) |lf| { |
| 1037 | comp.link_prog_node = main_progress_node.start("Linking", 0); |
| 1038 | + if (lf.cast(.elf2)) |elf| { |
| 1039 | + comp.link_prog_node.increaseEstimatedTotalItems(3); |
| 1040 | + comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0); |
| 1041 | + comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0); |
| 1042 | + elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len); |
| 1043 | + } |
| 1044 | } |
| 1045 | - defer if (have_link_node) { |
| 1046 | + defer { |
| 1047 | comp.link_prog_node.end(); |
| 1048 | comp.link_prog_node = .none; |
| 1049 | - }; |
| 1050 | + comp.link_uav_prog_node.end(); |
| 1051 | + comp.link_uav_prog_node = .none; |
| 1052 | + comp.link_lazy_prog_node.end(); |
| 1053 | + comp.link_lazy_prog_node = .none; |
| 1054 | + if (comp.bin_file) |lf| { |
| 1055 | + if (lf.cast(.elf2)) |elf| { |
| 1056 | + elf.mf.update_prog_node.end(); |
| 1057 | + elf.mf.update_prog_node = .none; |
| 1058 | + } |
| 1059 | + } |
| 1060 | + } |
| 1061 | |
| 1062 | try comp.performAllTheWork(main_progress_node); |
| 1063 | |
| 1064 | @@ -3100,6 +3117,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 1065 | try pt.populateTestFunctions(); |
| 1066 | } |
| 1067 | |
| 1068 | + link.updateErrorData(pt); |
| 1069 | + |
| 1070 | try pt.processExports(); |
| 1071 | } |
| 1072 | |
| 1073 | @@ -3474,6 +3493,8 @@ fn addNonIncrementalStuffToCacheManifest( |
| 1074 | |
| 1075 | man.hash.add(comp.config.use_llvm); |
| 1076 | man.hash.add(comp.config.use_lib_llvm); |
| 1077 | + man.hash.add(comp.config.use_lld); |
| 1078 | + man.hash.add(comp.config.use_new_linker); |
| 1079 | man.hash.add(comp.config.is_test); |
| 1080 | man.hash.add(comp.config.import_memory); |
| 1081 | man.hash.add(comp.config.export_memory); |
| 1082 | @@ -4073,7 +4094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 1083 | defer sorted_failed_analysis.deinit(gpa); |
| 1084 | var added_any_analysis_error = false; |
| 1085 | for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { |
| 1086 | - if (comp.incremental) { |
| 1087 | + if (comp.config.incremental) { |
| 1088 | const refs = try zcu.resolveReferences(); |
| 1089 | if (!refs.contains(anal_unit)) continue; |
| 1090 | } |
| 1091 | @@ -4240,7 +4261,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 1092 | |
| 1093 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a |
| 1094 | // very common way for incremental compilation bugs to manifest, so let's always check it. |
| 1095 | - if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) { |
| 1096 | + if (comp.zcu) |zcu| if (comp.config.incremental and bundle.root_list.items.len == 0) { |
| 1097 | for (zcu.transitive_failed_analysis.keys()) |failed_unit| { |
| 1098 | const refs = try zcu.resolveReferences(); |
| 1099 | var ref = refs.get(failed_unit) orelse continue; |
| 1100 | @@ -4949,7 +4970,7 @@ fn performAllTheWork( |
| 1101 | tr.stats.n_reachable_files = @intCast(zcu.alive_files.count()); |
| 1102 | } |
| 1103 | |
| 1104 | - if (comp.incremental) { |
| 1105 | + if (comp.config.incremental) { |
| 1106 | const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0); |
| 1107 | defer update_zir_refs_node.end(); |
| 1108 | try pt.updateZirRefs(); |
| 1109 | diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig |
| 1110 | index d8751251da..45f7e509de 100644 |
| 1111 | --- a/src/Compilation/Config.zig |
| 1112 | +++ b/src/Compilation/Config.zig |
| 1113 | @@ -49,6 +49,8 @@ use_lib_llvm: bool, |
| 1114 | use_lld: bool, |
| 1115 | c_frontend: CFrontend, |
| 1116 | lto: std.zig.LtoMode, |
| 1117 | +use_new_linker: bool, |
| 1118 | +incremental: bool, |
| 1119 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 1120 | /// Always set to `command` for non-WASI targets. |
| 1121 | wasi_exec_model: std.builtin.WasiExecModel, |
| 1122 | @@ -104,6 +106,8 @@ pub const Options = struct { |
| 1123 | use_lld: ?bool = null, |
| 1124 | use_clang: ?bool = null, |
| 1125 | lto: ?std.zig.LtoMode = null, |
| 1126 | + use_new_linker: ?bool = null, |
| 1127 | + incremental: bool = false, |
| 1128 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 1129 | wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 1130 | import_memory: ?bool = null, |
| 1131 | @@ -147,6 +151,8 @@ pub const ResolveError = error{ |
| 1132 | LldUnavailable, |
| 1133 | ClangUnavailable, |
| 1134 | DllExportFnsRequiresWindows, |
| 1135 | + NewLinkerIncompatibleWithLld, |
| 1136 | + NewLinkerIncompatibleObjectFormat, |
| 1137 | }; |
| 1138 | |
| 1139 | pub fn resolve(options: Options) ResolveError!Config { |
| 1140 | @@ -458,6 +464,22 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 1141 | break :b .none; |
| 1142 | }; |
| 1143 | |
| 1144 | + const use_new_linker = b: { |
| 1145 | + if (use_lld) { |
| 1146 | + if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld; |
| 1147 | + break :b false; |
| 1148 | + } |
| 1149 | + |
| 1150 | + if (!target_util.hasNewLinkerSupport(target.ofmt)) { |
| 1151 | + if (options.use_new_linker == true) return error.NewLinkerIncompatibleObjectFormat; |
| 1152 | + break :b false; |
| 1153 | + } |
| 1154 | + |
| 1155 | + if (options.use_new_linker) |x| break :b x; |
| 1156 | + |
| 1157 | + break :b options.incremental; |
| 1158 | + }; |
| 1159 | + |
| 1160 | const root_strip = b: { |
| 1161 | if (options.root_strip) |x| break :b x; |
| 1162 | if (root_optimize_mode == .ReleaseSmall) break :b true; |
| 1163 | @@ -531,6 +553,8 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 1164 | .root_error_tracing = root_error_tracing, |
| 1165 | .pie = pie, |
| 1166 | .lto = lto, |
| 1167 | + .use_new_linker = use_new_linker, |
| 1168 | + .incremental = options.incremental, |
| 1169 | .import_memory = import_memory, |
| 1170 | .export_memory = export_memory, |
| 1171 | .shared_memory = shared_memory, |
| 1172 | diff --git a/src/InternPool.zig b/src/InternPool.zig |
| 1173 | index 9965497742..f4344af86d 100644 |
| 1174 | --- a/src/InternPool.zig |
| 1175 | +++ b/src/InternPool.zig |
| 1176 | @@ -6424,14 +6424,25 @@ pub const Alignment = enum(u6) { |
| 1177 | return n + 1; |
| 1178 | } |
| 1179 | |
| 1180 | + pub fn toStdMem(a: Alignment) std.mem.Alignment { |
| 1181 | + assert(a != .none); |
| 1182 | + return @enumFromInt(@intFromEnum(a)); |
| 1183 | + } |
| 1184 | + |
| 1185 | + pub fn fromStdMem(a: std.mem.Alignment) Alignment { |
| 1186 | + const r: Alignment = @enumFromInt(@intFromEnum(a)); |
| 1187 | + assert(r != .none); |
| 1188 | + return r; |
| 1189 | + } |
| 1190 | + |
| 1191 | const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment; |
| 1192 | |
| 1193 | - pub fn toLlvm(this: @This()) LlvmBuilderAlignment { |
| 1194 | - return @enumFromInt(@intFromEnum(this)); |
| 1195 | + pub fn toLlvm(a: Alignment) LlvmBuilderAlignment { |
| 1196 | + return @enumFromInt(@intFromEnum(a)); |
| 1197 | } |
| 1198 | |
| 1199 | - pub fn fromLlvm(other: LlvmBuilderAlignment) @This() { |
| 1200 | - return @enumFromInt(@intFromEnum(other)); |
| 1201 | + pub fn fromLlvm(a: LlvmBuilderAlignment) Alignment { |
| 1202 | + return @enumFromInt(@intFromEnum(a)); |
| 1203 | } |
| 1204 | }; |
| 1205 | |
| 1206 | diff --git a/src/Sema.zig b/src/Sema.zig |
| 1207 | index 946e890ea3..d0576de33d 100644 |
| 1208 | --- a/src/Sema.zig |
| 1209 | +++ b/src/Sema.zig |
| 1210 | @@ -3032,7 +3032,7 @@ fn zirStructDecl( |
| 1211 | }); |
| 1212 | errdefer pt.destroyNamespace(new_namespace_index); |
| 1213 | |
| 1214 | - if (pt.zcu.comp.incremental) { |
| 1215 | + if (pt.zcu.comp.config.incremental) { |
| 1216 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 1217 | } |
| 1218 | |
| 1219 | @@ -3430,7 +3430,7 @@ fn zirUnionDecl( |
| 1220 | }); |
| 1221 | errdefer pt.destroyNamespace(new_namespace_index); |
| 1222 | |
| 1223 | - if (pt.zcu.comp.incremental) { |
| 1224 | + if (pt.zcu.comp.config.incremental) { |
| 1225 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 1226 | } |
| 1227 | |
| 1228 | @@ -6217,7 +6217,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 1229 | if (ptr_info.byte_offset != 0) { |
| 1230 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); |
| 1231 | } |
| 1232 | - if (options.linkage == .internal) return; |
| 1233 | + if (zcu.llvm_object != null and options.linkage == .internal) return; |
| 1234 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); |
| 1235 | if (!try sema.validateExternType(export_ty, .other)) { |
| 1236 | return sema.failWithOwnedErrorMsg(block, msg: { |
| 1237 | @@ -6256,7 +6256,7 @@ pub fn analyzeExport( |
| 1238 | const zcu = pt.zcu; |
| 1239 | const ip = &zcu.intern_pool; |
| 1240 | |
| 1241 | - if (options.linkage == .internal) |
| 1242 | + if (zcu.llvm_object != null and options.linkage == .internal) |
| 1243 | return; |
| 1244 | |
| 1245 | try sema.ensureNavResolved(block, src, orig_nav_index, .fully); |
| 1246 | @@ -7709,7 +7709,7 @@ fn analyzeCall( |
| 1247 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 1248 | // since dependencies are not marked on callers. If we want to keep this around (we should |
| 1249 | // check that it's worthwhile first!), each memoized call needs an `AnalUnit`. |
| 1250 | - if (zcu.comp.incremental) break :m false; |
| 1251 | + if (zcu.comp.config.incremental) break :m false; |
| 1252 | if (!block.isComptime()) break :m false; |
| 1253 | for (args) |a| { |
| 1254 | const val = (try sema.resolveValue(a)).?; |
| 1255 | @@ -31208,7 +31208,7 @@ fn addReferenceEntry( |
| 1256 | .func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced |
| 1257 | else => {}, |
| 1258 | } |
| 1259 | - if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; |
| 1260 | + if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return; |
| 1261 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); |
| 1262 | if (gop.found_existing) return; |
| 1263 | try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: { |
| 1264 | @@ -31225,7 +31225,7 @@ pub fn addTypeReferenceEntry( |
| 1265 | referenced_type: InternPool.Index, |
| 1266 | ) !void { |
| 1267 | const zcu = sema.pt.zcu; |
| 1268 | - if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; |
| 1269 | + if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return; |
| 1270 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type); |
| 1271 | if (gop.found_existing) return; |
| 1272 | try zcu.addTypeReference(sema.owner, referenced_type, src); |
| 1273 | @@ -36875,7 +36875,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool |
| 1274 | |
| 1275 | pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 1276 | const pt = sema.pt; |
| 1277 | - if (!pt.zcu.comp.incremental) return; |
| 1278 | + if (!pt.zcu.comp.config.incremental) return; |
| 1279 | |
| 1280 | const gop = try sema.dependencies.getOrPut(sema.gpa, dependee); |
| 1281 | if (gop.found_existing) return; |
| 1282 | diff --git a/src/Value.zig b/src/Value.zig |
| 1283 | index 8de5621761..381eacf45a 100644 |
| 1284 | --- a/src/Value.zig |
| 1285 | +++ b/src/Value.zig |
| 1286 | @@ -23,7 +23,7 @@ pub fn format(val: Value, writer: *std.Io.Writer) !void { |
| 1287 | |
| 1288 | /// This is a debug function. In order to print values in a meaningful way |
| 1289 | /// we also need access to the type. |
| 1290 | -pub fn dump(start_val: Value, w: std.Io.Writer) std.Io.Writer.Error!void { |
| 1291 | +pub fn dump(start_val: Value, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 1292 | try w.print("(interned: {})", .{start_val.toIntern()}); |
| 1293 | } |
| 1294 | |
| 1295 | diff --git a/src/Zcu.zig b/src/Zcu.zig |
| 1296 | index 706bdb5165..8e9e9c2902 100644 |
| 1297 | --- a/src/Zcu.zig |
| 1298 | +++ b/src/Zcu.zig |
| 1299 | @@ -3166,7 +3166,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 1300 | } |
| 1301 | |
| 1302 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 1303 | - if (!zcu.comp.incremental) return null; |
| 1304 | + if (!zcu.comp.config.incremental) return null; |
| 1305 | |
| 1306 | if (zcu.outdated.count() == 0) { |
| 1307 | // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those |
| 1308 | diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig |
| 1309 | index 77cddb204e..32782e7e89 100644 |
| 1310 | --- a/src/Zcu/PerThread.zig |
| 1311 | +++ b/src/Zcu/PerThread.zig |
| 1312 | @@ -1815,7 +1815,7 @@ fn createFileRootStruct( |
| 1313 | wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none); |
| 1314 | ip.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 1315 | |
| 1316 | - if (zcu.comp.incremental) { |
| 1317 | + if (zcu.comp.config.incremental) { |
| 1318 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 1319 | } |
| 1320 | |
| 1321 | diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig |
| 1322 | index 7b13cfc90d..fe40ba4bbb 100644 |
| 1323 | --- a/src/arch/riscv64/CodeGen.zig |
| 1324 | +++ b/src/arch/riscv64/CodeGen.zig |
| 1325 | @@ -858,9 +858,11 @@ pub fn generateLazy( |
| 1326 | pt: Zcu.PerThread, |
| 1327 | src_loc: Zcu.LazySrcLoc, |
| 1328 | lazy_sym: link.File.LazySymbol, |
| 1329 | - code: *std.ArrayListUnmanaged(u8), |
| 1330 | + atom_index: u32, |
| 1331 | + w: *std.Io.Writer, |
| 1332 | debug_output: link.File.DebugInfoOutput, |
| 1333 | -) CodeGenError!void { |
| 1334 | +) (CodeGenError || std.Io.Writer.Error)!void { |
| 1335 | + _ = atom_index; |
| 1336 | const comp = bin_file.comp; |
| 1337 | const gpa = comp.gpa; |
| 1338 | const mod = comp.root_mod; |
| 1339 | @@ -914,7 +916,7 @@ pub fn generateLazy( |
| 1340 | }, |
| 1341 | .bin_file = bin_file, |
| 1342 | .debug_output = debug_output, |
| 1343 | - .code = code, |
| 1344 | + .w = w, |
| 1345 | .prev_di_pc = undefined, // no debug info yet |
| 1346 | .prev_di_line = undefined, // no debug info yet |
| 1347 | .prev_di_column = undefined, // no debug info yet |
| 1348 | diff --git a/src/arch/riscv64/Emit.zig b/src/arch/riscv64/Emit.zig |
| 1349 | index 2e72aff941..64a476007c 100644 |
| 1350 | --- a/src/arch/riscv64/Emit.zig |
| 1351 | +++ b/src/arch/riscv64/Emit.zig |
| 1352 | @@ -3,7 +3,7 @@ |
| 1353 | bin_file: *link.File, |
| 1354 | lower: Lower, |
| 1355 | debug_output: link.File.DebugInfoOutput, |
| 1356 | -code: *std.ArrayListUnmanaged(u8), |
| 1357 | +w: *std.Io.Writer, |
| 1358 | |
| 1359 | prev_di_line: u32, |
| 1360 | prev_di_column: u32, |
| 1361 | @@ -13,7 +13,7 @@ prev_di_pc: usize, |
| 1362 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 1363 | relocs: std.ArrayListUnmanaged(Reloc) = .empty, |
| 1364 | |
| 1365 | -pub const Error = Lower.Error || error{ |
| 1366 | +pub const Error = Lower.Error || std.Io.Writer.Error || error{ |
| 1367 | EmitFail, |
| 1368 | }; |
| 1369 | |
| 1370 | @@ -25,13 +25,13 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1371 | try emit.code_offset_mapping.putNoClobber( |
| 1372 | emit.lower.allocator, |
| 1373 | mir_index, |
| 1374 | - @intCast(emit.code.items.len), |
| 1375 | + @intCast(emit.w.end), |
| 1376 | ); |
| 1377 | const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true }); |
| 1378 | var lowered_relocs = lowered.relocs; |
| 1379 | for (lowered.insts, 0..) |lowered_inst, lowered_index| { |
| 1380 | - const start_offset: u32 = @intCast(emit.code.items.len); |
| 1381 | - std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), lowered_inst.toU32(), .little); |
| 1382 | + const start_offset: u32 = @intCast(emit.w.end); |
| 1383 | + try emit.w.writeInt(u32, lowered_inst.toU32(), .little); |
| 1384 | |
| 1385 | while (lowered_relocs.len > 0 and |
| 1386 | lowered_relocs[0].lowered_inst_index == lowered_index) : ({ |
| 1387 | @@ -175,7 +175,7 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 1388 | return emit.fail("relocation target not found!", .{}); |
| 1389 | |
| 1390 | const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); |
| 1391 | - const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4]; |
| 1392 | + const code = emit.w.buffered()[reloc.source + reloc.offset ..][0..4]; |
| 1393 | |
| 1394 | switch (reloc.fmt) { |
| 1395 | .J => riscv_util.writeInstJ(code, @bitCast(disp)), |
| 1396 | @@ -187,7 +187,7 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 1397 | |
| 1398 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { |
| 1399 | const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); |
| 1400 | - const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 1401 | + const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 1402 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 1403 | switch (emit.debug_output) { |
| 1404 | .dwarf => |dw| { |
| 1405 | @@ -196,7 +196,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { |
| 1406 | try dw.advancePCAndLine(delta_line, delta_pc); |
| 1407 | emit.prev_di_line = line; |
| 1408 | emit.prev_di_column = column; |
| 1409 | - emit.prev_di_pc = emit.code.items.len; |
| 1410 | + emit.prev_di_pc = emit.w.end; |
| 1411 | }, |
| 1412 | .none => {}, |
| 1413 | } |
| 1414 | diff --git a/src/arch/riscv64/Mir.zig b/src/arch/riscv64/Mir.zig |
| 1415 | index 6fb8e23a98..204ab6a3c0 100644 |
| 1416 | --- a/src/arch/riscv64/Mir.zig |
| 1417 | +++ b/src/arch/riscv64/Mir.zig |
| 1418 | @@ -109,9 +109,11 @@ pub fn emit( |
| 1419 | pt: Zcu.PerThread, |
| 1420 | src_loc: Zcu.LazySrcLoc, |
| 1421 | func_index: InternPool.Index, |
| 1422 | - code: *std.ArrayListUnmanaged(u8), |
| 1423 | + atom_index: u32, |
| 1424 | + w: *std.Io.Writer, |
| 1425 | debug_output: link.File.DebugInfoOutput, |
| 1426 | -) codegen.CodeGenError!void { |
| 1427 | +) (codegen.CodeGenError || std.Io.Writer.Error)!void { |
| 1428 | + _ = atom_index; |
| 1429 | const zcu = pt.zcu; |
| 1430 | const comp = zcu.comp; |
| 1431 | const gpa = comp.gpa; |
| 1432 | @@ -132,7 +134,7 @@ pub fn emit( |
| 1433 | }, |
| 1434 | .bin_file = lf, |
| 1435 | .debug_output = debug_output, |
| 1436 | - .code = code, |
| 1437 | + .w = w, |
| 1438 | .prev_di_pc = 0, |
| 1439 | .prev_di_line = func.lbrace_line, |
| 1440 | .prev_di_column = func.lbrace_column, |
| 1441 | diff --git a/src/arch/sparc64/Emit.zig b/src/arch/sparc64/Emit.zig |
| 1442 | index d41f1cdf07..26282b09ab 100644 |
| 1443 | --- a/src/arch/sparc64/Emit.zig |
| 1444 | +++ b/src/arch/sparc64/Emit.zig |
| 1445 | @@ -21,7 +21,7 @@ debug_output: link.File.DebugInfoOutput, |
| 1446 | target: *const std.Target, |
| 1447 | err_msg: ?*ErrorMsg = null, |
| 1448 | src_loc: Zcu.LazySrcLoc, |
| 1449 | -code: *std.ArrayListUnmanaged(u8), |
| 1450 | +w: *std.Io.Writer, |
| 1451 | |
| 1452 | prev_di_line: u32, |
| 1453 | prev_di_column: u32, |
| 1454 | @@ -40,7 +40,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn |
| 1455 | /// instruction |
| 1456 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 1457 | |
| 1458 | -const InnerError = error{ |
| 1459 | +const InnerError = std.Io.Writer.Error || error{ |
| 1460 | OutOfMemory, |
| 1461 | EmitFail, |
| 1462 | }; |
| 1463 | @@ -292,7 +292,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 1464 | .bpcc => switch (tag) { |
| 1465 | .bpcc => { |
| 1466 | const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int; |
| 1467 | - const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.code.items.len)); |
| 1468 | + const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.w.end)); |
| 1469 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); |
| 1470 | |
| 1471 | try emit.writeInstruction( |
| 1472 | @@ -310,7 +310,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 1473 | .bpr => switch (tag) { |
| 1474 | .bpr => { |
| 1475 | const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg; |
| 1476 | - const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.code.items.len)); |
| 1477 | + const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.w.end)); |
| 1478 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); |
| 1479 | |
| 1480 | try emit.writeInstruction( |
| 1481 | @@ -494,13 +494,13 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 1482 | |
| 1483 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { |
| 1484 | const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line)); |
| 1485 | - const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 1486 | + const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 1487 | switch (emit.debug_output) { |
| 1488 | .dwarf => |dbg_out| { |
| 1489 | try dbg_out.advancePCAndLine(delta_line, delta_pc); |
| 1490 | emit.prev_di_line = line; |
| 1491 | emit.prev_di_column = column; |
| 1492 | - emit.prev_di_pc = emit.code.items.len; |
| 1493 | + emit.prev_di_pc = emit.w.end; |
| 1494 | }, |
| 1495 | else => {}, |
| 1496 | } |
| 1497 | @@ -675,13 +675,8 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 1498 | } |
| 1499 | |
| 1500 | fn writeInstruction(emit: *Emit, instruction: Instruction) !void { |
| 1501 | - const comp = emit.bin_file.comp; |
| 1502 | - const gpa = comp.gpa; |
| 1503 | - |
| 1504 | // SPARCv9 instructions are always arranged in BE regardless of the |
| 1505 | // endianness mode the CPU is running in (Section 3.1 of the ISA specification). |
| 1506 | // This is to ease porting in case someone wants to do a LE SPARCv9 backend. |
| 1507 | - const endian: Endian = .big; |
| 1508 | - |
| 1509 | - std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), instruction.toU32(), endian); |
| 1510 | + try emit.w.writeInt(u32, instruction.toU32(), .big); |
| 1511 | } |
| 1512 | diff --git a/src/arch/sparc64/Mir.zig b/src/arch/sparc64/Mir.zig |
| 1513 | index 842ac10fed..41d135eb83 100644 |
| 1514 | --- a/src/arch/sparc64/Mir.zig |
| 1515 | +++ b/src/arch/sparc64/Mir.zig |
| 1516 | @@ -380,9 +380,11 @@ pub fn emit( |
| 1517 | pt: Zcu.PerThread, |
| 1518 | src_loc: Zcu.LazySrcLoc, |
| 1519 | func_index: InternPool.Index, |
| 1520 | - code: *std.ArrayListUnmanaged(u8), |
| 1521 | + atom_index: u32, |
| 1522 | + w: *std.Io.Writer, |
| 1523 | debug_output: link.File.DebugInfoOutput, |
| 1524 | -) codegen.CodeGenError!void { |
| 1525 | +) (codegen.CodeGenError || std.Io.Writer.Error)!void { |
| 1526 | + _ = atom_index; |
| 1527 | const zcu = pt.zcu; |
| 1528 | const func = zcu.funcInfo(func_index); |
| 1529 | const nav = func.owner_nav; |
| 1530 | @@ -393,7 +395,7 @@ pub fn emit( |
| 1531 | .debug_output = debug_output, |
| 1532 | .target = &mod.resolved_target.result, |
| 1533 | .src_loc = src_loc, |
| 1534 | - .code = code, |
| 1535 | + .w = w, |
| 1536 | .prev_di_pc = 0, |
| 1537 | .prev_di_line = func.lbrace_line, |
| 1538 | .prev_di_column = func.lbrace_column, |
| 1539 | diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig |
| 1540 | index b5760c95ac..1827b50d61 100644 |
| 1541 | --- a/src/arch/x86_64/CodeGen.zig |
| 1542 | +++ b/src/arch/x86_64/CodeGen.zig |
| 1543 | @@ -550,9 +550,9 @@ pub const MCValue = union(enum) { |
| 1544 | @tagName(pl.reg), |
| 1545 | }), |
| 1546 | .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), |
| 1547 | - .indirect_load_frame => |pl| try w.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }), |
| 1548 | - .load_frame => |pl| try w.print("[{} + 0x{x}]", .{ pl.index, pl.off }), |
| 1549 | - .lea_frame => |pl| try w.print("{} + 0x{x}", .{ pl.index, pl.off }), |
| 1550 | + .indirect_load_frame => |pl| try w.print("[[{f} + 0x{x}]]", .{ pl.index, pl.off }), |
| 1551 | + .load_frame => |pl| try w.print("[{f} + 0x{x}]", .{ pl.index, pl.off }), |
| 1552 | + .lea_frame => |pl| try w.print("{f} + 0x{x}", .{ pl.index, pl.off }), |
| 1553 | .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}), |
| 1554 | .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}), |
| 1555 | .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}), |
| 1556 | @@ -561,10 +561,10 @@ pub const MCValue = union(enum) { |
| 1557 | .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), |
| 1558 | .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}), |
| 1559 | .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}), |
| 1560 | - .elementwise_args => |pl| try w.print("elementwise:{d}:[{} + 0x{x}]", .{ |
| 1561 | + .elementwise_args => |pl| try w.print("elementwise:{d}:[{f} + 0x{x}]", .{ |
| 1562 | pl.regs, pl.frame_index, pl.frame_off, |
| 1563 | }), |
| 1564 | - .reserved_frame => |pl| try w.print("(dead:{})", .{pl}), |
| 1565 | + .reserved_frame => |pl| try w.print("(dead:{f})", .{pl}), |
| 1566 | .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}), |
| 1567 | } |
| 1568 | } |
| 1569 | @@ -1038,7 +1038,8 @@ pub fn generateLazy( |
| 1570 | pt: Zcu.PerThread, |
| 1571 | src_loc: Zcu.LazySrcLoc, |
| 1572 | lazy_sym: link.File.LazySymbol, |
| 1573 | - code: *std.ArrayListUnmanaged(u8), |
| 1574 | + atom_index: u32, |
| 1575 | + w: *std.Io.Writer, |
| 1576 | debug_output: link.File.DebugInfoOutput, |
| 1577 | ) codegen.CodeGenError!void { |
| 1578 | const gpa = pt.zcu.gpa; |
| 1579 | @@ -1081,7 +1082,7 @@ pub fn generateLazy( |
| 1580 | else => |e| return e, |
| 1581 | }; |
| 1582 | |
| 1583 | - try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, code, debug_output); |
| 1584 | + try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, atom_index, w, debug_output); |
| 1585 | } |
| 1586 | |
| 1587 | const FormatNavData = struct { |
| 1588 | @@ -2022,7 +2023,7 @@ fn gen( |
| 1589 | .{}, |
| 1590 | ); |
| 1591 | self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; |
| 1592 | - tracking_log.debug("spill {f} to {}", .{ self.ret_mcv.long, frame_index }); |
| 1593 | + tracking_log.debug("spill {f} to {f}", .{ self.ret_mcv.long, frame_index }); |
| 1594 | }, |
| 1595 | else => unreachable, |
| 1596 | } |
| 1597 | diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig |
| 1598 | index 84bb325322..c2b38d8e6d 100644 |
| 1599 | --- a/src/arch/x86_64/Emit.zig |
| 1600 | +++ b/src/arch/x86_64/Emit.zig |
| 1601 | @@ -6,7 +6,7 @@ pt: Zcu.PerThread, |
| 1602 | pic: bool, |
| 1603 | atom_index: u32, |
| 1604 | debug_output: link.File.DebugInfoOutput, |
| 1605 | -code: *std.ArrayListUnmanaged(u8), |
| 1606 | +w: *std.Io.Writer, |
| 1607 | |
| 1608 | prev_di_loc: Loc, |
| 1609 | /// Relative to the beginning of `code`. |
| 1610 | @@ -18,7 +18,8 @@ table_relocs: std.ArrayListUnmanaged(TableReloc), |
| 1611 | |
| 1612 | pub const Error = Lower.Error || error{ |
| 1613 | EmitFail, |
| 1614 | -} || link.File.UpdateDebugInfoError; |
| 1615 | + NotFile, |
| 1616 | +} || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError; |
| 1617 | |
| 1618 | pub fn emitMir(emit: *Emit) Error!void { |
| 1619 | const comp = emit.bin_file.comp; |
| 1620 | @@ -29,12 +30,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1621 | var local_index: usize = 0; |
| 1622 | for (0..emit.lower.mir.instructions.len) |mir_i| { |
| 1623 | const mir_index: Mir.Inst.Index = @intCast(mir_i); |
| 1624 | - emit.code_offset_mapping.items[mir_index] = @intCast(emit.code.items.len); |
| 1625 | + emit.code_offset_mapping.items[mir_index] = @intCast(emit.w.end); |
| 1626 | const lowered = try emit.lower.lowerMir(mir_index); |
| 1627 | var lowered_relocs = lowered.relocs; |
| 1628 | lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| { |
| 1629 | if (lowered_inst.prefix == .directive) { |
| 1630 | - const start_offset: u32 = @intCast(emit.code.items.len); |
| 1631 | + const start_offset: u32 = @intCast(emit.w.end); |
| 1632 | switch (emit.debug_output) { |
| 1633 | .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) { |
| 1634 | .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ |
| 1635 | @@ -164,6 +165,8 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1636 | .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 1637 | elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err| |
| 1638 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 1639 | + else if (emit.bin_file.cast(.elf2)) |elf| |
| 1640 | + @intFromEnum(try elf.lazySymbol(lazy_sym)) |
| 1641 | else if (emit.bin_file.cast(.macho)) |macho_file| |
| 1642 | macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| |
| 1643 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 1644 | @@ -180,12 +183,15 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1645 | .extern_func => |extern_func| .{ |
| 1646 | .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 1647 | try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) |
| 1648 | - else if (emit.bin_file.cast(.macho)) |macho_file| |
| 1649 | + else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ |
| 1650 | + .name = extern_func.toSlice(&emit.lower.mir).?, |
| 1651 | + .type = .FUNC, |
| 1652 | + })) else if (emit.bin_file.cast(.macho)) |macho_file| |
| 1653 | try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) |
| 1654 | else if (emit.bin_file.cast(.coff)) |coff_file| |
| 1655 | try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt") |
| 1656 | else |
| 1657 | - return emit.fail("external symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), |
| 1658 | + return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), |
| 1659 | .is_extern = true, |
| 1660 | .type = .symbol, |
| 1661 | }, |
| 1662 | @@ -205,7 +211,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1663 | }, |
| 1664 | else => {}, |
| 1665 | } |
| 1666 | - if (emit.bin_file.cast(.elf)) |_| { |
| 1667 | + if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) { |
| 1668 | if (!emit.pic) switch (lowered_inst.encoding.mnemonic) { |
| 1669 | .lea => try emit.encodeInst(try .new(.none, .mov, &.{ |
| 1670 | lowered_inst.ops[0], |
| 1671 | @@ -315,7 +321,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1672 | }, |
| 1673 | .branch, .tls => unreachable, |
| 1674 | .tlv => { |
| 1675 | - if (emit.bin_file.cast(.elf)) |elf_file| { |
| 1676 | + if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) { |
| 1677 | // TODO handle extern TLS vars, i.e., emit GD model |
| 1678 | if (emit.pic) switch (lowered_inst.encoding.mnemonic) { |
| 1679 | .lea, .mov => { |
| 1680 | @@ -337,7 +343,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1681 | }, emit.lower.target), &.{.{ |
| 1682 | .op_index = 0, |
| 1683 | .target = .{ |
| 1684 | - .index = try elf_file.getGlobalSymbol("__tls_get_addr", null), |
| 1685 | + .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 1686 | + try elf_file.getGlobalSymbol("__tls_get_addr", null) |
| 1687 | + else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ |
| 1688 | + .name = "__tls_get_addr", |
| 1689 | + .type = .FUNC, |
| 1690 | + })) else unreachable, |
| 1691 | .is_extern = true, |
| 1692 | .type = .branch, |
| 1693 | }, |
| 1694 | @@ -441,7 +452,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1695 | log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ |
| 1696 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 1697 | }); |
| 1698 | - try dwarf.enterBlock(emit.code.items.len); |
| 1699 | + try dwarf.enterBlock(emit.w.end); |
| 1700 | }, |
| 1701 | .none => {}, |
| 1702 | }, |
| 1703 | @@ -450,7 +461,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1704 | log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ |
| 1705 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 1706 | }); |
| 1707 | - try dwarf.leaveBlock(emit.code.items.len); |
| 1708 | + try dwarf.leaveBlock(emit.w.end); |
| 1709 | }, |
| 1710 | .none => {}, |
| 1711 | }, |
| 1712 | @@ -459,7 +470,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1713 | log.debug("mirDbgEnterInline (line={d}, col={d})", .{ |
| 1714 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 1715 | }); |
| 1716 | - try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); |
| 1717 | + try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column); |
| 1718 | }, |
| 1719 | .none => {}, |
| 1720 | }, |
| 1721 | @@ -468,7 +479,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1722 | log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ |
| 1723 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 1724 | }); |
| 1725 | - try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.code.items.len); |
| 1726 | + try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end); |
| 1727 | }, |
| 1728 | .none => {}, |
| 1729 | }, |
| 1730 | @@ -634,7 +645,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1731 | for (emit.relocs.items) |reloc| { |
| 1732 | const target = emit.code_offset_mapping.items[reloc.target]; |
| 1733 | const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset; |
| 1734 | - const inst_bytes = emit.code.items[reloc.inst_offset..][0..reloc.inst_length]; |
| 1735 | + const inst_bytes = emit.w.buffered()[reloc.inst_offset..][0..reloc.inst_length]; |
| 1736 | switch (reloc.source_length) { |
| 1737 | else => unreachable, |
| 1738 | inline 1, 4 => |source_length| std.mem.writeInt( |
| 1739 | @@ -646,12 +657,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1740 | } |
| 1741 | } |
| 1742 | if (emit.lower.mir.table.len > 0) { |
| 1743 | + const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8); |
| 1744 | + var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size); |
| 1745 | if (emit.bin_file.cast(.elf)) |elf_file| { |
| 1746 | const zo = elf_file.zigObjectPtr().?; |
| 1747 | const atom = zo.symbol(emit.atom_index).atom(elf_file).?; |
| 1748 | |
| 1749 | - const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8); |
| 1750 | - var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size); |
| 1751 | for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{ |
| 1752 | .r_offset = table_reloc.source_offset, |
| 1753 | .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"), |
| 1754 | @@ -665,7 +676,26 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 1755 | }, zo); |
| 1756 | table_offset += ptr_size; |
| 1757 | } |
| 1758 | - try emit.code.appendNTimes(gpa, 0, table_offset - emit.code.items.len); |
| 1759 | + try emit.w.splatByteAll(0, table_offset - emit.w.end); |
| 1760 | + } else if (emit.bin_file.cast(.elf2)) |elf| { |
| 1761 | + for (emit.table_relocs.items) |table_reloc| try elf.addReloc( |
| 1762 | + @enumFromInt(emit.atom_index), |
| 1763 | + table_reloc.source_offset, |
| 1764 | + @enumFromInt(emit.atom_index), |
| 1765 | + @as(i64, table_offset) + table_reloc.target_offset, |
| 1766 | + .{ .x86_64 = .@"32" }, |
| 1767 | + ); |
| 1768 | + for (emit.lower.mir.table) |entry| { |
| 1769 | + try elf.addReloc( |
| 1770 | + @enumFromInt(emit.atom_index), |
| 1771 | + table_offset, |
| 1772 | + @enumFromInt(emit.atom_index), |
| 1773 | + emit.code_offset_mapping.items[entry], |
| 1774 | + .{ .x86_64 = .@"64" }, |
| 1775 | + ); |
| 1776 | + table_offset += ptr_size; |
| 1777 | + } |
| 1778 | + try emit.w.splatByteAll(0, table_offset - emit.w.end); |
| 1779 | } else unreachable; |
| 1780 | } |
| 1781 | } |
| 1782 | @@ -696,16 +726,12 @@ const RelocInfo = struct { |
| 1783 | fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void { |
| 1784 | const comp = emit.bin_file.comp; |
| 1785 | const gpa = comp.gpa; |
| 1786 | - const start_offset: u32 = @intCast(emit.code.items.len); |
| 1787 | - { |
| 1788 | - var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, emit.code); |
| 1789 | - defer emit.code.* = aw.toArrayList(); |
| 1790 | - lowered_inst.encode(&aw.writer, .{}) catch |err| switch (err) { |
| 1791 | - error.WriteFailed => return error.OutOfMemory, |
| 1792 | - else => |e| return e, |
| 1793 | - }; |
| 1794 | - } |
| 1795 | - const end_offset: u32 = @intCast(emit.code.items.len); |
| 1796 | + const start_offset: u32 = @intCast(emit.w.end); |
| 1797 | + lowered_inst.encode(emit.w, .{}) catch |err| switch (err) { |
| 1798 | + error.WriteFailed => return error.OutOfMemory, |
| 1799 | + else => |e| return e, |
| 1800 | + }; |
| 1801 | + const end_offset: u32 = @intCast(emit.w.end); |
| 1802 | for (reloc_info) |reloc| switch (reloc.target.type) { |
| 1803 | .inst => { |
| 1804 | const inst_length: u4 = @intCast(end_offset - start_offset); |
| 1805 | @@ -769,7 +795,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 1806 | .symbolnum = @intCast(reloc.target.index), |
| 1807 | }, |
| 1808 | }); |
| 1809 | - } else if (emit.bin_file.cast(.coff)) |coff_file| { |
| 1810 | + } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 1811 | + @enumFromInt(emit.atom_index), |
| 1812 | + end_offset - 4, |
| 1813 | + @enumFromInt(reloc.target.index), |
| 1814 | + reloc.off, |
| 1815 | + .{ .x86_64 = .@"32" }, |
| 1816 | + ) else if (emit.bin_file.cast(.coff)) |coff_file| { |
| 1817 | const atom_index = coff_file.getAtomIndexForSymbol( |
| 1818 | .{ .sym_index = emit.atom_index, .file = null }, |
| 1819 | ).?; |
| 1820 | @@ -794,7 +826,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 1821 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), |
| 1822 | .r_addend = reloc.off - 4, |
| 1823 | }, zo); |
| 1824 | - } else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 1825 | + } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 1826 | + @enumFromInt(emit.atom_index), |
| 1827 | + end_offset - 4, |
| 1828 | + @enumFromInt(reloc.target.index), |
| 1829 | + reloc.off - 4, |
| 1830 | + .{ .x86_64 = .PC32 }, |
| 1831 | + ) else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 1832 | const zo = macho_file.getZigObject().?; |
| 1833 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
| 1834 | try atom.addReloc(macho_file, .{ |
| 1835 | @@ -849,7 +887,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 1836 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), |
| 1837 | .r_addend = reloc.off, |
| 1838 | }, zo); |
| 1839 | - } else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 1840 | + } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 1841 | + @enumFromInt(emit.atom_index), |
| 1842 | + end_offset - 4, |
| 1843 | + @enumFromInt(reloc.target.index), |
| 1844 | + reloc.off, |
| 1845 | + .{ .x86_64 = .TPOFF32 }, |
| 1846 | + ) else if (emit.bin_file.cast(.macho)) |macho_file| { |
| 1847 | const zo = macho_file.getZigObject().?; |
| 1848 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
| 1849 | try atom.addReloc(macho_file, .{ |
| 1850 | @@ -908,7 +952,7 @@ const Loc = struct { |
| 1851 | |
| 1852 | fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { |
| 1853 | const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); |
| 1854 | - const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 1855 | + const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 1856 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 1857 | switch (emit.debug_output) { |
| 1858 | .dwarf => |dwarf| { |
| 1859 | @@ -916,7 +960,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { |
| 1860 | if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); |
| 1861 | try dwarf.advancePCAndLine(delta_line, delta_pc); |
| 1862 | emit.prev_di_loc = loc; |
| 1863 | - emit.prev_di_pc = emit.code.items.len; |
| 1864 | + emit.prev_di_pc = emit.w.end; |
| 1865 | }, |
| 1866 | .none => {}, |
| 1867 | } |
| 1868 | diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig |
| 1869 | index e70018850d..caf41ffb39 100644 |
| 1870 | --- a/src/arch/x86_64/Mir.zig |
| 1871 | +++ b/src/arch/x86_64/Mir.zig |
| 1872 | @@ -1976,7 +1976,8 @@ pub fn emit( |
| 1873 | pt: Zcu.PerThread, |
| 1874 | src_loc: Zcu.LazySrcLoc, |
| 1875 | func_index: InternPool.Index, |
| 1876 | - code: *std.ArrayListUnmanaged(u8), |
| 1877 | + atom_index: u32, |
| 1878 | + w: *std.Io.Writer, |
| 1879 | debug_output: link.File.DebugInfoOutput, |
| 1880 | ) codegen.CodeGenError!void { |
| 1881 | const zcu = pt.zcu; |
| 1882 | @@ -1997,17 +1998,9 @@ pub fn emit( |
| 1883 | .bin_file = lf, |
| 1884 | .pt = pt, |
| 1885 | .pic = mod.pic, |
| 1886 | - .atom_index = sym: { |
| 1887 | - if (lf.cast(.elf)) |ef| break :sym try ef.zigObjectPtr().?.getOrCreateMetadataForNav(zcu, nav); |
| 1888 | - if (lf.cast(.macho)) |mf| break :sym try mf.getZigObject().?.getOrCreateMetadataForNav(mf, nav); |
| 1889 | - if (lf.cast(.coff)) |cf| { |
| 1890 | - const atom = try cf.getOrCreateAtomForNav(nav); |
| 1891 | - break :sym cf.getAtom(atom).getSymbolIndex().?; |
| 1892 | - } |
| 1893 | - unreachable; |
| 1894 | - }, |
| 1895 | + .atom_index = atom_index, |
| 1896 | .debug_output = debug_output, |
| 1897 | - .code = code, |
| 1898 | + .w = w, |
| 1899 | |
| 1900 | .prev_di_loc = .{ |
| 1901 | .line = func.lbrace_line, |
| 1902 | @@ -2037,7 +2030,8 @@ pub fn emitLazy( |
| 1903 | pt: Zcu.PerThread, |
| 1904 | src_loc: Zcu.LazySrcLoc, |
| 1905 | lazy_sym: link.File.LazySymbol, |
| 1906 | - code: *std.ArrayListUnmanaged(u8), |
| 1907 | + atom_index: u32, |
| 1908 | + w: *std.Io.Writer, |
| 1909 | debug_output: link.File.DebugInfoOutput, |
| 1910 | ) codegen.CodeGenError!void { |
| 1911 | const zcu = pt.zcu; |
| 1912 | @@ -2055,20 +2049,9 @@ pub fn emitLazy( |
| 1913 | .bin_file = lf, |
| 1914 | .pt = pt, |
| 1915 | .pic = mod.pic, |
| 1916 | - .atom_index = sym: { |
| 1917 | - if (lf.cast(.elf)) |ef| break :sym ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_sym) catch |err| |
| 1918 | - return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); |
| 1919 | - if (lf.cast(.macho)) |mf| break :sym mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_sym) catch |err| |
| 1920 | - return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); |
| 1921 | - if (lf.cast(.coff)) |cf| { |
| 1922 | - const atom = cf.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| |
| 1923 | - return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); |
| 1924 | - break :sym cf.getAtom(atom).getSymbolIndex().?; |
| 1925 | - } |
| 1926 | - unreachable; |
| 1927 | - }, |
| 1928 | + .atom_index = atom_index, |
| 1929 | .debug_output = debug_output, |
| 1930 | - .code = code, |
| 1931 | + .w = w, |
| 1932 | |
| 1933 | .prev_di_loc = undefined, |
| 1934 | .prev_di_pc = undefined, |
| 1935 | diff --git a/src/arch/x86_64/bits.zig b/src/arch/x86_64/bits.zig |
| 1936 | index 835093d11a..0504810933 100644 |
| 1937 | --- a/src/arch/x86_64/bits.zig |
| 1938 | +++ b/src/arch/x86_64/bits.zig |
| 1939 | @@ -727,6 +727,14 @@ pub const FrameIndex = enum(u32) { |
| 1940 | pub fn isNamed(fi: FrameIndex) bool { |
| 1941 | return @intFromEnum(fi) < named_count; |
| 1942 | } |
| 1943 | + |
| 1944 | + pub fn format(fi: FrameIndex, writer: *std.Io.Writer) std.Io.Writer.Error!void { |
| 1945 | + if (fi.isNamed()) { |
| 1946 | + try writer.print("FrameIndex.{t}", .{fi}); |
| 1947 | + } else { |
| 1948 | + try writer.print("FrameIndex({d})", .{@intFromEnum(fi)}); |
| 1949 | + } |
| 1950 | + } |
| 1951 | }; |
| 1952 | |
| 1953 | pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; |
| 1954 | diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig |
| 1955 | index 03ff7134f6..1d9c67175e 100644 |
| 1956 | --- a/src/arch/x86_64/encoder.zig |
| 1957 | +++ b/src/arch/x86_64/encoder.zig |
| 1958 | @@ -259,7 +259,7 @@ pub const Instruction = struct { |
| 1959 | switch (sib.base) { |
| 1960 | .none => any = false, |
| 1961 | .reg => |reg| try w.print("{s}", .{@tagName(reg)}), |
| 1962 | - .frame => |frame_index| try w.print("{}", .{frame_index}), |
| 1963 | + .frame => |frame_index| try w.print("{f}", .{frame_index}), |
| 1964 | .table => try w.print("Table", .{}), |
| 1965 | .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}), |
| 1966 | .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}), |
| 1967 | diff --git a/src/codegen.zig b/src/codegen.zig |
| 1968 | index 56e6e7c99f..4cbf3f5616 100644 |
| 1969 | --- a/src/codegen.zig |
| 1970 | +++ b/src/codegen.zig |
| 1971 | @@ -6,7 +6,6 @@ const link = @import("link.zig"); |
| 1972 | const log = std.log.scoped(.codegen); |
| 1973 | const mem = std.mem; |
| 1974 | const math = std.math; |
| 1975 | -const ArrayList = std.ArrayList; |
| 1976 | const target_util = @import("target.zig"); |
| 1977 | const trace = @import("tracy.zig").trace; |
| 1978 | |
| 1979 | @@ -179,10 +178,11 @@ pub fn emitFunction( |
| 1980 | pt: Zcu.PerThread, |
| 1981 | src_loc: Zcu.LazySrcLoc, |
| 1982 | func_index: InternPool.Index, |
| 1983 | + atom_index: u32, |
| 1984 | any_mir: *const AnyMir, |
| 1985 | - code: *ArrayList(u8), |
| 1986 | + w: *std.Io.Writer, |
| 1987 | debug_output: link.File.DebugInfoOutput, |
| 1988 | -) CodeGenError!void { |
| 1989 | +) (CodeGenError || std.Io.Writer.Error)!void { |
| 1990 | const zcu = pt.zcu; |
| 1991 | const func = zcu.funcInfo(func_index); |
| 1992 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| 1993 | @@ -195,7 +195,7 @@ pub fn emitFunction( |
| 1994 | => |backend| { |
| 1995 | dev.check(devFeatureForBackend(backend)); |
| 1996 | const mir = &@field(any_mir, AnyMir.tag(backend)); |
| 1997 | - return mir.emit(lf, pt, src_loc, func_index, code, debug_output); |
| 1998 | + return mir.emit(lf, pt, src_loc, func_index, atom_index, w, debug_output); |
| 1999 | }, |
| 2000 | } |
| 2001 | } |
| 2002 | @@ -205,9 +205,10 @@ pub fn generateLazyFunction( |
| 2003 | pt: Zcu.PerThread, |
| 2004 | src_loc: Zcu.LazySrcLoc, |
| 2005 | lazy_sym: link.File.LazySymbol, |
| 2006 | - code: *ArrayList(u8), |
| 2007 | + atom_index: u32, |
| 2008 | + w: *std.Io.Writer, |
| 2009 | debug_output: link.File.DebugInfoOutput, |
| 2010 | -) CodeGenError!void { |
| 2011 | +) (CodeGenError || std.Io.Writer.Error)!void { |
| 2012 | const zcu = pt.zcu; |
| 2013 | const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index| |
| 2014 | &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result |
| 2015 | @@ -217,19 +218,11 @@ pub fn generateLazyFunction( |
| 2016 | else => unreachable, |
| 2017 | inline .stage2_riscv64, .stage2_x86_64 => |backend| { |
| 2018 | dev.check(devFeatureForBackend(backend)); |
| 2019 | - return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output); |
| 2020 | + return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_index, w, debug_output); |
| 2021 | }, |
| 2022 | } |
| 2023 | } |
| 2024 | |
| 2025 | -fn writeFloat(comptime F: type, f: F, target: *const std.Target, endian: std.builtin.Endian, code: []u8) void { |
| 2026 | - _ = target; |
| 2027 | - const bits = @typeInfo(F).float.bits; |
| 2028 | - const Int = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } }); |
| 2029 | - const int: Int = @bitCast(f); |
| 2030 | - mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); |
| 2031 | -} |
| 2032 | - |
| 2033 | pub fn generateLazySymbol( |
| 2034 | bin_file: *link.File, |
| 2035 | pt: Zcu.PerThread, |
| 2036 | @@ -237,17 +230,14 @@ pub fn generateLazySymbol( |
| 2037 | lazy_sym: link.File.LazySymbol, |
| 2038 | // TODO don't use an "out" parameter like this; put it in the result instead |
| 2039 | alignment: *Alignment, |
| 2040 | - code: *ArrayList(u8), |
| 2041 | + w: *std.Io.Writer, |
| 2042 | debug_output: link.File.DebugInfoOutput, |
| 2043 | reloc_parent: link.File.RelocInfo.Parent, |
| 2044 | -) CodeGenError!void { |
| 2045 | - _ = reloc_parent; |
| 2046 | - |
| 2047 | +) (CodeGenError || std.Io.Writer.Error)!void { |
| 2048 | const tracy = trace(@src()); |
| 2049 | defer tracy.end(); |
| 2050 | |
| 2051 | const comp = bin_file.comp; |
| 2052 | - const gpa = comp.gpa; |
| 2053 | const zcu = pt.zcu; |
| 2054 | const ip = &zcu.intern_pool; |
| 2055 | const target = &comp.root_mod.resolved_target.result; |
| 2056 | @@ -260,37 +250,36 @@ pub fn generateLazySymbol( |
| 2057 | |
| 2058 | if (lazy_sym.kind == .code) { |
| 2059 | alignment.* = target_util.defaultFunctionAlignment(target); |
| 2060 | - return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, code, debug_output); |
| 2061 | + return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, reloc_parent.atom_index, w, debug_output); |
| 2062 | } |
| 2063 | |
| 2064 | if (lazy_sym.ty == .anyerror_type) { |
| 2065 | alignment.* = .@"4"; |
| 2066 | const err_names = ip.global_error_set.getNamesFromMainThread(); |
| 2067 | - var offset_index: u32 = @intCast(code.items.len); |
| 2068 | - var string_index: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); |
| 2069 | - try code.resize(gpa, offset_index + string_index); |
| 2070 | - mem.writeInt(u32, code.items[offset_index..][0..4], @intCast(err_names.len), endian); |
| 2071 | + const strings_start: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); |
| 2072 | + var string_index = strings_start; |
| 2073 | + try w.rebase(w.end, string_index); |
| 2074 | + w.writeInt(u32, @intCast(err_names.len), endian) catch unreachable; |
| 2075 | if (err_names.len == 0) return; |
| 2076 | - offset_index += 4; |
| 2077 | for (err_names) |err_name_nts| { |
| 2078 | - const err_name = err_name_nts.toSlice(ip); |
| 2079 | - mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); |
| 2080 | - offset_index += 4; |
| 2081 | - try code.ensureUnusedCapacity(gpa, err_name.len + 1); |
| 2082 | - code.appendSliceAssumeCapacity(err_name); |
| 2083 | - code.appendAssumeCapacity(0); |
| 2084 | - string_index += @intCast(err_name.len + 1); |
| 2085 | + w.writeInt(u32, string_index, endian) catch unreachable; |
| 2086 | + string_index += @intCast(err_name_nts.toSlice(ip).len + 1); |
| 2087 | + } |
| 2088 | + w.writeInt(u32, string_index, endian) catch unreachable; |
| 2089 | + try w.rebase(w.end, string_index - strings_start); |
| 2090 | + for (err_names) |err_name_nts| { |
| 2091 | + w.writeAll(err_name_nts.toSlice(ip)) catch unreachable; |
| 2092 | + w.writeByte(0) catch unreachable; |
| 2093 | } |
| 2094 | - mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); |
| 2095 | } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") { |
| 2096 | alignment.* = .@"1"; |
| 2097 | const enum_ty = Type.fromInterned(lazy_sym.ty); |
| 2098 | const tag_names = enum_ty.enumFields(zcu); |
| 2099 | for (0..tag_names.len) |tag_index| { |
| 2100 | const tag_name = tag_names.get(ip)[tag_index].toSlice(ip); |
| 2101 | - try code.ensureUnusedCapacity(gpa, tag_name.len + 1); |
| 2102 | - code.appendSliceAssumeCapacity(tag_name); |
| 2103 | - code.appendAssumeCapacity(0); |
| 2104 | + try w.rebase(w.end, tag_name.len + 1); |
| 2105 | + w.writeAll(tag_name) catch unreachable; |
| 2106 | + w.writeByte(0) catch unreachable; |
| 2107 | } |
| 2108 | } else { |
| 2109 | return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{ |
| 2110 | @@ -312,14 +301,13 @@ pub fn generateSymbol( |
| 2111 | pt: Zcu.PerThread, |
| 2112 | src_loc: Zcu.LazySrcLoc, |
| 2113 | val: Value, |
| 2114 | - code: *ArrayList(u8), |
| 2115 | + w: *std.Io.Writer, |
| 2116 | reloc_parent: link.File.RelocInfo.Parent, |
| 2117 | -) GenerateSymbolError!void { |
| 2118 | +) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 2119 | const tracy = trace(@src()); |
| 2120 | defer tracy.end(); |
| 2121 | |
| 2122 | const zcu = pt.zcu; |
| 2123 | - const gpa = zcu.gpa; |
| 2124 | const ip = &zcu.intern_pool; |
| 2125 | const ty = val.typeOf(zcu); |
| 2126 | |
| 2127 | @@ -330,7 +318,7 @@ pub fn generateSymbol( |
| 2128 | |
| 2129 | if (val.isUndef(zcu)) { |
| 2130 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 2131 | - try code.appendNTimes(gpa, 0xaa, abi_size); |
| 2132 | + try w.splatByteAll(0xaa, abi_size); |
| 2133 | return; |
| 2134 | } |
| 2135 | |
| 2136 | @@ -360,7 +348,7 @@ pub fn generateSymbol( |
| 2137 | .null => unreachable, // non-runtime value |
| 2138 | .@"unreachable" => unreachable, // non-runtime value |
| 2139 | .empty_tuple => return, |
| 2140 | - .false, .true => try code.append(gpa, switch (simple_value) { |
| 2141 | + .false, .true => try w.writeByte(switch (simple_value) { |
| 2142 | .false => 0, |
| 2143 | .true => 1, |
| 2144 | else => unreachable, |
| 2145 | @@ -376,11 +364,11 @@ pub fn generateSymbol( |
| 2146 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 2147 | var space: Value.BigIntSpace = undefined; |
| 2148 | const int_val = val.toBigInt(&space, zcu); |
| 2149 | - int_val.writeTwosComplement(try code.addManyAsSlice(gpa, abi_size), endian); |
| 2150 | + int_val.writeTwosComplement(try w.writableSlice(abi_size), endian); |
| 2151 | }, |
| 2152 | .err => |err| { |
| 2153 | const int = try pt.getErrorValue(err.name); |
| 2154 | - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(int), endian); |
| 2155 | + try w.writeInt(u16, @intCast(int), endian); |
| 2156 | }, |
| 2157 | .error_union => |error_union| { |
| 2158 | const payload_ty = ty.errorUnionPayload(zcu); |
| 2159 | @@ -390,7 +378,7 @@ pub fn generateSymbol( |
| 2160 | }; |
| 2161 | |
| 2162 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 2163 | - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); |
| 2164 | + try w.writeInt(u16, err_val, endian); |
| 2165 | return; |
| 2166 | } |
| 2167 | |
| 2168 | @@ -400,63 +388,63 @@ pub fn generateSymbol( |
| 2169 | |
| 2170 | // error value first when its type is larger than the error union's payload |
| 2171 | if (error_align.order(payload_align) == .gt) { |
| 2172 | - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); |
| 2173 | + try w.writeInt(u16, err_val, endian); |
| 2174 | } |
| 2175 | |
| 2176 | // emit payload part of the error union |
| 2177 | { |
| 2178 | - const begin = code.items.len; |
| 2179 | + const begin = w.end; |
| 2180 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) { |
| 2181 | .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }), |
| 2182 | .payload => |payload| payload, |
| 2183 | - }), code, reloc_parent); |
| 2184 | - const unpadded_end = code.items.len - begin; |
| 2185 | + }), w, reloc_parent); |
| 2186 | + const unpadded_end = w.end - begin; |
| 2187 | const padded_end = abi_align.forward(unpadded_end); |
| 2188 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 2189 | |
| 2190 | if (padding > 0) { |
| 2191 | - try code.appendNTimes(gpa, 0, padding); |
| 2192 | + try w.splatByteAll(0, padding); |
| 2193 | } |
| 2194 | } |
| 2195 | |
| 2196 | // Payload size is larger than error set, so emit our error set last |
| 2197 | if (error_align.compare(.lte, payload_align)) { |
| 2198 | - const begin = code.items.len; |
| 2199 | - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); |
| 2200 | - const unpadded_end = code.items.len - begin; |
| 2201 | + const begin = w.end; |
| 2202 | + try w.writeInt(u16, err_val, endian); |
| 2203 | + const unpadded_end = w.end - begin; |
| 2204 | const padded_end = abi_align.forward(unpadded_end); |
| 2205 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 2206 | |
| 2207 | if (padding > 0) { |
| 2208 | - try code.appendNTimes(gpa, 0, padding); |
| 2209 | + try w.splatByteAll(0, padding); |
| 2210 | } |
| 2211 | } |
| 2212 | }, |
| 2213 | .enum_tag => |enum_tag| { |
| 2214 | const int_tag_ty = ty.intTagType(zcu); |
| 2215 | - try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); |
| 2216 | + try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), w, reloc_parent); |
| 2217 | }, |
| 2218 | .float => |float| storage: switch (float.storage) { |
| 2219 | - .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), |
| 2220 | - .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), |
| 2221 | - .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), |
| 2222 | + .f16 => |f16_val| try w.writeInt(u16, @bitCast(f16_val), endian), |
| 2223 | + .f32 => |f32_val| try w.writeInt(u32, @bitCast(f32_val), endian), |
| 2224 | + .f64 => |f64_val| try w.writeInt(u64, @bitCast(f64_val), endian), |
| 2225 | .f80 => |f80_val| { |
| 2226 | - writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(gpa, 10)); |
| 2227 | + try w.writeInt(u80, @bitCast(f80_val), endian); |
| 2228 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 2229 | - try code.appendNTimes(gpa, 0, abi_size - 10); |
| 2230 | + try w.splatByteAll(0, abi_size - 10); |
| 2231 | }, |
| 2232 | .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { |
| 2233 | else => unreachable, |
| 2234 | 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, |
| 2235 | 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, |
| 2236 | 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, |
| 2237 | - 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), |
| 2238 | + 128 => try w.writeInt(u128, @bitCast(f128_val), endian), |
| 2239 | }, |
| 2240 | }, |
| 2241 | - .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), |
| 2242 | + .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), w, reloc_parent, 0), |
| 2243 | .slice => |slice| { |
| 2244 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent); |
| 2245 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent); |
| 2246 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), w, reloc_parent); |
| 2247 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), w, reloc_parent); |
| 2248 | }, |
| 2249 | .opt => { |
| 2250 | const payload_type = ty.optionalChild(zcu); |
| 2251 | @@ -465,9 +453,9 @@ pub fn generateSymbol( |
| 2252 | |
| 2253 | if (ty.optionalReprIsPayload(zcu)) { |
| 2254 | if (payload_val) |value| { |
| 2255 | - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); |
| 2256 | + try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); |
| 2257 | } else { |
| 2258 | - try code.appendNTimes(gpa, 0, abi_size); |
| 2259 | + try w.splatByteAll(0, abi_size); |
| 2260 | } |
| 2261 | } else { |
| 2262 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1; |
| 2263 | @@ -475,15 +463,15 @@ pub fn generateSymbol( |
| 2264 | const value = payload_val orelse Value.fromInterned(try pt.intern(.{ |
| 2265 | .undef = payload_type.toIntern(), |
| 2266 | })); |
| 2267 | - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); |
| 2268 | + try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); |
| 2269 | } |
| 2270 | - try code.append(gpa, @intFromBool(payload_val != null)); |
| 2271 | - try code.appendNTimes(gpa, 0, padding); |
| 2272 | + try w.writeByte(@intFromBool(payload_val != null)); |
| 2273 | + try w.splatByteAll(0, padding); |
| 2274 | } |
| 2275 | }, |
| 2276 | .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { |
| 2277 | .array_type => |array_type| switch (aggregate.storage) { |
| 2278 | - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(array_type.lenIncludingSentinel(), ip)), |
| 2279 | + .bytes => |bytes| try w.writeAll(bytes.toSlice(array_type.lenIncludingSentinel(), ip)), |
| 2280 | .elems, .repeated_elem => { |
| 2281 | var index: u64 = 0; |
| 2282 | while (index < array_type.lenIncludingSentinel()) : (index += 1) { |
| 2283 | @@ -494,14 +482,14 @@ pub fn generateSymbol( |
| 2284 | elem |
| 2285 | else |
| 2286 | array_type.sentinel, |
| 2287 | - }), code, reloc_parent); |
| 2288 | + }), w, reloc_parent); |
| 2289 | } |
| 2290 | }, |
| 2291 | }, |
| 2292 | .vector_type => |vector_type| { |
| 2293 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 2294 | if (vector_type.child == .bool_type) { |
| 2295 | - const bytes = try code.addManyAsSlice(gpa, abi_size); |
| 2296 | + const bytes = try w.writableSlice(abi_size); |
| 2297 | @memset(bytes, 0xaa); |
| 2298 | var index: usize = 0; |
| 2299 | const len = math.cast(usize, vector_type.len) orelse return error.Overflow; |
| 2300 | @@ -540,7 +528,7 @@ pub fn generateSymbol( |
| 2301 | } |
| 2302 | } else { |
| 2303 | switch (aggregate.storage) { |
| 2304 | - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(vector_type.len, ip)), |
| 2305 | + .bytes => |bytes| try w.writeAll(bytes.toSlice(vector_type.len, ip)), |
| 2306 | .elems, .repeated_elem => { |
| 2307 | var index: u64 = 0; |
| 2308 | while (index < vector_type.len) : (index += 1) { |
| 2309 | @@ -550,7 +538,7 @@ pub fn generateSymbol( |
| 2310 | math.cast(usize, index) orelse return error.Overflow |
| 2311 | ], |
| 2312 | .repeated_elem => |elem| elem, |
| 2313 | - }), code, reloc_parent); |
| 2314 | + }), w, reloc_parent); |
| 2315 | } |
| 2316 | }, |
| 2317 | } |
| 2318 | @@ -558,11 +546,11 @@ pub fn generateSymbol( |
| 2319 | const padding = abi_size - |
| 2320 | (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse |
| 2321 | return error.Overflow); |
| 2322 | - if (padding > 0) try code.appendNTimes(gpa, 0, padding); |
| 2323 | + if (padding > 0) try w.splatByteAll(0, padding); |
| 2324 | } |
| 2325 | }, |
| 2326 | .tuple_type => |tuple| { |
| 2327 | - const struct_begin = code.items.len; |
| 2328 | + const struct_begin = w.end; |
| 2329 | for ( |
| 2330 | tuple.types.get(ip), |
| 2331 | tuple.values.get(ip), |
| 2332 | @@ -580,8 +568,8 @@ pub fn generateSymbol( |
| 2333 | .repeated_elem => |elem| elem, |
| 2334 | }; |
| 2335 | |
| 2336 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); |
| 2337 | - const unpadded_field_end = code.items.len - struct_begin; |
| 2338 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 2339 | + const unpadded_field_end = w.end - struct_begin; |
| 2340 | |
| 2341 | // Pad struct members if required |
| 2342 | const padded_field_end = ty.structFieldOffset(index + 1, zcu); |
| 2343 | @@ -589,7 +577,7 @@ pub fn generateSymbol( |
| 2344 | return error.Overflow; |
| 2345 | |
| 2346 | if (padding > 0) { |
| 2347 | - try code.appendNTimes(gpa, 0, padding); |
| 2348 | + try w.splatByteAll(0, padding); |
| 2349 | } |
| 2350 | } |
| 2351 | }, |
| 2352 | @@ -598,8 +586,9 @@ pub fn generateSymbol( |
| 2353 | switch (struct_type.layout) { |
| 2354 | .@"packed" => { |
| 2355 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 2356 | - const current_pos = code.items.len; |
| 2357 | - try code.appendNTimes(gpa, 0, abi_size); |
| 2358 | + const start = w.end; |
| 2359 | + const buffer = try w.writableSlice(abi_size); |
| 2360 | + @memset(buffer, 0); |
| 2361 | var bits: u16 = 0; |
| 2362 | |
| 2363 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { |
| 2364 | @@ -619,22 +608,20 @@ pub fn generateSymbol( |
| 2365 | error.DivisionByZero => unreachable, |
| 2366 | error.UnexpectedRemainder => return error.RelocationNotByteAligned, |
| 2367 | }; |
| 2368 | - code.items.len = current_pos + field_offset; |
| 2369 | - // TODO: code.lockPointers(); |
| 2370 | + w.end = start + field_offset; |
| 2371 | defer { |
| 2372 | - assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8)); |
| 2373 | - // TODO: code.unlockPointers(); |
| 2374 | - code.items.len = current_pos + abi_size; |
| 2375 | + assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8)); |
| 2376 | + w.end = start + abi_size; |
| 2377 | } |
| 2378 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); |
| 2379 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 2380 | } else { |
| 2381 | - Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable; |
| 2382 | + Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable; |
| 2383 | } |
| 2384 | bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); |
| 2385 | } |
| 2386 | }, |
| 2387 | .auto, .@"extern" => { |
| 2388 | - const struct_begin = code.items.len; |
| 2389 | + const struct_begin = w.end; |
| 2390 | const field_types = struct_type.field_types.get(ip); |
| 2391 | const offsets = struct_type.offsets.get(ip); |
| 2392 | |
| 2393 | @@ -654,11 +641,11 @@ pub fn generateSymbol( |
| 2394 | |
| 2395 | const padding = math.cast( |
| 2396 | usize, |
| 2397 | - offsets[field_index] - (code.items.len - struct_begin), |
| 2398 | + offsets[field_index] - (w.end - struct_begin), |
| 2399 | ) orelse return error.Overflow; |
| 2400 | - if (padding > 0) try code.appendNTimes(gpa, 0, padding); |
| 2401 | + if (padding > 0) try w.splatByteAll(0, padding); |
| 2402 | |
| 2403 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); |
| 2404 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 2405 | } |
| 2406 | |
| 2407 | const size = struct_type.sizeUnordered(ip); |
| 2408 | @@ -666,10 +653,9 @@ pub fn generateSymbol( |
| 2409 | |
| 2410 | const padding = math.cast( |
| 2411 | usize, |
| 2412 | - std.mem.alignForward(u64, size, @max(alignment, 1)) - |
| 2413 | - (code.items.len - struct_begin), |
| 2414 | + std.mem.alignForward(u64, size, @max(alignment, 1)) - (w.end - struct_begin), |
| 2415 | ) orelse return error.Overflow; |
| 2416 | - if (padding > 0) try code.appendNTimes(gpa, 0, padding); |
| 2417 | + if (padding > 0) try w.splatByteAll(0, padding); |
| 2418 | }, |
| 2419 | } |
| 2420 | }, |
| 2421 | @@ -679,12 +665,12 @@ pub fn generateSymbol( |
| 2422 | const layout = ty.unionGetLayout(zcu); |
| 2423 | |
| 2424 | if (layout.payload_size == 0) { |
| 2425 | - return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); |
| 2426 | + return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 2427 | } |
| 2428 | |
| 2429 | // Check if we should store the tag first. |
| 2430 | if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { |
| 2431 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); |
| 2432 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 2433 | } |
| 2434 | |
| 2435 | const union_obj = zcu.typeToUnion(ty).?; |
| 2436 | @@ -692,24 +678,24 @@ pub fn generateSymbol( |
| 2437 | const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; |
| 2438 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 2439 | if (!field_ty.hasRuntimeBits(zcu)) { |
| 2440 | - try code.appendNTimes(gpa, 0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); |
| 2441 | + try w.splatByteAll(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); |
| 2442 | } else { |
| 2443 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); |
| 2444 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); |
| 2445 | |
| 2446 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow; |
| 2447 | if (padding > 0) { |
| 2448 | - try code.appendNTimes(gpa, 0, padding); |
| 2449 | + try w.splatByteAll(0, padding); |
| 2450 | } |
| 2451 | } |
| 2452 | } else { |
| 2453 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); |
| 2454 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); |
| 2455 | } |
| 2456 | |
| 2457 | if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { |
| 2458 | - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); |
| 2459 | + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 2460 | |
| 2461 | if (layout.padding > 0) { |
| 2462 | - try code.appendNTimes(gpa, 0, layout.padding); |
| 2463 | + try w.splatByteAll(0, layout.padding); |
| 2464 | } |
| 2465 | } |
| 2466 | }, |
| 2467 | @@ -722,30 +708,30 @@ fn lowerPtr( |
| 2468 | pt: Zcu.PerThread, |
| 2469 | src_loc: Zcu.LazySrcLoc, |
| 2470 | ptr_val: InternPool.Index, |
| 2471 | - code: *ArrayList(u8), |
| 2472 | + w: *std.Io.Writer, |
| 2473 | reloc_parent: link.File.RelocInfo.Parent, |
| 2474 | prev_offset: u64, |
| 2475 | -) GenerateSymbolError!void { |
| 2476 | +) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 2477 | const zcu = pt.zcu; |
| 2478 | const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; |
| 2479 | const offset: u64 = prev_offset + ptr.byte_offset; |
| 2480 | return switch (ptr.base_addr) { |
| 2481 | - .nav => |nav| try lowerNavRef(bin_file, pt, nav, code, reloc_parent, offset), |
| 2482 | - .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset), |
| 2483 | - .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent), |
| 2484 | + .nav => |nav| try lowerNavRef(bin_file, pt, nav, w, reloc_parent, offset), |
| 2485 | + .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, w, reloc_parent, offset), |
| 2486 | + .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), w, reloc_parent), |
| 2487 | .eu_payload => |eu_ptr| try lowerPtr( |
| 2488 | bin_file, |
| 2489 | pt, |
| 2490 | src_loc, |
| 2491 | eu_ptr, |
| 2492 | - code, |
| 2493 | + w, |
| 2494 | reloc_parent, |
| 2495 | offset + errUnionPayloadOffset( |
| 2496 | Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu), |
| 2497 | zcu, |
| 2498 | ), |
| 2499 | ), |
| 2500 | - .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset), |
| 2501 | + .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, w, reloc_parent, offset), |
| 2502 | .field => |field| { |
| 2503 | const base_ptr = Value.fromInterned(field.base); |
| 2504 | const base_ty = base_ptr.typeOf(zcu).childType(zcu); |
| 2505 | @@ -764,7 +750,7 @@ fn lowerPtr( |
| 2506 | }, |
| 2507 | else => unreachable, |
| 2508 | }; |
| 2509 | - return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off); |
| 2510 | + return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off); |
| 2511 | }, |
| 2512 | .arr_elem, .comptime_field, .comptime_alloc => unreachable, |
| 2513 | }; |
| 2514 | @@ -775,12 +761,11 @@ fn lowerUavRef( |
| 2515 | pt: Zcu.PerThread, |
| 2516 | src_loc: Zcu.LazySrcLoc, |
| 2517 | uav: InternPool.Key.Ptr.BaseAddr.Uav, |
| 2518 | - code: *ArrayList(u8), |
| 2519 | + w: *std.Io.Writer, |
| 2520 | reloc_parent: link.File.RelocInfo.Parent, |
| 2521 | offset: u64, |
| 2522 | -) GenerateSymbolError!void { |
| 2523 | +) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 2524 | const zcu = pt.zcu; |
| 2525 | - const gpa = zcu.gpa; |
| 2526 | const ip = &zcu.intern_pool; |
| 2527 | const comp = lf.comp; |
| 2528 | const target = &comp.root_mod.resolved_target.result; |
| 2529 | @@ -790,10 +775,9 @@ fn lowerUavRef( |
| 2530 | const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; |
| 2531 | |
| 2532 | log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)}); |
| 2533 | - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); |
| 2534 | |
| 2535 | if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) { |
| 2536 | - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); |
| 2537 | + try w.splatByteAll(0xaa, ptr_width_bytes); |
| 2538 | return; |
| 2539 | } |
| 2540 | |
| 2541 | @@ -804,29 +788,32 @@ fn lowerUavRef( |
| 2542 | dev.check(link.File.Tag.wasm.devFeature()); |
| 2543 | const wasm = lf.cast(.wasm).?; |
| 2544 | assert(reloc_parent == .none); |
| 2545 | - try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset)); |
| 2546 | - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); |
| 2547 | + try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset)); |
| 2548 | + try w.splatByteAll(0, ptr_width_bytes); |
| 2549 | return; |
| 2550 | }, |
| 2551 | else => {}, |
| 2552 | } |
| 2553 | |
| 2554 | - const uav_align = ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment; |
| 2555 | + const uav_align = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu); |
| 2556 | switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) { |
| 2557 | .sym_index => {}, |
| 2558 | .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}), |
| 2559 | } |
| 2560 | |
| 2561 | - const vaddr = try lf.getUavVAddr(uav_val, .{ |
| 2562 | + const vaddr = lf.getUavVAddr(uav_val, .{ |
| 2563 | .parent = reloc_parent, |
| 2564 | - .offset = code.items.len, |
| 2565 | + .offset = w.end, |
| 2566 | .addend = @intCast(offset), |
| 2567 | - }); |
| 2568 | + }) catch |err| switch (err) { |
| 2569 | + error.OutOfMemory => return error.OutOfMemory, |
| 2570 | + else => |e| std.debug.panic("TODO rework lowerUav. internal error: {t}", .{e}), |
| 2571 | + }; |
| 2572 | const endian = target.cpu.arch.endian(); |
| 2573 | switch (ptr_width_bytes) { |
| 2574 | - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), |
| 2575 | - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), |
| 2576 | - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), |
| 2577 | + 2 => try w.writeInt(u16, @intCast(vaddr), endian), |
| 2578 | + 4 => try w.writeInt(u32, @intCast(vaddr), endian), |
| 2579 | + 8 => try w.writeInt(u64, vaddr, endian), |
| 2580 | else => unreachable, |
| 2581 | } |
| 2582 | } |
| 2583 | @@ -835,10 +822,10 @@ fn lowerNavRef( |
| 2584 | lf: *link.File, |
| 2585 | pt: Zcu.PerThread, |
| 2586 | nav_index: InternPool.Nav.Index, |
| 2587 | - code: *ArrayList(u8), |
| 2588 | + w: *std.Io.Writer, |
| 2589 | reloc_parent: link.File.RelocInfo.Parent, |
| 2590 | offset: u64, |
| 2591 | -) GenerateSymbolError!void { |
| 2592 | +) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 2593 | const zcu = pt.zcu; |
| 2594 | const gpa = zcu.gpa; |
| 2595 | const ip = &zcu.intern_pool; |
| 2596 | @@ -848,10 +835,8 @@ fn lowerNavRef( |
| 2597 | const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); |
| 2598 | const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; |
| 2599 | |
| 2600 | - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); |
| 2601 | - |
| 2602 | if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) { |
| 2603 | - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); |
| 2604 | + try w.splatByteAll(0xaa, ptr_width_bytes); |
| 2605 | return; |
| 2606 | } |
| 2607 | |
| 2608 | @@ -870,13 +855,13 @@ fn lowerNavRef( |
| 2609 | } else { |
| 2610 | try wasm.func_table_fixups.append(gpa, .{ |
| 2611 | .table_index = @enumFromInt(gop.index), |
| 2612 | - .offset = @intCast(code.items.len), |
| 2613 | + .offset = @intCast(w.end), |
| 2614 | }); |
| 2615 | } |
| 2616 | } else { |
| 2617 | if (is_obj) { |
| 2618 | try wasm.out_relocs.append(gpa, .{ |
| 2619 | - .offset = @intCast(code.items.len), |
| 2620 | + .offset = @intCast(w.end), |
| 2621 | .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, |
| 2622 | .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, |
| 2623 | .addend = @intCast(offset), |
| 2624 | @@ -885,12 +870,12 @@ fn lowerNavRef( |
| 2625 | try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); |
| 2626 | wasm.nav_fixups.appendAssumeCapacity(.{ |
| 2627 | .navs_exe_index = try wasm.refNavExe(nav_index), |
| 2628 | - .offset = @intCast(code.items.len), |
| 2629 | + .offset = @intCast(w.end), |
| 2630 | .addend = @intCast(offset), |
| 2631 | }); |
| 2632 | } |
| 2633 | } |
| 2634 | - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); |
| 2635 | + try w.splatByteAll(0, ptr_width_bytes); |
| 2636 | return; |
| 2637 | }, |
| 2638 | else => {}, |
| 2639 | @@ -898,14 +883,14 @@ fn lowerNavRef( |
| 2640 | |
| 2641 | const vaddr = lf.getNavVAddr(pt, nav_index, .{ |
| 2642 | .parent = reloc_parent, |
| 2643 | - .offset = code.items.len, |
| 2644 | + .offset = w.end, |
| 2645 | .addend = @intCast(offset), |
| 2646 | }) catch @panic("TODO rework getNavVAddr"); |
| 2647 | const endian = target.cpu.arch.endian(); |
| 2648 | switch (ptr_width_bytes) { |
| 2649 | - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), |
| 2650 | - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), |
| 2651 | - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), |
| 2652 | + 2 => try w.writeInt(u16, @intCast(vaddr), endian), |
| 2653 | + 4 => try w.writeInt(u32, @intCast(vaddr), endian), |
| 2654 | + 8 => try w.writeInt(u64, vaddr, endian), |
| 2655 | else => unreachable, |
| 2656 | } |
| 2657 | } |
| 2658 | @@ -962,6 +947,16 @@ pub fn genNavRef( |
| 2659 | }, |
| 2660 | .link_once => unreachable, |
| 2661 | } |
| 2662 | + } else if (lf.cast(.elf2)) |elf| { |
| 2663 | + return .{ .sym_index = @intFromEnum(elf.navSymbol(zcu, nav_index) catch |err| switch (err) { |
| 2664 | + error.OutOfMemory => return error.OutOfMemory, |
| 2665 | + else => |e| return .{ .fail = try ErrorMsg.create( |
| 2666 | + zcu.gpa, |
| 2667 | + src_loc, |
| 2668 | + "linker failed to create a nav: {t}", |
| 2669 | + .{e}, |
| 2670 | + ) }, |
| 2671 | + }) }; |
| 2672 | } else if (lf.cast(.macho)) |macho_file| { |
| 2673 | const zo = macho_file.getZigObject().?; |
| 2674 | switch (linkage) { |
| 2675 | diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig |
| 2676 | index 318a51da95..be6478eae8 100644 |
| 2677 | --- a/src/codegen/aarch64/Mir.zig |
| 2678 | +++ b/src/codegen/aarch64/Mir.zig |
| 2679 | @@ -56,13 +56,13 @@ pub fn emit( |
| 2680 | pt: Zcu.PerThread, |
| 2681 | src_loc: Zcu.LazySrcLoc, |
| 2682 | func_index: InternPool.Index, |
| 2683 | - code: *std.ArrayListUnmanaged(u8), |
| 2684 | + atom_index: u32, |
| 2685 | + w: *std.Io.Writer, |
| 2686 | debug_output: link.File.DebugInfoOutput, |
| 2687 | ) !void { |
| 2688 | _ = debug_output; |
| 2689 | const zcu = pt.zcu; |
| 2690 | const ip = &zcu.intern_pool; |
| 2691 | - const gpa = zcu.gpa; |
| 2692 | const func = zcu.funcInfo(func_index); |
| 2693 | const nav = ip.getNav(func.owner_nav); |
| 2694 | const mod = zcu.navFileScope(func.owner_nav).mod.?; |
| 2695 | @@ -81,20 +81,19 @@ pub fn emit( |
| 2696 | @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)), |
| 2697 | Instruction.size, |
| 2698 | ) - 1); |
| 2699 | - try code.ensureUnusedCapacity(gpa, Instruction.size * |
| 2700 | - (code_len + literals_align_gap + mir.literals.len)); |
| 2701 | - emitInstructionsForward(code, mir.prologue); |
| 2702 | - emitInstructionsBackward(code, mir.body); |
| 2703 | - const body_end: u32 = @intCast(code.items.len); |
| 2704 | - emitInstructionsBackward(code, mir.epilogue); |
| 2705 | - code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap); |
| 2706 | - code.appendSliceAssumeCapacity(@ptrCast(mir.literals)); |
| 2707 | + try w.rebase(w.end, Instruction.size * (code_len + literals_align_gap + mir.literals.len)); |
| 2708 | + emitInstructionsForward(w, mir.prologue) catch unreachable; |
| 2709 | + emitInstructionsBackward(w, mir.body) catch unreachable; |
| 2710 | + const body_end: u32 = @intCast(w.end); |
| 2711 | + emitInstructionsBackward(w, mir.epilogue) catch unreachable; |
| 2712 | + w.splatByteAll(0, Instruction.size * literals_align_gap) catch unreachable; |
| 2713 | + w.writeAll(@ptrCast(mir.literals)) catch unreachable; |
| 2714 | mir_log.debug("", .{}); |
| 2715 | |
| 2716 | for (mir.nav_relocs) |nav_reloc| try emitReloc( |
| 2717 | lf, |
| 2718 | zcu, |
| 2719 | - func.owner_nav, |
| 2720 | + atom_index, |
| 2721 | switch (try @import("../../codegen.zig").genNavRef( |
| 2722 | lf, |
| 2723 | pt, |
| 2724 | @@ -112,7 +111,7 @@ pub fn emit( |
| 2725 | for (mir.uav_relocs) |uav_reloc| try emitReloc( |
| 2726 | lf, |
| 2727 | zcu, |
| 2728 | - func.owner_nav, |
| 2729 | + atom_index, |
| 2730 | switch (try lf.lowerUav( |
| 2731 | pt, |
| 2732 | uav_reloc.uav.val, |
| 2733 | @@ -129,7 +128,7 @@ pub fn emit( |
| 2734 | for (mir.lazy_relocs) |lazy_reloc| try emitReloc( |
| 2735 | lf, |
| 2736 | zcu, |
| 2737 | - func.owner_nav, |
| 2738 | + atom_index, |
| 2739 | if (lf.cast(.elf)) |ef| |
| 2740 | ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| |
| 2741 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) |
| 2742 | @@ -150,7 +149,7 @@ pub fn emit( |
| 2743 | for (mir.global_relocs) |global_reloc| try emitReloc( |
| 2744 | lf, |
| 2745 | zcu, |
| 2746 | - func.owner_nav, |
| 2747 | + atom_index, |
| 2748 | if (lf.cast(.elf)) |ef| |
| 2749 | try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null) |
| 2750 | else if (lf.cast(.macho)) |mf| |
| 2751 | @@ -168,30 +167,30 @@ pub fn emit( |
| 2752 | var instruction = mir.body[literal_reloc.label]; |
| 2753 | instruction.load_store.register_literal.group.imm19 += literal_reloc_offset; |
| 2754 | instruction.write( |
| 2755 | - code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], |
| 2756 | + w.buffered()[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], |
| 2757 | ); |
| 2758 | } |
| 2759 | } |
| 2760 | |
| 2761 | -fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { |
| 2762 | - for (instructions) |instruction| emitInstruction(code, instruction); |
| 2763 | +fn emitInstructionsForward(w: *std.Io.Writer, instructions: []const Instruction) !void { |
| 2764 | + for (instructions) |instruction| try emitInstruction(w, instruction); |
| 2765 | } |
| 2766 | -fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { |
| 2767 | +fn emitInstructionsBackward(w: *std.Io.Writer, instructions: []const Instruction) !void { |
| 2768 | var instruction_index = instructions.len; |
| 2769 | while (instruction_index > 0) { |
| 2770 | instruction_index -= 1; |
| 2771 | - emitInstruction(code, instructions[instruction_index]); |
| 2772 | + try emitInstruction(w, instructions[instruction_index]); |
| 2773 | } |
| 2774 | } |
| 2775 | -fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void { |
| 2776 | +fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void { |
| 2777 | mir_log.debug(" {f}", .{instruction}); |
| 2778 | - instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size)); |
| 2779 | + instruction.write(try w.writableArray(Instruction.size)); |
| 2780 | } |
| 2781 | |
| 2782 | fn emitReloc( |
| 2783 | lf: *link.File, |
| 2784 | zcu: *Zcu, |
| 2785 | - owner_nav: InternPool.Nav.Index, |
| 2786 | + atom_index: u32, |
| 2787 | sym_index: u32, |
| 2788 | instruction: Instruction, |
| 2789 | offset: u32, |
| 2790 | @@ -202,7 +201,7 @@ fn emitReloc( |
| 2791 | else => unreachable, |
| 2792 | .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { |
| 2793 | const zo = ef.zigObjectPtr().?; |
| 2794 | - const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; |
| 2795 | + const atom = zo.symbol(atom_index).atom(ef).?; |
| 2796 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { |
| 2797 | else => unreachable, |
| 2798 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { |
| 2799 | @@ -221,7 +220,7 @@ fn emitReloc( |
| 2800 | }, zo); |
| 2801 | } else if (lf.cast(.macho)) |mf| { |
| 2802 | const zo = mf.getZigObject().?; |
| 2803 | - const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; |
| 2804 | + const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 2805 | switch (decoded.decode()) { |
| 2806 | else => unreachable, |
| 2807 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { |
| 2808 | @@ -260,7 +259,7 @@ fn emitReloc( |
| 2809 | }, |
| 2810 | .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { |
| 2811 | const zo = ef.zigObjectPtr().?; |
| 2812 | - const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; |
| 2813 | + const atom = zo.symbol(atom_index).atom(ef).?; |
| 2814 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { |
| 2815 | .b => .JUMP26, |
| 2816 | .bl => .CALL26, |
| 2817 | @@ -272,7 +271,7 @@ fn emitReloc( |
| 2818 | }, zo); |
| 2819 | } else if (lf.cast(.macho)) |mf| { |
| 2820 | const zo = mf.getZigObject().?; |
| 2821 | - const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; |
| 2822 | + const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 2823 | try atom.addReloc(mf, .{ |
| 2824 | .tag = .@"extern", |
| 2825 | .offset = offset, |
| 2826 | @@ -289,7 +288,7 @@ fn emitReloc( |
| 2827 | }, |
| 2828 | .load_store => |decoded| if (lf.cast(.elf)) |ef| { |
| 2829 | const zo = ef.zigObjectPtr().?; |
| 2830 | - const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; |
| 2831 | + const atom = zo.symbol(atom_index).atom(ef).?; |
| 2832 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { |
| 2833 | .integer => |integer| switch (integer.decode()) { |
| 2834 | .unallocated, .prfm => unreachable, |
| 2835 | @@ -316,7 +315,7 @@ fn emitReloc( |
| 2836 | }, zo); |
| 2837 | } else if (lf.cast(.macho)) |mf| { |
| 2838 | const zo = mf.getZigObject().?; |
| 2839 | - const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; |
| 2840 | + const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 2841 | try atom.addReloc(mf, .{ |
| 2842 | .tag = .@"extern", |
| 2843 | .offset = offset, |
| 2844 | diff --git a/src/dev.zig b/src/dev.zig |
| 2845 | index ac30cedecd..266796a2dc 100644 |
| 2846 | --- a/src/dev.zig |
| 2847 | +++ b/src/dev.zig |
| 2848 | @@ -97,6 +97,7 @@ pub const Env = enum { |
| 2849 | .lld_linker, |
| 2850 | .coff_linker, |
| 2851 | .elf_linker, |
| 2852 | + .elf2_linker, |
| 2853 | .macho_linker, |
| 2854 | .c_linker, |
| 2855 | .wasm_linker, |
| 2856 | @@ -163,6 +164,7 @@ pub const Env = enum { |
| 2857 | .incremental, |
| 2858 | .aarch64_backend, |
| 2859 | .elf_linker, |
| 2860 | + .elf2_linker, |
| 2861 | => true, |
| 2862 | else => Env.sema.supports(feature), |
| 2863 | }, |
| 2864 | @@ -210,6 +212,7 @@ pub const Env = enum { |
| 2865 | .legalize, |
| 2866 | .x86_64_backend, |
| 2867 | .elf_linker, |
| 2868 | + .elf2_linker, |
| 2869 | => true, |
| 2870 | else => Env.sema.supports(feature), |
| 2871 | }, |
| 2872 | @@ -282,6 +285,7 @@ pub const Feature = enum { |
| 2873 | lld_linker, |
| 2874 | coff_linker, |
| 2875 | elf_linker, |
| 2876 | + elf2_linker, |
| 2877 | macho_linker, |
| 2878 | c_linker, |
| 2879 | wasm_linker, |
| 2880 | diff --git a/src/link.zig b/src/link.zig |
| 2881 | index 27cd6620e3..277013efb3 100644 |
| 2882 | --- a/src/link.zig |
| 2883 | +++ b/src/link.zig |
| 2884 | @@ -219,6 +219,7 @@ pub const Diags = struct { |
| 2885 | } |
| 2886 | |
| 2887 | pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void { |
| 2888 | + @branchHint(.cold); |
| 2889 | return addErrorSourceLocation(diags, .none, format, args); |
| 2890 | } |
| 2891 | |
| 2892 | @@ -529,7 +530,7 @@ pub const File = struct { |
| 2893 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); |
| 2894 | return &lld.base; |
| 2895 | } |
| 2896 | - switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { |
| 2897 | + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) { |
| 2898 | .plan9 => return error.UnsupportedObjectFormat, |
| 2899 | inline else => |tag| { |
| 2900 | dev.check(tag.devFeature()); |
| 2901 | @@ -552,7 +553,7 @@ pub const File = struct { |
| 2902 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); |
| 2903 | return &lld.base; |
| 2904 | } |
| 2905 | - switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { |
| 2906 | + switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) { |
| 2907 | .plan9 => return error.UnsupportedObjectFormat, |
| 2908 | inline else => |tag| { |
| 2909 | dev.check(tag.devFeature()); |
| 2910 | @@ -579,7 +580,8 @@ pub const File = struct { |
| 2911 | const emit = base.emit; |
| 2912 | if (base.child_pid) |pid| { |
| 2913 | if (builtin.os.tag == .windows) { |
| 2914 | - base.cast(.coff).?.ptraceAttach(pid) catch |err| { |
| 2915 | + const coff_file = base.cast(.coff).?; |
| 2916 | + coff_file.ptraceAttach(pid) catch |err| { |
| 2917 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); |
| 2918 | }; |
| 2919 | } else { |
| 2920 | @@ -597,8 +599,11 @@ pub const File = struct { |
| 2921 | .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| { |
| 2922 | log.warn("ptrace failure: {s}", .{@errorName(err)}); |
| 2923 | }, |
| 2924 | - .macos => base.cast(.macho).?.ptraceAttach(pid) catch |err| { |
| 2925 | - log.warn("attaching failed with error: {s}", .{@errorName(err)}); |
| 2926 | + .macos => { |
| 2927 | + const macho_file = base.cast(.macho).?; |
| 2928 | + macho_file.ptraceAttach(pid) catch |err| { |
| 2929 | + log.warn("attaching failed with error: {s}", .{@errorName(err)}); |
| 2930 | + }; |
| 2931 | }, |
| 2932 | .windows => unreachable, |
| 2933 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 2934 | @@ -613,6 +618,20 @@ pub const File = struct { |
| 2935 | .mode = determineMode(output_mode, link_mode), |
| 2936 | }); |
| 2937 | }, |
| 2938 | + .elf2 => { |
| 2939 | + const elf = base.cast(.elf2).?; |
| 2940 | + if (base.file == null) { |
| 2941 | + elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{ |
| 2942 | + .truncate = false, |
| 2943 | + .read = true, |
| 2944 | + .mode = determineMode(comp.config.output_mode, comp.config.link_mode), |
| 2945 | + }); |
| 2946 | + base.file = elf.mf.file; |
| 2947 | + try elf.mf.ensureTotalCapacity( |
| 2948 | + @intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]), |
| 2949 | + ); |
| 2950 | + } |
| 2951 | + }, |
| 2952 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 2953 | .plan9 => unreachable, |
| 2954 | } |
| 2955 | @@ -669,14 +688,30 @@ pub const File = struct { |
| 2956 | |
| 2957 | if (base.child_pid) |pid| { |
| 2958 | switch (builtin.os.tag) { |
| 2959 | - .macos => base.cast(.macho).?.ptraceDetach(pid) catch |err| { |
| 2960 | - log.warn("detaching failed with error: {s}", .{@errorName(err)}); |
| 2961 | + .macos => { |
| 2962 | + const macho_file = base.cast(.macho).?; |
| 2963 | + macho_file.ptraceDetach(pid) catch |err| { |
| 2964 | + log.warn("detaching failed with error: {s}", .{@errorName(err)}); |
| 2965 | + }; |
| 2966 | + }, |
| 2967 | + .windows => { |
| 2968 | + const coff_file = base.cast(.coff).?; |
| 2969 | + coff_file.ptraceDetach(pid); |
| 2970 | }, |
| 2971 | - .windows => base.cast(.coff).?.ptraceDetach(pid), |
| 2972 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 2973 | } |
| 2974 | } |
| 2975 | }, |
| 2976 | + .elf2 => { |
| 2977 | + const elf = base.cast(.elf2).?; |
| 2978 | + if (base.file) |f| { |
| 2979 | + elf.mf.unmap(); |
| 2980 | + assert(elf.mf.file.handle == f.handle); |
| 2981 | + elf.mf.file = undefined; |
| 2982 | + f.close(); |
| 2983 | + base.file = null; |
| 2984 | + } |
| 2985 | + }, |
| 2986 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 2987 | .plan9 => unreachable, |
| 2988 | } |
| 2989 | @@ -793,6 +828,7 @@ pub const File = struct { |
| 2990 | .spirv => {}, |
| 2991 | .goff, .xcoff => {}, |
| 2992 | .plan9 => unreachable, |
| 2993 | + .elf2 => {}, |
| 2994 | inline else => |tag| { |
| 2995 | dev.check(tag.devFeature()); |
| 2996 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); |
| 2997 | @@ -825,6 +861,26 @@ pub const File = struct { |
| 2998 | } |
| 2999 | } |
| 3000 | |
| 3001 | + pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool { |
| 3002 | + switch (base.tag) { |
| 3003 | + else => return false, |
| 3004 | + inline .elf2 => |tag| { |
| 3005 | + dev.check(tag.devFeature()); |
| 3006 | + return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid); |
| 3007 | + }, |
| 3008 | + } |
| 3009 | + } |
| 3010 | + |
| 3011 | + pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void { |
| 3012 | + switch (base.tag) { |
| 3013 | + else => {}, |
| 3014 | + inline .elf2 => |tag| { |
| 3015 | + dev.check(tag.devFeature()); |
| 3016 | + return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt); |
| 3017 | + }, |
| 3018 | + } |
| 3019 | + } |
| 3020 | + |
| 3021 | pub const FlushError = error{ |
| 3022 | /// Indicates an error will be present in `Compilation.link_diags`. |
| 3023 | LinkFailure, |
| 3024 | @@ -1099,7 +1155,7 @@ pub const File = struct { |
| 3025 | if (base.zcu_object_basename != null) return; |
| 3026 | |
| 3027 | switch (base.tag) { |
| 3028 | - inline .wasm => |tag| { |
| 3029 | + inline .elf2, .wasm => |tag| { |
| 3030 | dev.check(tag.devFeature()); |
| 3031 | return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); |
| 3032 | }, |
| 3033 | @@ -1110,6 +1166,7 @@ pub const File = struct { |
| 3034 | pub const Tag = enum { |
| 3035 | coff, |
| 3036 | elf, |
| 3037 | + elf2, |
| 3038 | macho, |
| 3039 | c, |
| 3040 | wasm, |
| 3041 | @@ -1123,6 +1180,7 @@ pub const File = struct { |
| 3042 | return switch (tag) { |
| 3043 | .coff => Coff, |
| 3044 | .elf => Elf, |
| 3045 | + .elf2 => Elf2, |
| 3046 | .macho => MachO, |
| 3047 | .c => C, |
| 3048 | .wasm => Wasm, |
| 3049 | @@ -1134,10 +1192,10 @@ pub const File = struct { |
| 3050 | }; |
| 3051 | } |
| 3052 | |
| 3053 | - fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag { |
| 3054 | + fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag { |
| 3055 | return switch (ofmt) { |
| 3056 | .coff => .coff, |
| 3057 | - .elf => .elf, |
| 3058 | + .elf => if (use_new_linker) .elf2 else .elf, |
| 3059 | .macho => .macho, |
| 3060 | .wasm => .wasm, |
| 3061 | .plan9 => .plan9, |
| 3062 | @@ -1223,6 +1281,7 @@ pub const File = struct { |
| 3063 | pub const C = @import("link/C.zig"); |
| 3064 | pub const Coff = @import("link/Coff.zig"); |
| 3065 | pub const Elf = @import("link/Elf.zig"); |
| 3066 | + pub const Elf2 = @import("link/Elf2.zig"); |
| 3067 | pub const MachO = @import("link/MachO.zig"); |
| 3068 | pub const SpirV = @import("link/SpirV.zig"); |
| 3069 | pub const Wasm = @import("link/Wasm.zig"); |
| 3070 | @@ -1548,6 +1607,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void { |
| 3071 | } |
| 3072 | } |
| 3073 | } |
| 3074 | +pub fn doIdleTask(comp: *Compilation, tid: usize) error{ OutOfMemory, LinkFailure }!bool { |
| 3075 | + return if (comp.bin_file) |lf| lf.idle(@enumFromInt(tid)) else false; |
| 3076 | +} |
| 3077 | /// After the main pipeline is done, but before flush, the compilation may need to link one final |
| 3078 | /// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running |
| 3079 | /// by then, we expose this function which can be called directly. |
| 3080 | @@ -1573,6 +1635,13 @@ pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 3081 | }; |
| 3082 | } |
| 3083 | } |
| 3084 | +pub fn updateErrorData(pt: Zcu.PerThread) void { |
| 3085 | + const comp = pt.zcu.comp; |
| 3086 | + if (comp.bin_file) |lf| lf.updateErrorData(pt) catch |err| switch (err) { |
| 3087 | + error.OutOfMemory => comp.link_diags.setAllocFailure(), |
| 3088 | + error.LinkFailure => {}, |
| 3089 | + }; |
| 3090 | +} |
| 3091 | |
| 3092 | /// Provided by the CLI, processed into `LinkInput` instances at the start of |
| 3093 | /// the compilation pipeline. |
| 3094 | diff --git a/src/link/Coff.zig b/src/link/Coff.zig |
| 3095 | index e016473531..f3e3b3d0b5 100644 |
| 3096 | --- a/src/link/Coff.zig |
| 3097 | +++ b/src/link/Coff.zig |
| 3098 | @@ -953,7 +953,7 @@ fn writeOffsetTableEntry(coff: *Coff, index: usize) !void { |
| 3099 | } |
| 3100 | |
| 3101 | fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { |
| 3102 | - if (!coff.base.comp.incremental) return; |
| 3103 | + if (!coff.base.comp.config.incremental) return; |
| 3104 | // TODO: reverse-lookup might come in handy here |
| 3105 | for (coff.relocs.values()) |*relocs| { |
| 3106 | for (relocs.items) |*reloc| { |
| 3107 | @@ -964,7 +964,7 @@ fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { |
| 3108 | } |
| 3109 | |
| 3110 | fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void { |
| 3111 | - if (!coff.base.comp.incremental) return; |
| 3112 | + if (!coff.base.comp.config.incremental) return; |
| 3113 | const got_moved = blk: { |
| 3114 | const sect_id = coff.got_section_index orelse break :blk false; |
| 3115 | break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr; |
| 3116 | @@ -1111,20 +1111,24 @@ pub fn updateFunc( |
| 3117 | |
| 3118 | coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?; |
| 3119 | |
| 3120 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3121 | - defer code_buffer.deinit(gpa); |
| 3122 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3123 | + defer aw.deinit(); |
| 3124 | |
| 3125 | - try codegen.emitFunction( |
| 3126 | + codegen.emitFunction( |
| 3127 | &coff.base, |
| 3128 | pt, |
| 3129 | zcu.navSrcLoc(nav_index), |
| 3130 | func_index, |
| 3131 | + coff.getAtom(atom_index).getSymbolIndex().?, |
| 3132 | mir, |
| 3133 | - &code_buffer, |
| 3134 | + &aw.writer, |
| 3135 | .none, |
| 3136 | - ); |
| 3137 | + ) catch |err| switch (err) { |
| 3138 | + error.WriteFailed => return error.OutOfMemory, |
| 3139 | + else => |e| return e, |
| 3140 | + }; |
| 3141 | |
| 3142 | - try coff.updateNavCode(pt, nav_index, code_buffer.items, .FUNCTION); |
| 3143 | + try coff.updateNavCode(pt, nav_index, aw.written(), .FUNCTION); |
| 3144 | |
| 3145 | // Exports will be updated by `Zcu.processExports` after the update. |
| 3146 | } |
| 3147 | @@ -1145,18 +1149,18 @@ fn lowerConst( |
| 3148 | ) !LowerConstResult { |
| 3149 | const gpa = coff.base.comp.gpa; |
| 3150 | |
| 3151 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3152 | - defer code_buffer.deinit(gpa); |
| 3153 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3154 | + defer aw.deinit(); |
| 3155 | |
| 3156 | const atom_index = try coff.createAtom(); |
| 3157 | const sym = coff.getAtom(atom_index).getSymbolPtr(coff); |
| 3158 | try coff.setSymbolName(sym, name); |
| 3159 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1)); |
| 3160 | |
| 3161 | - try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{ |
| 3162 | + try codegen.generateSymbol(&coff.base, pt, src_loc, val, &aw.writer, .{ |
| 3163 | .atom_index = coff.getAtom(atom_index).getSymbolIndex().?, |
| 3164 | }); |
| 3165 | - const code = code_buffer.items; |
| 3166 | + const code = aw.written(); |
| 3167 | |
| 3168 | const atom = coff.getAtomPtr(atom_index); |
| 3169 | atom.size = @intCast(code.len); |
| 3170 | @@ -1170,7 +1174,7 @@ fn lowerConst( |
| 3171 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value }); |
| 3172 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 3173 | |
| 3174 | - try coff.writeAtom(atom_index, code, coff.base.comp.incremental); |
| 3175 | + try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental); |
| 3176 | |
| 3177 | return .{ .ok = atom_index }; |
| 3178 | } |
| 3179 | @@ -1214,19 +1218,22 @@ pub fn updateNav( |
| 3180 | |
| 3181 | coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index); |
| 3182 | |
| 3183 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3184 | - defer code_buffer.deinit(gpa); |
| 3185 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3186 | + defer aw.deinit(); |
| 3187 | |
| 3188 | - try codegen.generateSymbol( |
| 3189 | + codegen.generateSymbol( |
| 3190 | &coff.base, |
| 3191 | pt, |
| 3192 | zcu.navSrcLoc(nav_index), |
| 3193 | nav_init, |
| 3194 | - &code_buffer, |
| 3195 | + &aw.writer, |
| 3196 | .{ .atom_index = atom.getSymbolIndex().? }, |
| 3197 | - ); |
| 3198 | + ) catch |err| switch (err) { |
| 3199 | + error.WriteFailed => return error.OutOfMemory, |
| 3200 | + else => |e| return e, |
| 3201 | + }; |
| 3202 | |
| 3203 | - try coff.updateNavCode(pt, nav_index, code_buffer.items, .NULL); |
| 3204 | + try coff.updateNavCode(pt, nav_index, aw.written(), .NULL); |
| 3205 | } |
| 3206 | |
| 3207 | // Exports will be updated by `Zcu.processExports` after the update. |
| 3208 | @@ -1244,8 +1251,8 @@ fn updateLazySymbolAtom( |
| 3209 | const gpa = comp.gpa; |
| 3210 | |
| 3211 | var required_alignment: InternPool.Alignment = .none; |
| 3212 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3213 | - defer code_buffer.deinit(gpa); |
| 3214 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3215 | + defer aw.deinit(); |
| 3216 | |
| 3217 | const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| 3218 | @tagName(sym.kind), |
| 3219 | @@ -1262,11 +1269,11 @@ fn updateLazySymbolAtom( |
| 3220 | src, |
| 3221 | sym, |
| 3222 | &required_alignment, |
| 3223 | - &code_buffer, |
| 3224 | + &aw.writer, |
| 3225 | .none, |
| 3226 | .{ .atom_index = local_sym_index }, |
| 3227 | ); |
| 3228 | - const code = code_buffer.items; |
| 3229 | + const code = aw.written(); |
| 3230 | |
| 3231 | const atom = coff.getAtomPtr(atom_index); |
| 3232 | const symbol = atom.getSymbolPtr(coff); |
| 3233 | @@ -1285,7 +1292,7 @@ fn updateLazySymbolAtom( |
| 3234 | symbol.value = vaddr; |
| 3235 | |
| 3236 | try coff.addGotEntry(.{ .sym_index = local_sym_index }); |
| 3237 | - try coff.writeAtom(atom_index, code, coff.base.comp.incremental); |
| 3238 | + try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental); |
| 3239 | } |
| 3240 | |
| 3241 | pub fn getOrCreateAtomForLazySymbol( |
| 3242 | @@ -1437,7 +1444,7 @@ fn updateNavCode( |
| 3243 | }; |
| 3244 | } |
| 3245 | |
| 3246 | - coff.writeAtom(atom_index, code, coff.base.comp.incremental) catch |err| switch (err) { |
| 3247 | + coff.writeAtom(atom_index, code, coff.base.comp.config.incremental) catch |err| switch (err) { |
| 3248 | error.OutOfMemory => return error.OutOfMemory, |
| 3249 | else => |e| return coff.base.cgFail(nav_index, "failed to write atom: {s}", .{@errorName(e)}), |
| 3250 | }; |
| 3251 | @@ -1539,14 +1546,12 @@ pub fn updateExports( |
| 3252 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1)); |
| 3253 | sym.type = atom.getSymbol(coff).type; |
| 3254 | |
| 3255 | - switch (exp.opts.linkage) { |
| 3256 | - .strong => { |
| 3257 | - sym.storage_class = .EXTERNAL; |
| 3258 | - }, |
| 3259 | - .internal => @panic("TODO Internal"), |
| 3260 | + sym.storage_class = switch (exp.opts.linkage) { |
| 3261 | + .internal => .EXTERNAL, |
| 3262 | + .strong => .EXTERNAL, |
| 3263 | .weak => @panic("TODO WeakExternal"), |
| 3264 | else => unreachable, |
| 3265 | - } |
| 3266 | + }; |
| 3267 | |
| 3268 | try coff.resolveGlobalSymbol(sym_loc); |
| 3269 | } |
| 3270 | diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig |
| 3271 | index f4af5f4148..595e3583d5 100644 |
| 3272 | --- a/src/link/Dwarf.zig |
| 3273 | +++ b/src/link/Dwarf.zig |
| 3274 | @@ -2126,19 +2126,22 @@ pub const WipNav = struct { |
| 3275 | const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0; |
| 3276 | try diw.writeUleb128(size); |
| 3277 | if (size == 0) return; |
| 3278 | - var bytes = wip_nav.debug_info.toArrayList(); |
| 3279 | - defer wip_nav.debug_info = .fromArrayList(wip_nav.dwarf.gpa, &bytes); |
| 3280 | - const old_len = bytes.items.len; |
| 3281 | + const old_end = wip_nav.debug_info.writer.end; |
| 3282 | try codegen.generateSymbol( |
| 3283 | wip_nav.dwarf.bin_file, |
| 3284 | wip_nav.pt, |
| 3285 | src_loc, |
| 3286 | val, |
| 3287 | - &bytes, |
| 3288 | + &wip_nav.debug_info.writer, |
| 3289 | .{ .debug_output = .{ .dwarf = wip_nav } }, |
| 3290 | ); |
| 3291 | - if (old_len + size != bytes.items.len) { |
| 3292 | - std.debug.print("{f} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), size, bytes.items.len - old_len }); |
| 3293 | + if (old_end + size != wip_nav.debug_info.writer.end) { |
| 3294 | + std.debug.print("{f} [{}]: {} != {}\n", .{ |
| 3295 | + ty.fmt(wip_nav.pt), |
| 3296 | + ty.toIntern(), |
| 3297 | + size, |
| 3298 | + wip_nav.debug_info.writer.end - old_end, |
| 3299 | + }); |
| 3300 | unreachable; |
| 3301 | } |
| 3302 | } |
| 3303 | @@ -6429,7 +6432,7 @@ fn sleb128Bytes(value: anytype) u32 { |
| 3304 | /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional |
| 3305 | const force_incremental = false; |
| 3306 | inline fn incremental(dwarf: Dwarf) bool { |
| 3307 | - return force_incremental or dwarf.bin_file.comp.incremental; |
| 3308 | + return force_incremental or dwarf.bin_file.comp.config.incremental; |
| 3309 | } |
| 3310 | |
| 3311 | const Allocator = std.mem.Allocator; |
| 3312 | diff --git a/src/link/Elf/LinkerDefined.zig b/src/link/Elf/LinkerDefined.zig |
| 3313 | index b74406c368..d7e3cf62f3 100644 |
| 3314 | --- a/src/link/Elf/LinkerDefined.zig |
| 3315 | +++ b/src/link/Elf/LinkerDefined.zig |
| 3316 | @@ -47,7 +47,7 @@ fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) |
| 3317 | const esym = self.symtab.addOneAssumeCapacity(); |
| 3318 | esym.* = .{ |
| 3319 | .st_name = name_off, |
| 3320 | - .st_info = elf.STB_WEAK << 4, |
| 3321 | + .st_info = @as(u8, elf.STB_WEAK) << 4, |
| 3322 | .st_other = @intFromEnum(elf.STV.HIDDEN), |
| 3323 | .st_shndx = elf.SHN_ABS, |
| 3324 | .st_value = 0, |
| 3325 | diff --git a/src/link/Elf/SharedObject.zig b/src/link/Elf/SharedObject.zig |
| 3326 | index 8c79def16b..4dce40e370 100644 |
| 3327 | --- a/src/link/Elf/SharedObject.zig |
| 3328 | +++ b/src/link/Elf/SharedObject.zig |
| 3329 | @@ -105,7 +105,7 @@ pub fn parseHeader( |
| 3330 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 3331 | } |
| 3332 | if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic; |
| 3333 | - if (ehdr.e_ident[elf.EI_VERSION] != 1) return error.BadElfVersion; |
| 3334 | + if (ehdr.e_ident[elf.EI.VERSION] != 1) return error.BadElfVersion; |
| 3335 | if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject; |
| 3336 | |
| 3337 | if (target.toElfMachine() != ehdr.e_machine) |
| 3338 | diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig |
| 3339 | index bf65d04e4a..a3ede11dc4 100644 |
| 3340 | --- a/src/link/Elf/ZigObject.zig |
| 3341 | +++ b/src/link/Elf/ZigObject.zig |
| 3342 | @@ -277,8 +277,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { |
| 3343 | pt, |
| 3344 | .{ .kind = .code, .ty = .anyerror_type }, |
| 3345 | metadata.text_symbol_index, |
| 3346 | - ) catch |err| return switch (err) { |
| 3347 | - error.CodegenFail => error.LinkFailure, |
| 3348 | + ) catch |err| switch (err) { |
| 3349 | + error.CodegenFail => return error.LinkFailure, |
| 3350 | else => |e| return e, |
| 3351 | }; |
| 3352 | if (metadata.rodata_state != .unused) self.updateLazySymbol( |
| 3353 | @@ -286,8 +286,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { |
| 3354 | pt, |
| 3355 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 3356 | metadata.rodata_symbol_index, |
| 3357 | - ) catch |err| return switch (err) { |
| 3358 | - error.CodegenFail => error.LinkFailure, |
| 3359 | + ) catch |err| switch (err) { |
| 3360 | + error.CodegenFail => return error.LinkFailure, |
| 3361 | else => |e| return e, |
| 3362 | }; |
| 3363 | } |
| 3364 | @@ -1533,22 +1533,26 @@ pub fn updateFunc( |
| 3365 | const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav); |
| 3366 | self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self); |
| 3367 | |
| 3368 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3369 | - defer code_buffer.deinit(gpa); |
| 3370 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3371 | + defer aw.deinit(); |
| 3372 | |
| 3373 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; |
| 3374 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 3375 | |
| 3376 | - try codegen.emitFunction( |
| 3377 | + codegen.emitFunction( |
| 3378 | &elf_file.base, |
| 3379 | pt, |
| 3380 | zcu.navSrcLoc(func.owner_nav), |
| 3381 | func_index, |
| 3382 | + sym_index, |
| 3383 | mir, |
| 3384 | - &code_buffer, |
| 3385 | + &aw.writer, |
| 3386 | if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none, |
| 3387 | - ); |
| 3388 | - const code = code_buffer.items; |
| 3389 | + ) catch |err| switch (err) { |
| 3390 | + error.WriteFailed => return error.OutOfMemory, |
| 3391 | + else => |e| return e, |
| 3392 | + }; |
| 3393 | + const code = aw.written(); |
| 3394 | |
| 3395 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); |
| 3396 | log.debug("setting shdr({x},{s}) for {f}", .{ |
| 3397 | @@ -1663,21 +1667,24 @@ pub fn updateNav( |
| 3398 | const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index); |
| 3399 | self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); |
| 3400 | |
| 3401 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3402 | - defer code_buffer.deinit(zcu.gpa); |
| 3403 | + var aw: std.Io.Writer.Allocating = .init(zcu.gpa); |
| 3404 | + defer aw.deinit(); |
| 3405 | |
| 3406 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; |
| 3407 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 3408 | |
| 3409 | - try codegen.generateSymbol( |
| 3410 | + codegen.generateSymbol( |
| 3411 | &elf_file.base, |
| 3412 | pt, |
| 3413 | zcu.navSrcLoc(nav_index), |
| 3414 | Value.fromInterned(nav_init), |
| 3415 | - &code_buffer, |
| 3416 | + &aw.writer, |
| 3417 | .{ .atom_index = sym_index }, |
| 3418 | - ); |
| 3419 | - const code = code_buffer.items; |
| 3420 | + ) catch |err| switch (err) { |
| 3421 | + error.WriteFailed => return error.OutOfMemory, |
| 3422 | + else => |e| return e, |
| 3423 | + }; |
| 3424 | + const code = aw.written(); |
| 3425 | |
| 3426 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); |
| 3427 | log.debug("setting shdr({x},{s}) for {f}", .{ |
| 3428 | @@ -1722,8 +1729,8 @@ fn updateLazySymbol( |
| 3429 | const gpa = zcu.gpa; |
| 3430 | |
| 3431 | var required_alignment: InternPool.Alignment = .none; |
| 3432 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3433 | - defer code_buffer.deinit(gpa); |
| 3434 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3435 | + defer aw.deinit(); |
| 3436 | |
| 3437 | const name_str_index = blk: { |
| 3438 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| 3439 | @@ -1734,18 +1741,20 @@ fn updateLazySymbol( |
| 3440 | break :blk try self.strtab.insert(gpa, name); |
| 3441 | }; |
| 3442 | |
| 3443 | - const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded; |
| 3444 | - try codegen.generateLazySymbol( |
| 3445 | + codegen.generateLazySymbol( |
| 3446 | &elf_file.base, |
| 3447 | pt, |
| 3448 | - src, |
| 3449 | + Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse .unneeded, |
| 3450 | sym, |
| 3451 | &required_alignment, |
| 3452 | - &code_buffer, |
| 3453 | + &aw.writer, |
| 3454 | .none, |
| 3455 | .{ .atom_index = symbol_index }, |
| 3456 | - ); |
| 3457 | - const code = code_buffer.items; |
| 3458 | + ) catch |err| switch (err) { |
| 3459 | + error.WriteFailed => return error.OutOfMemory, |
| 3460 | + else => |e| return e, |
| 3461 | + }; |
| 3462 | + const code = aw.written(); |
| 3463 | |
| 3464 | const output_section_index = switch (sym.kind) { |
| 3465 | .code => if (self.text_index) |sym_index| |
| 3466 | @@ -1807,21 +1816,24 @@ fn lowerConst( |
| 3467 | ) !codegen.SymbolResult { |
| 3468 | const gpa = pt.zcu.gpa; |
| 3469 | |
| 3470 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 3471 | - defer code_buffer.deinit(gpa); |
| 3472 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 3473 | + defer aw.deinit(); |
| 3474 | |
| 3475 | const name_off = try self.addString(gpa, name); |
| 3476 | const sym_index = try self.newSymbolWithAtom(gpa, name_off); |
| 3477 | |
| 3478 | - try codegen.generateSymbol( |
| 3479 | + codegen.generateSymbol( |
| 3480 | &elf_file.base, |
| 3481 | pt, |
| 3482 | src_loc, |
| 3483 | val, |
| 3484 | - &code_buffer, |
| 3485 | + &aw.writer, |
| 3486 | .{ .atom_index = sym_index }, |
| 3487 | - ); |
| 3488 | - const code = code_buffer.items; |
| 3489 | + ) catch |err| switch (err) { |
| 3490 | + error.WriteFailed => return error.OutOfMemory, |
| 3491 | + else => |e| return e, |
| 3492 | + }; |
| 3493 | + const code = aw.written(); |
| 3494 | |
| 3495 | const local_sym = self.symbol(sym_index); |
| 3496 | const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; |
| 3497 | diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig |
| 3498 | new file mode 100644 |
| 3499 | index 0000000000..e43ebf2639 |
| 3500 | --- /dev/null |
| 3501 | +++ b/src/link/Elf2.zig |
| 3502 | @@ -0,0 +1,2036 @@ |
| 3503 | +base: link.File, |
| 3504 | +mf: MappedFile, |
| 3505 | +nodes: std.MultiArrayList(Node), |
| 3506 | +symtab: std.ArrayList(Symbol), |
| 3507 | +shstrtab: StringTable, |
| 3508 | +strtab: StringTable, |
| 3509 | +globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| 3510 | +navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), |
| 3511 | +uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| 3512 | +lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 3513 | + map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| 3514 | + pending_index: u32, |
| 3515 | +}), |
| 3516 | +pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { |
| 3517 | + alignment: InternPool.Alignment, |
| 3518 | + src_loc: Zcu.LazySrcLoc, |
| 3519 | +}), |
| 3520 | +relocs: std.ArrayList(Reloc), |
| 3521 | +/// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. |
| 3522 | +entry_hack: Symbol.Index, |
| 3523 | + |
| 3524 | +pub const Node = union(enum) { |
| 3525 | + file, |
| 3526 | + ehdr, |
| 3527 | + shdr, |
| 3528 | + segment: u32, |
| 3529 | + section: Symbol.Index, |
| 3530 | + nav: InternPool.Nav.Index, |
| 3531 | + uav: InternPool.Index, |
| 3532 | + lazy_code: InternPool.Index, |
| 3533 | + lazy_const_data: InternPool.Index, |
| 3534 | + |
| 3535 | + pub const Tag = @typeInfo(Node).@"union".tag_type.?; |
| 3536 | + |
| 3537 | + const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; |
| 3538 | + const known = known: { |
| 3539 | + const Known = enum { |
| 3540 | + file, |
| 3541 | + seg_rodata, |
| 3542 | + ehdr, |
| 3543 | + phdr, |
| 3544 | + shdr, |
| 3545 | + seg_text, |
| 3546 | + seg_data, |
| 3547 | + }; |
| 3548 | + var mut_known: std.enums.EnumFieldStruct( |
| 3549 | + Known, |
| 3550 | + MappedFile.Node.Index, |
| 3551 | + null, |
| 3552 | + ) = undefined; |
| 3553 | + for (@typeInfo(Known).@"enum".fields) |field| |
| 3554 | + @field(mut_known, field.name) = @enumFromInt(field.value); |
| 3555 | + break :known mut_known; |
| 3556 | + }; |
| 3557 | + |
| 3558 | + comptime { |
| 3559 | + if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); |
| 3560 | + } |
| 3561 | +}; |
| 3562 | + |
| 3563 | +pub const StringTable = struct { |
| 3564 | + map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), |
| 3565 | + size: u32, |
| 3566 | + |
| 3567 | + const Context = struct { |
| 3568 | + slice: []const u8, |
| 3569 | + |
| 3570 | + pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool { |
| 3571 | + return lhs_key == rhs_key; |
| 3572 | + } |
| 3573 | + |
| 3574 | + pub fn hash(ctx: Context, key: u32) u64 { |
| 3575 | + return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0)); |
| 3576 | + } |
| 3577 | + }; |
| 3578 | + |
| 3579 | + const Adapter = struct { |
| 3580 | + slice: []const u8, |
| 3581 | + |
| 3582 | + pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool { |
| 3583 | + return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and |
| 3584 | + adapter.slice[rhs_key + lhs_key.len] == 0; |
| 3585 | + } |
| 3586 | + |
| 3587 | + pub fn hash(_: Adapter, key: []const u8) u64 { |
| 3588 | + assert(std.mem.indexOfScalar(u8, key, 0) == null); |
| 3589 | + return std.hash_map.hashString(key); |
| 3590 | + } |
| 3591 | + }; |
| 3592 | + |
| 3593 | + pub fn get( |
| 3594 | + st: *StringTable, |
| 3595 | + gpa: std.mem.Allocator, |
| 3596 | + mf: *MappedFile, |
| 3597 | + ni: MappedFile.Node.Index, |
| 3598 | + key: []const u8, |
| 3599 | + ) !u32 { |
| 3600 | + const slice_const = ni.sliceConst(mf); |
| 3601 | + const gop = try st.map.getOrPutContextAdapted( |
| 3602 | + gpa, |
| 3603 | + key, |
| 3604 | + StringTable.Adapter{ .slice = slice_const }, |
| 3605 | + .{ .slice = slice_const }, |
| 3606 | + ); |
| 3607 | + if (gop.found_existing) return gop.key_ptr.*; |
| 3608 | + const old_size = st.size; |
| 3609 | + const new_size: u32 = @intCast(old_size + key.len + 1); |
| 3610 | + st.size = new_size; |
| 3611 | + try ni.resize(mf, gpa, new_size); |
| 3612 | + const slice = ni.slice(mf)[old_size..]; |
| 3613 | + @memcpy(slice[0..key.len], key); |
| 3614 | + slice[key.len] = 0; |
| 3615 | + gop.key_ptr.* = old_size; |
| 3616 | + return old_size; |
| 3617 | + } |
| 3618 | +}; |
| 3619 | + |
| 3620 | +pub const Symbol = struct { |
| 3621 | + ni: MappedFile.Node.Index, |
| 3622 | + /// Relocations contained within this symbol |
| 3623 | + loc_relocs: Reloc.Index, |
| 3624 | + /// Relocations targeting this symbol |
| 3625 | + target_relocs: Reloc.Index, |
| 3626 | + unused: u32 = 0, |
| 3627 | + |
| 3628 | + pub const Index = enum(u32) { |
| 3629 | + null, |
| 3630 | + symtab, |
| 3631 | + shstrtab, |
| 3632 | + strtab, |
| 3633 | + rodata, |
| 3634 | + text, |
| 3635 | + data, |
| 3636 | + tdata, |
| 3637 | + _, |
| 3638 | + |
| 3639 | + pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { |
| 3640 | + return &elf.symtab.items[@intFromEnum(si)]; |
| 3641 | + } |
| 3642 | + |
| 3643 | + pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index { |
| 3644 | + const ni = si.get(elf).ni; |
| 3645 | + assert(ni != .none); |
| 3646 | + return ni; |
| 3647 | + } |
| 3648 | + |
| 3649 | + pub const InitOptions = struct { |
| 3650 | + name: []const u8 = "", |
| 3651 | + size: std.elf.Word = 0, |
| 3652 | + type: std.elf.STT, |
| 3653 | + bind: std.elf.STB = .LOCAL, |
| 3654 | + visibility: std.elf.STV = .DEFAULT, |
| 3655 | + shndx: std.elf.Section = std.elf.SHN_UNDEF, |
| 3656 | + }; |
| 3657 | + pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { |
| 3658 | + const name_entry = try elf.string(.strtab, opts.name); |
| 3659 | + try Symbol.Index.symtab.node(elf).resize( |
| 3660 | + &elf.mf, |
| 3661 | + elf.base.comp.gpa, |
| 3662 | + @as(usize, switch (elf.identClass()) { |
| 3663 | + .NONE, _ => unreachable, |
| 3664 | + .@"32" => @sizeOf(std.elf.Elf32.Sym), |
| 3665 | + .@"64" => @sizeOf(std.elf.Elf64.Sym), |
| 3666 | + }) * elf.symtab.items.len, |
| 3667 | + ); |
| 3668 | + switch (elf.symPtr(si)) { |
| 3669 | + inline else => |sym| sym.* = .{ |
| 3670 | + .name = name_entry, |
| 3671 | + .value = 0, |
| 3672 | + .size = opts.size, |
| 3673 | + .info = .{ |
| 3674 | + .type = opts.type, |
| 3675 | + .bind = opts.bind, |
| 3676 | + }, |
| 3677 | + .other = .{ |
| 3678 | + .visibility = opts.visibility, |
| 3679 | + }, |
| 3680 | + .shndx = opts.shndx, |
| 3681 | + }, |
| 3682 | + } |
| 3683 | + } |
| 3684 | + |
| 3685 | + pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 3686 | + for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { |
| 3687 | + if (reloc.loc != si) break; |
| 3688 | + reloc.apply(elf); |
| 3689 | + } |
| 3690 | + } |
| 3691 | + |
| 3692 | + pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void { |
| 3693 | + var ri = si.get(elf).target_relocs; |
| 3694 | + while (ri != .none) { |
| 3695 | + const reloc = ri.get(elf); |
| 3696 | + assert(reloc.target == si); |
| 3697 | + reloc.apply(elf); |
| 3698 | + ri = reloc.next; |
| 3699 | + } |
| 3700 | + } |
| 3701 | + |
| 3702 | + pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 3703 | + const sym = si.get(elf); |
| 3704 | + for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { |
| 3705 | + if (reloc.loc != si) break; |
| 3706 | + reloc.delete(elf); |
| 3707 | + } |
| 3708 | + sym.loc_relocs = .none; |
| 3709 | + } |
| 3710 | + }; |
| 3711 | + |
| 3712 | + comptime { |
| 3713 | + if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); |
| 3714 | + } |
| 3715 | +}; |
| 3716 | + |
| 3717 | +pub const Reloc = extern struct { |
| 3718 | + type: Reloc.Type, |
| 3719 | + prev: Reloc.Index, |
| 3720 | + next: Reloc.Index, |
| 3721 | + loc: Symbol.Index, |
| 3722 | + target: Symbol.Index, |
| 3723 | + unused: u32, |
| 3724 | + offset: u64, |
| 3725 | + addend: i64, |
| 3726 | + |
| 3727 | + pub const Type = extern union { |
| 3728 | + x86_64: std.elf.R_X86_64, |
| 3729 | + aarch64: std.elf.R_AARCH64, |
| 3730 | + riscv: std.elf.R_RISCV, |
| 3731 | + ppc64: std.elf.R_PPC64, |
| 3732 | + }; |
| 3733 | + |
| 3734 | + pub const Index = enum(u32) { |
| 3735 | + none = std.math.maxInt(u32), |
| 3736 | + _, |
| 3737 | + |
| 3738 | + pub fn get(si: Reloc.Index, elf: *Elf) *Reloc { |
| 3739 | + return &elf.relocs.items[@intFromEnum(si)]; |
| 3740 | + } |
| 3741 | + }; |
| 3742 | + |
| 3743 | + pub fn apply(reloc: *const Reloc, elf: *Elf) void { |
| 3744 | + const target_endian = elf.endian(); |
| 3745 | + switch (reloc.loc.get(elf).ni) { |
| 3746 | + .none => return, |
| 3747 | + else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 3748 | + } |
| 3749 | + switch (reloc.target.get(elf).ni) { |
| 3750 | + .none => return, |
| 3751 | + else => |ni| if (ni.hasMoved(&elf.mf)) return, |
| 3752 | + } |
| 3753 | + switch (elf.shdrSlice()) { |
| 3754 | + inline else => |shdr, class| { |
| 3755 | + const sym = @field(elf.symSlice(), @tagName(class)); |
| 3756 | + const loc_sym = &sym[@intFromEnum(reloc.loc)]; |
| 3757 | + const loc_shndx = |
| 3758 | + std.mem.toNative(@TypeOf(loc_sym.shndx), loc_sym.shndx, target_endian); |
| 3759 | + assert(loc_shndx != std.elf.SHN_UNDEF); |
| 3760 | + const loc_sh = &shdr[loc_shndx]; |
| 3761 | + const loc_value = std.mem.toNative( |
| 3762 | + @TypeOf(loc_sym.value), |
| 3763 | + loc_sym.value, |
| 3764 | + target_endian, |
| 3765 | + ) + reloc.offset; |
| 3766 | + const loc_sh_addr = |
| 3767 | + std.mem.toNative(@TypeOf(loc_sh.addr), loc_sh.addr, target_endian); |
| 3768 | + const loc_sh_offset = |
| 3769 | + std.mem.toNative(@TypeOf(loc_sh.offset), loc_sh.offset, target_endian); |
| 3770 | + const loc_file_offset: usize = @intCast(loc_value - loc_sh_addr + loc_sh_offset); |
| 3771 | + const target_sym = &sym[@intFromEnum(reloc.target)]; |
| 3772 | + const target_value = std.mem.toNative( |
| 3773 | + @TypeOf(target_sym.value), |
| 3774 | + target_sym.value, |
| 3775 | + target_endian, |
| 3776 | + ) +% @as(u64, @bitCast(reloc.addend)); |
| 3777 | + switch (elf.ehdrField(.machine)) { |
| 3778 | + else => |machine| @panic(@tagName(machine)), |
| 3779 | + .X86_64 => switch (reloc.type.x86_64) { |
| 3780 | + else => |kind| @panic(@tagName(kind)), |
| 3781 | + .@"64" => std.mem.writeInt( |
| 3782 | + u64, |
| 3783 | + elf.mf.contents[loc_file_offset..][0..8], |
| 3784 | + target_value, |
| 3785 | + target_endian, |
| 3786 | + ), |
| 3787 | + .PC32 => std.mem.writeInt( |
| 3788 | + i32, |
| 3789 | + elf.mf.contents[loc_file_offset..][0..4], |
| 3790 | + @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| 3791 | + target_endian, |
| 3792 | + ), |
| 3793 | + .@"32" => std.mem.writeInt( |
| 3794 | + u32, |
| 3795 | + elf.mf.contents[loc_file_offset..][0..4], |
| 3796 | + @intCast(target_value), |
| 3797 | + target_endian, |
| 3798 | + ), |
| 3799 | + .TPOFF32 => { |
| 3800 | + const phdr = @field(elf.phdrSlice(), @tagName(class)); |
| 3801 | + const ph = &phdr[4]; |
| 3802 | + assert(std.mem.toNative( |
| 3803 | + @TypeOf(ph.type), |
| 3804 | + ph.type, |
| 3805 | + target_endian, |
| 3806 | + ) == std.elf.PT_TLS); |
| 3807 | + std.mem.writeInt( |
| 3808 | + i32, |
| 3809 | + elf.mf.contents[loc_file_offset..][0..4], |
| 3810 | + @intCast(@as(i64, @bitCast(target_value -% std.mem.toNative( |
| 3811 | + @TypeOf(ph.memsz), |
| 3812 | + ph.memsz, |
| 3813 | + target_endian, |
| 3814 | + )))), |
| 3815 | + target_endian, |
| 3816 | + ); |
| 3817 | + }, |
| 3818 | + }, |
| 3819 | + } |
| 3820 | + }, |
| 3821 | + } |
| 3822 | + } |
| 3823 | + |
| 3824 | + pub fn delete(reloc: *Reloc, elf: *Elf) void { |
| 3825 | + switch (reloc.prev) { |
| 3826 | + .none => { |
| 3827 | + const target = reloc.target.get(elf); |
| 3828 | + assert(target.target_relocs.get(elf) == reloc); |
| 3829 | + target.target_relocs = reloc.next; |
| 3830 | + }, |
| 3831 | + else => |prev| prev.get(elf).next = reloc.next, |
| 3832 | + } |
| 3833 | + switch (reloc.next) { |
| 3834 | + .none => {}, |
| 3835 | + else => |next| next.get(elf).prev = reloc.prev, |
| 3836 | + } |
| 3837 | + reloc.* = undefined; |
| 3838 | + } |
| 3839 | + |
| 3840 | + comptime { |
| 3841 | + if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); |
| 3842 | + } |
| 3843 | +}; |
| 3844 | + |
| 3845 | +pub fn open( |
| 3846 | + arena: std.mem.Allocator, |
| 3847 | + comp: *Compilation, |
| 3848 | + path: std.Build.Cache.Path, |
| 3849 | + options: link.File.OpenOptions, |
| 3850 | +) !*Elf { |
| 3851 | + return create(arena, comp, path, options); |
| 3852 | +} |
| 3853 | +pub fn createEmpty( |
| 3854 | + arena: std.mem.Allocator, |
| 3855 | + comp: *Compilation, |
| 3856 | + path: std.Build.Cache.Path, |
| 3857 | + options: link.File.OpenOptions, |
| 3858 | +) !*Elf { |
| 3859 | + return create(arena, comp, path, options); |
| 3860 | +} |
| 3861 | +fn create( |
| 3862 | + arena: std.mem.Allocator, |
| 3863 | + comp: *Compilation, |
| 3864 | + path: std.Build.Cache.Path, |
| 3865 | + options: link.File.OpenOptions, |
| 3866 | +) !*Elf { |
| 3867 | + _ = options; |
| 3868 | + const target = &comp.root_mod.resolved_target.result; |
| 3869 | + assert(target.ofmt == .elf); |
| 3870 | + const class: std.elf.CLASS = switch (target.ptrBitWidth()) { |
| 3871 | + 0...32 => .@"32", |
| 3872 | + 33...64 => .@"64", |
| 3873 | + else => return error.UnsupportedELFArchitecture, |
| 3874 | + }; |
| 3875 | + const data: std.elf.DATA = switch (target.cpu.arch.endian()) { |
| 3876 | + .little => .@"2LSB", |
| 3877 | + .big => .@"2MSB", |
| 3878 | + }; |
| 3879 | + const osabi: std.elf.OSABI = switch (target.os.tag) { |
| 3880 | + else => .NONE, |
| 3881 | + .freestanding, .other => .STANDALONE, |
| 3882 | + .netbsd => .NETBSD, |
| 3883 | + .solaris => .SOLARIS, |
| 3884 | + .aix => .AIX, |
| 3885 | + .freebsd => .FREEBSD, |
| 3886 | + .cuda => .CUDA, |
| 3887 | + .amdhsa => .AMDGPU_HSA, |
| 3888 | + .amdpal => .AMDGPU_PAL, |
| 3889 | + .mesa3d => .AMDGPU_MESA3D, |
| 3890 | + }; |
| 3891 | + const @"type": std.elf.ET = switch (comp.config.output_mode) { |
| 3892 | + .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC, |
| 3893 | + .Lib => switch (comp.config.link_mode) { |
| 3894 | + .static => .REL, |
| 3895 | + .dynamic => .DYN, |
| 3896 | + }, |
| 3897 | + .Obj => .REL, |
| 3898 | + }; |
| 3899 | + const machine: std.elf.EM = switch (target.cpu.arch) { |
| 3900 | + .spirv32, .spirv64, .wasm32, .wasm64 => .NONE, |
| 3901 | + .sparc => .SPARC, |
| 3902 | + .x86 => .@"386", |
| 3903 | + .m68k => .@"68K", |
| 3904 | + .mips, .mipsel, .mips64, .mips64el => .MIPS, |
| 3905 | + .powerpc, .powerpcle => .PPC, |
| 3906 | + .powerpc64, .powerpc64le => .PPC64, |
| 3907 | + .s390x => .S390, |
| 3908 | + .arm, .armeb, .thumb, .thumbeb => .ARM, |
| 3909 | + .hexagon => .SH, |
| 3910 | + .sparc64 => .SPARCV9, |
| 3911 | + .arc => .ARC, |
| 3912 | + .x86_64 => .X86_64, |
| 3913 | + .or1k => .OR1K, |
| 3914 | + .xtensa => .XTENSA, |
| 3915 | + .msp430 => .MSP430, |
| 3916 | + .avr => .AVR, |
| 3917 | + .nvptx, .nvptx64 => .CUDA, |
| 3918 | + .kalimba => .CSR_KALIMBA, |
| 3919 | + .aarch64, .aarch64_be => .AARCH64, |
| 3920 | + .xcore => .XCORE, |
| 3921 | + .amdgcn => .AMDGPU, |
| 3922 | + .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV, |
| 3923 | + .lanai => .LANAI, |
| 3924 | + .bpfel, .bpfeb => .BPF, |
| 3925 | + .ve => .VE, |
| 3926 | + .csky => .CSKY, |
| 3927 | + .loongarch32, .loongarch64 => .LOONGARCH, |
| 3928 | + .propeller => if (target.cpu.has(.propeller, .p2)) .PROPELLER2 else .PROPELLER, |
| 3929 | + }; |
| 3930 | + const maybe_interp = switch (comp.config.output_mode) { |
| 3931 | + .Exe, .Lib => switch (comp.config.link_mode) { |
| 3932 | + .static => null, |
| 3933 | + .dynamic => target.dynamic_linker.get(), |
| 3934 | + }, |
| 3935 | + .Obj => null, |
| 3936 | + }; |
| 3937 | + |
| 3938 | + const elf = try arena.create(Elf); |
| 3939 | + const file = try path.root_dir.handle.createFile(path.sub_path, .{ |
| 3940 | + .read = true, |
| 3941 | + .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), |
| 3942 | + }); |
| 3943 | + errdefer file.close(); |
| 3944 | + elf.* = .{ |
| 3945 | + .base = .{ |
| 3946 | + .tag = .elf2, |
| 3947 | + |
| 3948 | + .comp = comp, |
| 3949 | + .emit = path, |
| 3950 | + |
| 3951 | + .file = file, |
| 3952 | + .gc_sections = false, |
| 3953 | + .print_gc_sections = false, |
| 3954 | + .build_id = .none, |
| 3955 | + .allow_shlib_undefined = false, |
| 3956 | + .stack_size = 0, |
| 3957 | + }, |
| 3958 | + .mf = try .init(file, comp.gpa), |
| 3959 | + .nodes = .empty, |
| 3960 | + .symtab = .empty, |
| 3961 | + .shstrtab = .{ |
| 3962 | + .map = .empty, |
| 3963 | + .size = 1, |
| 3964 | + }, |
| 3965 | + .strtab = .{ |
| 3966 | + .map = .empty, |
| 3967 | + .size = 1, |
| 3968 | + }, |
| 3969 | + .globals = .empty, |
| 3970 | + .navs = .empty, |
| 3971 | + .uavs = .empty, |
| 3972 | + .lazy = .initFill(.{ |
| 3973 | + .map = .empty, |
| 3974 | + .pending_index = 0, |
| 3975 | + }), |
| 3976 | + .pending_uavs = .empty, |
| 3977 | + .relocs = .empty, |
| 3978 | + .entry_hack = .null, |
| 3979 | + }; |
| 3980 | + errdefer elf.deinit(); |
| 3981 | + |
| 3982 | + switch (class) { |
| 3983 | + .NONE, _ => unreachable, |
| 3984 | + inline .@"32", .@"64" => |ct_class| try elf.initHeaders( |
| 3985 | + ct_class, |
| 3986 | + data, |
| 3987 | + osabi, |
| 3988 | + @"type", |
| 3989 | + machine, |
| 3990 | + maybe_interp, |
| 3991 | + ), |
| 3992 | + } |
| 3993 | + |
| 3994 | + return elf; |
| 3995 | +} |
| 3996 | + |
| 3997 | +pub fn deinit(elf: *Elf) void { |
| 3998 | + const gpa = elf.base.comp.gpa; |
| 3999 | + elf.mf.deinit(gpa); |
| 4000 | + elf.nodes.deinit(gpa); |
| 4001 | + elf.symtab.deinit(gpa); |
| 4002 | + elf.shstrtab.map.deinit(gpa); |
| 4003 | + elf.strtab.map.deinit(gpa); |
| 4004 | + elf.globals.deinit(gpa); |
| 4005 | + elf.navs.deinit(gpa); |
| 4006 | + elf.uavs.deinit(gpa); |
| 4007 | + for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| 4008 | + elf.pending_uavs.deinit(gpa); |
| 4009 | + elf.relocs.deinit(gpa); |
| 4010 | + elf.* = undefined; |
| 4011 | +} |
| 4012 | + |
| 4013 | +fn initHeaders( |
| 4014 | + elf: *Elf, |
| 4015 | + comptime class: std.elf.CLASS, |
| 4016 | + data: std.elf.DATA, |
| 4017 | + osabi: std.elf.OSABI, |
| 4018 | + @"type": std.elf.ET, |
| 4019 | + machine: std.elf.EM, |
| 4020 | + maybe_interp: ?[]const u8, |
| 4021 | +) !void { |
| 4022 | + const comp = elf.base.comp; |
| 4023 | + const gpa = comp.gpa; |
| 4024 | + const ElfN = switch (class) { |
| 4025 | + .NONE, _ => comptime unreachable, |
| 4026 | + .@"32" => std.elf.Elf32, |
| 4027 | + .@"64" => std.elf.Elf64, |
| 4028 | + }; |
| 4029 | + const addr_align: std.mem.Alignment = comptime .fromByteUnits(@sizeOf(ElfN.Addr)); |
| 4030 | + const target_endian: std.builtin.Endian = switch (data) { |
| 4031 | + .NONE, _ => unreachable, |
| 4032 | + .@"2LSB" => .little, |
| 4033 | + .@"2MSB" => .big, |
| 4034 | + }; |
| 4035 | + |
| 4036 | + var phnum: u32 = 0; |
| 4037 | + const phdr_phndx = phnum; |
| 4038 | + phnum += 1; |
| 4039 | + const interp_phndx = if (maybe_interp) |_| phndx: { |
| 4040 | + defer phnum += 1; |
| 4041 | + break :phndx phnum; |
| 4042 | + } else undefined; |
| 4043 | + const rodata_phndx = phnum; |
| 4044 | + phnum += 1; |
| 4045 | + const text_phndx = phnum; |
| 4046 | + phnum += 1; |
| 4047 | + const data_phndx = phnum; |
| 4048 | + phnum += 1; |
| 4049 | + const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { |
| 4050 | + defer phnum += 1; |
| 4051 | + break :phndx phnum; |
| 4052 | + } else undefined; |
| 4053 | + |
| 4054 | + try elf.nodes.ensureTotalCapacity(gpa, Node.known_count); |
| 4055 | + elf.nodes.appendAssumeCapacity(.file); |
| 4056 | + |
| 4057 | + const seg_rodata_ni = Node.known.seg_rodata; |
| 4058 | + assert(seg_rodata_ni == try elf.mf.addOnlyChildNode(gpa, .root, .{ |
| 4059 | + .alignment = elf.mf.flags.block_size, |
| 4060 | + .fixed = true, |
| 4061 | + .moved = true, |
| 4062 | + })); |
| 4063 | + elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); |
| 4064 | + |
| 4065 | + const ehdr_ni = Node.known.ehdr; |
| 4066 | + assert(ehdr_ni == try elf.mf.addOnlyChildNode(gpa, seg_rodata_ni, .{ |
| 4067 | + .size = @sizeOf(ElfN.Ehdr), |
| 4068 | + .alignment = addr_align, |
| 4069 | + .fixed = true, |
| 4070 | + })); |
| 4071 | + elf.nodes.appendAssumeCapacity(.ehdr); |
| 4072 | + |
| 4073 | + const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); |
| 4074 | + const EI = std.elf.EI; |
| 4075 | + @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); |
| 4076 | + ehdr.ident[EI.CLASS] = @intFromEnum(class); |
| 4077 | + ehdr.ident[EI.DATA] = @intFromEnum(data); |
| 4078 | + ehdr.ident[EI.VERSION] = 1; |
| 4079 | + ehdr.ident[EI.OSABI] = @intFromEnum(osabi); |
| 4080 | + ehdr.ident[EI.ABIVERSION] = 0; |
| 4081 | + @memset(ehdr.ident[EI.PAD..], 0); |
| 4082 | + ehdr.type = @"type"; |
| 4083 | + ehdr.machine = machine; |
| 4084 | + ehdr.version = 1; |
| 4085 | + ehdr.entry = 0; |
| 4086 | + ehdr.phoff = 0; |
| 4087 | + ehdr.shoff = 0; |
| 4088 | + ehdr.flags = 0; |
| 4089 | + ehdr.ehsize = @sizeOf(ElfN.Ehdr); |
| 4090 | + ehdr.phentsize = @sizeOf(ElfN.Phdr); |
| 4091 | + ehdr.phnum = @min(phnum, std.elf.PN_XNUM); |
| 4092 | + ehdr.shentsize = @sizeOf(ElfN.Shdr); |
| 4093 | + ehdr.shnum = 1; |
| 4094 | + ehdr.shstrndx = 0; |
| 4095 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); |
| 4096 | + |
| 4097 | + const phdr_ni = Node.known.phdr; |
| 4098 | + assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ |
| 4099 | + .size = @sizeOf(ElfN.Phdr) * phnum, |
| 4100 | + .alignment = addr_align, |
| 4101 | + .moved = true, |
| 4102 | + .resized = true, |
| 4103 | + })); |
| 4104 | + elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); |
| 4105 | + |
| 4106 | + const shdr_ni = Node.known.shdr; |
| 4107 | + assert(shdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ |
| 4108 | + .size = @sizeOf(ElfN.Shdr), |
| 4109 | + .alignment = addr_align, |
| 4110 | + })); |
| 4111 | + elf.nodes.appendAssumeCapacity(.shdr); |
| 4112 | + |
| 4113 | + const seg_text_ni = Node.known.seg_text; |
| 4114 | + assert(seg_text_ni == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 4115 | + .alignment = elf.mf.flags.block_size, |
| 4116 | + .moved = true, |
| 4117 | + })); |
| 4118 | + elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); |
| 4119 | + |
| 4120 | + const seg_data_ni = Node.known.seg_data; |
| 4121 | + assert(seg_data_ni == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 4122 | + .alignment = elf.mf.flags.block_size, |
| 4123 | + .moved = true, |
| 4124 | + })); |
| 4125 | + elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); |
| 4126 | + |
| 4127 | + assert(elf.nodes.len == Node.known_count); |
| 4128 | + |
| 4129 | + { |
| 4130 | + const phdr: []ElfN.Phdr = @ptrCast(@alignCast(phdr_ni.slice(&elf.mf))); |
| 4131 | + const ph_phdr = &phdr[phdr_phndx]; |
| 4132 | + ph_phdr.* = .{ |
| 4133 | + .type = std.elf.PT_PHDR, |
| 4134 | + .offset = 0, |
| 4135 | + .vaddr = 0, |
| 4136 | + .paddr = 0, |
| 4137 | + .filesz = 0, |
| 4138 | + .memsz = 0, |
| 4139 | + .flags = .{ .R = true }, |
| 4140 | + .@"align" = @intCast(phdr_ni.alignment(&elf.mf).toByteUnits()), |
| 4141 | + }; |
| 4142 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); |
| 4143 | + |
| 4144 | + if (maybe_interp) |_| { |
| 4145 | + const ph_interp = &phdr[interp_phndx]; |
| 4146 | + ph_interp.* = .{ |
| 4147 | + .type = std.elf.PT_INTERP, |
| 4148 | + .offset = 0, |
| 4149 | + .vaddr = 0, |
| 4150 | + .paddr = 0, |
| 4151 | + .filesz = 0, |
| 4152 | + .memsz = 0, |
| 4153 | + .flags = .{ .R = true }, |
| 4154 | + .@"align" = 1, |
| 4155 | + }; |
| 4156 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); |
| 4157 | + } |
| 4158 | + |
| 4159 | + const ph_rodata = &phdr[rodata_phndx]; |
| 4160 | + ph_rodata.* = .{ |
| 4161 | + .type = std.elf.PT_NULL, |
| 4162 | + .offset = 0, |
| 4163 | + .vaddr = 0, |
| 4164 | + .paddr = 0, |
| 4165 | + .filesz = 0, |
| 4166 | + .memsz = 0, |
| 4167 | + .flags = .{ .R = true }, |
| 4168 | + .@"align" = @intCast(seg_rodata_ni.alignment(&elf.mf).toByteUnits()), |
| 4169 | + }; |
| 4170 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); |
| 4171 | + |
| 4172 | + const ph_text = &phdr[text_phndx]; |
| 4173 | + ph_text.* = .{ |
| 4174 | + .type = std.elf.PT_NULL, |
| 4175 | + .offset = 0, |
| 4176 | + .vaddr = 0, |
| 4177 | + .paddr = 0, |
| 4178 | + .filesz = 0, |
| 4179 | + .memsz = 0, |
| 4180 | + .flags = .{ .R = true, .X = true }, |
| 4181 | + .@"align" = @intCast(seg_text_ni.alignment(&elf.mf).toByteUnits()), |
| 4182 | + }; |
| 4183 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); |
| 4184 | + |
| 4185 | + const ph_data = &phdr[data_phndx]; |
| 4186 | + ph_data.* = .{ |
| 4187 | + .type = std.elf.PT_NULL, |
| 4188 | + .offset = 0, |
| 4189 | + .vaddr = 0, |
| 4190 | + .paddr = 0, |
| 4191 | + .filesz = 0, |
| 4192 | + .memsz = 0, |
| 4193 | + .flags = .{ .R = true, .W = true }, |
| 4194 | + .@"align" = @intCast(seg_data_ni.alignment(&elf.mf).toByteUnits()), |
| 4195 | + }; |
| 4196 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); |
| 4197 | + |
| 4198 | + if (comp.config.any_non_single_threaded) { |
| 4199 | + const ph_tls = &phdr[tls_phndx]; |
| 4200 | + ph_tls.* = .{ |
| 4201 | + .type = std.elf.PT_TLS, |
| 4202 | + .offset = 0, |
| 4203 | + .vaddr = 0, |
| 4204 | + .paddr = 0, |
| 4205 | + .filesz = 0, |
| 4206 | + .memsz = 0, |
| 4207 | + .flags = .{ .R = true }, |
| 4208 | + .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), |
| 4209 | + }; |
| 4210 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); |
| 4211 | + } |
| 4212 | + |
| 4213 | + const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(shdr_ni.slice(&elf.mf))); |
| 4214 | + sh_null.* = .{ |
| 4215 | + .name = try elf.string(.shstrtab, ""), |
| 4216 | + .type = std.elf.SHT_NULL, |
| 4217 | + .flags = .{ .shf = .{} }, |
| 4218 | + .addr = 0, |
| 4219 | + .offset = 0, |
| 4220 | + .size = 0, |
| 4221 | + .link = 0, |
| 4222 | + .info = if (phnum >= std.elf.PN_XNUM) phnum else 0, |
| 4223 | + .addralign = 0, |
| 4224 | + .entsize = 0, |
| 4225 | + }; |
| 4226 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null); |
| 4227 | + } |
| 4228 | + |
| 4229 | + try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 4230 | + elf.symtab.addOneAssumeCapacity().* = .{ |
| 4231 | + .ni = .none, |
| 4232 | + .loc_relocs = .none, |
| 4233 | + .target_relocs = .none, |
| 4234 | + .unused = 0, |
| 4235 | + }; |
| 4236 | + assert(try elf.addSection(seg_rodata_ni, .{ |
| 4237 | + .type = std.elf.SHT_SYMTAB, |
| 4238 | + .addralign = addr_align, |
| 4239 | + .entsize = @sizeOf(ElfN.Sym), |
| 4240 | + }) == .symtab); |
| 4241 | + const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); |
| 4242 | + symtab.* = .{ |
| 4243 | + .name = try elf.string(.strtab, ""), |
| 4244 | + .value = 0, |
| 4245 | + .size = 0, |
| 4246 | + .info = .{ |
| 4247 | + .type = .NOTYPE, |
| 4248 | + .bind = .LOCAL, |
| 4249 | + }, |
| 4250 | + .other = .{ |
| 4251 | + .visibility = .DEFAULT, |
| 4252 | + }, |
| 4253 | + .shndx = std.elf.SHN_UNDEF, |
| 4254 | + }; |
| 4255 | + ehdr.shstrndx = ehdr.shnum; |
| 4256 | + assert(try elf.addSection(seg_rodata_ni, .{ |
| 4257 | + .type = std.elf.SHT_STRTAB, |
| 4258 | + .addralign = elf.mf.flags.block_size, |
| 4259 | + .entsize = 1, |
| 4260 | + }) == .shstrtab); |
| 4261 | + assert(try elf.addSection(seg_rodata_ni, .{ |
| 4262 | + .type = std.elf.SHT_STRTAB, |
| 4263 | + .addralign = elf.mf.flags.block_size, |
| 4264 | + .entsize = 1, |
| 4265 | + }) == .strtab); |
| 4266 | + try elf.renameSection(.symtab, ".symtab"); |
| 4267 | + try elf.renameSection(.shstrtab, ".shstrtab"); |
| 4268 | + try elf.renameSection(.strtab, ".strtab"); |
| 4269 | + try elf.linkSections(.symtab, .strtab); |
| 4270 | + Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 4271 | + Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 4272 | + |
| 4273 | + assert(try elf.addSection(seg_rodata_ni, .{ |
| 4274 | + .name = ".rodata", |
| 4275 | + .flags = .{ .ALLOC = true }, |
| 4276 | + .addralign = elf.mf.flags.block_size, |
| 4277 | + }) == .rodata); |
| 4278 | + assert(try elf.addSection(seg_text_ni, .{ |
| 4279 | + .name = ".text", |
| 4280 | + .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 4281 | + .addralign = elf.mf.flags.block_size, |
| 4282 | + }) == .text); |
| 4283 | + assert(try elf.addSection(seg_data_ni, .{ |
| 4284 | + .name = ".data", |
| 4285 | + .flags = .{ .WRITE = true, .ALLOC = true }, |
| 4286 | + .addralign = elf.mf.flags.block_size, |
| 4287 | + }) == .data); |
| 4288 | + if (comp.config.any_non_single_threaded) { |
| 4289 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 4290 | + const seg_tls_ni = try elf.mf.addLastChildNode(gpa, seg_data_ni, .{ |
| 4291 | + .alignment = elf.mf.flags.block_size, |
| 4292 | + .moved = true, |
| 4293 | + }); |
| 4294 | + elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); |
| 4295 | + |
| 4296 | + assert(try elf.addSection(seg_tls_ni, .{ |
| 4297 | + .name = ".tdata", |
| 4298 | + .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 4299 | + .addralign = elf.mf.flags.block_size, |
| 4300 | + }) == .tdata); |
| 4301 | + } |
| 4302 | + if (maybe_interp) |interp| { |
| 4303 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 4304 | + const seg_interp_ni = try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ |
| 4305 | + .size = interp.len + 1, |
| 4306 | + .moved = true, |
| 4307 | + .resized = true, |
| 4308 | + }); |
| 4309 | + elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); |
| 4310 | + |
| 4311 | + const sec_interp_si = try elf.addSection(seg_interp_ni, .{ |
| 4312 | + .name = ".interp", |
| 4313 | + .size = @intCast(interp.len + 1), |
| 4314 | + .flags = .{ .ALLOC = true }, |
| 4315 | + }); |
| 4316 | + const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); |
| 4317 | + @memcpy(sec_interp[0..interp.len], interp); |
| 4318 | + sec_interp[interp.len] = 0; |
| 4319 | + } |
| 4320 | +} |
| 4321 | + |
| 4322 | +fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node { |
| 4323 | + return elf.nodes.get(@intFromEnum(ni)); |
| 4324 | +} |
| 4325 | + |
| 4326 | +pub const EhdrPtr = union(std.elf.CLASS) { |
| 4327 | + NONE: noreturn, |
| 4328 | + @"32": *std.elf.Elf32.Ehdr, |
| 4329 | + @"64": *std.elf.Elf64.Ehdr, |
| 4330 | +}; |
| 4331 | +pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 4332 | + const slice = Node.known.ehdr.slice(&elf.mf); |
| 4333 | + return switch (elf.identClass()) { |
| 4334 | + .NONE, _ => unreachable, |
| 4335 | + inline .@"32", .@"64" => |class| @unionInit( |
| 4336 | + EhdrPtr, |
| 4337 | + @tagName(class), |
| 4338 | + @ptrCast(@alignCast(slice)), |
| 4339 | + ), |
| 4340 | + }; |
| 4341 | +} |
| 4342 | +pub fn ehdrField( |
| 4343 | + elf: *Elf, |
| 4344 | + comptime field: enum { type, machine }, |
| 4345 | +) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) { |
| 4346 | + const Field = @FieldType(std.elf.Elf32.Ehdr, @tagName(field)); |
| 4347 | + comptime assert(@FieldType(std.elf.Elf64.Ehdr, @tagName(field)) == Field); |
| 4348 | + return @enumFromInt(std.mem.toNative( |
| 4349 | + @typeInfo(Field).@"enum".tag_type, |
| 4350 | + @intFromEnum(switch (elf.ehdrPtr()) { |
| 4351 | + inline else => |ehdr| @field(ehdr, @tagName(field)), |
| 4352 | + }), |
| 4353 | + elf.endian(), |
| 4354 | + )); |
| 4355 | +} |
| 4356 | + |
| 4357 | +pub fn identClass(elf: *Elf) std.elf.CLASS { |
| 4358 | + return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); |
| 4359 | +} |
| 4360 | + |
| 4361 | +pub fn identData(elf: *Elf) std.elf.DATA { |
| 4362 | + return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); |
| 4363 | +} |
| 4364 | +fn endianForData(data: std.elf.DATA) std.builtin.Endian { |
| 4365 | + return switch (data) { |
| 4366 | + .NONE, _ => unreachable, |
| 4367 | + .@"2LSB" => .little, |
| 4368 | + .@"2MSB" => .big, |
| 4369 | + }; |
| 4370 | +} |
| 4371 | +pub fn endian(elf: *Elf) std.builtin.Endian { |
| 4372 | + return endianForData(elf.identData()); |
| 4373 | +} |
| 4374 | + |
| 4375 | +fn baseAddrForType(@"type": std.elf.ET) u64 { |
| 4376 | + return switch (@"type") { |
| 4377 | + else => 0, |
| 4378 | + .EXEC => 0x1000000, |
| 4379 | + }; |
| 4380 | +} |
| 4381 | +pub fn baseAddr(elf: *Elf) u64 { |
| 4382 | + return baseAddrForType(elf.ehdrField(.type)); |
| 4383 | +} |
| 4384 | + |
| 4385 | +pub const PhdrSlice = union(std.elf.CLASS) { |
| 4386 | + NONE: noreturn, |
| 4387 | + @"32": []std.elf.Elf32.Phdr, |
| 4388 | + @"64": []std.elf.Elf64.Phdr, |
| 4389 | +}; |
| 4390 | +pub fn phdrSlice(elf: *Elf) PhdrSlice { |
| 4391 | + const slice = Node.known.phdr.slice(&elf.mf); |
| 4392 | + return switch (elf.identClass()) { |
| 4393 | + .NONE, _ => unreachable, |
| 4394 | + inline .@"32", .@"64" => |class| @unionInit( |
| 4395 | + PhdrSlice, |
| 4396 | + @tagName(class), |
| 4397 | + @ptrCast(@alignCast(slice)), |
| 4398 | + ), |
| 4399 | + }; |
| 4400 | +} |
| 4401 | + |
| 4402 | +pub const ShdrSlice = union(std.elf.CLASS) { |
| 4403 | + NONE: noreturn, |
| 4404 | + @"32": []std.elf.Elf32.Shdr, |
| 4405 | + @"64": []std.elf.Elf64.Shdr, |
| 4406 | +}; |
| 4407 | +pub fn shdrSlice(elf: *Elf) ShdrSlice { |
| 4408 | + const slice = Node.known.shdr.slice(&elf.mf); |
| 4409 | + return switch (elf.identClass()) { |
| 4410 | + .NONE, _ => unreachable, |
| 4411 | + inline .@"32", .@"64" => |class| @unionInit( |
| 4412 | + ShdrSlice, |
| 4413 | + @tagName(class), |
| 4414 | + @ptrCast(@alignCast(slice)), |
| 4415 | + ), |
| 4416 | + }; |
| 4417 | +} |
| 4418 | + |
| 4419 | +pub const SymSlice = union(std.elf.CLASS) { |
| 4420 | + NONE: noreturn, |
| 4421 | + @"32": []std.elf.Elf32.Sym, |
| 4422 | + @"64": []std.elf.Elf64.Sym, |
| 4423 | +}; |
| 4424 | +pub fn symSlice(elf: *Elf) SymSlice { |
| 4425 | + const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); |
| 4426 | + return switch (elf.identClass()) { |
| 4427 | + .NONE, _ => unreachable, |
| 4428 | + inline .@"32", .@"64" => |class| @unionInit( |
| 4429 | + SymSlice, |
| 4430 | + @tagName(class), |
| 4431 | + @ptrCast(@alignCast(slice)), |
| 4432 | + ), |
| 4433 | + }; |
| 4434 | +} |
| 4435 | + |
| 4436 | +pub const SymPtr = union(std.elf.CLASS) { |
| 4437 | + NONE: noreturn, |
| 4438 | + @"32": *std.elf.Elf32.Sym, |
| 4439 | + @"64": *std.elf.Elf64.Sym, |
| 4440 | +}; |
| 4441 | +pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { |
| 4442 | + return switch (elf.symSlice()) { |
| 4443 | + inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]), |
| 4444 | + }; |
| 4445 | +} |
| 4446 | + |
| 4447 | +fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index { |
| 4448 | + defer elf.symtab.addOneAssumeCapacity().* = .{ |
| 4449 | + .ni = .none, |
| 4450 | + .loc_relocs = .none, |
| 4451 | + .target_relocs = .none, |
| 4452 | + .unused = 0, |
| 4453 | + }; |
| 4454 | + return @enumFromInt(elf.symtab.items.len); |
| 4455 | +} |
| 4456 | + |
| 4457 | +fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index { |
| 4458 | + const si = try elf.addSymbolAssumeCapacity(); |
| 4459 | + try si.init(elf, opts); |
| 4460 | + return si; |
| 4461 | +} |
| 4462 | + |
| 4463 | +pub fn globalSymbol( |
| 4464 | + elf: *Elf, |
| 4465 | + opts: struct { |
| 4466 | + name: []const u8, |
| 4467 | + type: std.elf.STT, |
| 4468 | + bind: std.elf.STB = .GLOBAL, |
| 4469 | + visibility: std.elf.STV = .DEFAULT, |
| 4470 | + }, |
| 4471 | +) !Symbol.Index { |
| 4472 | + const gpa = elf.base.comp.gpa; |
| 4473 | + try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 4474 | + const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); |
| 4475 | + if (!sym_gop.found_existing) sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ |
| 4476 | + .name = opts.name, |
| 4477 | + .type = opts.type, |
| 4478 | + .bind = opts.bind, |
| 4479 | + .visibility = opts.visibility, |
| 4480 | + }); |
| 4481 | + return sym_gop.value_ptr.*; |
| 4482 | +} |
| 4483 | + |
| 4484 | +fn navType( |
| 4485 | + ip: *const InternPool, |
| 4486 | + nav_status: @FieldType(InternPool.Nav, "status"), |
| 4487 | + any_non_single_threaded: bool, |
| 4488 | +) std.elf.STT { |
| 4489 | + return switch (nav_status) { |
| 4490 | + .unresolved => unreachable, |
| 4491 | + .type_resolved => |tr| if (any_non_single_threaded and tr.is_threadlocal) |
| 4492 | + .TLS |
| 4493 | + else if (ip.isFunctionType(tr.type)) |
| 4494 | + .FUNC |
| 4495 | + else |
| 4496 | + .OBJECT, |
| 4497 | + .fully_resolved => |fr| switch (ip.indexToKey(fr.val)) { |
| 4498 | + else => .OBJECT, |
| 4499 | + .variable => |variable| if (any_non_single_threaded and variable.is_threadlocal) |
| 4500 | + .TLS |
| 4501 | + else |
| 4502 | + .OBJECT, |
| 4503 | + .@"extern" => |@"extern"| if (any_non_single_threaded and @"extern".is_threadlocal) |
| 4504 | + .TLS |
| 4505 | + else if (ip.isFunctionType(@"extern".ty)) |
| 4506 | + .FUNC |
| 4507 | + else |
| 4508 | + .OBJECT, |
| 4509 | + .func => .FUNC, |
| 4510 | + }, |
| 4511 | + }; |
| 4512 | +} |
| 4513 | +pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { |
| 4514 | + const gpa = zcu.gpa; |
| 4515 | + const ip = &zcu.intern_pool; |
| 4516 | + const nav = ip.getNav(nav_index); |
| 4517 | + if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ |
| 4518 | + .name = @"extern".name.toSlice(ip), |
| 4519 | + .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), |
| 4520 | + .bind = switch (@"extern".linkage) { |
| 4521 | + .internal => .LOCAL, |
| 4522 | + .strong => .GLOBAL, |
| 4523 | + .weak => .WEAK, |
| 4524 | + .link_once => return error.LinkOnceUnsupported, |
| 4525 | + }, |
| 4526 | + .visibility = switch (@"extern".visibility) { |
| 4527 | + .default => .DEFAULT, |
| 4528 | + .hidden => .HIDDEN, |
| 4529 | + .protected => .PROTECTED, |
| 4530 | + }, |
| 4531 | + }); |
| 4532 | + try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 4533 | + const sym_gop = try elf.navs.getOrPut(gpa, nav_index); |
| 4534 | + if (!sym_gop.found_existing) { |
| 4535 | + sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ |
| 4536 | + .name = nav.fqn.toSlice(ip), |
| 4537 | + .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), |
| 4538 | + }); |
| 4539 | + } |
| 4540 | + return sym_gop.value_ptr.*; |
| 4541 | +} |
| 4542 | + |
| 4543 | +pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { |
| 4544 | + const gpa = elf.base.comp.gpa; |
| 4545 | + try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 4546 | + const sym_gop = try elf.uavs.getOrPut(gpa, uav_val); |
| 4547 | + if (!sym_gop.found_existing) |
| 4548 | + sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); |
| 4549 | + return sym_gop.value_ptr.*; |
| 4550 | +} |
| 4551 | + |
| 4552 | +pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 4553 | + const gpa = elf.base.comp.gpa; |
| 4554 | + try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 4555 | + const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); |
| 4556 | + if (!sym_gop.found_existing) { |
| 4557 | + sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ |
| 4558 | + .type = switch (lazy.kind) { |
| 4559 | + .code => .FUNC, |
| 4560 | + .const_data => .OBJECT, |
| 4561 | + }, |
| 4562 | + }); |
| 4563 | + elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1); |
| 4564 | + } |
| 4565 | + return sym_gop.value_ptr.*; |
| 4566 | +} |
| 4567 | + |
| 4568 | +pub fn getNavVAddr( |
| 4569 | + elf: *Elf, |
| 4570 | + pt: Zcu.PerThread, |
| 4571 | + nav: InternPool.Nav.Index, |
| 4572 | + reloc_info: link.File.RelocInfo, |
| 4573 | +) !u64 { |
| 4574 | + return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav)); |
| 4575 | +} |
| 4576 | + |
| 4577 | +pub fn getUavVAddr( |
| 4578 | + elf: *Elf, |
| 4579 | + uav: InternPool.Index, |
| 4580 | + reloc_info: link.File.RelocInfo, |
| 4581 | +) !u64 { |
| 4582 | + return elf.getVAddr(reloc_info, try elf.uavSymbol(uav)); |
| 4583 | +} |
| 4584 | + |
| 4585 | +pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { |
| 4586 | + try elf.addReloc( |
| 4587 | + @enumFromInt(reloc_info.parent.atom_index), |
| 4588 | + reloc_info.offset, |
| 4589 | + target_si, |
| 4590 | + reloc_info.addend, |
| 4591 | + switch (elf.ehdrField(.machine)) { |
| 4592 | + else => unreachable, |
| 4593 | + .X86_64 => .{ .x86_64 = switch (elf.identClass()) { |
| 4594 | + .NONE, _ => unreachable, |
| 4595 | + .@"32" => .@"32", |
| 4596 | + .@"64" => .@"64", |
| 4597 | + } }, |
| 4598 | + }, |
| 4599 | + ); |
| 4600 | + return 0; |
| 4601 | +} |
| 4602 | + |
| 4603 | +fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 4604 | + name: []const u8 = "", |
| 4605 | + type: std.elf.Word = std.elf.SHT_NULL, |
| 4606 | + size: std.elf.Word = 0, |
| 4607 | + flags: std.elf.SHF = .{}, |
| 4608 | + addralign: std.mem.Alignment = .@"1", |
| 4609 | + entsize: std.elf.Word = 0, |
| 4610 | +}) !Symbol.Index { |
| 4611 | + const gpa = elf.base.comp.gpa; |
| 4612 | + const target_endian = elf.endian(); |
| 4613 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 4614 | + try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 4615 | + |
| 4616 | + const shstrtab_entry = try elf.string(.shstrtab, opts.name); |
| 4617 | + const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) { |
| 4618 | + inline else => |ehdr| { |
| 4619 | + const shentsize = std.mem.toNative(@TypeOf(ehdr.shentsize), ehdr.shentsize, target_endian); |
| 4620 | + const shndx = std.mem.toNative(@TypeOf(ehdr.shnum), ehdr.shnum, target_endian); |
| 4621 | + const shnum = shndx + 1; |
| 4622 | + ehdr.shnum = std.mem.nativeTo(@TypeOf(ehdr.shnum), shnum, target_endian); |
| 4623 | + break :shndx .{ shndx, shentsize * shnum }; |
| 4624 | + }, |
| 4625 | + }; |
| 4626 | + try Node.known.shdr.resize(&elf.mf, gpa, shdr_size); |
| 4627 | + const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ |
| 4628 | + .alignment = opts.addralign, |
| 4629 | + .size = opts.size, |
| 4630 | + .moved = true, |
| 4631 | + }); |
| 4632 | + const si = try elf.addSymbolAssumeCapacity(); |
| 4633 | + elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 4634 | + si.get(elf).ni = ni; |
| 4635 | + try si.init(elf, .{ |
| 4636 | + .name = opts.name, |
| 4637 | + .size = opts.size, |
| 4638 | + .type = .SECTION, |
| 4639 | + .shndx = shndx, |
| 4640 | + }); |
| 4641 | + switch (elf.shdrSlice()) { |
| 4642 | + inline else => |shdr| { |
| 4643 | + const sh = &shdr[shndx]; |
| 4644 | + sh.* = .{ |
| 4645 | + .name = shstrtab_entry, |
| 4646 | + .type = opts.type, |
| 4647 | + .flags = .{ .shf = opts.flags }, |
| 4648 | + .addr = 0, |
| 4649 | + .offset = 0, |
| 4650 | + .size = opts.size, |
| 4651 | + .link = 0, |
| 4652 | + .info = 0, |
| 4653 | + .addralign = @intCast(opts.addralign.toByteUnits()), |
| 4654 | + .entsize = opts.entsize, |
| 4655 | + }; |
| 4656 | + if (target_endian != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh); |
| 4657 | + }, |
| 4658 | + } |
| 4659 | + return si; |
| 4660 | +} |
| 4661 | + |
| 4662 | +fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 4663 | + const strtab_entry = try elf.string(.strtab, name); |
| 4664 | + const shstrtab_entry = try elf.string(.shstrtab, name); |
| 4665 | + const target_endian = elf.endian(); |
| 4666 | + switch (elf.shdrSlice()) { |
| 4667 | + inline else => |shdr, class| { |
| 4668 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 4669 | + sym.name = std.mem.nativeTo(@TypeOf(sym.name), strtab_entry, target_endian); |
| 4670 | + const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); |
| 4671 | + const sh = &shdr[shndx]; |
| 4672 | + sh.name = std.mem.nativeTo(@TypeOf(sh.name), shstrtab_entry, target_endian); |
| 4673 | + }, |
| 4674 | + } |
| 4675 | +} |
| 4676 | + |
| 4677 | +fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 4678 | + const target_endian = elf.endian(); |
| 4679 | + switch (elf.shdrSlice()) { |
| 4680 | + inline else => |shdr, class| { |
| 4681 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 4682 | + const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); |
| 4683 | + shdr[shndx].link = @field(elf.symPtr(link_si), @tagName(class)).shndx; |
| 4684 | + }, |
| 4685 | + } |
| 4686 | +} |
| 4687 | + |
| 4688 | +fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 4689 | + const target_endian = elf.endian(); |
| 4690 | + const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) { |
| 4691 | + inline else => |shndx, class| { |
| 4692 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 4693 | + const sh = &shndx[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; |
| 4694 | + break :name std.mem.toNative(@TypeOf(sh.name), sh.name, target_endian); |
| 4695 | + }, |
| 4696 | + }..]; |
| 4697 | + return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; |
| 4698 | +} |
| 4699 | + |
| 4700 | +fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 { |
| 4701 | + if (key.len == 0) return 0; |
| 4702 | + return @field(elf, @tagName(section)).get( |
| 4703 | + elf.base.comp.gpa, |
| 4704 | + &elf.mf, |
| 4705 | + @field(Symbol.Index, @tagName(section)).node(elf), |
| 4706 | + key, |
| 4707 | + ); |
| 4708 | +} |
| 4709 | + |
| 4710 | +pub fn addReloc( |
| 4711 | + elf: *Elf, |
| 4712 | + loc_si: Symbol.Index, |
| 4713 | + offset: u64, |
| 4714 | + target_si: Symbol.Index, |
| 4715 | + addend: i64, |
| 4716 | + @"type": Reloc.Type, |
| 4717 | +) !void { |
| 4718 | + const gpa = elf.base.comp.gpa; |
| 4719 | + const target = target_si.get(elf); |
| 4720 | + const ri: link.File.Elf2.Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| 4721 | + (try elf.relocs.addOne(gpa)).* = .{ |
| 4722 | + .type = @"type", |
| 4723 | + .prev = .none, |
| 4724 | + .next = target.target_relocs, |
| 4725 | + .loc = loc_si, |
| 4726 | + .target = target_si, |
| 4727 | + .unused = 0, |
| 4728 | + .offset = offset, |
| 4729 | + .addend = addend, |
| 4730 | + }; |
| 4731 | + switch (target.target_relocs) { |
| 4732 | + .none => {}, |
| 4733 | + else => |target_ri| target_ri.get(elf).prev = ri, |
| 4734 | + } |
| 4735 | + target.target_relocs = ri; |
| 4736 | +} |
| 4737 | + |
| 4738 | +pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void { |
| 4739 | + _ = elf; |
| 4740 | + _ = prog_node; |
| 4741 | +} |
| 4742 | + |
| 4743 | +pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 4744 | + elf.updateNavInner(pt, nav_index) catch |err| switch (err) { |
| 4745 | + error.OutOfMemory, |
| 4746 | + error.Overflow, |
| 4747 | + error.RelocationNotByteAligned, |
| 4748 | + => |e| return e, |
| 4749 | + else => |e| return elf.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}), |
| 4750 | + }; |
| 4751 | +} |
| 4752 | +fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 4753 | + const comp = elf.base.comp; |
| 4754 | + const zcu = pt.zcu; |
| 4755 | + const gpa = zcu.gpa; |
| 4756 | + const ip = &zcu.intern_pool; |
| 4757 | + |
| 4758 | + const nav = ip.getNav(nav_index); |
| 4759 | + const nav_val = nav.status.fully_resolved.val; |
| 4760 | + const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) { |
| 4761 | + else => .{ nav_val, false }, |
| 4762 | + .variable => |variable| .{ variable.init, variable.is_threadlocal }, |
| 4763 | + .@"extern" => return, |
| 4764 | + .func => .{ .none, false }, |
| 4765 | + }; |
| 4766 | + if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; |
| 4767 | + |
| 4768 | + const si = try elf.navSymbol(zcu, nav_index); |
| 4769 | + const ni = ni: { |
| 4770 | + const sym = si.get(elf); |
| 4771 | + switch (sym.ni) { |
| 4772 | + .none => { |
| 4773 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 4774 | + const sec_si: Symbol.Index = |
| 4775 | + if (is_threadlocal and comp.config.any_non_single_threaded) .tdata else .data; |
| 4776 | + const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ |
| 4777 | + .alignment = pt.navAlignment(nav_index).toStdMem(), |
| 4778 | + .moved = true, |
| 4779 | + }); |
| 4780 | + elf.nodes.appendAssumeCapacity(.{ .nav = nav_index }); |
| 4781 | + sym.ni = ni; |
| 4782 | + switch (elf.symPtr(si)) { |
| 4783 | + inline else => |sym_ptr, class| sym_ptr.shndx = |
| 4784 | + @field(elf.symPtr(sec_si), @tagName(class)).shndx, |
| 4785 | + } |
| 4786 | + }, |
| 4787 | + else => si.deleteLocationRelocs(elf), |
| 4788 | + } |
| 4789 | + assert(sym.loc_relocs == .none); |
| 4790 | + sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 4791 | + break :ni sym.ni; |
| 4792 | + }; |
| 4793 | + |
| 4794 | + const size = size: { |
| 4795 | + var nw: MappedFile.Node.Writer = undefined; |
| 4796 | + ni.writer(&elf.mf, gpa, &nw); |
| 4797 | + defer nw.deinit(); |
| 4798 | + codegen.generateSymbol( |
| 4799 | + &elf.base, |
| 4800 | + pt, |
| 4801 | + zcu.navSrcLoc(nav_index), |
| 4802 | + .fromInterned(nav_init), |
| 4803 | + &nw.interface, |
| 4804 | + .{ .atom_index = @intFromEnum(si) }, |
| 4805 | + ) catch |err| switch (err) { |
| 4806 | + error.WriteFailed => return error.OutOfMemory, |
| 4807 | + else => |e| return e, |
| 4808 | + }; |
| 4809 | + break :size nw.interface.end; |
| 4810 | + }; |
| 4811 | + |
| 4812 | + const target_endian = elf.endian(); |
| 4813 | + switch (elf.symPtr(si)) { |
| 4814 | + inline else => |sym| sym.size = |
| 4815 | + std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), |
| 4816 | + } |
| 4817 | + si.applyLocationRelocs(elf); |
| 4818 | +} |
| 4819 | + |
| 4820 | +pub fn lowerUav( |
| 4821 | + elf: *Elf, |
| 4822 | + pt: Zcu.PerThread, |
| 4823 | + uav_val: InternPool.Index, |
| 4824 | + uav_align: InternPool.Alignment, |
| 4825 | + src_loc: Zcu.LazySrcLoc, |
| 4826 | +) !codegen.SymbolResult { |
| 4827 | + const zcu = pt.zcu; |
| 4828 | + const gpa = zcu.gpa; |
| 4829 | + |
| 4830 | + try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); |
| 4831 | + const si = elf.uavSymbol(uav_val) catch |err| switch (err) { |
| 4832 | + error.OutOfMemory => return error.OutOfMemory, |
| 4833 | + else => |e| return .{ .fail = try Zcu.ErrorMsg.create( |
| 4834 | + gpa, |
| 4835 | + src_loc, |
| 4836 | + "linker failed to update constant: {s}", |
| 4837 | + .{@errorName(e)}, |
| 4838 | + ) }, |
| 4839 | + }; |
| 4840 | + if (switch (si.get(elf).ni) { |
| 4841 | + .none => true, |
| 4842 | + else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt), |
| 4843 | + }) { |
| 4844 | + const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val); |
| 4845 | + if (gop.found_existing) { |
| 4846 | + gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); |
| 4847 | + } else { |
| 4848 | + gop.value_ptr.* = .{ |
| 4849 | + .alignment = uav_align, |
| 4850 | + .src_loc = src_loc, |
| 4851 | + }; |
| 4852 | + elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1); |
| 4853 | + } |
| 4854 | + } |
| 4855 | + return .{ .sym_index = @intFromEnum(si) }; |
| 4856 | +} |
| 4857 | + |
| 4858 | +pub fn updateFunc( |
| 4859 | + elf: *Elf, |
| 4860 | + pt: Zcu.PerThread, |
| 4861 | + func_index: InternPool.Index, |
| 4862 | + mir: *const codegen.AnyMir, |
| 4863 | +) !void { |
| 4864 | + elf.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { |
| 4865 | + error.OutOfMemory, |
| 4866 | + error.Overflow, |
| 4867 | + error.RelocationNotByteAligned, |
| 4868 | + error.CodegenFail, |
| 4869 | + => |e| return e, |
| 4870 | + else => |e| return elf.base.cgFail( |
| 4871 | + pt.zcu.funcInfo(func_index).owner_nav, |
| 4872 | + "linker failed to update function: {s}", |
| 4873 | + .{@errorName(e)}, |
| 4874 | + ), |
| 4875 | + }; |
| 4876 | +} |
| 4877 | +fn updateFuncInner( |
| 4878 | + elf: *Elf, |
| 4879 | + pt: Zcu.PerThread, |
| 4880 | + func_index: InternPool.Index, |
| 4881 | + mir: *const codegen.AnyMir, |
| 4882 | +) !void { |
| 4883 | + const zcu = pt.zcu; |
| 4884 | + const gpa = zcu.gpa; |
| 4885 | + const ip = &zcu.intern_pool; |
| 4886 | + const func = zcu.funcInfo(func_index); |
| 4887 | + const nav = ip.getNav(func.owner_nav); |
| 4888 | + |
| 4889 | + const si = try elf.navSymbol(zcu, func.owner_nav); |
| 4890 | + log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); |
| 4891 | + const ni = ni: { |
| 4892 | + const sym = si.get(elf); |
| 4893 | + switch (sym.ni) { |
| 4894 | + .none => { |
| 4895 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 4896 | + const mod = zcu.navFileScope(func.owner_nav).mod.?; |
| 4897 | + const target = &mod.resolved_target.result; |
| 4898 | + const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.text.node(elf), .{ |
| 4899 | + .alignment = switch (nav.status.fully_resolved.alignment) { |
| 4900 | + .none => switch (mod.optimize_mode) { |
| 4901 | + .Debug, |
| 4902 | + .ReleaseSafe, |
| 4903 | + .ReleaseFast, |
| 4904 | + => target_util.defaultFunctionAlignment(target), |
| 4905 | + .ReleaseSmall => target_util.minFunctionAlignment(target), |
| 4906 | + }, |
| 4907 | + else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), |
| 4908 | + }.toStdMem(), |
| 4909 | + .moved = true, |
| 4910 | + }); |
| 4911 | + elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav }); |
| 4912 | + sym.ni = ni; |
| 4913 | + switch (elf.symPtr(si)) { |
| 4914 | + inline else => |sym_ptr, class| sym_ptr.shndx = |
| 4915 | + @field(elf.symPtr(.text), @tagName(class)).shndx, |
| 4916 | + } |
| 4917 | + }, |
| 4918 | + else => si.deleteLocationRelocs(elf), |
| 4919 | + } |
| 4920 | + assert(sym.loc_relocs == .none); |
| 4921 | + sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 4922 | + break :ni sym.ni; |
| 4923 | + }; |
| 4924 | + |
| 4925 | + const size = size: { |
| 4926 | + var nw: MappedFile.Node.Writer = undefined; |
| 4927 | + ni.writer(&elf.mf, gpa, &nw); |
| 4928 | + defer nw.deinit(); |
| 4929 | + codegen.emitFunction( |
| 4930 | + &elf.base, |
| 4931 | + pt, |
| 4932 | + zcu.navSrcLoc(func.owner_nav), |
| 4933 | + func_index, |
| 4934 | + @intFromEnum(si), |
| 4935 | + mir, |
| 4936 | + &nw.interface, |
| 4937 | + .none, |
| 4938 | + ) catch |err| switch (err) { |
| 4939 | + error.WriteFailed => return nw.err.?, |
| 4940 | + else => |e| return e, |
| 4941 | + }; |
| 4942 | + break :size nw.interface.end; |
| 4943 | + }; |
| 4944 | + |
| 4945 | + const target_endian = elf.endian(); |
| 4946 | + switch (elf.symPtr(si)) { |
| 4947 | + inline else => |sym| sym.size = |
| 4948 | + std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), |
| 4949 | + } |
| 4950 | + si.applyLocationRelocs(elf); |
| 4951 | +} |
| 4952 | + |
| 4953 | +pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| 4954 | + const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return; |
| 4955 | + elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) { |
| 4956 | + error.OutOfMemory => return error.OutOfMemory, |
| 4957 | + error.CodegenFail => return error.LinkFailure, |
| 4958 | + else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), |
| 4959 | + }; |
| 4960 | +} |
| 4961 | + |
| 4962 | +pub fn flush( |
| 4963 | + elf: *Elf, |
| 4964 | + arena: std.mem.Allocator, |
| 4965 | + tid: Zcu.PerThread.Id, |
| 4966 | + prog_node: std.Progress.Node, |
| 4967 | +) !void { |
| 4968 | + _ = arena; |
| 4969 | + _ = prog_node; |
| 4970 | + while (try elf.idle(tid)) {} |
| 4971 | +} |
| 4972 | + |
| 4973 | +pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 4974 | + const comp = elf.base.comp; |
| 4975 | + task: { |
| 4976 | + while (elf.pending_uavs.pop()) |pending_uav| { |
| 4977 | + const sub_prog_node = |
| 4978 | + elf.idleProgNode( |
| 4979 | + tid, |
| 4980 | + comp.link_uav_prog_node, |
| 4981 | + .{ .uav = pending_uav.key }, |
| 4982 | + ); |
| 4983 | + defer sub_prog_node.end(); |
| 4984 | + break :task elf.flushUav( |
| 4985 | + .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, |
| 4986 | + pending_uav.key, |
| 4987 | + pending_uav.value.alignment, |
| 4988 | + pending_uav.value.src_loc, |
| 4989 | + ) catch |err| switch (err) { |
| 4990 | + error.OutOfMemory => return error.OutOfMemory, |
| 4991 | + else => |e| return elf.base.comp.link_diags.fail( |
| 4992 | + "linker failed to lower constant: {t}", |
| 4993 | + .{e}, |
| 4994 | + ), |
| 4995 | + }; |
| 4996 | + } |
| 4997 | + var lazy_it = elf.lazy.iterator(); |
| 4998 | + while (lazy_it.next()) |lazy| for ( |
| 4999 | + lazy.value.map.keys()[lazy.value.pending_index..], |
| 5000 | + lazy.value.map.values()[lazy.value.pending_index..], |
| 5001 | + ) |ty, si| { |
| 5002 | + lazy.value.pending_index += 1; |
| 5003 | + const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; |
| 5004 | + const kind = switch (lazy.key) { |
| 5005 | + .code => "code", |
| 5006 | + .const_data => "data", |
| 5007 | + }; |
| 5008 | + var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 5009 | + const sub_prog_node = comp.link_lazy_prog_node.start( |
| 5010 | + std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ |
| 5011 | + kind, |
| 5012 | + Type.fromInterned(ty).fmt(pt), |
| 5013 | + }) catch &name, |
| 5014 | + 0, |
| 5015 | + ); |
| 5016 | + defer sub_prog_node.end(); |
| 5017 | + break :task elf.flushLazy(pt, .{ |
| 5018 | + .kind = lazy.key, |
| 5019 | + .ty = ty, |
| 5020 | + }, si) catch |err| switch (err) { |
| 5021 | + error.OutOfMemory => return error.OutOfMemory, |
| 5022 | + else => |e| return elf.base.comp.link_diags.fail( |
| 5023 | + "linker failed to lower lazy {s}: {t}", |
| 5024 | + .{ kind, e }, |
| 5025 | + ), |
| 5026 | + }; |
| 5027 | + }; |
| 5028 | + while (elf.mf.updates.pop()) |ni| { |
| 5029 | + const clean_moved = ni.cleanMoved(&elf.mf); |
| 5030 | + const clean_resized = ni.cleanResized(&elf.mf); |
| 5031 | + if (clean_moved or clean_resized) { |
| 5032 | + const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); |
| 5033 | + defer sub_prog_node.end(); |
| 5034 | + if (clean_moved) try elf.flushMoved(ni); |
| 5035 | + if (clean_resized) try elf.flushResized(ni); |
| 5036 | + break :task; |
| 5037 | + } else elf.mf.update_prog_node.completeOne(); |
| 5038 | + } |
| 5039 | + } |
| 5040 | + if (elf.pending_uavs.count() > 0) return true; |
| 5041 | + for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 5042 | + if (elf.mf.updates.items.len > 0) return true; |
| 5043 | + return false; |
| 5044 | +} |
| 5045 | + |
| 5046 | +fn idleProgNode( |
| 5047 | + elf: *Elf, |
| 5048 | + tid: Zcu.PerThread.Id, |
| 5049 | + prog_node: std.Progress.Node, |
| 5050 | + node: Node, |
| 5051 | +) std.Progress.Node { |
| 5052 | + var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 5053 | + return prog_node.start(name: switch (node) { |
| 5054 | + else => |tag| @tagName(tag), |
| 5055 | + .section => |si| elf.sectionName(si), |
| 5056 | + .nav => |nav| { |
| 5057 | + const ip = &elf.base.comp.zcu.?.intern_pool; |
| 5058 | + break :name ip.getNav(nav).fqn.toSlice(ip); |
| 5059 | + }, |
| 5060 | + .uav => |uav| std.fmt.bufPrint(&name, "{f}", .{ |
| 5061 | + Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), |
| 5062 | + }) catch &name, |
| 5063 | + }, 0); |
| 5064 | +} |
| 5065 | + |
| 5066 | +fn flushUav( |
| 5067 | + elf: *Elf, |
| 5068 | + pt: Zcu.PerThread, |
| 5069 | + uav_val: InternPool.Index, |
| 5070 | + uav_align: InternPool.Alignment, |
| 5071 | + src_loc: Zcu.LazySrcLoc, |
| 5072 | +) !void { |
| 5073 | + const zcu = pt.zcu; |
| 5074 | + const gpa = zcu.gpa; |
| 5075 | + |
| 5076 | + const si = try elf.uavSymbol(uav_val); |
| 5077 | + const ni = ni: { |
| 5078 | + const sym = si.get(elf); |
| 5079 | + switch (sym.ni) { |
| 5080 | + .none => { |
| 5081 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5082 | + const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{ |
| 5083 | + .alignment = uav_align.toStdMem(), |
| 5084 | + .moved = true, |
| 5085 | + }); |
| 5086 | + elf.nodes.appendAssumeCapacity(.{ .uav = uav_val }); |
| 5087 | + sym.ni = ni; |
| 5088 | + switch (elf.symPtr(si)) { |
| 5089 | + inline else => |sym_ptr, class| sym_ptr.shndx = |
| 5090 | + @field(elf.symPtr(.data), @tagName(class)).shndx, |
| 5091 | + } |
| 5092 | + }, |
| 5093 | + else => { |
| 5094 | + if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return; |
| 5095 | + si.deleteLocationRelocs(elf); |
| 5096 | + }, |
| 5097 | + } |
| 5098 | + assert(sym.loc_relocs == .none); |
| 5099 | + sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 5100 | + break :ni sym.ni; |
| 5101 | + }; |
| 5102 | + |
| 5103 | + const size = size: { |
| 5104 | + var nw: MappedFile.Node.Writer = undefined; |
| 5105 | + ni.writer(&elf.mf, gpa, &nw); |
| 5106 | + defer nw.deinit(); |
| 5107 | + codegen.generateSymbol( |
| 5108 | + &elf.base, |
| 5109 | + pt, |
| 5110 | + src_loc, |
| 5111 | + .fromInterned(uav_val), |
| 5112 | + &nw.interface, |
| 5113 | + .{ .atom_index = @intFromEnum(si) }, |
| 5114 | + ) catch |err| switch (err) { |
| 5115 | + error.WriteFailed => return error.OutOfMemory, |
| 5116 | + else => |e| return e, |
| 5117 | + }; |
| 5118 | + break :size nw.interface.end; |
| 5119 | + }; |
| 5120 | + |
| 5121 | + const target_endian = elf.endian(); |
| 5122 | + switch (elf.symPtr(si)) { |
| 5123 | + inline else => |sym| sym.size = |
| 5124 | + std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), |
| 5125 | + } |
| 5126 | + si.applyLocationRelocs(elf); |
| 5127 | +} |
| 5128 | + |
| 5129 | +fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void { |
| 5130 | + const zcu = pt.zcu; |
| 5131 | + const gpa = zcu.gpa; |
| 5132 | + |
| 5133 | + const ni = ni: { |
| 5134 | + const sym = si.get(elf); |
| 5135 | + switch (sym.ni) { |
| 5136 | + .none => { |
| 5137 | + try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5138 | + const sec_si: Symbol.Index = switch (lazy.kind) { |
| 5139 | + .code => .text, |
| 5140 | + .const_data => .rodata, |
| 5141 | + }; |
| 5142 | + const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true }); |
| 5143 | + elf.nodes.appendAssumeCapacity(switch (lazy.kind) { |
| 5144 | + .code => .{ .lazy_code = lazy.ty }, |
| 5145 | + .const_data => .{ .lazy_const_data = lazy.ty }, |
| 5146 | + }); |
| 5147 | + sym.ni = ni; |
| 5148 | + switch (elf.symPtr(si)) { |
| 5149 | + inline else => |sym_ptr, class| sym_ptr.shndx = |
| 5150 | + @field(elf.symPtr(sec_si), @tagName(class)).shndx, |
| 5151 | + } |
| 5152 | + }, |
| 5153 | + else => si.deleteLocationRelocs(elf), |
| 5154 | + } |
| 5155 | + assert(sym.loc_relocs == .none); |
| 5156 | + sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 5157 | + break :ni sym.ni; |
| 5158 | + }; |
| 5159 | + |
| 5160 | + const size = size: { |
| 5161 | + var required_alignment: InternPool.Alignment = .none; |
| 5162 | + var nw: MappedFile.Node.Writer = undefined; |
| 5163 | + ni.writer(&elf.mf, gpa, &nw); |
| 5164 | + defer nw.deinit(); |
| 5165 | + try codegen.generateLazySymbol( |
| 5166 | + &elf.base, |
| 5167 | + pt, |
| 5168 | + Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, |
| 5169 | + lazy, |
| 5170 | + &required_alignment, |
| 5171 | + &nw.interface, |
| 5172 | + .none, |
| 5173 | + .{ .atom_index = @intFromEnum(si) }, |
| 5174 | + ); |
| 5175 | + break :size nw.interface.end; |
| 5176 | + }; |
| 5177 | + |
| 5178 | + const target_endian = elf.endian(); |
| 5179 | + switch (elf.symPtr(si)) { |
| 5180 | + inline else => |sym| sym.size = |
| 5181 | + std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), |
| 5182 | + } |
| 5183 | + si.applyLocationRelocs(elf); |
| 5184 | +} |
| 5185 | + |
| 5186 | +fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 5187 | + const target_endian = elf.endian(); |
| 5188 | + const file_offset = ni.fileLocation(&elf.mf, false).offset; |
| 5189 | + const node = elf.getNode(ni); |
| 5190 | + switch (node) { |
| 5191 | + else => |tag| @panic(@tagName(tag)), |
| 5192 | + .ehdr => assert(file_offset == 0), |
| 5193 | + .shdr => switch (elf.ehdrPtr()) { |
| 5194 | + inline else => |ehdr| ehdr.shoff = |
| 5195 | + std.mem.nativeTo(@TypeOf(ehdr.shoff), @intCast(file_offset), target_endian), |
| 5196 | + }, |
| 5197 | + .segment => |phndx| switch (elf.phdrSlice()) { |
| 5198 | + inline else => |phdr, class| { |
| 5199 | + const ph = &phdr[phndx]; |
| 5200 | + switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { |
| 5201 | + else => unreachable, |
| 5202 | + std.elf.PT_NULL, std.elf.PT_LOAD, std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, |
| 5203 | + std.elf.PT_PHDR => { |
| 5204 | + const ehdr = @field(elf.ehdrPtr(), @tagName(class)); |
| 5205 | + ehdr.phoff = |
| 5206 | + std.mem.nativeTo(@TypeOf(ehdr.phoff), @intCast(file_offset), target_endian); |
| 5207 | + }, |
| 5208 | + std.elf.PT_TLS => {}, |
| 5209 | + } |
| 5210 | + ph.offset = std.mem.nativeTo(@TypeOf(ph.offset), @intCast(file_offset), target_endian); |
| 5211 | + ph.vaddr = std.mem.nativeTo( |
| 5212 | + @TypeOf(ph.vaddr), |
| 5213 | + @intCast(elf.baseAddr() + file_offset), |
| 5214 | + target_endian, |
| 5215 | + ); |
| 5216 | + ph.paddr = ph.vaddr; |
| 5217 | + }, |
| 5218 | + }, |
| 5219 | + .section => |si| switch (elf.shdrSlice()) { |
| 5220 | + inline else => |shdr, class| { |
| 5221 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 5222 | + const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); |
| 5223 | + const sh = &shdr[shndx]; |
| 5224 | + const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( |
| 5225 | + @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, |
| 5226 | + @bitCast(sh.flags), |
| 5227 | + target_endian, |
| 5228 | + )); |
| 5229 | + if (flags.shf.ALLOC) { |
| 5230 | + sym.value = std.mem.nativeTo( |
| 5231 | + @TypeOf(sym.value), |
| 5232 | + @intCast(elf.baseAddr() + file_offset), |
| 5233 | + target_endian, |
| 5234 | + ); |
| 5235 | + sh.addr = sym.value; |
| 5236 | + } |
| 5237 | + sh.offset = std.mem.nativeTo(@TypeOf(sh.offset), @intCast(file_offset), target_endian); |
| 5238 | + }, |
| 5239 | + }, |
| 5240 | + .nav, .uav, .lazy_code, .lazy_const_data => { |
| 5241 | + const si = switch (node) { |
| 5242 | + else => unreachable, |
| 5243 | + .nav => |nav| elf.navs.get(nav), |
| 5244 | + .uav => |uav| elf.uavs.get(uav), |
| 5245 | + .lazy_code => |ty| elf.lazy.getPtr(.code).map.get(ty), |
| 5246 | + .lazy_const_data => |ty| elf.lazy.getPtr(.const_data).map.get(ty), |
| 5247 | + }.?; |
| 5248 | + switch (elf.shdrSlice()) { |
| 5249 | + inline else => |shdr, class| { |
| 5250 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 5251 | + const sh = &shdr[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; |
| 5252 | + const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( |
| 5253 | + @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, |
| 5254 | + @bitCast(sh.flags), |
| 5255 | + target_endian, |
| 5256 | + )); |
| 5257 | + const sh_addr = if (flags.shf.TLS) |
| 5258 | + 0 |
| 5259 | + else |
| 5260 | + std.mem.toNative(@TypeOf(sh.addr), sh.addr, target_endian); |
| 5261 | + const sh_offset = std.mem.toNative(@TypeOf(sh.offset), sh.offset, target_endian); |
| 5262 | + sym.value = std.mem.nativeTo( |
| 5263 | + @TypeOf(sym.value), |
| 5264 | + @intCast(file_offset - sh_offset + sh_addr), |
| 5265 | + target_endian, |
| 5266 | + ); |
| 5267 | + if (si == elf.entry_hack) @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; |
| 5268 | + }, |
| 5269 | + } |
| 5270 | + si.applyLocationRelocs(elf); |
| 5271 | + si.applyTargetRelocs(elf); |
| 5272 | + }, |
| 5273 | + } |
| 5274 | + try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 5275 | +} |
| 5276 | + |
| 5277 | +fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 5278 | + const target_endian = elf.endian(); |
| 5279 | + _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 5280 | + const node = elf.getNode(ni); |
| 5281 | + switch (node) { |
| 5282 | + else => |tag| @panic(@tagName(tag)), |
| 5283 | + .file, .shdr => {}, |
| 5284 | + .segment => |phndx| switch (elf.phdrSlice()) { |
| 5285 | + inline else => |phdr| { |
| 5286 | + const ph = &phdr[phndx]; |
| 5287 | + ph.filesz = std.mem.nativeTo(@TypeOf(ph.filesz), @intCast(size), target_endian); |
| 5288 | + ph.memsz = ph.filesz; |
| 5289 | + switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { |
| 5290 | + else => unreachable, |
| 5291 | + std.elf.PT_NULL => { |
| 5292 | + if (size > 0) ph.type = std.mem.nativeTo( |
| 5293 | + @TypeOf(ph.type), |
| 5294 | + std.elf.PT_LOAD, |
| 5295 | + target_endian, |
| 5296 | + ); |
| 5297 | + }, |
| 5298 | + std.elf.PT_LOAD => { |
| 5299 | + if (size == 0) ph.type = std.mem.nativeTo( |
| 5300 | + @TypeOf(ph.type), |
| 5301 | + std.elf.PT_NULL, |
| 5302 | + target_endian, |
| 5303 | + ); |
| 5304 | + }, |
| 5305 | + std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => {}, |
| 5306 | + std.elf.PT_TLS => try ni.childrenMoved(elf.base.comp.gpa, &elf.mf), |
| 5307 | + } |
| 5308 | + }, |
| 5309 | + }, |
| 5310 | + .section => |si| switch (elf.shdrSlice()) { |
| 5311 | + inline else => |shdr, class| { |
| 5312 | + const sym = @field(elf.symPtr(si), @tagName(class)); |
| 5313 | + const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); |
| 5314 | + const sh = &shdr[shndx]; |
| 5315 | + switch (std.mem.toNative(@TypeOf(sh.type), sh.type, target_endian)) { |
| 5316 | + else => unreachable, |
| 5317 | + std.elf.SHT_NULL => { |
| 5318 | + if (size > 0) sh.type = std.mem.nativeTo( |
| 5319 | + @TypeOf(sh.type), |
| 5320 | + std.elf.SHT_PROGBITS, |
| 5321 | + target_endian, |
| 5322 | + ); |
| 5323 | + }, |
| 5324 | + std.elf.SHT_PROGBITS => { |
| 5325 | + if (size == 0) sh.type = std.mem.nativeTo( |
| 5326 | + @TypeOf(sh.type), |
| 5327 | + std.elf.SHT_NULL, |
| 5328 | + target_endian, |
| 5329 | + ); |
| 5330 | + }, |
| 5331 | + std.elf.SHT_SYMTAB => sh.info = std.mem.nativeTo( |
| 5332 | + @TypeOf(sh.info), |
| 5333 | + @intCast(@divExact( |
| 5334 | + size, |
| 5335 | + std.mem.toNative(@TypeOf(sh.entsize), sh.entsize, target_endian), |
| 5336 | + )), |
| 5337 | + target_endian, |
| 5338 | + ), |
| 5339 | + std.elf.SHT_STRTAB => {}, |
| 5340 | + } |
| 5341 | + sh.size = std.mem.nativeTo(@TypeOf(sh.size), @intCast(size), target_endian); |
| 5342 | + }, |
| 5343 | + }, |
| 5344 | + .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 5345 | + } |
| 5346 | +} |
| 5347 | + |
| 5348 | +pub fn updateExports( |
| 5349 | + elf: *Elf, |
| 5350 | + pt: Zcu.PerThread, |
| 5351 | + exported: Zcu.Exported, |
| 5352 | + export_indices: []const Zcu.Export.Index, |
| 5353 | +) !void { |
| 5354 | + return elf.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { |
| 5355 | + error.OutOfMemory => error.OutOfMemory, |
| 5356 | + error.LinkFailure => error.AnalysisFail, |
| 5357 | + else => |e| switch (elf.base.comp.link_diags.fail( |
| 5358 | + "linker failed to update exports: {t}", |
| 5359 | + .{e}, |
| 5360 | + )) { |
| 5361 | + error.LinkFailure => return error.AnalysisFail, |
| 5362 | + }, |
| 5363 | + }; |
| 5364 | +} |
| 5365 | +fn updateExportsInner( |
| 5366 | + elf: *Elf, |
| 5367 | + pt: Zcu.PerThread, |
| 5368 | + exported: Zcu.Exported, |
| 5369 | + export_indices: []const Zcu.Export.Index, |
| 5370 | +) !void { |
| 5371 | + const zcu = pt.zcu; |
| 5372 | + const gpa = zcu.gpa; |
| 5373 | + const ip = &zcu.intern_pool; |
| 5374 | + |
| 5375 | + switch (exported) { |
| 5376 | + .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), |
| 5377 | + .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ |
| 5378 | + Type.fromInterned(ip.typeOf(uav)).fmt(pt), |
| 5379 | + Value.fromInterned(uav).fmtValue(pt), |
| 5380 | + }), |
| 5381 | + } |
| 5382 | + try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len); |
| 5383 | + const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) { |
| 5384 | + .nav => |nav| .{ |
| 5385 | + try elf.navSymbol(zcu, nav), |
| 5386 | + navType(ip, ip.getNav(nav).status, elf.base.comp.config.any_non_single_threaded), |
| 5387 | + }, |
| 5388 | + .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav( |
| 5389 | + pt, |
| 5390 | + uav, |
| 5391 | + Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), |
| 5392 | + export_indices[0].ptr(zcu).src, |
| 5393 | + )) { |
| 5394 | + .sym_index => |si| si, |
| 5395 | + .fail => |em| { |
| 5396 | + defer em.destroy(gpa); |
| 5397 | + return elf.base.comp.link_diags.fail("{s}", .{em.msg}); |
| 5398 | + }, |
| 5399 | + }), .OBJECT }, |
| 5400 | + }; |
| 5401 | + while (try elf.idle(pt.tid)) {} |
| 5402 | + const exported_ni = exported_si.node(elf); |
| 5403 | + const value, const size, const shndx = switch (elf.symPtr(exported_si)) { |
| 5404 | + inline else => |exported_sym| .{ exported_sym.value, exported_sym.size, exported_sym.shndx }, |
| 5405 | + }; |
| 5406 | + for (export_indices) |export_index| { |
| 5407 | + const @"export" = export_index.ptr(zcu); |
| 5408 | + const name = @"export".opts.name.toSlice(ip); |
| 5409 | + const export_si = try elf.globalSymbol(.{ |
| 5410 | + .name = name, |
| 5411 | + .type = @"type", |
| 5412 | + .bind = switch (@"export".opts.linkage) { |
| 5413 | + .internal => .LOCAL, |
| 5414 | + .strong => .GLOBAL, |
| 5415 | + .weak => .WEAK, |
| 5416 | + .link_once => return error.LinkOnceUnsupported, |
| 5417 | + }, |
| 5418 | + .visibility = switch (@"export".opts.visibility) { |
| 5419 | + .default => .DEFAULT, |
| 5420 | + .hidden => .HIDDEN, |
| 5421 | + .protected => .PROTECTED, |
| 5422 | + }, |
| 5423 | + }); |
| 5424 | + export_si.get(elf).ni = exported_ni; |
| 5425 | + switch (elf.symPtr(export_si)) { |
| 5426 | + inline else => |export_sym| { |
| 5427 | + export_sym.value = @intCast(value); |
| 5428 | + export_sym.size = @intCast(size); |
| 5429 | + export_sym.shndx = shndx; |
| 5430 | + }, |
| 5431 | + } |
| 5432 | + export_si.applyTargetRelocs(elf); |
| 5433 | + if (std.mem.eql(u8, name, "_start")) { |
| 5434 | + elf.entry_hack = exported_si; |
| 5435 | + switch (elf.ehdrPtr()) { |
| 5436 | + inline else => |ehdr| ehdr.entry = @intCast(value), |
| 5437 | + } |
| 5438 | + } |
| 5439 | + } |
| 5440 | +} |
| 5441 | + |
| 5442 | +pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { |
| 5443 | + _ = elf; |
| 5444 | + _ = exported; |
| 5445 | + _ = name; |
| 5446 | +} |
| 5447 | + |
| 5448 | +pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) void { |
| 5449 | + const w = std.debug.lockStderrWriter(&.{}); |
| 5450 | + defer std.debug.unlockStderrWriter(); |
| 5451 | + elf.printNode(tid, w, .root, 0) catch {}; |
| 5452 | +} |
| 5453 | + |
| 5454 | +pub fn printNode( |
| 5455 | + elf: *Elf, |
| 5456 | + tid: Zcu.PerThread.Id, |
| 5457 | + w: *std.Io.Writer, |
| 5458 | + ni: MappedFile.Node.Index, |
| 5459 | + indent: usize, |
| 5460 | +) !void { |
| 5461 | + const node = elf.getNode(ni); |
| 5462 | + const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)]; |
| 5463 | + const off, const size = mf_node.location().resolve(&elf.mf); |
| 5464 | + try w.splatByteAll(' ', indent); |
| 5465 | + try w.writeAll(@tagName(node)); |
| 5466 | + switch (node) { |
| 5467 | + else => {}, |
| 5468 | + .section => |si| try w.print("({s})", .{elf.sectionName(si)}), |
| 5469 | + .nav => |nav_index| { |
| 5470 | + const zcu = elf.base.comp.zcu.?; |
| 5471 | + const ip = &zcu.intern_pool; |
| 5472 | + const nav = ip.getNav(nav_index); |
| 5473 | + try w.print("({f}, {f})", .{ |
| 5474 | + Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), |
| 5475 | + nav.fqn.fmt(ip), |
| 5476 | + }); |
| 5477 | + }, |
| 5478 | + .uav => |uav| { |
| 5479 | + const zcu = elf.base.comp.zcu.?; |
| 5480 | + const val: Value = .fromInterned(uav); |
| 5481 | + try w.print("({f}, {f})", .{ |
| 5482 | + val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), |
| 5483 | + val.fmtValue(.{ .zcu = zcu, .tid = tid }), |
| 5484 | + }); |
| 5485 | + }, |
| 5486 | + } |
| 5487 | + try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ |
| 5488 | + @intFromEnum(ni), |
| 5489 | + off, |
| 5490 | + size, |
| 5491 | + mf_node.flags.alignment.toByteUnits(), |
| 5492 | + if (mf_node.flags.fixed) " fixed" else "", |
| 5493 | + if (mf_node.flags.moved) " moved" else "", |
| 5494 | + if (mf_node.flags.resized) " resized" else "", |
| 5495 | + if (mf_node.flags.has_content) " has_content" else "", |
| 5496 | + }); |
| 5497 | + var child_ni = mf_node.first; |
| 5498 | + switch (child_ni) { |
| 5499 | + .none => { |
| 5500 | + const file_loc = ni.fileLocation(&elf.mf, false); |
| 5501 | + if (file_loc.size == 0) return; |
| 5502 | + var address = file_loc.offset; |
| 5503 | + const line_len = 0x10; |
| 5504 | + var line_it = std.mem.window( |
| 5505 | + u8, |
| 5506 | + elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 5507 | + line_len, |
| 5508 | + line_len, |
| 5509 | + ); |
| 5510 | + while (line_it.next()) |line_bytes| : (address += line_len) { |
| 5511 | + try w.splatByteAll(' ', indent + 1); |
| 5512 | + try w.print("{x:0>8}", .{address}); |
| 5513 | + for (line_bytes) |byte| try w.print(" {x:0>2}", .{byte}); |
| 5514 | + try w.writeByte('\n'); |
| 5515 | + } |
| 5516 | + }, |
| 5517 | + else => while (child_ni != .none) { |
| 5518 | + try elf.printNode(tid, w, child_ni, indent + 1); |
| 5519 | + child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next; |
| 5520 | + }, |
| 5521 | + } |
| 5522 | +} |
| 5523 | + |
| 5524 | +const assert = std.debug.assert; |
| 5525 | +const builtin = @import("builtin"); |
| 5526 | +const codegen = @import("../codegen.zig"); |
| 5527 | +const Compilation = @import("../Compilation.zig"); |
| 5528 | +const Elf = @This(); |
| 5529 | +const InternPool = @import("../InternPool.zig"); |
| 5530 | +const link = @import("../link.zig"); |
| 5531 | +const log = std.log.scoped(.link); |
| 5532 | +const MappedFile = @import("MappedFile.zig"); |
| 5533 | +const native_endian = builtin.cpu.arch.endian(); |
| 5534 | +const std = @import("std"); |
| 5535 | +const target_util = @import("../target.zig"); |
| 5536 | +const Type = @import("../Type.zig"); |
| 5537 | +const Value = @import("../Value.zig"); |
| 5538 | +const Zcu = @import("../Zcu.zig"); |
| 5539 | diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig |
| 5540 | index b1fc6528d5..5a0a71f380 100644 |
| 5541 | --- a/src/link/MachO/ZigObject.zig |
| 5542 | +++ b/src/link/MachO/ZigObject.zig |
| 5543 | @@ -784,22 +784,26 @@ pub fn updateFunc( |
| 5544 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav); |
| 5545 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); |
| 5546 | |
| 5547 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 5548 | - defer code_buffer.deinit(gpa); |
| 5549 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 5550 | + defer aw.deinit(); |
| 5551 | |
| 5552 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; |
| 5553 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 5554 | |
| 5555 | - try codegen.emitFunction( |
| 5556 | + codegen.emitFunction( |
| 5557 | &macho_file.base, |
| 5558 | pt, |
| 5559 | zcu.navSrcLoc(func.owner_nav), |
| 5560 | func_index, |
| 5561 | + sym_index, |
| 5562 | mir, |
| 5563 | - &code_buffer, |
| 5564 | + &aw.writer, |
| 5565 | if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, |
| 5566 | - ); |
| 5567 | - const code = code_buffer.items; |
| 5568 | + ) catch |err| switch (err) { |
| 5569 | + error.WriteFailed => return error.OutOfMemory, |
| 5570 | + else => |e| return e, |
| 5571 | + }; |
| 5572 | + const code = aw.written(); |
| 5573 | |
| 5574 | const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code); |
| 5575 | const old_rva, const old_alignment = blk: { |
| 5576 | @@ -895,21 +899,24 @@ pub fn updateNav( |
| 5577 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); |
| 5578 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); |
| 5579 | |
| 5580 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 5581 | - defer code_buffer.deinit(zcu.gpa); |
| 5582 | + var aw: std.Io.Writer.Allocating = .init(zcu.gpa); |
| 5583 | + defer aw.deinit(); |
| 5584 | |
| 5585 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; |
| 5586 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 5587 | |
| 5588 | - try codegen.generateSymbol( |
| 5589 | + codegen.generateSymbol( |
| 5590 | &macho_file.base, |
| 5591 | pt, |
| 5592 | zcu.navSrcLoc(nav_index), |
| 5593 | Value.fromInterned(nav_init), |
| 5594 | - &code_buffer, |
| 5595 | + &aw.writer, |
| 5596 | .{ .atom_index = sym_index }, |
| 5597 | - ); |
| 5598 | - const code = code_buffer.items; |
| 5599 | + ) catch |err| switch (err) { |
| 5600 | + error.WriteFailed => return error.OutOfMemory, |
| 5601 | + else => |e| return e, |
| 5602 | + }; |
| 5603 | + const code = aw.written(); |
| 5604 | |
| 5605 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); |
| 5606 | if (isThreadlocal(macho_file, nav_index)) |
| 5607 | @@ -1198,21 +1205,24 @@ fn lowerConst( |
| 5608 | ) !codegen.SymbolResult { |
| 5609 | const gpa = macho_file.base.comp.gpa; |
| 5610 | |
| 5611 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 5612 | - defer code_buffer.deinit(gpa); |
| 5613 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 5614 | + defer aw.deinit(); |
| 5615 | |
| 5616 | const name_str = try self.addString(gpa, name); |
| 5617 | const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file); |
| 5618 | |
| 5619 | - try codegen.generateSymbol( |
| 5620 | + codegen.generateSymbol( |
| 5621 | &macho_file.base, |
| 5622 | pt, |
| 5623 | src_loc, |
| 5624 | val, |
| 5625 | - &code_buffer, |
| 5626 | + &aw.writer, |
| 5627 | .{ .atom_index = sym_index }, |
| 5628 | - ); |
| 5629 | - const code = code_buffer.items; |
| 5630 | + ) catch |err| switch (err) { |
| 5631 | + error.WriteFailed => return error.OutOfMemory, |
| 5632 | + else => |e| return e, |
| 5633 | + }; |
| 5634 | + const code = aw.written(); |
| 5635 | |
| 5636 | const sym = &self.symbols.items[sym_index]; |
| 5637 | sym.out_n_sect = output_section_index; |
| 5638 | @@ -1349,8 +1359,8 @@ fn updateLazySymbol( |
| 5639 | const gpa = zcu.gpa; |
| 5640 | |
| 5641 | var required_alignment: Atom.Alignment = .none; |
| 5642 | - var code_buffer: std.ArrayListUnmanaged(u8) = .empty; |
| 5643 | - defer code_buffer.deinit(gpa); |
| 5644 | + var aw: std.Io.Writer.Allocating = .init(gpa); |
| 5645 | + defer aw.deinit(); |
| 5646 | |
| 5647 | const name_str = blk: { |
| 5648 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| 5649 | @@ -1368,11 +1378,11 @@ fn updateLazySymbol( |
| 5650 | src, |
| 5651 | lazy_sym, |
| 5652 | &required_alignment, |
| 5653 | - &code_buffer, |
| 5654 | + &aw.writer, |
| 5655 | .none, |
| 5656 | .{ .atom_index = symbol_index }, |
| 5657 | ); |
| 5658 | - const code = code_buffer.items; |
| 5659 | + const code = aw.written(); |
| 5660 | |
| 5661 | const output_section_index = switch (lazy_sym.kind) { |
| 5662 | .code => macho_file.zig_text_sect_index.?, |
| 5663 | diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig |
| 5664 | new file mode 100644 |
| 5665 | index 0000000000..d04a8d533a |
| 5666 | --- /dev/null |
| 5667 | +++ b/src/link/MappedFile.zig |
| 5668 | @@ -0,0 +1,929 @@ |
| 5669 | +file: std.fs.File, |
| 5670 | +flags: packed struct { |
| 5671 | + block_size: std.mem.Alignment, |
| 5672 | + copy_file_range_unsupported: bool, |
| 5673 | + fallocate_punch_hole_unsupported: bool, |
| 5674 | + fallocate_insert_range_unsupported: bool, |
| 5675 | +}, |
| 5676 | +section: if (is_windows) windows.HANDLE else void, |
| 5677 | +contents: []align(std.heap.page_size_min) u8, |
| 5678 | +nodes: std.ArrayList(Node), |
| 5679 | +free_ni: Node.Index, |
| 5680 | +large: std.ArrayList(u64), |
| 5681 | +updates: std.ArrayList(Node.Index), |
| 5682 | +update_prog_node: std.Progress.Node, |
| 5683 | +writers: std.SinglyLinkedList, |
| 5684 | + |
| 5685 | +pub const Error = std.posix.MMapError || |
| 5686 | + std.posix.MRemapError || |
| 5687 | + std.fs.File.SetEndPosError || |
| 5688 | + std.fs.File.CopyRangeError || |
| 5689 | + error{NotFile}; |
| 5690 | + |
| 5691 | +pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile { |
| 5692 | + var mf: MappedFile = .{ |
| 5693 | + .file = file, |
| 5694 | + .flags = undefined, |
| 5695 | + .section = if (is_windows) windows.INVALID_HANDLE_VALUE else {}, |
| 5696 | + .contents = &.{}, |
| 5697 | + .nodes = .empty, |
| 5698 | + .free_ni = .none, |
| 5699 | + .large = .empty, |
| 5700 | + .updates = .empty, |
| 5701 | + .update_prog_node = .none, |
| 5702 | + .writers = .{}, |
| 5703 | + }; |
| 5704 | + errdefer mf.deinit(gpa); |
| 5705 | + const size: u64, const blksize = if (is_windows) |
| 5706 | + .{ try windows.GetFileSizeEx(file.handle), 1 } |
| 5707 | + else stat: { |
| 5708 | + const stat = try std.posix.fstat(mf.file.handle); |
| 5709 | + if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists; |
| 5710 | + break :stat .{ @bitCast(stat.size), stat.blksize }; |
| 5711 | + }; |
| 5712 | + mf.flags = .{ |
| 5713 | + .block_size = .fromByteUnits( |
| 5714 | + std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)), |
| 5715 | + ), |
| 5716 | + .copy_file_range_unsupported = false, |
| 5717 | + .fallocate_insert_range_unsupported = false, |
| 5718 | + .fallocate_punch_hole_unsupported = false, |
| 5719 | + }; |
| 5720 | + try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5721 | + assert(try mf.addNode(gpa, .{ |
| 5722 | + .add_node = .{ |
| 5723 | + .size = size, |
| 5724 | + .fixed = true, |
| 5725 | + }, |
| 5726 | + }) == Node.Index.root); |
| 5727 | + try mf.ensureTotalCapacity(@intCast(size)); |
| 5728 | + return mf; |
| 5729 | +} |
| 5730 | + |
| 5731 | +pub fn deinit(mf: *MappedFile, gpa: std.mem.Allocator) void { |
| 5732 | + mf.unmap(); |
| 5733 | + mf.nodes.deinit(gpa); |
| 5734 | + mf.large.deinit(gpa); |
| 5735 | + mf.updates.deinit(gpa); |
| 5736 | + mf.update_prog_node.end(); |
| 5737 | + assert(mf.writers.first == null); |
| 5738 | + mf.* = undefined; |
| 5739 | +} |
| 5740 | + |
| 5741 | +pub const Node = extern struct { |
| 5742 | + parent: Node.Index, |
| 5743 | + prev: Node.Index, |
| 5744 | + next: Node.Index, |
| 5745 | + first: Node.Index, |
| 5746 | + last: Node.Index, |
| 5747 | + flags: Flags, |
| 5748 | + location_payload: Location.Payload, |
| 5749 | + |
| 5750 | + pub const Flags = packed struct(u32) { |
| 5751 | + location_tag: Location.Tag, |
| 5752 | + alignment: std.mem.Alignment, |
| 5753 | + /// Whether this node can be moved. |
| 5754 | + fixed: bool, |
| 5755 | + /// Whether this node has been moved. |
| 5756 | + moved: bool, |
| 5757 | + /// Whether this node has been resized. |
| 5758 | + resized: bool, |
| 5759 | + /// Whether this node might contain non-zero bytes. |
| 5760 | + has_content: bool, |
| 5761 | + unused: @Type(.{ .int = .{ |
| 5762 | + .signedness = .unsigned, |
| 5763 | + .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5, |
| 5764 | + } }) = 0, |
| 5765 | + }; |
| 5766 | + |
| 5767 | + pub const Location = union(enum(u1)) { |
| 5768 | + small: extern struct { |
| 5769 | + /// Relative to `parent`. |
| 5770 | + offset: u32, |
| 5771 | + size: u32, |
| 5772 | + }, |
| 5773 | + large: extern struct { |
| 5774 | + index: usize, |
| 5775 | + unused: @Type(.{ .int = .{ |
| 5776 | + .signedness = .unsigned, |
| 5777 | + .bits = 64 - @bitSizeOf(usize), |
| 5778 | + } }) = 0, |
| 5779 | + }, |
| 5780 | + |
| 5781 | + pub const Tag = @typeInfo(Location).@"union".tag_type.?; |
| 5782 | + pub const Payload = @Type(.{ .@"union" = .{ |
| 5783 | + .layout = .@"extern", |
| 5784 | + .tag_type = null, |
| 5785 | + .fields = @typeInfo(Location).@"union".fields, |
| 5786 | + .decls = &.{}, |
| 5787 | + } }); |
| 5788 | + |
| 5789 | + pub fn resolve(loc: Location, mf: *const MappedFile) [2]u64 { |
| 5790 | + return switch (loc) { |
| 5791 | + .small => |small| .{ small.offset, small.size }, |
| 5792 | + .large => |large| mf.large.items[large.index..][0..2].*, |
| 5793 | + }; |
| 5794 | + } |
| 5795 | + }; |
| 5796 | + |
| 5797 | + pub const Index = enum(u32) { |
| 5798 | + none, |
| 5799 | + _, |
| 5800 | + |
| 5801 | + pub const root: Node.Index = .none; |
| 5802 | + |
| 5803 | + fn get(ni: Node.Index, mf: *const MappedFile) *Node { |
| 5804 | + return &mf.nodes.items[@intFromEnum(ni)]; |
| 5805 | + } |
| 5806 | + |
| 5807 | + pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { |
| 5808 | + var child_ni = ni.get(mf).last; |
| 5809 | + while (child_ni != .none) { |
| 5810 | + try child_ni.moved(gpa, mf); |
| 5811 | + child_ni = child_ni.get(mf).prev; |
| 5812 | + } |
| 5813 | + } |
| 5814 | + |
| 5815 | + pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { |
| 5816 | + var parent_ni = ni; |
| 5817 | + while (parent_ni != .none) { |
| 5818 | + const parent = parent_ni.get(mf); |
| 5819 | + if (parent.flags.moved) return true; |
| 5820 | + parent_ni = parent.parent; |
| 5821 | + } |
| 5822 | + return false; |
| 5823 | + } |
| 5824 | + pub fn moved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { |
| 5825 | + try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 5826 | + ni.movedAssumeCapacity(mf); |
| 5827 | + } |
| 5828 | + pub fn cleanMoved(ni: Node.Index, mf: *const MappedFile) bool { |
| 5829 | + const node_moved = &ni.get(mf).flags.moved; |
| 5830 | + defer node_moved.* = false; |
| 5831 | + return node_moved.*; |
| 5832 | + } |
| 5833 | + fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { |
| 5834 | + var parent_ni = ni; |
| 5835 | + while (parent_ni != .none) { |
| 5836 | + const parent_node = parent_ni.get(mf); |
| 5837 | + if (parent_node.flags.moved) return; |
| 5838 | + parent_ni = parent_node.parent; |
| 5839 | + } |
| 5840 | + const node = ni.get(mf); |
| 5841 | + node.flags.moved = true; |
| 5842 | + if (node.flags.resized) return; |
| 5843 | + mf.updates.appendAssumeCapacity(ni); |
| 5844 | + mf.update_prog_node.increaseEstimatedTotalItems(1); |
| 5845 | + } |
| 5846 | + |
| 5847 | + pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool { |
| 5848 | + return ni.get(mf).flags.resized; |
| 5849 | + } |
| 5850 | + pub fn resized(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { |
| 5851 | + try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 5852 | + ni.resizedAssumeCapacity(mf); |
| 5853 | + } |
| 5854 | + pub fn cleanResized(ni: Node.Index, mf: *const MappedFile) bool { |
| 5855 | + const node_resized = &ni.get(mf).flags.resized; |
| 5856 | + defer node_resized.* = false; |
| 5857 | + return node_resized.*; |
| 5858 | + } |
| 5859 | + fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { |
| 5860 | + const node = ni.get(mf); |
| 5861 | + if (node.flags.resized) return; |
| 5862 | + node.flags.resized = true; |
| 5863 | + if (node.flags.moved) return; |
| 5864 | + mf.updates.appendAssumeCapacity(ni); |
| 5865 | + mf.update_prog_node.increaseEstimatedTotalItems(1); |
| 5866 | + } |
| 5867 | + |
| 5868 | + pub fn alignment(ni: Node.Index, mf: *const MappedFile) std.mem.Alignment { |
| 5869 | + return ni.get(mf).flags.alignment; |
| 5870 | + } |
| 5871 | + |
| 5872 | + fn setLocationAssumeCapacity(ni: Node.Index, mf: *MappedFile, offset: u64, size: u64) void { |
| 5873 | + const node = ni.get(mf); |
| 5874 | + if (size == 0) node.flags.has_content = false; |
| 5875 | + switch (node.location()) { |
| 5876 | + .small => |small| { |
| 5877 | + if (small.offset != offset) ni.movedAssumeCapacity(mf); |
| 5878 | + if (small.size != size) ni.resizedAssumeCapacity(mf); |
| 5879 | + if (std.math.cast(u32, offset)) |small_offset| { |
| 5880 | + if (std.math.cast(u32, size)) |small_size| { |
| 5881 | + node.location_payload.small = .{ |
| 5882 | + .offset = small_offset, |
| 5883 | + .size = small_size, |
| 5884 | + }; |
| 5885 | + return; |
| 5886 | + } |
| 5887 | + } |
| 5888 | + defer mf.large.appendSliceAssumeCapacity(&.{ offset, size }); |
| 5889 | + node.flags.location_tag = .large; |
| 5890 | + node.location_payload = .{ .large = .{ .index = mf.large.items.len } }; |
| 5891 | + }, |
| 5892 | + .large => |large| { |
| 5893 | + const large_items = mf.large.items[large.index..][0..2]; |
| 5894 | + if (large_items[0] != offset) ni.movedAssumeCapacity(mf); |
| 5895 | + if (large_items[1] != size) ni.resizedAssumeCapacity(mf); |
| 5896 | + large_items.* = .{ offset, size }; |
| 5897 | + }, |
| 5898 | + } |
| 5899 | + } |
| 5900 | + |
| 5901 | + pub fn location(ni: Node.Index, mf: *const MappedFile) Location { |
| 5902 | + return ni.get(mf).location(); |
| 5903 | + } |
| 5904 | + |
| 5905 | + pub fn fileLocation( |
| 5906 | + ni: Node.Index, |
| 5907 | + mf: *const MappedFile, |
| 5908 | + set_has_content: bool, |
| 5909 | + ) struct { offset: u64, size: u64 } { |
| 5910 | + var offset, const size = ni.location(mf).resolve(mf); |
| 5911 | + var parent_ni = ni; |
| 5912 | + while (true) { |
| 5913 | + const parent = parent_ni.get(mf); |
| 5914 | + if (set_has_content) parent.flags.has_content = true; |
| 5915 | + if (parent_ni == .none) break; |
| 5916 | + parent_ni = parent.parent; |
| 5917 | + offset += parent_ni.location(mf).resolve(mf)[0]; |
| 5918 | + } |
| 5919 | + return .{ .offset = offset, .size = size }; |
| 5920 | + } |
| 5921 | + |
| 5922 | + pub fn slice(ni: Node.Index, mf: *const MappedFile) []u8 { |
| 5923 | + const file_loc = ni.fileLocation(mf, true); |
| 5924 | + return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; |
| 5925 | + } |
| 5926 | + |
| 5927 | + pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 { |
| 5928 | + const file_loc = ni.fileLocation(mf, false); |
| 5929 | + return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; |
| 5930 | + } |
| 5931 | + |
| 5932 | + pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64) !void { |
| 5933 | + try mf.resizeNode(gpa, ni, size); |
| 5934 | + var writers_it = mf.writers.first; |
| 5935 | + while (writers_it) |writer_node| : (writers_it = writer_node.next) { |
| 5936 | + const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); |
| 5937 | + w.interface.buffer = w.ni.slice(mf); |
| 5938 | + } |
| 5939 | + } |
| 5940 | + |
| 5941 | + pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { |
| 5942 | + w.* = .{ |
| 5943 | + .gpa = gpa, |
| 5944 | + .mf = mf, |
| 5945 | + .writer_node = .{}, |
| 5946 | + .ni = ni, |
| 5947 | + .interface = .{ |
| 5948 | + .buffer = ni.slice(mf), |
| 5949 | + .vtable = &Writer.vtable, |
| 5950 | + }, |
| 5951 | + .err = null, |
| 5952 | + }; |
| 5953 | + mf.writers.prepend(&w.writer_node); |
| 5954 | + } |
| 5955 | + }; |
| 5956 | + |
| 5957 | + pub fn location(node: *const Node) Location { |
| 5958 | + return switch (node.flags.location_tag) { |
| 5959 | + inline else => |tag| @unionInit( |
| 5960 | + Location, |
| 5961 | + @tagName(tag), |
| 5962 | + @field(node.location_payload, @tagName(tag)), |
| 5963 | + ), |
| 5964 | + }; |
| 5965 | + } |
| 5966 | + |
| 5967 | + pub const Writer = struct { |
| 5968 | + gpa: std.mem.Allocator, |
| 5969 | + mf: *MappedFile, |
| 5970 | + writer_node: std.SinglyLinkedList.Node, |
| 5971 | + ni: Node.Index, |
| 5972 | + interface: std.Io.Writer, |
| 5973 | + err: ?Error, |
| 5974 | + |
| 5975 | + pub fn deinit(w: *Writer) void { |
| 5976 | + assert(w.mf.writers.popFirst() == &w.writer_node); |
| 5977 | + w.* = undefined; |
| 5978 | + } |
| 5979 | + |
| 5980 | + const vtable: std.Io.Writer.VTable = .{ |
| 5981 | + .drain = drain, |
| 5982 | + .sendFile = sendFile, |
| 5983 | + .flush = std.Io.Writer.noopFlush, |
| 5984 | + .rebase = growingRebase, |
| 5985 | + }; |
| 5986 | + |
| 5987 | + fn drain( |
| 5988 | + interface: *std.Io.Writer, |
| 5989 | + data: []const []const u8, |
| 5990 | + splat: usize, |
| 5991 | + ) std.Io.Writer.Error!usize { |
| 5992 | + const pattern = data[data.len - 1]; |
| 5993 | + const splat_len = pattern.len * splat; |
| 5994 | + const start_len = interface.end; |
| 5995 | + assert(data.len != 0); |
| 5996 | + for (data) |bytes| { |
| 5997 | + try growingRebase(interface, interface.end, bytes.len + splat_len + 1); |
| 5998 | + @memcpy(interface.buffer[interface.end..][0..bytes.len], bytes); |
| 5999 | + interface.end += bytes.len; |
| 6000 | + } |
| 6001 | + if (splat == 0) { |
| 6002 | + interface.end -= pattern.len; |
| 6003 | + } else switch (pattern.len) { |
| 6004 | + 0 => {}, |
| 6005 | + 1 => { |
| 6006 | + @memset(interface.buffer[interface.end..][0 .. splat - 1], pattern[0]); |
| 6007 | + interface.end += splat - 1; |
| 6008 | + }, |
| 6009 | + else => for (0..splat - 1) |_| { |
| 6010 | + @memcpy(interface.buffer[interface.end..][0..pattern.len], pattern); |
| 6011 | + interface.end += pattern.len; |
| 6012 | + }, |
| 6013 | + } |
| 6014 | + return interface.end - start_len; |
| 6015 | + } |
| 6016 | + |
| 6017 | + fn sendFile( |
| 6018 | + interface: *std.Io.Writer, |
| 6019 | + file_reader: *std.fs.File.Reader, |
| 6020 | + limit: std.Io.Limit, |
| 6021 | + ) std.Io.Writer.FileError!usize { |
| 6022 | + if (limit == .nothing) return 0; |
| 6023 | + const pos = file_reader.logicalPos(); |
| 6024 | + const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line; |
| 6025 | + if (additional == 0) return error.EndOfStream; |
| 6026 | + try growingRebase(interface, interface.end, limit.minInt64(additional)); |
| 6027 | + switch (file_reader.mode) { |
| 6028 | + .positional => { |
| 6029 | + const fr_buf = file_reader.interface.buffered(); |
| 6030 | + const buf_copy_size = interface.write(fr_buf) catch unreachable; |
| 6031 | + file_reader.interface.toss(buf_copy_size); |
| 6032 | + if (buf_copy_size < fr_buf.len) return buf_copy_size; |
| 6033 | + assert(file_reader.logicalPos() == file_reader.pos); |
| 6034 | + |
| 6035 | + const w: *Writer = @fieldParentPtr("interface", interface); |
| 6036 | + const copy_size: usize = @intCast(w.mf.copyFileRange( |
| 6037 | + file_reader.file, |
| 6038 | + file_reader.pos, |
| 6039 | + w.ni.fileLocation(w.mf, true).offset + interface.end, |
| 6040 | + limit.minInt(interface.unusedCapacityLen()), |
| 6041 | + ) catch |err| { |
| 6042 | + w.err = err; |
| 6043 | + return error.WriteFailed; |
| 6044 | + }); |
| 6045 | + interface.end += copy_size; |
| 6046 | + return copy_size; |
| 6047 | + }, |
| 6048 | + .streaming, |
| 6049 | + .streaming_reading, |
| 6050 | + .positional_reading, |
| 6051 | + .failure, |
| 6052 | + => { |
| 6053 | + const dest = limit.slice(interface.unusedCapacitySlice()); |
| 6054 | + const n = try file_reader.read(dest); |
| 6055 | + interface.end += n; |
| 6056 | + return n; |
| 6057 | + }, |
| 6058 | + } |
| 6059 | + } |
| 6060 | + |
| 6061 | + fn growingRebase( |
| 6062 | + interface: *std.Io.Writer, |
| 6063 | + preserve: usize, |
| 6064 | + unused_capacity: usize, |
| 6065 | + ) std.Io.Writer.Error!void { |
| 6066 | + _ = preserve; |
| 6067 | + const total_capacity = interface.end + unused_capacity; |
| 6068 | + if (interface.buffer.len >= total_capacity) return; |
| 6069 | + const w: *Writer = @fieldParentPtr("interface", interface); |
| 6070 | + w.ni.resize(w.mf, w.gpa, total_capacity +| total_capacity / 2) catch |err| { |
| 6071 | + w.err = err; |
| 6072 | + return error.WriteFailed; |
| 6073 | + }; |
| 6074 | + } |
| 6075 | + }; |
| 6076 | + |
| 6077 | + comptime { |
| 6078 | + if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 32); |
| 6079 | + } |
| 6080 | +}; |
| 6081 | + |
| 6082 | +fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { |
| 6083 | + parent: Node.Index = .none, |
| 6084 | + prev: Node.Index = .none, |
| 6085 | + next: Node.Index = .none, |
| 6086 | + offset: u64 = 0, |
| 6087 | + add_node: AddNodeOptions, |
| 6088 | +}) !Node.Index { |
| 6089 | + if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 6090 | + const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); |
| 6091 | + const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { |
| 6092 | + if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ |
| 6093 | + .small = .{ .offset = small_offset, .size = 0 }, |
| 6094 | + } }; |
| 6095 | + try mf.large.ensureUnusedCapacity(gpa, 2); |
| 6096 | + defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 }); |
| 6097 | + break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; |
| 6098 | + }; |
| 6099 | + const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { |
| 6100 | + .none => .{ @enumFromInt(mf.nodes.items.len), mf.nodes.addOneAssumeCapacity() }, |
| 6101 | + else => |free_ni| { |
| 6102 | + const free_node = free_ni.get(mf); |
| 6103 | + mf.free_ni = free_node.next; |
| 6104 | + break :free .{ free_ni, free_node }; |
| 6105 | + }, |
| 6106 | + }; |
| 6107 | + free_node.* = .{ |
| 6108 | + .parent = opts.parent, |
| 6109 | + .prev = opts.prev, |
| 6110 | + .next = opts.next, |
| 6111 | + .first = .none, |
| 6112 | + .last = .none, |
| 6113 | + .flags = .{ |
| 6114 | + .location_tag = location_tag, |
| 6115 | + .alignment = opts.add_node.alignment, |
| 6116 | + .fixed = opts.add_node.fixed, |
| 6117 | + .moved = true, |
| 6118 | + .resized = true, |
| 6119 | + .has_content = false, |
| 6120 | + }, |
| 6121 | + .location_payload = location_payload, |
| 6122 | + }; |
| 6123 | + { |
| 6124 | + defer { |
| 6125 | + free_node.flags.moved = false; |
| 6126 | + free_node.flags.resized = false; |
| 6127 | + } |
| 6128 | + if (offset > opts.parent.location(mf).resolve(mf)[1]) try opts.parent.resize(mf, gpa, offset); |
| 6129 | + try free_ni.resize(mf, gpa, opts.add_node.size); |
| 6130 | + } |
| 6131 | + if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); |
| 6132 | + if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); |
| 6133 | + return free_ni; |
| 6134 | +} |
| 6135 | + |
| 6136 | +pub const AddNodeOptions = struct { |
| 6137 | + size: u64 = 0, |
| 6138 | + alignment: std.mem.Alignment = .@"1", |
| 6139 | + fixed: bool = false, |
| 6140 | + moved: bool = false, |
| 6141 | + resized: bool = false, |
| 6142 | +}; |
| 6143 | + |
| 6144 | +pub fn addOnlyChildNode( |
| 6145 | + mf: *MappedFile, |
| 6146 | + gpa: std.mem.Allocator, |
| 6147 | + parent_ni: Node.Index, |
| 6148 | + opts: AddNodeOptions, |
| 6149 | +) !Node.Index { |
| 6150 | + try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 6151 | + const parent = parent_ni.get(mf); |
| 6152 | + assert(parent.first == .none and parent.last == .none); |
| 6153 | + const ni = try mf.addNode(gpa, .{ |
| 6154 | + .parent = parent_ni, |
| 6155 | + .add_node = opts, |
| 6156 | + }); |
| 6157 | + parent.first = ni; |
| 6158 | + parent.last = ni; |
| 6159 | + return ni; |
| 6160 | +} |
| 6161 | + |
| 6162 | +pub fn addLastChildNode( |
| 6163 | + mf: *MappedFile, |
| 6164 | + gpa: std.mem.Allocator, |
| 6165 | + parent_ni: Node.Index, |
| 6166 | + opts: AddNodeOptions, |
| 6167 | +) !Node.Index { |
| 6168 | + try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 6169 | + const parent = parent_ni.get(mf); |
| 6170 | + const ni = try mf.addNode(gpa, .{ |
| 6171 | + .parent = parent_ni, |
| 6172 | + .prev = parent.last, |
| 6173 | + .offset = offset: switch (parent.last) { |
| 6174 | + .none => 0, |
| 6175 | + else => |last_ni| { |
| 6176 | + const last_offset, const last_size = last_ni.location(mf).resolve(mf); |
| 6177 | + break :offset last_offset + last_size; |
| 6178 | + }, |
| 6179 | + }, |
| 6180 | + .add_node = opts, |
| 6181 | + }); |
| 6182 | + switch (parent.last) { |
| 6183 | + .none => parent.first = ni, |
| 6184 | + else => |last_ni| last_ni.get(mf).next = ni, |
| 6185 | + } |
| 6186 | + parent.last = ni; |
| 6187 | + return ni; |
| 6188 | +} |
| 6189 | + |
| 6190 | +pub fn addNodeAfter( |
| 6191 | + mf: *MappedFile, |
| 6192 | + gpa: std.mem.Allocator, |
| 6193 | + prev_ni: Node.Index, |
| 6194 | + opts: AddNodeOptions, |
| 6195 | +) !Node.Index { |
| 6196 | + assert(prev_ni != .none); |
| 6197 | + try mf.nodes.ensureUnusedCapacity(gpa, 1); |
| 6198 | + const prev = prev_ni.get(mf); |
| 6199 | + const prev_offset, const prev_size = prev.location().resolve(mf); |
| 6200 | + const ni = try mf.addNode(gpa, .{ |
| 6201 | + .parent = prev.parent, |
| 6202 | + .prev = prev_ni, |
| 6203 | + .next = prev.next, |
| 6204 | + .offset = prev_offset + prev_size, |
| 6205 | + .add_node = opts, |
| 6206 | + }); |
| 6207 | + switch (prev.next) { |
| 6208 | + .none => prev.parent.get(mf).last = ni, |
| 6209 | + else => |next_ni| next_ni.get(mf).prev = ni, |
| 6210 | + } |
| 6211 | + prev.next = ni; |
| 6212 | + return ni; |
| 6213 | +} |
| 6214 | + |
| 6215 | +fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void { |
| 6216 | + const node = ni.get(mf); |
| 6217 | + var old_offset, const old_size = node.location().resolve(mf); |
| 6218 | + const new_size = node.flags.alignment.forward(@intCast(requested_size)); |
| 6219 | + // Resize the entire file |
| 6220 | + if (ni == Node.Index.root) { |
| 6221 | + try mf.file.setEndPos(new_size); |
| 6222 | + try mf.ensureTotalCapacity(@intCast(new_size)); |
| 6223 | + try mf.ensureCapacityForSetLocation(gpa); |
| 6224 | + ni.setLocationAssumeCapacity(mf, old_offset, new_size); |
| 6225 | + return; |
| 6226 | + } |
| 6227 | + while (true) { |
| 6228 | + const parent = node.parent.get(mf); |
| 6229 | + _, const old_parent_size = parent.location().resolve(mf); |
| 6230 | + const trailing_end = switch (node.next) { |
| 6231 | + .none => parent.location().resolve(mf)[1], |
| 6232 | + else => |next_ni| next_ni.location(mf).resolve(mf)[0], |
| 6233 | + }; |
| 6234 | + assert(old_offset + old_size <= trailing_end); |
| 6235 | + // Expand the node into available trailing free space |
| 6236 | + if (old_offset + new_size <= trailing_end) { |
| 6237 | + try mf.ensureCapacityForSetLocation(gpa); |
| 6238 | + ni.setLocationAssumeCapacity(mf, old_offset, new_size); |
| 6239 | + return; |
| 6240 | + } |
| 6241 | + // Ask the filesystem driver to insert an extent into the file without copying any data |
| 6242 | + if (is_linux and !mf.flags.fallocate_insert_range_unsupported and |
| 6243 | + node.flags.alignment.order(mf.flags.block_size).compare(.gte)) |
| 6244 | + insert_range: { |
| 6245 | + const last_offset, const last_size = parent.last.location(mf).resolve(mf); |
| 6246 | + const last_end = last_offset + last_size; |
| 6247 | + assert(last_end <= old_parent_size); |
| 6248 | + const range_size = |
| 6249 | + node.flags.alignment.forward(@intCast(requested_size +| requested_size / 2)) - old_size; |
| 6250 | + const new_parent_size = last_end + range_size; |
| 6251 | + if (new_parent_size > old_parent_size) { |
| 6252 | + try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2); |
| 6253 | + continue; |
| 6254 | + } |
| 6255 | + const range_file_offset = ni.fileLocation(mf, false).offset + old_size; |
| 6256 | + retry: while (true) { |
| 6257 | + switch (linux.E.init(linux.fallocate( |
| 6258 | + mf.file.handle, |
| 6259 | + linux.FALLOC.FL_INSERT_RANGE, |
| 6260 | + @intCast(range_file_offset), |
| 6261 | + @intCast(range_size), |
| 6262 | + ))) { |
| 6263 | + .SUCCESS => { |
| 6264 | + var enclosing_ni = ni; |
| 6265 | + while (enclosing_ni != .none) { |
| 6266 | + try mf.ensureCapacityForSetLocation(gpa); |
| 6267 | + const enclosing = enclosing_ni.get(mf); |
| 6268 | + const enclosing_offset, const enclosing_size = |
| 6269 | + enclosing.location().resolve(mf); |
| 6270 | + enclosing_ni.setLocationAssumeCapacity( |
| 6271 | + mf, |
| 6272 | + enclosing_offset, |
| 6273 | + enclosing_size + range_size, |
| 6274 | + ); |
| 6275 | + var after_ni = enclosing.next; |
| 6276 | + while (after_ni != .none) { |
| 6277 | + try mf.ensureCapacityForSetLocation(gpa); |
| 6278 | + const after = after_ni.get(mf); |
| 6279 | + const after_offset, const after_size = after.location().resolve(mf); |
| 6280 | + after_ni.setLocationAssumeCapacity( |
| 6281 | + mf, |
| 6282 | + range_size + after_offset, |
| 6283 | + after_size, |
| 6284 | + ); |
| 6285 | + after_ni = after.next; |
| 6286 | + } |
| 6287 | + enclosing_ni = enclosing.parent; |
| 6288 | + } |
| 6289 | + return; |
| 6290 | + }, |
| 6291 | + .INTR => continue :retry, |
| 6292 | + .BADF, .FBIG, .INVAL => unreachable, |
| 6293 | + .IO => return error.InputOutput, |
| 6294 | + .NODEV => return error.NotFile, |
| 6295 | + .NOSPC => return error.NoSpaceLeft, |
| 6296 | + .NOSYS, .OPNOTSUPP => { |
| 6297 | + mf.flags.fallocate_insert_range_unsupported = true; |
| 6298 | + break :insert_range; |
| 6299 | + }, |
| 6300 | + .PERM => return error.PermissionDenied, |
| 6301 | + .SPIPE => return error.Unseekable, |
| 6302 | + .TXTBSY => return error.FileBusy, |
| 6303 | + else => |e| return std.posix.unexpectedErrno(e), |
| 6304 | + } |
| 6305 | + } |
| 6306 | + } |
| 6307 | + switch (node.next) { |
| 6308 | + .none => { |
| 6309 | + // As this is the last node, we simply need more space in the parent |
| 6310 | + const new_parent_size = old_offset + new_size; |
| 6311 | + try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2); |
| 6312 | + }, |
| 6313 | + else => |*next_ni_ptr| switch (node.flags.fixed) { |
| 6314 | + false => { |
| 6315 | + // Make space at the end of the parent for this floating node |
| 6316 | + const last = parent.last.get(mf); |
| 6317 | + const last_offset, const last_size = last.location().resolve(mf); |
| 6318 | + const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size)); |
| 6319 | + const new_parent_size = new_offset + new_size; |
| 6320 | + if (new_parent_size > old_parent_size) { |
| 6321 | + try mf.resizeNode( |
| 6322 | + gpa, |
| 6323 | + node.parent, |
| 6324 | + new_parent_size +| new_parent_size / 2, |
| 6325 | + ); |
| 6326 | + continue; |
| 6327 | + } |
| 6328 | + const next_ni = next_ni_ptr.*; |
| 6329 | + next_ni.get(mf).prev = node.prev; |
| 6330 | + switch (node.prev) { |
| 6331 | + .none => parent.first = next_ni, |
| 6332 | + else => |prev_ni| prev_ni.get(mf).next = next_ni, |
| 6333 | + } |
| 6334 | + last.next = ni; |
| 6335 | + node.prev = parent.last; |
| 6336 | + next_ni_ptr.* = .none; |
| 6337 | + parent.last = ni; |
| 6338 | + if (node.flags.has_content) { |
| 6339 | + const parent_file_offset = node.parent.fileLocation(mf, false).offset; |
| 6340 | + try mf.moveRange( |
| 6341 | + parent_file_offset + old_offset, |
| 6342 | + parent_file_offset + new_offset, |
| 6343 | + old_size, |
| 6344 | + ); |
| 6345 | + } |
| 6346 | + old_offset = new_offset; |
| 6347 | + }, |
| 6348 | + true => { |
| 6349 | + // Move the next floating node to make space for this fixed node |
| 6350 | + const next_ni = next_ni_ptr.*; |
| 6351 | + const next = next_ni.get(mf); |
| 6352 | + assert(!next.flags.fixed); |
| 6353 | + const next_offset, const next_size = next.location().resolve(mf); |
| 6354 | + const last = parent.last.get(mf); |
| 6355 | + const last_offset, const last_size = last.location().resolve(mf); |
| 6356 | + const new_offset = next.flags.alignment.forward(@intCast( |
| 6357 | + @max(old_offset + new_size, last_offset + last_size), |
| 6358 | + )); |
| 6359 | + const new_parent_size = new_offset + next_size; |
| 6360 | + if (new_parent_size > old_parent_size) { |
| 6361 | + try mf.resizeNode( |
| 6362 | + gpa, |
| 6363 | + node.parent, |
| 6364 | + new_parent_size +| new_parent_size / 2, |
| 6365 | + ); |
| 6366 | + continue; |
| 6367 | + } |
| 6368 | + try mf.ensureCapacityForSetLocation(gpa); |
| 6369 | + next.prev = parent.last; |
| 6370 | + parent.last = next_ni; |
| 6371 | + last.next = next_ni; |
| 6372 | + next_ni_ptr.* = next.next; |
| 6373 | + switch (next.next) { |
| 6374 | + .none => {}, |
| 6375 | + else => |next_next_ni| next_next_ni.get(mf).prev = ni, |
| 6376 | + } |
| 6377 | + next.next = .none; |
| 6378 | + if (node.flags.has_content) { |
| 6379 | + const parent_file_offset = node.parent.fileLocation(mf, false).offset; |
| 6380 | + try mf.moveRange( |
| 6381 | + parent_file_offset + next_offset, |
| 6382 | + parent_file_offset + new_offset, |
| 6383 | + next_size, |
| 6384 | + ); |
| 6385 | + } |
| 6386 | + next_ni.setLocationAssumeCapacity(mf, new_offset, next_size); |
| 6387 | + }, |
| 6388 | + }, |
| 6389 | + } |
| 6390 | + } |
| 6391 | +} |
| 6392 | + |
| 6393 | +fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { |
| 6394 | + // make a copy of this node at the new location |
| 6395 | + try mf.copyRange(old_file_offset, new_file_offset, size); |
| 6396 | + // delete the copy of this node at the old location |
| 6397 | + if (is_linux and !mf.flags.fallocate_punch_hole_unsupported and |
| 6398 | + size >= mf.flags.block_size.toByteUnits() * 2 - 1) while (true) |
| 6399 | + { |
| 6400 | + switch (linux.E.init(linux.fallocate( |
| 6401 | + mf.file.handle, |
| 6402 | + linux.FALLOC.FL_PUNCH_HOLE | linux.FALLOC.FL_KEEP_SIZE, |
| 6403 | + @intCast(old_file_offset), |
| 6404 | + @intCast(size), |
| 6405 | + ))) { |
| 6406 | + .SUCCESS => return, |
| 6407 | + .INTR => continue, |
| 6408 | + .BADF, .FBIG, .INVAL => unreachable, |
| 6409 | + .IO => return error.InputOutput, |
| 6410 | + .NODEV => return error.NotFile, |
| 6411 | + .NOSPC => return error.NoSpaceLeft, |
| 6412 | + .NOSYS, .OPNOTSUPP => { |
| 6413 | + mf.flags.fallocate_punch_hole_unsupported = true; |
| 6414 | + break; |
| 6415 | + }, |
| 6416 | + .PERM => return error.PermissionDenied, |
| 6417 | + .SPIPE => return error.Unseekable, |
| 6418 | + .TXTBSY => return error.FileBusy, |
| 6419 | + else => |e| return std.posix.unexpectedErrno(e), |
| 6420 | + } |
| 6421 | + }; |
| 6422 | + @memset(mf.contents[@intCast(old_file_offset)..][0..@intCast(size)], 0); |
| 6423 | +} |
| 6424 | + |
| 6425 | +fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { |
| 6426 | + const copy_size = try mf.copyFileRange(mf.file, old_file_offset, new_file_offset, size); |
| 6427 | + if (copy_size < size) @memcpy( |
| 6428 | + mf.contents[@intCast(new_file_offset + copy_size)..][0..@intCast(size - copy_size)], |
| 6429 | + mf.contents[@intCast(old_file_offset + copy_size)..][0..@intCast(size - copy_size)], |
| 6430 | + ); |
| 6431 | +} |
| 6432 | + |
| 6433 | +fn copyFileRange( |
| 6434 | + mf: *MappedFile, |
| 6435 | + old_file: std.fs.File, |
| 6436 | + old_file_offset: u64, |
| 6437 | + new_file_offset: u64, |
| 6438 | + size: u64, |
| 6439 | +) !u64 { |
| 6440 | + var remaining_size = size; |
| 6441 | + if (is_linux and !mf.flags.copy_file_range_unsupported) { |
| 6442 | + var old_file_offset_mut: i64 = @intCast(old_file_offset); |
| 6443 | + var new_file_offset_mut: i64 = @intCast(new_file_offset); |
| 6444 | + while (remaining_size >= mf.flags.block_size.toByteUnits() * 2 - 1) { |
| 6445 | + const copy_len = linux.copy_file_range( |
| 6446 | + old_file.handle, |
| 6447 | + &old_file_offset_mut, |
| 6448 | + mf.file.handle, |
| 6449 | + &new_file_offset_mut, |
| 6450 | + @intCast(remaining_size), |
| 6451 | + 0, |
| 6452 | + ); |
| 6453 | + switch (linux.E.init(copy_len)) { |
| 6454 | + .SUCCESS => { |
| 6455 | + if (copy_len == 0) break; |
| 6456 | + remaining_size -= copy_len; |
| 6457 | + if (remaining_size == 0) break; |
| 6458 | + }, |
| 6459 | + .INTR => continue, |
| 6460 | + .BADF, .FBIG, .INVAL, .OVERFLOW => unreachable, |
| 6461 | + .IO => return error.InputOutput, |
| 6462 | + .ISDIR => return error.IsDir, |
| 6463 | + .NOMEM => return error.SystemResources, |
| 6464 | + .NOSPC => return error.NoSpaceLeft, |
| 6465 | + .NOSYS, .OPNOTSUPP, .XDEV => { |
| 6466 | + mf.flags.copy_file_range_unsupported = true; |
| 6467 | + break; |
| 6468 | + }, |
| 6469 | + .PERM => return error.PermissionDenied, |
| 6470 | + .TXTBSY => return error.FileBusy, |
| 6471 | + else => |e| return std.posix.unexpectedErrno(e), |
| 6472 | + } |
| 6473 | + } |
| 6474 | + } |
| 6475 | + return size - remaining_size; |
| 6476 | +} |
| 6477 | + |
| 6478 | +fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) !void { |
| 6479 | + try mf.large.ensureUnusedCapacity(gpa, 2); |
| 6480 | + try mf.updates.ensureUnusedCapacity(gpa, 1); |
| 6481 | +} |
| 6482 | + |
| 6483 | +pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) !void { |
| 6484 | + if (mf.contents.len >= new_capacity) return; |
| 6485 | + try mf.ensureTotalCapacityPrecise(new_capacity +| new_capacity / 2); |
| 6486 | +} |
| 6487 | + |
| 6488 | +pub fn ensureTotalCapacityPrecise(mf: *MappedFile, new_capacity: usize) !void { |
| 6489 | + if (mf.contents.len >= new_capacity) return; |
| 6490 | + const aligned_capacity = mf.flags.block_size.forward(new_capacity); |
| 6491 | + if (!is_linux) mf.unmap() else if (mf.contents.len > 0) { |
| 6492 | + mf.contents = try std.posix.mremap( |
| 6493 | + mf.contents.ptr, |
| 6494 | + mf.contents.len, |
| 6495 | + aligned_capacity, |
| 6496 | + .{ .MAYMOVE = true }, |
| 6497 | + null, |
| 6498 | + ); |
| 6499 | + return; |
| 6500 | + } |
| 6501 | + if (is_windows) { |
| 6502 | + if (mf.section == windows.INVALID_HANDLE_VALUE) switch (windows.ntdll.NtCreateSection( |
| 6503 | + &mf.section, |
| 6504 | + windows.STANDARD_RIGHTS_REQUIRED | windows.SECTION_QUERY | |
| 6505 | + windows.SECTION_MAP_WRITE | windows.SECTION_MAP_READ | windows.SECTION_EXTEND_SIZE, |
| 6506 | + null, |
| 6507 | + @constCast(&@as(i64, @intCast(aligned_capacity))), |
| 6508 | + windows.PAGE_READWRITE, |
| 6509 | + windows.SEC_COMMIT, |
| 6510 | + mf.file.handle, |
| 6511 | + )) { |
| 6512 | + .SUCCESS => {}, |
| 6513 | + else => return error.MemoryMappingNotSupported, |
| 6514 | + }; |
| 6515 | + var contents_ptr: ?[*]align(std.heap.page_size_min) u8 = null; |
| 6516 | + var contents_len = aligned_capacity; |
| 6517 | + switch (windows.ntdll.NtMapViewOfSection( |
| 6518 | + mf.section, |
| 6519 | + windows.GetCurrentProcess(), |
| 6520 | + @ptrCast(&contents_ptr), |
| 6521 | + null, |
| 6522 | + 0, |
| 6523 | + null, |
| 6524 | + &contents_len, |
| 6525 | + .ViewUnmap, |
| 6526 | + 0, |
| 6527 | + windows.PAGE_READWRITE, |
| 6528 | + )) { |
| 6529 | + .SUCCESS => mf.contents = contents_ptr.?[0..contents_len], |
| 6530 | + else => return error.MemoryMappingNotSupported, |
| 6531 | + } |
| 6532 | + } else mf.contents = try std.posix.mmap( |
| 6533 | + null, |
| 6534 | + aligned_capacity, |
| 6535 | + std.posix.PROT.READ | std.posix.PROT.WRITE, |
| 6536 | + .{ .TYPE = if (is_linux) .SHARED_VALIDATE else .SHARED }, |
| 6537 | + mf.file.handle, |
| 6538 | + 0, |
| 6539 | + ); |
| 6540 | +} |
| 6541 | + |
| 6542 | +pub fn unmap(mf: *MappedFile) void { |
| 6543 | + if (mf.contents.len == 0) return; |
| 6544 | + if (is_windows) |
| 6545 | + _ = windows.ntdll.NtUnmapViewOfSection(windows.GetCurrentProcess(), mf.contents.ptr) |
| 6546 | + else |
| 6547 | + std.posix.munmap(mf.contents); |
| 6548 | + mf.contents = &.{}; |
| 6549 | + if (is_windows and mf.section != windows.INVALID_HANDLE_VALUE) { |
| 6550 | + windows.CloseHandle(mf.section); |
| 6551 | + mf.section = windows.INVALID_HANDLE_VALUE; |
| 6552 | + } |
| 6553 | +} |
| 6554 | + |
| 6555 | +fn verify(mf: *MappedFile) void { |
| 6556 | + const root = Node.Index.root.get(mf); |
| 6557 | + assert(root.parent == .none); |
| 6558 | + assert(root.prev == .none); |
| 6559 | + assert(root.next == .none); |
| 6560 | + mf.verifyNode(Node.Index.root); |
| 6561 | +} |
| 6562 | + |
| 6563 | +fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void { |
| 6564 | + const parent = parent_ni.get(mf); |
| 6565 | + const parent_offset, const parent_size = parent.location().resolve(mf); |
| 6566 | + var prev_ni: Node.Index = .none; |
| 6567 | + var prev_end: u64 = 0; |
| 6568 | + var ni = parent.first; |
| 6569 | + while (true) { |
| 6570 | + if (ni == .none) { |
| 6571 | + assert(parent.last == prev_ni); |
| 6572 | + return; |
| 6573 | + } |
| 6574 | + const node = ni.get(mf); |
| 6575 | + assert(node.parent == parent_ni); |
| 6576 | + const offset, const size = node.location().resolve(mf); |
| 6577 | + assert(node.flags.alignment.check(@intCast(offset))); |
| 6578 | + assert(node.flags.alignment.check(@intCast(size))); |
| 6579 | + const end = offset + size; |
| 6580 | + assert(end <= parent_offset + parent_size); |
| 6581 | + assert(offset >= prev_end); |
| 6582 | + assert(node.prev == prev_ni); |
| 6583 | + mf.verifyNode(ni); |
| 6584 | + prev_ni = ni; |
| 6585 | + prev_end = end; |
| 6586 | + ni = node.next; |
| 6587 | + } |
| 6588 | +} |
| 6589 | + |
| 6590 | +const assert = std.debug.assert; |
| 6591 | +const builtin = @import("builtin"); |
| 6592 | +const is_linux = builtin.os.tag == .linux; |
| 6593 | +const is_windows = builtin.os.tag == .windows; |
| 6594 | +const linux = std.os.linux; |
| 6595 | +const MappedFile = @This(); |
| 6596 | +const std = @import("std"); |
| 6597 | +const windows = std.os.windows; |
| 6598 | diff --git a/src/link/Queue.zig b/src/link/Queue.zig |
| 6599 | index 9f4535e1fe..742b4664f1 100644 |
| 6600 | --- a/src/link/Queue.zig |
| 6601 | +++ b/src/link/Queue.zig |
| 6602 | @@ -22,17 +22,17 @@ prelink_wait_count: u32, |
| 6603 | |
| 6604 | /// Prelink tasks which have been enqueued and are not yet owned by the worker thread. |
| 6605 | /// Allocated into `gpa`, guarded by `mutex`. |
| 6606 | -queued_prelink: std.ArrayListUnmanaged(PrelinkTask), |
| 6607 | +queued_prelink: std.ArrayList(PrelinkTask), |
| 6608 | /// The worker thread moves items from `queued_prelink` into this array in order to process them. |
| 6609 | /// Allocated into `gpa`, accessed only by the worker thread. |
| 6610 | -wip_prelink: std.ArrayListUnmanaged(PrelinkTask), |
| 6611 | +wip_prelink: std.ArrayList(PrelinkTask), |
| 6612 | |
| 6613 | /// Like `queued_prelink`, but for ZCU tasks. |
| 6614 | /// Allocated into `gpa`, guarded by `mutex`. |
| 6615 | -queued_zcu: std.ArrayListUnmanaged(ZcuTask), |
| 6616 | +queued_zcu: std.ArrayList(ZcuTask), |
| 6617 | /// Like `wip_prelink`, but for ZCU tasks. |
| 6618 | /// Allocated into `gpa`, accessed only by the worker thread. |
| 6619 | -wip_zcu: std.ArrayListUnmanaged(ZcuTask), |
| 6620 | +wip_zcu: std.ArrayList(ZcuTask), |
| 6621 | |
| 6622 | /// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this |
| 6623 | /// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the |
| 6624 | @@ -213,32 +213,41 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error! |
| 6625 | |
| 6626 | fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 6627 | q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex` |
| 6628 | - |
| 6629 | if (std.debug.runtime_safety) { |
| 6630 | q.mutex.lock(); |
| 6631 | defer q.mutex.unlock(); |
| 6632 | assert(q.state == .running); |
| 6633 | } |
| 6634 | + |
| 6635 | + var have_idle_tasks = true; |
| 6636 | prelink: while (true) { |
| 6637 | assert(q.wip_prelink.items.len == 0); |
| 6638 | - { |
| 6639 | - q.mutex.lock(); |
| 6640 | - defer q.mutex.unlock(); |
| 6641 | - std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink); |
| 6642 | - if (q.wip_prelink.items.len == 0) { |
| 6643 | - if (q.prelink_wait_count == 0) { |
| 6644 | - break :prelink; // prelink is done |
| 6645 | - } else { |
| 6646 | + swap_queues: while (true) { |
| 6647 | + { |
| 6648 | + q.mutex.lock(); |
| 6649 | + defer q.mutex.unlock(); |
| 6650 | + std.mem.swap(std.ArrayList(PrelinkTask), &q.queued_prelink, &q.wip_prelink); |
| 6651 | + if (q.wip_prelink.items.len > 0) break :swap_queues; |
| 6652 | + if (q.prelink_wait_count == 0) break :prelink; // prelink is done |
| 6653 | + if (!have_idle_tasks) { |
| 6654 | // We're expecting more prelink tasks so can't move on to ZCU tasks. |
| 6655 | q.state = .finished; |
| 6656 | q.flush_safety.unlock(); |
| 6657 | return; |
| 6658 | } |
| 6659 | } |
| 6660 | + have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { |
| 6661 | + error.OutOfMemory => have_idle_tasks: { |
| 6662 | + comp.link_diags.setAllocFailure(); |
| 6663 | + break :have_idle_tasks false; |
| 6664 | + }, |
| 6665 | + error.LinkFailure => false, |
| 6666 | + }; |
| 6667 | } |
| 6668 | for (q.wip_prelink.items) |task| { |
| 6669 | link.doPrelinkTask(comp, task); |
| 6670 | } |
| 6671 | + have_idle_tasks = true; |
| 6672 | q.wip_prelink.clearRetainingCapacity(); |
| 6673 | } |
| 6674 | |
| 6675 | @@ -256,17 +265,29 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 6676 | |
| 6677 | // Now we can run ZCU tasks. |
| 6678 | while (true) { |
| 6679 | - if (q.wip_zcu.items.len == q.wip_zcu_idx) { |
| 6680 | + if (q.wip_zcu.items.len == q.wip_zcu_idx) swap_queues: { |
| 6681 | q.wip_zcu.clearRetainingCapacity(); |
| 6682 | q.wip_zcu_idx = 0; |
| 6683 | - q.mutex.lock(); |
| 6684 | - defer q.mutex.unlock(); |
| 6685 | - std.mem.swap(std.ArrayListUnmanaged(ZcuTask), &q.queued_zcu, &q.wip_zcu); |
| 6686 | - if (q.wip_zcu.items.len == 0) { |
| 6687 | - // We've exhausted all available tasks. |
| 6688 | - q.state = .finished; |
| 6689 | - q.flush_safety.unlock(); |
| 6690 | - return; |
| 6691 | + while (true) { |
| 6692 | + { |
| 6693 | + q.mutex.lock(); |
| 6694 | + defer q.mutex.unlock(); |
| 6695 | + std.mem.swap(std.ArrayList(ZcuTask), &q.queued_zcu, &q.wip_zcu); |
| 6696 | + if (q.wip_zcu.items.len > 0) break :swap_queues; |
| 6697 | + if (!have_idle_tasks) { |
| 6698 | + // We've exhausted all available tasks. |
| 6699 | + q.state = .finished; |
| 6700 | + q.flush_safety.unlock(); |
| 6701 | + return; |
| 6702 | + } |
| 6703 | + } |
| 6704 | + have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { |
| 6705 | + error.OutOfMemory => have_idle_tasks: { |
| 6706 | + comp.link_diags.setAllocFailure(); |
| 6707 | + break :have_idle_tasks false; |
| 6708 | + }, |
| 6709 | + error.LinkFailure => false, |
| 6710 | + }; |
| 6711 | } |
| 6712 | } |
| 6713 | const task = q.wip_zcu.items[q.wip_zcu_idx]; |
| 6714 | @@ -274,8 +295,18 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 6715 | pending: { |
| 6716 | if (task != .link_func) break :pending; |
| 6717 | const status_ptr = &task.link_func.mir.status; |
| 6718 | - // First check without the mutex to optimize for the common case where MIR is ready. |
| 6719 | - if (status_ptr.load(.acquire) != .pending) break :pending; |
| 6720 | + while (true) { |
| 6721 | + // First check without the mutex to optimize for the common case where MIR is ready. |
| 6722 | + if (status_ptr.load(.acquire) != .pending) break :pending; |
| 6723 | + if (have_idle_tasks) have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { |
| 6724 | + error.OutOfMemory => have_idle_tasks: { |
| 6725 | + comp.link_diags.setAllocFailure(); |
| 6726 | + break :have_idle_tasks false; |
| 6727 | + }, |
| 6728 | + error.LinkFailure => false, |
| 6729 | + }; |
| 6730 | + if (!have_idle_tasks) break; |
| 6731 | + } |
| 6732 | q.mutex.lock(); |
| 6733 | defer q.mutex.unlock(); |
| 6734 | if (status_ptr.load(.acquire) != .pending) break :pending; |
| 6735 | @@ -298,6 +329,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 6736 | } |
| 6737 | } |
| 6738 | q.wip_zcu_idx += 1; |
| 6739 | + have_idle_tasks = true; |
| 6740 | } |
| 6741 | } |
| 6742 | |
| 6743 | diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig |
| 6744 | index a125a70aae..d60b91c30f 100644 |
| 6745 | --- a/src/link/Wasm.zig |
| 6746 | +++ b/src/link/Wasm.zig |
| 6747 | @@ -4257,7 +4257,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu |
| 6748 | const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len); |
| 6749 | wasm.string_bytes_lock.lock(); |
| 6750 | |
| 6751 | - try codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &wasm.string_bytes, .none); |
| 6752 | + { |
| 6753 | + var aw: std.Io.Writer.Allocating = .fromArrayList(wasm.base.comp.gpa, &wasm.string_bytes); |
| 6754 | + defer wasm.string_bytes = aw.toArrayList(); |
| 6755 | + codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &aw.writer, .none) catch |err| switch (err) { |
| 6756 | + error.WriteFailed => return error.OutOfMemory, |
| 6757 | + else => |e| return e, |
| 6758 | + }; |
| 6759 | + } |
| 6760 | |
| 6761 | const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start); |
| 6762 | const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start); |
| 6763 | diff --git a/src/main.zig b/src/main.zig |
| 6764 | index 26d44c4463..9d43e47ea2 100644 |
| 6765 | --- a/src/main.zig |
| 6766 | +++ b/src/main.zig |
| 6767 | @@ -904,7 +904,6 @@ fn buildOutputType( |
| 6768 | var mingw_unicode_entry_point: bool = false; |
| 6769 | var enable_link_snapshots: bool = false; |
| 6770 | var debug_compiler_runtime_libs = false; |
| 6771 | - var opt_incremental: ?bool = null; |
| 6772 | var install_name: ?[]const u8 = null; |
| 6773 | var hash_style: link.File.Lld.Elf.HashStyle = .both; |
| 6774 | var entitlements: ?[]const u8 = null; |
| 6775 | @@ -1374,9 +1373,9 @@ fn buildOutputType( |
| 6776 | } |
| 6777 | } else if (mem.eql(u8, arg, "-fincremental")) { |
| 6778 | dev.check(.incremental); |
| 6779 | - opt_incremental = true; |
| 6780 | + create_module.opts.incremental = true; |
| 6781 | } else if (mem.eql(u8, arg, "-fno-incremental")) { |
| 6782 | - opt_incremental = false; |
| 6783 | + create_module.opts.incremental = false; |
| 6784 | } else if (mem.eql(u8, arg, "--entitlements")) { |
| 6785 | entitlements = args_iter.nextOrFatal(); |
| 6786 | } else if (mem.eql(u8, arg, "-fcompiler-rt")) { |
| 6787 | @@ -1479,6 +1478,10 @@ fn buildOutputType( |
| 6788 | create_module.opts.use_lld = true; |
| 6789 | } else if (mem.eql(u8, arg, "-fno-lld")) { |
| 6790 | create_module.opts.use_lld = false; |
| 6791 | + } else if (mem.eql(u8, arg, "-fnew-linker")) { |
| 6792 | + create_module.opts.use_new_linker = true; |
| 6793 | + } else if (mem.eql(u8, arg, "-fno-new-linker")) { |
| 6794 | + create_module.opts.use_new_linker = false; |
| 6795 | } else if (mem.eql(u8, arg, "-fclang")) { |
| 6796 | create_module.opts.use_clang = true; |
| 6797 | } else if (mem.eql(u8, arg, "-fno-clang")) { |
| 6798 | @@ -3371,7 +3374,7 @@ fn buildOutputType( |
| 6799 | else => false, |
| 6800 | }; |
| 6801 | |
| 6802 | - const incremental = opt_incremental orelse false; |
| 6803 | + const incremental = create_module.resolved_options.incremental; |
| 6804 | if (debug_incremental and !incremental) { |
| 6805 | fatal("--debug-incremental requires -fincremental", .{}); |
| 6806 | } |
| 6807 | @@ -3502,7 +3505,6 @@ fn buildOutputType( |
| 6808 | .subsystem = subsystem, |
| 6809 | .debug_compile_errors = debug_compile_errors, |
| 6810 | .debug_incremental = debug_incremental, |
| 6811 | - .incremental = incremental, |
| 6812 | .enable_link_snapshots = enable_link_snapshots, |
| 6813 | .install_name = install_name, |
| 6814 | .entitlements = entitlements, |
| 6815 | @@ -4016,6 +4018,8 @@ fn createModule( |
| 6816 | error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}), |
| 6817 | error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}), |
| 6818 | error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}), |
| 6819 | + error.NewLinkerIncompatibleObjectFormat => fatal("using the new linker to link {s} files is unsupported", .{@tagName(target.ofmt)}), |
| 6820 | + error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}), |
| 6821 | }; |
| 6822 | } |
| 6823 | |
| 6824 | diff --git a/src/target.zig b/src/target.zig |
| 6825 | index e999d2ae22..1cf5c9b082 100644 |
| 6826 | --- a/src/target.zig |
| 6827 | +++ b/src/target.zig |
| 6828 | @@ -231,6 +231,13 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { |
| 6829 | }; |
| 6830 | } |
| 6831 | |
| 6832 | +pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat) bool { |
| 6833 | + return switch (ofmt) { |
| 6834 | + .elf => true, |
| 6835 | + else => false, |
| 6836 | + }; |
| 6837 | +} |
| 6838 | + |
| 6839 | /// The set of targets that our own self-hosted backends have robust support for. |
| 6840 | /// Used to select between LLVM backend and self-hosted backend when compiling in |
| 6841 | /// debug mode. A given target should only return true here if it is passing greater |
| 6842 | diff --git a/test/incremental/change_exports b/test/incremental/change_exports |
| 6843 | index 01605bdeeb..e492930031 100644 |
| 6844 | --- a/test/incremental/change_exports |
| 6845 | +++ b/test/incremental/change_exports |
| 6846 | @@ -1,4 +1,4 @@ |
| 6847 | -//#target=x86_64-linux-selfhosted |
| 6848 | +#target=x86_64-linux-selfhosted |
| 6849 | #target=x86_64-linux-cbe |
| 6850 | #target=x86_64-windows-cbe |
| 6851 | |
| 6852 | diff --git a/test/incremental/change_panic_handler b/test/incremental/change_panic_handler |
| 6853 | index 3e400b854e..699134100e 100644 |
| 6854 | --- a/test/incremental/change_panic_handler |
| 6855 | +++ b/test/incremental/change_panic_handler |
| 6856 | @@ -1,3 +1,4 @@ |
| 6857 | +#target=x86_64-linux-selfhosted |
| 6858 | #target=x86_64-linux-cbe |
| 6859 | #target=x86_64-windows-cbe |
| 6860 | #update=initial version |
| 6861 | diff --git a/test/incremental/change_panic_handler_explicit b/test/incremental/change_panic_handler_explicit |
| 6862 | index 9f7eb6c12f..2d068d593e 100644 |
| 6863 | --- a/test/incremental/change_panic_handler_explicit |
| 6864 | +++ b/test/incremental/change_panic_handler_explicit |
| 6865 | @@ -1,3 +1,4 @@ |
| 6866 | +#target=x86_64-linux-selfhosted |
| 6867 | #target=x86_64-linux-cbe |
| 6868 | #target=x86_64-windows-cbe |
| 6869 | #update=initial version |
| 6870 | diff --git a/test/incremental/change_struct_same_fields b/test/incremental/change_struct_same_fields |
| 6871 | index 97049a1fc0..f3bfbbdd69 100644 |
| 6872 | --- a/test/incremental/change_struct_same_fields |
| 6873 | +++ b/test/incremental/change_struct_same_fields |
| 6874 | @@ -1,4 +1,4 @@ |
| 6875 | -//#target=x86_64-linux-selfhosted |
| 6876 | +#target=x86_64-linux-selfhosted |
| 6877 | #target=x86_64-linux-cbe |
| 6878 | #target=x86_64-windows-cbe |
| 6879 | #target=wasm32-wasi-selfhosted |
| 6880 | diff --git a/test/incremental/type_becomes_comptime_only b/test/incremental/type_becomes_comptime_only |
| 6881 | index 5c5d332975..3bcae1cd21 100644 |
| 6882 | --- a/test/incremental/type_becomes_comptime_only |
| 6883 | +++ b/test/incremental/type_becomes_comptime_only |
| 6884 | @@ -1,3 +1,4 @@ |
| 6885 | +#target=x86_64-linux-selfhosted |
| 6886 | #target=x86_64-linux-cbe |
| 6887 | #target=x86_64-windows-cbe |
| 6888 | #target=wasm32-wasi-selfhosted |