| author | |
| committer | |
| log | f58200e3f2967a06f343c9fc9dcae9de18def92a |
| tree | 84257e40a7a0186fbc10cf7467e65f004036d3e3 |
| parent | 2a97e0af6d42e038d962890a320e262e676d44cb |
This iteration already has significantly better incremental support.
Closes #2411045 files changed, 4141 insertions(+), 536 deletions(-)
CMakeLists.txt+2| ... | @@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -583,6 +583,7 @@ set(ZIG_STAGE2_SOURCES |
| 583 | src/link/Elf/relocatable.zig | 583 | src/link/Elf/relocatable.zig |
| 584 | src/link/Elf/relocation.zig | 584 | src/link/Elf/relocation.zig |
| 585 | src/link/Elf/synthetic_sections.zig | 585 | src/link/Elf/synthetic_sections.zig |
| 586 | src/link/Elf2.zig | ||
| 586 | src/link/Goff.zig | 587 | src/link/Goff.zig |
| 587 | src/link/LdScript.zig | 588 | src/link/LdScript.zig |
| 588 | src/link/Lld.zig | 589 | src/link/Lld.zig |
| ... | @@ -612,6 +613,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -612,6 +613,7 @@ set(ZIG_STAGE2_SOURCES |
| 612 | src/link/MachO/synthetic.zig | 613 | src/link/MachO/synthetic.zig |
| 613 | src/link/MachO/Thunk.zig | 614 | src/link/MachO/Thunk.zig |
| 614 | src/link/MachO/uuid.zig | 615 | src/link/MachO/uuid.zig |
| 616 | src/link/MappedFile.zig | ||
| 615 | src/link/Queue.zig | 617 | src/link/Queue.zig |
| 616 | src/link/StringTable.zig | 618 | src/link/StringTable.zig |
| 617 | src/link/Wasm.zig | 619 | src/link/Wasm.zig |
build.zig+1| ... | @@ -202,6 +202,7 @@ pub fn build(b: *std.Build) !void { | ... | @@ -202,6 +202,7 @@ pub fn build(b: *std.Build) !void { |
| 202 | }); | 202 | }); |
| 203 | exe.pie = pie; | 203 | exe.pie = pie; |
| 204 | exe.entitlements = entitlements; | 204 | exe.entitlements = entitlements; |
| 205 | exe.use_new_linker = b.option(bool, "new-linker", "Use the new linker"); | ||
| 205 | 206 | ||
| 206 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); | 207 | const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend"); |
| 207 | exe.use_llvm = use_llvm; | 208 | exe.use_llvm = use_llvm; |
ci/x86_64-linux-debug-llvm.sh created100644→100755lib/compiler_rt/fma.zig+4-4| ... | @@ -203,7 +203,7 @@ fn add_adjusted(a: f64, b: f64) f64 { | ... | @@ -203,7 +203,7 @@ fn add_adjusted(a: f64, b: f64) f64 { |
| 203 | if (uhii & 1 == 0) { | 203 | if (uhii & 1 == 0) { |
| 204 | // hibits += copysign(1.0, sum.hi, sum.lo) | 204 | // hibits += copysign(1.0, sum.hi, sum.lo) |
| 205 | const uloi: u64 = @bitCast(sum.lo); | 205 | const uloi: u64 = @bitCast(sum.lo); |
| 206 | uhii += 1 - ((uhii ^ uloi) >> 62); | 206 | uhii = uhii + 1 - ((uhii ^ uloi) >> 62); |
| 207 | sum.hi = @bitCast(uhii); | 207 | sum.hi = @bitCast(uhii); |
| 208 | } | 208 | } |
| 209 | } | 209 | } |
| ... | @@ -217,7 +217,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { | ... | @@ -217,7 +217,7 @@ fn add_and_denorm(a: f64, b: f64, scale: i32) f64 { |
| 217 | const bits_lost = -@as(i32, @intCast((uhii >> 52) & 0x7FF)) - scale + 1; | 217 | const bits_lost = -@as(i32, @intCast((uhii >> 52) & 0x7FF)) - scale + 1; |
| 218 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | 218 | if ((bits_lost != 1) == (uhii & 1 != 0)) { |
| 219 | const uloi: u64 = @bitCast(sum.lo); | 219 | const uloi: u64 = @bitCast(sum.lo); |
| 220 | uhii += 1 - (((uhii ^ uloi) >> 62) & 2); | 220 | uhii = uhii + 1 - (((uhii ^ uloi) >> 62) & 2); |
| 221 | sum.hi = @bitCast(uhii); | 221 | sum.hi = @bitCast(uhii); |
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| ... | @@ -259,7 +259,7 @@ fn add_adjusted128(a: f128, b: f128) f128 { | ... | @@ -259,7 +259,7 @@ fn add_adjusted128(a: f128, b: f128) f128 { |
| 259 | if (uhii & 1 == 0) { | 259 | if (uhii & 1 == 0) { |
| 260 | // hibits += copysign(1.0, sum.hi, sum.lo) | 260 | // hibits += copysign(1.0, sum.hi, sum.lo) |
| 261 | const uloi: u128 = @bitCast(sum.lo); | 261 | const uloi: u128 = @bitCast(sum.lo); |
| 262 | uhii += 1 - ((uhii ^ uloi) >> 126); | 262 | uhii = uhii + 1 - ((uhii ^ uloi) >> 126); |
| 263 | sum.hi = @bitCast(uhii); | 263 | sum.hi = @bitCast(uhii); |
| 264 | } | 264 | } |
| 265 | } | 265 | } |
| ... | @@ -284,7 +284,7 @@ fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 { | ... | @@ -284,7 +284,7 @@ fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 { |
| 284 | const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1; | 284 | const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1; |
| 285 | if ((bits_lost != 1) == (uhii & 1 != 0)) { | 285 | if ((bits_lost != 1) == (uhii & 1 != 0)) { |
| 286 | const uloi: u128 = @bitCast(sum.lo); | 286 | const uloi: u128 = @bitCast(sum.lo); |
| 287 | uhii += 1 - (((uhii ^ uloi) >> 126) & 2); | 287 | uhii = uhii + 1 - (((uhii ^ uloi) >> 126) & 2); |
| 288 | sum.hi = @bitCast(uhii); | 288 | sum.hi = @bitCast(uhii); |
| 289 | } | 289 | } |
| 290 | } | 290 | } |
lib/std/Build/Step/Compile.zig+3| ... | @@ -192,6 +192,7 @@ want_lto: ?bool = null, | ... | @@ -192,6 +192,7 @@ want_lto: ?bool = null, |
| 192 | 192 | ||
| 193 | use_llvm: ?bool, | 193 | use_llvm: ?bool, |
| 194 | use_lld: ?bool, | 194 | use_lld: ?bool, |
| 195 | use_new_linker: ?bool, | ||
| 195 | 196 | ||
| 196 | /// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI | 197 | /// Corresponds to the `-fallow-so-scripts` / `-fno-allow-so-scripts` CLI |
| 197 | /// flags, overriding the global user setting provided to the `zig build` | 198 | /// flags, overriding the global user setting provided to the `zig build` |
| ... | @@ -441,6 +442,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { | ... | @@ -441,6 +442,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { |
| 441 | 442 | ||
| 442 | .use_llvm = options.use_llvm, | 443 | .use_llvm = options.use_llvm, |
| 443 | .use_lld = options.use_lld, | 444 | .use_lld = options.use_lld, |
| 445 | .use_new_linker = null, | ||
| 444 | 446 | ||
| 445 | .zig_process = null, | 447 | .zig_process = null, |
| 446 | }; | 448 | }; |
| ... | @@ -1096,6 +1098,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { | ... | @@ -1096,6 +1098,7 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 { |
| 1096 | 1098 | ||
| 1097 | try addFlag(&zig_args, "llvm", compile.use_llvm); | 1099 | try addFlag(&zig_args, "llvm", compile.use_llvm); |
| 1098 | try addFlag(&zig_args, "lld", compile.use_lld); | 1100 | try addFlag(&zig_args, "lld", compile.use_lld); |
| 1101 | try addFlag(&zig_args, "new-linker", compile.use_new_linker); | ||
| 1099 | 1102 | ||
| 1100 | if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| { | 1103 | if (compile.root_module.resolved_target.?.query.ofmt) |ofmt| { |
| 1101 | try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)})); | 1104 | try zig_args.append(try std.fmt.allocPrint(arena, "-ofmt={s}", .{@tagName(ofmt)})); |
lib/std/elf.zig+493-102| ... | @@ -323,6 +323,8 @@ pub const PT_LOPROC = 0x70000000; | ... | @@ -323,6 +323,8 @@ pub const PT_LOPROC = 0x70000000; |
| 323 | /// End of processor-specific | 323 | /// End of processor-specific |
| 324 | pub const PT_HIPROC = 0x7fffffff; | 324 | pub const PT_HIPROC = 0x7fffffff; |
| 325 | 325 | ||
| 326 | pub const PN_XNUM = 0xffff; | ||
| 327 | |||
| 326 | /// Section header table entry unused | 328 | /// Section header table entry unused |
| 327 | pub const SHT_NULL = 0; | 329 | pub const SHT_NULL = 0; |
| 328 | /// Program data | 330 | /// Program data |
| ... | @@ -385,63 +387,149 @@ pub const SHT_HIUSER = 0xffffffff; | ... | @@ -385,63 +387,149 @@ pub const SHT_HIUSER = 0xffffffff; |
| 385 | // Note type for .note.gnu.build_id | 387 | // Note type for .note.gnu.build_id |
| 386 | pub const NT_GNU_BUILD_ID = 3; | 388 | pub const NT_GNU_BUILD_ID = 3; |
| 387 | 389 | ||
| 388 | /// Local symbol | 390 | /// Deprecated, use `@intFromEnum(std.elf.STB.LOCAL)` |
| 389 | pub const STB_LOCAL = 0; | 391 | pub const STB_LOCAL = @intFromEnum(STB.LOCAL); |
| 390 | /// Global symbol | 392 | /// Deprecated, use `@intFromEnum(std.elf.STB.GLOBAL)` |
| 391 | pub const STB_GLOBAL = 1; | 393 | pub const STB_GLOBAL = @intFromEnum(STB.GLOBAL); |
| 392 | /// Weak symbol | 394 | /// Deprecated, use `@intFromEnum(std.elf.STB.WEAK)` |
| 393 | pub const STB_WEAK = 2; | 395 | pub const STB_WEAK = @intFromEnum(STB.WEAK); |
| 394 | /// Number of defined types | 396 | /// Deprecated, use `std.elf.STB.NUM` |
| 395 | pub const STB_NUM = 3; | 397 | pub const STB_NUM = STB.NUM; |
| 396 | /// Start of OS-specific | 398 | /// Deprecated, use `@intFromEnum(std.elf.STB.LOOS)` |
| 397 | pub const STB_LOOS = 10; | 399 | pub const STB_LOOS = @intFromEnum(STB.LOOS); |
| 398 | /// Unique symbol | 400 | /// Deprecated, use `@intFromEnum(std.elf.STB.GNU_UNIQUE)` |
| 399 | pub const STB_GNU_UNIQUE = 10; | 401 | pub const STB_GNU_UNIQUE = @intFromEnum(STB.GNU_UNIQUE); |
| 400 | /// End of OS-specific | 402 | /// Deprecated, use `@intFromEnum(std.elf.STB.HIOS)` |
| 401 | pub const STB_HIOS = 12; | 403 | pub const STB_HIOS = @intFromEnum(STB.HIOS); |
| 402 | /// Start of processor-specific | 404 | /// Deprecated, use `@intFromEnum(std.elf.STB.LOPROC)` |
| 403 | pub const STB_LOPROC = 13; | 405 | pub const STB_LOPROC = @intFromEnum(STB.LOPROC); |
| 404 | /// End of processor-specific | 406 | /// Deprecated, use `@intFromEnum(std.elf.STB.HIPROC)` |
| 405 | pub const STB_HIPROC = 15; | 407 | pub const STB_HIPROC = @intFromEnum(STB.HIPROC); |
| 406 | 408 | ||
| 407 | pub const STB_MIPS_SPLIT_COMMON = 13; | 409 | /// Deprecated, use `@intFromEnum(std.elf.STB.MIPS_SPLIT_COMMON)` |
| 408 | 410 | pub const STB_MIPS_SPLIT_COMMON = @intFromEnum(STB.MIBS_SPLIT_COMMON); | |
| 409 | /// Symbol type is unspecified | 411 | |
| 410 | pub const STT_NOTYPE = 0; | 412 | /// Deprecated, use `@intFromEnum(std.elf.STT.NOTYPE)` |
| 411 | /// Symbol is a data object | 413 | pub const STT_NOTYPE = @intFromEnum(STT.NOTYPE); |
| 412 | pub const STT_OBJECT = 1; | 414 | /// Deprecated, use `@intFromEnum(std.elf.STT.OBJECT)` |
| 413 | /// Symbol is a code object | 415 | pub const STT_OBJECT = @intFromEnum(STT.OBJECT); |
| 414 | pub const STT_FUNC = 2; | 416 | /// Deprecated, use `@intFromEnum(std.elf.STT.FUNC)` |
| 415 | /// Symbol associated with a section | 417 | pub const STT_FUNC = @intFromEnum(STT.FUNC); |
| 416 | pub const STT_SECTION = 3; | 418 | /// Deprecated, use `@intFromEnum(std.elf.STT.SECTION)` |
| 417 | /// Symbol's name is file name | 419 | pub const STT_SECTION = @intFromEnum(STT.SECTION); |
| 418 | pub const STT_FILE = 4; | 420 | /// Deprecated, use `@intFromEnum(std.elf.STT.FILE)` |
| 419 | /// Symbol is a common data object | 421 | pub const STT_FILE = @intFromEnum(STT.FILE); |
| 420 | pub const STT_COMMON = 5; | 422 | /// Deprecated, use `@intFromEnum(std.elf.STT.COMMON)` |
| 421 | /// Symbol is thread-local data object | 423 | pub const STT_COMMON = @intFromEnum(STT.COMMON); |
| 422 | pub const STT_TLS = 6; | 424 | /// Deprecated, use `@intFromEnum(std.elf.STT.TLS)` |
| 423 | /// Number of defined types | 425 | pub const STT_TLS = @intFromEnum(STT.TLS); |
| 424 | pub const STT_NUM = 7; | 426 | /// Deprecated, use `std.elf.STT.NUM` |
| 425 | /// Start of OS-specific | 427 | pub const STT_NUM = STT.NUM; |
| 426 | pub const STT_LOOS = 10; | 428 | /// Deprecated, use `@intFromEnum(std.elf.STT.LOOS)` |
| 427 | /// Symbol is indirect code object | 429 | pub const STT_LOOS = @intFromEnum(STT.LOOS); |
| 428 | pub const STT_GNU_IFUNC = 10; | 430 | /// Deprecated, use `@intFromEnum(std.elf.STT.GNU_IFUNC)` |
| 429 | /// End of OS-specific | 431 | pub const STT_GNU_IFUNC = @intFromEnum(STT.GNU_IFUNC); |
| 430 | pub const STT_HIOS = 12; | 432 | /// Deprecated, use `@intFromEnum(std.elf.STT.HIOS)` |
| 431 | /// Start of processor-specific | 433 | pub const STT_HIOS = @intFromEnum(STT.HIOS); |
| 432 | pub const STT_LOPROC = 13; | 434 | /// Deprecated, use `@intFromEnum(std.elf.STT.LOPROC)` |
| 433 | /// End of processor-specific | 435 | pub const STT_LOPROC = @intFromEnum(STT.LOPROC); |
| 434 | pub const STT_HIPROC = 15; | 436 | /// Deprecated, use `@intFromEnum(std.elf.STT.HIPROC)` |
| 437 | pub const STT_HIPROC = @intFromEnum(STT.HIPROC); | ||
| 438 | |||
| 439 | /// Deprecated, use `@intFromEnum(std.elf.STT.SPARC_REGISTER)` | ||
| 440 | pub const STT_SPARC_REGISTER = @intFromEnum(STT.SPARC_REGISTER); | ||
| 441 | |||
| 442 | /// Deprecated, use `@intFromEnum(std.elf.STT.PARISC_MILLICODE)` | ||
| 443 | pub const STT_PARISC_MILLICODE = @intFromEnum(STT.PARISC_MILLICODE); | ||
| 444 | |||
| 445 | /// Deprecated, use `@intFromEnum(std.elf.STT.HP_OPAQUE)` | ||
| 446 | pub const STT_HP_OPAQUE = @intFromEnum(STT.HP_OPAQUE); | ||
| 447 | /// Deprecated, use `@intFromEnum(std.elf.STT.HP_STUB)` | ||
| 448 | pub const STT_HP_STUB = @intFromEnum(STT.HP_STUB); | ||
| 449 | |||
| 450 | /// Deprecated, use `@intFromEnum(std.elf.STT.ARM_TFUNC)` | ||
| 451 | pub const STT_ARM_TFUNC = @intFromEnum(STT.ARM_TFUNC); | ||
| 452 | /// Deprecated, use `@intFromEnum(std.elf.STT.ARM_16BIT)` | ||
| 453 | pub const STT_ARM_16BIT = @intFromEnum(STT.ARM_16BIT); | ||
| 454 | |||
| 455 | pub const STB = enum(u4) { | ||
| 456 | /// Local symbol | ||
| 457 | LOCAL = 0, | ||
| 458 | /// Global symbol | ||
| 459 | GLOBAL = 1, | ||
| 460 | /// Weak symbol | ||
| 461 | WEAK = 2, | ||
| 462 | _, | ||
| 463 | |||
| 464 | /// Number of defined types | ||
| 465 | pub const NUM = @typeInfo(STB).@"enum".fields.len; | ||
| 466 | |||
| 467 | /// Start of OS-specific | ||
| 468 | pub const LOOS: STB = @enumFromInt(10); | ||
| 469 | /// End of OS-specific | ||
| 470 | pub const HIOS: STB = @enumFromInt(12); | ||
| 471 | |||
| 472 | /// Unique symbol | ||
| 473 | pub const GNU_UNIQUE: STB = @enumFromInt(@intFromEnum(LOOS) + 0); | ||
| 474 | |||
| 475 | /// Start of processor-specific | ||
| 476 | pub const LOPROC: STB = @enumFromInt(13); | ||
| 477 | /// End of processor-specific | ||
| 478 | pub const HIPROC: STB = @enumFromInt(15); | ||
| 479 | |||
| 480 | pub const MIPS_SPLIT_COMMON: STB = @enumFromInt(@intFromEnum(LOPROC) + 0); | ||
| 481 | }; | ||
| 482 | |||
| 483 | pub const STT = enum(u4) { | ||
| 484 | /// Symbol type is unspecified | ||
| 485 | NOTYPE = 0, | ||
| 486 | /// Symbol is a data object | ||
| 487 | OBJECT = 1, | ||
| 488 | /// Symbol is a code object | ||
| 489 | FUNC = 2, | ||
| 490 | /// Symbol associated with a section | ||
| 491 | SECTION = 3, | ||
| 492 | /// Symbol's name is file name | ||
| 493 | FILE = 4, | ||
| 494 | /// Symbol is a common data object | ||
| 495 | COMMON = 5, | ||
| 496 | /// Symbol is thread-local data object | ||
| 497 | TLS = 6, | ||
| 498 | _, | ||
| 499 | |||
| 500 | /// Number of defined types | ||
| 501 | pub const NUM = @typeInfo(STT).@"enum".fields.len; | ||
| 502 | |||
| 503 | /// Start of OS-specific | ||
| 504 | pub const LOOS: STT = @enumFromInt(10); | ||
| 505 | /// End of OS-specific | ||
| 506 | pub const HIOS: STT = @enumFromInt(12); | ||
| 435 | 507 | ||
| 436 | pub const STT_SPARC_REGISTER = 13; | 508 | /// Symbol is indirect code object |
| 509 | pub const GNU_IFUNC: STT = @enumFromInt(@intFromEnum(LOOS) + 0); | ||
| 437 | 510 | ||
| 438 | pub const STT_PARISC_MILLICODE = 13; | 511 | pub const HP_OPAQUE: STT = @enumFromInt(@intFromEnum(LOOS) + 1); |
| 512 | pub const HP_STUB: STT = @enumFromInt(@intFromEnum(LOOS) + 2); | ||
| 439 | 513 | ||
| 440 | pub const STT_HP_OPAQUE = (STT_LOOS + 0x1); | 514 | /// Start of processor-specific |
| 441 | pub const STT_HP_STUB = (STT_LOOS + 0x2); | 515 | pub const LOPROC: STT = @enumFromInt(13); |
| 516 | /// End of processor-specific | ||
| 517 | pub const HIPROC: STT = @enumFromInt(15); | ||
| 442 | 518 | ||
| 443 | pub const STT_ARM_TFUNC = STT_LOPROC; | 519 | pub const SPARC_REGISTER: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); |
| 444 | pub const STT_ARM_16BIT = STT_HIPROC; | 520 | |
| 521 | pub const PARISC_MILLICODE: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); | ||
| 522 | |||
| 523 | pub const ARM_TFUNC: STT = @enumFromInt(@intFromEnum(LOPROC) + 0); | ||
| 524 | pub const ARM_16BIT: STT = @enumFromInt(@intFromEnum(HIPROC) + 2); | ||
| 525 | }; | ||
| 526 | |||
| 527 | pub const STV = enum(u3) { | ||
| 528 | DEFAULT = 0, | ||
| 529 | INTERNAL = 1, | ||
| 530 | HIDDEN = 2, | ||
| 531 | PROTECTED = 3, | ||
| 532 | }; | ||
| 445 | 533 | ||
| 446 | pub const MAGIC = "\x7fELF"; | 534 | pub const MAGIC = "\x7fELF"; |
| 447 | 535 | ||
| ... | @@ -534,15 +622,15 @@ pub const Header = struct { | ... | @@ -534,15 +622,15 @@ pub const Header = struct { |
| 534 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); | 622 | const buf = try r.peek(@sizeOf(Elf64_Ehdr)); |
| 535 | 623 | ||
| 536 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; | 624 | if (!mem.eql(u8, buf[0..4], MAGIC)) return error.InvalidElfMagic; |
| 537 | if (buf[EI_VERSION] != 1) return error.InvalidElfVersion; | 625 | if (buf[EI.VERSION] != 1) return error.InvalidElfVersion; |
| 538 | 626 | ||
| 539 | const endian: std.builtin.Endian = switch (buf[EI_DATA]) { | 627 | const endian: std.builtin.Endian = switch (buf[EI.DATA]) { |
| 540 | ELFDATA2LSB => .little, | 628 | ELFDATA2LSB => .little, |
| 541 | ELFDATA2MSB => .big, | 629 | ELFDATA2MSB => .big, |
| 542 | else => return error.InvalidElfEndian, | 630 | else => return error.InvalidElfEndian, |
| 543 | }; | 631 | }; |
| 544 | 632 | ||
| 545 | return switch (buf[EI_CLASS]) { | 633 | return switch (buf[EI.CLASS]) { |
| 546 | ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian), | 634 | ELFCLASS32 => .init(try r.takeStruct(Elf32_Ehdr, endian), endian), |
| 547 | ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian), | 635 | ELFCLASS64 => .init(try r.takeStruct(Elf64_Ehdr, endian), endian), |
| 548 | else => return error.InvalidElfClass, | 636 | else => return error.InvalidElfClass, |
| ... | @@ -559,8 +647,8 @@ pub const Header = struct { | ... | @@ -559,8 +647,8 @@ pub const Header = struct { |
| 559 | else => @compileError("bad type"), | 647 | else => @compileError("bad type"), |
| 560 | }, | 648 | }, |
| 561 | .endian = endian, | 649 | .endian = endian, |
| 562 | .os_abi = @enumFromInt(hdr.e_ident[EI_OSABI]), | 650 | .os_abi = @enumFromInt(hdr.e_ident[EI.OSABI]), |
| 563 | .abi_version = hdr.e_ident[EI_ABIVERSION], | 651 | .abi_version = hdr.e_ident[EI.ABIVERSION], |
| 564 | .type = hdr.e_type, | 652 | .type = hdr.e_type, |
| 565 | .machine = hdr.e_machine, | 653 | .machine = hdr.e_machine, |
| 566 | .entry = hdr.e_entry, | 654 | .entry = hdr.e_entry, |
| ... | @@ -683,38 +771,200 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { | ... | @@ -683,38 +771,200 @@ fn takeShdr(reader: *std.Io.Reader, elf_header: Header) !?Elf64_Shdr { |
| 683 | }; | 771 | }; |
| 684 | } | 772 | } |
| 685 | 773 | ||
| 686 | pub const ELFCLASSNONE = 0; | 774 | pub const EI = struct { |
| 687 | pub const ELFCLASS32 = 1; | 775 | pub const CLASS = 4; |
| 688 | pub const ELFCLASS64 = 2; | 776 | pub const DATA = 5; |
| 689 | pub const ELFCLASSNUM = 3; | 777 | pub const VERSION = 6; |
| 690 | 778 | pub const OSABI = 7; | |
| 691 | pub const ELFDATANONE = 0; | 779 | pub const ABIVERSION = 8; |
| 692 | pub const ELFDATA2LSB = 1; | 780 | pub const PAD = 9; |
| 693 | pub const ELFDATA2MSB = 2; | 781 | pub const NIDENT = 16; |
| 694 | pub const ELFDATANUM = 3; | 782 | }; |
| 695 | 783 | ||
| 696 | pub const EI_CLASS = 4; | 784 | /// Deprecated, use `std.elf.EI.CLASS` |
| 697 | pub const EI_DATA = 5; | 785 | pub const EI_CLASS = EI.CLASS; |
| 698 | pub const EI_VERSION = 6; | 786 | /// Deprecated, use `std.elf.EI.DATA` |
| 699 | pub const EI_OSABI = 7; | 787 | pub const EI_DATA = EI.DATA; |
| 700 | pub const EI_ABIVERSION = 8; | 788 | /// Deprecated, use `std.elf.EI.VERSION` |
| 701 | pub const EI_PAD = 9; | 789 | pub const EI_VERSION = EI.VERSION; |
| 702 | 790 | /// Deprecated, use `std.elf.EI.OSABI` | |
| 703 | pub const EI_NIDENT = 16; | 791 | pub const EI_OSABI = EI.OSABI; |
| 792 | /// Deprecated, use `std.elf.EI.ABIVERSION` | ||
| 793 | pub const EI_ABIVERSION = EI.ABIVERSION; | ||
| 794 | /// Deprecated, use `std.elf.EI.PAD` | ||
| 795 | pub const EI_PAD = EI.PAD; | ||
| 796 | /// Deprecated, use `std.elf.EI.NIDENT` | ||
| 797 | pub const EI_NIDENT = EI.NIDENT; | ||
| 704 | 798 | ||
| 705 | pub const Half = u16; | 799 | pub const Half = u16; |
| 706 | pub const Word = u32; | 800 | pub const Word = u32; |
| 707 | pub const Sword = i32; | 801 | pub const Sword = i32; |
| 708 | pub const Elf32_Xword = u64; | 802 | pub const Xword = u64; |
| 709 | pub const Elf32_Sxword = i64; | 803 | pub const Sxword = i64; |
| 710 | pub const Elf64_Xword = u64; | 804 | pub const Section = u16; |
| 805 | pub const Elf32 = struct { | ||
| 806 | pub const Addr = u32; | ||
| 807 | pub const Off = u32; | ||
| 808 | pub const Ehdr = extern struct { | ||
| 809 | ident: [EI.NIDENT]u8, | ||
| 810 | type: ET, | ||
| 811 | machine: EM, | ||
| 812 | version: Word, | ||
| 813 | entry: Elf32.Addr, | ||
| 814 | phoff: Elf32.Off, | ||
| 815 | shoff: Elf32.Off, | ||
| 816 | flags: Word, | ||
| 817 | ehsize: Half, | ||
| 818 | phentsize: Half, | ||
| 819 | phnum: Half, | ||
| 820 | shentsize: Half, | ||
| 821 | shnum: Half, | ||
| 822 | shstrndx: Half, | ||
| 823 | }; | ||
| 824 | pub const Phdr = extern struct { | ||
| 825 | type: Word, | ||
| 826 | offset: Elf32.Off, | ||
| 827 | vaddr: Elf32.Addr, | ||
| 828 | paddr: Elf32.Addr, | ||
| 829 | filesz: Word, | ||
| 830 | memsz: Word, | ||
| 831 | flags: PF, | ||
| 832 | @"align": Word, | ||
| 833 | }; | ||
| 834 | pub const Shdr = extern struct { | ||
| 835 | name: Word, | ||
| 836 | type: Word, | ||
| 837 | flags: packed struct { shf: SHF }, | ||
| 838 | addr: Elf32.Addr, | ||
| 839 | offset: Elf32.Off, | ||
| 840 | size: Word, | ||
| 841 | link: Word, | ||
| 842 | info: Word, | ||
| 843 | addralign: Word, | ||
| 844 | entsize: Word, | ||
| 845 | }; | ||
| 846 | pub const Chdr = extern struct { | ||
| 847 | type: COMPRESS, | ||
| 848 | size: Word, | ||
| 849 | addralign: Word, | ||
| 850 | }; | ||
| 851 | pub const Sym = extern struct { | ||
| 852 | name: Word, | ||
| 853 | value: Elf32.Addr, | ||
| 854 | size: Word, | ||
| 855 | info: Info, | ||
| 856 | other: Other, | ||
| 857 | shndx: Section, | ||
| 858 | |||
| 859 | pub const Info = packed struct(u8) { | ||
| 860 | type: STT, | ||
| 861 | bind: STB, | ||
| 862 | }; | ||
| 863 | |||
| 864 | pub const Other = packed struct(u8) { | ||
| 865 | visibility: STV, | ||
| 866 | unused: u5 = 0, | ||
| 867 | }; | ||
| 868 | }; | ||
| 869 | comptime { | ||
| 870 | assert(@sizeOf(Elf32.Ehdr) == 52); | ||
| 871 | assert(@sizeOf(Elf32.Phdr) == 32); | ||
| 872 | assert(@sizeOf(Elf32.Shdr) == 40); | ||
| 873 | assert(@sizeOf(Elf32.Sym) == 16); | ||
| 874 | } | ||
| 875 | }; | ||
| 876 | pub const Elf64 = struct { | ||
| 877 | pub const Addr = u64; | ||
| 878 | pub const Off = u64; | ||
| 879 | pub const Ehdr = extern struct { | ||
| 880 | ident: [EI.NIDENT]u8, | ||
| 881 | type: ET, | ||
| 882 | machine: EM, | ||
| 883 | version: Word, | ||
| 884 | entry: Elf64.Addr, | ||
| 885 | phoff: Elf64.Off, | ||
| 886 | shoff: Elf64.Off, | ||
| 887 | flags: Word, | ||
| 888 | ehsize: Half, | ||
| 889 | phentsize: Half, | ||
| 890 | phnum: Half, | ||
| 891 | shentsize: Half, | ||
| 892 | shnum: Half, | ||
| 893 | shstrndx: Half, | ||
| 894 | }; | ||
| 895 | pub const Phdr = extern struct { | ||
| 896 | type: Word, | ||
| 897 | flags: PF, | ||
| 898 | offset: Elf64.Off, | ||
| 899 | vaddr: Elf64.Addr, | ||
| 900 | paddr: Elf64.Addr, | ||
| 901 | filesz: Xword, | ||
| 902 | memsz: Xword, | ||
| 903 | @"align": Xword, | ||
| 904 | }; | ||
| 905 | pub const Shdr = extern struct { | ||
| 906 | name: Word, | ||
| 907 | type: Word, | ||
| 908 | flags: packed struct { shf: SHF, unused: Word = 0 }, | ||
| 909 | addr: Elf64.Addr, | ||
| 910 | offset: Elf64.Off, | ||
| 911 | size: Xword, | ||
| 912 | link: Word, | ||
| 913 | info: Word, | ||
| 914 | addralign: Xword, | ||
| 915 | entsize: Xword, | ||
| 916 | }; | ||
| 917 | pub const Chdr = extern struct { | ||
| 918 | type: COMPRESS, | ||
| 919 | reserved: Word = 0, | ||
| 920 | size: Xword, | ||
| 921 | addralign: Xword, | ||
| 922 | }; | ||
| 923 | pub const Sym = extern struct { | ||
| 924 | name: Word, | ||
| 925 | info: Info, | ||
| 926 | other: Other, | ||
| 927 | shndx: Section, | ||
| 928 | value: Elf64.Addr, | ||
| 929 | size: Xword, | ||
| 930 | |||
| 931 | pub const Info = Elf32.Sym.Info; | ||
| 932 | pub const Other = Elf32.Sym.Other; | ||
| 933 | }; | ||
| 934 | comptime { | ||
| 935 | assert(@sizeOf(Elf64.Ehdr) == 64); | ||
| 936 | assert(@sizeOf(Elf64.Phdr) == 56); | ||
| 937 | assert(@sizeOf(Elf64.Shdr) == 64); | ||
| 938 | assert(@sizeOf(Elf64.Sym) == 24); | ||
| 939 | } | ||
| 940 | }; | ||
| 941 | pub const ElfN = switch (@sizeOf(usize)) { | ||
| 942 | 4 => Elf32, | ||
| 943 | 8 => Elf64, | ||
| 944 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 945 | }; | ||
| 946 | |||
| 947 | /// Deprecated, use `std.elf.Xword` | ||
| 948 | pub const Elf32_Xword = Xword; | ||
| 949 | /// Deprecated, use `std.elf.Sxword` | ||
| 950 | pub const Elf32_Sxword = Sxword; | ||
| 951 | /// Deprecated, use `std.elf.Xword` | ||
| 952 | pub const Elf64_Xword = Xword; | ||
| 953 | /// Deprecated, use `std.elf.Sxword` | ||
| 711 | pub const Elf64_Sxword = i64; | 954 | pub const Elf64_Sxword = i64; |
| 955 | /// Deprecated, use `std.elf.Elf32.Addr` | ||
| 712 | pub const Elf32_Addr = u32; | 956 | pub const Elf32_Addr = u32; |
| 957 | /// Deprecated, use `std.elf.Elf64.Addr` | ||
| 713 | pub const Elf64_Addr = u64; | 958 | pub const Elf64_Addr = u64; |
| 959 | /// Deprecated, use `std.elf.Elf32.Off` | ||
| 714 | pub const Elf32_Off = u32; | 960 | pub const Elf32_Off = u32; |
| 961 | /// Deprecated, use `std.elf.Elf64.Off` | ||
| 715 | pub const Elf64_Off = u64; | 962 | pub const Elf64_Off = u64; |
| 963 | /// Deprecated, use `std.elf.Section` | ||
| 716 | pub const Elf32_Section = u16; | 964 | pub const Elf32_Section = u16; |
| 965 | /// Deprecated, use `std.elf.Section` | ||
| 717 | pub const Elf64_Section = u16; | 966 | pub const Elf64_Section = u16; |
| 967 | /// Deprecated, use `std.elf.Elf32.Ehdr` | ||
| 718 | pub const Elf32_Ehdr = extern struct { | 968 | pub const Elf32_Ehdr = extern struct { |
| 719 | e_ident: [EI_NIDENT]u8, | 969 | e_ident: [EI_NIDENT]u8, |
| 720 | e_type: ET, | 970 | e_type: ET, |
| ... | @@ -731,8 +981,9 @@ pub const Elf32_Ehdr = extern struct { | ... | @@ -731,8 +981,9 @@ pub const Elf32_Ehdr = extern struct { |
| 731 | e_shnum: Half, | 981 | e_shnum: Half, |
| 732 | e_shstrndx: Half, | 982 | e_shstrndx: Half, |
| 733 | }; | 983 | }; |
| 984 | /// Deprecated, use `std.elf.Elf64.Ehdr` | ||
| 734 | pub const Elf64_Ehdr = extern struct { | 985 | pub const Elf64_Ehdr = extern struct { |
| 735 | e_ident: [EI_NIDENT]u8, | 986 | e_ident: [EI.NIDENT]u8, |
| 736 | e_type: ET, | 987 | e_type: ET, |
| 737 | e_machine: EM, | 988 | e_machine: EM, |
| 738 | e_version: Word, | 989 | e_version: Word, |
| ... | @@ -747,6 +998,7 @@ pub const Elf64_Ehdr = extern struct { | ... | @@ -747,6 +998,7 @@ pub const Elf64_Ehdr = extern struct { |
| 747 | e_shnum: Half, | 998 | e_shnum: Half, |
| 748 | e_shstrndx: Half, | 999 | e_shstrndx: Half, |
| 749 | }; | 1000 | }; |
| 1001 | /// Deprecated, use `std.elf.Elf32.Phdr` | ||
| 750 | pub const Elf32_Phdr = extern struct { | 1002 | pub const Elf32_Phdr = extern struct { |
| 751 | p_type: Word, | 1003 | p_type: Word, |
| 752 | p_offset: Elf32_Off, | 1004 | p_offset: Elf32_Off, |
| ... | @@ -757,6 +1009,7 @@ pub const Elf32_Phdr = extern struct { | ... | @@ -757,6 +1009,7 @@ pub const Elf32_Phdr = extern struct { |
| 757 | p_flags: Word, | 1009 | p_flags: Word, |
| 758 | p_align: Word, | 1010 | p_align: Word, |
| 759 | }; | 1011 | }; |
| 1012 | /// Deprecated, use `std.elf.Elf64.Phdr` | ||
| 760 | pub const Elf64_Phdr = extern struct { | 1013 | pub const Elf64_Phdr = extern struct { |
| 761 | p_type: Word, | 1014 | p_type: Word, |
| 762 | p_flags: Word, | 1015 | p_flags: Word, |
| ... | @@ -767,6 +1020,7 @@ pub const Elf64_Phdr = extern struct { | ... | @@ -767,6 +1020,7 @@ pub const Elf64_Phdr = extern struct { |
| 767 | p_memsz: Elf64_Xword, | 1020 | p_memsz: Elf64_Xword, |
| 768 | p_align: Elf64_Xword, | 1021 | p_align: Elf64_Xword, |
| 769 | }; | 1022 | }; |
| 1023 | /// Deprecated, use `std.elf.Elf32.Shdr` | ||
| 770 | pub const Elf32_Shdr = extern struct { | 1024 | pub const Elf32_Shdr = extern struct { |
| 771 | sh_name: Word, | 1025 | sh_name: Word, |
| 772 | sh_type: Word, | 1026 | sh_type: Word, |
| ... | @@ -779,6 +1033,7 @@ pub const Elf32_Shdr = extern struct { | ... | @@ -779,6 +1033,7 @@ pub const Elf32_Shdr = extern struct { |
| 779 | sh_addralign: Word, | 1033 | sh_addralign: Word, |
| 780 | sh_entsize: Word, | 1034 | sh_entsize: Word, |
| 781 | }; | 1035 | }; |
| 1036 | /// Deprecated, use `std.elf.Elf64.Shdr` | ||
| 782 | pub const Elf64_Shdr = extern struct { | 1037 | pub const Elf64_Shdr = extern struct { |
| 783 | sh_name: Word, | 1038 | sh_name: Word, |
| 784 | sh_type: Word, | 1039 | sh_type: Word, |
| ... | @@ -791,17 +1046,20 @@ pub const Elf64_Shdr = extern struct { | ... | @@ -791,17 +1046,20 @@ pub const Elf64_Shdr = extern struct { |
| 791 | sh_addralign: Elf64_Xword, | 1046 | sh_addralign: Elf64_Xword, |
| 792 | sh_entsize: Elf64_Xword, | 1047 | sh_entsize: Elf64_Xword, |
| 793 | }; | 1048 | }; |
| 1049 | /// Deprecated, use `std.elf.Elf32.Chdr` | ||
| 794 | pub const Elf32_Chdr = extern struct { | 1050 | pub const Elf32_Chdr = extern struct { |
| 795 | ch_type: COMPRESS, | 1051 | ch_type: COMPRESS, |
| 796 | ch_size: Word, | 1052 | ch_size: Word, |
| 797 | ch_addralign: Word, | 1053 | ch_addralign: Word, |
| 798 | }; | 1054 | }; |
| 1055 | /// Deprecated, use `std.elf.Elf64.Chdr` | ||
| 799 | pub const Elf64_Chdr = extern struct { | 1056 | pub const Elf64_Chdr = extern struct { |
| 800 | ch_type: COMPRESS, | 1057 | ch_type: COMPRESS, |
| 801 | ch_reserved: Word = 0, | 1058 | ch_reserved: Word = 0, |
| 802 | ch_size: Elf64_Xword, | 1059 | ch_size: Elf64_Xword, |
| 803 | ch_addralign: Elf64_Xword, | 1060 | ch_addralign: Elf64_Xword, |
| 804 | }; | 1061 | }; |
| 1062 | /// Deprecated, use `std.elf.Elf32.Sym` | ||
| 805 | pub const Elf32_Sym = extern struct { | 1063 | pub const Elf32_Sym = extern struct { |
| 806 | st_name: Word, | 1064 | st_name: Word, |
| 807 | st_value: Elf32_Addr, | 1065 | st_value: Elf32_Addr, |
| ... | @@ -817,6 +1075,7 @@ pub const Elf32_Sym = extern struct { | ... | @@ -817,6 +1075,7 @@ pub const Elf32_Sym = extern struct { |
| 817 | return @truncate(self.st_info >> 4); | 1075 | return @truncate(self.st_info >> 4); |
| 818 | } | 1076 | } |
| 819 | }; | 1077 | }; |
| 1078 | /// Deprecated, use `std.elf.Elf64.Sym` | ||
| 820 | pub const Elf64_Sym = extern struct { | 1079 | pub const Elf64_Sym = extern struct { |
| 821 | st_name: Word, | 1080 | st_name: Word, |
| 822 | st_info: u8, | 1081 | st_info: u8, |
| ... | @@ -1020,27 +1279,18 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct { | ... | @@ -1020,27 +1279,18 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct { |
| 1020 | flags2: Word, | 1279 | flags2: Word, |
| 1021 | }; | 1280 | }; |
| 1022 | 1281 | ||
| 1023 | comptime { | ||
| 1024 | assert(@sizeOf(Elf32_Ehdr) == 52); | ||
| 1025 | assert(@sizeOf(Elf64_Ehdr) == 64); | ||
| 1026 | |||
| 1027 | assert(@sizeOf(Elf32_Phdr) == 32); | ||
| 1028 | assert(@sizeOf(Elf64_Phdr) == 56); | ||
| 1029 | |||
| 1030 | assert(@sizeOf(Elf32_Shdr) == 40); | ||
| 1031 | assert(@sizeOf(Elf64_Shdr) == 64); | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | pub const Auxv = switch (@sizeOf(usize)) { | 1282 | pub const Auxv = switch (@sizeOf(usize)) { |
| 1035 | 4 => Elf32_auxv_t, | 1283 | 4 => Elf32_auxv_t, |
| 1036 | 8 => Elf64_auxv_t, | 1284 | 8 => Elf64_auxv_t, |
| 1037 | else => @compileError("expected pointer size of 32 or 64"), | 1285 | else => @compileError("expected pointer size of 32 or 64"), |
| 1038 | }; | 1286 | }; |
| 1287 | /// Deprecated, use `std.elf.ElfN.Ehdr` | ||
| 1039 | pub const Ehdr = switch (@sizeOf(usize)) { | 1288 | pub const Ehdr = switch (@sizeOf(usize)) { |
| 1040 | 4 => Elf32_Ehdr, | 1289 | 4 => Elf32_Ehdr, |
| 1041 | 8 => Elf64_Ehdr, | 1290 | 8 => Elf64_Ehdr, |
| 1042 | else => @compileError("expected pointer size of 32 or 64"), | 1291 | else => @compileError("expected pointer size of 32 or 64"), |
| 1043 | }; | 1292 | }; |
| 1293 | /// Deprecated, use `std.elf.ElfN.Phdr` | ||
| 1044 | pub const Phdr = switch (@sizeOf(usize)) { | 1294 | pub const Phdr = switch (@sizeOf(usize)) { |
| 1045 | 4 => Elf32_Phdr, | 1295 | 4 => Elf32_Phdr, |
| 1046 | 8 => Elf64_Phdr, | 1296 | 8 => Elf64_Phdr, |
| ... | @@ -1071,20 +1321,53 @@ pub const Shdr = switch (@sizeOf(usize)) { | ... | @@ -1071,20 +1321,53 @@ pub const Shdr = switch (@sizeOf(usize)) { |
| 1071 | 8 => Elf64_Shdr, | 1321 | 8 => Elf64_Shdr, |
| 1072 | else => @compileError("expected pointer size of 32 or 64"), | 1322 | else => @compileError("expected pointer size of 32 or 64"), |
| 1073 | }; | 1323 | }; |
| 1324 | /// Deprecated, use `std.elf.ElfN.Chdr` | ||
| 1074 | pub const Chdr = switch (@sizeOf(usize)) { | 1325 | pub const Chdr = switch (@sizeOf(usize)) { |
| 1075 | 4 => Elf32_Chdr, | 1326 | 4 => Elf32_Chdr, |
| 1076 | 8 => Elf64_Chdr, | 1327 | 8 => Elf64_Chdr, |
| 1077 | else => @compileError("expected pointer size of 32 or 64"), | 1328 | else => @compileError("expected pointer size of 32 or 64"), |
| 1078 | }; | 1329 | }; |
| 1330 | /// Deprecated, use `std.elf.ElfN.Sym` | ||
| 1079 | pub const Sym = switch (@sizeOf(usize)) { | 1331 | pub const Sym = switch (@sizeOf(usize)) { |
| 1080 | 4 => Elf32_Sym, | 1332 | 4 => Elf32_Sym, |
| 1081 | 8 => Elf64_Sym, | 1333 | 8 => Elf64_Sym, |
| 1082 | else => @compileError("expected pointer size of 32 or 64"), | 1334 | else => @compileError("expected pointer size of 32 or 64"), |
| 1083 | }; | 1335 | }; |
| 1084 | pub const Addr = switch (@sizeOf(usize)) { | 1336 | /// Deprecated, use `std.elf.ElfN.Addr` |
| 1085 | 4 => Elf32_Addr, | 1337 | pub const Addr = ElfN.Addr; |
| 1086 | 8 => Elf64_Addr, | 1338 | |
| 1087 | else => @compileError("expected pointer size of 32 or 64"), | 1339 | /// Deprecated, use `@intFromEnum(std.elf.CLASS.NONE)` |
| 1340 | pub const ELFCLASSNONE = @intFromEnum(CLASS.NONE); | ||
| 1341 | /// Deprecated, use `@intFromEnum(std.elf.CLASS.@"32")` | ||
| 1342 | pub const ELFCLASS32 = @intFromEnum(CLASS.@"32"); | ||
| 1343 | /// Deprecated, use `@intFromEnum(std.elf.CLASS.@"64")` | ||
| 1344 | pub const ELFCLASS64 = @intFromEnum(CLASS.@"64"); | ||
| 1345 | /// Deprecated, use `@intFromEnum(std.elf.CLASS.NUM)` | ||
| 1346 | pub const ELFCLASSNUM = CLASS.NUM; | ||
| 1347 | pub const CLASS = enum(u8) { | ||
| 1348 | NONE = 0, | ||
| 1349 | @"32" = 1, | ||
| 1350 | @"64" = 2, | ||
| 1351 | _, | ||
| 1352 | |||
| 1353 | pub const NUM = @typeInfo(CLASS).@"enum".fields.len; | ||
| 1354 | }; | ||
| 1355 | |||
| 1356 | /// Deprecated, use `@intFromEnum(std.elf.DATA.NONE)` | ||
| 1357 | pub const ELFDATANONE = @intFromEnum(DATA.NONE); | ||
| 1358 | /// Deprecated, use `@intFromEnum(std.elf.DATA.@"2LSB")` | ||
| 1359 | pub const ELFDATA2LSB = @intFromEnum(DATA.@"2LSB"); | ||
| 1360 | /// Deprecated, use `@intFromEnum(std.elf.DATA.@"2MSB")` | ||
| 1361 | pub const ELFDATA2MSB = @intFromEnum(DATA.@"2MSB"); | ||
| 1362 | /// Deprecated, use `@intFromEnum(std.elf.DATA.NUM)` | ||
| 1363 | pub const ELFDATANUM = DATA.NUM; | ||
| 1364 | pub const DATA = enum(u8) { | ||
| 1365 | NONE = 0, | ||
| 1366 | @"2LSB" = 1, | ||
| 1367 | @"2MSB" = 2, | ||
| 1368 | _, | ||
| 1369 | |||
| 1370 | pub const NUM = @typeInfo(DATA).@"enum".fields.len; | ||
| 1088 | }; | 1371 | }; |
| 1089 | 1372 | ||
| 1090 | pub const OSABI = enum(u8) { | 1373 | pub const OSABI = enum(u8) { |
| ... | @@ -1718,6 +2001,108 @@ pub const SHF_MIPS_STRING = 0x80000000; | ... | @@ -1718,6 +2001,108 @@ pub const SHF_MIPS_STRING = 0x80000000; |
| 1718 | /// Make code section unreadable when in execute-only mode | 2001 | /// Make code section unreadable when in execute-only mode |
| 1719 | pub const SHF_ARM_PURECODE = 0x2000000; | 2002 | pub const SHF_ARM_PURECODE = 0x2000000; |
| 1720 | 2003 | ||
| 2004 | pub const SHF = packed struct(Word) { | ||
| 2005 | /// Section data should be writable during execution. | ||
| 2006 | WRITE: bool = false, | ||
| 2007 | /// Section occupies memory during program execution. | ||
| 2008 | ALLOC: bool = false, | ||
| 2009 | /// Section contains executable machine instructions. | ||
| 2010 | EXECINSTR: bool = false, | ||
| 2011 | unused3: u1 = 0, | ||
| 2012 | /// The data in this section may be merged. | ||
| 2013 | MERGE: bool = false, | ||
| 2014 | /// The data in this section is null-terminated strings. | ||
| 2015 | STRINGS: bool = false, | ||
| 2016 | /// A field in this section holds a section header table index. | ||
| 2017 | INFO_LINK: bool = false, | ||
| 2018 | /// Adds special ordering requirements for link editors. | ||
| 2019 | LINK_ORDER: bool = false, | ||
| 2020 | /// This section requires special OS-specific processing to avoid incorrect behavior. | ||
| 2021 | OS_NONCONFORMING: bool = false, | ||
| 2022 | /// This section is a member of a section group. | ||
| 2023 | GROUP: bool = false, | ||
| 2024 | /// This section holds Thread-Local Storage. | ||
| 2025 | TLS: bool = false, | ||
| 2026 | /// Identifies a section containing compressed data. | ||
| 2027 | COMPRESSED: bool = false, | ||
| 2028 | unused12: u8 = 0, | ||
| 2029 | OS: packed union { | ||
| 2030 | MASK: u8, | ||
| 2031 | GNU: packed struct(u8) { | ||
| 2032 | unused0: u1 = 0, | ||
| 2033 | /// Not to be GCed by the linker | ||
| 2034 | RETAIN: bool = false, | ||
| 2035 | unused2: u6 = 0, | ||
| 2036 | }, | ||
| 2037 | MIPS: packed struct(u8) { | ||
| 2038 | unused0: u4 = 0, | ||
| 2039 | /// Section contains text/data which may be replicated in other sections. | ||
| 2040 | /// Linker must retain only one copy. | ||
| 2041 | NODUPES: bool = false, | ||
| 2042 | /// Linker must generate implicit hidden weak names. | ||
| 2043 | NAMES: bool = false, | ||
| 2044 | /// Section data local to process. | ||
| 2045 | LOCAL: bool = false, | ||
| 2046 | /// Do not strip this section. | ||
| 2047 | NOSTRIP: bool = false, | ||
| 2048 | }, | ||
| 2049 | ARM: packed struct(u8) { | ||
| 2050 | unused0: u5 = 0, | ||
| 2051 | /// Make code section unreadable when in execute-only mode | ||
| 2052 | PURECODE: bool = false, | ||
| 2053 | unused6: u2 = 0, | ||
| 2054 | }, | ||
| 2055 | } = .{ .MASK = 0 }, | ||
| 2056 | PROC: packed union { | ||
| 2057 | MASK: u4, | ||
| 2058 | XCORE: packed struct(u4) { | ||
| 2059 | /// All sections with the "d" flag are grouped together by the linker to form | ||
| 2060 | /// the data section and the dp register is set to the start of the section by | ||
| 2061 | /// the boot code. | ||
| 2062 | DP_SECTION: bool = false, | ||
| 2063 | /// All sections with the "c" flag are grouped together by the linker to form | ||
| 2064 | /// the constant pool and the cp register is set to the start of the constant | ||
| 2065 | /// pool by the boot code. | ||
| 2066 | CP_SECTION: bool = false, | ||
| 2067 | unused2: u1 = 0, | ||
| 2068 | /// This section is excluded from the final executable or shared library. | ||
| 2069 | EXCLUDE: bool = false, | ||
| 2070 | }, | ||
| 2071 | X86_64: packed struct(u4) { | ||
| 2072 | /// If an object file section does not have this flag set, then it may not hold | ||
| 2073 | /// more than 2GB and can be freely referred to in objects using smaller code | ||
| 2074 | /// models. Otherwise, only objects using larger code models can refer to them. | ||
| 2075 | /// For example, a medium code model object can refer to data in a section that | ||
| 2076 | /// sets this flag besides being able to refer to data in a section that does | ||
| 2077 | /// not set it; likewise, a small code model object can refer only to code in a | ||
| 2078 | /// section that does not set this flag. | ||
| 2079 | LARGE: bool = false, | ||
| 2080 | unused1: u2 = 0, | ||
| 2081 | /// This section is excluded from the final executable or shared library. | ||
| 2082 | EXCLUDE: bool = false, | ||
| 2083 | }, | ||
| 2084 | HEX: packed struct(u4) { | ||
| 2085 | /// All sections with the GPREL flag are grouped into a global data area | ||
| 2086 | /// for faster accesses | ||
| 2087 | GPREL: bool = false, | ||
| 2088 | unused1: u2 = 0, | ||
| 2089 | /// This section is excluded from the final executable or shared library. | ||
| 2090 | EXCLUDE: bool = false, | ||
| 2091 | }, | ||
| 2092 | MIPS: packed struct(u4) { | ||
| 2093 | /// All sections with the GPREL flag are grouped into a global data area | ||
| 2094 | /// for faster accesses | ||
| 2095 | GPREL: bool = false, | ||
| 2096 | /// This section should be merged. | ||
| 2097 | MERGE: bool = false, | ||
| 2098 | /// Address size to be inferred from section entry size. | ||
| 2099 | ADDR: bool = false, | ||
| 2100 | /// Section data is string data by default. | ||
| 2101 | STRING: bool = false, | ||
| 2102 | }, | ||
| 2103 | } = .{ .MASK = 0 }, | ||
| 2104 | }; | ||
| 2105 | |||
| 1721 | /// Execute | 2106 | /// Execute |
| 1722 | pub const PF_X = 1; | 2107 | pub const PF_X = 1; |
| 1723 | 2108 | ||
| ... | @@ -1733,6 +2118,19 @@ pub const PF_MASKOS = 0x0ff00000; | ... | @@ -1733,6 +2118,19 @@ pub const PF_MASKOS = 0x0ff00000; |
| 1733 | /// Bits for processor-specific semantics. | 2118 | /// Bits for processor-specific semantics. |
| 1734 | pub const PF_MASKPROC = 0xf0000000; | 2119 | pub const PF_MASKPROC = 0xf0000000; |
| 1735 | 2120 | ||
| 2121 | pub const PF = packed struct(Word) { | ||
| 2122 | X: bool = false, | ||
| 2123 | W: bool = false, | ||
| 2124 | R: bool = false, | ||
| 2125 | unused3: u17 = 0, | ||
| 2126 | OS: packed union { | ||
| 2127 | MASK: u8, | ||
| 2128 | } = .{ .MASK = 0 }, | ||
| 2129 | PROC: packed union { | ||
| 2130 | MASK: u4, | ||
| 2131 | } = .{ .MASK = 0 }, | ||
| 2132 | }; | ||
| 2133 | |||
| 1736 | /// Undefined section | 2134 | /// Undefined section |
| 1737 | pub const SHN_UNDEF = 0; | 2135 | pub const SHN_UNDEF = 0; |
| 1738 | /// Start of reserved indices | 2136 | /// Start of reserved indices |
| ... | @@ -2303,13 +2701,6 @@ pub const R_PPC64 = enum(u32) { | ... | @@ -2303,13 +2701,6 @@ pub const R_PPC64 = enum(u32) { |
| 2303 | _, | 2701 | _, |
| 2304 | }; | 2702 | }; |
| 2305 | 2703 | ||
| 2306 | pub const STV = enum(u3) { | ||
| 2307 | DEFAULT = 0, | ||
| 2308 | INTERNAL = 1, | ||
| 2309 | HIDDEN = 2, | ||
| 2310 | PROTECTED = 3, | ||
| 2311 | }; | ||
| 2312 | |||
| 2313 | pub const ar_hdr = extern struct { | 2704 | pub const ar_hdr = extern struct { |
| 2314 | /// Member file name, sometimes / terminated. | 2705 | /// Member file name, sometimes / terminated. |
| 2315 | ar_name: [16]u8, | 2706 | ar_name: [16]u8, |
lib/std/zig/system.zig+6-6| ... | @@ -516,15 +516,15 @@ pub fn abiAndDynamicLinkerFromFile( | ... | @@ -516,15 +516,15 @@ pub fn abiAndDynamicLinkerFromFile( |
| 516 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); | 516 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); |
| 517 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); | 517 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); |
| 518 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | 518 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
| 519 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) { | 519 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { |
| 520 | elf.ELFDATA2LSB => .little, | 520 | elf.ELFDATA2LSB => .little, |
| 521 | elf.ELFDATA2MSB => .big, | 521 | elf.ELFDATA2MSB => .big, |
| 522 | else => return error.InvalidElfEndian, | 522 | else => return error.InvalidElfEndian, |
| 523 | }; | 523 | }; |
| 524 | const need_bswap = elf_endian != native_endian; | 524 | const need_bswap = elf_endian != native_endian; |
| 525 | if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; | 525 | if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; |
| 526 | 526 | ||
| 527 | const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { | 527 | const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { |
| 528 | elf.ELFCLASS32 => false, | 528 | elf.ELFCLASS32 => false, |
| 529 | elf.ELFCLASS64 => true, | 529 | elf.ELFCLASS64 => true, |
| 530 | else => return error.InvalidElfClass, | 530 | else => return error.InvalidElfClass, |
| ... | @@ -920,15 +920,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { | ... | @@ -920,15 +920,15 @@ fn glibcVerFromSoFile(file: fs.File) !std.SemanticVersion { |
| 920 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); | 920 | const hdr32: *elf.Elf32_Ehdr = @ptrCast(&hdr_buf); |
| 921 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); | 921 | const hdr64: *elf.Elf64_Ehdr = @ptrCast(&hdr_buf); |
| 922 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; | 922 | if (!mem.eql(u8, hdr32.e_ident[0..4], elf.MAGIC)) return error.InvalidElfMagic; |
| 923 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI_DATA]) { | 923 | const elf_endian: std.builtin.Endian = switch (hdr32.e_ident[elf.EI.DATA]) { |
| 924 | elf.ELFDATA2LSB => .little, | 924 | elf.ELFDATA2LSB => .little, |
| 925 | elf.ELFDATA2MSB => .big, | 925 | elf.ELFDATA2MSB => .big, |
| 926 | else => return error.InvalidElfEndian, | 926 | else => return error.InvalidElfEndian, |
| 927 | }; | 927 | }; |
| 928 | const need_bswap = elf_endian != native_endian; | 928 | const need_bswap = elf_endian != native_endian; |
| 929 | if (hdr32.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; | 929 | if (hdr32.e_ident[elf.EI.VERSION] != 1) return error.InvalidElfVersion; |
| 930 | 930 | ||
| 931 | const is_64 = switch (hdr32.e_ident[elf.EI_CLASS]) { | 931 | const is_64 = switch (hdr32.e_ident[elf.EI.CLASS]) { |
| 932 | elf.ELFCLASS32 => false, | 932 | elf.ELFCLASS32 => false, |
| 933 | elf.ELFCLASS64 => true, | 933 | elf.ELFCLASS64 => true, |
| 934 | else => return error.InvalidElfClass, | 934 | else => return error.InvalidElfClass, |
src/Compilation.zig+34-13| ... | @@ -177,7 +177,6 @@ debug_compiler_runtime_libs: bool, | ... | @@ -177,7 +177,6 @@ debug_compiler_runtime_libs: bool, |
| 177 | debug_compile_errors: bool, | 177 | debug_compile_errors: bool, |
| 178 | /// Do not check this field directly. Instead, use the `debugIncremental` wrapper function. | 178 | /// Do not check this field directly. Instead, use the `debugIncremental` wrapper function. |
| 179 | debug_incremental: bool, | 179 | debug_incremental: bool, |
| 180 | incremental: bool, | ||
| 181 | alloc_failure_occurred: bool = false, | 180 | alloc_failure_occurred: bool = false, |
| 182 | last_update_was_cache_hit: bool = false, | 181 | last_update_was_cache_hit: bool = false, |
| 183 | 182 | ||
| ... | @@ -256,7 +255,9 @@ mutex: if (builtin.single_threaded) struct { | ... | @@ -256,7 +255,9 @@ mutex: if (builtin.single_threaded) struct { |
| 256 | test_filters: []const []const u8, | 255 | test_filters: []const []const u8, |
| 257 | 256 | ||
| 258 | link_task_wait_group: WaitGroup = .{}, | 257 | link_task_wait_group: WaitGroup = .{}, |
| 259 | link_prog_node: std.Progress.Node = std.Progress.Node.none, | 258 | link_prog_node: std.Progress.Node = .none, |
| 259 | link_uav_prog_node: std.Progress.Node = .none, | ||
| 260 | link_lazy_prog_node: std.Progress.Node = .none, | ||
| 260 | 261 | ||
| 261 | llvm_opt_bisect_limit: c_int, | 262 | llvm_opt_bisect_limit: c_int, |
| 262 | 263 | ||
| ... | @@ -1746,7 +1747,6 @@ pub const CreateOptions = struct { | ... | @@ -1746,7 +1747,6 @@ pub const CreateOptions = struct { |
| 1746 | debug_compiler_runtime_libs: bool = false, | 1747 | debug_compiler_runtime_libs: bool = false, |
| 1747 | debug_compile_errors: bool = false, | 1748 | debug_compile_errors: bool = false, |
| 1748 | debug_incremental: bool = false, | 1749 | debug_incremental: bool = false, |
| 1749 | incremental: bool = false, | ||
| 1750 | /// Normally when you create a `Compilation`, Zig will automatically build | 1750 | /// Normally when you create a `Compilation`, Zig will automatically build |
| 1751 | /// and link in required dependencies, such as compiler-rt and libc. When | 1751 | /// and link in required dependencies, such as compiler-rt and libc. When |
| 1752 | /// building such dependencies themselves, this flag must be set to avoid | 1752 | /// building such dependencies themselves, this flag must be set to avoid |
| ... | @@ -1982,6 +1982,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options | ... | @@ -1982,6 +1982,7 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 1982 | }; | 1982 | }; |
| 1983 | if (have_zcu and (!need_llvm or use_llvm)) { | 1983 | if (have_zcu and (!need_llvm or use_llvm)) { |
| 1984 | if (output_mode == .Obj) break :s .zcu; | 1984 | if (output_mode == .Obj) break :s .zcu; |
| 1985 | if (options.config.use_new_linker) break :s .zcu; | ||
| 1985 | switch (target_util.zigBackend(target, use_llvm)) { | 1986 | switch (target_util.zigBackend(target, use_llvm)) { |
| 1986 | else => {}, | 1987 | else => {}, |
| 1987 | .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { | 1988 | .stage2_aarch64, .stage2_x86_64 => if (target.ofmt == .coff) { |
| ... | @@ -2188,8 +2189,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options | ... | @@ -2188,8 +2189,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 2188 | .inherited = .{}, | 2189 | .inherited = .{}, |
| 2189 | .global = options.config, | 2190 | .global = options.config, |
| 2190 | .parent = options.root_mod, | 2191 | .parent = options.root_mod, |
| 2191 | }) catch |err| return switch (err) { | 2192 | }) catch |err| switch (err) { |
| 2192 | error.OutOfMemory => |e| return e, | 2193 | error.OutOfMemory => return error.OutOfMemory, |
| 2193 | // None of these are possible because the configuration matches the root module | 2194 | // None of these are possible because the configuration matches the root module |
| 2194 | // which already passed these checks. | 2195 | // which already passed these checks. |
| 2195 | error.ValgrindUnsupportedOnTarget => unreachable, | 2196 | error.ValgrindUnsupportedOnTarget => unreachable, |
| ... | @@ -2266,7 +2267,6 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options | ... | @@ -2266,7 +2267,6 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 2266 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, | 2267 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 2267 | .debug_compile_errors = options.debug_compile_errors, | 2268 | .debug_compile_errors = options.debug_compile_errors, |
| 2268 | .debug_incremental = options.debug_incremental, | 2269 | .debug_incremental = options.debug_incremental, |
| 2269 | .incremental = options.incremental, | ||
| 2270 | .root_name = root_name, | 2270 | .root_name = root_name, |
| 2271 | .sysroot = sysroot, | 2271 | .sysroot = sysroot, |
| 2272 | .windows_libs = .empty, | 2272 | .windows_libs = .empty, |
| ... | @@ -2409,6 +2409,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options | ... | @@ -2409,6 +2409,8 @@ pub fn create(gpa: Allocator, arena: Allocator, diag: *CreateDiagnostic, options |
| 2409 | // Synchronize with other matching comments: ZigOnlyHashStuff | 2409 | // Synchronize with other matching comments: ZigOnlyHashStuff |
| 2410 | hash.add(use_llvm); | 2410 | hash.add(use_llvm); |
| 2411 | hash.add(options.config.use_lib_llvm); | 2411 | hash.add(options.config.use_lib_llvm); |
| 2412 | hash.add(options.config.use_lld); | ||
| 2413 | hash.add(options.config.use_new_linker); | ||
| 2412 | hash.add(options.config.dll_export_fns); | 2414 | hash.add(options.config.dll_export_fns); |
| 2413 | hash.add(options.config.is_test); | 2415 | hash.add(options.config.is_test); |
| 2414 | hash.addListOfBytes(options.test_filters); | 2416 | hash.addListOfBytes(options.test_filters); |
| ... | @@ -3075,14 +3077,29 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -3075,14 +3077,29 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3075 | 3077 | ||
| 3076 | // The linker progress node is set up here instead of in `performAllTheWork`, because | 3078 | // The linker progress node is set up here instead of in `performAllTheWork`, because |
| 3077 | // we also want it around during `flush`. | 3079 | // we also want it around during `flush`. |
| 3078 | const have_link_node = comp.bin_file != null; | 3080 | if (comp.bin_file) |lf| { |
| 3079 | if (have_link_node) { | ||
| 3080 | comp.link_prog_node = main_progress_node.start("Linking", 0); | 3081 | comp.link_prog_node = main_progress_node.start("Linking", 0); |
| 3082 | if (lf.cast(.elf2)) |elf| { | ||
| 3083 | comp.link_prog_node.increaseEstimatedTotalItems(3); | ||
| 3084 | comp.link_uav_prog_node = comp.link_prog_node.start("Constants", 0); | ||
| 3085 | comp.link_lazy_prog_node = comp.link_prog_node.start("Synthetics", 0); | ||
| 3086 | elf.mf.update_prog_node = comp.link_prog_node.start("Relocations", elf.mf.updates.items.len); | ||
| 3087 | } | ||
| 3081 | } | 3088 | } |
| 3082 | defer if (have_link_node) { | 3089 | defer { |
| 3083 | comp.link_prog_node.end(); | 3090 | comp.link_prog_node.end(); |
| 3084 | comp.link_prog_node = .none; | 3091 | comp.link_prog_node = .none; |
| 3085 | }; | 3092 | comp.link_uav_prog_node.end(); |
| 3093 | comp.link_uav_prog_node = .none; | ||
| 3094 | comp.link_lazy_prog_node.end(); | ||
| 3095 | comp.link_lazy_prog_node = .none; | ||
| 3096 | if (comp.bin_file) |lf| { | ||
| 3097 | if (lf.cast(.elf2)) |elf| { | ||
| 3098 | elf.mf.update_prog_node.end(); | ||
| 3099 | elf.mf.update_prog_node = .none; | ||
| 3100 | } | ||
| 3101 | } | ||
| 3102 | } | ||
| 3086 | 3103 | ||
| 3087 | try comp.performAllTheWork(main_progress_node); | 3104 | try comp.performAllTheWork(main_progress_node); |
| 3088 | 3105 | ||
| ... | @@ -3100,6 +3117,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE | ... | @@ -3100,6 +3117,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3100 | try pt.populateTestFunctions(); | 3117 | try pt.populateTestFunctions(); |
| 3101 | } | 3118 | } |
| 3102 | 3119 | ||
| 3120 | link.updateErrorData(pt); | ||
| 3121 | |||
| 3103 | try pt.processExports(); | 3122 | try pt.processExports(); |
| 3104 | } | 3123 | } |
| 3105 | 3124 | ||
| ... | @@ -3474,6 +3493,8 @@ fn addNonIncrementalStuffToCacheManifest( | ... | @@ -3474,6 +3493,8 @@ fn addNonIncrementalStuffToCacheManifest( |
| 3474 | 3493 | ||
| 3475 | man.hash.add(comp.config.use_llvm); | 3494 | man.hash.add(comp.config.use_llvm); |
| 3476 | man.hash.add(comp.config.use_lib_llvm); | 3495 | man.hash.add(comp.config.use_lib_llvm); |
| 3496 | man.hash.add(comp.config.use_lld); | ||
| 3497 | man.hash.add(comp.config.use_new_linker); | ||
| 3477 | man.hash.add(comp.config.is_test); | 3498 | man.hash.add(comp.config.is_test); |
| 3478 | man.hash.add(comp.config.import_memory); | 3499 | man.hash.add(comp.config.import_memory); |
| 3479 | man.hash.add(comp.config.export_memory); | 3500 | man.hash.add(comp.config.export_memory); |
| ... | @@ -4073,7 +4094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | ... | @@ -4073,7 +4094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 4073 | defer sorted_failed_analysis.deinit(gpa); | 4094 | defer sorted_failed_analysis.deinit(gpa); |
| 4074 | var added_any_analysis_error = false; | 4095 | var added_any_analysis_error = false; |
| 4075 | for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { | 4096 | for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { |
| 4076 | if (comp.incremental) { | 4097 | if (comp.config.incremental) { |
| 4077 | const refs = try zcu.resolveReferences(); | 4098 | const refs = try zcu.resolveReferences(); |
| 4078 | if (!refs.contains(anal_unit)) continue; | 4099 | if (!refs.contains(anal_unit)) continue; |
| 4079 | } | 4100 | } |
| ... | @@ -4240,7 +4261,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | ... | @@ -4240,7 +4261,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 4240 | 4261 | ||
| 4241 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a | 4262 | // TODO: eventually, this should be behind `std.debug.runtime_safety`. But right now, this is a |
| 4242 | // very common way for incremental compilation bugs to manifest, so let's always check it. | 4263 | // very common way for incremental compilation bugs to manifest, so let's always check it. |
| 4243 | if (comp.zcu) |zcu| if (comp.incremental and bundle.root_list.items.len == 0) { | 4264 | if (comp.zcu) |zcu| if (comp.config.incremental and bundle.root_list.items.len == 0) { |
| 4244 | for (zcu.transitive_failed_analysis.keys()) |failed_unit| { | 4265 | for (zcu.transitive_failed_analysis.keys()) |failed_unit| { |
| 4245 | const refs = try zcu.resolveReferences(); | 4266 | const refs = try zcu.resolveReferences(); |
| 4246 | var ref = refs.get(failed_unit) orelse continue; | 4267 | var ref = refs.get(failed_unit) orelse continue; |
| ... | @@ -4949,7 +4970,7 @@ fn performAllTheWork( | ... | @@ -4949,7 +4970,7 @@ fn performAllTheWork( |
| 4949 | tr.stats.n_reachable_files = @intCast(zcu.alive_files.count()); | 4970 | tr.stats.n_reachable_files = @intCast(zcu.alive_files.count()); |
| 4950 | } | 4971 | } |
| 4951 | 4972 | ||
| 4952 | if (comp.incremental) { | 4973 | if (comp.config.incremental) { |
| 4953 | const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0); | 4974 | const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0); |
| 4954 | defer update_zir_refs_node.end(); | 4975 | defer update_zir_refs_node.end(); |
| 4955 | try pt.updateZirRefs(); | 4976 | try pt.updateZirRefs(); |
src/Compilation/Config.zig+24| ... | @@ -49,6 +49,8 @@ use_lib_llvm: bool, | ... | @@ -49,6 +49,8 @@ use_lib_llvm: bool, |
| 49 | use_lld: bool, | 49 | use_lld: bool, |
| 50 | c_frontend: CFrontend, | 50 | c_frontend: CFrontend, |
| 51 | lto: std.zig.LtoMode, | 51 | lto: std.zig.LtoMode, |
| 52 | use_new_linker: bool, | ||
| 53 | incremental: bool, | ||
| 52 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). | 54 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 53 | /// Always set to `command` for non-WASI targets. | 55 | /// Always set to `command` for non-WASI targets. |
| 54 | wasi_exec_model: std.builtin.WasiExecModel, | 56 | wasi_exec_model: std.builtin.WasiExecModel, |
| ... | @@ -104,6 +106,8 @@ pub const Options = struct { | ... | @@ -104,6 +106,8 @@ pub const Options = struct { |
| 104 | use_lld: ?bool = null, | 106 | use_lld: ?bool = null, |
| 105 | use_clang: ?bool = null, | 107 | use_clang: ?bool = null, |
| 106 | lto: ?std.zig.LtoMode = null, | 108 | lto: ?std.zig.LtoMode = null, |
| 109 | use_new_linker: ?bool = null, | ||
| 110 | incremental: bool = false, | ||
| 107 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). | 111 | /// WASI-only. Type of WASI execution model ("command" or "reactor"). |
| 108 | wasi_exec_model: ?std.builtin.WasiExecModel = null, | 112 | wasi_exec_model: ?std.builtin.WasiExecModel = null, |
| 109 | import_memory: ?bool = null, | 113 | import_memory: ?bool = null, |
| ... | @@ -147,6 +151,8 @@ pub const ResolveError = error{ | ... | @@ -147,6 +151,8 @@ pub const ResolveError = error{ |
| 147 | LldUnavailable, | 151 | LldUnavailable, |
| 148 | ClangUnavailable, | 152 | ClangUnavailable, |
| 149 | DllExportFnsRequiresWindows, | 153 | DllExportFnsRequiresWindows, |
| 154 | NewLinkerIncompatibleWithLld, | ||
| 155 | NewLinkerIncompatibleObjectFormat, | ||
| 150 | }; | 156 | }; |
| 151 | 157 | ||
| 152 | pub fn resolve(options: Options) ResolveError!Config { | 158 | pub fn resolve(options: Options) ResolveError!Config { |
| ... | @@ -458,6 +464,22 @@ pub fn resolve(options: Options) ResolveError!Config { | ... | @@ -458,6 +464,22 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 458 | break :b .none; | 464 | break :b .none; |
| 459 | }; | 465 | }; |
| 460 | 466 | ||
| 467 | const use_new_linker = b: { | ||
| 468 | if (use_lld) { | ||
| 469 | if (options.use_new_linker == true) return error.NewLinkerIncompatibleWithLld; | ||
| 470 | break :b false; | ||
| 471 | } | ||
| 472 | |||
| 473 | if (!target_util.hasNewLinkerSupport(target.ofmt)) { | ||
| 474 | if (options.use_new_linker == true) return error.NewLinkerIncompatibleObjectFormat; | ||
| 475 | break :b false; | ||
| 476 | } | ||
| 477 | |||
| 478 | if (options.use_new_linker) |x| break :b x; | ||
| 479 | |||
| 480 | break :b options.incremental; | ||
| 481 | }; | ||
| 482 | |||
| 461 | const root_strip = b: { | 483 | const root_strip = b: { |
| 462 | if (options.root_strip) |x| break :b x; | 484 | if (options.root_strip) |x| break :b x; |
| 463 | if (root_optimize_mode == .ReleaseSmall) break :b true; | 485 | if (root_optimize_mode == .ReleaseSmall) break :b true; |
| ... | @@ -531,6 +553,8 @@ pub fn resolve(options: Options) ResolveError!Config { | ... | @@ -531,6 +553,8 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 531 | .root_error_tracing = root_error_tracing, | 553 | .root_error_tracing = root_error_tracing, |
| 532 | .pie = pie, | 554 | .pie = pie, |
| 533 | .lto = lto, | 555 | .lto = lto, |
| 556 | .use_new_linker = use_new_linker, | ||
| 557 | .incremental = options.incremental, | ||
| 534 | .import_memory = import_memory, | 558 | .import_memory = import_memory, |
| 535 | .export_memory = export_memory, | 559 | .export_memory = export_memory, |
| 536 | .shared_memory = shared_memory, | 560 | .shared_memory = shared_memory, |
src/InternPool.zig+15-4| ... | @@ -6424,14 +6424,25 @@ pub const Alignment = enum(u6) { | ... | @@ -6424,14 +6424,25 @@ pub const Alignment = enum(u6) { |
| 6424 | return n + 1; | 6424 | return n + 1; |
| 6425 | } | 6425 | } |
| 6426 | 6426 | ||
| 6427 | pub fn toStdMem(a: Alignment) std.mem.Alignment { | ||
| 6428 | assert(a != .none); | ||
| 6429 | return @enumFromInt(@intFromEnum(a)); | ||
| 6430 | } | ||
| 6431 | |||
| 6432 | pub fn fromStdMem(a: std.mem.Alignment) Alignment { | ||
| 6433 | const r: Alignment = @enumFromInt(@intFromEnum(a)); | ||
| 6434 | assert(r != .none); | ||
| 6435 | return r; | ||
| 6436 | } | ||
| 6437 | |||
| 6427 | const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment; | 6438 | const LlvmBuilderAlignment = std.zig.llvm.Builder.Alignment; |
| 6428 | 6439 | ||
| 6429 | pub fn toLlvm(this: @This()) LlvmBuilderAlignment { | 6440 | pub fn toLlvm(a: Alignment) LlvmBuilderAlignment { |
| 6430 | return @enumFromInt(@intFromEnum(this)); | 6441 | return @enumFromInt(@intFromEnum(a)); |
| 6431 | } | 6442 | } |
| 6432 | 6443 | ||
| 6433 | pub fn fromLlvm(other: LlvmBuilderAlignment) @This() { | 6444 | pub fn fromLlvm(a: LlvmBuilderAlignment) Alignment { |
| 6434 | return @enumFromInt(@intFromEnum(other)); | 6445 | return @enumFromInt(@intFromEnum(a)); |
| 6435 | } | 6446 | } |
| 6436 | }; | 6447 | }; |
| 6437 | 6448 |
src/Sema.zig+8-8| ... | @@ -3032,7 +3032,7 @@ fn zirStructDecl( | ... | @@ -3032,7 +3032,7 @@ fn zirStructDecl( |
| 3032 | }); | 3032 | }); |
| 3033 | errdefer pt.destroyNamespace(new_namespace_index); | 3033 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3034 | 3034 | ||
| 3035 | if (pt.zcu.comp.incremental) { | 3035 | if (pt.zcu.comp.config.incremental) { |
| 3036 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | 3036 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 3037 | } | 3037 | } |
| 3038 | 3038 | ||
| ... | @@ -3430,7 +3430,7 @@ fn zirUnionDecl( | ... | @@ -3430,7 +3430,7 @@ fn zirUnionDecl( |
| 3430 | }); | 3430 | }); |
| 3431 | errdefer pt.destroyNamespace(new_namespace_index); | 3431 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3432 | 3432 | ||
| 3433 | if (pt.zcu.comp.incremental) { | 3433 | if (pt.zcu.comp.config.incremental) { |
| 3434 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | 3434 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 3435 | } | 3435 | } |
| 3436 | 3436 | ||
| ... | @@ -6217,7 +6217,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -6217,7 +6217,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 6217 | if (ptr_info.byte_offset != 0) { | 6217 | if (ptr_info.byte_offset != 0) { |
| 6218 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); | 6218 | return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); |
| 6219 | } | 6219 | } |
| 6220 | if (options.linkage == .internal) return; | 6220 | if (zcu.llvm_object != null and options.linkage == .internal) return; |
| 6221 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); | 6221 | const export_ty = Value.fromInterned(uav.val).typeOf(zcu); |
| 6222 | if (!try sema.validateExternType(export_ty, .other)) { | 6222 | if (!try sema.validateExternType(export_ty, .other)) { |
| 6223 | return sema.failWithOwnedErrorMsg(block, msg: { | 6223 | return sema.failWithOwnedErrorMsg(block, msg: { |
| ... | @@ -6256,7 +6256,7 @@ pub fn analyzeExport( | ... | @@ -6256,7 +6256,7 @@ pub fn analyzeExport( |
| 6256 | const zcu = pt.zcu; | 6256 | const zcu = pt.zcu; |
| 6257 | const ip = &zcu.intern_pool; | 6257 | const ip = &zcu.intern_pool; |
| 6258 | 6258 | ||
| 6259 | if (options.linkage == .internal) | 6259 | if (zcu.llvm_object != null and options.linkage == .internal) |
| 6260 | return; | 6260 | return; |
| 6261 | 6261 | ||
| 6262 | try sema.ensureNavResolved(block, src, orig_nav_index, .fully); | 6262 | try sema.ensureNavResolved(block, src, orig_nav_index, .fully); |
| ... | @@ -7709,7 +7709,7 @@ fn analyzeCall( | ... | @@ -7709,7 +7709,7 @@ fn analyzeCall( |
| 7709 | // TODO: comptime call memoization is currently not supported under incremental compilation | 7709 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 7710 | // since dependencies are not marked on callers. If we want to keep this around (we should | 7710 | // since dependencies are not marked on callers. If we want to keep this around (we should |
| 7711 | // check that it's worthwhile first!), each memoized call needs an `AnalUnit`. | 7711 | // check that it's worthwhile first!), each memoized call needs an `AnalUnit`. |
| 7712 | if (zcu.comp.incremental) break :m false; | 7712 | if (zcu.comp.config.incremental) break :m false; |
| 7713 | if (!block.isComptime()) break :m false; | 7713 | if (!block.isComptime()) break :m false; |
| 7714 | for (args) |a| { | 7714 | for (args) |a| { |
| 7715 | const val = (try sema.resolveValue(a)).?; | 7715 | const val = (try sema.resolveValue(a)).?; |
| ... | @@ -31208,7 +31208,7 @@ fn addReferenceEntry( | ... | @@ -31208,7 +31208,7 @@ fn addReferenceEntry( |
| 31208 | .func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced | 31208 | .func => |f| assert(ip.unwrapCoercedFunc(f) == f), // for `.{ .func = f }`, `f` must be uncoerced |
| 31209 | else => {}, | 31209 | else => {}, |
| 31210 | } | 31210 | } |
| 31211 | if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; | 31211 | if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return; |
| 31212 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); | 31212 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); |
| 31213 | if (gop.found_existing) return; | 31213 | if (gop.found_existing) return; |
| 31214 | try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: { | 31214 | try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: { |
| ... | @@ -31225,7 +31225,7 @@ pub fn addTypeReferenceEntry( | ... | @@ -31225,7 +31225,7 @@ pub fn addTypeReferenceEntry( |
| 31225 | referenced_type: InternPool.Index, | 31225 | referenced_type: InternPool.Index, |
| 31226 | ) !void { | 31226 | ) !void { |
| 31227 | const zcu = sema.pt.zcu; | 31227 | const zcu = sema.pt.zcu; |
| 31228 | if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; | 31228 | if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return; |
| 31229 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type); | 31229 | const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type); |
| 31230 | if (gop.found_existing) return; | 31230 | if (gop.found_existing) return; |
| 31231 | try zcu.addTypeReference(sema.owner, referenced_type, src); | 31231 | try zcu.addTypeReference(sema.owner, referenced_type, src); |
| ... | @@ -36875,7 +36875,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool | ... | @@ -36875,7 +36875,7 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool |
| 36875 | 36875 | ||
| 36876 | pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { | 36876 | pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 36877 | const pt = sema.pt; | 36877 | const pt = sema.pt; |
| 36878 | if (!pt.zcu.comp.incremental) return; | 36878 | if (!pt.zcu.comp.config.incremental) return; |
| 36879 | 36879 | ||
| 36880 | const gop = try sema.dependencies.getOrPut(sema.gpa, dependee); | 36880 | const gop = try sema.dependencies.getOrPut(sema.gpa, dependee); |
| 36881 | if (gop.found_existing) return; | 36881 | if (gop.found_existing) return; |
src/Value.zig+1-1| ... | @@ -23,7 +23,7 @@ pub fn format(val: Value, writer: *std.Io.Writer) !void { | ... | @@ -23,7 +23,7 @@ pub fn format(val: Value, writer: *std.Io.Writer) !void { |
| 23 | 23 | ||
| 24 | /// This is a debug function. In order to print values in a meaningful way | 24 | /// This is a debug function. In order to print values in a meaningful way |
| 25 | /// we also need access to the type. | 25 | /// we also need access to the type. |
| 26 | pub fn dump(start_val: Value, w: std.Io.Writer) std.Io.Writer.Error!void { | 26 | pub fn dump(start_val: Value, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 27 | try w.print("(interned: {})", .{start_val.toIntern()}); | 27 | try w.print("(interned: {})", .{start_val.toIntern()}); |
| 28 | } | 28 | } |
| 29 | 29 |
src/Zcu.zig+1-1| ... | @@ -3166,7 +3166,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni | ... | @@ -3166,7 +3166,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni |
| 3166 | } | 3166 | } |
| 3167 | 3167 | ||
| 3168 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { | 3168 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 3169 | if (!zcu.comp.incremental) return null; | 3169 | if (!zcu.comp.config.incremental) return null; |
| 3170 | 3170 | ||
| 3171 | if (zcu.outdated.count() == 0) { | 3171 | if (zcu.outdated.count() == 0) { |
| 3172 | // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those | 3172 | // Any units in `potentially_outdated` must just be stuck in loops with one another: none of those |
src/Zcu/PerThread.zig+1-1| ... | @@ -1815,7 +1815,7 @@ fn createFileRootStruct( | ... | @@ -1815,7 +1815,7 @@ fn createFileRootStruct( |
| 1815 | wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none); | 1815 | wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none); |
| 1816 | ip.namespacePtr(namespace_index).owner_type = wip_ty.index; | 1816 | ip.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 1817 | 1817 | ||
| 1818 | if (zcu.comp.incremental) { | 1818 | if (zcu.comp.config.incremental) { |
| 1819 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); | 1819 | try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst }); |
| 1820 | } | 1820 | } |
| 1821 | 1821 |
src/arch/riscv64/CodeGen.zig+5-3| ... | @@ -858,9 +858,11 @@ pub fn generateLazy( | ... | @@ -858,9 +858,11 @@ pub fn generateLazy( |
| 858 | pt: Zcu.PerThread, | 858 | pt: Zcu.PerThread, |
| 859 | src_loc: Zcu.LazySrcLoc, | 859 | src_loc: Zcu.LazySrcLoc, |
| 860 | lazy_sym: link.File.LazySymbol, | 860 | lazy_sym: link.File.LazySymbol, |
| 861 | code: *std.ArrayListUnmanaged(u8), | 861 | atom_index: u32, |
| 862 | w: *std.Io.Writer, | ||
| 862 | debug_output: link.File.DebugInfoOutput, | 863 | debug_output: link.File.DebugInfoOutput, |
| 863 | ) CodeGenError!void { | 864 | ) (CodeGenError || std.Io.Writer.Error)!void { |
| 865 | _ = atom_index; | ||
| 864 | const comp = bin_file.comp; | 866 | const comp = bin_file.comp; |
| 865 | const gpa = comp.gpa; | 867 | const gpa = comp.gpa; |
| 866 | const mod = comp.root_mod; | 868 | const mod = comp.root_mod; |
| ... | @@ -914,7 +916,7 @@ pub fn generateLazy( | ... | @@ -914,7 +916,7 @@ pub fn generateLazy( |
| 914 | }, | 916 | }, |
| 915 | .bin_file = bin_file, | 917 | .bin_file = bin_file, |
| 916 | .debug_output = debug_output, | 918 | .debug_output = debug_output, |
| 917 | .code = code, | 919 | .w = w, |
| 918 | .prev_di_pc = undefined, // no debug info yet | 920 | .prev_di_pc = undefined, // no debug info yet |
| 919 | .prev_di_line = undefined, // no debug info yet | 921 | .prev_di_line = undefined, // no debug info yet |
| 920 | .prev_di_column = undefined, // no debug info yet | 922 | .prev_di_column = undefined, // no debug info yet |
src/arch/riscv64/Emit.zig+8-8| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | bin_file: *link.File, | 3 | bin_file: *link.File, |
| 4 | lower: Lower, | 4 | lower: Lower, |
| 5 | debug_output: link.File.DebugInfoOutput, | 5 | debug_output: link.File.DebugInfoOutput, |
| 6 | code: *std.ArrayListUnmanaged(u8), | 6 | w: *std.Io.Writer, |
| 7 | 7 | ||
| 8 | prev_di_line: u32, | 8 | prev_di_line: u32, |
| 9 | prev_di_column: u32, | 9 | prev_di_column: u32, |
| ... | @@ -13,7 +13,7 @@ prev_di_pc: usize, | ... | @@ -13,7 +13,7 @@ prev_di_pc: usize, |
| 13 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, | 13 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 14 | relocs: std.ArrayListUnmanaged(Reloc) = .empty, | 14 | relocs: std.ArrayListUnmanaged(Reloc) = .empty, |
| 15 | 15 | ||
| 16 | pub const Error = Lower.Error || error{ | 16 | pub const Error = Lower.Error || std.Io.Writer.Error || error{ |
| 17 | EmitFail, | 17 | EmitFail, |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| ... | @@ -25,13 +25,13 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -25,13 +25,13 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 25 | try emit.code_offset_mapping.putNoClobber( | 25 | try emit.code_offset_mapping.putNoClobber( |
| 26 | emit.lower.allocator, | 26 | emit.lower.allocator, |
| 27 | mir_index, | 27 | mir_index, |
| 28 | @intCast(emit.code.items.len), | 28 | @intCast(emit.w.end), |
| 29 | ); | 29 | ); |
| 30 | const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true }); | 30 | const lowered = try emit.lower.lowerMir(mir_index, .{ .allow_frame_locs = true }); |
| 31 | var lowered_relocs = lowered.relocs; | 31 | var lowered_relocs = lowered.relocs; |
| 32 | for (lowered.insts, 0..) |lowered_inst, lowered_index| { | 32 | for (lowered.insts, 0..) |lowered_inst, lowered_index| { |
| 33 | const start_offset: u32 = @intCast(emit.code.items.len); | 33 | const start_offset: u32 = @intCast(emit.w.end); |
| 34 | std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), lowered_inst.toU32(), .little); | 34 | try emit.w.writeInt(u32, lowered_inst.toU32(), .little); |
| 35 | 35 | ||
| 36 | while (lowered_relocs.len > 0 and | 36 | while (lowered_relocs.len > 0 and |
| 37 | lowered_relocs[0].lowered_inst_index == lowered_index) : ({ | 37 | lowered_relocs[0].lowered_inst_index == lowered_index) : ({ |
| ... | @@ -175,7 +175,7 @@ fn fixupRelocs(emit: *Emit) Error!void { | ... | @@ -175,7 +175,7 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 175 | return emit.fail("relocation target not found!", .{}); | 175 | return emit.fail("relocation target not found!", .{}); |
| 176 | 176 | ||
| 177 | const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); | 177 | const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); |
| 178 | const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4]; | 178 | const code = emit.w.buffered()[reloc.source + reloc.offset ..][0..4]; |
| 179 | 179 | ||
| 180 | switch (reloc.fmt) { | 180 | switch (reloc.fmt) { |
| 181 | .J => riscv_util.writeInstJ(code, @bitCast(disp)), | 181 | .J => riscv_util.writeInstJ(code, @bitCast(disp)), |
| ... | @@ -187,7 +187,7 @@ fn fixupRelocs(emit: *Emit) Error!void { | ... | @@ -187,7 +187,7 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 187 | 187 | ||
| 188 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { | 188 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { |
| 189 | const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); | 189 | const delta_line = @as(i33, line) - @as(i33, emit.prev_di_line); |
| 190 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; | 190 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 191 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); | 191 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 192 | switch (emit.debug_output) { | 192 | switch (emit.debug_output) { |
| 193 | .dwarf => |dw| { | 193 | .dwarf => |dw| { |
| ... | @@ -196,7 +196,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { | ... | @@ -196,7 +196,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { |
| 196 | try dw.advancePCAndLine(delta_line, delta_pc); | 196 | try dw.advancePCAndLine(delta_line, delta_pc); |
| 197 | emit.prev_di_line = line; | 197 | emit.prev_di_line = line; |
| 198 | emit.prev_di_column = column; | 198 | emit.prev_di_column = column; |
| 199 | emit.prev_di_pc = emit.code.items.len; | 199 | emit.prev_di_pc = emit.w.end; |
| 200 | }, | 200 | }, |
| 201 | .none => {}, | 201 | .none => {}, |
| 202 | } | 202 | } |
src/arch/riscv64/Mir.zig+5-3| ... | @@ -109,9 +109,11 @@ pub fn emit( | ... | @@ -109,9 +109,11 @@ pub fn emit( |
| 109 | pt: Zcu.PerThread, | 109 | pt: Zcu.PerThread, |
| 110 | src_loc: Zcu.LazySrcLoc, | 110 | src_loc: Zcu.LazySrcLoc, |
| 111 | func_index: InternPool.Index, | 111 | func_index: InternPool.Index, |
| 112 | code: *std.ArrayListUnmanaged(u8), | 112 | atom_index: u32, |
| 113 | w: *std.Io.Writer, | ||
| 113 | debug_output: link.File.DebugInfoOutput, | 114 | debug_output: link.File.DebugInfoOutput, |
| 114 | ) codegen.CodeGenError!void { | 115 | ) (codegen.CodeGenError || std.Io.Writer.Error)!void { |
| 116 | _ = atom_index; | ||
| 115 | const zcu = pt.zcu; | 117 | const zcu = pt.zcu; |
| 116 | const comp = zcu.comp; | 118 | const comp = zcu.comp; |
| 117 | const gpa = comp.gpa; | 119 | const gpa = comp.gpa; |
| ... | @@ -132,7 +134,7 @@ pub fn emit( | ... | @@ -132,7 +134,7 @@ pub fn emit( |
| 132 | }, | 134 | }, |
| 133 | .bin_file = lf, | 135 | .bin_file = lf, |
| 134 | .debug_output = debug_output, | 136 | .debug_output = debug_output, |
| 135 | .code = code, | 137 | .w = w, |
| 136 | .prev_di_pc = 0, | 138 | .prev_di_pc = 0, |
| 137 | .prev_di_line = func.lbrace_line, | 139 | .prev_di_line = func.lbrace_line, |
| 138 | .prev_di_column = func.lbrace_column, | 140 | .prev_di_column = func.lbrace_column, |
src/arch/sparc64/Emit.zig+7-12| ... | @@ -21,7 +21,7 @@ debug_output: link.File.DebugInfoOutput, | ... | @@ -21,7 +21,7 @@ debug_output: link.File.DebugInfoOutput, |
| 21 | target: *const std.Target, | 21 | target: *const std.Target, |
| 22 | err_msg: ?*ErrorMsg = null, | 22 | err_msg: ?*ErrorMsg = null, |
| 23 | src_loc: Zcu.LazySrcLoc, | 23 | src_loc: Zcu.LazySrcLoc, |
| 24 | code: *std.ArrayListUnmanaged(u8), | 24 | w: *std.Io.Writer, |
| 25 | 25 | ||
| 26 | prev_di_line: u32, | 26 | prev_di_line: u32, |
| 27 | prev_di_column: u32, | 27 | prev_di_column: u32, |
| ... | @@ -40,7 +40,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn | ... | @@ -40,7 +40,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn |
| 40 | /// instruction | 40 | /// instruction |
| 41 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, | 41 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 42 | 42 | ||
| 43 | const InnerError = error{ | 43 | const InnerError = std.Io.Writer.Error || error{ |
| 44 | OutOfMemory, | 44 | OutOfMemory, |
| 45 | EmitFail, | 45 | EmitFail, |
| 46 | }; | 46 | }; |
| ... | @@ -292,7 +292,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -292,7 +292,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 292 | .bpcc => switch (tag) { | 292 | .bpcc => switch (tag) { |
| 293 | .bpcc => { | 293 | .bpcc => { |
| 294 | const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int; | 294 | const branch_predict_int = emit.mir.instructions.items(.data)[inst].branch_predict_int; |
| 295 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.code.items.len)); | 295 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_int.inst).?)) - @as(i64, @intCast(emit.w.end)); |
| 296 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); | 296 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); |
| 297 | 297 | ||
| 298 | try emit.writeInstruction( | 298 | try emit.writeInstruction( |
| ... | @@ -310,7 +310,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -310,7 +310,7 @@ fn mirConditionalBranch(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 310 | .bpr => switch (tag) { | 310 | .bpr => switch (tag) { |
| 311 | .bpr => { | 311 | .bpr => { |
| 312 | const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg; | 312 | const branch_predict_reg = emit.mir.instructions.items(.data)[inst].branch_predict_reg; |
| 313 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.code.items.len)); | 313 | const offset = @as(i64, @intCast(emit.code_offset_mapping.get(branch_predict_reg.inst).?)) - @as(i64, @intCast(emit.w.end)); |
| 314 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); | 314 | log.debug("mirConditionalBranch: {} offset={}", .{ inst, offset }); |
| 315 | 315 | ||
| 316 | try emit.writeInstruction( | 316 | try emit.writeInstruction( |
| ... | @@ -494,13 +494,13 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { | ... | @@ -494,13 +494,13 @@ fn branchTarget(emit: *Emit, inst: Mir.Inst.Index) Mir.Inst.Index { |
| 494 | 494 | ||
| 495 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { | 495 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { |
| 496 | const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line)); | 496 | const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line)); |
| 497 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; | 497 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 498 | switch (emit.debug_output) { | 498 | switch (emit.debug_output) { |
| 499 | .dwarf => |dbg_out| { | 499 | .dwarf => |dbg_out| { |
| 500 | try dbg_out.advancePCAndLine(delta_line, delta_pc); | 500 | try dbg_out.advancePCAndLine(delta_line, delta_pc); |
| 501 | emit.prev_di_line = line; | 501 | emit.prev_di_line = line; |
| 502 | emit.prev_di_column = column; | 502 | emit.prev_di_column = column; |
| 503 | emit.prev_di_pc = emit.code.items.len; | 503 | emit.prev_di_pc = emit.w.end; |
| 504 | }, | 504 | }, |
| 505 | else => {}, | 505 | else => {}, |
| 506 | } | 506 | } |
| ... | @@ -675,13 +675,8 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { | ... | @@ -675,13 +675,8 @@ fn optimalBranchType(emit: *Emit, tag: Mir.Inst.Tag, offset: i64) !BranchType { |
| 675 | } | 675 | } |
| 676 | 676 | ||
| 677 | fn writeInstruction(emit: *Emit, instruction: Instruction) !void { | 677 | fn writeInstruction(emit: *Emit, instruction: Instruction) !void { |
| 678 | const comp = emit.bin_file.comp; | ||
| 679 | const gpa = comp.gpa; | ||
| 680 | |||
| 681 | // SPARCv9 instructions are always arranged in BE regardless of the | 678 | // SPARCv9 instructions are always arranged in BE regardless of the |
| 682 | // endianness mode the CPU is running in (Section 3.1 of the ISA specification). | 679 | // endianness mode the CPU is running in (Section 3.1 of the ISA specification). |
| 683 | // This is to ease porting in case someone wants to do a LE SPARCv9 backend. | 680 | // This is to ease porting in case someone wants to do a LE SPARCv9 backend. |
| 684 | const endian: Endian = .big; | 681 | try emit.w.writeInt(u32, instruction.toU32(), .big); |
| 685 | |||
| 686 | std.mem.writeInt(u32, try emit.code.addManyAsArray(gpa, 4), instruction.toU32(), endian); | ||
| 687 | } | 682 | } |
src/arch/sparc64/Mir.zig+5-3| ... | @@ -380,9 +380,11 @@ pub fn emit( | ... | @@ -380,9 +380,11 @@ pub fn emit( |
| 380 | pt: Zcu.PerThread, | 380 | pt: Zcu.PerThread, |
| 381 | src_loc: Zcu.LazySrcLoc, | 381 | src_loc: Zcu.LazySrcLoc, |
| 382 | func_index: InternPool.Index, | 382 | func_index: InternPool.Index, |
| 383 | code: *std.ArrayListUnmanaged(u8), | 383 | atom_index: u32, |
| 384 | w: *std.Io.Writer, | ||
| 384 | debug_output: link.File.DebugInfoOutput, | 385 | debug_output: link.File.DebugInfoOutput, |
| 385 | ) codegen.CodeGenError!void { | 386 | ) (codegen.CodeGenError || std.Io.Writer.Error)!void { |
| 387 | _ = atom_index; | ||
| 386 | const zcu = pt.zcu; | 388 | const zcu = pt.zcu; |
| 387 | const func = zcu.funcInfo(func_index); | 389 | const func = zcu.funcInfo(func_index); |
| 388 | const nav = func.owner_nav; | 390 | const nav = func.owner_nav; |
| ... | @@ -393,7 +395,7 @@ pub fn emit( | ... | @@ -393,7 +395,7 @@ pub fn emit( |
| 393 | .debug_output = debug_output, | 395 | .debug_output = debug_output, |
| 394 | .target = &mod.resolved_target.result, | 396 | .target = &mod.resolved_target.result, |
| 395 | .src_loc = src_loc, | 397 | .src_loc = src_loc, |
| 396 | .code = code, | 398 | .w = w, |
| 397 | .prev_di_pc = 0, | 399 | .prev_di_pc = 0, |
| 398 | .prev_di_line = func.lbrace_line, | 400 | .prev_di_line = func.lbrace_line, |
| 399 | .prev_di_column = func.lbrace_column, | 401 | .prev_di_column = func.lbrace_column, |
src/arch/x86_64/CodeGen.zig+9-8| ... | @@ -550,9 +550,9 @@ pub const MCValue = union(enum) { | ... | @@ -550,9 +550,9 @@ pub const MCValue = union(enum) { |
| 550 | @tagName(pl.reg), | 550 | @tagName(pl.reg), |
| 551 | }), | 551 | }), |
| 552 | .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), | 552 | .indirect => |pl| try w.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), |
| 553 | .indirect_load_frame => |pl| try w.print("[[{} + 0x{x}]]", .{ pl.index, pl.off }), | 553 | .indirect_load_frame => |pl| try w.print("[[{f} + 0x{x}]]", .{ pl.index, pl.off }), |
| 554 | .load_frame => |pl| try w.print("[{} + 0x{x}]", .{ pl.index, pl.off }), | 554 | .load_frame => |pl| try w.print("[{f} + 0x{x}]", .{ pl.index, pl.off }), |
| 555 | .lea_frame => |pl| try w.print("{} + 0x{x}", .{ pl.index, pl.off }), | 555 | .lea_frame => |pl| try w.print("{f} + 0x{x}", .{ pl.index, pl.off }), |
| 556 | .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}), | 556 | .load_nav => |pl| try w.print("[nav:{d}]", .{@intFromEnum(pl)}), |
| 557 | .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}), | 557 | .lea_nav => |pl| try w.print("nav:{d}", .{@intFromEnum(pl)}), |
| 558 | .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}), | 558 | .load_uav => |pl| try w.print("[uav:{d}]", .{@intFromEnum(pl.val)}), |
| ... | @@ -561,10 +561,10 @@ pub const MCValue = union(enum) { | ... | @@ -561,10 +561,10 @@ pub const MCValue = union(enum) { |
| 561 | .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), | 561 | .lea_lazy_sym => |pl| try w.print("lazy:{s}:{d}", .{ @tagName(pl.kind), @intFromEnum(pl.ty) }), |
| 562 | .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}), | 562 | .load_extern_func => |pl| try w.print("[extern:{d}]", .{@intFromEnum(pl)}), |
| 563 | .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}), | 563 | .lea_extern_func => |pl| try w.print("extern:{d}", .{@intFromEnum(pl)}), |
| 564 | .elementwise_args => |pl| try w.print("elementwise:{d}:[{} + 0x{x}]", .{ | 564 | .elementwise_args => |pl| try w.print("elementwise:{d}:[{f} + 0x{x}]", .{ |
| 565 | pl.regs, pl.frame_index, pl.frame_off, | 565 | pl.regs, pl.frame_index, pl.frame_off, |
| 566 | }), | 566 | }), |
| 567 | .reserved_frame => |pl| try w.print("(dead:{})", .{pl}), | 567 | .reserved_frame => |pl| try w.print("(dead:{f})", .{pl}), |
| 568 | .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}), | 568 | .air_ref => |pl| try w.print("(air:0x{x})", .{@intFromEnum(pl)}), |
| 569 | } | 569 | } |
| 570 | } | 570 | } |
| ... | @@ -1038,7 +1038,8 @@ pub fn generateLazy( | ... | @@ -1038,7 +1038,8 @@ pub fn generateLazy( |
| 1038 | pt: Zcu.PerThread, | 1038 | pt: Zcu.PerThread, |
| 1039 | src_loc: Zcu.LazySrcLoc, | 1039 | src_loc: Zcu.LazySrcLoc, |
| 1040 | lazy_sym: link.File.LazySymbol, | 1040 | lazy_sym: link.File.LazySymbol, |
| 1041 | code: *std.ArrayListUnmanaged(u8), | 1041 | atom_index: u32, |
| 1042 | w: *std.Io.Writer, | ||
| 1042 | debug_output: link.File.DebugInfoOutput, | 1043 | debug_output: link.File.DebugInfoOutput, |
| 1043 | ) codegen.CodeGenError!void { | 1044 | ) codegen.CodeGenError!void { |
| 1044 | const gpa = pt.zcu.gpa; | 1045 | const gpa = pt.zcu.gpa; |
| ... | @@ -1081,7 +1082,7 @@ pub fn generateLazy( | ... | @@ -1081,7 +1082,7 @@ pub fn generateLazy( |
| 1081 | else => |e| return e, | 1082 | else => |e| return e, |
| 1082 | }; | 1083 | }; |
| 1083 | 1084 | ||
| 1084 | try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, code, debug_output); | 1085 | try function.getTmpMir().emitLazy(bin_file, pt, src_loc, lazy_sym, atom_index, w, debug_output); |
| 1085 | } | 1086 | } |
| 1086 | 1087 | ||
| 1087 | const FormatNavData = struct { | 1088 | const FormatNavData = struct { |
| ... | @@ -2022,7 +2023,7 @@ fn gen( | ... | @@ -2022,7 +2023,7 @@ fn gen( |
| 2022 | .{}, | 2023 | .{}, |
| 2023 | ); | 2024 | ); |
| 2024 | self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; | 2025 | self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } }; |
| 2025 | tracking_log.debug("spill {f} to {}", .{ self.ret_mcv.long, frame_index }); | 2026 | tracking_log.debug("spill {f} to {f}", .{ self.ret_mcv.long, frame_index }); |
| 2026 | }, | 2027 | }, |
| 2027 | else => unreachable, | 2028 | else => unreachable, |
| 2028 | } | 2029 | } |
src/arch/x86_64/Emit.zig+76-32| ... | @@ -6,7 +6,7 @@ pt: Zcu.PerThread, | ... | @@ -6,7 +6,7 @@ pt: Zcu.PerThread, |
| 6 | pic: bool, | 6 | pic: bool, |
| 7 | atom_index: u32, | 7 | atom_index: u32, |
| 8 | debug_output: link.File.DebugInfoOutput, | 8 | debug_output: link.File.DebugInfoOutput, |
| 9 | code: *std.ArrayListUnmanaged(u8), | 9 | w: *std.Io.Writer, |
| 10 | 10 | ||
| 11 | prev_di_loc: Loc, | 11 | prev_di_loc: Loc, |
| 12 | /// Relative to the beginning of `code`. | 12 | /// Relative to the beginning of `code`. |
| ... | @@ -18,7 +18,8 @@ table_relocs: std.ArrayListUnmanaged(TableReloc), | ... | @@ -18,7 +18,8 @@ table_relocs: std.ArrayListUnmanaged(TableReloc), |
| 18 | 18 | ||
| 19 | pub const Error = Lower.Error || error{ | 19 | pub const Error = Lower.Error || error{ |
| 20 | EmitFail, | 20 | EmitFail, |
| 21 | } || link.File.UpdateDebugInfoError; | 21 | NotFile, |
| 22 | } || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError; | ||
| 22 | 23 | ||
| 23 | pub fn emitMir(emit: *Emit) Error!void { | 24 | pub fn emitMir(emit: *Emit) Error!void { |
| 24 | const comp = emit.bin_file.comp; | 25 | const comp = emit.bin_file.comp; |
| ... | @@ -29,12 +30,12 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -29,12 +30,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 29 | var local_index: usize = 0; | 30 | var local_index: usize = 0; |
| 30 | for (0..emit.lower.mir.instructions.len) |mir_i| { | 31 | for (0..emit.lower.mir.instructions.len) |mir_i| { |
| 31 | const mir_index: Mir.Inst.Index = @intCast(mir_i); | 32 | const mir_index: Mir.Inst.Index = @intCast(mir_i); |
| 32 | emit.code_offset_mapping.items[mir_index] = @intCast(emit.code.items.len); | 33 | emit.code_offset_mapping.items[mir_index] = @intCast(emit.w.end); |
| 33 | const lowered = try emit.lower.lowerMir(mir_index); | 34 | const lowered = try emit.lower.lowerMir(mir_index); |
| 34 | var lowered_relocs = lowered.relocs; | 35 | var lowered_relocs = lowered.relocs; |
| 35 | lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| { | 36 | lowered_inst: for (lowered.insts, 0..) |lowered_inst, lowered_index| { |
| 36 | if (lowered_inst.prefix == .directive) { | 37 | if (lowered_inst.prefix == .directive) { |
| 37 | const start_offset: u32 = @intCast(emit.code.items.len); | 38 | const start_offset: u32 = @intCast(emit.w.end); |
| 38 | switch (emit.debug_output) { | 39 | switch (emit.debug_output) { |
| 39 | .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) { | 40 | .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) { |
| 40 | .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ | 41 | .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ |
| ... | @@ -164,6 +165,8 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -164,6 +165,8 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 164 | .index = if (emit.bin_file.cast(.elf)) |elf_file| | 165 | .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 165 | elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err| | 166 | elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, emit.pt, lazy_sym) catch |err| |
| 166 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) | 167 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| 168 | else if (emit.bin_file.cast(.elf2)) |elf| | ||
| 169 | @intFromEnum(try elf.lazySymbol(lazy_sym)) | ||
| 167 | else if (emit.bin_file.cast(.macho)) |macho_file| | 170 | else if (emit.bin_file.cast(.macho)) |macho_file| |
| 168 | macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| | 171 | macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, emit.pt, lazy_sym) catch |err| |
| 169 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) | 172 | return emit.fail("{s} creating lazy symbol", .{@errorName(err)}) |
| ... | @@ -180,12 +183,15 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -180,12 +183,15 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 180 | .extern_func => |extern_func| .{ | 183 | .extern_func => |extern_func| .{ |
| 181 | .index = if (emit.bin_file.cast(.elf)) |elf_file| | 184 | .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 182 | try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) | 185 | try elf_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) |
| 183 | else if (emit.bin_file.cast(.macho)) |macho_file| | 186 | else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ |
| 187 | .name = extern_func.toSlice(&emit.lower.mir).?, | ||
| 188 | .type = .FUNC, | ||
| 189 | })) else if (emit.bin_file.cast(.macho)) |macho_file| | ||
| 184 | try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) | 190 | try macho_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, null) |
| 185 | else if (emit.bin_file.cast(.coff)) |coff_file| | 191 | else if (emit.bin_file.cast(.coff)) |coff_file| |
| 186 | try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt") | 192 | try coff_file.getGlobalSymbol(extern_func.toSlice(&emit.lower.mir).?, "compiler_rt") |
| 187 | else | 193 | else |
| 188 | return emit.fail("external symbols unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), | 194 | return emit.fail("external symbol unimplemented for {s}", .{@tagName(emit.bin_file.tag)}), |
| 189 | .is_extern = true, | 195 | .is_extern = true, |
| 190 | .type = .symbol, | 196 | .type = .symbol, |
| 191 | }, | 197 | }, |
| ... | @@ -205,7 +211,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -205,7 +211,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 205 | }, | 211 | }, |
| 206 | else => {}, | 212 | else => {}, |
| 207 | } | 213 | } |
| 208 | if (emit.bin_file.cast(.elf)) |_| { | 214 | if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) { |
| 209 | if (!emit.pic) switch (lowered_inst.encoding.mnemonic) { | 215 | if (!emit.pic) switch (lowered_inst.encoding.mnemonic) { |
| 210 | .lea => try emit.encodeInst(try .new(.none, .mov, &.{ | 216 | .lea => try emit.encodeInst(try .new(.none, .mov, &.{ |
| 211 | lowered_inst.ops[0], | 217 | lowered_inst.ops[0], |
| ... | @@ -315,7 +321,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -315,7 +321,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 315 | }, | 321 | }, |
| 316 | .branch, .tls => unreachable, | 322 | .branch, .tls => unreachable, |
| 317 | .tlv => { | 323 | .tlv => { |
| 318 | if (emit.bin_file.cast(.elf)) |elf_file| { | 324 | if (emit.bin_file.cast(.elf) != null or emit.bin_file.cast(.elf2) != null) { |
| 319 | // TODO handle extern TLS vars, i.e., emit GD model | 325 | // TODO handle extern TLS vars, i.e., emit GD model |
| 320 | if (emit.pic) switch (lowered_inst.encoding.mnemonic) { | 326 | if (emit.pic) switch (lowered_inst.encoding.mnemonic) { |
| 321 | .lea, .mov => { | 327 | .lea, .mov => { |
| ... | @@ -337,7 +343,12 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -337,7 +343,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 337 | }, emit.lower.target), &.{.{ | 343 | }, emit.lower.target), &.{.{ |
| 338 | .op_index = 0, | 344 | .op_index = 0, |
| 339 | .target = .{ | 345 | .target = .{ |
| 340 | .index = try elf_file.getGlobalSymbol("__tls_get_addr", null), | 346 | .index = if (emit.bin_file.cast(.elf)) |elf_file| |
| 347 | try elf_file.getGlobalSymbol("__tls_get_addr", null) | ||
| 348 | else if (emit.bin_file.cast(.elf2)) |elf| @intFromEnum(try elf.globalSymbol(.{ | ||
| 349 | .name = "__tls_get_addr", | ||
| 350 | .type = .FUNC, | ||
| 351 | })) else unreachable, | ||
| 341 | .is_extern = true, | 352 | .is_extern = true, |
| 342 | .type = .branch, | 353 | .type = .branch, |
| 343 | }, | 354 | }, |
| ... | @@ -441,7 +452,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -441,7 +452,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 441 | log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ | 452 | log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ |
| 442 | emit.prev_di_loc.line, emit.prev_di_loc.column, | 453 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 443 | }); | 454 | }); |
| 444 | try dwarf.enterBlock(emit.code.items.len); | 455 | try dwarf.enterBlock(emit.w.end); |
| 445 | }, | 456 | }, |
| 446 | .none => {}, | 457 | .none => {}, |
| 447 | }, | 458 | }, |
| ... | @@ -450,7 +461,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -450,7 +461,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 450 | log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ | 461 | log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ |
| 451 | emit.prev_di_loc.line, emit.prev_di_loc.column, | 462 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 452 | }); | 463 | }); |
| 453 | try dwarf.leaveBlock(emit.code.items.len); | 464 | try dwarf.leaveBlock(emit.w.end); |
| 454 | }, | 465 | }, |
| 455 | .none => {}, | 466 | .none => {}, |
| 456 | }, | 467 | }, |
| ... | @@ -459,7 +470,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -459,7 +470,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 459 | log.debug("mirDbgEnterInline (line={d}, col={d})", .{ | 470 | log.debug("mirDbgEnterInline (line={d}, col={d})", .{ |
| 460 | emit.prev_di_loc.line, emit.prev_di_loc.column, | 471 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 461 | }); | 472 | }); |
| 462 | try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.code.items.len, emit.prev_di_loc.line, emit.prev_di_loc.column); | 473 | try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column); |
| 463 | }, | 474 | }, |
| 464 | .none => {}, | 475 | .none => {}, |
| 465 | }, | 476 | }, |
| ... | @@ -468,7 +479,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -468,7 +479,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 468 | log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ | 479 | log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ |
| 469 | emit.prev_di_loc.line, emit.prev_di_loc.column, | 480 | emit.prev_di_loc.line, emit.prev_di_loc.column, |
| 470 | }); | 481 | }); |
| 471 | try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.code.items.len); | 482 | try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end); |
| 472 | }, | 483 | }, |
| 473 | .none => {}, | 484 | .none => {}, |
| 474 | }, | 485 | }, |
| ... | @@ -634,7 +645,7 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -634,7 +645,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 634 | for (emit.relocs.items) |reloc| { | 645 | for (emit.relocs.items) |reloc| { |
| 635 | const target = emit.code_offset_mapping.items[reloc.target]; | 646 | const target = emit.code_offset_mapping.items[reloc.target]; |
| 636 | const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset; | 647 | const disp = @as(i64, @intCast(target)) - @as(i64, @intCast(reloc.inst_offset + reloc.inst_length)) + reloc.target_offset; |
| 637 | const inst_bytes = emit.code.items[reloc.inst_offset..][0..reloc.inst_length]; | 648 | const inst_bytes = emit.w.buffered()[reloc.inst_offset..][0..reloc.inst_length]; |
| 638 | switch (reloc.source_length) { | 649 | switch (reloc.source_length) { |
| 639 | else => unreachable, | 650 | else => unreachable, |
| 640 | inline 1, 4 => |source_length| std.mem.writeInt( | 651 | inline 1, 4 => |source_length| std.mem.writeInt( |
| ... | @@ -646,12 +657,12 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -646,12 +657,12 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 646 | } | 657 | } |
| 647 | } | 658 | } |
| 648 | if (emit.lower.mir.table.len > 0) { | 659 | if (emit.lower.mir.table.len > 0) { |
| 660 | const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8); | ||
| 661 | var table_offset = std.mem.alignForward(u32, @intCast(emit.w.end), ptr_size); | ||
| 649 | if (emit.bin_file.cast(.elf)) |elf_file| { | 662 | if (emit.bin_file.cast(.elf)) |elf_file| { |
| 650 | const zo = elf_file.zigObjectPtr().?; | 663 | const zo = elf_file.zigObjectPtr().?; |
| 651 | const atom = zo.symbol(emit.atom_index).atom(elf_file).?; | 664 | const atom = zo.symbol(emit.atom_index).atom(elf_file).?; |
| 652 | 665 | ||
| 653 | const ptr_size = @divExact(emit.lower.target.ptrBitWidth(), 8); | ||
| 654 | var table_offset = std.mem.alignForward(u32, @intCast(emit.code.items.len), ptr_size); | ||
| 655 | for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{ | 666 | for (emit.table_relocs.items) |table_reloc| try atom.addReloc(gpa, .{ |
| 656 | .r_offset = table_reloc.source_offset, | 667 | .r_offset = table_reloc.source_offset, |
| 657 | .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"), | 668 | .r_info = @as(u64, emit.atom_index) << 32 | @intFromEnum(std.elf.R_X86_64.@"32"), |
| ... | @@ -665,7 +676,26 @@ pub fn emitMir(emit: *Emit) Error!void { | ... | @@ -665,7 +676,26 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 665 | }, zo); | 676 | }, zo); |
| 666 | table_offset += ptr_size; | 677 | table_offset += ptr_size; |
| 667 | } | 678 | } |
| 668 | try emit.code.appendNTimes(gpa, 0, table_offset - emit.code.items.len); | 679 | try emit.w.splatByteAll(0, table_offset - emit.w.end); |
| 680 | } else if (emit.bin_file.cast(.elf2)) |elf| { | ||
| 681 | for (emit.table_relocs.items) |table_reloc| try elf.addReloc( | ||
| 682 | @enumFromInt(emit.atom_index), | ||
| 683 | table_reloc.source_offset, | ||
| 684 | @enumFromInt(emit.atom_index), | ||
| 685 | @as(i64, table_offset) + table_reloc.target_offset, | ||
| 686 | .{ .x86_64 = .@"32" }, | ||
| 687 | ); | ||
| 688 | for (emit.lower.mir.table) |entry| { | ||
| 689 | try elf.addReloc( | ||
| 690 | @enumFromInt(emit.atom_index), | ||
| 691 | table_offset, | ||
| 692 | @enumFromInt(emit.atom_index), | ||
| 693 | emit.code_offset_mapping.items[entry], | ||
| 694 | .{ .x86_64 = .@"64" }, | ||
| 695 | ); | ||
| 696 | table_offset += ptr_size; | ||
| 697 | } | ||
| 698 | try emit.w.splatByteAll(0, table_offset - emit.w.end); | ||
| 669 | } else unreachable; | 699 | } else unreachable; |
| 670 | } | 700 | } |
| 671 | } | 701 | } |
| ... | @@ -696,16 +726,12 @@ const RelocInfo = struct { | ... | @@ -696,16 +726,12 @@ const RelocInfo = struct { |
| 696 | fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void { | 726 | fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocInfo) Error!void { |
| 697 | const comp = emit.bin_file.comp; | 727 | const comp = emit.bin_file.comp; |
| 698 | const gpa = comp.gpa; | 728 | const gpa = comp.gpa; |
| 699 | const start_offset: u32 = @intCast(emit.code.items.len); | 729 | const start_offset: u32 = @intCast(emit.w.end); |
| 700 | { | 730 | lowered_inst.encode(emit.w, .{}) catch |err| switch (err) { |
| 701 | var aw: std.Io.Writer.Allocating = .fromArrayList(gpa, emit.code); | 731 | error.WriteFailed => return error.OutOfMemory, |
| 702 | defer emit.code.* = aw.toArrayList(); | 732 | else => |e| return e, |
| 703 | lowered_inst.encode(&aw.writer, .{}) catch |err| switch (err) { | 733 | }; |
| 704 | error.WriteFailed => return error.OutOfMemory, | 734 | const end_offset: u32 = @intCast(emit.w.end); |
| 705 | else => |e| return e, | ||
| 706 | }; | ||
| 707 | } | ||
| 708 | const end_offset: u32 = @intCast(emit.code.items.len); | ||
| 709 | for (reloc_info) |reloc| switch (reloc.target.type) { | 735 | for (reloc_info) |reloc| switch (reloc.target.type) { |
| 710 | .inst => { | 736 | .inst => { |
| 711 | const inst_length: u4 = @intCast(end_offset - start_offset); | 737 | const inst_length: u4 = @intCast(end_offset - start_offset); |
| ... | @@ -769,7 +795,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI | ... | @@ -769,7 +795,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 769 | .symbolnum = @intCast(reloc.target.index), | 795 | .symbolnum = @intCast(reloc.target.index), |
| 770 | }, | 796 | }, |
| 771 | }); | 797 | }); |
| 772 | } else if (emit.bin_file.cast(.coff)) |coff_file| { | 798 | } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 799 | @enumFromInt(emit.atom_index), | ||
| 800 | end_offset - 4, | ||
| 801 | @enumFromInt(reloc.target.index), | ||
| 802 | reloc.off, | ||
| 803 | .{ .x86_64 = .@"32" }, | ||
| 804 | ) else if (emit.bin_file.cast(.coff)) |coff_file| { | ||
| 773 | const atom_index = coff_file.getAtomIndexForSymbol( | 805 | const atom_index = coff_file.getAtomIndexForSymbol( |
| 774 | .{ .sym_index = emit.atom_index, .file = null }, | 806 | .{ .sym_index = emit.atom_index, .file = null }, |
| 775 | ).?; | 807 | ).?; |
| ... | @@ -794,7 +826,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI | ... | @@ -794,7 +826,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 794 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), | 826 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), |
| 795 | .r_addend = reloc.off - 4, | 827 | .r_addend = reloc.off - 4, |
| 796 | }, zo); | 828 | }, zo); |
| 797 | } else if (emit.bin_file.cast(.macho)) |macho_file| { | 829 | } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 830 | @enumFromInt(emit.atom_index), | ||
| 831 | end_offset - 4, | ||
| 832 | @enumFromInt(reloc.target.index), | ||
| 833 | reloc.off - 4, | ||
| 834 | .{ .x86_64 = .PC32 }, | ||
| 835 | ) else if (emit.bin_file.cast(.macho)) |macho_file| { | ||
| 798 | const zo = macho_file.getZigObject().?; | 836 | const zo = macho_file.getZigObject().?; |
| 799 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; | 837 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
| 800 | try atom.addReloc(macho_file, .{ | 838 | try atom.addReloc(macho_file, .{ |
| ... | @@ -849,7 +887,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI | ... | @@ -849,7 +887,13 @@ fn encodeInst(emit: *Emit, lowered_inst: Instruction, reloc_info: []const RelocI |
| 849 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), | 887 | .r_info = @as(u64, reloc.target.index) << 32 | @intFromEnum(r_type), |
| 850 | .r_addend = reloc.off, | 888 | .r_addend = reloc.off, |
| 851 | }, zo); | 889 | }, zo); |
| 852 | } else if (emit.bin_file.cast(.macho)) |macho_file| { | 890 | } else if (emit.bin_file.cast(.elf2)) |elf| try elf.addReloc( |
| 891 | @enumFromInt(emit.atom_index), | ||
| 892 | end_offset - 4, | ||
| 893 | @enumFromInt(reloc.target.index), | ||
| 894 | reloc.off, | ||
| 895 | .{ .x86_64 = .TPOFF32 }, | ||
| 896 | ) else if (emit.bin_file.cast(.macho)) |macho_file| { | ||
| 853 | const zo = macho_file.getZigObject().?; | 897 | const zo = macho_file.getZigObject().?; |
| 854 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; | 898 | const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?; |
| 855 | try atom.addReloc(macho_file, .{ | 899 | try atom.addReloc(macho_file, .{ |
| ... | @@ -908,7 +952,7 @@ const Loc = struct { | ... | @@ -908,7 +952,7 @@ const Loc = struct { |
| 908 | 952 | ||
| 909 | fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { | 953 | fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { |
| 910 | const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); | 954 | const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); |
| 911 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; | 955 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 912 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); | 956 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 913 | switch (emit.debug_output) { | 957 | switch (emit.debug_output) { |
| 914 | .dwarf => |dwarf| { | 958 | .dwarf => |dwarf| { |
| ... | @@ -916,7 +960,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { | ... | @@ -916,7 +960,7 @@ fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { |
| 916 | if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); | 960 | if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); |
| 917 | try dwarf.advancePCAndLine(delta_line, delta_pc); | 961 | try dwarf.advancePCAndLine(delta_line, delta_pc); |
| 918 | emit.prev_di_loc = loc; | 962 | emit.prev_di_loc = loc; |
| 919 | emit.prev_di_pc = emit.code.items.len; | 963 | emit.prev_di_pc = emit.w.end; |
| 920 | }, | 964 | }, |
| 921 | .none => {}, | 965 | .none => {}, |
| 922 | } | 966 | } |
src/arch/x86_64/Mir.zig+8-25| ... | @@ -1976,7 +1976,8 @@ pub fn emit( | ... | @@ -1976,7 +1976,8 @@ pub fn emit( |
| 1976 | pt: Zcu.PerThread, | 1976 | pt: Zcu.PerThread, |
| 1977 | src_loc: Zcu.LazySrcLoc, | 1977 | src_loc: Zcu.LazySrcLoc, |
| 1978 | func_index: InternPool.Index, | 1978 | func_index: InternPool.Index, |
| 1979 | code: *std.ArrayListUnmanaged(u8), | 1979 | atom_index: u32, |
| 1980 | w: *std.Io.Writer, | ||
| 1980 | debug_output: link.File.DebugInfoOutput, | 1981 | debug_output: link.File.DebugInfoOutput, |
| 1981 | ) codegen.CodeGenError!void { | 1982 | ) codegen.CodeGenError!void { |
| 1982 | const zcu = pt.zcu; | 1983 | const zcu = pt.zcu; |
| ... | @@ -1997,17 +1998,9 @@ pub fn emit( | ... | @@ -1997,17 +1998,9 @@ pub fn emit( |
| 1997 | .bin_file = lf, | 1998 | .bin_file = lf, |
| 1998 | .pt = pt, | 1999 | .pt = pt, |
| 1999 | .pic = mod.pic, | 2000 | .pic = mod.pic, |
| 2000 | .atom_index = sym: { | 2001 | .atom_index = atom_index, |
| 2001 | if (lf.cast(.elf)) |ef| break :sym try ef.zigObjectPtr().?.getOrCreateMetadataForNav(zcu, nav); | ||
| 2002 | if (lf.cast(.macho)) |mf| break :sym try mf.getZigObject().?.getOrCreateMetadataForNav(mf, nav); | ||
| 2003 | if (lf.cast(.coff)) |cf| { | ||
| 2004 | const atom = try cf.getOrCreateAtomForNav(nav); | ||
| 2005 | break :sym cf.getAtom(atom).getSymbolIndex().?; | ||
| 2006 | } | ||
| 2007 | unreachable; | ||
| 2008 | }, | ||
| 2009 | .debug_output = debug_output, | 2002 | .debug_output = debug_output, |
| 2010 | .code = code, | 2003 | .w = w, |
| 2011 | 2004 | ||
| 2012 | .prev_di_loc = .{ | 2005 | .prev_di_loc = .{ |
| 2013 | .line = func.lbrace_line, | 2006 | .line = func.lbrace_line, |
| ... | @@ -2037,7 +2030,8 @@ pub fn emitLazy( | ... | @@ -2037,7 +2030,8 @@ pub fn emitLazy( |
| 2037 | pt: Zcu.PerThread, | 2030 | pt: Zcu.PerThread, |
| 2038 | src_loc: Zcu.LazySrcLoc, | 2031 | src_loc: Zcu.LazySrcLoc, |
| 2039 | lazy_sym: link.File.LazySymbol, | 2032 | lazy_sym: link.File.LazySymbol, |
| 2040 | code: *std.ArrayListUnmanaged(u8), | 2033 | atom_index: u32, |
| 2034 | w: *std.Io.Writer, | ||
| 2041 | debug_output: link.File.DebugInfoOutput, | 2035 | debug_output: link.File.DebugInfoOutput, |
| 2042 | ) codegen.CodeGenError!void { | 2036 | ) codegen.CodeGenError!void { |
| 2043 | const zcu = pt.zcu; | 2037 | const zcu = pt.zcu; |
| ... | @@ -2055,20 +2049,9 @@ pub fn emitLazy( | ... | @@ -2055,20 +2049,9 @@ pub fn emitLazy( |
| 2055 | .bin_file = lf, | 2049 | .bin_file = lf, |
| 2056 | .pt = pt, | 2050 | .pt = pt, |
| 2057 | .pic = mod.pic, | 2051 | .pic = mod.pic, |
| 2058 | .atom_index = sym: { | 2052 | .atom_index = atom_index, |
| 2059 | if (lf.cast(.elf)) |ef| break :sym ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_sym) catch |err| | ||
| 2060 | return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); | ||
| 2061 | if (lf.cast(.macho)) |mf| break :sym mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_sym) catch |err| | ||
| 2062 | return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); | ||
| 2063 | if (lf.cast(.coff)) |cf| { | ||
| 2064 | const atom = cf.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err| | ||
| 2065 | return zcu.codegenFailType(lazy_sym.ty, "{s} creating lazy symbol", .{@errorName(err)}); | ||
| 2066 | break :sym cf.getAtom(atom).getSymbolIndex().?; | ||
| 2067 | } | ||
| 2068 | unreachable; | ||
| 2069 | }, | ||
| 2070 | .debug_output = debug_output, | 2053 | .debug_output = debug_output, |
| 2071 | .code = code, | 2054 | .w = w, |
| 2072 | 2055 | ||
| 2073 | .prev_di_loc = undefined, | 2056 | .prev_di_loc = undefined, |
| 2074 | .prev_di_pc = undefined, | 2057 | .prev_di_pc = undefined, |
src/arch/x86_64/bits.zig+8| ... | @@ -727,6 +727,14 @@ pub const FrameIndex = enum(u32) { | ... | @@ -727,6 +727,14 @@ pub const FrameIndex = enum(u32) { |
| 727 | pub fn isNamed(fi: FrameIndex) bool { | 727 | pub fn isNamed(fi: FrameIndex) bool { |
| 728 | return @intFromEnum(fi) < named_count; | 728 | return @intFromEnum(fi) < named_count; |
| 729 | } | 729 | } |
| 730 | |||
| 731 | pub fn format(fi: FrameIndex, writer: *std.Io.Writer) std.Io.Writer.Error!void { | ||
| 732 | if (fi.isNamed()) { | ||
| 733 | try writer.print("FrameIndex.{t}", .{fi}); | ||
| 734 | } else { | ||
| 735 | try writer.print("FrameIndex({d})", .{@intFromEnum(fi)}); | ||
| 736 | } | ||
| 737 | } | ||
| 730 | }; | 738 | }; |
| 731 | 739 | ||
| 732 | pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; | 740 | pub const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; |
src/arch/x86_64/encoder.zig+1-1| ... | @@ -259,7 +259,7 @@ pub const Instruction = struct { | ... | @@ -259,7 +259,7 @@ pub const Instruction = struct { |
| 259 | switch (sib.base) { | 259 | switch (sib.base) { |
| 260 | .none => any = false, | 260 | .none => any = false, |
| 261 | .reg => |reg| try w.print("{s}", .{@tagName(reg)}), | 261 | .reg => |reg| try w.print("{s}", .{@tagName(reg)}), |
| 262 | .frame => |frame_index| try w.print("{}", .{frame_index}), | 262 | .frame => |frame_index| try w.print("{f}", .{frame_index}), |
| 263 | .table => try w.print("Table", .{}), | 263 | .table => try w.print("Table", .{}), |
| 264 | .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}), | 264 | .rip_inst => |inst_index| try w.print("RipInst({d})", .{inst_index}), |
| 265 | .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}), | 265 | .nav => |nav| try w.print("Nav({d})", .{@intFromEnum(nav)}), |
src/codegen.zig+133-138| ... | @@ -6,7 +6,6 @@ const link = @import("link.zig"); | ... | @@ -6,7 +6,6 @@ const link = @import("link.zig"); |
| 6 | const log = std.log.scoped(.codegen); | 6 | const log = std.log.scoped(.codegen); |
| 7 | const mem = std.mem; | 7 | const mem = std.mem; |
| 8 | const math = std.math; | 8 | const math = std.math; |
| 9 | const ArrayList = std.ArrayList; | ||
| 10 | const target_util = @import("target.zig"); | 9 | const target_util = @import("target.zig"); |
| 11 | const trace = @import("tracy.zig").trace; | 10 | const trace = @import("tracy.zig").trace; |
| 12 | 11 | ||
| ... | @@ -179,10 +178,11 @@ pub fn emitFunction( | ... | @@ -179,10 +178,11 @@ pub fn emitFunction( |
| 179 | pt: Zcu.PerThread, | 178 | pt: Zcu.PerThread, |
| 180 | src_loc: Zcu.LazySrcLoc, | 179 | src_loc: Zcu.LazySrcLoc, |
| 181 | func_index: InternPool.Index, | 180 | func_index: InternPool.Index, |
| 181 | atom_index: u32, | ||
| 182 | any_mir: *const AnyMir, | 182 | any_mir: *const AnyMir, |
| 183 | code: *ArrayList(u8), | 183 | w: *std.Io.Writer, |
| 184 | debug_output: link.File.DebugInfoOutput, | 184 | debug_output: link.File.DebugInfoOutput, |
| 185 | ) CodeGenError!void { | 185 | ) (CodeGenError || std.Io.Writer.Error)!void { |
| 186 | const zcu = pt.zcu; | 186 | const zcu = pt.zcu; |
| 187 | const func = zcu.funcInfo(func_index); | 187 | const func = zcu.funcInfo(func_index); |
| 188 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; | 188 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| ... | @@ -195,7 +195,7 @@ pub fn emitFunction( | ... | @@ -195,7 +195,7 @@ pub fn emitFunction( |
| 195 | => |backend| { | 195 | => |backend| { |
| 196 | dev.check(devFeatureForBackend(backend)); | 196 | dev.check(devFeatureForBackend(backend)); |
| 197 | const mir = &@field(any_mir, AnyMir.tag(backend)); | 197 | const mir = &@field(any_mir, AnyMir.tag(backend)); |
| 198 | return mir.emit(lf, pt, src_loc, func_index, code, debug_output); | 198 | return mir.emit(lf, pt, src_loc, func_index, atom_index, w, debug_output); |
| 199 | }, | 199 | }, |
| 200 | } | 200 | } |
| 201 | } | 201 | } |
| ... | @@ -205,9 +205,10 @@ pub fn generateLazyFunction( | ... | @@ -205,9 +205,10 @@ pub fn generateLazyFunction( |
| 205 | pt: Zcu.PerThread, | 205 | pt: Zcu.PerThread, |
| 206 | src_loc: Zcu.LazySrcLoc, | 206 | src_loc: Zcu.LazySrcLoc, |
| 207 | lazy_sym: link.File.LazySymbol, | 207 | lazy_sym: link.File.LazySymbol, |
| 208 | code: *ArrayList(u8), | 208 | atom_index: u32, |
| 209 | w: *std.Io.Writer, | ||
| 209 | debug_output: link.File.DebugInfoOutput, | 210 | debug_output: link.File.DebugInfoOutput, |
| 210 | ) CodeGenError!void { | 211 | ) (CodeGenError || std.Io.Writer.Error)!void { |
| 211 | const zcu = pt.zcu; | 212 | const zcu = pt.zcu; |
| 212 | const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index| | 213 | const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index| |
| 213 | &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result | 214 | &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result |
| ... | @@ -217,19 +218,11 @@ pub fn generateLazyFunction( | ... | @@ -217,19 +218,11 @@ pub fn generateLazyFunction( |
| 217 | else => unreachable, | 218 | else => unreachable, |
| 218 | inline .stage2_riscv64, .stage2_x86_64 => |backend| { | 219 | inline .stage2_riscv64, .stage2_x86_64 => |backend| { |
| 219 | dev.check(devFeatureForBackend(backend)); | 220 | dev.check(devFeatureForBackend(backend)); |
| 220 | return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output); | 221 | return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_index, w, debug_output); |
| 221 | }, | 222 | }, |
| 222 | } | 223 | } |
| 223 | } | 224 | } |
| 224 | 225 | ||
| 225 | fn writeFloat(comptime F: type, f: F, target: *const std.Target, endian: std.builtin.Endian, code: []u8) void { | ||
| 226 | _ = target; | ||
| 227 | const bits = @typeInfo(F).float.bits; | ||
| 228 | const Int = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } }); | ||
| 229 | const int: Int = @bitCast(f); | ||
| 230 | mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); | ||
| 231 | } | ||
| 232 | |||
| 233 | pub fn generateLazySymbol( | 226 | pub fn generateLazySymbol( |
| 234 | bin_file: *link.File, | 227 | bin_file: *link.File, |
| 235 | pt: Zcu.PerThread, | 228 | pt: Zcu.PerThread, |
| ... | @@ -237,17 +230,14 @@ pub fn generateLazySymbol( | ... | @@ -237,17 +230,14 @@ pub fn generateLazySymbol( |
| 237 | lazy_sym: link.File.LazySymbol, | 230 | lazy_sym: link.File.LazySymbol, |
| 238 | // TODO don't use an "out" parameter like this; put it in the result instead | 231 | // TODO don't use an "out" parameter like this; put it in the result instead |
| 239 | alignment: *Alignment, | 232 | alignment: *Alignment, |
| 240 | code: *ArrayList(u8), | 233 | w: *std.Io.Writer, |
| 241 | debug_output: link.File.DebugInfoOutput, | 234 | debug_output: link.File.DebugInfoOutput, |
| 242 | reloc_parent: link.File.RelocInfo.Parent, | 235 | reloc_parent: link.File.RelocInfo.Parent, |
| 243 | ) CodeGenError!void { | 236 | ) (CodeGenError || std.Io.Writer.Error)!void { |
| 244 | _ = reloc_parent; | ||
| 245 | |||
| 246 | const tracy = trace(@src()); | 237 | const tracy = trace(@src()); |
| 247 | defer tracy.end(); | 238 | defer tracy.end(); |
| 248 | 239 | ||
| 249 | const comp = bin_file.comp; | 240 | const comp = bin_file.comp; |
| 250 | const gpa = comp.gpa; | ||
| 251 | const zcu = pt.zcu; | 241 | const zcu = pt.zcu; |
| 252 | const ip = &zcu.intern_pool; | 242 | const ip = &zcu.intern_pool; |
| 253 | const target = &comp.root_mod.resolved_target.result; | 243 | const target = &comp.root_mod.resolved_target.result; |
| ... | @@ -260,37 +250,36 @@ pub fn generateLazySymbol( | ... | @@ -260,37 +250,36 @@ pub fn generateLazySymbol( |
| 260 | 250 | ||
| 261 | if (lazy_sym.kind == .code) { | 251 | if (lazy_sym.kind == .code) { |
| 262 | alignment.* = target_util.defaultFunctionAlignment(target); | 252 | alignment.* = target_util.defaultFunctionAlignment(target); |
| 263 | return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, code, debug_output); | 253 | return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, reloc_parent.atom_index, w, debug_output); |
| 264 | } | 254 | } |
| 265 | 255 | ||
| 266 | if (lazy_sym.ty == .anyerror_type) { | 256 | if (lazy_sym.ty == .anyerror_type) { |
| 267 | alignment.* = .@"4"; | 257 | alignment.* = .@"4"; |
| 268 | const err_names = ip.global_error_set.getNamesFromMainThread(); | 258 | const err_names = ip.global_error_set.getNamesFromMainThread(); |
| 269 | var offset_index: u32 = @intCast(code.items.len); | 259 | const strings_start: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); |
| 270 | var string_index: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); | 260 | var string_index = strings_start; |
| 271 | try code.resize(gpa, offset_index + string_index); | 261 | try w.rebase(w.end, string_index); |
| 272 | mem.writeInt(u32, code.items[offset_index..][0..4], @intCast(err_names.len), endian); | 262 | w.writeInt(u32, @intCast(err_names.len), endian) catch unreachable; |
| 273 | if (err_names.len == 0) return; | 263 | if (err_names.len == 0) return; |
| 274 | offset_index += 4; | ||
| 275 | for (err_names) |err_name_nts| { | 264 | for (err_names) |err_name_nts| { |
| 276 | const err_name = err_name_nts.toSlice(ip); | 265 | w.writeInt(u32, string_index, endian) catch unreachable; |
| 277 | mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); | 266 | string_index += @intCast(err_name_nts.toSlice(ip).len + 1); |
| 278 | offset_index += 4; | 267 | } |
| 279 | try code.ensureUnusedCapacity(gpa, err_name.len + 1); | 268 | w.writeInt(u32, string_index, endian) catch unreachable; |
| 280 | code.appendSliceAssumeCapacity(err_name); | 269 | try w.rebase(w.end, string_index - strings_start); |
| 281 | code.appendAssumeCapacity(0); | 270 | for (err_names) |err_name_nts| { |
| 282 | string_index += @intCast(err_name.len + 1); | 271 | w.writeAll(err_name_nts.toSlice(ip)) catch unreachable; |
| 272 | w.writeByte(0) catch unreachable; | ||
| 283 | } | 273 | } |
| 284 | mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); | ||
| 285 | } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") { | 274 | } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") { |
| 286 | alignment.* = .@"1"; | 275 | alignment.* = .@"1"; |
| 287 | const enum_ty = Type.fromInterned(lazy_sym.ty); | 276 | const enum_ty = Type.fromInterned(lazy_sym.ty); |
| 288 | const tag_names = enum_ty.enumFields(zcu); | 277 | const tag_names = enum_ty.enumFields(zcu); |
| 289 | for (0..tag_names.len) |tag_index| { | 278 | for (0..tag_names.len) |tag_index| { |
| 290 | const tag_name = tag_names.get(ip)[tag_index].toSlice(ip); | 279 | const tag_name = tag_names.get(ip)[tag_index].toSlice(ip); |
| 291 | try code.ensureUnusedCapacity(gpa, tag_name.len + 1); | 280 | try w.rebase(w.end, tag_name.len + 1); |
| 292 | code.appendSliceAssumeCapacity(tag_name); | 281 | w.writeAll(tag_name) catch unreachable; |
| 293 | code.appendAssumeCapacity(0); | 282 | w.writeByte(0) catch unreachable; |
| 294 | } | 283 | } |
| 295 | } else { | 284 | } else { |
| 296 | return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{ | 285 | return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{ |
| ... | @@ -312,14 +301,13 @@ pub fn generateSymbol( | ... | @@ -312,14 +301,13 @@ pub fn generateSymbol( |
| 312 | pt: Zcu.PerThread, | 301 | pt: Zcu.PerThread, |
| 313 | src_loc: Zcu.LazySrcLoc, | 302 | src_loc: Zcu.LazySrcLoc, |
| 314 | val: Value, | 303 | val: Value, |
| 315 | code: *ArrayList(u8), | 304 | w: *std.Io.Writer, |
| 316 | reloc_parent: link.File.RelocInfo.Parent, | 305 | reloc_parent: link.File.RelocInfo.Parent, |
| 317 | ) GenerateSymbolError!void { | 306 | ) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 318 | const tracy = trace(@src()); | 307 | const tracy = trace(@src()); |
| 319 | defer tracy.end(); | 308 | defer tracy.end(); |
| 320 | 309 | ||
| 321 | const zcu = pt.zcu; | 310 | const zcu = pt.zcu; |
| 322 | const gpa = zcu.gpa; | ||
| 323 | const ip = &zcu.intern_pool; | 311 | const ip = &zcu.intern_pool; |
| 324 | const ty = val.typeOf(zcu); | 312 | const ty = val.typeOf(zcu); |
| 325 | 313 | ||
| ... | @@ -330,7 +318,7 @@ pub fn generateSymbol( | ... | @@ -330,7 +318,7 @@ pub fn generateSymbol( |
| 330 | 318 | ||
| 331 | if (val.isUndef(zcu)) { | 319 | if (val.isUndef(zcu)) { |
| 332 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | 320 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 333 | try code.appendNTimes(gpa, 0xaa, abi_size); | 321 | try w.splatByteAll(0xaa, abi_size); |
| 334 | return; | 322 | return; |
| 335 | } | 323 | } |
| 336 | 324 | ||
| ... | @@ -360,7 +348,7 @@ pub fn generateSymbol( | ... | @@ -360,7 +348,7 @@ pub fn generateSymbol( |
| 360 | .null => unreachable, // non-runtime value | 348 | .null => unreachable, // non-runtime value |
| 361 | .@"unreachable" => unreachable, // non-runtime value | 349 | .@"unreachable" => unreachable, // non-runtime value |
| 362 | .empty_tuple => return, | 350 | .empty_tuple => return, |
| 363 | .false, .true => try code.append(gpa, switch (simple_value) { | 351 | .false, .true => try w.writeByte(switch (simple_value) { |
| 364 | .false => 0, | 352 | .false => 0, |
| 365 | .true => 1, | 353 | .true => 1, |
| 366 | else => unreachable, | 354 | else => unreachable, |
| ... | @@ -376,11 +364,11 @@ pub fn generateSymbol( | ... | @@ -376,11 +364,11 @@ pub fn generateSymbol( |
| 376 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | 364 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 377 | var space: Value.BigIntSpace = undefined; | 365 | var space: Value.BigIntSpace = undefined; |
| 378 | const int_val = val.toBigInt(&space, zcu); | 366 | const int_val = val.toBigInt(&space, zcu); |
| 379 | int_val.writeTwosComplement(try code.addManyAsSlice(gpa, abi_size), endian); | 367 | int_val.writeTwosComplement(try w.writableSlice(abi_size), endian); |
| 380 | }, | 368 | }, |
| 381 | .err => |err| { | 369 | .err => |err| { |
| 382 | const int = try pt.getErrorValue(err.name); | 370 | const int = try pt.getErrorValue(err.name); |
| 383 | mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(int), endian); | 371 | try w.writeInt(u16, @intCast(int), endian); |
| 384 | }, | 372 | }, |
| 385 | .error_union => |error_union| { | 373 | .error_union => |error_union| { |
| 386 | const payload_ty = ty.errorUnionPayload(zcu); | 374 | const payload_ty = ty.errorUnionPayload(zcu); |
| ... | @@ -390,7 +378,7 @@ pub fn generateSymbol( | ... | @@ -390,7 +378,7 @@ pub fn generateSymbol( |
| 390 | }; | 378 | }; |
| 391 | 379 | ||
| 392 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 380 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| 393 | mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); | 381 | try w.writeInt(u16, err_val, endian); |
| 394 | return; | 382 | return; |
| 395 | } | 383 | } |
| 396 | 384 | ||
| ... | @@ -400,63 +388,63 @@ pub fn generateSymbol( | ... | @@ -400,63 +388,63 @@ pub fn generateSymbol( |
| 400 | 388 | ||
| 401 | // error value first when its type is larger than the error union's payload | 389 | // error value first when its type is larger than the error union's payload |
| 402 | if (error_align.order(payload_align) == .gt) { | 390 | if (error_align.order(payload_align) == .gt) { |
| 403 | mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); | 391 | try w.writeInt(u16, err_val, endian); |
| 404 | } | 392 | } |
| 405 | 393 | ||
| 406 | // emit payload part of the error union | 394 | // emit payload part of the error union |
| 407 | { | 395 | { |
| 408 | const begin = code.items.len; | 396 | const begin = w.end; |
| 409 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) { | 397 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) { |
| 410 | .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }), | 398 | .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }), |
| 411 | .payload => |payload| payload, | 399 | .payload => |payload| payload, |
| 412 | }), code, reloc_parent); | 400 | }), w, reloc_parent); |
| 413 | const unpadded_end = code.items.len - begin; | 401 | const unpadded_end = w.end - begin; |
| 414 | const padded_end = abi_align.forward(unpadded_end); | 402 | const padded_end = abi_align.forward(unpadded_end); |
| 415 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 403 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 416 | 404 | ||
| 417 | if (padding > 0) { | 405 | if (padding > 0) { |
| 418 | try code.appendNTimes(gpa, 0, padding); | 406 | try w.splatByteAll(0, padding); |
| 419 | } | 407 | } |
| 420 | } | 408 | } |
| 421 | 409 | ||
| 422 | // Payload size is larger than error set, so emit our error set last | 410 | // Payload size is larger than error set, so emit our error set last |
| 423 | if (error_align.compare(.lte, payload_align)) { | 411 | if (error_align.compare(.lte, payload_align)) { |
| 424 | const begin = code.items.len; | 412 | const begin = w.end; |
| 425 | mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); | 413 | try w.writeInt(u16, err_val, endian); |
| 426 | const unpadded_end = code.items.len - begin; | 414 | const unpadded_end = w.end - begin; |
| 427 | const padded_end = abi_align.forward(unpadded_end); | 415 | const padded_end = abi_align.forward(unpadded_end); |
| 428 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; | 416 | const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; |
| 429 | 417 | ||
| 430 | if (padding > 0) { | 418 | if (padding > 0) { |
| 431 | try code.appendNTimes(gpa, 0, padding); | 419 | try w.splatByteAll(0, padding); |
| 432 | } | 420 | } |
| 433 | } | 421 | } |
| 434 | }, | 422 | }, |
| 435 | .enum_tag => |enum_tag| { | 423 | .enum_tag => |enum_tag| { |
| 436 | const int_tag_ty = ty.intTagType(zcu); | 424 | const int_tag_ty = ty.intTagType(zcu); |
| 437 | try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); | 425 | try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), w, reloc_parent); |
| 438 | }, | 426 | }, |
| 439 | .float => |float| storage: switch (float.storage) { | 427 | .float => |float| storage: switch (float.storage) { |
| 440 | .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), | 428 | .f16 => |f16_val| try w.writeInt(u16, @bitCast(f16_val), endian), |
| 441 | .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), | 429 | .f32 => |f32_val| try w.writeInt(u32, @bitCast(f32_val), endian), |
| 442 | .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), | 430 | .f64 => |f64_val| try w.writeInt(u64, @bitCast(f64_val), endian), |
| 443 | .f80 => |f80_val| { | 431 | .f80 => |f80_val| { |
| 444 | writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(gpa, 10)); | 432 | try w.writeInt(u80, @bitCast(f80_val), endian); |
| 445 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | 433 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 446 | try code.appendNTimes(gpa, 0, abi_size - 10); | 434 | try w.splatByteAll(0, abi_size - 10); |
| 447 | }, | 435 | }, |
| 448 | .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { | 436 | .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { |
| 449 | else => unreachable, | 437 | else => unreachable, |
| 450 | 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, | 438 | 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, |
| 451 | 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, | 439 | 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, |
| 452 | 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, | 440 | 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, |
| 453 | 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), | 441 | 128 => try w.writeInt(u128, @bitCast(f128_val), endian), |
| 454 | }, | 442 | }, |
| 455 | }, | 443 | }, |
| 456 | .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), | 444 | .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), w, reloc_parent, 0), |
| 457 | .slice => |slice| { | 445 | .slice => |slice| { |
| 458 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent); | 446 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), w, reloc_parent); |
| 459 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent); | 447 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), w, reloc_parent); |
| 460 | }, | 448 | }, |
| 461 | .opt => { | 449 | .opt => { |
| 462 | const payload_type = ty.optionalChild(zcu); | 450 | const payload_type = ty.optionalChild(zcu); |
| ... | @@ -465,9 +453,9 @@ pub fn generateSymbol( | ... | @@ -465,9 +453,9 @@ pub fn generateSymbol( |
| 465 | 453 | ||
| 466 | if (ty.optionalReprIsPayload(zcu)) { | 454 | if (ty.optionalReprIsPayload(zcu)) { |
| 467 | if (payload_val) |value| { | 455 | if (payload_val) |value| { |
| 468 | try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); | 456 | try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); |
| 469 | } else { | 457 | } else { |
| 470 | try code.appendNTimes(gpa, 0, abi_size); | 458 | try w.splatByteAll(0, abi_size); |
| 471 | } | 459 | } |
| 472 | } else { | 460 | } else { |
| 473 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1; | 461 | const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1; |
| ... | @@ -475,15 +463,15 @@ pub fn generateSymbol( | ... | @@ -475,15 +463,15 @@ pub fn generateSymbol( |
| 475 | const value = payload_val orelse Value.fromInterned(try pt.intern(.{ | 463 | const value = payload_val orelse Value.fromInterned(try pt.intern(.{ |
| 476 | .undef = payload_type.toIntern(), | 464 | .undef = payload_type.toIntern(), |
| 477 | })); | 465 | })); |
| 478 | try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); | 466 | try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); |
| 479 | } | 467 | } |
| 480 | try code.append(gpa, @intFromBool(payload_val != null)); | 468 | try w.writeByte(@intFromBool(payload_val != null)); |
| 481 | try code.appendNTimes(gpa, 0, padding); | 469 | try w.splatByteAll(0, padding); |
| 482 | } | 470 | } |
| 483 | }, | 471 | }, |
| 484 | .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { | 472 | .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { |
| 485 | .array_type => |array_type| switch (aggregate.storage) { | 473 | .array_type => |array_type| switch (aggregate.storage) { |
| 486 | .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(array_type.lenIncludingSentinel(), ip)), | 474 | .bytes => |bytes| try w.writeAll(bytes.toSlice(array_type.lenIncludingSentinel(), ip)), |
| 487 | .elems, .repeated_elem => { | 475 | .elems, .repeated_elem => { |
| 488 | var index: u64 = 0; | 476 | var index: u64 = 0; |
| 489 | while (index < array_type.lenIncludingSentinel()) : (index += 1) { | 477 | while (index < array_type.lenIncludingSentinel()) : (index += 1) { |
| ... | @@ -494,14 +482,14 @@ pub fn generateSymbol( | ... | @@ -494,14 +482,14 @@ pub fn generateSymbol( |
| 494 | elem | 482 | elem |
| 495 | else | 483 | else |
| 496 | array_type.sentinel, | 484 | array_type.sentinel, |
| 497 | }), code, reloc_parent); | 485 | }), w, reloc_parent); |
| 498 | } | 486 | } |
| 499 | }, | 487 | }, |
| 500 | }, | 488 | }, |
| 501 | .vector_type => |vector_type| { | 489 | .vector_type => |vector_type| { |
| 502 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | 490 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 503 | if (vector_type.child == .bool_type) { | 491 | if (vector_type.child == .bool_type) { |
| 504 | const bytes = try code.addManyAsSlice(gpa, abi_size); | 492 | const bytes = try w.writableSlice(abi_size); |
| 505 | @memset(bytes, 0xaa); | 493 | @memset(bytes, 0xaa); |
| 506 | var index: usize = 0; | 494 | var index: usize = 0; |
| 507 | const len = math.cast(usize, vector_type.len) orelse return error.Overflow; | 495 | const len = math.cast(usize, vector_type.len) orelse return error.Overflow; |
| ... | @@ -540,7 +528,7 @@ pub fn generateSymbol( | ... | @@ -540,7 +528,7 @@ pub fn generateSymbol( |
| 540 | } | 528 | } |
| 541 | } else { | 529 | } else { |
| 542 | switch (aggregate.storage) { | 530 | switch (aggregate.storage) { |
| 543 | .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(vector_type.len, ip)), | 531 | .bytes => |bytes| try w.writeAll(bytes.toSlice(vector_type.len, ip)), |
| 544 | .elems, .repeated_elem => { | 532 | .elems, .repeated_elem => { |
| 545 | var index: u64 = 0; | 533 | var index: u64 = 0; |
| 546 | while (index < vector_type.len) : (index += 1) { | 534 | while (index < vector_type.len) : (index += 1) { |
| ... | @@ -550,7 +538,7 @@ pub fn generateSymbol( | ... | @@ -550,7 +538,7 @@ pub fn generateSymbol( |
| 550 | math.cast(usize, index) orelse return error.Overflow | 538 | math.cast(usize, index) orelse return error.Overflow |
| 551 | ], | 539 | ], |
| 552 | .repeated_elem => |elem| elem, | 540 | .repeated_elem => |elem| elem, |
| 553 | }), code, reloc_parent); | 541 | }), w, reloc_parent); |
| 554 | } | 542 | } |
| 555 | }, | 543 | }, |
| 556 | } | 544 | } |
| ... | @@ -558,11 +546,11 @@ pub fn generateSymbol( | ... | @@ -558,11 +546,11 @@ pub fn generateSymbol( |
| 558 | const padding = abi_size - | 546 | const padding = abi_size - |
| 559 | (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse | 547 | (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse |
| 560 | return error.Overflow); | 548 | return error.Overflow); |
| 561 | if (padding > 0) try code.appendNTimes(gpa, 0, padding); | 549 | if (padding > 0) try w.splatByteAll(0, padding); |
| 562 | } | 550 | } |
| 563 | }, | 551 | }, |
| 564 | .tuple_type => |tuple| { | 552 | .tuple_type => |tuple| { |
| 565 | const struct_begin = code.items.len; | 553 | const struct_begin = w.end; |
| 566 | for ( | 554 | for ( |
| 567 | tuple.types.get(ip), | 555 | tuple.types.get(ip), |
| 568 | tuple.values.get(ip), | 556 | tuple.values.get(ip), |
| ... | @@ -580,8 +568,8 @@ pub fn generateSymbol( | ... | @@ -580,8 +568,8 @@ pub fn generateSymbol( |
| 580 | .repeated_elem => |elem| elem, | 568 | .repeated_elem => |elem| elem, |
| 581 | }; | 569 | }; |
| 582 | 570 | ||
| 583 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); | 571 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 584 | const unpadded_field_end = code.items.len - struct_begin; | 572 | const unpadded_field_end = w.end - struct_begin; |
| 585 | 573 | ||
| 586 | // Pad struct members if required | 574 | // Pad struct members if required |
| 587 | const padded_field_end = ty.structFieldOffset(index + 1, zcu); | 575 | const padded_field_end = ty.structFieldOffset(index + 1, zcu); |
| ... | @@ -589,7 +577,7 @@ pub fn generateSymbol( | ... | @@ -589,7 +577,7 @@ pub fn generateSymbol( |
| 589 | return error.Overflow; | 577 | return error.Overflow; |
| 590 | 578 | ||
| 591 | if (padding > 0) { | 579 | if (padding > 0) { |
| 592 | try code.appendNTimes(gpa, 0, padding); | 580 | try w.splatByteAll(0, padding); |
| 593 | } | 581 | } |
| 594 | } | 582 | } |
| 595 | }, | 583 | }, |
| ... | @@ -598,8 +586,9 @@ pub fn generateSymbol( | ... | @@ -598,8 +586,9 @@ pub fn generateSymbol( |
| 598 | switch (struct_type.layout) { | 586 | switch (struct_type.layout) { |
| 599 | .@"packed" => { | 587 | .@"packed" => { |
| 600 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; | 588 | const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; |
| 601 | const current_pos = code.items.len; | 589 | const start = w.end; |
| 602 | try code.appendNTimes(gpa, 0, abi_size); | 590 | const buffer = try w.writableSlice(abi_size); |
| 591 | @memset(buffer, 0); | ||
| 603 | var bits: u16 = 0; | 592 | var bits: u16 = 0; |
| 604 | 593 | ||
| 605 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { | 594 | for (struct_type.field_types.get(ip), 0..) |field_ty, index| { |
| ... | @@ -619,22 +608,20 @@ pub fn generateSymbol( | ... | @@ -619,22 +608,20 @@ pub fn generateSymbol( |
| 619 | error.DivisionByZero => unreachable, | 608 | error.DivisionByZero => unreachable, |
| 620 | error.UnexpectedRemainder => return error.RelocationNotByteAligned, | 609 | error.UnexpectedRemainder => return error.RelocationNotByteAligned, |
| 621 | }; | 610 | }; |
| 622 | code.items.len = current_pos + field_offset; | 611 | w.end = start + field_offset; |
| 623 | // TODO: code.lockPointers(); | ||
| 624 | defer { | 612 | defer { |
| 625 | assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8)); | 613 | assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8)); |
| 626 | // TODO: code.unlockPointers(); | 614 | w.end = start + abi_size; |
| 627 | code.items.len = current_pos + abi_size; | ||
| 628 | } | 615 | } |
| 629 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); | 616 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 630 | } else { | 617 | } else { |
| 631 | Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable; | 618 | Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable; |
| 632 | } | 619 | } |
| 633 | bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); | 620 | bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); |
| 634 | } | 621 | } |
| 635 | }, | 622 | }, |
| 636 | .auto, .@"extern" => { | 623 | .auto, .@"extern" => { |
| 637 | const struct_begin = code.items.len; | 624 | const struct_begin = w.end; |
| 638 | const field_types = struct_type.field_types.get(ip); | 625 | const field_types = struct_type.field_types.get(ip); |
| 639 | const offsets = struct_type.offsets.get(ip); | 626 | const offsets = struct_type.offsets.get(ip); |
| 640 | 627 | ||
| ... | @@ -654,11 +641,11 @@ pub fn generateSymbol( | ... | @@ -654,11 +641,11 @@ pub fn generateSymbol( |
| 654 | 641 | ||
| 655 | const padding = math.cast( | 642 | const padding = math.cast( |
| 656 | usize, | 643 | usize, |
| 657 | offsets[field_index] - (code.items.len - struct_begin), | 644 | offsets[field_index] - (w.end - struct_begin), |
| 658 | ) orelse return error.Overflow; | 645 | ) orelse return error.Overflow; |
| 659 | if (padding > 0) try code.appendNTimes(gpa, 0, padding); | 646 | if (padding > 0) try w.splatByteAll(0, padding); |
| 660 | 647 | ||
| 661 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); | 648 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); |
| 662 | } | 649 | } |
| 663 | 650 | ||
| 664 | const size = struct_type.sizeUnordered(ip); | 651 | const size = struct_type.sizeUnordered(ip); |
| ... | @@ -666,10 +653,9 @@ pub fn generateSymbol( | ... | @@ -666,10 +653,9 @@ pub fn generateSymbol( |
| 666 | 653 | ||
| 667 | const padding = math.cast( | 654 | const padding = math.cast( |
| 668 | usize, | 655 | usize, |
| 669 | std.mem.alignForward(u64, size, @max(alignment, 1)) - | 656 | std.mem.alignForward(u64, size, @max(alignment, 1)) - (w.end - struct_begin), |
| 670 | (code.items.len - struct_begin), | ||
| 671 | ) orelse return error.Overflow; | 657 | ) orelse return error.Overflow; |
| 672 | if (padding > 0) try code.appendNTimes(gpa, 0, padding); | 658 | if (padding > 0) try w.splatByteAll(0, padding); |
| 673 | }, | 659 | }, |
| 674 | } | 660 | } |
| 675 | }, | 661 | }, |
| ... | @@ -679,12 +665,12 @@ pub fn generateSymbol( | ... | @@ -679,12 +665,12 @@ pub fn generateSymbol( |
| 679 | const layout = ty.unionGetLayout(zcu); | 665 | const layout = ty.unionGetLayout(zcu); |
| 680 | 666 | ||
| 681 | if (layout.payload_size == 0) { | 667 | if (layout.payload_size == 0) { |
| 682 | return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); | 668 | return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 683 | } | 669 | } |
| 684 | 670 | ||
| 685 | // Check if we should store the tag first. | 671 | // Check if we should store the tag first. |
| 686 | if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { | 672 | if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { |
| 687 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); | 673 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 688 | } | 674 | } |
| 689 | 675 | ||
| 690 | const union_obj = zcu.typeToUnion(ty).?; | 676 | const union_obj = zcu.typeToUnion(ty).?; |
| ... | @@ -692,24 +678,24 @@ pub fn generateSymbol( | ... | @@ -692,24 +678,24 @@ pub fn generateSymbol( |
| 692 | const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; | 678 | const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; |
| 693 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); | 679 | const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); |
| 694 | if (!field_ty.hasRuntimeBits(zcu)) { | 680 | if (!field_ty.hasRuntimeBits(zcu)) { |
| 695 | try code.appendNTimes(gpa, 0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); | 681 | try w.splatByteAll(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); |
| 696 | } else { | 682 | } else { |
| 697 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); | 683 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); |
| 698 | 684 | ||
| 699 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow; | 685 | const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow; |
| 700 | if (padding > 0) { | 686 | if (padding > 0) { |
| 701 | try code.appendNTimes(gpa, 0, padding); | 687 | try w.splatByteAll(0, padding); |
| 702 | } | 688 | } |
| 703 | } | 689 | } |
| 704 | } else { | 690 | } else { |
| 705 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); | 691 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); |
| 706 | } | 692 | } |
| 707 | 693 | ||
| 708 | if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { | 694 | if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { |
| 709 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); | 695 | try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); |
| 710 | 696 | ||
| 711 | if (layout.padding > 0) { | 697 | if (layout.padding > 0) { |
| 712 | try code.appendNTimes(gpa, 0, layout.padding); | 698 | try w.splatByteAll(0, layout.padding); |
| 713 | } | 699 | } |
| 714 | } | 700 | } |
| 715 | }, | 701 | }, |
| ... | @@ -722,30 +708,30 @@ fn lowerPtr( | ... | @@ -722,30 +708,30 @@ fn lowerPtr( |
| 722 | pt: Zcu.PerThread, | 708 | pt: Zcu.PerThread, |
| 723 | src_loc: Zcu.LazySrcLoc, | 709 | src_loc: Zcu.LazySrcLoc, |
| 724 | ptr_val: InternPool.Index, | 710 | ptr_val: InternPool.Index, |
| 725 | code: *ArrayList(u8), | 711 | w: *std.Io.Writer, |
| 726 | reloc_parent: link.File.RelocInfo.Parent, | 712 | reloc_parent: link.File.RelocInfo.Parent, |
| 727 | prev_offset: u64, | 713 | prev_offset: u64, |
| 728 | ) GenerateSymbolError!void { | 714 | ) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 729 | const zcu = pt.zcu; | 715 | const zcu = pt.zcu; |
| 730 | const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; | 716 | const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; |
| 731 | const offset: u64 = prev_offset + ptr.byte_offset; | 717 | const offset: u64 = prev_offset + ptr.byte_offset; |
| 732 | return switch (ptr.base_addr) { | 718 | return switch (ptr.base_addr) { |
| 733 | .nav => |nav| try lowerNavRef(bin_file, pt, nav, code, reloc_parent, offset), | 719 | .nav => |nav| try lowerNavRef(bin_file, pt, nav, w, reloc_parent, offset), |
| 734 | .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset), | 720 | .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, w, reloc_parent, offset), |
| 735 | .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent), | 721 | .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), w, reloc_parent), |
| 736 | .eu_payload => |eu_ptr| try lowerPtr( | 722 | .eu_payload => |eu_ptr| try lowerPtr( |
| 737 | bin_file, | 723 | bin_file, |
| 738 | pt, | 724 | pt, |
| 739 | src_loc, | 725 | src_loc, |
| 740 | eu_ptr, | 726 | eu_ptr, |
| 741 | code, | 727 | w, |
| 742 | reloc_parent, | 728 | reloc_parent, |
| 743 | offset + errUnionPayloadOffset( | 729 | offset + errUnionPayloadOffset( |
| 744 | Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu), | 730 | Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu), |
| 745 | zcu, | 731 | zcu, |
| 746 | ), | 732 | ), |
| 747 | ), | 733 | ), |
| 748 | .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset), | 734 | .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, w, reloc_parent, offset), |
| 749 | .field => |field| { | 735 | .field => |field| { |
| 750 | const base_ptr = Value.fromInterned(field.base); | 736 | const base_ptr = Value.fromInterned(field.base); |
| 751 | const base_ty = base_ptr.typeOf(zcu).childType(zcu); | 737 | const base_ty = base_ptr.typeOf(zcu).childType(zcu); |
| ... | @@ -764,7 +750,7 @@ fn lowerPtr( | ... | @@ -764,7 +750,7 @@ fn lowerPtr( |
| 764 | }, | 750 | }, |
| 765 | else => unreachable, | 751 | else => unreachable, |
| 766 | }; | 752 | }; |
| 767 | return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off); | 753 | return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off); |
| 768 | }, | 754 | }, |
| 769 | .arr_elem, .comptime_field, .comptime_alloc => unreachable, | 755 | .arr_elem, .comptime_field, .comptime_alloc => unreachable, |
| 770 | }; | 756 | }; |
| ... | @@ -775,12 +761,11 @@ fn lowerUavRef( | ... | @@ -775,12 +761,11 @@ fn lowerUavRef( |
| 775 | pt: Zcu.PerThread, | 761 | pt: Zcu.PerThread, |
| 776 | src_loc: Zcu.LazySrcLoc, | 762 | src_loc: Zcu.LazySrcLoc, |
| 777 | uav: InternPool.Key.Ptr.BaseAddr.Uav, | 763 | uav: InternPool.Key.Ptr.BaseAddr.Uav, |
| 778 | code: *ArrayList(u8), | 764 | w: *std.Io.Writer, |
| 779 | reloc_parent: link.File.RelocInfo.Parent, | 765 | reloc_parent: link.File.RelocInfo.Parent, |
| 780 | offset: u64, | 766 | offset: u64, |
| 781 | ) GenerateSymbolError!void { | 767 | ) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 782 | const zcu = pt.zcu; | 768 | const zcu = pt.zcu; |
| 783 | const gpa = zcu.gpa; | ||
| 784 | const ip = &zcu.intern_pool; | 769 | const ip = &zcu.intern_pool; |
| 785 | const comp = lf.comp; | 770 | const comp = lf.comp; |
| 786 | const target = &comp.root_mod.resolved_target.result; | 771 | const target = &comp.root_mod.resolved_target.result; |
| ... | @@ -790,10 +775,9 @@ fn lowerUavRef( | ... | @@ -790,10 +775,9 @@ fn lowerUavRef( |
| 790 | const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; | 775 | const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; |
| 791 | 776 | ||
| 792 | log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)}); | 777 | log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)}); |
| 793 | try code.ensureUnusedCapacity(gpa, ptr_width_bytes); | ||
| 794 | 778 | ||
| 795 | if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) { | 779 | if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) { |
| 796 | code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); | 780 | try w.splatByteAll(0xaa, ptr_width_bytes); |
| 797 | return; | 781 | return; |
| 798 | } | 782 | } |
| 799 | 783 | ||
| ... | @@ -804,29 +788,32 @@ fn lowerUavRef( | ... | @@ -804,29 +788,32 @@ fn lowerUavRef( |
| 804 | dev.check(link.File.Tag.wasm.devFeature()); | 788 | dev.check(link.File.Tag.wasm.devFeature()); |
| 805 | const wasm = lf.cast(.wasm).?; | 789 | const wasm = lf.cast(.wasm).?; |
| 806 | assert(reloc_parent == .none); | 790 | assert(reloc_parent == .none); |
| 807 | try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset)); | 791 | try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset)); |
| 808 | code.appendNTimesAssumeCapacity(0, ptr_width_bytes); | 792 | try w.splatByteAll(0, ptr_width_bytes); |
| 809 | return; | 793 | return; |
| 810 | }, | 794 | }, |
| 811 | else => {}, | 795 | else => {}, |
| 812 | } | 796 | } |
| 813 | 797 | ||
| 814 | const uav_align = ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment; | 798 | const uav_align = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu); |
| 815 | switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) { | 799 | switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) { |
| 816 | .sym_index => {}, | 800 | .sym_index => {}, |
| 817 | .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}), | 801 | .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}), |
| 818 | } | 802 | } |
| 819 | 803 | ||
| 820 | const vaddr = try lf.getUavVAddr(uav_val, .{ | 804 | const vaddr = lf.getUavVAddr(uav_val, .{ |
| 821 | .parent = reloc_parent, | 805 | .parent = reloc_parent, |
| 822 | .offset = code.items.len, | 806 | .offset = w.end, |
| 823 | .addend = @intCast(offset), | 807 | .addend = @intCast(offset), |
| 824 | }); | 808 | }) catch |err| switch (err) { |
| 809 | error.OutOfMemory => return error.OutOfMemory, | ||
| 810 | else => |e| std.debug.panic("TODO rework lowerUav. internal error: {t}", .{e}), | ||
| 811 | }; | ||
| 825 | const endian = target.cpu.arch.endian(); | 812 | const endian = target.cpu.arch.endian(); |
| 826 | switch (ptr_width_bytes) { | 813 | switch (ptr_width_bytes) { |
| 827 | 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), | 814 | 2 => try w.writeInt(u16, @intCast(vaddr), endian), |
| 828 | 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), | 815 | 4 => try w.writeInt(u32, @intCast(vaddr), endian), |
| 829 | 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), | 816 | 8 => try w.writeInt(u64, vaddr, endian), |
| 830 | else => unreachable, | 817 | else => unreachable, |
| 831 | } | 818 | } |
| 832 | } | 819 | } |
| ... | @@ -835,10 +822,10 @@ fn lowerNavRef( | ... | @@ -835,10 +822,10 @@ fn lowerNavRef( |
| 835 | lf: *link.File, | 822 | lf: *link.File, |
| 836 | pt: Zcu.PerThread, | 823 | pt: Zcu.PerThread, |
| 837 | nav_index: InternPool.Nav.Index, | 824 | nav_index: InternPool.Nav.Index, |
| 838 | code: *ArrayList(u8), | 825 | w: *std.Io.Writer, |
| 839 | reloc_parent: link.File.RelocInfo.Parent, | 826 | reloc_parent: link.File.RelocInfo.Parent, |
| 840 | offset: u64, | 827 | offset: u64, |
| 841 | ) GenerateSymbolError!void { | 828 | ) (GenerateSymbolError || std.Io.Writer.Error)!void { |
| 842 | const zcu = pt.zcu; | 829 | const zcu = pt.zcu; |
| 843 | const gpa = zcu.gpa; | 830 | const gpa = zcu.gpa; |
| 844 | const ip = &zcu.intern_pool; | 831 | const ip = &zcu.intern_pool; |
| ... | @@ -848,10 +835,8 @@ fn lowerNavRef( | ... | @@ -848,10 +835,8 @@ fn lowerNavRef( |
| 848 | const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); | 835 | const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); |
| 849 | const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; | 836 | const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; |
| 850 | 837 | ||
| 851 | try code.ensureUnusedCapacity(gpa, ptr_width_bytes); | ||
| 852 | |||
| 853 | if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) { | 838 | if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) { |
| 854 | code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); | 839 | try w.splatByteAll(0xaa, ptr_width_bytes); |
| 855 | return; | 840 | return; |
| 856 | } | 841 | } |
| 857 | 842 | ||
| ... | @@ -870,13 +855,13 @@ fn lowerNavRef( | ... | @@ -870,13 +855,13 @@ fn lowerNavRef( |
| 870 | } else { | 855 | } else { |
| 871 | try wasm.func_table_fixups.append(gpa, .{ | 856 | try wasm.func_table_fixups.append(gpa, .{ |
| 872 | .table_index = @enumFromInt(gop.index), | 857 | .table_index = @enumFromInt(gop.index), |
| 873 | .offset = @intCast(code.items.len), | 858 | .offset = @intCast(w.end), |
| 874 | }); | 859 | }); |
| 875 | } | 860 | } |
| 876 | } else { | 861 | } else { |
| 877 | if (is_obj) { | 862 | if (is_obj) { |
| 878 | try wasm.out_relocs.append(gpa, .{ | 863 | try wasm.out_relocs.append(gpa, .{ |
| 879 | .offset = @intCast(code.items.len), | 864 | .offset = @intCast(w.end), |
| 880 | .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, | 865 | .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, |
| 881 | .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, | 866 | .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, |
| 882 | .addend = @intCast(offset), | 867 | .addend = @intCast(offset), |
| ... | @@ -885,12 +870,12 @@ fn lowerNavRef( | ... | @@ -885,12 +870,12 @@ fn lowerNavRef( |
| 885 | try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); | 870 | try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); |
| 886 | wasm.nav_fixups.appendAssumeCapacity(.{ | 871 | wasm.nav_fixups.appendAssumeCapacity(.{ |
| 887 | .navs_exe_index = try wasm.refNavExe(nav_index), | 872 | .navs_exe_index = try wasm.refNavExe(nav_index), |
| 888 | .offset = @intCast(code.items.len), | 873 | .offset = @intCast(w.end), |
| 889 | .addend = @intCast(offset), | 874 | .addend = @intCast(offset), |
| 890 | }); | 875 | }); |
| 891 | } | 876 | } |
| 892 | } | 877 | } |
| 893 | code.appendNTimesAssumeCapacity(0, ptr_width_bytes); | 878 | try w.splatByteAll(0, ptr_width_bytes); |
| 894 | return; | 879 | return; |
| 895 | }, | 880 | }, |
| 896 | else => {}, | 881 | else => {}, |
| ... | @@ -898,14 +883,14 @@ fn lowerNavRef( | ... | @@ -898,14 +883,14 @@ fn lowerNavRef( |
| 898 | 883 | ||
| 899 | const vaddr = lf.getNavVAddr(pt, nav_index, .{ | 884 | const vaddr = lf.getNavVAddr(pt, nav_index, .{ |
| 900 | .parent = reloc_parent, | 885 | .parent = reloc_parent, |
| 901 | .offset = code.items.len, | 886 | .offset = w.end, |
| 902 | .addend = @intCast(offset), | 887 | .addend = @intCast(offset), |
| 903 | }) catch @panic("TODO rework getNavVAddr"); | 888 | }) catch @panic("TODO rework getNavVAddr"); |
| 904 | const endian = target.cpu.arch.endian(); | 889 | const endian = target.cpu.arch.endian(); |
| 905 | switch (ptr_width_bytes) { | 890 | switch (ptr_width_bytes) { |
| 906 | 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), | 891 | 2 => try w.writeInt(u16, @intCast(vaddr), endian), |
| 907 | 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), | 892 | 4 => try w.writeInt(u32, @intCast(vaddr), endian), |
| 908 | 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), | 893 | 8 => try w.writeInt(u64, vaddr, endian), |
| 909 | else => unreachable, | 894 | else => unreachable, |
| 910 | } | 895 | } |
| 911 | } | 896 | } |
| ... | @@ -962,6 +947,16 @@ pub fn genNavRef( | ... | @@ -962,6 +947,16 @@ pub fn genNavRef( |
| 962 | }, | 947 | }, |
| 963 | .link_once => unreachable, | 948 | .link_once => unreachable, |
| 964 | } | 949 | } |
| 950 | } else if (lf.cast(.elf2)) |elf| { | ||
| 951 | return .{ .sym_index = @intFromEnum(elf.navSymbol(zcu, nav_index) catch |err| switch (err) { | ||
| 952 | error.OutOfMemory => return error.OutOfMemory, | ||
| 953 | else => |e| return .{ .fail = try ErrorMsg.create( | ||
| 954 | zcu.gpa, | ||
| 955 | src_loc, | ||
| 956 | "linker failed to create a nav: {t}", | ||
| 957 | .{e}, | ||
| 958 | ) }, | ||
| 959 | }) }; | ||
| 965 | } else if (lf.cast(.macho)) |macho_file| { | 960 | } else if (lf.cast(.macho)) |macho_file| { |
| 966 | const zo = macho_file.getZigObject().?; | 961 | const zo = macho_file.getZigObject().?; |
| 967 | switch (linkage) { | 962 | switch (linkage) { |
src/codegen/aarch64/Mir.zig+27-28| ... | @@ -56,13 +56,13 @@ pub fn emit( | ... | @@ -56,13 +56,13 @@ pub fn emit( |
| 56 | pt: Zcu.PerThread, | 56 | pt: Zcu.PerThread, |
| 57 | src_loc: Zcu.LazySrcLoc, | 57 | src_loc: Zcu.LazySrcLoc, |
| 58 | func_index: InternPool.Index, | 58 | func_index: InternPool.Index, |
| 59 | code: *std.ArrayListUnmanaged(u8), | 59 | atom_index: u32, |
| 60 | w: *std.Io.Writer, | ||
| 60 | debug_output: link.File.DebugInfoOutput, | 61 | debug_output: link.File.DebugInfoOutput, |
| 61 | ) !void { | 62 | ) !void { |
| 62 | _ = debug_output; | 63 | _ = debug_output; |
| 63 | const zcu = pt.zcu; | 64 | const zcu = pt.zcu; |
| 64 | const ip = &zcu.intern_pool; | 65 | const ip = &zcu.intern_pool; |
| 65 | const gpa = zcu.gpa; | ||
| 66 | const func = zcu.funcInfo(func_index); | 66 | const func = zcu.funcInfo(func_index); |
| 67 | const nav = ip.getNav(func.owner_nav); | 67 | const nav = ip.getNav(func.owner_nav); |
| 68 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | 68 | const mod = zcu.navFileScope(func.owner_nav).mod.?; |
| ... | @@ -81,20 +81,19 @@ pub fn emit( | ... | @@ -81,20 +81,19 @@ pub fn emit( |
| 81 | @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)), | 81 | @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)), |
| 82 | Instruction.size, | 82 | Instruction.size, |
| 83 | ) - 1); | 83 | ) - 1); |
| 84 | try code.ensureUnusedCapacity(gpa, Instruction.size * | 84 | try w.rebase(w.end, Instruction.size * (code_len + literals_align_gap + mir.literals.len)); |
| 85 | (code_len + literals_align_gap + mir.literals.len)); | 85 | emitInstructionsForward(w, mir.prologue) catch unreachable; |
| 86 | emitInstructionsForward(code, mir.prologue); | 86 | emitInstructionsBackward(w, mir.body) catch unreachable; |
| 87 | emitInstructionsBackward(code, mir.body); | 87 | const body_end: u32 = @intCast(w.end); |
| 88 | const body_end: u32 = @intCast(code.items.len); | 88 | emitInstructionsBackward(w, mir.epilogue) catch unreachable; |
| 89 | emitInstructionsBackward(code, mir.epilogue); | 89 | w.splatByteAll(0, Instruction.size * literals_align_gap) catch unreachable; |
| 90 | code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap); | 90 | w.writeAll(@ptrCast(mir.literals)) catch unreachable; |
| 91 | code.appendSliceAssumeCapacity(@ptrCast(mir.literals)); | ||
| 92 | mir_log.debug("", .{}); | 91 | mir_log.debug("", .{}); |
| 93 | 92 | ||
| 94 | for (mir.nav_relocs) |nav_reloc| try emitReloc( | 93 | for (mir.nav_relocs) |nav_reloc| try emitReloc( |
| 95 | lf, | 94 | lf, |
| 96 | zcu, | 95 | zcu, |
| 97 | func.owner_nav, | 96 | atom_index, |
| 98 | switch (try @import("../../codegen.zig").genNavRef( | 97 | switch (try @import("../../codegen.zig").genNavRef( |
| 99 | lf, | 98 | lf, |
| 100 | pt, | 99 | pt, |
| ... | @@ -112,7 +111,7 @@ pub fn emit( | ... | @@ -112,7 +111,7 @@ pub fn emit( |
| 112 | for (mir.uav_relocs) |uav_reloc| try emitReloc( | 111 | for (mir.uav_relocs) |uav_reloc| try emitReloc( |
| 113 | lf, | 112 | lf, |
| 114 | zcu, | 113 | zcu, |
| 115 | func.owner_nav, | 114 | atom_index, |
| 116 | switch (try lf.lowerUav( | 115 | switch (try lf.lowerUav( |
| 117 | pt, | 116 | pt, |
| 118 | uav_reloc.uav.val, | 117 | uav_reloc.uav.val, |
| ... | @@ -129,7 +128,7 @@ pub fn emit( | ... | @@ -129,7 +128,7 @@ pub fn emit( |
| 129 | for (mir.lazy_relocs) |lazy_reloc| try emitReloc( | 128 | for (mir.lazy_relocs) |lazy_reloc| try emitReloc( |
| 130 | lf, | 129 | lf, |
| 131 | zcu, | 130 | zcu, |
| 132 | func.owner_nav, | 131 | atom_index, |
| 133 | if (lf.cast(.elf)) |ef| | 132 | if (lf.cast(.elf)) |ef| |
| 134 | ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| | 133 | ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err| |
| 135 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) | 134 | return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}) |
| ... | @@ -150,7 +149,7 @@ pub fn emit( | ... | @@ -150,7 +149,7 @@ pub fn emit( |
| 150 | for (mir.global_relocs) |global_reloc| try emitReloc( | 149 | for (mir.global_relocs) |global_reloc| try emitReloc( |
| 151 | lf, | 150 | lf, |
| 152 | zcu, | 151 | zcu, |
| 153 | func.owner_nav, | 152 | atom_index, |
| 154 | if (lf.cast(.elf)) |ef| | 153 | if (lf.cast(.elf)) |ef| |
| 155 | try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null) | 154 | try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null) |
| 156 | else if (lf.cast(.macho)) |mf| | 155 | else if (lf.cast(.macho)) |mf| |
| ... | @@ -168,30 +167,30 @@ pub fn emit( | ... | @@ -168,30 +167,30 @@ pub fn emit( |
| 168 | var instruction = mir.body[literal_reloc.label]; | 167 | var instruction = mir.body[literal_reloc.label]; |
| 169 | instruction.load_store.register_literal.group.imm19 += literal_reloc_offset; | 168 | instruction.load_store.register_literal.group.imm19 += literal_reloc_offset; |
| 170 | instruction.write( | 169 | instruction.write( |
| 171 | code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], | 170 | w.buffered()[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size], |
| 172 | ); | 171 | ); |
| 173 | } | 172 | } |
| 174 | } | 173 | } |
| 175 | 174 | ||
| 176 | fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { | 175 | fn emitInstructionsForward(w: *std.Io.Writer, instructions: []const Instruction) !void { |
| 177 | for (instructions) |instruction| emitInstruction(code, instruction); | 176 | for (instructions) |instruction| try emitInstruction(w, instruction); |
| 178 | } | 177 | } |
| 179 | fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void { | 178 | fn emitInstructionsBackward(w: *std.Io.Writer, instructions: []const Instruction) !void { |
| 180 | var instruction_index = instructions.len; | 179 | var instruction_index = instructions.len; |
| 181 | while (instruction_index > 0) { | 180 | while (instruction_index > 0) { |
| 182 | instruction_index -= 1; | 181 | instruction_index -= 1; |
| 183 | emitInstruction(code, instructions[instruction_index]); | 182 | try emitInstruction(w, instructions[instruction_index]); |
| 184 | } | 183 | } |
| 185 | } | 184 | } |
| 186 | fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void { | 185 | fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void { |
| 187 | mir_log.debug(" {f}", .{instruction}); | 186 | mir_log.debug(" {f}", .{instruction}); |
| 188 | instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size)); | 187 | instruction.write(try w.writableArray(Instruction.size)); |
| 189 | } | 188 | } |
| 190 | 189 | ||
| 191 | fn emitReloc( | 190 | fn emitReloc( |
| 192 | lf: *link.File, | 191 | lf: *link.File, |
| 193 | zcu: *Zcu, | 192 | zcu: *Zcu, |
| 194 | owner_nav: InternPool.Nav.Index, | 193 | atom_index: u32, |
| 195 | sym_index: u32, | 194 | sym_index: u32, |
| 196 | instruction: Instruction, | 195 | instruction: Instruction, |
| 197 | offset: u32, | 196 | offset: u32, |
| ... | @@ -202,7 +201,7 @@ fn emitReloc( | ... | @@ -202,7 +201,7 @@ fn emitReloc( |
| 202 | else => unreachable, | 201 | else => unreachable, |
| 203 | .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { | 202 | .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| { |
| 204 | const zo = ef.zigObjectPtr().?; | 203 | const zo = ef.zigObjectPtr().?; |
| 205 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | 204 | const atom = zo.symbol(atom_index).atom(ef).?; |
| 206 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { | 205 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) { |
| 207 | else => unreachable, | 206 | else => unreachable, |
| 208 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { | 207 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { |
| ... | @@ -221,7 +220,7 @@ fn emitReloc( | ... | @@ -221,7 +220,7 @@ fn emitReloc( |
| 221 | }, zo); | 220 | }, zo); |
| 222 | } else if (lf.cast(.macho)) |mf| { | 221 | } else if (lf.cast(.macho)) |mf| { |
| 223 | const zo = mf.getZigObject().?; | 222 | const zo = mf.getZigObject().?; |
| 224 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | 223 | const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 225 | switch (decoded.decode()) { | 224 | switch (decoded.decode()) { |
| 226 | else => unreachable, | 225 | else => unreachable, |
| 227 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { | 226 | .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) { |
| ... | @@ -260,7 +259,7 @@ fn emitReloc( | ... | @@ -260,7 +259,7 @@ fn emitReloc( |
| 260 | }, | 259 | }, |
| 261 | .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { | 260 | .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| { |
| 262 | const zo = ef.zigObjectPtr().?; | 261 | const zo = ef.zigObjectPtr().?; |
| 263 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | 262 | const atom = zo.symbol(atom_index).atom(ef).?; |
| 264 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { | 263 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) { |
| 265 | .b => .JUMP26, | 264 | .b => .JUMP26, |
| 266 | .bl => .CALL26, | 265 | .bl => .CALL26, |
| ... | @@ -272,7 +271,7 @@ fn emitReloc( | ... | @@ -272,7 +271,7 @@ fn emitReloc( |
| 272 | }, zo); | 271 | }, zo); |
| 273 | } else if (lf.cast(.macho)) |mf| { | 272 | } else if (lf.cast(.macho)) |mf| { |
| 274 | const zo = mf.getZigObject().?; | 273 | const zo = mf.getZigObject().?; |
| 275 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | 274 | const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 276 | try atom.addReloc(mf, .{ | 275 | try atom.addReloc(mf, .{ |
| 277 | .tag = .@"extern", | 276 | .tag = .@"extern", |
| 278 | .offset = offset, | 277 | .offset = offset, |
| ... | @@ -289,7 +288,7 @@ fn emitReloc( | ... | @@ -289,7 +288,7 @@ fn emitReloc( |
| 289 | }, | 288 | }, |
| 290 | .load_store => |decoded| if (lf.cast(.elf)) |ef| { | 289 | .load_store => |decoded| if (lf.cast(.elf)) |ef| { |
| 291 | const zo = ef.zigObjectPtr().?; | 290 | const zo = ef.zigObjectPtr().?; |
| 292 | const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?; | 291 | const atom = zo.symbol(atom_index).atom(ef).?; |
| 293 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { | 292 | const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) { |
| 294 | .integer => |integer| switch (integer.decode()) { | 293 | .integer => |integer| switch (integer.decode()) { |
| 295 | .unallocated, .prfm => unreachable, | 294 | .unallocated, .prfm => unreachable, |
| ... | @@ -316,7 +315,7 @@ fn emitReloc( | ... | @@ -316,7 +315,7 @@ fn emitReloc( |
| 316 | }, zo); | 315 | }, zo); |
| 317 | } else if (lf.cast(.macho)) |mf| { | 316 | } else if (lf.cast(.macho)) |mf| { |
| 318 | const zo = mf.getZigObject().?; | 317 | const zo = mf.getZigObject().?; |
| 319 | const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?; | 318 | const atom = zo.symbols.items[atom_index].getAtom(mf).?; |
| 320 | try atom.addReloc(mf, .{ | 319 | try atom.addReloc(mf, .{ |
| 321 | .tag = .@"extern", | 320 | .tag = .@"extern", |
| 322 | .offset = offset, | 321 | .offset = offset, |
src/dev.zig+4| ... | @@ -97,6 +97,7 @@ pub const Env = enum { | ... | @@ -97,6 +97,7 @@ pub const Env = enum { |
| 97 | .lld_linker, | 97 | .lld_linker, |
| 98 | .coff_linker, | 98 | .coff_linker, |
| 99 | .elf_linker, | 99 | .elf_linker, |
| 100 | .elf2_linker, | ||
| 100 | .macho_linker, | 101 | .macho_linker, |
| 101 | .c_linker, | 102 | .c_linker, |
| 102 | .wasm_linker, | 103 | .wasm_linker, |
| ... | @@ -163,6 +164,7 @@ pub const Env = enum { | ... | @@ -163,6 +164,7 @@ pub const Env = enum { |
| 163 | .incremental, | 164 | .incremental, |
| 164 | .aarch64_backend, | 165 | .aarch64_backend, |
| 165 | .elf_linker, | 166 | .elf_linker, |
| 167 | .elf2_linker, | ||
| 166 | => true, | 168 | => true, |
| 167 | else => Env.sema.supports(feature), | 169 | else => Env.sema.supports(feature), |
| 168 | }, | 170 | }, |
| ... | @@ -210,6 +212,7 @@ pub const Env = enum { | ... | @@ -210,6 +212,7 @@ pub const Env = enum { |
| 210 | .legalize, | 212 | .legalize, |
| 211 | .x86_64_backend, | 213 | .x86_64_backend, |
| 212 | .elf_linker, | 214 | .elf_linker, |
| 215 | .elf2_linker, | ||
| 213 | => true, | 216 | => true, |
| 214 | else => Env.sema.supports(feature), | 217 | else => Env.sema.supports(feature), |
| 215 | }, | 218 | }, |
| ... | @@ -282,6 +285,7 @@ pub const Feature = enum { | ... | @@ -282,6 +285,7 @@ pub const Feature = enum { |
| 282 | lld_linker, | 285 | lld_linker, |
| 283 | coff_linker, | 286 | coff_linker, |
| 284 | elf_linker, | 287 | elf_linker, |
| 288 | elf2_linker, | ||
| 285 | macho_linker, | 289 | macho_linker, |
| 286 | c_linker, | 290 | c_linker, |
| 287 | wasm_linker, | 291 | wasm_linker, |
src/link.zig+80-11| ... | @@ -219,6 +219,7 @@ pub const Diags = struct { | ... | @@ -219,6 +219,7 @@ pub const Diags = struct { |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void { | 221 | pub fn addError(diags: *Diags, comptime format: []const u8, args: anytype) void { |
| 222 | @branchHint(.cold); | ||
| 222 | return addErrorSourceLocation(diags, .none, format, args); | 223 | return addErrorSourceLocation(diags, .none, format, args); |
| 223 | } | 224 | } |
| 224 | 225 | ||
| ... | @@ -529,7 +530,7 @@ pub const File = struct { | ... | @@ -529,7 +530,7 @@ pub const File = struct { |
| 529 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); | 530 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); |
| 530 | return &lld.base; | 531 | return &lld.base; |
| 531 | } | 532 | } |
| 532 | switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { | 533 | switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) { |
| 533 | .plan9 => return error.UnsupportedObjectFormat, | 534 | .plan9 => return error.UnsupportedObjectFormat, |
| 534 | inline else => |tag| { | 535 | inline else => |tag| { |
| 535 | dev.check(tag.devFeature()); | 536 | dev.check(tag.devFeature()); |
| ... | @@ -552,7 +553,7 @@ pub const File = struct { | ... | @@ -552,7 +553,7 @@ pub const File = struct { |
| 552 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); | 553 | const lld: *Lld = try .createEmpty(arena, comp, emit, options); |
| 553 | return &lld.base; | 554 | return &lld.base; |
| 554 | } | 555 | } |
| 555 | switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) { | 556 | switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt, comp.config.use_new_linker)) { |
| 556 | .plan9 => return error.UnsupportedObjectFormat, | 557 | .plan9 => return error.UnsupportedObjectFormat, |
| 557 | inline else => |tag| { | 558 | inline else => |tag| { |
| 558 | dev.check(tag.devFeature()); | 559 | dev.check(tag.devFeature()); |
| ... | @@ -579,7 +580,8 @@ pub const File = struct { | ... | @@ -579,7 +580,8 @@ pub const File = struct { |
| 579 | const emit = base.emit; | 580 | const emit = base.emit; |
| 580 | if (base.child_pid) |pid| { | 581 | if (base.child_pid) |pid| { |
| 581 | if (builtin.os.tag == .windows) { | 582 | if (builtin.os.tag == .windows) { |
| 582 | base.cast(.coff).?.ptraceAttach(pid) catch |err| { | 583 | const coff_file = base.cast(.coff).?; |
| 584 | coff_file.ptraceAttach(pid) catch |err| { | ||
| 583 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); | 585 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); |
| 584 | }; | 586 | }; |
| 585 | } else { | 587 | } else { |
| ... | @@ -597,8 +599,11 @@ pub const File = struct { | ... | @@ -597,8 +599,11 @@ pub const File = struct { |
| 597 | .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| { | 599 | .linux => std.posix.ptrace(std.os.linux.PTRACE.ATTACH, pid, 0, 0) catch |err| { |
| 598 | log.warn("ptrace failure: {s}", .{@errorName(err)}); | 600 | log.warn("ptrace failure: {s}", .{@errorName(err)}); |
| 599 | }, | 601 | }, |
| 600 | .macos => base.cast(.macho).?.ptraceAttach(pid) catch |err| { | 602 | .macos => { |
| 601 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); | 603 | const macho_file = base.cast(.macho).?; |
| 604 | macho_file.ptraceAttach(pid) catch |err| { | ||
| 605 | log.warn("attaching failed with error: {s}", .{@errorName(err)}); | ||
| 606 | }; | ||
| 602 | }, | 607 | }, |
| 603 | .windows => unreachable, | 608 | .windows => unreachable, |
| 604 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | 609 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| ... | @@ -613,6 +618,20 @@ pub const File = struct { | ... | @@ -613,6 +618,20 @@ pub const File = struct { |
| 613 | .mode = determineMode(output_mode, link_mode), | 618 | .mode = determineMode(output_mode, link_mode), |
| 614 | }); | 619 | }); |
| 615 | }, | 620 | }, |
| 621 | .elf2 => { | ||
| 622 | const elf = base.cast(.elf2).?; | ||
| 623 | if (base.file == null) { | ||
| 624 | elf.mf.file = try base.emit.root_dir.handle.createFile(base.emit.sub_path, .{ | ||
| 625 | .truncate = false, | ||
| 626 | .read = true, | ||
| 627 | .mode = determineMode(comp.config.output_mode, comp.config.link_mode), | ||
| 628 | }); | ||
| 629 | base.file = elf.mf.file; | ||
| 630 | try elf.mf.ensureTotalCapacity( | ||
| 631 | @intCast(elf.mf.nodes.items[0].location().resolve(&elf.mf)[1]), | ||
| 632 | ); | ||
| 633 | } | ||
| 634 | }, | ||
| 616 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), | 635 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 617 | .plan9 => unreachable, | 636 | .plan9 => unreachable, |
| 618 | } | 637 | } |
| ... | @@ -669,14 +688,30 @@ pub const File = struct { | ... | @@ -669,14 +688,30 @@ pub const File = struct { |
| 669 | 688 | ||
| 670 | if (base.child_pid) |pid| { | 689 | if (base.child_pid) |pid| { |
| 671 | switch (builtin.os.tag) { | 690 | switch (builtin.os.tag) { |
| 672 | .macos => base.cast(.macho).?.ptraceDetach(pid) catch |err| { | 691 | .macos => { |
| 673 | log.warn("detaching failed with error: {s}", .{@errorName(err)}); | 692 | const macho_file = base.cast(.macho).?; |
| 693 | macho_file.ptraceDetach(pid) catch |err| { | ||
| 694 | log.warn("detaching failed with error: {s}", .{@errorName(err)}); | ||
| 695 | }; | ||
| 696 | }, | ||
| 697 | .windows => { | ||
| 698 | const coff_file = base.cast(.coff).?; | ||
| 699 | coff_file.ptraceDetach(pid); | ||
| 674 | }, | 700 | }, |
| 675 | .windows => base.cast(.coff).?.ptraceDetach(pid), | ||
| 676 | else => return error.HotSwapUnavailableOnHostOperatingSystem, | 701 | else => return error.HotSwapUnavailableOnHostOperatingSystem, |
| 677 | } | 702 | } |
| 678 | } | 703 | } |
| 679 | }, | 704 | }, |
| 705 | .elf2 => { | ||
| 706 | const elf = base.cast(.elf2).?; | ||
| 707 | if (base.file) |f| { | ||
| 708 | elf.mf.unmap(); | ||
| 709 | assert(elf.mf.file.handle == f.handle); | ||
| 710 | elf.mf.file = undefined; | ||
| 711 | f.close(); | ||
| 712 | base.file = null; | ||
| 713 | } | ||
| 714 | }, | ||
| 680 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), | 715 | .c, .spirv => dev.checkAny(&.{ .c_linker, .spirv_linker }), |
| 681 | .plan9 => unreachable, | 716 | .plan9 => unreachable, |
| 682 | } | 717 | } |
| ... | @@ -793,6 +828,7 @@ pub const File = struct { | ... | @@ -793,6 +828,7 @@ pub const File = struct { |
| 793 | .spirv => {}, | 828 | .spirv => {}, |
| 794 | .goff, .xcoff => {}, | 829 | .goff, .xcoff => {}, |
| 795 | .plan9 => unreachable, | 830 | .plan9 => unreachable, |
| 831 | .elf2 => {}, | ||
| 796 | inline else => |tag| { | 832 | inline else => |tag| { |
| 797 | dev.check(tag.devFeature()); | 833 | dev.check(tag.devFeature()); |
| 798 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); | 834 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id); |
| ... | @@ -825,6 +861,26 @@ pub const File = struct { | ... | @@ -825,6 +861,26 @@ pub const File = struct { |
| 825 | } | 861 | } |
| 826 | } | 862 | } |
| 827 | 863 | ||
| 864 | pub fn idle(base: *File, tid: Zcu.PerThread.Id) !bool { | ||
| 865 | switch (base.tag) { | ||
| 866 | else => return false, | ||
| 867 | inline .elf2 => |tag| { | ||
| 868 | dev.check(tag.devFeature()); | ||
| 869 | return @as(*tag.Type(), @fieldParentPtr("base", base)).idle(tid); | ||
| 870 | }, | ||
| 871 | } | ||
| 872 | } | ||
| 873 | |||
| 874 | pub fn updateErrorData(base: *File, pt: Zcu.PerThread) !void { | ||
| 875 | switch (base.tag) { | ||
| 876 | else => {}, | ||
| 877 | inline .elf2 => |tag| { | ||
| 878 | dev.check(tag.devFeature()); | ||
| 879 | return @as(*tag.Type(), @fieldParentPtr("base", base)).updateErrorData(pt); | ||
| 880 | }, | ||
| 881 | } | ||
| 882 | } | ||
| 883 | |||
| 828 | pub const FlushError = error{ | 884 | pub const FlushError = error{ |
| 829 | /// Indicates an error will be present in `Compilation.link_diags`. | 885 | /// Indicates an error will be present in `Compilation.link_diags`. |
| 830 | LinkFailure, | 886 | LinkFailure, |
| ... | @@ -1099,7 +1155,7 @@ pub const File = struct { | ... | @@ -1099,7 +1155,7 @@ pub const File = struct { |
| 1099 | if (base.zcu_object_basename != null) return; | 1155 | if (base.zcu_object_basename != null) return; |
| 1100 | 1156 | ||
| 1101 | switch (base.tag) { | 1157 | switch (base.tag) { |
| 1102 | inline .wasm => |tag| { | 1158 | inline .elf2, .wasm => |tag| { |
| 1103 | dev.check(tag.devFeature()); | 1159 | dev.check(tag.devFeature()); |
| 1104 | return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); | 1160 | return @as(*tag.Type(), @fieldParentPtr("base", base)).prelink(base.comp.link_prog_node); |
| 1105 | }, | 1161 | }, |
| ... | @@ -1110,6 +1166,7 @@ pub const File = struct { | ... | @@ -1110,6 +1166,7 @@ pub const File = struct { |
| 1110 | pub const Tag = enum { | 1166 | pub const Tag = enum { |
| 1111 | coff, | 1167 | coff, |
| 1112 | elf, | 1168 | elf, |
| 1169 | elf2, | ||
| 1113 | macho, | 1170 | macho, |
| 1114 | c, | 1171 | c, |
| 1115 | wasm, | 1172 | wasm, |
| ... | @@ -1123,6 +1180,7 @@ pub const File = struct { | ... | @@ -1123,6 +1180,7 @@ pub const File = struct { |
| 1123 | return switch (tag) { | 1180 | return switch (tag) { |
| 1124 | .coff => Coff, | 1181 | .coff => Coff, |
| 1125 | .elf => Elf, | 1182 | .elf => Elf, |
| 1183 | .elf2 => Elf2, | ||
| 1126 | .macho => MachO, | 1184 | .macho => MachO, |
| 1127 | .c => C, | 1185 | .c => C, |
| 1128 | .wasm => Wasm, | 1186 | .wasm => Wasm, |
| ... | @@ -1134,10 +1192,10 @@ pub const File = struct { | ... | @@ -1134,10 +1192,10 @@ pub const File = struct { |
| 1134 | }; | 1192 | }; |
| 1135 | } | 1193 | } |
| 1136 | 1194 | ||
| 1137 | fn fromObjectFormat(ofmt: std.Target.ObjectFormat) Tag { | 1195 | fn fromObjectFormat(ofmt: std.Target.ObjectFormat, use_new_linker: bool) Tag { |
| 1138 | return switch (ofmt) { | 1196 | return switch (ofmt) { |
| 1139 | .coff => .coff, | 1197 | .coff => .coff, |
| 1140 | .elf => .elf, | 1198 | .elf => if (use_new_linker) .elf2 else .elf, |
| 1141 | .macho => .macho, | 1199 | .macho => .macho, |
| 1142 | .wasm => .wasm, | 1200 | .wasm => .wasm, |
| 1143 | .plan9 => .plan9, | 1201 | .plan9 => .plan9, |
| ... | @@ -1223,6 +1281,7 @@ pub const File = struct { | ... | @@ -1223,6 +1281,7 @@ pub const File = struct { |
| 1223 | pub const C = @import("link/C.zig"); | 1281 | pub const C = @import("link/C.zig"); |
| 1224 | pub const Coff = @import("link/Coff.zig"); | 1282 | pub const Coff = @import("link/Coff.zig"); |
| 1225 | pub const Elf = @import("link/Elf.zig"); | 1283 | pub const Elf = @import("link/Elf.zig"); |
| 1284 | pub const Elf2 = @import("link/Elf2.zig"); | ||
| 1226 | pub const MachO = @import("link/MachO.zig"); | 1285 | pub const MachO = @import("link/MachO.zig"); |
| 1227 | pub const SpirV = @import("link/SpirV.zig"); | 1286 | pub const SpirV = @import("link/SpirV.zig"); |
| 1228 | pub const Wasm = @import("link/Wasm.zig"); | 1287 | pub const Wasm = @import("link/Wasm.zig"); |
| ... | @@ -1548,6 +1607,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void { | ... | @@ -1548,6 +1607,9 @@ pub fn doZcuTask(comp: *Compilation, tid: usize, task: ZcuTask) void { |
| 1548 | } | 1607 | } |
| 1549 | } | 1608 | } |
| 1550 | } | 1609 | } |
| 1610 | pub fn doIdleTask(comp: *Compilation, tid: usize) error{ OutOfMemory, LinkFailure }!bool { | ||
| 1611 | return if (comp.bin_file) |lf| lf.idle(@enumFromInt(tid)) else false; | ||
| 1612 | } | ||
| 1551 | /// After the main pipeline is done, but before flush, the compilation may need to link one final | 1613 | /// After the main pipeline is done, but before flush, the compilation may need to link one final |
| 1552 | /// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running | 1614 | /// `Nav` into the binary: the `builtin.test_functions` value. Since the link thread isn't running |
| 1553 | /// by then, we expose this function which can be called directly. | 1615 | /// by then, we expose this function which can be called directly. |
| ... | @@ -1573,6 +1635,13 @@ pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) | ... | @@ -1573,6 +1635,13 @@ pub fn linkTestFunctionsNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 1573 | }; | 1635 | }; |
| 1574 | } | 1636 | } |
| 1575 | } | 1637 | } |
| 1638 | pub fn updateErrorData(pt: Zcu.PerThread) void { | ||
| 1639 | const comp = pt.zcu.comp; | ||
| 1640 | if (comp.bin_file) |lf| lf.updateErrorData(pt) catch |err| switch (err) { | ||
| 1641 | error.OutOfMemory => comp.link_diags.setAllocFailure(), | ||
| 1642 | error.LinkFailure => {}, | ||
| 1643 | }; | ||
| 1644 | } | ||
| 1576 | 1645 | ||
| 1577 | /// Provided by the CLI, processed into `LinkInput` instances at the start of | 1646 | /// Provided by the CLI, processed into `LinkInput` instances at the start of |
| 1578 | /// the compilation pipeline. | 1647 | /// the compilation pipeline. |
src/link/Coff.zig+36-31| ... | @@ -953,7 +953,7 @@ fn writeOffsetTableEntry(coff: *Coff, index: usize) !void { | ... | @@ -953,7 +953,7 @@ fn writeOffsetTableEntry(coff: *Coff, index: usize) !void { |
| 953 | } | 953 | } |
| 954 | 954 | ||
| 955 | fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { | 955 | fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { |
| 956 | if (!coff.base.comp.incremental) return; | 956 | if (!coff.base.comp.config.incremental) return; |
| 957 | // TODO: reverse-lookup might come in handy here | 957 | // TODO: reverse-lookup might come in handy here |
| 958 | for (coff.relocs.values()) |*relocs| { | 958 | for (coff.relocs.values()) |*relocs| { |
| 959 | for (relocs.items) |*reloc| { | 959 | for (relocs.items) |*reloc| { |
| ... | @@ -964,7 +964,7 @@ fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { | ... | @@ -964,7 +964,7 @@ fn markRelocsDirtyByTarget(coff: *Coff, target: SymbolWithLoc) void { |
| 964 | } | 964 | } |
| 965 | 965 | ||
| 966 | fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void { | 966 | fn markRelocsDirtyByAddress(coff: *Coff, addr: u32) void { |
| 967 | if (!coff.base.comp.incremental) return; | 967 | if (!coff.base.comp.config.incremental) return; |
| 968 | const got_moved = blk: { | 968 | const got_moved = blk: { |
| 969 | const sect_id = coff.got_section_index orelse break :blk false; | 969 | const sect_id = coff.got_section_index orelse break :blk false; |
| 970 | break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr; | 970 | break :blk coff.sections.items(.header)[sect_id].virtual_address >= addr; |
| ... | @@ -1111,20 +1111,24 @@ pub fn updateFunc( | ... | @@ -1111,20 +1111,24 @@ pub fn updateFunc( |
| 1111 | 1111 | ||
| 1112 | coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?; | 1112 | coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?; |
| 1113 | 1113 | ||
| 1114 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1114 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1115 | defer code_buffer.deinit(gpa); | 1115 | defer aw.deinit(); |
| 1116 | 1116 | ||
| 1117 | try codegen.emitFunction( | 1117 | codegen.emitFunction( |
| 1118 | &coff.base, | 1118 | &coff.base, |
| 1119 | pt, | 1119 | pt, |
| 1120 | zcu.navSrcLoc(nav_index), | 1120 | zcu.navSrcLoc(nav_index), |
| 1121 | func_index, | 1121 | func_index, |
| 1122 | coff.getAtom(atom_index).getSymbolIndex().?, | ||
| 1122 | mir, | 1123 | mir, |
| 1123 | &code_buffer, | 1124 | &aw.writer, |
| 1124 | .none, | 1125 | .none, |
| 1125 | ); | 1126 | ) catch |err| switch (err) { |
| 1127 | error.WriteFailed => return error.OutOfMemory, | ||
| 1128 | else => |e| return e, | ||
| 1129 | }; | ||
| 1126 | 1130 | ||
| 1127 | try coff.updateNavCode(pt, nav_index, code_buffer.items, .FUNCTION); | 1131 | try coff.updateNavCode(pt, nav_index, aw.written(), .FUNCTION); |
| 1128 | 1132 | ||
| 1129 | // Exports will be updated by `Zcu.processExports` after the update. | 1133 | // Exports will be updated by `Zcu.processExports` after the update. |
| 1130 | } | 1134 | } |
| ... | @@ -1145,18 +1149,18 @@ fn lowerConst( | ... | @@ -1145,18 +1149,18 @@ fn lowerConst( |
| 1145 | ) !LowerConstResult { | 1149 | ) !LowerConstResult { |
| 1146 | const gpa = coff.base.comp.gpa; | 1150 | const gpa = coff.base.comp.gpa; |
| 1147 | 1151 | ||
| 1148 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1152 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1149 | defer code_buffer.deinit(gpa); | 1153 | defer aw.deinit(); |
| 1150 | 1154 | ||
| 1151 | const atom_index = try coff.createAtom(); | 1155 | const atom_index = try coff.createAtom(); |
| 1152 | const sym = coff.getAtom(atom_index).getSymbolPtr(coff); | 1156 | const sym = coff.getAtom(atom_index).getSymbolPtr(coff); |
| 1153 | try coff.setSymbolName(sym, name); | 1157 | try coff.setSymbolName(sym, name); |
| 1154 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1)); | 1158 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(sect_id + 1)); |
| 1155 | 1159 | ||
| 1156 | try codegen.generateSymbol(&coff.base, pt, src_loc, val, &code_buffer, .{ | 1160 | try codegen.generateSymbol(&coff.base, pt, src_loc, val, &aw.writer, .{ |
| 1157 | .atom_index = coff.getAtom(atom_index).getSymbolIndex().?, | 1161 | .atom_index = coff.getAtom(atom_index).getSymbolIndex().?, |
| 1158 | }); | 1162 | }); |
| 1159 | const code = code_buffer.items; | 1163 | const code = aw.written(); |
| 1160 | 1164 | ||
| 1161 | const atom = coff.getAtomPtr(atom_index); | 1165 | const atom = coff.getAtomPtr(atom_index); |
| 1162 | atom.size = @intCast(code.len); | 1166 | atom.size = @intCast(code.len); |
| ... | @@ -1170,7 +1174,7 @@ fn lowerConst( | ... | @@ -1170,7 +1174,7 @@ fn lowerConst( |
| 1170 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value }); | 1174 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(coff).value }); |
| 1171 | log.debug(" (required alignment 0x{x})", .{required_alignment}); | 1175 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 1172 | 1176 | ||
| 1173 | try coff.writeAtom(atom_index, code, coff.base.comp.incremental); | 1177 | try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental); |
| 1174 | 1178 | ||
| 1175 | return .{ .ok = atom_index }; | 1179 | return .{ .ok = atom_index }; |
| 1176 | } | 1180 | } |
| ... | @@ -1214,19 +1218,22 @@ pub fn updateNav( | ... | @@ -1214,19 +1218,22 @@ pub fn updateNav( |
| 1214 | 1218 | ||
| 1215 | coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index); | 1219 | coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index); |
| 1216 | 1220 | ||
| 1217 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1221 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1218 | defer code_buffer.deinit(gpa); | 1222 | defer aw.deinit(); |
| 1219 | 1223 | ||
| 1220 | try codegen.generateSymbol( | 1224 | codegen.generateSymbol( |
| 1221 | &coff.base, | 1225 | &coff.base, |
| 1222 | pt, | 1226 | pt, |
| 1223 | zcu.navSrcLoc(nav_index), | 1227 | zcu.navSrcLoc(nav_index), |
| 1224 | nav_init, | 1228 | nav_init, |
| 1225 | &code_buffer, | 1229 | &aw.writer, |
| 1226 | .{ .atom_index = atom.getSymbolIndex().? }, | 1230 | .{ .atom_index = atom.getSymbolIndex().? }, |
| 1227 | ); | 1231 | ) catch |err| switch (err) { |
| 1232 | error.WriteFailed => return error.OutOfMemory, | ||
| 1233 | else => |e| return e, | ||
| 1234 | }; | ||
| 1228 | 1235 | ||
| 1229 | try coff.updateNavCode(pt, nav_index, code_buffer.items, .NULL); | 1236 | try coff.updateNavCode(pt, nav_index, aw.written(), .NULL); |
| 1230 | } | 1237 | } |
| 1231 | 1238 | ||
| 1232 | // Exports will be updated by `Zcu.processExports` after the update. | 1239 | // Exports will be updated by `Zcu.processExports` after the update. |
| ... | @@ -1244,8 +1251,8 @@ fn updateLazySymbolAtom( | ... | @@ -1244,8 +1251,8 @@ fn updateLazySymbolAtom( |
| 1244 | const gpa = comp.gpa; | 1251 | const gpa = comp.gpa; |
| 1245 | 1252 | ||
| 1246 | var required_alignment: InternPool.Alignment = .none; | 1253 | var required_alignment: InternPool.Alignment = .none; |
| 1247 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1254 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1248 | defer code_buffer.deinit(gpa); | 1255 | defer aw.deinit(); |
| 1249 | 1256 | ||
| 1250 | const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{ | 1257 | const name = try allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| 1251 | @tagName(sym.kind), | 1258 | @tagName(sym.kind), |
| ... | @@ -1262,11 +1269,11 @@ fn updateLazySymbolAtom( | ... | @@ -1262,11 +1269,11 @@ fn updateLazySymbolAtom( |
| 1262 | src, | 1269 | src, |
| 1263 | sym, | 1270 | sym, |
| 1264 | &required_alignment, | 1271 | &required_alignment, |
| 1265 | &code_buffer, | 1272 | &aw.writer, |
| 1266 | .none, | 1273 | .none, |
| 1267 | .{ .atom_index = local_sym_index }, | 1274 | .{ .atom_index = local_sym_index }, |
| 1268 | ); | 1275 | ); |
| 1269 | const code = code_buffer.items; | 1276 | const code = aw.written(); |
| 1270 | 1277 | ||
| 1271 | const atom = coff.getAtomPtr(atom_index); | 1278 | const atom = coff.getAtomPtr(atom_index); |
| 1272 | const symbol = atom.getSymbolPtr(coff); | 1279 | const symbol = atom.getSymbolPtr(coff); |
| ... | @@ -1285,7 +1292,7 @@ fn updateLazySymbolAtom( | ... | @@ -1285,7 +1292,7 @@ fn updateLazySymbolAtom( |
| 1285 | symbol.value = vaddr; | 1292 | symbol.value = vaddr; |
| 1286 | 1293 | ||
| 1287 | try coff.addGotEntry(.{ .sym_index = local_sym_index }); | 1294 | try coff.addGotEntry(.{ .sym_index = local_sym_index }); |
| 1288 | try coff.writeAtom(atom_index, code, coff.base.comp.incremental); | 1295 | try coff.writeAtom(atom_index, code, coff.base.comp.config.incremental); |
| 1289 | } | 1296 | } |
| 1290 | 1297 | ||
| 1291 | pub fn getOrCreateAtomForLazySymbol( | 1298 | pub fn getOrCreateAtomForLazySymbol( |
| ... | @@ -1437,7 +1444,7 @@ fn updateNavCode( | ... | @@ -1437,7 +1444,7 @@ fn updateNavCode( |
| 1437 | }; | 1444 | }; |
| 1438 | } | 1445 | } |
| 1439 | 1446 | ||
| 1440 | coff.writeAtom(atom_index, code, coff.base.comp.incremental) catch |err| switch (err) { | 1447 | coff.writeAtom(atom_index, code, coff.base.comp.config.incremental) catch |err| switch (err) { |
| 1441 | error.OutOfMemory => return error.OutOfMemory, | 1448 | error.OutOfMemory => return error.OutOfMemory, |
| 1442 | else => |e| return coff.base.cgFail(nav_index, "failed to write atom: {s}", .{@errorName(e)}), | 1449 | else => |e| return coff.base.cgFail(nav_index, "failed to write atom: {s}", .{@errorName(e)}), |
| 1443 | }; | 1450 | }; |
| ... | @@ -1539,14 +1546,12 @@ pub fn updateExports( | ... | @@ -1539,14 +1546,12 @@ pub fn updateExports( |
| 1539 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1)); | 1546 | sym.section_number = @as(coff_util.SectionNumber, @enumFromInt(metadata.section + 1)); |
| 1540 | sym.type = atom.getSymbol(coff).type; | 1547 | sym.type = atom.getSymbol(coff).type; |
| 1541 | 1548 | ||
| 1542 | switch (exp.opts.linkage) { | 1549 | sym.storage_class = switch (exp.opts.linkage) { |
| 1543 | .strong => { | 1550 | .internal => .EXTERNAL, |
| 1544 | sym.storage_class = .EXTERNAL; | 1551 | .strong => .EXTERNAL, |
| 1545 | }, | ||
| 1546 | .internal => @panic("TODO Internal"), | ||
| 1547 | .weak => @panic("TODO WeakExternal"), | 1552 | .weak => @panic("TODO WeakExternal"), |
| 1548 | else => unreachable, | 1553 | else => unreachable, |
| 1549 | } | 1554 | }; |
| 1550 | 1555 | ||
| 1551 | try coff.resolveGlobalSymbol(sym_loc); | 1556 | try coff.resolveGlobalSymbol(sym_loc); |
| 1552 | } | 1557 | } |
src/link/Dwarf.zig+10-7| ... | @@ -2126,19 +2126,22 @@ pub const WipNav = struct { | ... | @@ -2126,19 +2126,22 @@ pub const WipNav = struct { |
| 2126 | const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0; | 2126 | const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0; |
| 2127 | try diw.writeUleb128(size); | 2127 | try diw.writeUleb128(size); |
| 2128 | if (size == 0) return; | 2128 | if (size == 0) return; |
| 2129 | var bytes = wip_nav.debug_info.toArrayList(); | 2129 | const old_end = wip_nav.debug_info.writer.end; |
| 2130 | defer wip_nav.debug_info = .fromArrayList(wip_nav.dwarf.gpa, &bytes); | ||
| 2131 | const old_len = bytes.items.len; | ||
| 2132 | try codegen.generateSymbol( | 2130 | try codegen.generateSymbol( |
| 2133 | wip_nav.dwarf.bin_file, | 2131 | wip_nav.dwarf.bin_file, |
| 2134 | wip_nav.pt, | 2132 | wip_nav.pt, |
| 2135 | src_loc, | 2133 | src_loc, |
| 2136 | val, | 2134 | val, |
| 2137 | &bytes, | 2135 | &wip_nav.debug_info.writer, |
| 2138 | .{ .debug_output = .{ .dwarf = wip_nav } }, | 2136 | .{ .debug_output = .{ .dwarf = wip_nav } }, |
| 2139 | ); | 2137 | ); |
| 2140 | if (old_len + size != bytes.items.len) { | 2138 | if (old_end + size != wip_nav.debug_info.writer.end) { |
| 2141 | std.debug.print("{f} [{}]: {} != {}\n", .{ ty.fmt(wip_nav.pt), ty.toIntern(), size, bytes.items.len - old_len }); | 2139 | std.debug.print("{f} [{}]: {} != {}\n", .{ |
| 2140 | ty.fmt(wip_nav.pt), | ||
| 2141 | ty.toIntern(), | ||
| 2142 | size, | ||
| 2143 | wip_nav.debug_info.writer.end - old_end, | ||
| 2144 | }); | ||
| 2142 | unreachable; | 2145 | unreachable; |
| 2143 | } | 2146 | } |
| 2144 | } | 2147 | } |
| ... | @@ -6429,7 +6432,7 @@ fn sleb128Bytes(value: anytype) u32 { | ... | @@ -6429,7 +6432,7 @@ fn sleb128Bytes(value: anytype) u32 { |
| 6429 | /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional | 6432 | /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional |
| 6430 | const force_incremental = false; | 6433 | const force_incremental = false; |
| 6431 | inline fn incremental(dwarf: Dwarf) bool { | 6434 | inline fn incremental(dwarf: Dwarf) bool { |
| 6432 | return force_incremental or dwarf.bin_file.comp.incremental; | 6435 | return force_incremental or dwarf.bin_file.comp.config.incremental; |
| 6433 | } | 6436 | } |
| 6434 | 6437 | ||
| 6435 | const Allocator = std.mem.Allocator; | 6438 | const Allocator = std.mem.Allocator; |
src/link/Elf/LinkerDefined.zig+1-1| ... | @@ -47,7 +47,7 @@ fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) | ... | @@ -47,7 +47,7 @@ fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) |
| 47 | const esym = self.symtab.addOneAssumeCapacity(); | 47 | const esym = self.symtab.addOneAssumeCapacity(); |
| 48 | esym.* = .{ | 48 | esym.* = .{ |
| 49 | .st_name = name_off, | 49 | .st_name = name_off, |
| 50 | .st_info = elf.STB_WEAK << 4, | 50 | .st_info = @as(u8, elf.STB_WEAK) << 4, |
| 51 | .st_other = @intFromEnum(elf.STV.HIDDEN), | 51 | .st_other = @intFromEnum(elf.STV.HIDDEN), |
| 52 | .st_shndx = elf.SHN_ABS, | 52 | .st_shndx = elf.SHN_ABS, |
| 53 | .st_value = 0, | 53 | .st_value = 0, |
src/link/Elf/SharedObject.zig+1-1| ... | @@ -105,7 +105,7 @@ pub fn parseHeader( | ... | @@ -105,7 +105,7 @@ pub fn parseHeader( |
| 105 | if (amt != buf.len) return error.UnexpectedEndOfFile; | 105 | if (amt != buf.len) return error.UnexpectedEndOfFile; |
| 106 | } | 106 | } |
| 107 | if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic; | 107 | if (!mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")) return error.BadMagic; |
| 108 | if (ehdr.e_ident[elf.EI_VERSION] != 1) return error.BadElfVersion; | 108 | if (ehdr.e_ident[elf.EI.VERSION] != 1) return error.BadElfVersion; |
| 109 | if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject; | 109 | if (ehdr.e_type != elf.ET.DYN) return error.NotSharedObject; |
| 110 | 110 | ||
| 111 | if (target.toElfMachine() != ehdr.e_machine) | 111 | if (target.toElfMachine() != ehdr.e_machine) |
src/link/Elf/ZigObject.zig+42-30| ... | @@ -277,8 +277,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { | ... | @@ -277,8 +277,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { |
| 277 | pt, | 277 | pt, |
| 278 | .{ .kind = .code, .ty = .anyerror_type }, | 278 | .{ .kind = .code, .ty = .anyerror_type }, |
| 279 | metadata.text_symbol_index, | 279 | metadata.text_symbol_index, |
| 280 | ) catch |err| return switch (err) { | 280 | ) catch |err| switch (err) { |
| 281 | error.CodegenFail => error.LinkFailure, | 281 | error.CodegenFail => return error.LinkFailure, |
| 282 | else => |e| return e, | 282 | else => |e| return e, |
| 283 | }; | 283 | }; |
| 284 | if (metadata.rodata_state != .unused) self.updateLazySymbol( | 284 | if (metadata.rodata_state != .unused) self.updateLazySymbol( |
| ... | @@ -286,8 +286,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { | ... | @@ -286,8 +286,8 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { |
| 286 | pt, | 286 | pt, |
| 287 | .{ .kind = .const_data, .ty = .anyerror_type }, | 287 | .{ .kind = .const_data, .ty = .anyerror_type }, |
| 288 | metadata.rodata_symbol_index, | 288 | metadata.rodata_symbol_index, |
| 289 | ) catch |err| return switch (err) { | 289 | ) catch |err| switch (err) { |
| 290 | error.CodegenFail => error.LinkFailure, | 290 | error.CodegenFail => return error.LinkFailure, |
| 291 | else => |e| return e, | 291 | else => |e| return e, |
| 292 | }; | 292 | }; |
| 293 | } | 293 | } |
| ... | @@ -1533,22 +1533,26 @@ pub fn updateFunc( | ... | @@ -1533,22 +1533,26 @@ pub fn updateFunc( |
| 1533 | const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav); | 1533 | const sym_index = try self.getOrCreateMetadataForNav(zcu, func.owner_nav); |
| 1534 | self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self); | 1534 | self.atom(self.symbol(sym_index).ref.index).?.freeRelocs(self); |
| 1535 | 1535 | ||
| 1536 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1536 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1537 | defer code_buffer.deinit(gpa); | 1537 | defer aw.deinit(); |
| 1538 | 1538 | ||
| 1539 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; | 1539 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; |
| 1540 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); | 1540 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 1541 | 1541 | ||
| 1542 | try codegen.emitFunction( | 1542 | codegen.emitFunction( |
| 1543 | &elf_file.base, | 1543 | &elf_file.base, |
| 1544 | pt, | 1544 | pt, |
| 1545 | zcu.navSrcLoc(func.owner_nav), | 1545 | zcu.navSrcLoc(func.owner_nav), |
| 1546 | func_index, | 1546 | func_index, |
| 1547 | sym_index, | ||
| 1547 | mir, | 1548 | mir, |
| 1548 | &code_buffer, | 1549 | &aw.writer, |
| 1549 | if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none, | 1550 | if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none, |
| 1550 | ); | 1551 | ) catch |err| switch (err) { |
| 1551 | const code = code_buffer.items; | 1552 | error.WriteFailed => return error.OutOfMemory, |
| 1553 | else => |e| return e, | ||
| 1554 | }; | ||
| 1555 | const code = aw.written(); | ||
| 1552 | 1556 | ||
| 1553 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); | 1557 | const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code); |
| 1554 | log.debug("setting shdr({x},{s}) for {f}", .{ | 1558 | log.debug("setting shdr({x},{s}) for {f}", .{ |
| ... | @@ -1663,21 +1667,24 @@ pub fn updateNav( | ... | @@ -1663,21 +1667,24 @@ pub fn updateNav( |
| 1663 | const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index); | 1667 | const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index); |
| 1664 | self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); | 1668 | self.symbol(sym_index).atom(elf_file).?.freeRelocs(self); |
| 1665 | 1669 | ||
| 1666 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1670 | var aw: std.Io.Writer.Allocating = .init(zcu.gpa); |
| 1667 | defer code_buffer.deinit(zcu.gpa); | 1671 | defer aw.deinit(); |
| 1668 | 1672 | ||
| 1669 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; | 1673 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; |
| 1670 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); | 1674 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 1671 | 1675 | ||
| 1672 | try codegen.generateSymbol( | 1676 | codegen.generateSymbol( |
| 1673 | &elf_file.base, | 1677 | &elf_file.base, |
| 1674 | pt, | 1678 | pt, |
| 1675 | zcu.navSrcLoc(nav_index), | 1679 | zcu.navSrcLoc(nav_index), |
| 1676 | Value.fromInterned(nav_init), | 1680 | Value.fromInterned(nav_init), |
| 1677 | &code_buffer, | 1681 | &aw.writer, |
| 1678 | .{ .atom_index = sym_index }, | 1682 | .{ .atom_index = sym_index }, |
| 1679 | ); | 1683 | ) catch |err| switch (err) { |
| 1680 | const code = code_buffer.items; | 1684 | error.WriteFailed => return error.OutOfMemory, |
| 1685 | else => |e| return e, | ||
| 1686 | }; | ||
| 1687 | const code = aw.written(); | ||
| 1681 | 1688 | ||
| 1682 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); | 1689 | const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code); |
| 1683 | log.debug("setting shdr({x},{s}) for {f}", .{ | 1690 | log.debug("setting shdr({x},{s}) for {f}", .{ |
| ... | @@ -1722,8 +1729,8 @@ fn updateLazySymbol( | ... | @@ -1722,8 +1729,8 @@ fn updateLazySymbol( |
| 1722 | const gpa = zcu.gpa; | 1729 | const gpa = zcu.gpa; |
| 1723 | 1730 | ||
| 1724 | var required_alignment: InternPool.Alignment = .none; | 1731 | var required_alignment: InternPool.Alignment = .none; |
| 1725 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1732 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1726 | defer code_buffer.deinit(gpa); | 1733 | defer aw.deinit(); |
| 1727 | 1734 | ||
| 1728 | const name_str_index = blk: { | 1735 | const name_str_index = blk: { |
| 1729 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ | 1736 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| ... | @@ -1734,18 +1741,20 @@ fn updateLazySymbol( | ... | @@ -1734,18 +1741,20 @@ fn updateLazySymbol( |
| 1734 | break :blk try self.strtab.insert(gpa, name); | 1741 | break :blk try self.strtab.insert(gpa, name); |
| 1735 | }; | 1742 | }; |
| 1736 | 1743 | ||
| 1737 | const src = Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse Zcu.LazySrcLoc.unneeded; | 1744 | codegen.generateLazySymbol( |
| 1738 | try codegen.generateLazySymbol( | ||
| 1739 | &elf_file.base, | 1745 | &elf_file.base, |
| 1740 | pt, | 1746 | pt, |
| 1741 | src, | 1747 | Type.fromInterned(sym.ty).srcLocOrNull(zcu) orelse .unneeded, |
| 1742 | sym, | 1748 | sym, |
| 1743 | &required_alignment, | 1749 | &required_alignment, |
| 1744 | &code_buffer, | 1750 | &aw.writer, |
| 1745 | .none, | 1751 | .none, |
| 1746 | .{ .atom_index = symbol_index }, | 1752 | .{ .atom_index = symbol_index }, |
| 1747 | ); | 1753 | ) catch |err| switch (err) { |
| 1748 | const code = code_buffer.items; | 1754 | error.WriteFailed => return error.OutOfMemory, |
| 1755 | else => |e| return e, | ||
| 1756 | }; | ||
| 1757 | const code = aw.written(); | ||
| 1749 | 1758 | ||
| 1750 | const output_section_index = switch (sym.kind) { | 1759 | const output_section_index = switch (sym.kind) { |
| 1751 | .code => if (self.text_index) |sym_index| | 1760 | .code => if (self.text_index) |sym_index| |
| ... | @@ -1807,21 +1816,24 @@ fn lowerConst( | ... | @@ -1807,21 +1816,24 @@ fn lowerConst( |
| 1807 | ) !codegen.SymbolResult { | 1816 | ) !codegen.SymbolResult { |
| 1808 | const gpa = pt.zcu.gpa; | 1817 | const gpa = pt.zcu.gpa; |
| 1809 | 1818 | ||
| 1810 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1819 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1811 | defer code_buffer.deinit(gpa); | 1820 | defer aw.deinit(); |
| 1812 | 1821 | ||
| 1813 | const name_off = try self.addString(gpa, name); | 1822 | const name_off = try self.addString(gpa, name); |
| 1814 | const sym_index = try self.newSymbolWithAtom(gpa, name_off); | 1823 | const sym_index = try self.newSymbolWithAtom(gpa, name_off); |
| 1815 | 1824 | ||
| 1816 | try codegen.generateSymbol( | 1825 | codegen.generateSymbol( |
| 1817 | &elf_file.base, | 1826 | &elf_file.base, |
| 1818 | pt, | 1827 | pt, |
| 1819 | src_loc, | 1828 | src_loc, |
| 1820 | val, | 1829 | val, |
| 1821 | &code_buffer, | 1830 | &aw.writer, |
| 1822 | .{ .atom_index = sym_index }, | 1831 | .{ .atom_index = sym_index }, |
| 1823 | ); | 1832 | ) catch |err| switch (err) { |
| 1824 | const code = code_buffer.items; | 1833 | error.WriteFailed => return error.OutOfMemory, |
| 1834 | else => |e| return e, | ||
| 1835 | }; | ||
| 1836 | const code = aw.written(); | ||
| 1825 | 1837 | ||
| 1826 | const local_sym = self.symbol(sym_index); | 1838 | const local_sym = self.symbol(sym_index); |
| 1827 | const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; | 1839 | const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index]; |
src/link/Elf2.zig created+2036| ... | @@ -0,0 +1,2036 @@ | ||
| 1 | base: link.File, | ||
| 2 | mf: MappedFile, | ||
| 3 | nodes: std.MultiArrayList(Node), | ||
| 4 | symtab: std.ArrayList(Symbol), | ||
| 5 | shstrtab: StringTable, | ||
| 6 | strtab: StringTable, | ||
| 7 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), | ||
| 8 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | ||
| 9 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 10 | lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | ||
| 11 | map: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | ||
| 12 | pending_index: u32, | ||
| 13 | }), | ||
| 14 | pending_uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, struct { | ||
| 15 | alignment: InternPool.Alignment, | ||
| 16 | src_loc: Zcu.LazySrcLoc, | ||
| 17 | }), | ||
| 18 | relocs: std.ArrayList(Reloc), | ||
| 19 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. | ||
| 20 | entry_hack: Symbol.Index, | ||
| 21 | |||
| 22 | pub const Node = union(enum) { | ||
| 23 | file, | ||
| 24 | ehdr, | ||
| 25 | shdr, | ||
| 26 | segment: u32, | ||
| 27 | section: Symbol.Index, | ||
| 28 | nav: InternPool.Nav.Index, | ||
| 29 | uav: InternPool.Index, | ||
| 30 | lazy_code: InternPool.Index, | ||
| 31 | lazy_const_data: InternPool.Index, | ||
| 32 | |||
| 33 | pub const Tag = @typeInfo(Node).@"union".tag_type.?; | ||
| 34 | |||
| 35 | const known_count = @typeInfo(@TypeOf(known)).@"struct".fields.len; | ||
| 36 | const known = known: { | ||
| 37 | const Known = enum { | ||
| 38 | file, | ||
| 39 | seg_rodata, | ||
| 40 | ehdr, | ||
| 41 | phdr, | ||
| 42 | shdr, | ||
| 43 | seg_text, | ||
| 44 | seg_data, | ||
| 45 | }; | ||
| 46 | var mut_known: std.enums.EnumFieldStruct( | ||
| 47 | Known, | ||
| 48 | MappedFile.Node.Index, | ||
| 49 | null, | ||
| 50 | ) = undefined; | ||
| 51 | for (@typeInfo(Known).@"enum".fields) |field| | ||
| 52 | @field(mut_known, field.name) = @enumFromInt(field.value); | ||
| 53 | break :known mut_known; | ||
| 54 | }; | ||
| 55 | |||
| 56 | comptime { | ||
| 57 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 8); | ||
| 58 | } | ||
| 59 | }; | ||
| 60 | |||
| 61 | pub const StringTable = struct { | ||
| 62 | map: std.HashMapUnmanaged(u32, void, StringTable.Context, std.hash_map.default_max_load_percentage), | ||
| 63 | size: u32, | ||
| 64 | |||
| 65 | const Context = struct { | ||
| 66 | slice: []const u8, | ||
| 67 | |||
| 68 | pub fn eql(_: Context, lhs_key: u32, rhs_key: u32) bool { | ||
| 69 | return lhs_key == rhs_key; | ||
| 70 | } | ||
| 71 | |||
| 72 | pub fn hash(ctx: Context, key: u32) u64 { | ||
| 73 | return std.hash_map.hashString(std.mem.sliceTo(ctx.slice[key..], 0)); | ||
| 74 | } | ||
| 75 | }; | ||
| 76 | |||
| 77 | const Adapter = struct { | ||
| 78 | slice: []const u8, | ||
| 79 | |||
| 80 | pub fn eql(adapter: Adapter, lhs_key: []const u8, rhs_key: u32) bool { | ||
| 81 | return std.mem.startsWith(u8, adapter.slice[rhs_key..], lhs_key) and | ||
| 82 | adapter.slice[rhs_key + lhs_key.len] == 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | pub fn hash(_: Adapter, key: []const u8) u64 { | ||
| 86 | assert(std.mem.indexOfScalar(u8, key, 0) == null); | ||
| 87 | return std.hash_map.hashString(key); | ||
| 88 | } | ||
| 89 | }; | ||
| 90 | |||
| 91 | pub fn get( | ||
| 92 | st: *StringTable, | ||
| 93 | gpa: std.mem.Allocator, | ||
| 94 | mf: *MappedFile, | ||
| 95 | ni: MappedFile.Node.Index, | ||
| 96 | key: []const u8, | ||
| 97 | ) !u32 { | ||
| 98 | const slice_const = ni.sliceConst(mf); | ||
| 99 | const gop = try st.map.getOrPutContextAdapted( | ||
| 100 | gpa, | ||
| 101 | key, | ||
| 102 | StringTable.Adapter{ .slice = slice_const }, | ||
| 103 | .{ .slice = slice_const }, | ||
| 104 | ); | ||
| 105 | if (gop.found_existing) return gop.key_ptr.*; | ||
| 106 | const old_size = st.size; | ||
| 107 | const new_size: u32 = @intCast(old_size + key.len + 1); | ||
| 108 | st.size = new_size; | ||
| 109 | try ni.resize(mf, gpa, new_size); | ||
| 110 | const slice = ni.slice(mf)[old_size..]; | ||
| 111 | @memcpy(slice[0..key.len], key); | ||
| 112 | slice[key.len] = 0; | ||
| 113 | gop.key_ptr.* = old_size; | ||
| 114 | return old_size; | ||
| 115 | } | ||
| 116 | }; | ||
| 117 | |||
| 118 | pub const Symbol = struct { | ||
| 119 | ni: MappedFile.Node.Index, | ||
| 120 | /// Relocations contained within this symbol | ||
| 121 | loc_relocs: Reloc.Index, | ||
| 122 | /// Relocations targeting this symbol | ||
| 123 | target_relocs: Reloc.Index, | ||
| 124 | unused: u32 = 0, | ||
| 125 | |||
| 126 | pub const Index = enum(u32) { | ||
| 127 | null, | ||
| 128 | symtab, | ||
| 129 | shstrtab, | ||
| 130 | strtab, | ||
| 131 | rodata, | ||
| 132 | text, | ||
| 133 | data, | ||
| 134 | tdata, | ||
| 135 | _, | ||
| 136 | |||
| 137 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { | ||
| 138 | return &elf.symtab.items[@intFromEnum(si)]; | ||
| 139 | } | ||
| 140 | |||
| 141 | pub fn node(si: Symbol.Index, elf: *Elf) MappedFile.Node.Index { | ||
| 142 | const ni = si.get(elf).ni; | ||
| 143 | assert(ni != .none); | ||
| 144 | return ni; | ||
| 145 | } | ||
| 146 | |||
| 147 | pub const InitOptions = struct { | ||
| 148 | name: []const u8 = "", | ||
| 149 | size: std.elf.Word = 0, | ||
| 150 | type: std.elf.STT, | ||
| 151 | bind: std.elf.STB = .LOCAL, | ||
| 152 | visibility: std.elf.STV = .DEFAULT, | ||
| 153 | shndx: std.elf.Section = std.elf.SHN_UNDEF, | ||
| 154 | }; | ||
| 155 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { | ||
| 156 | const name_entry = try elf.string(.strtab, opts.name); | ||
| 157 | try Symbol.Index.symtab.node(elf).resize( | ||
| 158 | &elf.mf, | ||
| 159 | elf.base.comp.gpa, | ||
| 160 | @as(usize, switch (elf.identClass()) { | ||
| 161 | .NONE, _ => unreachable, | ||
| 162 | .@"32" => @sizeOf(std.elf.Elf32.Sym), | ||
| 163 | .@"64" => @sizeOf(std.elf.Elf64.Sym), | ||
| 164 | }) * elf.symtab.items.len, | ||
| 165 | ); | ||
| 166 | switch (elf.symPtr(si)) { | ||
| 167 | inline else => |sym| sym.* = .{ | ||
| 168 | .name = name_entry, | ||
| 169 | .value = 0, | ||
| 170 | .size = opts.size, | ||
| 171 | .info = .{ | ||
| 172 | .type = opts.type, | ||
| 173 | .bind = opts.bind, | ||
| 174 | }, | ||
| 175 | .other = .{ | ||
| 176 | .visibility = opts.visibility, | ||
| 177 | }, | ||
| 178 | .shndx = opts.shndx, | ||
| 179 | }, | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { | ||
| 184 | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { | ||
| 185 | if (reloc.loc != si) break; | ||
| 186 | reloc.apply(elf); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | pub fn applyTargetRelocs(si: Symbol.Index, elf: *Elf) void { | ||
| 191 | var ri = si.get(elf).target_relocs; | ||
| 192 | while (ri != .none) { | ||
| 193 | const reloc = ri.get(elf); | ||
| 194 | assert(reloc.target == si); | ||
| 195 | reloc.apply(elf); | ||
| 196 | ri = reloc.next; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | pub fn deleteLocationRelocs(si: Symbol.Index, elf: *Elf) void { | ||
| 201 | const sym = si.get(elf); | ||
| 202 | for (elf.relocs.items[@intFromEnum(sym.loc_relocs)..]) |*reloc| { | ||
| 203 | if (reloc.loc != si) break; | ||
| 204 | reloc.delete(elf); | ||
| 205 | } | ||
| 206 | sym.loc_relocs = .none; | ||
| 207 | } | ||
| 208 | }; | ||
| 209 | |||
| 210 | comptime { | ||
| 211 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); | ||
| 212 | } | ||
| 213 | }; | ||
| 214 | |||
| 215 | pub const Reloc = extern struct { | ||
| 216 | type: Reloc.Type, | ||
| 217 | prev: Reloc.Index, | ||
| 218 | next: Reloc.Index, | ||
| 219 | loc: Symbol.Index, | ||
| 220 | target: Symbol.Index, | ||
| 221 | unused: u32, | ||
| 222 | offset: u64, | ||
| 223 | addend: i64, | ||
| 224 | |||
| 225 | pub const Type = extern union { | ||
| 226 | x86_64: std.elf.R_X86_64, | ||
| 227 | aarch64: std.elf.R_AARCH64, | ||
| 228 | riscv: std.elf.R_RISCV, | ||
| 229 | ppc64: std.elf.R_PPC64, | ||
| 230 | }; | ||
| 231 | |||
| 232 | pub const Index = enum(u32) { | ||
| 233 | none = std.math.maxInt(u32), | ||
| 234 | _, | ||
| 235 | |||
| 236 | pub fn get(si: Reloc.Index, elf: *Elf) *Reloc { | ||
| 237 | return &elf.relocs.items[@intFromEnum(si)]; | ||
| 238 | } | ||
| 239 | }; | ||
| 240 | |||
| 241 | pub fn apply(reloc: *const Reloc, elf: *Elf) void { | ||
| 242 | const target_endian = elf.endian(); | ||
| 243 | switch (reloc.loc.get(elf).ni) { | ||
| 244 | .none => return, | ||
| 245 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | ||
| 246 | } | ||
| 247 | switch (reloc.target.get(elf).ni) { | ||
| 248 | .none => return, | ||
| 249 | else => |ni| if (ni.hasMoved(&elf.mf)) return, | ||
| 250 | } | ||
| 251 | switch (elf.shdrSlice()) { | ||
| 252 | inline else => |shdr, class| { | ||
| 253 | const sym = @field(elf.symSlice(), @tagName(class)); | ||
| 254 | const loc_sym = &sym[@intFromEnum(reloc.loc)]; | ||
| 255 | const loc_shndx = | ||
| 256 | std.mem.toNative(@TypeOf(loc_sym.shndx), loc_sym.shndx, target_endian); | ||
| 257 | assert(loc_shndx != std.elf.SHN_UNDEF); | ||
| 258 | const loc_sh = &shdr[loc_shndx]; | ||
| 259 | const loc_value = std.mem.toNative( | ||
| 260 | @TypeOf(loc_sym.value), | ||
| 261 | loc_sym.value, | ||
| 262 | target_endian, | ||
| 263 | ) + reloc.offset; | ||
| 264 | const loc_sh_addr = | ||
| 265 | std.mem.toNative(@TypeOf(loc_sh.addr), loc_sh.addr, target_endian); | ||
| 266 | const loc_sh_offset = | ||
| 267 | std.mem.toNative(@TypeOf(loc_sh.offset), loc_sh.offset, target_endian); | ||
| 268 | const loc_file_offset: usize = @intCast(loc_value - loc_sh_addr + loc_sh_offset); | ||
| 269 | const target_sym = &sym[@intFromEnum(reloc.target)]; | ||
| 270 | const target_value = std.mem.toNative( | ||
| 271 | @TypeOf(target_sym.value), | ||
| 272 | target_sym.value, | ||
| 273 | target_endian, | ||
| 274 | ) +% @as(u64, @bitCast(reloc.addend)); | ||
| 275 | switch (elf.ehdrField(.machine)) { | ||
| 276 | else => |machine| @panic(@tagName(machine)), | ||
| 277 | .X86_64 => switch (reloc.type.x86_64) { | ||
| 278 | else => |kind| @panic(@tagName(kind)), | ||
| 279 | .@"64" => std.mem.writeInt( | ||
| 280 | u64, | ||
| 281 | elf.mf.contents[loc_file_offset..][0..8], | ||
| 282 | target_value, | ||
| 283 | target_endian, | ||
| 284 | ), | ||
| 285 | .PC32 => std.mem.writeInt( | ||
| 286 | i32, | ||
| 287 | elf.mf.contents[loc_file_offset..][0..4], | ||
| 288 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), | ||
| 289 | target_endian, | ||
| 290 | ), | ||
| 291 | .@"32" => std.mem.writeInt( | ||
| 292 | u32, | ||
| 293 | elf.mf.contents[loc_file_offset..][0..4], | ||
| 294 | @intCast(target_value), | ||
| 295 | target_endian, | ||
| 296 | ), | ||
| 297 | .TPOFF32 => { | ||
| 298 | const phdr = @field(elf.phdrSlice(), @tagName(class)); | ||
| 299 | const ph = &phdr[4]; | ||
| 300 | assert(std.mem.toNative( | ||
| 301 | @TypeOf(ph.type), | ||
| 302 | ph.type, | ||
| 303 | target_endian, | ||
| 304 | ) == std.elf.PT_TLS); | ||
| 305 | std.mem.writeInt( | ||
| 306 | i32, | ||
| 307 | elf.mf.contents[loc_file_offset..][0..4], | ||
| 308 | @intCast(@as(i64, @bitCast(target_value -% std.mem.toNative( | ||
| 309 | @TypeOf(ph.memsz), | ||
| 310 | ph.memsz, | ||
| 311 | target_endian, | ||
| 312 | )))), | ||
| 313 | target_endian, | ||
| 314 | ); | ||
| 315 | }, | ||
| 316 | }, | ||
| 317 | } | ||
| 318 | }, | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | pub fn delete(reloc: *Reloc, elf: *Elf) void { | ||
| 323 | switch (reloc.prev) { | ||
| 324 | .none => { | ||
| 325 | const target = reloc.target.get(elf); | ||
| 326 | assert(target.target_relocs.get(elf) == reloc); | ||
| 327 | target.target_relocs = reloc.next; | ||
| 328 | }, | ||
| 329 | else => |prev| prev.get(elf).next = reloc.next, | ||
| 330 | } | ||
| 331 | switch (reloc.next) { | ||
| 332 | .none => {}, | ||
| 333 | else => |next| next.get(elf).prev = reloc.prev, | ||
| 334 | } | ||
| 335 | reloc.* = undefined; | ||
| 336 | } | ||
| 337 | |||
| 338 | comptime { | ||
| 339 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Reloc) == 40); | ||
| 340 | } | ||
| 341 | }; | ||
| 342 | |||
| 343 | pub fn open( | ||
| 344 | arena: std.mem.Allocator, | ||
| 345 | comp: *Compilation, | ||
| 346 | path: std.Build.Cache.Path, | ||
| 347 | options: link.File.OpenOptions, | ||
| 348 | ) !*Elf { | ||
| 349 | return create(arena, comp, path, options); | ||
| 350 | } | ||
| 351 | pub fn createEmpty( | ||
| 352 | arena: std.mem.Allocator, | ||
| 353 | comp: *Compilation, | ||
| 354 | path: std.Build.Cache.Path, | ||
| 355 | options: link.File.OpenOptions, | ||
| 356 | ) !*Elf { | ||
| 357 | return create(arena, comp, path, options); | ||
| 358 | } | ||
| 359 | fn create( | ||
| 360 | arena: std.mem.Allocator, | ||
| 361 | comp: *Compilation, | ||
| 362 | path: std.Build.Cache.Path, | ||
| 363 | options: link.File.OpenOptions, | ||
| 364 | ) !*Elf { | ||
| 365 | _ = options; | ||
| 366 | const target = &comp.root_mod.resolved_target.result; | ||
| 367 | assert(target.ofmt == .elf); | ||
| 368 | const class: std.elf.CLASS = switch (target.ptrBitWidth()) { | ||
| 369 | 0...32 => .@"32", | ||
| 370 | 33...64 => .@"64", | ||
| 371 | else => return error.UnsupportedELFArchitecture, | ||
| 372 | }; | ||
| 373 | const data: std.elf.DATA = switch (target.cpu.arch.endian()) { | ||
| 374 | .little => .@"2LSB", | ||
| 375 | .big => .@"2MSB", | ||
| 376 | }; | ||
| 377 | const osabi: std.elf.OSABI = switch (target.os.tag) { | ||
| 378 | else => .NONE, | ||
| 379 | .freestanding, .other => .STANDALONE, | ||
| 380 | .netbsd => .NETBSD, | ||
| 381 | .solaris => .SOLARIS, | ||
| 382 | .aix => .AIX, | ||
| 383 | .freebsd => .FREEBSD, | ||
| 384 | .cuda => .CUDA, | ||
| 385 | .amdhsa => .AMDGPU_HSA, | ||
| 386 | .amdpal => .AMDGPU_PAL, | ||
| 387 | .mesa3d => .AMDGPU_MESA3D, | ||
| 388 | }; | ||
| 389 | const @"type": std.elf.ET = switch (comp.config.output_mode) { | ||
| 390 | .Exe => if (comp.config.pie or target.os.tag == .haiku) .DYN else .EXEC, | ||
| 391 | .Lib => switch (comp.config.link_mode) { | ||
| 392 | .static => .REL, | ||
| 393 | .dynamic => .DYN, | ||
| 394 | }, | ||
| 395 | .Obj => .REL, | ||
| 396 | }; | ||
| 397 | const machine: std.elf.EM = switch (target.cpu.arch) { | ||
| 398 | .spirv32, .spirv64, .wasm32, .wasm64 => .NONE, | ||
| 399 | .sparc => .SPARC, | ||
| 400 | .x86 => .@"386", | ||
| 401 | .m68k => .@"68K", | ||
| 402 | .mips, .mipsel, .mips64, .mips64el => .MIPS, | ||
| 403 | .powerpc, .powerpcle => .PPC, | ||
| 404 | .powerpc64, .powerpc64le => .PPC64, | ||
| 405 | .s390x => .S390, | ||
| 406 | .arm, .armeb, .thumb, .thumbeb => .ARM, | ||
| 407 | .hexagon => .SH, | ||
| 408 | .sparc64 => .SPARCV9, | ||
| 409 | .arc => .ARC, | ||
| 410 | .x86_64 => .X86_64, | ||
| 411 | .or1k => .OR1K, | ||
| 412 | .xtensa => .XTENSA, | ||
| 413 | .msp430 => .MSP430, | ||
| 414 | .avr => .AVR, | ||
| 415 | .nvptx, .nvptx64 => .CUDA, | ||
| 416 | .kalimba => .CSR_KALIMBA, | ||
| 417 | .aarch64, .aarch64_be => .AARCH64, | ||
| 418 | .xcore => .XCORE, | ||
| 419 | .amdgcn => .AMDGPU, | ||
| 420 | .riscv32, .riscv32be, .riscv64, .riscv64be => .RISCV, | ||
| 421 | .lanai => .LANAI, | ||
| 422 | .bpfel, .bpfeb => .BPF, | ||
| 423 | .ve => .VE, | ||
| 424 | .csky => .CSKY, | ||
| 425 | .loongarch32, .loongarch64 => .LOONGARCH, | ||
| 426 | .propeller => if (target.cpu.has(.propeller, .p2)) .PROPELLER2 else .PROPELLER, | ||
| 427 | }; | ||
| 428 | const maybe_interp = switch (comp.config.output_mode) { | ||
| 429 | .Exe, .Lib => switch (comp.config.link_mode) { | ||
| 430 | .static => null, | ||
| 431 | .dynamic => target.dynamic_linker.get(), | ||
| 432 | }, | ||
| 433 | .Obj => null, | ||
| 434 | }; | ||
| 435 | |||
| 436 | const elf = try arena.create(Elf); | ||
| 437 | const file = try path.root_dir.handle.createFile(path.sub_path, .{ | ||
| 438 | .read = true, | ||
| 439 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), | ||
| 440 | }); | ||
| 441 | errdefer file.close(); | ||
| 442 | elf.* = .{ | ||
| 443 | .base = .{ | ||
| 444 | .tag = .elf2, | ||
| 445 | |||
| 446 | .comp = comp, | ||
| 447 | .emit = path, | ||
| 448 | |||
| 449 | .file = file, | ||
| 450 | .gc_sections = false, | ||
| 451 | .print_gc_sections = false, | ||
| 452 | .build_id = .none, | ||
| 453 | .allow_shlib_undefined = false, | ||
| 454 | .stack_size = 0, | ||
| 455 | }, | ||
| 456 | .mf = try .init(file, comp.gpa), | ||
| 457 | .nodes = .empty, | ||
| 458 | .symtab = .empty, | ||
| 459 | .shstrtab = .{ | ||
| 460 | .map = .empty, | ||
| 461 | .size = 1, | ||
| 462 | }, | ||
| 463 | .strtab = .{ | ||
| 464 | .map = .empty, | ||
| 465 | .size = 1, | ||
| 466 | }, | ||
| 467 | .globals = .empty, | ||
| 468 | .navs = .empty, | ||
| 469 | .uavs = .empty, | ||
| 470 | .lazy = .initFill(.{ | ||
| 471 | .map = .empty, | ||
| 472 | .pending_index = 0, | ||
| 473 | }), | ||
| 474 | .pending_uavs = .empty, | ||
| 475 | .relocs = .empty, | ||
| 476 | .entry_hack = .null, | ||
| 477 | }; | ||
| 478 | errdefer elf.deinit(); | ||
| 479 | |||
| 480 | switch (class) { | ||
| 481 | .NONE, _ => unreachable, | ||
| 482 | inline .@"32", .@"64" => |ct_class| try elf.initHeaders( | ||
| 483 | ct_class, | ||
| 484 | data, | ||
| 485 | osabi, | ||
| 486 | @"type", | ||
| 487 | machine, | ||
| 488 | maybe_interp, | ||
| 489 | ), | ||
| 490 | } | ||
| 491 | |||
| 492 | return elf; | ||
| 493 | } | ||
| 494 | |||
| 495 | pub fn deinit(elf: *Elf) void { | ||
| 496 | const gpa = elf.base.comp.gpa; | ||
| 497 | elf.mf.deinit(gpa); | ||
| 498 | elf.nodes.deinit(gpa); | ||
| 499 | elf.symtab.deinit(gpa); | ||
| 500 | elf.shstrtab.map.deinit(gpa); | ||
| 501 | elf.strtab.map.deinit(gpa); | ||
| 502 | elf.globals.deinit(gpa); | ||
| 503 | elf.navs.deinit(gpa); | ||
| 504 | elf.uavs.deinit(gpa); | ||
| 505 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); | ||
| 506 | elf.pending_uavs.deinit(gpa); | ||
| 507 | elf.relocs.deinit(gpa); | ||
| 508 | elf.* = undefined; | ||
| 509 | } | ||
| 510 | |||
| 511 | fn initHeaders( | ||
| 512 | elf: *Elf, | ||
| 513 | comptime class: std.elf.CLASS, | ||
| 514 | data: std.elf.DATA, | ||
| 515 | osabi: std.elf.OSABI, | ||
| 516 | @"type": std.elf.ET, | ||
| 517 | machine: std.elf.EM, | ||
| 518 | maybe_interp: ?[]const u8, | ||
| 519 | ) !void { | ||
| 520 | const comp = elf.base.comp; | ||
| 521 | const gpa = comp.gpa; | ||
| 522 | const ElfN = switch (class) { | ||
| 523 | .NONE, _ => comptime unreachable, | ||
| 524 | .@"32" => std.elf.Elf32, | ||
| 525 | .@"64" => std.elf.Elf64, | ||
| 526 | }; | ||
| 527 | const addr_align: std.mem.Alignment = comptime .fromByteUnits(@sizeOf(ElfN.Addr)); | ||
| 528 | const target_endian: std.builtin.Endian = switch (data) { | ||
| 529 | .NONE, _ => unreachable, | ||
| 530 | .@"2LSB" => .little, | ||
| 531 | .@"2MSB" => .big, | ||
| 532 | }; | ||
| 533 | |||
| 534 | var phnum: u32 = 0; | ||
| 535 | const phdr_phndx = phnum; | ||
| 536 | phnum += 1; | ||
| 537 | const interp_phndx = if (maybe_interp) |_| phndx: { | ||
| 538 | defer phnum += 1; | ||
| 539 | break :phndx phnum; | ||
| 540 | } else undefined; | ||
| 541 | const rodata_phndx = phnum; | ||
| 542 | phnum += 1; | ||
| 543 | const text_phndx = phnum; | ||
| 544 | phnum += 1; | ||
| 545 | const data_phndx = phnum; | ||
| 546 | phnum += 1; | ||
| 547 | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { | ||
| 548 | defer phnum += 1; | ||
| 549 | break :phndx phnum; | ||
| 550 | } else undefined; | ||
| 551 | |||
| 552 | try elf.nodes.ensureTotalCapacity(gpa, Node.known_count); | ||
| 553 | elf.nodes.appendAssumeCapacity(.file); | ||
| 554 | |||
| 555 | const seg_rodata_ni = Node.known.seg_rodata; | ||
| 556 | assert(seg_rodata_ni == try elf.mf.addOnlyChildNode(gpa, .root, .{ | ||
| 557 | .alignment = elf.mf.flags.block_size, | ||
| 558 | .fixed = true, | ||
| 559 | .moved = true, | ||
| 560 | })); | ||
| 561 | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); | ||
| 562 | |||
| 563 | const ehdr_ni = Node.known.ehdr; | ||
| 564 | assert(ehdr_ni == try elf.mf.addOnlyChildNode(gpa, seg_rodata_ni, .{ | ||
| 565 | .size = @sizeOf(ElfN.Ehdr), | ||
| 566 | .alignment = addr_align, | ||
| 567 | .fixed = true, | ||
| 568 | })); | ||
| 569 | elf.nodes.appendAssumeCapacity(.ehdr); | ||
| 570 | |||
| 571 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(ehdr_ni.slice(&elf.mf))); | ||
| 572 | const EI = std.elf.EI; | ||
| 573 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | ||
| 574 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | ||
| 575 | ehdr.ident[EI.DATA] = @intFromEnum(data); | ||
| 576 | ehdr.ident[EI.VERSION] = 1; | ||
| 577 | ehdr.ident[EI.OSABI] = @intFromEnum(osabi); | ||
| 578 | ehdr.ident[EI.ABIVERSION] = 0; | ||
| 579 | @memset(ehdr.ident[EI.PAD..], 0); | ||
| 580 | ehdr.type = @"type"; | ||
| 581 | ehdr.machine = machine; | ||
| 582 | ehdr.version = 1; | ||
| 583 | ehdr.entry = 0; | ||
| 584 | ehdr.phoff = 0; | ||
| 585 | ehdr.shoff = 0; | ||
| 586 | ehdr.flags = 0; | ||
| 587 | ehdr.ehsize = @sizeOf(ElfN.Ehdr); | ||
| 588 | ehdr.phentsize = @sizeOf(ElfN.Phdr); | ||
| 589 | ehdr.phnum = @min(phnum, std.elf.PN_XNUM); | ||
| 590 | ehdr.shentsize = @sizeOf(ElfN.Shdr); | ||
| 591 | ehdr.shnum = 1; | ||
| 592 | ehdr.shstrndx = 0; | ||
| 593 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | ||
| 594 | |||
| 595 | const phdr_ni = Node.known.phdr; | ||
| 596 | assert(phdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | ||
| 597 | .size = @sizeOf(ElfN.Phdr) * phnum, | ||
| 598 | .alignment = addr_align, | ||
| 599 | .moved = true, | ||
| 600 | .resized = true, | ||
| 601 | })); | ||
| 602 | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); | ||
| 603 | |||
| 604 | const shdr_ni = Node.known.shdr; | ||
| 605 | assert(shdr_ni == try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | ||
| 606 | .size = @sizeOf(ElfN.Shdr), | ||
| 607 | .alignment = addr_align, | ||
| 608 | })); | ||
| 609 | elf.nodes.appendAssumeCapacity(.shdr); | ||
| 610 | |||
| 611 | const seg_text_ni = Node.known.seg_text; | ||
| 612 | assert(seg_text_ni == try elf.mf.addLastChildNode(gpa, .root, .{ | ||
| 613 | .alignment = elf.mf.flags.block_size, | ||
| 614 | .moved = true, | ||
| 615 | })); | ||
| 616 | elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); | ||
| 617 | |||
| 618 | const seg_data_ni = Node.known.seg_data; | ||
| 619 | assert(seg_data_ni == try elf.mf.addLastChildNode(gpa, .root, .{ | ||
| 620 | .alignment = elf.mf.flags.block_size, | ||
| 621 | .moved = true, | ||
| 622 | })); | ||
| 623 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); | ||
| 624 | |||
| 625 | assert(elf.nodes.len == Node.known_count); | ||
| 626 | |||
| 627 | { | ||
| 628 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(phdr_ni.slice(&elf.mf))); | ||
| 629 | const ph_phdr = &phdr[phdr_phndx]; | ||
| 630 | ph_phdr.* = .{ | ||
| 631 | .type = std.elf.PT_PHDR, | ||
| 632 | .offset = 0, | ||
| 633 | .vaddr = 0, | ||
| 634 | .paddr = 0, | ||
| 635 | .filesz = 0, | ||
| 636 | .memsz = 0, | ||
| 637 | .flags = .{ .R = true }, | ||
| 638 | .@"align" = @intCast(phdr_ni.alignment(&elf.mf).toByteUnits()), | ||
| 639 | }; | ||
| 640 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); | ||
| 641 | |||
| 642 | if (maybe_interp) |_| { | ||
| 643 | const ph_interp = &phdr[interp_phndx]; | ||
| 644 | ph_interp.* = .{ | ||
| 645 | .type = std.elf.PT_INTERP, | ||
| 646 | .offset = 0, | ||
| 647 | .vaddr = 0, | ||
| 648 | .paddr = 0, | ||
| 649 | .filesz = 0, | ||
| 650 | .memsz = 0, | ||
| 651 | .flags = .{ .R = true }, | ||
| 652 | .@"align" = 1, | ||
| 653 | }; | ||
| 654 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); | ||
| 655 | } | ||
| 656 | |||
| 657 | const ph_rodata = &phdr[rodata_phndx]; | ||
| 658 | ph_rodata.* = .{ | ||
| 659 | .type = std.elf.PT_NULL, | ||
| 660 | .offset = 0, | ||
| 661 | .vaddr = 0, | ||
| 662 | .paddr = 0, | ||
| 663 | .filesz = 0, | ||
| 664 | .memsz = 0, | ||
| 665 | .flags = .{ .R = true }, | ||
| 666 | .@"align" = @intCast(seg_rodata_ni.alignment(&elf.mf).toByteUnits()), | ||
| 667 | }; | ||
| 668 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); | ||
| 669 | |||
| 670 | const ph_text = &phdr[text_phndx]; | ||
| 671 | ph_text.* = .{ | ||
| 672 | .type = std.elf.PT_NULL, | ||
| 673 | .offset = 0, | ||
| 674 | .vaddr = 0, | ||
| 675 | .paddr = 0, | ||
| 676 | .filesz = 0, | ||
| 677 | .memsz = 0, | ||
| 678 | .flags = .{ .R = true, .X = true }, | ||
| 679 | .@"align" = @intCast(seg_text_ni.alignment(&elf.mf).toByteUnits()), | ||
| 680 | }; | ||
| 681 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); | ||
| 682 | |||
| 683 | const ph_data = &phdr[data_phndx]; | ||
| 684 | ph_data.* = .{ | ||
| 685 | .type = std.elf.PT_NULL, | ||
| 686 | .offset = 0, | ||
| 687 | .vaddr = 0, | ||
| 688 | .paddr = 0, | ||
| 689 | .filesz = 0, | ||
| 690 | .memsz = 0, | ||
| 691 | .flags = .{ .R = true, .W = true }, | ||
| 692 | .@"align" = @intCast(seg_data_ni.alignment(&elf.mf).toByteUnits()), | ||
| 693 | }; | ||
| 694 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); | ||
| 695 | |||
| 696 | if (comp.config.any_non_single_threaded) { | ||
| 697 | const ph_tls = &phdr[tls_phndx]; | ||
| 698 | ph_tls.* = .{ | ||
| 699 | .type = std.elf.PT_TLS, | ||
| 700 | .offset = 0, | ||
| 701 | .vaddr = 0, | ||
| 702 | .paddr = 0, | ||
| 703 | .filesz = 0, | ||
| 704 | .memsz = 0, | ||
| 705 | .flags = .{ .R = true }, | ||
| 706 | .@"align" = @intCast(elf.mf.flags.block_size.toByteUnits()), | ||
| 707 | }; | ||
| 708 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); | ||
| 709 | } | ||
| 710 | |||
| 711 | const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(shdr_ni.slice(&elf.mf))); | ||
| 712 | sh_null.* = .{ | ||
| 713 | .name = try elf.string(.shstrtab, ""), | ||
| 714 | .type = std.elf.SHT_NULL, | ||
| 715 | .flags = .{ .shf = .{} }, | ||
| 716 | .addr = 0, | ||
| 717 | .offset = 0, | ||
| 718 | .size = 0, | ||
| 719 | .link = 0, | ||
| 720 | .info = if (phnum >= std.elf.PN_XNUM) phnum else 0, | ||
| 721 | .addralign = 0, | ||
| 722 | .entsize = 0, | ||
| 723 | }; | ||
| 724 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_null); | ||
| 725 | } | ||
| 726 | |||
| 727 | try elf.symtab.ensureTotalCapacity(gpa, 1); | ||
| 728 | elf.symtab.addOneAssumeCapacity().* = .{ | ||
| 729 | .ni = .none, | ||
| 730 | .loc_relocs = .none, | ||
| 731 | .target_relocs = .none, | ||
| 732 | .unused = 0, | ||
| 733 | }; | ||
| 734 | assert(try elf.addSection(seg_rodata_ni, .{ | ||
| 735 | .type = std.elf.SHT_SYMTAB, | ||
| 736 | .addralign = addr_align, | ||
| 737 | .entsize = @sizeOf(ElfN.Sym), | ||
| 738 | }) == .symtab); | ||
| 739 | const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); | ||
| 740 | symtab.* = .{ | ||
| 741 | .name = try elf.string(.strtab, ""), | ||
| 742 | .value = 0, | ||
| 743 | .size = 0, | ||
| 744 | .info = .{ | ||
| 745 | .type = .NOTYPE, | ||
| 746 | .bind = .LOCAL, | ||
| 747 | }, | ||
| 748 | .other = .{ | ||
| 749 | .visibility = .DEFAULT, | ||
| 750 | }, | ||
| 751 | .shndx = std.elf.SHN_UNDEF, | ||
| 752 | }; | ||
| 753 | ehdr.shstrndx = ehdr.shnum; | ||
| 754 | assert(try elf.addSection(seg_rodata_ni, .{ | ||
| 755 | .type = std.elf.SHT_STRTAB, | ||
| 756 | .addralign = elf.mf.flags.block_size, | ||
| 757 | .entsize = 1, | ||
| 758 | }) == .shstrtab); | ||
| 759 | assert(try elf.addSection(seg_rodata_ni, .{ | ||
| 760 | .type = std.elf.SHT_STRTAB, | ||
| 761 | .addralign = elf.mf.flags.block_size, | ||
| 762 | .entsize = 1, | ||
| 763 | }) == .strtab); | ||
| 764 | try elf.renameSection(.symtab, ".symtab"); | ||
| 765 | try elf.renameSection(.shstrtab, ".shstrtab"); | ||
| 766 | try elf.renameSection(.strtab, ".strtab"); | ||
| 767 | try elf.linkSections(.symtab, .strtab); | ||
| 768 | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; | ||
| 769 | Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; | ||
| 770 | |||
| 771 | assert(try elf.addSection(seg_rodata_ni, .{ | ||
| 772 | .name = ".rodata", | ||
| 773 | .flags = .{ .ALLOC = true }, | ||
| 774 | .addralign = elf.mf.flags.block_size, | ||
| 775 | }) == .rodata); | ||
| 776 | assert(try elf.addSection(seg_text_ni, .{ | ||
| 777 | .name = ".text", | ||
| 778 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | ||
| 779 | .addralign = elf.mf.flags.block_size, | ||
| 780 | }) == .text); | ||
| 781 | assert(try elf.addSection(seg_data_ni, .{ | ||
| 782 | .name = ".data", | ||
| 783 | .flags = .{ .WRITE = true, .ALLOC = true }, | ||
| 784 | .addralign = elf.mf.flags.block_size, | ||
| 785 | }) == .data); | ||
| 786 | if (comp.config.any_non_single_threaded) { | ||
| 787 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 788 | const seg_tls_ni = try elf.mf.addLastChildNode(gpa, seg_data_ni, .{ | ||
| 789 | .alignment = elf.mf.flags.block_size, | ||
| 790 | .moved = true, | ||
| 791 | }); | ||
| 792 | elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); | ||
| 793 | |||
| 794 | assert(try elf.addSection(seg_tls_ni, .{ | ||
| 795 | .name = ".tdata", | ||
| 796 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, | ||
| 797 | .addralign = elf.mf.flags.block_size, | ||
| 798 | }) == .tdata); | ||
| 799 | } | ||
| 800 | if (maybe_interp) |interp| { | ||
| 801 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 802 | const seg_interp_ni = try elf.mf.addLastChildNode(gpa, seg_rodata_ni, .{ | ||
| 803 | .size = interp.len + 1, | ||
| 804 | .moved = true, | ||
| 805 | .resized = true, | ||
| 806 | }); | ||
| 807 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); | ||
| 808 | |||
| 809 | const sec_interp_si = try elf.addSection(seg_interp_ni, .{ | ||
| 810 | .name = ".interp", | ||
| 811 | .size = @intCast(interp.len + 1), | ||
| 812 | .flags = .{ .ALLOC = true }, | ||
| 813 | }); | ||
| 814 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); | ||
| 815 | @memcpy(sec_interp[0..interp.len], interp); | ||
| 816 | sec_interp[interp.len] = 0; | ||
| 817 | } | ||
| 818 | } | ||
| 819 | |||
| 820 | fn getNode(elf: *Elf, ni: MappedFile.Node.Index) Node { | ||
| 821 | return elf.nodes.get(@intFromEnum(ni)); | ||
| 822 | } | ||
| 823 | |||
| 824 | pub const EhdrPtr = union(std.elf.CLASS) { | ||
| 825 | NONE: noreturn, | ||
| 826 | @"32": *std.elf.Elf32.Ehdr, | ||
| 827 | @"64": *std.elf.Elf64.Ehdr, | ||
| 828 | }; | ||
| 829 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { | ||
| 830 | const slice = Node.known.ehdr.slice(&elf.mf); | ||
| 831 | return switch (elf.identClass()) { | ||
| 832 | .NONE, _ => unreachable, | ||
| 833 | inline .@"32", .@"64" => |class| @unionInit( | ||
| 834 | EhdrPtr, | ||
| 835 | @tagName(class), | ||
| 836 | @ptrCast(@alignCast(slice)), | ||
| 837 | ), | ||
| 838 | }; | ||
| 839 | } | ||
| 840 | pub fn ehdrField( | ||
| 841 | elf: *Elf, | ||
| 842 | comptime field: enum { type, machine }, | ||
| 843 | ) @FieldType(std.elf.Elf32.Ehdr, @tagName(field)) { | ||
| 844 | const Field = @FieldType(std.elf.Elf32.Ehdr, @tagName(field)); | ||
| 845 | comptime assert(@FieldType(std.elf.Elf64.Ehdr, @tagName(field)) == Field); | ||
| 846 | return @enumFromInt(std.mem.toNative( | ||
| 847 | @typeInfo(Field).@"enum".tag_type, | ||
| 848 | @intFromEnum(switch (elf.ehdrPtr()) { | ||
| 849 | inline else => |ehdr| @field(ehdr, @tagName(field)), | ||
| 850 | }), | ||
| 851 | elf.endian(), | ||
| 852 | )); | ||
| 853 | } | ||
| 854 | |||
| 855 | pub fn identClass(elf: *Elf) std.elf.CLASS { | ||
| 856 | return @enumFromInt(elf.mf.contents[std.elf.EI.CLASS]); | ||
| 857 | } | ||
| 858 | |||
| 859 | pub fn identData(elf: *Elf) std.elf.DATA { | ||
| 860 | return @enumFromInt(elf.mf.contents[std.elf.EI.DATA]); | ||
| 861 | } | ||
| 862 | fn endianForData(data: std.elf.DATA) std.builtin.Endian { | ||
| 863 | return switch (data) { | ||
| 864 | .NONE, _ => unreachable, | ||
| 865 | .@"2LSB" => .little, | ||
| 866 | .@"2MSB" => .big, | ||
| 867 | }; | ||
| 868 | } | ||
| 869 | pub fn endian(elf: *Elf) std.builtin.Endian { | ||
| 870 | return endianForData(elf.identData()); | ||
| 871 | } | ||
| 872 | |||
| 873 | fn baseAddrForType(@"type": std.elf.ET) u64 { | ||
| 874 | return switch (@"type") { | ||
| 875 | else => 0, | ||
| 876 | .EXEC => 0x1000000, | ||
| 877 | }; | ||
| 878 | } | ||
| 879 | pub fn baseAddr(elf: *Elf) u64 { | ||
| 880 | return baseAddrForType(elf.ehdrField(.type)); | ||
| 881 | } | ||
| 882 | |||
| 883 | pub const PhdrSlice = union(std.elf.CLASS) { | ||
| 884 | NONE: noreturn, | ||
| 885 | @"32": []std.elf.Elf32.Phdr, | ||
| 886 | @"64": []std.elf.Elf64.Phdr, | ||
| 887 | }; | ||
| 888 | pub fn phdrSlice(elf: *Elf) PhdrSlice { | ||
| 889 | const slice = Node.known.phdr.slice(&elf.mf); | ||
| 890 | return switch (elf.identClass()) { | ||
| 891 | .NONE, _ => unreachable, | ||
| 892 | inline .@"32", .@"64" => |class| @unionInit( | ||
| 893 | PhdrSlice, | ||
| 894 | @tagName(class), | ||
| 895 | @ptrCast(@alignCast(slice)), | ||
| 896 | ), | ||
| 897 | }; | ||
| 898 | } | ||
| 899 | |||
| 900 | pub const ShdrSlice = union(std.elf.CLASS) { | ||
| 901 | NONE: noreturn, | ||
| 902 | @"32": []std.elf.Elf32.Shdr, | ||
| 903 | @"64": []std.elf.Elf64.Shdr, | ||
| 904 | }; | ||
| 905 | pub fn shdrSlice(elf: *Elf) ShdrSlice { | ||
| 906 | const slice = Node.known.shdr.slice(&elf.mf); | ||
| 907 | return switch (elf.identClass()) { | ||
| 908 | .NONE, _ => unreachable, | ||
| 909 | inline .@"32", .@"64" => |class| @unionInit( | ||
| 910 | ShdrSlice, | ||
| 911 | @tagName(class), | ||
| 912 | @ptrCast(@alignCast(slice)), | ||
| 913 | ), | ||
| 914 | }; | ||
| 915 | } | ||
| 916 | |||
| 917 | pub const SymSlice = union(std.elf.CLASS) { | ||
| 918 | NONE: noreturn, | ||
| 919 | @"32": []std.elf.Elf32.Sym, | ||
| 920 | @"64": []std.elf.Elf64.Sym, | ||
| 921 | }; | ||
| 922 | pub fn symSlice(elf: *Elf) SymSlice { | ||
| 923 | const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); | ||
| 924 | return switch (elf.identClass()) { | ||
| 925 | .NONE, _ => unreachable, | ||
| 926 | inline .@"32", .@"64" => |class| @unionInit( | ||
| 927 | SymSlice, | ||
| 928 | @tagName(class), | ||
| 929 | @ptrCast(@alignCast(slice)), | ||
| 930 | ), | ||
| 931 | }; | ||
| 932 | } | ||
| 933 | |||
| 934 | pub const SymPtr = union(std.elf.CLASS) { | ||
| 935 | NONE: noreturn, | ||
| 936 | @"32": *std.elf.Elf32.Sym, | ||
| 937 | @"64": *std.elf.Elf64.Sym, | ||
| 938 | }; | ||
| 939 | pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { | ||
| 940 | return switch (elf.symSlice()) { | ||
| 941 | inline else => |sym, class| @unionInit(SymPtr, @tagName(class), &sym[@intFromEnum(si)]), | ||
| 942 | }; | ||
| 943 | } | ||
| 944 | |||
| 945 | fn addSymbolAssumeCapacity(elf: *Elf) !Symbol.Index { | ||
| 946 | defer elf.symtab.addOneAssumeCapacity().* = .{ | ||
| 947 | .ni = .none, | ||
| 948 | .loc_relocs = .none, | ||
| 949 | .target_relocs = .none, | ||
| 950 | .unused = 0, | ||
| 951 | }; | ||
| 952 | return @enumFromInt(elf.symtab.items.len); | ||
| 953 | } | ||
| 954 | |||
| 955 | fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.Index { | ||
| 956 | const si = try elf.addSymbolAssumeCapacity(); | ||
| 957 | try si.init(elf, opts); | ||
| 958 | return si; | ||
| 959 | } | ||
| 960 | |||
| 961 | pub fn globalSymbol( | ||
| 962 | elf: *Elf, | ||
| 963 | opts: struct { | ||
| 964 | name: []const u8, | ||
| 965 | type: std.elf.STT, | ||
| 966 | bind: std.elf.STB = .GLOBAL, | ||
| 967 | visibility: std.elf.STV = .DEFAULT, | ||
| 968 | }, | ||
| 969 | ) !Symbol.Index { | ||
| 970 | const gpa = elf.base.comp.gpa; | ||
| 971 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | ||
| 972 | const sym_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); | ||
| 973 | if (!sym_gop.found_existing) sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | ||
| 974 | .name = opts.name, | ||
| 975 | .type = opts.type, | ||
| 976 | .bind = opts.bind, | ||
| 977 | .visibility = opts.visibility, | ||
| 978 | }); | ||
| 979 | return sym_gop.value_ptr.*; | ||
| 980 | } | ||
| 981 | |||
| 982 | fn navType( | ||
| 983 | ip: *const InternPool, | ||
| 984 | nav_status: @FieldType(InternPool.Nav, "status"), | ||
| 985 | any_non_single_threaded: bool, | ||
| 986 | ) std.elf.STT { | ||
| 987 | return switch (nav_status) { | ||
| 988 | .unresolved => unreachable, | ||
| 989 | .type_resolved => |tr| if (any_non_single_threaded and tr.is_threadlocal) | ||
| 990 | .TLS | ||
| 991 | else if (ip.isFunctionType(tr.type)) | ||
| 992 | .FUNC | ||
| 993 | else | ||
| 994 | .OBJECT, | ||
| 995 | .fully_resolved => |fr| switch (ip.indexToKey(fr.val)) { | ||
| 996 | else => .OBJECT, | ||
| 997 | .variable => |variable| if (any_non_single_threaded and variable.is_threadlocal) | ||
| 998 | .TLS | ||
| 999 | else | ||
| 1000 | .OBJECT, | ||
| 1001 | .@"extern" => |@"extern"| if (any_non_single_threaded and @"extern".is_threadlocal) | ||
| 1002 | .TLS | ||
| 1003 | else if (ip.isFunctionType(@"extern".ty)) | ||
| 1004 | .FUNC | ||
| 1005 | else | ||
| 1006 | .OBJECT, | ||
| 1007 | .func => .FUNC, | ||
| 1008 | }, | ||
| 1009 | }; | ||
| 1010 | } | ||
| 1011 | pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { | ||
| 1012 | const gpa = zcu.gpa; | ||
| 1013 | const ip = &zcu.intern_pool; | ||
| 1014 | const nav = ip.getNav(nav_index); | ||
| 1015 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ | ||
| 1016 | .name = @"extern".name.toSlice(ip), | ||
| 1017 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), | ||
| 1018 | .bind = switch (@"extern".linkage) { | ||
| 1019 | .internal => .LOCAL, | ||
| 1020 | .strong => .GLOBAL, | ||
| 1021 | .weak => .WEAK, | ||
| 1022 | .link_once => return error.LinkOnceUnsupported, | ||
| 1023 | }, | ||
| 1024 | .visibility = switch (@"extern".visibility) { | ||
| 1025 | .default => .DEFAULT, | ||
| 1026 | .hidden => .HIDDEN, | ||
| 1027 | .protected => .PROTECTED, | ||
| 1028 | }, | ||
| 1029 | }); | ||
| 1030 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | ||
| 1031 | const sym_gop = try elf.navs.getOrPut(gpa, nav_index); | ||
| 1032 | if (!sym_gop.found_existing) { | ||
| 1033 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | ||
| 1034 | .name = nav.fqn.toSlice(ip), | ||
| 1035 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), | ||
| 1036 | }); | ||
| 1037 | } | ||
| 1038 | return sym_gop.value_ptr.*; | ||
| 1039 | } | ||
| 1040 | |||
| 1041 | pub fn uavSymbol(elf: *Elf, uav_val: InternPool.Index) !Symbol.Index { | ||
| 1042 | const gpa = elf.base.comp.gpa; | ||
| 1043 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | ||
| 1044 | const sym_gop = try elf.uavs.getOrPut(gpa, uav_val); | ||
| 1045 | if (!sym_gop.found_existing) | ||
| 1046 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ .type = .OBJECT }); | ||
| 1047 | return sym_gop.value_ptr.*; | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { | ||
| 1051 | const gpa = elf.base.comp.gpa; | ||
| 1052 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | ||
| 1053 | const sym_gop = try elf.lazy.getPtr(lazy.kind).map.getOrPut(gpa, lazy.ty); | ||
| 1054 | if (!sym_gop.found_existing) { | ||
| 1055 | sym_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | ||
| 1056 | .type = switch (lazy.kind) { | ||
| 1057 | .code => .FUNC, | ||
| 1058 | .const_data => .OBJECT, | ||
| 1059 | }, | ||
| 1060 | }); | ||
| 1061 | elf.base.comp.link_lazy_prog_node.increaseEstimatedTotalItems(1); | ||
| 1062 | } | ||
| 1063 | return sym_gop.value_ptr.*; | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | pub fn getNavVAddr( | ||
| 1067 | elf: *Elf, | ||
| 1068 | pt: Zcu.PerThread, | ||
| 1069 | nav: InternPool.Nav.Index, | ||
| 1070 | reloc_info: link.File.RelocInfo, | ||
| 1071 | ) !u64 { | ||
| 1072 | return elf.getVAddr(reloc_info, try elf.navSymbol(pt.zcu, nav)); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | pub fn getUavVAddr( | ||
| 1076 | elf: *Elf, | ||
| 1077 | uav: InternPool.Index, | ||
| 1078 | reloc_info: link.File.RelocInfo, | ||
| 1079 | ) !u64 { | ||
| 1080 | return elf.getVAddr(reloc_info, try elf.uavSymbol(uav)); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.Index) !u64 { | ||
| 1084 | try elf.addReloc( | ||
| 1085 | @enumFromInt(reloc_info.parent.atom_index), | ||
| 1086 | reloc_info.offset, | ||
| 1087 | target_si, | ||
| 1088 | reloc_info.addend, | ||
| 1089 | switch (elf.ehdrField(.machine)) { | ||
| 1090 | else => unreachable, | ||
| 1091 | .X86_64 => .{ .x86_64 = switch (elf.identClass()) { | ||
| 1092 | .NONE, _ => unreachable, | ||
| 1093 | .@"32" => .@"32", | ||
| 1094 | .@"64" => .@"64", | ||
| 1095 | } }, | ||
| 1096 | }, | ||
| 1097 | ); | ||
| 1098 | return 0; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ||
| 1102 | name: []const u8 = "", | ||
| 1103 | type: std.elf.Word = std.elf.SHT_NULL, | ||
| 1104 | size: std.elf.Word = 0, | ||
| 1105 | flags: std.elf.SHF = .{}, | ||
| 1106 | addralign: std.mem.Alignment = .@"1", | ||
| 1107 | entsize: std.elf.Word = 0, | ||
| 1108 | }) !Symbol.Index { | ||
| 1109 | const gpa = elf.base.comp.gpa; | ||
| 1110 | const target_endian = elf.endian(); | ||
| 1111 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1112 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | ||
| 1113 | |||
| 1114 | const shstrtab_entry = try elf.string(.shstrtab, opts.name); | ||
| 1115 | const shndx, const shdr_size = shndx: switch (elf.ehdrPtr()) { | ||
| 1116 | inline else => |ehdr| { | ||
| 1117 | const shentsize = std.mem.toNative(@TypeOf(ehdr.shentsize), ehdr.shentsize, target_endian); | ||
| 1118 | const shndx = std.mem.toNative(@TypeOf(ehdr.shnum), ehdr.shnum, target_endian); | ||
| 1119 | const shnum = shndx + 1; | ||
| 1120 | ehdr.shnum = std.mem.nativeTo(@TypeOf(ehdr.shnum), shnum, target_endian); | ||
| 1121 | break :shndx .{ shndx, shentsize * shnum }; | ||
| 1122 | }, | ||
| 1123 | }; | ||
| 1124 | try Node.known.shdr.resize(&elf.mf, gpa, shdr_size); | ||
| 1125 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ | ||
| 1126 | .alignment = opts.addralign, | ||
| 1127 | .size = opts.size, | ||
| 1128 | .moved = true, | ||
| 1129 | }); | ||
| 1130 | const si = try elf.addSymbolAssumeCapacity(); | ||
| 1131 | elf.nodes.appendAssumeCapacity(.{ .section = si }); | ||
| 1132 | si.get(elf).ni = ni; | ||
| 1133 | try si.init(elf, .{ | ||
| 1134 | .name = opts.name, | ||
| 1135 | .size = opts.size, | ||
| 1136 | .type = .SECTION, | ||
| 1137 | .shndx = shndx, | ||
| 1138 | }); | ||
| 1139 | switch (elf.shdrSlice()) { | ||
| 1140 | inline else => |shdr| { | ||
| 1141 | const sh = &shdr[shndx]; | ||
| 1142 | sh.* = .{ | ||
| 1143 | .name = shstrtab_entry, | ||
| 1144 | .type = opts.type, | ||
| 1145 | .flags = .{ .shf = opts.flags }, | ||
| 1146 | .addr = 0, | ||
| 1147 | .offset = 0, | ||
| 1148 | .size = opts.size, | ||
| 1149 | .link = 0, | ||
| 1150 | .info = 0, | ||
| 1151 | .addralign = @intCast(opts.addralign.toByteUnits()), | ||
| 1152 | .entsize = opts.entsize, | ||
| 1153 | }; | ||
| 1154 | if (target_endian != native_endian) std.mem.byteSwapAllFields(@TypeOf(sh.*), sh); | ||
| 1155 | }, | ||
| 1156 | } | ||
| 1157 | return si; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { | ||
| 1161 | const strtab_entry = try elf.string(.strtab, name); | ||
| 1162 | const shstrtab_entry = try elf.string(.shstrtab, name); | ||
| 1163 | const target_endian = elf.endian(); | ||
| 1164 | switch (elf.shdrSlice()) { | ||
| 1165 | inline else => |shdr, class| { | ||
| 1166 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1167 | sym.name = std.mem.nativeTo(@TypeOf(sym.name), strtab_entry, target_endian); | ||
| 1168 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | ||
| 1169 | const sh = &shdr[shndx]; | ||
| 1170 | sh.name = std.mem.nativeTo(@TypeOf(sh.name), shstrtab_entry, target_endian); | ||
| 1171 | }, | ||
| 1172 | } | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { | ||
| 1176 | const target_endian = elf.endian(); | ||
| 1177 | switch (elf.shdrSlice()) { | ||
| 1178 | inline else => |shdr, class| { | ||
| 1179 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1180 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | ||
| 1181 | shdr[shndx].link = @field(elf.symPtr(link_si), @tagName(class)).shndx; | ||
| 1182 | }, | ||
| 1183 | } | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { | ||
| 1187 | const target_endian = elf.endian(); | ||
| 1188 | const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[name: switch (elf.shdrSlice()) { | ||
| 1189 | inline else => |shndx, class| { | ||
| 1190 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1191 | const sh = &shndx[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; | ||
| 1192 | break :name std.mem.toNative(@TypeOf(sh.name), sh.name, target_endian); | ||
| 1193 | }, | ||
| 1194 | }..]; | ||
| 1195 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 { | ||
| 1199 | if (key.len == 0) return 0; | ||
| 1200 | return @field(elf, @tagName(section)).get( | ||
| 1201 | elf.base.comp.gpa, | ||
| 1202 | &elf.mf, | ||
| 1203 | @field(Symbol.Index, @tagName(section)).node(elf), | ||
| 1204 | key, | ||
| 1205 | ); | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | pub fn addReloc( | ||
| 1209 | elf: *Elf, | ||
| 1210 | loc_si: Symbol.Index, | ||
| 1211 | offset: u64, | ||
| 1212 | target_si: Symbol.Index, | ||
| 1213 | addend: i64, | ||
| 1214 | @"type": Reloc.Type, | ||
| 1215 | ) !void { | ||
| 1216 | const gpa = elf.base.comp.gpa; | ||
| 1217 | const target = target_si.get(elf); | ||
| 1218 | const ri: link.File.Elf2.Reloc.Index = @enumFromInt(elf.relocs.items.len); | ||
| 1219 | (try elf.relocs.addOne(gpa)).* = .{ | ||
| 1220 | .type = @"type", | ||
| 1221 | .prev = .none, | ||
| 1222 | .next = target.target_relocs, | ||
| 1223 | .loc = loc_si, | ||
| 1224 | .target = target_si, | ||
| 1225 | .unused = 0, | ||
| 1226 | .offset = offset, | ||
| 1227 | .addend = addend, | ||
| 1228 | }; | ||
| 1229 | switch (target.target_relocs) { | ||
| 1230 | .none => {}, | ||
| 1231 | else => |target_ri| target_ri.get(elf).prev = ri, | ||
| 1232 | } | ||
| 1233 | target.target_relocs = ri; | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void { | ||
| 1237 | _ = elf; | ||
| 1238 | _ = prog_node; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1242 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { | ||
| 1243 | error.OutOfMemory, | ||
| 1244 | error.Overflow, | ||
| 1245 | error.RelocationNotByteAligned, | ||
| 1246 | => |e| return e, | ||
| 1247 | else => |e| return elf.base.cgFail(nav_index, "linker failed to update variable: {t}", .{e}), | ||
| 1248 | }; | ||
| 1249 | } | ||
| 1250 | fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | ||
| 1251 | const comp = elf.base.comp; | ||
| 1252 | const zcu = pt.zcu; | ||
| 1253 | const gpa = zcu.gpa; | ||
| 1254 | const ip = &zcu.intern_pool; | ||
| 1255 | |||
| 1256 | const nav = ip.getNav(nav_index); | ||
| 1257 | const nav_val = nav.status.fully_resolved.val; | ||
| 1258 | const nav_init, const is_threadlocal = switch (ip.indexToKey(nav_val)) { | ||
| 1259 | else => .{ nav_val, false }, | ||
| 1260 | .variable => |variable| .{ variable.init, variable.is_threadlocal }, | ||
| 1261 | .@"extern" => return, | ||
| 1262 | .func => .{ .none, false }, | ||
| 1263 | }; | ||
| 1264 | if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return; | ||
| 1265 | |||
| 1266 | const si = try elf.navSymbol(zcu, nav_index); | ||
| 1267 | const ni = ni: { | ||
| 1268 | const sym = si.get(elf); | ||
| 1269 | switch (sym.ni) { | ||
| 1270 | .none => { | ||
| 1271 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1272 | const sec_si: Symbol.Index = | ||
| 1273 | if (is_threadlocal and comp.config.any_non_single_threaded) .tdata else .data; | ||
| 1274 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ | ||
| 1275 | .alignment = pt.navAlignment(nav_index).toStdMem(), | ||
| 1276 | .moved = true, | ||
| 1277 | }); | ||
| 1278 | elf.nodes.appendAssumeCapacity(.{ .nav = nav_index }); | ||
| 1279 | sym.ni = ni; | ||
| 1280 | switch (elf.symPtr(si)) { | ||
| 1281 | inline else => |sym_ptr, class| sym_ptr.shndx = | ||
| 1282 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | ||
| 1283 | } | ||
| 1284 | }, | ||
| 1285 | else => si.deleteLocationRelocs(elf), | ||
| 1286 | } | ||
| 1287 | assert(sym.loc_relocs == .none); | ||
| 1288 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | ||
| 1289 | break :ni sym.ni; | ||
| 1290 | }; | ||
| 1291 | |||
| 1292 | const size = size: { | ||
| 1293 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1294 | ni.writer(&elf.mf, gpa, &nw); | ||
| 1295 | defer nw.deinit(); | ||
| 1296 | codegen.generateSymbol( | ||
| 1297 | &elf.base, | ||
| 1298 | pt, | ||
| 1299 | zcu.navSrcLoc(nav_index), | ||
| 1300 | .fromInterned(nav_init), | ||
| 1301 | &nw.interface, | ||
| 1302 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1303 | ) catch |err| switch (err) { | ||
| 1304 | error.WriteFailed => return error.OutOfMemory, | ||
| 1305 | else => |e| return e, | ||
| 1306 | }; | ||
| 1307 | break :size nw.interface.end; | ||
| 1308 | }; | ||
| 1309 | |||
| 1310 | const target_endian = elf.endian(); | ||
| 1311 | switch (elf.symPtr(si)) { | ||
| 1312 | inline else => |sym| sym.size = | ||
| 1313 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | ||
| 1314 | } | ||
| 1315 | si.applyLocationRelocs(elf); | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | pub fn lowerUav( | ||
| 1319 | elf: *Elf, | ||
| 1320 | pt: Zcu.PerThread, | ||
| 1321 | uav_val: InternPool.Index, | ||
| 1322 | uav_align: InternPool.Alignment, | ||
| 1323 | src_loc: Zcu.LazySrcLoc, | ||
| 1324 | ) !codegen.SymbolResult { | ||
| 1325 | const zcu = pt.zcu; | ||
| 1326 | const gpa = zcu.gpa; | ||
| 1327 | |||
| 1328 | try elf.pending_uavs.ensureUnusedCapacity(gpa, 1); | ||
| 1329 | const si = elf.uavSymbol(uav_val) catch |err| switch (err) { | ||
| 1330 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1331 | else => |e| return .{ .fail = try Zcu.ErrorMsg.create( | ||
| 1332 | gpa, | ||
| 1333 | src_loc, | ||
| 1334 | "linker failed to update constant: {s}", | ||
| 1335 | .{@errorName(e)}, | ||
| 1336 | ) }, | ||
| 1337 | }; | ||
| 1338 | if (switch (si.get(elf).ni) { | ||
| 1339 | .none => true, | ||
| 1340 | else => |ni| uav_align.toStdMem().order(ni.alignment(&elf.mf)).compare(.gt), | ||
| 1341 | }) { | ||
| 1342 | const gop = elf.pending_uavs.getOrPutAssumeCapacity(uav_val); | ||
| 1343 | if (gop.found_existing) { | ||
| 1344 | gop.value_ptr.alignment = gop.value_ptr.alignment.max(uav_align); | ||
| 1345 | } else { | ||
| 1346 | gop.value_ptr.* = .{ | ||
| 1347 | .alignment = uav_align, | ||
| 1348 | .src_loc = src_loc, | ||
| 1349 | }; | ||
| 1350 | elf.base.comp.link_uav_prog_node.increaseEstimatedTotalItems(1); | ||
| 1351 | } | ||
| 1352 | } | ||
| 1353 | return .{ .sym_index = @intFromEnum(si) }; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | pub fn updateFunc( | ||
| 1357 | elf: *Elf, | ||
| 1358 | pt: Zcu.PerThread, | ||
| 1359 | func_index: InternPool.Index, | ||
| 1360 | mir: *const codegen.AnyMir, | ||
| 1361 | ) !void { | ||
| 1362 | elf.updateFuncInner(pt, func_index, mir) catch |err| switch (err) { | ||
| 1363 | error.OutOfMemory, | ||
| 1364 | error.Overflow, | ||
| 1365 | error.RelocationNotByteAligned, | ||
| 1366 | error.CodegenFail, | ||
| 1367 | => |e| return e, | ||
| 1368 | else => |e| return elf.base.cgFail( | ||
| 1369 | pt.zcu.funcInfo(func_index).owner_nav, | ||
| 1370 | "linker failed to update function: {s}", | ||
| 1371 | .{@errorName(e)}, | ||
| 1372 | ), | ||
| 1373 | }; | ||
| 1374 | } | ||
| 1375 | fn updateFuncInner( | ||
| 1376 | elf: *Elf, | ||
| 1377 | pt: Zcu.PerThread, | ||
| 1378 | func_index: InternPool.Index, | ||
| 1379 | mir: *const codegen.AnyMir, | ||
| 1380 | ) !void { | ||
| 1381 | const zcu = pt.zcu; | ||
| 1382 | const gpa = zcu.gpa; | ||
| 1383 | const ip = &zcu.intern_pool; | ||
| 1384 | const func = zcu.funcInfo(func_index); | ||
| 1385 | const nav = ip.getNav(func.owner_nav); | ||
| 1386 | |||
| 1387 | const si = try elf.navSymbol(zcu, func.owner_nav); | ||
| 1388 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), si }); | ||
| 1389 | const ni = ni: { | ||
| 1390 | const sym = si.get(elf); | ||
| 1391 | switch (sym.ni) { | ||
| 1392 | .none => { | ||
| 1393 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1394 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | ||
| 1395 | const target = &mod.resolved_target.result; | ||
| 1396 | const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.text.node(elf), .{ | ||
| 1397 | .alignment = switch (nav.status.fully_resolved.alignment) { | ||
| 1398 | .none => switch (mod.optimize_mode) { | ||
| 1399 | .Debug, | ||
| 1400 | .ReleaseSafe, | ||
| 1401 | .ReleaseFast, | ||
| 1402 | => target_util.defaultFunctionAlignment(target), | ||
| 1403 | .ReleaseSmall => target_util.minFunctionAlignment(target), | ||
| 1404 | }, | ||
| 1405 | else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), | ||
| 1406 | }.toStdMem(), | ||
| 1407 | .moved = true, | ||
| 1408 | }); | ||
| 1409 | elf.nodes.appendAssumeCapacity(.{ .nav = func.owner_nav }); | ||
| 1410 | sym.ni = ni; | ||
| 1411 | switch (elf.symPtr(si)) { | ||
| 1412 | inline else => |sym_ptr, class| sym_ptr.shndx = | ||
| 1413 | @field(elf.symPtr(.text), @tagName(class)).shndx, | ||
| 1414 | } | ||
| 1415 | }, | ||
| 1416 | else => si.deleteLocationRelocs(elf), | ||
| 1417 | } | ||
| 1418 | assert(sym.loc_relocs == .none); | ||
| 1419 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | ||
| 1420 | break :ni sym.ni; | ||
| 1421 | }; | ||
| 1422 | |||
| 1423 | const size = size: { | ||
| 1424 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1425 | ni.writer(&elf.mf, gpa, &nw); | ||
| 1426 | defer nw.deinit(); | ||
| 1427 | codegen.emitFunction( | ||
| 1428 | &elf.base, | ||
| 1429 | pt, | ||
| 1430 | zcu.navSrcLoc(func.owner_nav), | ||
| 1431 | func_index, | ||
| 1432 | @intFromEnum(si), | ||
| 1433 | mir, | ||
| 1434 | &nw.interface, | ||
| 1435 | .none, | ||
| 1436 | ) catch |err| switch (err) { | ||
| 1437 | error.WriteFailed => return nw.err.?, | ||
| 1438 | else => |e| return e, | ||
| 1439 | }; | ||
| 1440 | break :size nw.interface.end; | ||
| 1441 | }; | ||
| 1442 | |||
| 1443 | const target_endian = elf.endian(); | ||
| 1444 | switch (elf.symPtr(si)) { | ||
| 1445 | inline else => |sym| sym.size = | ||
| 1446 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | ||
| 1447 | } | ||
| 1448 | si.applyLocationRelocs(elf); | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { | ||
| 1452 | const si = elf.lazy.getPtr(.const_data).map.get(.anyerror_type) orelse return; | ||
| 1453 | elf.flushLazy(pt, .{ .kind = .const_data, .ty = .anyerror_type }, si) catch |err| switch (err) { | ||
| 1454 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1455 | error.CodegenFail => return error.LinkFailure, | ||
| 1456 | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), | ||
| 1457 | }; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | pub fn flush( | ||
| 1461 | elf: *Elf, | ||
| 1462 | arena: std.mem.Allocator, | ||
| 1463 | tid: Zcu.PerThread.Id, | ||
| 1464 | prog_node: std.Progress.Node, | ||
| 1465 | ) !void { | ||
| 1466 | _ = arena; | ||
| 1467 | _ = prog_node; | ||
| 1468 | while (try elf.idle(tid)) {} | ||
| 1469 | } | ||
| 1470 | |||
| 1471 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ||
| 1472 | const comp = elf.base.comp; | ||
| 1473 | task: { | ||
| 1474 | while (elf.pending_uavs.pop()) |pending_uav| { | ||
| 1475 | const sub_prog_node = | ||
| 1476 | elf.idleProgNode( | ||
| 1477 | tid, | ||
| 1478 | comp.link_uav_prog_node, | ||
| 1479 | .{ .uav = pending_uav.key }, | ||
| 1480 | ); | ||
| 1481 | defer sub_prog_node.end(); | ||
| 1482 | break :task elf.flushUav( | ||
| 1483 | .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, | ||
| 1484 | pending_uav.key, | ||
| 1485 | pending_uav.value.alignment, | ||
| 1486 | pending_uav.value.src_loc, | ||
| 1487 | ) catch |err| switch (err) { | ||
| 1488 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1489 | else => |e| return elf.base.comp.link_diags.fail( | ||
| 1490 | "linker failed to lower constant: {t}", | ||
| 1491 | .{e}, | ||
| 1492 | ), | ||
| 1493 | }; | ||
| 1494 | } | ||
| 1495 | var lazy_it = elf.lazy.iterator(); | ||
| 1496 | while (lazy_it.next()) |lazy| for ( | ||
| 1497 | lazy.value.map.keys()[lazy.value.pending_index..], | ||
| 1498 | lazy.value.map.values()[lazy.value.pending_index..], | ||
| 1499 | ) |ty, si| { | ||
| 1500 | lazy.value.pending_index += 1; | ||
| 1501 | const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; | ||
| 1502 | const kind = switch (lazy.key) { | ||
| 1503 | .code => "code", | ||
| 1504 | .const_data => "data", | ||
| 1505 | }; | ||
| 1506 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1507 | const sub_prog_node = comp.link_lazy_prog_node.start( | ||
| 1508 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | ||
| 1509 | kind, | ||
| 1510 | Type.fromInterned(ty).fmt(pt), | ||
| 1511 | }) catch &name, | ||
| 1512 | 0, | ||
| 1513 | ); | ||
| 1514 | defer sub_prog_node.end(); | ||
| 1515 | break :task elf.flushLazy(pt, .{ | ||
| 1516 | .kind = lazy.key, | ||
| 1517 | .ty = ty, | ||
| 1518 | }, si) catch |err| switch (err) { | ||
| 1519 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1520 | else => |e| return elf.base.comp.link_diags.fail( | ||
| 1521 | "linker failed to lower lazy {s}: {t}", | ||
| 1522 | .{ kind, e }, | ||
| 1523 | ), | ||
| 1524 | }; | ||
| 1525 | }; | ||
| 1526 | while (elf.mf.updates.pop()) |ni| { | ||
| 1527 | const clean_moved = ni.cleanMoved(&elf.mf); | ||
| 1528 | const clean_resized = ni.cleanResized(&elf.mf); | ||
| 1529 | if (clean_moved or clean_resized) { | ||
| 1530 | const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); | ||
| 1531 | defer sub_prog_node.end(); | ||
| 1532 | if (clean_moved) try elf.flushMoved(ni); | ||
| 1533 | if (clean_resized) try elf.flushResized(ni); | ||
| 1534 | break :task; | ||
| 1535 | } else elf.mf.update_prog_node.completeOne(); | ||
| 1536 | } | ||
| 1537 | } | ||
| 1538 | if (elf.pending_uavs.count() > 0) return true; | ||
| 1539 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | ||
| 1540 | if (elf.mf.updates.items.len > 0) return true; | ||
| 1541 | return false; | ||
| 1542 | } | ||
| 1543 | |||
| 1544 | fn idleProgNode( | ||
| 1545 | elf: *Elf, | ||
| 1546 | tid: Zcu.PerThread.Id, | ||
| 1547 | prog_node: std.Progress.Node, | ||
| 1548 | node: Node, | ||
| 1549 | ) std.Progress.Node { | ||
| 1550 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | ||
| 1551 | return prog_node.start(name: switch (node) { | ||
| 1552 | else => |tag| @tagName(tag), | ||
| 1553 | .section => |si| elf.sectionName(si), | ||
| 1554 | .nav => |nav| { | ||
| 1555 | const ip = &elf.base.comp.zcu.?.intern_pool; | ||
| 1556 | break :name ip.getNav(nav).fqn.toSlice(ip); | ||
| 1557 | }, | ||
| 1558 | .uav => |uav| std.fmt.bufPrint(&name, "{f}", .{ | ||
| 1559 | Value.fromInterned(uav).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), | ||
| 1560 | }) catch &name, | ||
| 1561 | }, 0); | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | fn flushUav( | ||
| 1565 | elf: *Elf, | ||
| 1566 | pt: Zcu.PerThread, | ||
| 1567 | uav_val: InternPool.Index, | ||
| 1568 | uav_align: InternPool.Alignment, | ||
| 1569 | src_loc: Zcu.LazySrcLoc, | ||
| 1570 | ) !void { | ||
| 1571 | const zcu = pt.zcu; | ||
| 1572 | const gpa = zcu.gpa; | ||
| 1573 | |||
| 1574 | const si = try elf.uavSymbol(uav_val); | ||
| 1575 | const ni = ni: { | ||
| 1576 | const sym = si.get(elf); | ||
| 1577 | switch (sym.ni) { | ||
| 1578 | .none => { | ||
| 1579 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1580 | const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{ | ||
| 1581 | .alignment = uav_align.toStdMem(), | ||
| 1582 | .moved = true, | ||
| 1583 | }); | ||
| 1584 | elf.nodes.appendAssumeCapacity(.{ .uav = uav_val }); | ||
| 1585 | sym.ni = ni; | ||
| 1586 | switch (elf.symPtr(si)) { | ||
| 1587 | inline else => |sym_ptr, class| sym_ptr.shndx = | ||
| 1588 | @field(elf.symPtr(.data), @tagName(class)).shndx, | ||
| 1589 | } | ||
| 1590 | }, | ||
| 1591 | else => { | ||
| 1592 | if (sym.ni.alignment(&elf.mf).order(uav_align.toStdMem()).compare(.gte)) return; | ||
| 1593 | si.deleteLocationRelocs(elf); | ||
| 1594 | }, | ||
| 1595 | } | ||
| 1596 | assert(sym.loc_relocs == .none); | ||
| 1597 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | ||
| 1598 | break :ni sym.ni; | ||
| 1599 | }; | ||
| 1600 | |||
| 1601 | const size = size: { | ||
| 1602 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1603 | ni.writer(&elf.mf, gpa, &nw); | ||
| 1604 | defer nw.deinit(); | ||
| 1605 | codegen.generateSymbol( | ||
| 1606 | &elf.base, | ||
| 1607 | pt, | ||
| 1608 | src_loc, | ||
| 1609 | .fromInterned(uav_val), | ||
| 1610 | &nw.interface, | ||
| 1611 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1612 | ) catch |err| switch (err) { | ||
| 1613 | error.WriteFailed => return error.OutOfMemory, | ||
| 1614 | else => |e| return e, | ||
| 1615 | }; | ||
| 1616 | break :size nw.interface.end; | ||
| 1617 | }; | ||
| 1618 | |||
| 1619 | const target_endian = elf.endian(); | ||
| 1620 | switch (elf.symPtr(si)) { | ||
| 1621 | inline else => |sym| sym.size = | ||
| 1622 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | ||
| 1623 | } | ||
| 1624 | si.applyLocationRelocs(elf); | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lazy: link.File.LazySymbol, si: Symbol.Index) !void { | ||
| 1628 | const zcu = pt.zcu; | ||
| 1629 | const gpa = zcu.gpa; | ||
| 1630 | |||
| 1631 | const ni = ni: { | ||
| 1632 | const sym = si.get(elf); | ||
| 1633 | switch (sym.ni) { | ||
| 1634 | .none => { | ||
| 1635 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 1636 | const sec_si: Symbol.Index = switch (lazy.kind) { | ||
| 1637 | .code => .text, | ||
| 1638 | .const_data => .rodata, | ||
| 1639 | }; | ||
| 1640 | const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{ .moved = true }); | ||
| 1641 | elf.nodes.appendAssumeCapacity(switch (lazy.kind) { | ||
| 1642 | .code => .{ .lazy_code = lazy.ty }, | ||
| 1643 | .const_data => .{ .lazy_const_data = lazy.ty }, | ||
| 1644 | }); | ||
| 1645 | sym.ni = ni; | ||
| 1646 | switch (elf.symPtr(si)) { | ||
| 1647 | inline else => |sym_ptr, class| sym_ptr.shndx = | ||
| 1648 | @field(elf.symPtr(sec_si), @tagName(class)).shndx, | ||
| 1649 | } | ||
| 1650 | }, | ||
| 1651 | else => si.deleteLocationRelocs(elf), | ||
| 1652 | } | ||
| 1653 | assert(sym.loc_relocs == .none); | ||
| 1654 | sym.loc_relocs = @enumFromInt(elf.relocs.items.len); | ||
| 1655 | break :ni sym.ni; | ||
| 1656 | }; | ||
| 1657 | |||
| 1658 | const size = size: { | ||
| 1659 | var required_alignment: InternPool.Alignment = .none; | ||
| 1660 | var nw: MappedFile.Node.Writer = undefined; | ||
| 1661 | ni.writer(&elf.mf, gpa, &nw); | ||
| 1662 | defer nw.deinit(); | ||
| 1663 | try codegen.generateLazySymbol( | ||
| 1664 | &elf.base, | ||
| 1665 | pt, | ||
| 1666 | Type.fromInterned(lazy.ty).srcLocOrNull(pt.zcu) orelse .unneeded, | ||
| 1667 | lazy, | ||
| 1668 | &required_alignment, | ||
| 1669 | &nw.interface, | ||
| 1670 | .none, | ||
| 1671 | .{ .atom_index = @intFromEnum(si) }, | ||
| 1672 | ); | ||
| 1673 | break :size nw.interface.end; | ||
| 1674 | }; | ||
| 1675 | |||
| 1676 | const target_endian = elf.endian(); | ||
| 1677 | switch (elf.symPtr(si)) { | ||
| 1678 | inline else => |sym| sym.size = | ||
| 1679 | std.mem.nativeTo(@TypeOf(sym.size), @intCast(size), target_endian), | ||
| 1680 | } | ||
| 1681 | si.applyLocationRelocs(elf); | ||
| 1682 | } | ||
| 1683 | |||
| 1684 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ||
| 1685 | const target_endian = elf.endian(); | ||
| 1686 | const file_offset = ni.fileLocation(&elf.mf, false).offset; | ||
| 1687 | const node = elf.getNode(ni); | ||
| 1688 | switch (node) { | ||
| 1689 | else => |tag| @panic(@tagName(tag)), | ||
| 1690 | .ehdr => assert(file_offset == 0), | ||
| 1691 | .shdr => switch (elf.ehdrPtr()) { | ||
| 1692 | inline else => |ehdr| ehdr.shoff = | ||
| 1693 | std.mem.nativeTo(@TypeOf(ehdr.shoff), @intCast(file_offset), target_endian), | ||
| 1694 | }, | ||
| 1695 | .segment => |phndx| switch (elf.phdrSlice()) { | ||
| 1696 | inline else => |phdr, class| { | ||
| 1697 | const ph = &phdr[phndx]; | ||
| 1698 | switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { | ||
| 1699 | else => unreachable, | ||
| 1700 | std.elf.PT_NULL, std.elf.PT_LOAD, std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, | ||
| 1701 | std.elf.PT_PHDR => { | ||
| 1702 | const ehdr = @field(elf.ehdrPtr(), @tagName(class)); | ||
| 1703 | ehdr.phoff = | ||
| 1704 | std.mem.nativeTo(@TypeOf(ehdr.phoff), @intCast(file_offset), target_endian); | ||
| 1705 | }, | ||
| 1706 | std.elf.PT_TLS => {}, | ||
| 1707 | } | ||
| 1708 | ph.offset = std.mem.nativeTo(@TypeOf(ph.offset), @intCast(file_offset), target_endian); | ||
| 1709 | ph.vaddr = std.mem.nativeTo( | ||
| 1710 | @TypeOf(ph.vaddr), | ||
| 1711 | @intCast(elf.baseAddr() + file_offset), | ||
| 1712 | target_endian, | ||
| 1713 | ); | ||
| 1714 | ph.paddr = ph.vaddr; | ||
| 1715 | }, | ||
| 1716 | }, | ||
| 1717 | .section => |si| switch (elf.shdrSlice()) { | ||
| 1718 | inline else => |shdr, class| { | ||
| 1719 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1720 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | ||
| 1721 | const sh = &shdr[shndx]; | ||
| 1722 | const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( | ||
| 1723 | @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, | ||
| 1724 | @bitCast(sh.flags), | ||
| 1725 | target_endian, | ||
| 1726 | )); | ||
| 1727 | if (flags.shf.ALLOC) { | ||
| 1728 | sym.value = std.mem.nativeTo( | ||
| 1729 | @TypeOf(sym.value), | ||
| 1730 | @intCast(elf.baseAddr() + file_offset), | ||
| 1731 | target_endian, | ||
| 1732 | ); | ||
| 1733 | sh.addr = sym.value; | ||
| 1734 | } | ||
| 1735 | sh.offset = std.mem.nativeTo(@TypeOf(sh.offset), @intCast(file_offset), target_endian); | ||
| 1736 | }, | ||
| 1737 | }, | ||
| 1738 | .nav, .uav, .lazy_code, .lazy_const_data => { | ||
| 1739 | const si = switch (node) { | ||
| 1740 | else => unreachable, | ||
| 1741 | .nav => |nav| elf.navs.get(nav), | ||
| 1742 | .uav => |uav| elf.uavs.get(uav), | ||
| 1743 | .lazy_code => |ty| elf.lazy.getPtr(.code).map.get(ty), | ||
| 1744 | .lazy_const_data => |ty| elf.lazy.getPtr(.const_data).map.get(ty), | ||
| 1745 | }.?; | ||
| 1746 | switch (elf.shdrSlice()) { | ||
| 1747 | inline else => |shdr, class| { | ||
| 1748 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1749 | const sh = &shdr[std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian)]; | ||
| 1750 | const flags: @TypeOf(sh.flags) = @bitCast(std.mem.toNative( | ||
| 1751 | @typeInfo(@TypeOf(sh.flags)).@"struct".backing_integer.?, | ||
| 1752 | @bitCast(sh.flags), | ||
| 1753 | target_endian, | ||
| 1754 | )); | ||
| 1755 | const sh_addr = if (flags.shf.TLS) | ||
| 1756 | 0 | ||
| 1757 | else | ||
| 1758 | std.mem.toNative(@TypeOf(sh.addr), sh.addr, target_endian); | ||
| 1759 | const sh_offset = std.mem.toNative(@TypeOf(sh.offset), sh.offset, target_endian); | ||
| 1760 | sym.value = std.mem.nativeTo( | ||
| 1761 | @TypeOf(sym.value), | ||
| 1762 | @intCast(file_offset - sh_offset + sh_addr), | ||
| 1763 | target_endian, | ||
| 1764 | ); | ||
| 1765 | if (si == elf.entry_hack) @field(elf.ehdrPtr(), @tagName(class)).entry = sym.value; | ||
| 1766 | }, | ||
| 1767 | } | ||
| 1768 | si.applyLocationRelocs(elf); | ||
| 1769 | si.applyTargetRelocs(elf); | ||
| 1770 | }, | ||
| 1771 | } | ||
| 1772 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | ||
| 1773 | } | ||
| 1774 | |||
| 1775 | fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { | ||
| 1776 | const target_endian = elf.endian(); | ||
| 1777 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); | ||
| 1778 | const node = elf.getNode(ni); | ||
| 1779 | switch (node) { | ||
| 1780 | else => |tag| @panic(@tagName(tag)), | ||
| 1781 | .file, .shdr => {}, | ||
| 1782 | .segment => |phndx| switch (elf.phdrSlice()) { | ||
| 1783 | inline else => |phdr| { | ||
| 1784 | const ph = &phdr[phndx]; | ||
| 1785 | ph.filesz = std.mem.nativeTo(@TypeOf(ph.filesz), @intCast(size), target_endian); | ||
| 1786 | ph.memsz = ph.filesz; | ||
| 1787 | switch (std.mem.toNative(@TypeOf(ph.type), ph.type, target_endian)) { | ||
| 1788 | else => unreachable, | ||
| 1789 | std.elf.PT_NULL => { | ||
| 1790 | if (size > 0) ph.type = std.mem.nativeTo( | ||
| 1791 | @TypeOf(ph.type), | ||
| 1792 | std.elf.PT_LOAD, | ||
| 1793 | target_endian, | ||
| 1794 | ); | ||
| 1795 | }, | ||
| 1796 | std.elf.PT_LOAD => { | ||
| 1797 | if (size == 0) ph.type = std.mem.nativeTo( | ||
| 1798 | @TypeOf(ph.type), | ||
| 1799 | std.elf.PT_NULL, | ||
| 1800 | target_endian, | ||
| 1801 | ); | ||
| 1802 | }, | ||
| 1803 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP, std.elf.PT_PHDR => {}, | ||
| 1804 | std.elf.PT_TLS => try ni.childrenMoved(elf.base.comp.gpa, &elf.mf), | ||
| 1805 | } | ||
| 1806 | }, | ||
| 1807 | }, | ||
| 1808 | .section => |si| switch (elf.shdrSlice()) { | ||
| 1809 | inline else => |shdr, class| { | ||
| 1810 | const sym = @field(elf.symPtr(si), @tagName(class)); | ||
| 1811 | const shndx = std.mem.toNative(@TypeOf(sym.shndx), sym.shndx, target_endian); | ||
| 1812 | const sh = &shdr[shndx]; | ||
| 1813 | switch (std.mem.toNative(@TypeOf(sh.type), sh.type, target_endian)) { | ||
| 1814 | else => unreachable, | ||
| 1815 | std.elf.SHT_NULL => { | ||
| 1816 | if (size > 0) sh.type = std.mem.nativeTo( | ||
| 1817 | @TypeOf(sh.type), | ||
| 1818 | std.elf.SHT_PROGBITS, | ||
| 1819 | target_endian, | ||
| 1820 | ); | ||
| 1821 | }, | ||
| 1822 | std.elf.SHT_PROGBITS => { | ||
| 1823 | if (size == 0) sh.type = std.mem.nativeTo( | ||
| 1824 | @TypeOf(sh.type), | ||
| 1825 | std.elf.SHT_NULL, | ||
| 1826 | target_endian, | ||
| 1827 | ); | ||
| 1828 | }, | ||
| 1829 | std.elf.SHT_SYMTAB => sh.info = std.mem.nativeTo( | ||
| 1830 | @TypeOf(sh.info), | ||
| 1831 | @intCast(@divExact( | ||
| 1832 | size, | ||
| 1833 | std.mem.toNative(@TypeOf(sh.entsize), sh.entsize, target_endian), | ||
| 1834 | )), | ||
| 1835 | target_endian, | ||
| 1836 | ), | ||
| 1837 | std.elf.SHT_STRTAB => {}, | ||
| 1838 | } | ||
| 1839 | sh.size = std.mem.nativeTo(@TypeOf(sh.size), @intCast(size), target_endian); | ||
| 1840 | }, | ||
| 1841 | }, | ||
| 1842 | .nav, .uav, .lazy_code, .lazy_const_data => {}, | ||
| 1843 | } | ||
| 1844 | } | ||
| 1845 | |||
| 1846 | pub fn updateExports( | ||
| 1847 | elf: *Elf, | ||
| 1848 | pt: Zcu.PerThread, | ||
| 1849 | exported: Zcu.Exported, | ||
| 1850 | export_indices: []const Zcu.Export.Index, | ||
| 1851 | ) !void { | ||
| 1852 | return elf.updateExportsInner(pt, exported, export_indices) catch |err| switch (err) { | ||
| 1853 | error.OutOfMemory => error.OutOfMemory, | ||
| 1854 | error.LinkFailure => error.AnalysisFail, | ||
| 1855 | else => |e| switch (elf.base.comp.link_diags.fail( | ||
| 1856 | "linker failed to update exports: {t}", | ||
| 1857 | .{e}, | ||
| 1858 | )) { | ||
| 1859 | error.LinkFailure => return error.AnalysisFail, | ||
| 1860 | }, | ||
| 1861 | }; | ||
| 1862 | } | ||
| 1863 | fn updateExportsInner( | ||
| 1864 | elf: *Elf, | ||
| 1865 | pt: Zcu.PerThread, | ||
| 1866 | exported: Zcu.Exported, | ||
| 1867 | export_indices: []const Zcu.Export.Index, | ||
| 1868 | ) !void { | ||
| 1869 | const zcu = pt.zcu; | ||
| 1870 | const gpa = zcu.gpa; | ||
| 1871 | const ip = &zcu.intern_pool; | ||
| 1872 | |||
| 1873 | switch (exported) { | ||
| 1874 | .nav => |nav| log.debug("updateExports({f})", .{ip.getNav(nav).fqn.fmt(ip)}), | ||
| 1875 | .uav => |uav| log.debug("updateExports(@as({f}, {f}))", .{ | ||
| 1876 | Type.fromInterned(ip.typeOf(uav)).fmt(pt), | ||
| 1877 | Value.fromInterned(uav).fmtValue(pt), | ||
| 1878 | }), | ||
| 1879 | } | ||
| 1880 | try elf.symtab.ensureUnusedCapacity(gpa, export_indices.len); | ||
| 1881 | const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) { | ||
| 1882 | .nav => |nav| .{ | ||
| 1883 | try elf.navSymbol(zcu, nav), | ||
| 1884 | navType(ip, ip.getNav(nav).status, elf.base.comp.config.any_non_single_threaded), | ||
| 1885 | }, | ||
| 1886 | .uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav( | ||
| 1887 | pt, | ||
| 1888 | uav, | ||
| 1889 | Type.fromInterned(ip.typeOf(uav)).abiAlignment(zcu), | ||
| 1890 | export_indices[0].ptr(zcu).src, | ||
| 1891 | )) { | ||
| 1892 | .sym_index => |si| si, | ||
| 1893 | .fail => |em| { | ||
| 1894 | defer em.destroy(gpa); | ||
| 1895 | return elf.base.comp.link_diags.fail("{s}", .{em.msg}); | ||
| 1896 | }, | ||
| 1897 | }), .OBJECT }, | ||
| 1898 | }; | ||
| 1899 | while (try elf.idle(pt.tid)) {} | ||
| 1900 | const exported_ni = exported_si.node(elf); | ||
| 1901 | const value, const size, const shndx = switch (elf.symPtr(exported_si)) { | ||
| 1902 | inline else => |exported_sym| .{ exported_sym.value, exported_sym.size, exported_sym.shndx }, | ||
| 1903 | }; | ||
| 1904 | for (export_indices) |export_index| { | ||
| 1905 | const @"export" = export_index.ptr(zcu); | ||
| 1906 | const name = @"export".opts.name.toSlice(ip); | ||
| 1907 | const export_si = try elf.globalSymbol(.{ | ||
| 1908 | .name = name, | ||
| 1909 | .type = @"type", | ||
| 1910 | .bind = switch (@"export".opts.linkage) { | ||
| 1911 | .internal => .LOCAL, | ||
| 1912 | .strong => .GLOBAL, | ||
| 1913 | .weak => .WEAK, | ||
| 1914 | .link_once => return error.LinkOnceUnsupported, | ||
| 1915 | }, | ||
| 1916 | .visibility = switch (@"export".opts.visibility) { | ||
| 1917 | .default => .DEFAULT, | ||
| 1918 | .hidden => .HIDDEN, | ||
| 1919 | .protected => .PROTECTED, | ||
| 1920 | }, | ||
| 1921 | }); | ||
| 1922 | export_si.get(elf).ni = exported_ni; | ||
| 1923 | switch (elf.symPtr(export_si)) { | ||
| 1924 | inline else => |export_sym| { | ||
| 1925 | export_sym.value = @intCast(value); | ||
| 1926 | export_sym.size = @intCast(size); | ||
| 1927 | export_sym.shndx = shndx; | ||
| 1928 | }, | ||
| 1929 | } | ||
| 1930 | export_si.applyTargetRelocs(elf); | ||
| 1931 | if (std.mem.eql(u8, name, "_start")) { | ||
| 1932 | elf.entry_hack = exported_si; | ||
| 1933 | switch (elf.ehdrPtr()) { | ||
| 1934 | inline else => |ehdr| ehdr.entry = @intCast(value), | ||
| 1935 | } | ||
| 1936 | } | ||
| 1937 | } | ||
| 1938 | } | ||
| 1939 | |||
| 1940 | pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerminatedString) void { | ||
| 1941 | _ = elf; | ||
| 1942 | _ = exported; | ||
| 1943 | _ = name; | ||
| 1944 | } | ||
| 1945 | |||
| 1946 | pub fn dump(elf: *Elf, tid: Zcu.PerThread.Id) void { | ||
| 1947 | const w = std.debug.lockStderrWriter(&.{}); | ||
| 1948 | defer std.debug.unlockStderrWriter(); | ||
| 1949 | elf.printNode(tid, w, .root, 0) catch {}; | ||
| 1950 | } | ||
| 1951 | |||
| 1952 | pub fn printNode( | ||
| 1953 | elf: *Elf, | ||
| 1954 | tid: Zcu.PerThread.Id, | ||
| 1955 | w: *std.Io.Writer, | ||
| 1956 | ni: MappedFile.Node.Index, | ||
| 1957 | indent: usize, | ||
| 1958 | ) !void { | ||
| 1959 | const node = elf.getNode(ni); | ||
| 1960 | const mf_node = &elf.mf.nodes.items[@intFromEnum(ni)]; | ||
| 1961 | const off, const size = mf_node.location().resolve(&elf.mf); | ||
| 1962 | try w.splatByteAll(' ', indent); | ||
| 1963 | try w.writeAll(@tagName(node)); | ||
| 1964 | switch (node) { | ||
| 1965 | else => {}, | ||
| 1966 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), | ||
| 1967 | .nav => |nav_index| { | ||
| 1968 | const zcu = elf.base.comp.zcu.?; | ||
| 1969 | const ip = &zcu.intern_pool; | ||
| 1970 | const nav = ip.getNav(nav_index); | ||
| 1971 | try w.print("({f}, {f})", .{ | ||
| 1972 | Type.fromInterned(nav.typeOf(ip)).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 1973 | nav.fqn.fmt(ip), | ||
| 1974 | }); | ||
| 1975 | }, | ||
| 1976 | .uav => |uav| { | ||
| 1977 | const zcu = elf.base.comp.zcu.?; | ||
| 1978 | const val: Value = .fromInterned(uav); | ||
| 1979 | try w.print("({f}, {f})", .{ | ||
| 1980 | val.typeOf(zcu).fmt(.{ .zcu = zcu, .tid = tid }), | ||
| 1981 | val.fmtValue(.{ .zcu = zcu, .tid = tid }), | ||
| 1982 | }); | ||
| 1983 | }, | ||
| 1984 | } | ||
| 1985 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ | ||
| 1986 | @intFromEnum(ni), | ||
| 1987 | off, | ||
| 1988 | size, | ||
| 1989 | mf_node.flags.alignment.toByteUnits(), | ||
| 1990 | if (mf_node.flags.fixed) " fixed" else "", | ||
| 1991 | if (mf_node.flags.moved) " moved" else "", | ||
| 1992 | if (mf_node.flags.resized) " resized" else "", | ||
| 1993 | if (mf_node.flags.has_content) " has_content" else "", | ||
| 1994 | }); | ||
| 1995 | var child_ni = mf_node.first; | ||
| 1996 | switch (child_ni) { | ||
| 1997 | .none => { | ||
| 1998 | const file_loc = ni.fileLocation(&elf.mf, false); | ||
| 1999 | if (file_loc.size == 0) return; | ||
| 2000 | var address = file_loc.offset; | ||
| 2001 | const line_len = 0x10; | ||
| 2002 | var line_it = std.mem.window( | ||
| 2003 | u8, | ||
| 2004 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | ||
| 2005 | line_len, | ||
| 2006 | line_len, | ||
| 2007 | ); | ||
| 2008 | while (line_it.next()) |line_bytes| : (address += line_len) { | ||
| 2009 | try w.splatByteAll(' ', indent + 1); | ||
| 2010 | try w.print("{x:0>8}", .{address}); | ||
| 2011 | for (line_bytes) |byte| try w.print(" {x:0>2}", .{byte}); | ||
| 2012 | try w.writeByte('\n'); | ||
| 2013 | } | ||
| 2014 | }, | ||
| 2015 | else => while (child_ni != .none) { | ||
| 2016 | try elf.printNode(tid, w, child_ni, indent + 1); | ||
| 2017 | child_ni = elf.mf.nodes.items[@intFromEnum(child_ni)].next; | ||
| 2018 | }, | ||
| 2019 | } | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | const assert = std.debug.assert; | ||
| 2023 | const builtin = @import("builtin"); | ||
| 2024 | const codegen = @import("../codegen.zig"); | ||
| 2025 | const Compilation = @import("../Compilation.zig"); | ||
| 2026 | const Elf = @This(); | ||
| 2027 | const InternPool = @import("../InternPool.zig"); | ||
| 2028 | const link = @import("../link.zig"); | ||
| 2029 | const log = std.log.scoped(.link); | ||
| 2030 | const MappedFile = @import("MappedFile.zig"); | ||
| 2031 | const native_endian = builtin.cpu.arch.endian(); | ||
| 2032 | const std = @import("std"); | ||
| 2033 | const target_util = @import("../target.zig"); | ||
| 2034 | const Type = @import("../Type.zig"); | ||
| 2035 | const Value = @import("../Value.zig"); | ||
| 2036 | const Zcu = @import("../Zcu.zig"); | ||
src/link/MachO/ZigObject.zig+32-22| ... | @@ -784,22 +784,26 @@ pub fn updateFunc( | ... | @@ -784,22 +784,26 @@ pub fn updateFunc( |
| 784 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav); | 784 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, func.owner_nav); |
| 785 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); | 785 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); |
| 786 | 786 | ||
| 787 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 787 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 788 | defer code_buffer.deinit(gpa); | 788 | defer aw.deinit(); |
| 789 | 789 | ||
| 790 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; | 790 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null; |
| 791 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); | 791 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 792 | 792 | ||
| 793 | try codegen.emitFunction( | 793 | codegen.emitFunction( |
| 794 | &macho_file.base, | 794 | &macho_file.base, |
| 795 | pt, | 795 | pt, |
| 796 | zcu.navSrcLoc(func.owner_nav), | 796 | zcu.navSrcLoc(func.owner_nav), |
| 797 | func_index, | 797 | func_index, |
| 798 | sym_index, | ||
| 798 | mir, | 799 | mir, |
| 799 | &code_buffer, | 800 | &aw.writer, |
| 800 | if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, | 801 | if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, |
| 801 | ); | 802 | ) catch |err| switch (err) { |
| 802 | const code = code_buffer.items; | 803 | error.WriteFailed => return error.OutOfMemory, |
| 804 | else => |e| return e, | ||
| 805 | }; | ||
| 806 | const code = aw.written(); | ||
| 803 | 807 | ||
| 804 | const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code); | 808 | const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code); |
| 805 | const old_rva, const old_alignment = blk: { | 809 | const old_rva, const old_alignment = blk: { |
| ... | @@ -895,21 +899,24 @@ pub fn updateNav( | ... | @@ -895,21 +899,24 @@ pub fn updateNav( |
| 895 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); | 899 | const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index); |
| 896 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); | 900 | self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file); |
| 897 | 901 | ||
| 898 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 902 | var aw: std.Io.Writer.Allocating = .init(zcu.gpa); |
| 899 | defer code_buffer.deinit(zcu.gpa); | 903 | defer aw.deinit(); |
| 900 | 904 | ||
| 901 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; | 905 | var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null; |
| 902 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); | 906 | defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit(); |
| 903 | 907 | ||
| 904 | try codegen.generateSymbol( | 908 | codegen.generateSymbol( |
| 905 | &macho_file.base, | 909 | &macho_file.base, |
| 906 | pt, | 910 | pt, |
| 907 | zcu.navSrcLoc(nav_index), | 911 | zcu.navSrcLoc(nav_index), |
| 908 | Value.fromInterned(nav_init), | 912 | Value.fromInterned(nav_init), |
| 909 | &code_buffer, | 913 | &aw.writer, |
| 910 | .{ .atom_index = sym_index }, | 914 | .{ .atom_index = sym_index }, |
| 911 | ); | 915 | ) catch |err| switch (err) { |
| 912 | const code = code_buffer.items; | 916 | error.WriteFailed => return error.OutOfMemory, |
| 917 | else => |e| return e, | ||
| 918 | }; | ||
| 919 | const code = aw.written(); | ||
| 913 | 920 | ||
| 914 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); | 921 | const sect_index = try self.getNavOutputSection(macho_file, zcu, nav_index, code); |
| 915 | if (isThreadlocal(macho_file, nav_index)) | 922 | if (isThreadlocal(macho_file, nav_index)) |
| ... | @@ -1198,21 +1205,24 @@ fn lowerConst( | ... | @@ -1198,21 +1205,24 @@ fn lowerConst( |
| 1198 | ) !codegen.SymbolResult { | 1205 | ) !codegen.SymbolResult { |
| 1199 | const gpa = macho_file.base.comp.gpa; | 1206 | const gpa = macho_file.base.comp.gpa; |
| 1200 | 1207 | ||
| 1201 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1208 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1202 | defer code_buffer.deinit(gpa); | 1209 | defer aw.deinit(); |
| 1203 | 1210 | ||
| 1204 | const name_str = try self.addString(gpa, name); | 1211 | const name_str = try self.addString(gpa, name); |
| 1205 | const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file); | 1212 | const sym_index = try self.newSymbolWithAtom(gpa, name_str, macho_file); |
| 1206 | 1213 | ||
| 1207 | try codegen.generateSymbol( | 1214 | codegen.generateSymbol( |
| 1208 | &macho_file.base, | 1215 | &macho_file.base, |
| 1209 | pt, | 1216 | pt, |
| 1210 | src_loc, | 1217 | src_loc, |
| 1211 | val, | 1218 | val, |
| 1212 | &code_buffer, | 1219 | &aw.writer, |
| 1213 | .{ .atom_index = sym_index }, | 1220 | .{ .atom_index = sym_index }, |
| 1214 | ); | 1221 | ) catch |err| switch (err) { |
| 1215 | const code = code_buffer.items; | 1222 | error.WriteFailed => return error.OutOfMemory, |
| 1223 | else => |e| return e, | ||
| 1224 | }; | ||
| 1225 | const code = aw.written(); | ||
| 1216 | 1226 | ||
| 1217 | const sym = &self.symbols.items[sym_index]; | 1227 | const sym = &self.symbols.items[sym_index]; |
| 1218 | sym.out_n_sect = output_section_index; | 1228 | sym.out_n_sect = output_section_index; |
| ... | @@ -1349,8 +1359,8 @@ fn updateLazySymbol( | ... | @@ -1349,8 +1359,8 @@ fn updateLazySymbol( |
| 1349 | const gpa = zcu.gpa; | 1359 | const gpa = zcu.gpa; |
| 1350 | 1360 | ||
| 1351 | var required_alignment: Atom.Alignment = .none; | 1361 | var required_alignment: Atom.Alignment = .none; |
| 1352 | var code_buffer: std.ArrayListUnmanaged(u8) = .empty; | 1362 | var aw: std.Io.Writer.Allocating = .init(gpa); |
| 1353 | defer code_buffer.deinit(gpa); | 1363 | defer aw.deinit(); |
| 1354 | 1364 | ||
| 1355 | const name_str = blk: { | 1365 | const name_str = blk: { |
| 1356 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ | 1366 | const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{f}", .{ |
| ... | @@ -1368,11 +1378,11 @@ fn updateLazySymbol( | ... | @@ -1368,11 +1378,11 @@ fn updateLazySymbol( |
| 1368 | src, | 1378 | src, |
| 1369 | lazy_sym, | 1379 | lazy_sym, |
| 1370 | &required_alignment, | 1380 | &required_alignment, |
| 1371 | &code_buffer, | 1381 | &aw.writer, |
| 1372 | .none, | 1382 | .none, |
| 1373 | .{ .atom_index = symbol_index }, | 1383 | .{ .atom_index = symbol_index }, |
| 1374 | ); | 1384 | ); |
| 1375 | const code = code_buffer.items; | 1385 | const code = aw.written(); |
| 1376 | 1386 | ||
| 1377 | const output_section_index = switch (lazy_sym.kind) { | 1387 | const output_section_index = switch (lazy_sym.kind) { |
| 1378 | .code => macho_file.zig_text_sect_index.?, | 1388 | .code => macho_file.zig_text_sect_index.?, |
src/link/MappedFile.zig created+929| ... | @@ -0,0 +1,929 @@ | ||
| 1 | file: std.fs.File, | ||
| 2 | flags: packed struct { | ||
| 3 | block_size: std.mem.Alignment, | ||
| 4 | copy_file_range_unsupported: bool, | ||
| 5 | fallocate_punch_hole_unsupported: bool, | ||
| 6 | fallocate_insert_range_unsupported: bool, | ||
| 7 | }, | ||
| 8 | section: if (is_windows) windows.HANDLE else void, | ||
| 9 | contents: []align(std.heap.page_size_min) u8, | ||
| 10 | nodes: std.ArrayList(Node), | ||
| 11 | free_ni: Node.Index, | ||
| 12 | large: std.ArrayList(u64), | ||
| 13 | updates: std.ArrayList(Node.Index), | ||
| 14 | update_prog_node: std.Progress.Node, | ||
| 15 | writers: std.SinglyLinkedList, | ||
| 16 | |||
| 17 | pub const Error = std.posix.MMapError || | ||
| 18 | std.posix.MRemapError || | ||
| 19 | std.fs.File.SetEndPosError || | ||
| 20 | std.fs.File.CopyRangeError || | ||
| 21 | error{NotFile}; | ||
| 22 | |||
| 23 | pub fn init(file: std.fs.File, gpa: std.mem.Allocator) !MappedFile { | ||
| 24 | var mf: MappedFile = .{ | ||
| 25 | .file = file, | ||
| 26 | .flags = undefined, | ||
| 27 | .section = if (is_windows) windows.INVALID_HANDLE_VALUE else {}, | ||
| 28 | .contents = &.{}, | ||
| 29 | .nodes = .empty, | ||
| 30 | .free_ni = .none, | ||
| 31 | .large = .empty, | ||
| 32 | .updates = .empty, | ||
| 33 | .update_prog_node = .none, | ||
| 34 | .writers = .{}, | ||
| 35 | }; | ||
| 36 | errdefer mf.deinit(gpa); | ||
| 37 | const size: u64, const blksize = if (is_windows) | ||
| 38 | .{ try windows.GetFileSizeEx(file.handle), 1 } | ||
| 39 | else stat: { | ||
| 40 | const stat = try std.posix.fstat(mf.file.handle); | ||
| 41 | if (!std.posix.S.ISREG(stat.mode)) return error.PathAlreadyExists; | ||
| 42 | break :stat .{ @bitCast(stat.size), stat.blksize }; | ||
| 43 | }; | ||
| 44 | mf.flags = .{ | ||
| 45 | .block_size = .fromByteUnits( | ||
| 46 | std.math.ceilPowerOfTwoAssert(usize, @max(std.heap.pageSize(), blksize)), | ||
| 47 | ), | ||
| 48 | .copy_file_range_unsupported = false, | ||
| 49 | .fallocate_insert_range_unsupported = false, | ||
| 50 | .fallocate_punch_hole_unsupported = false, | ||
| 51 | }; | ||
| 52 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 53 | assert(try mf.addNode(gpa, .{ | ||
| 54 | .add_node = .{ | ||
| 55 | .size = size, | ||
| 56 | .fixed = true, | ||
| 57 | }, | ||
| 58 | }) == Node.Index.root); | ||
| 59 | try mf.ensureTotalCapacity(@intCast(size)); | ||
| 60 | return mf; | ||
| 61 | } | ||
| 62 | |||
| 63 | pub fn deinit(mf: *MappedFile, gpa: std.mem.Allocator) void { | ||
| 64 | mf.unmap(); | ||
| 65 | mf.nodes.deinit(gpa); | ||
| 66 | mf.large.deinit(gpa); | ||
| 67 | mf.updates.deinit(gpa); | ||
| 68 | mf.update_prog_node.end(); | ||
| 69 | assert(mf.writers.first == null); | ||
| 70 | mf.* = undefined; | ||
| 71 | } | ||
| 72 | |||
| 73 | pub const Node = extern struct { | ||
| 74 | parent: Node.Index, | ||
| 75 | prev: Node.Index, | ||
| 76 | next: Node.Index, | ||
| 77 | first: Node.Index, | ||
| 78 | last: Node.Index, | ||
| 79 | flags: Flags, | ||
| 80 | location_payload: Location.Payload, | ||
| 81 | |||
| 82 | pub const Flags = packed struct(u32) { | ||
| 83 | location_tag: Location.Tag, | ||
| 84 | alignment: std.mem.Alignment, | ||
| 85 | /// Whether this node can be moved. | ||
| 86 | fixed: bool, | ||
| 87 | /// Whether this node has been moved. | ||
| 88 | moved: bool, | ||
| 89 | /// Whether this node has been resized. | ||
| 90 | resized: bool, | ||
| 91 | /// Whether this node might contain non-zero bytes. | ||
| 92 | has_content: bool, | ||
| 93 | unused: @Type(.{ .int = .{ | ||
| 94 | .signedness = .unsigned, | ||
| 95 | .bits = 32 - @bitSizeOf(std.mem.Alignment) - 5, | ||
| 96 | } }) = 0, | ||
| 97 | }; | ||
| 98 | |||
| 99 | pub const Location = union(enum(u1)) { | ||
| 100 | small: extern struct { | ||
| 101 | /// Relative to `parent`. | ||
| 102 | offset: u32, | ||
| 103 | size: u32, | ||
| 104 | }, | ||
| 105 | large: extern struct { | ||
| 106 | index: usize, | ||
| 107 | unused: @Type(.{ .int = .{ | ||
| 108 | .signedness = .unsigned, | ||
| 109 | .bits = 64 - @bitSizeOf(usize), | ||
| 110 | } }) = 0, | ||
| 111 | }, | ||
| 112 | |||
| 113 | pub const Tag = @typeInfo(Location).@"union".tag_type.?; | ||
| 114 | pub const Payload = @Type(.{ .@"union" = .{ | ||
| 115 | .layout = .@"extern", | ||
| 116 | .tag_type = null, | ||
| 117 | .fields = @typeInfo(Location).@"union".fields, | ||
| 118 | .decls = &.{}, | ||
| 119 | } }); | ||
| 120 | |||
| 121 | pub fn resolve(loc: Location, mf: *const MappedFile) [2]u64 { | ||
| 122 | return switch (loc) { | ||
| 123 | .small => |small| .{ small.offset, small.size }, | ||
| 124 | .large => |large| mf.large.items[large.index..][0..2].*, | ||
| 125 | }; | ||
| 126 | } | ||
| 127 | }; | ||
| 128 | |||
| 129 | pub const Index = enum(u32) { | ||
| 130 | none, | ||
| 131 | _, | ||
| 132 | |||
| 133 | pub const root: Node.Index = .none; | ||
| 134 | |||
| 135 | fn get(ni: Node.Index, mf: *const MappedFile) *Node { | ||
| 136 | return &mf.nodes.items[@intFromEnum(ni)]; | ||
| 137 | } | ||
| 138 | |||
| 139 | pub fn childrenMoved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { | ||
| 140 | var child_ni = ni.get(mf).last; | ||
| 141 | while (child_ni != .none) { | ||
| 142 | try child_ni.moved(gpa, mf); | ||
| 143 | child_ni = child_ni.get(mf).prev; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | pub fn hasMoved(ni: Node.Index, mf: *const MappedFile) bool { | ||
| 148 | var parent_ni = ni; | ||
| 149 | while (parent_ni != .none) { | ||
| 150 | const parent = parent_ni.get(mf); | ||
| 151 | if (parent.flags.moved) return true; | ||
| 152 | parent_ni = parent.parent; | ||
| 153 | } | ||
| 154 | return false; | ||
| 155 | } | ||
| 156 | pub fn moved(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { | ||
| 157 | try mf.updates.ensureUnusedCapacity(gpa, 1); | ||
| 158 | ni.movedAssumeCapacity(mf); | ||
| 159 | } | ||
| 160 | pub fn cleanMoved(ni: Node.Index, mf: *const MappedFile) bool { | ||
| 161 | const node_moved = &ni.get(mf).flags.moved; | ||
| 162 | defer node_moved.* = false; | ||
| 163 | return node_moved.*; | ||
| 164 | } | ||
| 165 | fn movedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { | ||
| 166 | var parent_ni = ni; | ||
| 167 | while (parent_ni != .none) { | ||
| 168 | const parent_node = parent_ni.get(mf); | ||
| 169 | if (parent_node.flags.moved) return; | ||
| 170 | parent_ni = parent_node.parent; | ||
| 171 | } | ||
| 172 | const node = ni.get(mf); | ||
| 173 | node.flags.moved = true; | ||
| 174 | if (node.flags.resized) return; | ||
| 175 | mf.updates.appendAssumeCapacity(ni); | ||
| 176 | mf.update_prog_node.increaseEstimatedTotalItems(1); | ||
| 177 | } | ||
| 178 | |||
| 179 | pub fn hasResized(ni: Node.Index, mf: *const MappedFile) bool { | ||
| 180 | return ni.get(mf).flags.resized; | ||
| 181 | } | ||
| 182 | pub fn resized(ni: Node.Index, gpa: std.mem.Allocator, mf: *MappedFile) !void { | ||
| 183 | try mf.updates.ensureUnusedCapacity(gpa, 1); | ||
| 184 | ni.resizedAssumeCapacity(mf); | ||
| 185 | } | ||
| 186 | pub fn cleanResized(ni: Node.Index, mf: *const MappedFile) bool { | ||
| 187 | const node_resized = &ni.get(mf).flags.resized; | ||
| 188 | defer node_resized.* = false; | ||
| 189 | return node_resized.*; | ||
| 190 | } | ||
| 191 | fn resizedAssumeCapacity(ni: Node.Index, mf: *MappedFile) void { | ||
| 192 | const node = ni.get(mf); | ||
| 193 | if (node.flags.resized) return; | ||
| 194 | node.flags.resized = true; | ||
| 195 | if (node.flags.moved) return; | ||
| 196 | mf.updates.appendAssumeCapacity(ni); | ||
| 197 | mf.update_prog_node.increaseEstimatedTotalItems(1); | ||
| 198 | } | ||
| 199 | |||
| 200 | pub fn alignment(ni: Node.Index, mf: *const MappedFile) std.mem.Alignment { | ||
| 201 | return ni.get(mf).flags.alignment; | ||
| 202 | } | ||
| 203 | |||
| 204 | fn setLocationAssumeCapacity(ni: Node.Index, mf: *MappedFile, offset: u64, size: u64) void { | ||
| 205 | const node = ni.get(mf); | ||
| 206 | if (size == 0) node.flags.has_content = false; | ||
| 207 | switch (node.location()) { | ||
| 208 | .small => |small| { | ||
| 209 | if (small.offset != offset) ni.movedAssumeCapacity(mf); | ||
| 210 | if (small.size != size) ni.resizedAssumeCapacity(mf); | ||
| 211 | if (std.math.cast(u32, offset)) |small_offset| { | ||
| 212 | if (std.math.cast(u32, size)) |small_size| { | ||
| 213 | node.location_payload.small = .{ | ||
| 214 | .offset = small_offset, | ||
| 215 | .size = small_size, | ||
| 216 | }; | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | defer mf.large.appendSliceAssumeCapacity(&.{ offset, size }); | ||
| 221 | node.flags.location_tag = .large; | ||
| 222 | node.location_payload = .{ .large = .{ .index = mf.large.items.len } }; | ||
| 223 | }, | ||
| 224 | .large => |large| { | ||
| 225 | const large_items = mf.large.items[large.index..][0..2]; | ||
| 226 | if (large_items[0] != offset) ni.movedAssumeCapacity(mf); | ||
| 227 | if (large_items[1] != size) ni.resizedAssumeCapacity(mf); | ||
| 228 | large_items.* = .{ offset, size }; | ||
| 229 | }, | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | pub fn location(ni: Node.Index, mf: *const MappedFile) Location { | ||
| 234 | return ni.get(mf).location(); | ||
| 235 | } | ||
| 236 | |||
| 237 | pub fn fileLocation( | ||
| 238 | ni: Node.Index, | ||
| 239 | mf: *const MappedFile, | ||
| 240 | set_has_content: bool, | ||
| 241 | ) struct { offset: u64, size: u64 } { | ||
| 242 | var offset, const size = ni.location(mf).resolve(mf); | ||
| 243 | var parent_ni = ni; | ||
| 244 | while (true) { | ||
| 245 | const parent = parent_ni.get(mf); | ||
| 246 | if (set_has_content) parent.flags.has_content = true; | ||
| 247 | if (parent_ni == .none) break; | ||
| 248 | parent_ni = parent.parent; | ||
| 249 | offset += parent_ni.location(mf).resolve(mf)[0]; | ||
| 250 | } | ||
| 251 | return .{ .offset = offset, .size = size }; | ||
| 252 | } | ||
| 253 | |||
| 254 | pub fn slice(ni: Node.Index, mf: *const MappedFile) []u8 { | ||
| 255 | const file_loc = ni.fileLocation(mf, true); | ||
| 256 | return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; | ||
| 257 | } | ||
| 258 | |||
| 259 | pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 { | ||
| 260 | const file_loc = ni.fileLocation(mf, false); | ||
| 261 | return mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; | ||
| 262 | } | ||
| 263 | |||
| 264 | pub fn resize(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, size: u64) !void { | ||
| 265 | try mf.resizeNode(gpa, ni, size); | ||
| 266 | var writers_it = mf.writers.first; | ||
| 267 | while (writers_it) |writer_node| : (writers_it = writer_node.next) { | ||
| 268 | const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node); | ||
| 269 | w.interface.buffer = w.ni.slice(mf); | ||
| 270 | } | ||
| 271 | } | ||
| 272 | |||
| 273 | pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void { | ||
| 274 | w.* = .{ | ||
| 275 | .gpa = gpa, | ||
| 276 | .mf = mf, | ||
| 277 | .writer_node = .{}, | ||
| 278 | .ni = ni, | ||
| 279 | .interface = .{ | ||
| 280 | .buffer = ni.slice(mf), | ||
| 281 | .vtable = &Writer.vtable, | ||
| 282 | }, | ||
| 283 | .err = null, | ||
| 284 | }; | ||
| 285 | mf.writers.prepend(&w.writer_node); | ||
| 286 | } | ||
| 287 | }; | ||
| 288 | |||
| 289 | pub fn location(node: *const Node) Location { | ||
| 290 | return switch (node.flags.location_tag) { | ||
| 291 | inline else => |tag| @unionInit( | ||
| 292 | Location, | ||
| 293 | @tagName(tag), | ||
| 294 | @field(node.location_payload, @tagName(tag)), | ||
| 295 | ), | ||
| 296 | }; | ||
| 297 | } | ||
| 298 | |||
| 299 | pub const Writer = struct { | ||
| 300 | gpa: std.mem.Allocator, | ||
| 301 | mf: *MappedFile, | ||
| 302 | writer_node: std.SinglyLinkedList.Node, | ||
| 303 | ni: Node.Index, | ||
| 304 | interface: std.Io.Writer, | ||
| 305 | err: ?Error, | ||
| 306 | |||
| 307 | pub fn deinit(w: *Writer) void { | ||
| 308 | assert(w.mf.writers.popFirst() == &w.writer_node); | ||
| 309 | w.* = undefined; | ||
| 310 | } | ||
| 311 | |||
| 312 | const vtable: std.Io.Writer.VTable = .{ | ||
| 313 | .drain = drain, | ||
| 314 | .sendFile = sendFile, | ||
| 315 | .flush = std.Io.Writer.noopFlush, | ||
| 316 | .rebase = growingRebase, | ||
| 317 | }; | ||
| 318 | |||
| 319 | fn drain( | ||
| 320 | interface: *std.Io.Writer, | ||
| 321 | data: []const []const u8, | ||
| 322 | splat: usize, | ||
| 323 | ) std.Io.Writer.Error!usize { | ||
| 324 | const pattern = data[data.len - 1]; | ||
| 325 | const splat_len = pattern.len * splat; | ||
| 326 | const start_len = interface.end; | ||
| 327 | assert(data.len != 0); | ||
| 328 | for (data) |bytes| { | ||
| 329 | try growingRebase(interface, interface.end, bytes.len + splat_len + 1); | ||
| 330 | @memcpy(interface.buffer[interface.end..][0..bytes.len], bytes); | ||
| 331 | interface.end += bytes.len; | ||
| 332 | } | ||
| 333 | if (splat == 0) { | ||
| 334 | interface.end -= pattern.len; | ||
| 335 | } else switch (pattern.len) { | ||
| 336 | 0 => {}, | ||
| 337 | 1 => { | ||
| 338 | @memset(interface.buffer[interface.end..][0 .. splat - 1], pattern[0]); | ||
| 339 | interface.end += splat - 1; | ||
| 340 | }, | ||
| 341 | else => for (0..splat - 1) |_| { | ||
| 342 | @memcpy(interface.buffer[interface.end..][0..pattern.len], pattern); | ||
| 343 | interface.end += pattern.len; | ||
| 344 | }, | ||
| 345 | } | ||
| 346 | return interface.end - start_len; | ||
| 347 | } | ||
| 348 | |||
| 349 | fn sendFile( | ||
| 350 | interface: *std.Io.Writer, | ||
| 351 | file_reader: *std.fs.File.Reader, | ||
| 352 | limit: std.Io.Limit, | ||
| 353 | ) std.Io.Writer.FileError!usize { | ||
| 354 | if (limit == .nothing) return 0; | ||
| 355 | const pos = file_reader.logicalPos(); | ||
| 356 | const additional = if (file_reader.getSize()) |size| size - pos else |_| std.atomic.cache_line; | ||
| 357 | if (additional == 0) return error.EndOfStream; | ||
| 358 | try growingRebase(interface, interface.end, limit.minInt64(additional)); | ||
| 359 | switch (file_reader.mode) { | ||
| 360 | .positional => { | ||
| 361 | const fr_buf = file_reader.interface.buffered(); | ||
| 362 | const buf_copy_size = interface.write(fr_buf) catch unreachable; | ||
| 363 | file_reader.interface.toss(buf_copy_size); | ||
| 364 | if (buf_copy_size < fr_buf.len) return buf_copy_size; | ||
| 365 | assert(file_reader.logicalPos() == file_reader.pos); | ||
| 366 | |||
| 367 | const w: *Writer = @fieldParentPtr("interface", interface); | ||
| 368 | const copy_size: usize = @intCast(w.mf.copyFileRange( | ||
| 369 | file_reader.file, | ||
| 370 | file_reader.pos, | ||
| 371 | w.ni.fileLocation(w.mf, true).offset + interface.end, | ||
| 372 | limit.minInt(interface.unusedCapacityLen()), | ||
| 373 | ) catch |err| { | ||
| 374 | w.err = err; | ||
| 375 | return error.WriteFailed; | ||
| 376 | }); | ||
| 377 | interface.end += copy_size; | ||
| 378 | return copy_size; | ||
| 379 | }, | ||
| 380 | .streaming, | ||
| 381 | .streaming_reading, | ||
| 382 | .positional_reading, | ||
| 383 | .failure, | ||
| 384 | => { | ||
| 385 | const dest = limit.slice(interface.unusedCapacitySlice()); | ||
| 386 | const n = try file_reader.read(dest); | ||
| 387 | interface.end += n; | ||
| 388 | return n; | ||
| 389 | }, | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 393 | fn growingRebase( | ||
| 394 | interface: *std.Io.Writer, | ||
| 395 | preserve: usize, | ||
| 396 | unused_capacity: usize, | ||
| 397 | ) std.Io.Writer.Error!void { | ||
| 398 | _ = preserve; | ||
| 399 | const total_capacity = interface.end + unused_capacity; | ||
| 400 | if (interface.buffer.len >= total_capacity) return; | ||
| 401 | const w: *Writer = @fieldParentPtr("interface", interface); | ||
| 402 | w.ni.resize(w.mf, w.gpa, total_capacity +| total_capacity / 2) catch |err| { | ||
| 403 | w.err = err; | ||
| 404 | return error.WriteFailed; | ||
| 405 | }; | ||
| 406 | } | ||
| 407 | }; | ||
| 408 | |||
| 409 | comptime { | ||
| 410 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Node) == 32); | ||
| 411 | } | ||
| 412 | }; | ||
| 413 | |||
| 414 | fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct { | ||
| 415 | parent: Node.Index = .none, | ||
| 416 | prev: Node.Index = .none, | ||
| 417 | next: Node.Index = .none, | ||
| 418 | offset: u64 = 0, | ||
| 419 | add_node: AddNodeOptions, | ||
| 420 | }) !Node.Index { | ||
| 421 | if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1); | ||
| 422 | const offset = opts.add_node.alignment.forward(@intCast(opts.offset)); | ||
| 423 | const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: { | ||
| 424 | if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{ | ||
| 425 | .small = .{ .offset = small_offset, .size = 0 }, | ||
| 426 | } }; | ||
| 427 | try mf.large.ensureUnusedCapacity(gpa, 2); | ||
| 428 | defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 }); | ||
| 429 | break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } }; | ||
| 430 | }; | ||
| 431 | const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) { | ||
| 432 | .none => .{ @enumFromInt(mf.nodes.items.len), mf.nodes.addOneAssumeCapacity() }, | ||
| 433 | else => |free_ni| { | ||
| 434 | const free_node = free_ni.get(mf); | ||
| 435 | mf.free_ni = free_node.next; | ||
| 436 | break :free .{ free_ni, free_node }; | ||
| 437 | }, | ||
| 438 | }; | ||
| 439 | free_node.* = .{ | ||
| 440 | .parent = opts.parent, | ||
| 441 | .prev = opts.prev, | ||
| 442 | .next = opts.next, | ||
| 443 | .first = .none, | ||
| 444 | .last = .none, | ||
| 445 | .flags = .{ | ||
| 446 | .location_tag = location_tag, | ||
| 447 | .alignment = opts.add_node.alignment, | ||
| 448 | .fixed = opts.add_node.fixed, | ||
| 449 | .moved = true, | ||
| 450 | .resized = true, | ||
| 451 | .has_content = false, | ||
| 452 | }, | ||
| 453 | .location_payload = location_payload, | ||
| 454 | }; | ||
| 455 | { | ||
| 456 | defer { | ||
| 457 | free_node.flags.moved = false; | ||
| 458 | free_node.flags.resized = false; | ||
| 459 | } | ||
| 460 | if (offset > opts.parent.location(mf).resolve(mf)[1]) try opts.parent.resize(mf, gpa, offset); | ||
| 461 | try free_ni.resize(mf, gpa, opts.add_node.size); | ||
| 462 | } | ||
| 463 | if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf); | ||
| 464 | if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf); | ||
| 465 | return free_ni; | ||
| 466 | } | ||
| 467 | |||
| 468 | pub const AddNodeOptions = struct { | ||
| 469 | size: u64 = 0, | ||
| 470 | alignment: std.mem.Alignment = .@"1", | ||
| 471 | fixed: bool = false, | ||
| 472 | moved: bool = false, | ||
| 473 | resized: bool = false, | ||
| 474 | }; | ||
| 475 | |||
| 476 | pub fn addOnlyChildNode( | ||
| 477 | mf: *MappedFile, | ||
| 478 | gpa: std.mem.Allocator, | ||
| 479 | parent_ni: Node.Index, | ||
| 480 | opts: AddNodeOptions, | ||
| 481 | ) !Node.Index { | ||
| 482 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 483 | const parent = parent_ni.get(mf); | ||
| 484 | assert(parent.first == .none and parent.last == .none); | ||
| 485 | const ni = try mf.addNode(gpa, .{ | ||
| 486 | .parent = parent_ni, | ||
| 487 | .add_node = opts, | ||
| 488 | }); | ||
| 489 | parent.first = ni; | ||
| 490 | parent.last = ni; | ||
| 491 | return ni; | ||
| 492 | } | ||
| 493 | |||
| 494 | pub fn addLastChildNode( | ||
| 495 | mf: *MappedFile, | ||
| 496 | gpa: std.mem.Allocator, | ||
| 497 | parent_ni: Node.Index, | ||
| 498 | opts: AddNodeOptions, | ||
| 499 | ) !Node.Index { | ||
| 500 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 501 | const parent = parent_ni.get(mf); | ||
| 502 | const ni = try mf.addNode(gpa, .{ | ||
| 503 | .parent = parent_ni, | ||
| 504 | .prev = parent.last, | ||
| 505 | .offset = offset: switch (parent.last) { | ||
| 506 | .none => 0, | ||
| 507 | else => |last_ni| { | ||
| 508 | const last_offset, const last_size = last_ni.location(mf).resolve(mf); | ||
| 509 | break :offset last_offset + last_size; | ||
| 510 | }, | ||
| 511 | }, | ||
| 512 | .add_node = opts, | ||
| 513 | }); | ||
| 514 | switch (parent.last) { | ||
| 515 | .none => parent.first = ni, | ||
| 516 | else => |last_ni| last_ni.get(mf).next = ni, | ||
| 517 | } | ||
| 518 | parent.last = ni; | ||
| 519 | return ni; | ||
| 520 | } | ||
| 521 | |||
| 522 | pub fn addNodeAfter( | ||
| 523 | mf: *MappedFile, | ||
| 524 | gpa: std.mem.Allocator, | ||
| 525 | prev_ni: Node.Index, | ||
| 526 | opts: AddNodeOptions, | ||
| 527 | ) !Node.Index { | ||
| 528 | assert(prev_ni != .none); | ||
| 529 | try mf.nodes.ensureUnusedCapacity(gpa, 1); | ||
| 530 | const prev = prev_ni.get(mf); | ||
| 531 | const prev_offset, const prev_size = prev.location().resolve(mf); | ||
| 532 | const ni = try mf.addNode(gpa, .{ | ||
| 533 | .parent = prev.parent, | ||
| 534 | .prev = prev_ni, | ||
| 535 | .next = prev.next, | ||
| 536 | .offset = prev_offset + prev_size, | ||
| 537 | .add_node = opts, | ||
| 538 | }); | ||
| 539 | switch (prev.next) { | ||
| 540 | .none => prev.parent.get(mf).last = ni, | ||
| 541 | else => |next_ni| next_ni.get(mf).prev = ni, | ||
| 542 | } | ||
| 543 | prev.next = ni; | ||
| 544 | return ni; | ||
| 545 | } | ||
| 546 | |||
| 547 | fn resizeNode(mf: *MappedFile, gpa: std.mem.Allocator, ni: Node.Index, requested_size: u64) !void { | ||
| 548 | const node = ni.get(mf); | ||
| 549 | var old_offset, const old_size = node.location().resolve(mf); | ||
| 550 | const new_size = node.flags.alignment.forward(@intCast(requested_size)); | ||
| 551 | // Resize the entire file | ||
| 552 | if (ni == Node.Index.root) { | ||
| 553 | try mf.file.setEndPos(new_size); | ||
| 554 | try mf.ensureTotalCapacity(@intCast(new_size)); | ||
| 555 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 556 | ni.setLocationAssumeCapacity(mf, old_offset, new_size); | ||
| 557 | return; | ||
| 558 | } | ||
| 559 | while (true) { | ||
| 560 | const parent = node.parent.get(mf); | ||
| 561 | _, const old_parent_size = parent.location().resolve(mf); | ||
| 562 | const trailing_end = switch (node.next) { | ||
| 563 | .none => parent.location().resolve(mf)[1], | ||
| 564 | else => |next_ni| next_ni.location(mf).resolve(mf)[0], | ||
| 565 | }; | ||
| 566 | assert(old_offset + old_size <= trailing_end); | ||
| 567 | // Expand the node into available trailing free space | ||
| 568 | if (old_offset + new_size <= trailing_end) { | ||
| 569 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 570 | ni.setLocationAssumeCapacity(mf, old_offset, new_size); | ||
| 571 | return; | ||
| 572 | } | ||
| 573 | // Ask the filesystem driver to insert an extent into the file without copying any data | ||
| 574 | if (is_linux and !mf.flags.fallocate_insert_range_unsupported and | ||
| 575 | node.flags.alignment.order(mf.flags.block_size).compare(.gte)) | ||
| 576 | insert_range: { | ||
| 577 | const last_offset, const last_size = parent.last.location(mf).resolve(mf); | ||
| 578 | const last_end = last_offset + last_size; | ||
| 579 | assert(last_end <= old_parent_size); | ||
| 580 | const range_size = | ||
| 581 | node.flags.alignment.forward(@intCast(requested_size +| requested_size / 2)) - old_size; | ||
| 582 | const new_parent_size = last_end + range_size; | ||
| 583 | if (new_parent_size > old_parent_size) { | ||
| 584 | try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2); | ||
| 585 | continue; | ||
| 586 | } | ||
| 587 | const range_file_offset = ni.fileLocation(mf, false).offset + old_size; | ||
| 588 | retry: while (true) { | ||
| 589 | switch (linux.E.init(linux.fallocate( | ||
| 590 | mf.file.handle, | ||
| 591 | linux.FALLOC.FL_INSERT_RANGE, | ||
| 592 | @intCast(range_file_offset), | ||
| 593 | @intCast(range_size), | ||
| 594 | ))) { | ||
| 595 | .SUCCESS => { | ||
| 596 | var enclosing_ni = ni; | ||
| 597 | while (enclosing_ni != .none) { | ||
| 598 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 599 | const enclosing = enclosing_ni.get(mf); | ||
| 600 | const enclosing_offset, const enclosing_size = | ||
| 601 | enclosing.location().resolve(mf); | ||
| 602 | enclosing_ni.setLocationAssumeCapacity( | ||
| 603 | mf, | ||
| 604 | enclosing_offset, | ||
| 605 | enclosing_size + range_size, | ||
| 606 | ); | ||
| 607 | var after_ni = enclosing.next; | ||
| 608 | while (after_ni != .none) { | ||
| 609 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 610 | const after = after_ni.get(mf); | ||
| 611 | const after_offset, const after_size = after.location().resolve(mf); | ||
| 612 | after_ni.setLocationAssumeCapacity( | ||
| 613 | mf, | ||
| 614 | range_size + after_offset, | ||
| 615 | after_size, | ||
| 616 | ); | ||
| 617 | after_ni = after.next; | ||
| 618 | } | ||
| 619 | enclosing_ni = enclosing.parent; | ||
| 620 | } | ||
| 621 | return; | ||
| 622 | }, | ||
| 623 | .INTR => continue :retry, | ||
| 624 | .BADF, .FBIG, .INVAL => unreachable, | ||
| 625 | .IO => return error.InputOutput, | ||
| 626 | .NODEV => return error.NotFile, | ||
| 627 | .NOSPC => return error.NoSpaceLeft, | ||
| 628 | .NOSYS, .OPNOTSUPP => { | ||
| 629 | mf.flags.fallocate_insert_range_unsupported = true; | ||
| 630 | break :insert_range; | ||
| 631 | }, | ||
| 632 | .PERM => return error.PermissionDenied, | ||
| 633 | .SPIPE => return error.Unseekable, | ||
| 634 | .TXTBSY => return error.FileBusy, | ||
| 635 | else => |e| return std.posix.unexpectedErrno(e), | ||
| 636 | } | ||
| 637 | } | ||
| 638 | } | ||
| 639 | switch (node.next) { | ||
| 640 | .none => { | ||
| 641 | // As this is the last node, we simply need more space in the parent | ||
| 642 | const new_parent_size = old_offset + new_size; | ||
| 643 | try mf.resizeNode(gpa, node.parent, new_parent_size +| new_parent_size / 2); | ||
| 644 | }, | ||
| 645 | else => |*next_ni_ptr| switch (node.flags.fixed) { | ||
| 646 | false => { | ||
| 647 | // Make space at the end of the parent for this floating node | ||
| 648 | const last = parent.last.get(mf); | ||
| 649 | const last_offset, const last_size = last.location().resolve(mf); | ||
| 650 | const new_offset = node.flags.alignment.forward(@intCast(last_offset + last_size)); | ||
| 651 | const new_parent_size = new_offset + new_size; | ||
| 652 | if (new_parent_size > old_parent_size) { | ||
| 653 | try mf.resizeNode( | ||
| 654 | gpa, | ||
| 655 | node.parent, | ||
| 656 | new_parent_size +| new_parent_size / 2, | ||
| 657 | ); | ||
| 658 | continue; | ||
| 659 | } | ||
| 660 | const next_ni = next_ni_ptr.*; | ||
| 661 | next_ni.get(mf).prev = node.prev; | ||
| 662 | switch (node.prev) { | ||
| 663 | .none => parent.first = next_ni, | ||
| 664 | else => |prev_ni| prev_ni.get(mf).next = next_ni, | ||
| 665 | } | ||
| 666 | last.next = ni; | ||
| 667 | node.prev = parent.last; | ||
| 668 | next_ni_ptr.* = .none; | ||
| 669 | parent.last = ni; | ||
| 670 | if (node.flags.has_content) { | ||
| 671 | const parent_file_offset = node.parent.fileLocation(mf, false).offset; | ||
| 672 | try mf.moveRange( | ||
| 673 | parent_file_offset + old_offset, | ||
| 674 | parent_file_offset + new_offset, | ||
| 675 | old_size, | ||
| 676 | ); | ||
| 677 | } | ||
| 678 | old_offset = new_offset; | ||
| 679 | }, | ||
| 680 | true => { | ||
| 681 | // Move the next floating node to make space for this fixed node | ||
| 682 | const next_ni = next_ni_ptr.*; | ||
| 683 | const next = next_ni.get(mf); | ||
| 684 | assert(!next.flags.fixed); | ||
| 685 | const next_offset, const next_size = next.location().resolve(mf); | ||
| 686 | const last = parent.last.get(mf); | ||
| 687 | const last_offset, const last_size = last.location().resolve(mf); | ||
| 688 | const new_offset = next.flags.alignment.forward(@intCast( | ||
| 689 | @max(old_offset + new_size, last_offset + last_size), | ||
| 690 | )); | ||
| 691 | const new_parent_size = new_offset + next_size; | ||
| 692 | if (new_parent_size > old_parent_size) { | ||
| 693 | try mf.resizeNode( | ||
| 694 | gpa, | ||
| 695 | node.parent, | ||
| 696 | new_parent_size +| new_parent_size / 2, | ||
| 697 | ); | ||
| 698 | continue; | ||
| 699 | } | ||
| 700 | try mf.ensureCapacityForSetLocation(gpa); | ||
| 701 | next.prev = parent.last; | ||
| 702 | parent.last = next_ni; | ||
| 703 | last.next = next_ni; | ||
| 704 | next_ni_ptr.* = next.next; | ||
| 705 | switch (next.next) { | ||
| 706 | .none => {}, | ||
| 707 | else => |next_next_ni| next_next_ni.get(mf).prev = ni, | ||
| 708 | } | ||
| 709 | next.next = .none; | ||
| 710 | if (node.flags.has_content) { | ||
| 711 | const parent_file_offset = node.parent.fileLocation(mf, false).offset; | ||
| 712 | try mf.moveRange( | ||
| 713 | parent_file_offset + next_offset, | ||
| 714 | parent_file_offset + new_offset, | ||
| 715 | next_size, | ||
| 716 | ); | ||
| 717 | } | ||
| 718 | next_ni.setLocationAssumeCapacity(mf, new_offset, next_size); | ||
| 719 | }, | ||
| 720 | }, | ||
| 721 | } | ||
| 722 | } | ||
| 723 | } | ||
| 724 | |||
| 725 | fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { | ||
| 726 | // make a copy of this node at the new location | ||
| 727 | try mf.copyRange(old_file_offset, new_file_offset, size); | ||
| 728 | // delete the copy of this node at the old location | ||
| 729 | if (is_linux and !mf.flags.fallocate_punch_hole_unsupported and | ||
| 730 | size >= mf.flags.block_size.toByteUnits() * 2 - 1) while (true) | ||
| 731 | { | ||
| 732 | switch (linux.E.init(linux.fallocate( | ||
| 733 | mf.file.handle, | ||
| 734 | linux.FALLOC.FL_PUNCH_HOLE | linux.FALLOC.FL_KEEP_SIZE, | ||
| 735 | @intCast(old_file_offset), | ||
| 736 | @intCast(size), | ||
| 737 | ))) { | ||
| 738 | .SUCCESS => return, | ||
| 739 | .INTR => continue, | ||
| 740 | .BADF, .FBIG, .INVAL => unreachable, | ||
| 741 | .IO => return error.InputOutput, | ||
| 742 | .NODEV => return error.NotFile, | ||
| 743 | .NOSPC => return error.NoSpaceLeft, | ||
| 744 | .NOSYS, .OPNOTSUPP => { | ||
| 745 | mf.flags.fallocate_punch_hole_unsupported = true; | ||
| 746 | break; | ||
| 747 | }, | ||
| 748 | .PERM => return error.PermissionDenied, | ||
| 749 | .SPIPE => return error.Unseekable, | ||
| 750 | .TXTBSY => return error.FileBusy, | ||
| 751 | else => |e| return std.posix.unexpectedErrno(e), | ||
| 752 | } | ||
| 753 | }; | ||
| 754 | @memset(mf.contents[@intCast(old_file_offset)..][0..@intCast(size)], 0); | ||
| 755 | } | ||
| 756 | |||
| 757 | fn copyRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) !void { | ||
| 758 | const copy_size = try mf.copyFileRange(mf.file, old_file_offset, new_file_offset, size); | ||
| 759 | if (copy_size < size) @memcpy( | ||
| 760 | mf.contents[@intCast(new_file_offset + copy_size)..][0..@intCast(size - copy_size)], | ||
| 761 | mf.contents[@intCast(old_file_offset + copy_size)..][0..@intCast(size - copy_size)], | ||
| 762 | ); | ||
| 763 | } | ||
| 764 | |||
| 765 | fn copyFileRange( | ||
| 766 | mf: *MappedFile, | ||
| 767 | old_file: std.fs.File, | ||
| 768 | old_file_offset: u64, | ||
| 769 | new_file_offset: u64, | ||
| 770 | size: u64, | ||
| 771 | ) !u64 { | ||
| 772 | var remaining_size = size; | ||
| 773 | if (is_linux and !mf.flags.copy_file_range_unsupported) { | ||
| 774 | var old_file_offset_mut: i64 = @intCast(old_file_offset); | ||
| 775 | var new_file_offset_mut: i64 = @intCast(new_file_offset); | ||
| 776 | while (remaining_size >= mf.flags.block_size.toByteUnits() * 2 - 1) { | ||
| 777 | const copy_len = linux.copy_file_range( | ||
| 778 | old_file.handle, | ||
| 779 | &old_file_offset_mut, | ||
| 780 | mf.file.handle, | ||
| 781 | &new_file_offset_mut, | ||
| 782 | @intCast(remaining_size), | ||
| 783 | 0, | ||
| 784 | ); | ||
| 785 | switch (linux.E.init(copy_len)) { | ||
| 786 | .SUCCESS => { | ||
| 787 | if (copy_len == 0) break; | ||
| 788 | remaining_size -= copy_len; | ||
| 789 | if (remaining_size == 0) break; | ||
| 790 | }, | ||
| 791 | .INTR => continue, | ||
| 792 | .BADF, .FBIG, .INVAL, .OVERFLOW => unreachable, | ||
| 793 | .IO => return error.InputOutput, | ||
| 794 | .ISDIR => return error.IsDir, | ||
| 795 | .NOMEM => return error.SystemResources, | ||
| 796 | .NOSPC => return error.NoSpaceLeft, | ||
| 797 | .NOSYS, .OPNOTSUPP, .XDEV => { | ||
| 798 | mf.flags.copy_file_range_unsupported = true; | ||
| 799 | break; | ||
| 800 | }, | ||
| 801 | .PERM => return error.PermissionDenied, | ||
| 802 | .TXTBSY => return error.FileBusy, | ||
| 803 | else => |e| return std.posix.unexpectedErrno(e), | ||
| 804 | } | ||
| 805 | } | ||
| 806 | } | ||
| 807 | return size - remaining_size; | ||
| 808 | } | ||
| 809 | |||
| 810 | fn ensureCapacityForSetLocation(mf: *MappedFile, gpa: std.mem.Allocator) !void { | ||
| 811 | try mf.large.ensureUnusedCapacity(gpa, 2); | ||
| 812 | try mf.updates.ensureUnusedCapacity(gpa, 1); | ||
| 813 | } | ||
| 814 | |||
| 815 | pub fn ensureTotalCapacity(mf: *MappedFile, new_capacity: usize) !void { | ||
| 816 | if (mf.contents.len >= new_capacity) return; | ||
| 817 | try mf.ensureTotalCapacityPrecise(new_capacity +| new_capacity / 2); | ||
| 818 | } | ||
| 819 | |||
| 820 | pub fn ensureTotalCapacityPrecise(mf: *MappedFile, new_capacity: usize) !void { | ||
| 821 | if (mf.contents.len >= new_capacity) return; | ||
| 822 | const aligned_capacity = mf.flags.block_size.forward(new_capacity); | ||
| 823 | if (!is_linux) mf.unmap() else if (mf.contents.len > 0) { | ||
| 824 | mf.contents = try std.posix.mremap( | ||
| 825 | mf.contents.ptr, | ||
| 826 | mf.contents.len, | ||
| 827 | aligned_capacity, | ||
| 828 | .{ .MAYMOVE = true }, | ||
| 829 | null, | ||
| 830 | ); | ||
| 831 | return; | ||
| 832 | } | ||
| 833 | if (is_windows) { | ||
| 834 | if (mf.section == windows.INVALID_HANDLE_VALUE) switch (windows.ntdll.NtCreateSection( | ||
| 835 | &mf.section, | ||
| 836 | windows.STANDARD_RIGHTS_REQUIRED | windows.SECTION_QUERY | | ||
| 837 | windows.SECTION_MAP_WRITE | windows.SECTION_MAP_READ | windows.SECTION_EXTEND_SIZE, | ||
| 838 | null, | ||
| 839 | @constCast(&@as(i64, @intCast(aligned_capacity))), | ||
| 840 | windows.PAGE_READWRITE, | ||
| 841 | windows.SEC_COMMIT, | ||
| 842 | mf.file.handle, | ||
| 843 | )) { | ||
| 844 | .SUCCESS => {}, | ||
| 845 | else => return error.MemoryMappingNotSupported, | ||
| 846 | }; | ||
| 847 | var contents_ptr: ?[*]align(std.heap.page_size_min) u8 = null; | ||
| 848 | var contents_len = aligned_capacity; | ||
| 849 | switch (windows.ntdll.NtMapViewOfSection( | ||
| 850 | mf.section, | ||
| 851 | windows.GetCurrentProcess(), | ||
| 852 | @ptrCast(&contents_ptr), | ||
| 853 | null, | ||
| 854 | 0, | ||
| 855 | null, | ||
| 856 | &contents_len, | ||
| 857 | .ViewUnmap, | ||
| 858 | 0, | ||
| 859 | windows.PAGE_READWRITE, | ||
| 860 | )) { | ||
| 861 | .SUCCESS => mf.contents = contents_ptr.?[0..contents_len], | ||
| 862 | else => return error.MemoryMappingNotSupported, | ||
| 863 | } | ||
| 864 | } else mf.contents = try std.posix.mmap( | ||
| 865 | null, | ||
| 866 | aligned_capacity, | ||
| 867 | std.posix.PROT.READ | std.posix.PROT.WRITE, | ||
| 868 | .{ .TYPE = if (is_linux) .SHARED_VALIDATE else .SHARED }, | ||
| 869 | mf.file.handle, | ||
| 870 | 0, | ||
| 871 | ); | ||
| 872 | } | ||
| 873 | |||
| 874 | pub fn unmap(mf: *MappedFile) void { | ||
| 875 | if (mf.contents.len == 0) return; | ||
| 876 | if (is_windows) | ||
| 877 | _ = windows.ntdll.NtUnmapViewOfSection(windows.GetCurrentProcess(), mf.contents.ptr) | ||
| 878 | else | ||
| 879 | std.posix.munmap(mf.contents); | ||
| 880 | mf.contents = &.{}; | ||
| 881 | if (is_windows and mf.section != windows.INVALID_HANDLE_VALUE) { | ||
| 882 | windows.CloseHandle(mf.section); | ||
| 883 | mf.section = windows.INVALID_HANDLE_VALUE; | ||
| 884 | } | ||
| 885 | } | ||
| 886 | |||
| 887 | fn verify(mf: *MappedFile) void { | ||
| 888 | const root = Node.Index.root.get(mf); | ||
| 889 | assert(root.parent == .none); | ||
| 890 | assert(root.prev == .none); | ||
| 891 | assert(root.next == .none); | ||
| 892 | mf.verifyNode(Node.Index.root); | ||
| 893 | } | ||
| 894 | |||
| 895 | fn verifyNode(mf: *MappedFile, parent_ni: Node.Index) void { | ||
| 896 | const parent = parent_ni.get(mf); | ||
| 897 | const parent_offset, const parent_size = parent.location().resolve(mf); | ||
| 898 | var prev_ni: Node.Index = .none; | ||
| 899 | var prev_end: u64 = 0; | ||
| 900 | var ni = parent.first; | ||
| 901 | while (true) { | ||
| 902 | if (ni == .none) { | ||
| 903 | assert(parent.last == prev_ni); | ||
| 904 | return; | ||
| 905 | } | ||
| 906 | const node = ni.get(mf); | ||
| 907 | assert(node.parent == parent_ni); | ||
| 908 | const offset, const size = node.location().resolve(mf); | ||
| 909 | assert(node.flags.alignment.check(@intCast(offset))); | ||
| 910 | assert(node.flags.alignment.check(@intCast(size))); | ||
| 911 | const end = offset + size; | ||
| 912 | assert(end <= parent_offset + parent_size); | ||
| 913 | assert(offset >= prev_end); | ||
| 914 | assert(node.prev == prev_ni); | ||
| 915 | mf.verifyNode(ni); | ||
| 916 | prev_ni = ni; | ||
| 917 | prev_end = end; | ||
| 918 | ni = node.next; | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | const assert = std.debug.assert; | ||
| 923 | const builtin = @import("builtin"); | ||
| 924 | const is_linux = builtin.os.tag == .linux; | ||
| 925 | const is_windows = builtin.os.tag == .windows; | ||
| 926 | const linux = std.os.linux; | ||
| 927 | const MappedFile = @This(); | ||
| 928 | const std = @import("std"); | ||
| 929 | const windows = std.os.windows; | ||
src/link/Queue.zig+56-24| ... | @@ -22,17 +22,17 @@ prelink_wait_count: u32, | ... | @@ -22,17 +22,17 @@ prelink_wait_count: u32, |
| 22 | 22 | ||
| 23 | /// Prelink tasks which have been enqueued and are not yet owned by the worker thread. | 23 | /// Prelink tasks which have been enqueued and are not yet owned by the worker thread. |
| 24 | /// Allocated into `gpa`, guarded by `mutex`. | 24 | /// Allocated into `gpa`, guarded by `mutex`. |
| 25 | queued_prelink: std.ArrayListUnmanaged(PrelinkTask), | 25 | queued_prelink: std.ArrayList(PrelinkTask), |
| 26 | /// The worker thread moves items from `queued_prelink` into this array in order to process them. | 26 | /// The worker thread moves items from `queued_prelink` into this array in order to process them. |
| 27 | /// Allocated into `gpa`, accessed only by the worker thread. | 27 | /// Allocated into `gpa`, accessed only by the worker thread. |
| 28 | wip_prelink: std.ArrayListUnmanaged(PrelinkTask), | 28 | wip_prelink: std.ArrayList(PrelinkTask), |
| 29 | 29 | ||
| 30 | /// Like `queued_prelink`, but for ZCU tasks. | 30 | /// Like `queued_prelink`, but for ZCU tasks. |
| 31 | /// Allocated into `gpa`, guarded by `mutex`. | 31 | /// Allocated into `gpa`, guarded by `mutex`. |
| 32 | queued_zcu: std.ArrayListUnmanaged(ZcuTask), | 32 | queued_zcu: std.ArrayList(ZcuTask), |
| 33 | /// Like `wip_prelink`, but for ZCU tasks. | 33 | /// Like `wip_prelink`, but for ZCU tasks. |
| 34 | /// Allocated into `gpa`, accessed only by the worker thread. | 34 | /// Allocated into `gpa`, accessed only by the worker thread. |
| 35 | wip_zcu: std.ArrayListUnmanaged(ZcuTask), | 35 | wip_zcu: std.ArrayList(ZcuTask), |
| 36 | 36 | ||
| 37 | /// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this | 37 | /// When processing ZCU link tasks, we might have to block due to unpopulated MIR. When this |
| 38 | /// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the | 38 | /// happens, some tasks in `wip_zcu` have been run, and some are still pending. This is the |
| ... | @@ -213,32 +213,41 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error! | ... | @@ -213,32 +213,41 @@ pub fn enqueueZcu(q: *Queue, comp: *Compilation, task: ZcuTask) Allocator.Error! |
| 213 | 213 | ||
| 214 | fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { | 214 | fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 215 | q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex` | 215 | q.flush_safety.lock(); // every `return` site should unlock this before unlocking `q.mutex` |
| 216 | |||
| 217 | if (std.debug.runtime_safety) { | 216 | if (std.debug.runtime_safety) { |
| 218 | q.mutex.lock(); | 217 | q.mutex.lock(); |
| 219 | defer q.mutex.unlock(); | 218 | defer q.mutex.unlock(); |
| 220 | assert(q.state == .running); | 219 | assert(q.state == .running); |
| 221 | } | 220 | } |
| 221 | |||
| 222 | var have_idle_tasks = true; | ||
| 222 | prelink: while (true) { | 223 | prelink: while (true) { |
| 223 | assert(q.wip_prelink.items.len == 0); | 224 | assert(q.wip_prelink.items.len == 0); |
| 224 | { | 225 | swap_queues: while (true) { |
| 225 | q.mutex.lock(); | 226 | { |
| 226 | defer q.mutex.unlock(); | 227 | q.mutex.lock(); |
| 227 | std.mem.swap(std.ArrayListUnmanaged(PrelinkTask), &q.queued_prelink, &q.wip_prelink); | 228 | defer q.mutex.unlock(); |
| 228 | if (q.wip_prelink.items.len == 0) { | 229 | std.mem.swap(std.ArrayList(PrelinkTask), &q.queued_prelink, &q.wip_prelink); |
| 229 | if (q.prelink_wait_count == 0) { | 230 | if (q.wip_prelink.items.len > 0) break :swap_queues; |
| 230 | break :prelink; // prelink is done | 231 | if (q.prelink_wait_count == 0) break :prelink; // prelink is done |
| 231 | } else { | 232 | if (!have_idle_tasks) { |
| 232 | // We're expecting more prelink tasks so can't move on to ZCU tasks. | 233 | // We're expecting more prelink tasks so can't move on to ZCU tasks. |
| 233 | q.state = .finished; | 234 | q.state = .finished; |
| 234 | q.flush_safety.unlock(); | 235 | q.flush_safety.unlock(); |
| 235 | return; | 236 | return; |
| 236 | } | 237 | } |
| 237 | } | 238 | } |
| 239 | have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { | ||
| 240 | error.OutOfMemory => have_idle_tasks: { | ||
| 241 | comp.link_diags.setAllocFailure(); | ||
| 242 | break :have_idle_tasks false; | ||
| 243 | }, | ||
| 244 | error.LinkFailure => false, | ||
| 245 | }; | ||
| 238 | } | 246 | } |
| 239 | for (q.wip_prelink.items) |task| { | 247 | for (q.wip_prelink.items) |task| { |
| 240 | link.doPrelinkTask(comp, task); | 248 | link.doPrelinkTask(comp, task); |
| 241 | } | 249 | } |
| 250 | have_idle_tasks = true; | ||
| 242 | q.wip_prelink.clearRetainingCapacity(); | 251 | q.wip_prelink.clearRetainingCapacity(); |
| 243 | } | 252 | } |
| 244 | 253 | ||
| ... | @@ -256,17 +265,29 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { | ... | @@ -256,17 +265,29 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 256 | 265 | ||
| 257 | // Now we can run ZCU tasks. | 266 | // Now we can run ZCU tasks. |
| 258 | while (true) { | 267 | while (true) { |
| 259 | if (q.wip_zcu.items.len == q.wip_zcu_idx) { | 268 | if (q.wip_zcu.items.len == q.wip_zcu_idx) swap_queues: { |
| 260 | q.wip_zcu.clearRetainingCapacity(); | 269 | q.wip_zcu.clearRetainingCapacity(); |
| 261 | q.wip_zcu_idx = 0; | 270 | q.wip_zcu_idx = 0; |
| 262 | q.mutex.lock(); | 271 | while (true) { |
| 263 | defer q.mutex.unlock(); | 272 | { |
| 264 | std.mem.swap(std.ArrayListUnmanaged(ZcuTask), &q.queued_zcu, &q.wip_zcu); | 273 | q.mutex.lock(); |
| 265 | if (q.wip_zcu.items.len == 0) { | 274 | defer q.mutex.unlock(); |
| 266 | // We've exhausted all available tasks. | 275 | std.mem.swap(std.ArrayList(ZcuTask), &q.queued_zcu, &q.wip_zcu); |
| 267 | q.state = .finished; | 276 | if (q.wip_zcu.items.len > 0) break :swap_queues; |
| 268 | q.flush_safety.unlock(); | 277 | if (!have_idle_tasks) { |
| 269 | return; | 278 | // We've exhausted all available tasks. |
| 279 | q.state = .finished; | ||
| 280 | q.flush_safety.unlock(); | ||
| 281 | return; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { | ||
| 285 | error.OutOfMemory => have_idle_tasks: { | ||
| 286 | comp.link_diags.setAllocFailure(); | ||
| 287 | break :have_idle_tasks false; | ||
| 288 | }, | ||
| 289 | error.LinkFailure => false, | ||
| 290 | }; | ||
| 270 | } | 291 | } |
| 271 | } | 292 | } |
| 272 | const task = q.wip_zcu.items[q.wip_zcu_idx]; | 293 | const task = q.wip_zcu.items[q.wip_zcu_idx]; |
| ... | @@ -274,8 +295,18 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { | ... | @@ -274,8 +295,18 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 274 | pending: { | 295 | pending: { |
| 275 | if (task != .link_func) break :pending; | 296 | if (task != .link_func) break :pending; |
| 276 | const status_ptr = &task.link_func.mir.status; | 297 | const status_ptr = &task.link_func.mir.status; |
| 277 | // First check without the mutex to optimize for the common case where MIR is ready. | 298 | while (true) { |
| 278 | if (status_ptr.load(.acquire) != .pending) break :pending; | 299 | // First check without the mutex to optimize for the common case where MIR is ready. |
| 300 | if (status_ptr.load(.acquire) != .pending) break :pending; | ||
| 301 | if (have_idle_tasks) have_idle_tasks = link.doIdleTask(comp, tid) catch |err| switch (err) { | ||
| 302 | error.OutOfMemory => have_idle_tasks: { | ||
| 303 | comp.link_diags.setAllocFailure(); | ||
| 304 | break :have_idle_tasks false; | ||
| 305 | }, | ||
| 306 | error.LinkFailure => false, | ||
| 307 | }; | ||
| 308 | if (!have_idle_tasks) break; | ||
| 309 | } | ||
| 279 | q.mutex.lock(); | 310 | q.mutex.lock(); |
| 280 | defer q.mutex.unlock(); | 311 | defer q.mutex.unlock(); |
| 281 | if (status_ptr.load(.acquire) != .pending) break :pending; | 312 | if (status_ptr.load(.acquire) != .pending) break :pending; |
| ... | @@ -298,6 +329,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { | ... | @@ -298,6 +329,7 @@ fn flushTaskQueue(tid: usize, q: *Queue, comp: *Compilation) void { |
| 298 | } | 329 | } |
| 299 | } | 330 | } |
| 300 | q.wip_zcu_idx += 1; | 331 | q.wip_zcu_idx += 1; |
| 332 | have_idle_tasks = true; | ||
| 301 | } | 333 | } |
| 302 | } | 334 | } |
| 303 | 335 |
src/link/Wasm.zig+8-1| ... | @@ -4257,7 +4257,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu | ... | @@ -4257,7 +4257,14 @@ fn lowerZcuData(wasm: *Wasm, pt: Zcu.PerThread, ip_index: InternPool.Index) !Zcu |
| 4257 | const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len); | 4257 | const func_table_fixups_start: u32 = @intCast(wasm.func_table_fixups.items.len); |
| 4258 | wasm.string_bytes_lock.lock(); | 4258 | wasm.string_bytes_lock.lock(); |
| 4259 | 4259 | ||
| 4260 | try codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &wasm.string_bytes, .none); | 4260 | { |
| 4261 | var aw: std.Io.Writer.Allocating = .fromArrayList(wasm.base.comp.gpa, &wasm.string_bytes); | ||
| 4262 | defer wasm.string_bytes = aw.toArrayList(); | ||
| 4263 | codegen.generateSymbol(&wasm.base, pt, .unneeded, .fromInterned(ip_index), &aw.writer, .none) catch |err| switch (err) { | ||
| 4264 | error.WriteFailed => return error.OutOfMemory, | ||
| 4265 | else => |e| return e, | ||
| 4266 | }; | ||
| 4267 | } | ||
| 4261 | 4268 | ||
| 4262 | const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start); | 4269 | const code_len: u32 = @intCast(wasm.string_bytes.items.len - code_start); |
| 4263 | const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start); | 4270 | const relocs_len: u32 = @intCast(wasm.out_relocs.len - relocs_start); |
src/main.zig+9-5| ... | @@ -904,7 +904,6 @@ fn buildOutputType( | ... | @@ -904,7 +904,6 @@ fn buildOutputType( |
| 904 | var mingw_unicode_entry_point: bool = false; | 904 | var mingw_unicode_entry_point: bool = false; |
| 905 | var enable_link_snapshots: bool = false; | 905 | var enable_link_snapshots: bool = false; |
| 906 | var debug_compiler_runtime_libs = false; | 906 | var debug_compiler_runtime_libs = false; |
| 907 | var opt_incremental: ?bool = null; | ||
| 908 | var install_name: ?[]const u8 = null; | 907 | var install_name: ?[]const u8 = null; |
| 909 | var hash_style: link.File.Lld.Elf.HashStyle = .both; | 908 | var hash_style: link.File.Lld.Elf.HashStyle = .both; |
| 910 | var entitlements: ?[]const u8 = null; | 909 | var entitlements: ?[]const u8 = null; |
| ... | @@ -1374,9 +1373,9 @@ fn buildOutputType( | ... | @@ -1374,9 +1373,9 @@ fn buildOutputType( |
| 1374 | } | 1373 | } |
| 1375 | } else if (mem.eql(u8, arg, "-fincremental")) { | 1374 | } else if (mem.eql(u8, arg, "-fincremental")) { |
| 1376 | dev.check(.incremental); | 1375 | dev.check(.incremental); |
| 1377 | opt_incremental = true; | 1376 | create_module.opts.incremental = true; |
| 1378 | } else if (mem.eql(u8, arg, "-fno-incremental")) { | 1377 | } else if (mem.eql(u8, arg, "-fno-incremental")) { |
| 1379 | opt_incremental = false; | 1378 | create_module.opts.incremental = false; |
| 1380 | } else if (mem.eql(u8, arg, "--entitlements")) { | 1379 | } else if (mem.eql(u8, arg, "--entitlements")) { |
| 1381 | entitlements = args_iter.nextOrFatal(); | 1380 | entitlements = args_iter.nextOrFatal(); |
| 1382 | } else if (mem.eql(u8, arg, "-fcompiler-rt")) { | 1381 | } else if (mem.eql(u8, arg, "-fcompiler-rt")) { |
| ... | @@ -1479,6 +1478,10 @@ fn buildOutputType( | ... | @@ -1479,6 +1478,10 @@ fn buildOutputType( |
| 1479 | create_module.opts.use_lld = true; | 1478 | create_module.opts.use_lld = true; |
| 1480 | } else if (mem.eql(u8, arg, "-fno-lld")) { | 1479 | } else if (mem.eql(u8, arg, "-fno-lld")) { |
| 1481 | create_module.opts.use_lld = false; | 1480 | create_module.opts.use_lld = false; |
| 1481 | } else if (mem.eql(u8, arg, "-fnew-linker")) { | ||
| 1482 | create_module.opts.use_new_linker = true; | ||
| 1483 | } else if (mem.eql(u8, arg, "-fno-new-linker")) { | ||
| 1484 | create_module.opts.use_new_linker = false; | ||
| 1482 | } else if (mem.eql(u8, arg, "-fclang")) { | 1485 | } else if (mem.eql(u8, arg, "-fclang")) { |
| 1483 | create_module.opts.use_clang = true; | 1486 | create_module.opts.use_clang = true; |
| 1484 | } else if (mem.eql(u8, arg, "-fno-clang")) { | 1487 | } else if (mem.eql(u8, arg, "-fno-clang")) { |
| ... | @@ -3371,7 +3374,7 @@ fn buildOutputType( | ... | @@ -3371,7 +3374,7 @@ fn buildOutputType( |
| 3371 | else => false, | 3374 | else => false, |
| 3372 | }; | 3375 | }; |
| 3373 | 3376 | ||
| 3374 | const incremental = opt_incremental orelse false; | 3377 | const incremental = create_module.resolved_options.incremental; |
| 3375 | if (debug_incremental and !incremental) { | 3378 | if (debug_incremental and !incremental) { |
| 3376 | fatal("--debug-incremental requires -fincremental", .{}); | 3379 | fatal("--debug-incremental requires -fincremental", .{}); |
| 3377 | } | 3380 | } |
| ... | @@ -3502,7 +3505,6 @@ fn buildOutputType( | ... | @@ -3502,7 +3505,6 @@ fn buildOutputType( |
| 3502 | .subsystem = subsystem, | 3505 | .subsystem = subsystem, |
| 3503 | .debug_compile_errors = debug_compile_errors, | 3506 | .debug_compile_errors = debug_compile_errors, |
| 3504 | .debug_incremental = debug_incremental, | 3507 | .debug_incremental = debug_incremental, |
| 3505 | .incremental = incremental, | ||
| 3506 | .enable_link_snapshots = enable_link_snapshots, | 3508 | .enable_link_snapshots = enable_link_snapshots, |
| 3507 | .install_name = install_name, | 3509 | .install_name = install_name, |
| 3508 | .entitlements = entitlements, | 3510 | .entitlements = entitlements, |
| ... | @@ -4016,6 +4018,8 @@ fn createModule( | ... | @@ -4016,6 +4018,8 @@ fn createModule( |
| 4016 | error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}), | 4018 | error.LldUnavailable => fatal("zig was compiled without LLD libraries", .{}), |
| 4017 | error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}), | 4019 | error.ClangUnavailable => fatal("zig was compiled without Clang libraries", .{}), |
| 4018 | error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}), | 4020 | error.DllExportFnsRequiresWindows => fatal("only Windows OS targets support DLLs", .{}), |
| 4021 | error.NewLinkerIncompatibleObjectFormat => fatal("using the new linker to link {s} files is unsupported", .{@tagName(target.ofmt)}), | ||
| 4022 | error.NewLinkerIncompatibleWithLld => fatal("using the new linker is incompatible with using lld", .{}), | ||
| 4019 | }; | 4023 | }; |
| 4020 | } | 4024 | } |
| 4021 | 4025 |
src/target.zig+7| ... | @@ -231,6 +231,13 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { | ... | @@ -231,6 +231,13 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool { |
| 231 | }; | 231 | }; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | pub fn hasNewLinkerSupport(ofmt: std.Target.ObjectFormat) bool { | ||
| 235 | return switch (ofmt) { | ||
| 236 | .elf => true, | ||
| 237 | else => false, | ||
| 238 | }; | ||
| 239 | } | ||
| 240 | |||
| 234 | /// The set of targets that our own self-hosted backends have robust support for. | 241 | /// The set of targets that our own self-hosted backends have robust support for. |
| 235 | /// Used to select between LLVM backend and self-hosted backend when compiling in | 242 | /// Used to select between LLVM backend and self-hosted backend when compiling in |
| 236 | /// debug mode. A given target should only return true here if it is passing greater | 243 | /// debug mode. A given target should only return true here if it is passing greater |
test/incremental/change_exports+1-1| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | //#target=x86_64-linux-selfhosted | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-linux-cbe | 2 | #target=x86_64-linux-cbe |
| 3 | #target=x86_64-windows-cbe | 3 | #target=x86_64-windows-cbe |
| 4 | 4 |
test/incremental/change_panic_handler+1| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | #target=x86_64-linux-selfhosted | ||
| 1 | #target=x86_64-linux-cbe | 2 | #target=x86_64-linux-cbe |
| 2 | #target=x86_64-windows-cbe | 3 | #target=x86_64-windows-cbe |
| 3 | #update=initial version | 4 | #update=initial version |
test/incremental/change_panic_handler_explicit+1| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | #target=x86_64-linux-selfhosted | ||
| 1 | #target=x86_64-linux-cbe | 2 | #target=x86_64-linux-cbe |
| 2 | #target=x86_64-windows-cbe | 3 | #target=x86_64-windows-cbe |
| 3 | #update=initial version | 4 | #update=initial version |
test/incremental/change_struct_same_fields+1-1| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | //#target=x86_64-linux-selfhosted | 1 | #target=x86_64-linux-selfhosted |
| 2 | #target=x86_64-linux-cbe | 2 | #target=x86_64-linux-cbe |
| 3 | #target=x86_64-windows-cbe | 3 | #target=x86_64-windows-cbe |
| 4 | #target=wasm32-wasi-selfhosted | 4 | #target=wasm32-wasi-selfhosted |
test/incremental/type_becomes_comptime_only+1| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | #target=x86_64-linux-selfhosted | ||
| 1 | #target=x86_64-linux-cbe | 2 | #target=x86_64-linux-cbe |
| 2 | #target=x86_64-windows-cbe | 3 | #target=x86_64-windows-cbe |
| 3 | #target=wasm32-wasi-selfhosted | 4 | #target=wasm32-wasi-selfhosted |