authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-08-27 15:06:07-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-27 15:06:07-04:00
log1a178d499537b922ff05c5d0186ed5a00dbb1a9b
treeeb0bbade490e385b46942628016d34dd32515c86
parent93cb44c80582dd02b63b02e7bb7e54d7ad8a4ebc
parentf289b82d0efda77b72ccf9c826023e904f9ffcab
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21210 from jacobly0/eh-frame

Dwarf: implement .eh_frame

27 files changed, 1419 insertions(+), 346 deletions(-)

ci/x86_64-linux-debug.sh+1-1
...@@ -64,7 +64,7 @@ stage3-debug/bin/zig build \...@@ -64,7 +64,7 @@ stage3-debug/bin/zig build \
6464
65stage3-debug/bin/zig build test docs \65stage3-debug/bin/zig build test docs \
66 --maxrss 21000000000 \66 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Debug-62538077d/bin/lldb \67 -Dlldb=$HOME/deps/lldb-zig/Debug-70b8227f1/bin/lldb \
68 -fqemu \68 -fqemu \
69 -fwasmtime \69 -fwasmtime \
70 -Dstatic-llvm \70 -Dstatic-llvm \
ci/x86_64-linux-release.sh+1-1
...@@ -64,7 +64,7 @@ stage3-release/bin/zig build \...@@ -64,7 +64,7 @@ stage3-release/bin/zig build \
6464
65stage3-release/bin/zig build test docs \65stage3-release/bin/zig build test docs \
66 --maxrss 21000000000 \66 --maxrss 21000000000 \
67 -Dlldb=$HOME/deps/lldb-zig/Release-62538077d/bin/lldb \67 -Dlldb=$HOME/deps/lldb-zig/Release-70b8227f1/bin/lldb \
68 -fqemu \68 -fqemu \
69 -fwasmtime \69 -fwasmtime \
70 -Dstatic-llvm \70 -Dstatic-llvm \
lib/std/leb128.zig+1-1
...@@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;...@@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;
125pub fn writeIleb128(writer: anytype, arg: anytype) !void {125pub fn writeIleb128(writer: anytype, arg: anytype) !void {
126 const Arg = @TypeOf(arg);126 const Arg = @TypeOf(arg);
127 const Int = switch (Arg) {127 const Int = switch (Arg) {
128 comptime_int => std.math.IntFittingRange(-arg - 1, arg),128 comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)),
129 else => Arg,129 else => Arg,
130 };130 };
131 const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;131 const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;
lib/std/os/linux/x86_64.zig+3-2
...@@ -114,14 +114,15 @@ pub fn clone() callconv(.Naked) usize {...@@ -114,14 +114,15 @@ pub fn clone() callconv(.Naked) usize {
114 \\ movq %%rcx,(%%rsi)114 \\ movq %%rcx,(%%rsi)
115 \\ syscall115 \\ syscall
116 \\ testq %%rax,%%rax116 \\ testq %%rax,%%rax
117 \\ jnz 1f117 \\ jz 1f
118 \\ retq
119 \\1: .cfi_undefined %%rip
118 \\ xorl %%ebp,%%ebp120 \\ xorl %%ebp,%%ebp
119 \\ popq %%rdi121 \\ popq %%rdi
120 \\ callq *%%r9122 \\ callq *%%r9
121 \\ movl %%eax,%%edi123 \\ movl %%eax,%%edi
122 \\ movl $60,%%eax // SYS_exit124 \\ movl $60,%%eax // SYS_exit
123 \\ syscall125 \\ syscall
124 \\1: ret
125 \\126 \\
126 );127 );
127}128}
lib/std/start.zig+1
...@@ -249,6 +249,7 @@ fn _start() callconv(.Naked) noreturn {...@@ -249,6 +249,7 @@ fn _start() callconv(.Naked) noreturn {
249 // linker explicitly.249 // linker explicitly.
250 asm volatile (switch (native_arch) {250 asm volatile (switch (native_arch) {
251 .x86_64 =>251 .x86_64 =>
252 \\ .cfi_undefined %%rip
252 \\ xorl %%ebp, %%ebp253 \\ xorl %%ebp, %%ebp
253 \\ movq %%rsp, %%rdi254 \\ movq %%rsp, %%rdi
254 \\ andq $-16, %%rsp255 \\ andq $-16, %%rsp
src/Air.zig+4-1
...@@ -13,6 +13,7 @@ const Value = @import("Value.zig");...@@ -13,6 +13,7 @@ const Value = @import("Value.zig");
13const Type = @import("Type.zig");13const Type = @import("Type.zig");
14const InternPool = @import("InternPool.zig");14const InternPool = @import("InternPool.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const types_resolved = @import("Air/types_resolved.zig");
1617
17instructions: std.MultiArrayList(Inst).Slice,18instructions: std.MultiArrayList(Inst).Slice,
18/// The meaning of this data is determined by `Inst.Tag` value.19/// The meaning of this data is determined by `Inst.Tag` value.
...@@ -1899,4 +1900,6 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch {...@@ -1899,4 +1900,6 @@ pub fn unwrapSwitch(air: *const Air, switch_inst: Inst.Index) UnwrappedSwitch {
1899 };1900 };
1900}1901}
19011902
1902pub const typesFullyResolved = @import("Air/types_resolved.zig").typesFullyResolved;1903pub const typesFullyResolved = types_resolved.typesFullyResolved;
1904pub const typeFullyResolved = types_resolved.checkType;
1905pub const valFullyResolved = types_resolved.checkVal;
src/Air/types_resolved.zig+8-4
...@@ -432,8 +432,10 @@ fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {...@@ -432,8 +432,10 @@ fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
432 return checkVal(Value.fromInterned(ip_index), zcu);432 return checkVal(Value.fromInterned(ip_index), zcu);
433}433}
434434
435fn checkVal(val: Value, zcu: *Zcu) bool {435pub fn checkVal(val: Value, zcu: *Zcu) bool {
436 if (!checkType(val.typeOf(zcu), zcu)) return false;436 const ty = val.typeOf(zcu);
437 if (!checkType(ty, zcu)) return false;
438 if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false;
437 // Check for lazy values439 // Check for lazy values
438 switch (zcu.intern_pool.indexToKey(val.toIntern())) {440 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
439 .int => |int| switch (int.storage) {441 .int => |int| switch (int.storage) {
...@@ -446,9 +448,11 @@ fn checkVal(val: Value, zcu: *Zcu) bool {...@@ -446,9 +448,11 @@ fn checkVal(val: Value, zcu: *Zcu) bool {
446 }448 }
447}449}
448450
449fn checkType(ty: Type, zcu: *Zcu) bool {451pub fn checkType(ty: Type, zcu: *Zcu) bool {
450 const ip = &zcu.intern_pool;452 const ip = &zcu.intern_pool;
451 return switch (ty.zigTypeTag(zcu)) {453 return switch (ty.zigTypeTagOrPoison(zcu) catch |err| switch (err) {
454 error.GenericPoison => return true,
455 }) {
452 .Type,456 .Type,
453 .Void,457 .Void,
454 .Bool,458 .Bool,
src/Value.zig+23-41
...@@ -192,11 +192,12 @@ pub fn toBigIntAdvanced(...@@ -192,11 +192,12 @@ pub fn toBigIntAdvanced(
192 zcu: *Zcu,192 zcu: *Zcu,
193 tid: strat.Tid(),193 tid: strat.Tid(),
194) Zcu.CompileError!BigIntConst {194) Zcu.CompileError!BigIntConst {
195 const ip = &zcu.intern_pool;
195 return switch (val.toIntern()) {196 return switch (val.toIntern()) {
196 .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),197 .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
197 .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),198 .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
198 .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),199 .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
199 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {200 else => switch (ip.indexToKey(val.toIntern())) {
200 .int => |int| switch (int.storage) {201 .int => |int| switch (int.storage) {
201 .u64, .i64, .big_int => int.storage.toBigInt(space),202 .u64, .i64, .big_int => int.storage.toBigInt(space),
202 .lazy_align, .lazy_size => |ty| {203 .lazy_align, .lazy_size => |ty| {
...@@ -214,6 +215,7 @@ pub fn toBigIntAdvanced(...@@ -214,6 +215,7 @@ pub fn toBigIntAdvanced(
214 &space.limbs,215 &space.limbs,
215 (try val.getUnsignedIntInner(strat, zcu, tid)).?,216 (try val.getUnsignedIntInner(strat, zcu, tid)).?,
216 ).toConst(),217 ).toConst(),
218 .err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
217 else => unreachable,219 else => unreachable,
218 },220 },
219 };221 };
...@@ -326,15 +328,11 @@ pub fn toBool(val: Value) bool {...@@ -326,15 +328,11 @@ pub fn toBool(val: Value) bool {
326 };328 };
327}329}
328330
329fn ptrHasIntAddr(val: Value, zcu: *Zcu) bool {
330 return zcu.intern_pool.getBackingAddrTag(val.toIntern()).? == .int;
331}
332
333/// Write a Value's contents to `buffer`.331/// Write a Value's contents to `buffer`.
334///332///
335/// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past333/// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
336/// the end of the value in memory.334/// the end of the value in memory.
337pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) error{335pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
338 ReinterpretDeclRef,336 ReinterpretDeclRef,
339 IllDefinedMemoryLayout,337 IllDefinedMemoryLayout,
340 Unimplemented,338 Unimplemented,
...@@ -343,19 +341,25 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -343,19 +341,25 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
343 const zcu = pt.zcu;341 const zcu = pt.zcu;
344 const target = zcu.getTarget();342 const target = zcu.getTarget();
345 const endian = target.cpu.arch.endian();343 const endian = target.cpu.arch.endian();
344 const ip = &zcu.intern_pool;
345 const ty = val.typeOf(zcu);
346 if (val.isUndef(zcu)) {346 if (val.isUndef(zcu)) {
347 const size: usize = @intCast(ty.abiSize(zcu));347 const size: usize = @intCast(ty.abiSize(zcu));
348 @memset(buffer[0..size], 0xaa);348 @memset(buffer[0..size], 0xaa);
349 return;349 return;
350 }350 }
351 const ip = &zcu.intern_pool;
352 switch (ty.zigTypeTag(zcu)) {351 switch (ty.zigTypeTag(zcu)) {
353 .Void => {},352 .Void => {},
354 .Bool => {353 .Bool => {
355 buffer[0] = @intFromBool(val.toBool());354 buffer[0] = @intFromBool(val.toBool());
356 },355 },
357 .Int, .Enum => {356 .Int, .Enum, .ErrorSet, .Pointer => |tag| {
358 const int_info = ty.intInfo(zcu);357 const int_ty = if (tag == .Pointer) int_ty: {
358 if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
359 if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
360 break :int_ty Type.usize;
361 } else ty;
362 const int_info = int_ty.intInfo(zcu);
359 const bits = int_info.bits;363 const bits = int_info.bits;
360 const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);364 const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
361365
...@@ -379,7 +383,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -379,7 +383,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
379 var buf_off: usize = 0;383 var buf_off: usize = 0;
380 while (elem_i < len) : (elem_i += 1) {384 while (elem_i < len) : (elem_i += 1) {
381 const elem_val = try val.elemValue(pt, elem_i);385 const elem_val = try val.elemValue(pt, elem_i);
382 try elem_val.writeToMemory(elem_ty, pt, buffer[buf_off..]);386 try elem_val.writeToMemory(pt, buffer[buf_off..]);
383 buf_off += elem_size;387 buf_off += elem_size;
384 }388 }
385 },389 },
...@@ -403,8 +407,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -403,8 +407,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
403 .elems => |elems| elems[field_index],407 .elems => |elems| elems[field_index],
404 .repeated_elem => |elem| elem,408 .repeated_elem => |elem| elem,
405 });409 });
406 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]);410 try writeToMemory(field_val, pt, buffer[off..]);
407 try writeToMemory(field_val, field_ty, pt, buffer[off..]);
408 },411 },
409 .@"packed" => {412 .@"packed" => {
410 const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;413 const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8;
...@@ -412,22 +415,6 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -412,22 +415,6 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
412 },415 },
413 }416 }
414 },417 },
415 .ErrorSet => {
416 const bits = zcu.errorSetBits();
417 const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
418
419 const name = switch (ip.indexToKey(val.toIntern())) {
420 .err => |err| err.name,
421 .error_union => |error_union| error_union.val.err_name,
422 else => unreachable,
423 };
424 var bigint_buffer: BigIntSpace = undefined;
425 const bigint = BigIntMutable.init(
426 &bigint_buffer.limbs,
427 ip.getErrorValueIfExists(name).?,
428 ).toConst();
429 bigint.writeTwosComplement(buffer[0..byte_count], endian);
430 },
431 .Union => switch (ty.containerLayout(zcu)) {418 .Union => switch (ty.containerLayout(zcu)) {
432 .auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already419 .auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
433 .@"extern" => {420 .@"extern" => {
...@@ -437,11 +424,11 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -437,11 +424,11 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
437 const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);424 const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
438 const field_val = try val.fieldValue(pt, field_index);425 const field_val = try val.fieldValue(pt, field_index);
439 const byte_count: usize = @intCast(field_type.abiSize(zcu));426 const byte_count: usize = @intCast(field_type.abiSize(zcu));
440 return writeToMemory(field_val, field_type, pt, buffer[0..byte_count]);427 return writeToMemory(field_val, pt, buffer[0..byte_count]);
441 } else {428 } else {
442 const backing_ty = try ty.unionBackingType(pt);429 const backing_ty = try ty.unionBackingType(pt);
443 const byte_count: usize = @intCast(backing_ty.abiSize(zcu));430 const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
444 return writeToMemory(val.unionValue(zcu), backing_ty, pt, buffer[0..byte_count]);431 return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
445 }432 }
446 },433 },
447 .@"packed" => {434 .@"packed" => {
...@@ -450,19 +437,13 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro...@@ -450,19 +437,13 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
450 return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);437 return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
451 },438 },
452 },439 },
453 .Pointer => {
454 if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
455 if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
456 return val.writeToMemory(Type.usize, pt, buffer);
457 },
458 .Optional => {440 .Optional => {
459 if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout;441 if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout;
460 const child = ty.optionalChild(zcu);
461 const opt_val = val.optionalValue(zcu);442 const opt_val = val.optionalValue(zcu);
462 if (opt_val) |some| {443 if (opt_val) |some| {
463 return some.writeToMemory(child, pt, buffer);444 return some.writeToMemory(pt, buffer);
464 } else {445 } else {
465 return writeToMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer);446 return writeToMemory(try pt.intValue(Type.usize, 0), pt, buffer);
466 }447 }
467 },448 },
468 else => return error.Unimplemented,449 else => return error.Unimplemented,
...@@ -582,7 +563,7 @@ pub fn writeToPackedMemory(...@@ -582,7 +563,7 @@ pub fn writeToPackedMemory(
582 },563 },
583 .Pointer => {564 .Pointer => {
584 assert(!ty.isSlice(zcu)); // No well defined layout.565 assert(!ty.isSlice(zcu)); // No well defined layout.
585 if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;566 if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
586 return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);567 return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);
587 },568 },
588 .Optional => {569 .Optional => {
...@@ -3658,14 +3639,15 @@ pub fn mulAddScalar(...@@ -3658,14 +3639,15 @@ pub fn mulAddScalar(
36583639
3659/// If the value is represented in-memory as a series of bytes that all3640/// If the value is represented in-memory as a series of bytes that all
3660/// have the same value, return that byte value, otherwise null.3641/// have the same value, return that byte value, otherwise null.
3661pub fn hasRepeatedByteRepr(val: Value, ty: Type, pt: Zcu.PerThread) !?u8 {3642pub fn hasRepeatedByteRepr(val: Value, pt: Zcu.PerThread) !?u8 {
3662 const zcu = pt.zcu;3643 const zcu = pt.zcu;
3644 const ty = val.typeOf(zcu);
3663 const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;3645 const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
3664 assert(abi_size >= 1);3646 assert(abi_size >= 1);
3665 const byte_buffer = try zcu.gpa.alloc(u8, abi_size);3647 const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
3666 defer zcu.gpa.free(byte_buffer);3648 defer zcu.gpa.free(byte_buffer);
36673649
3668 writeToMemory(val, ty, pt, byte_buffer) catch |err| switch (err) {3650 writeToMemory(val, pt, byte_buffer) catch |err| switch (err) {
3669 error.OutOfMemory => return error.OutOfMemory,3651 error.OutOfMemory => return error.OutOfMemory,
3670 error.ReinterpretDeclRef => return null,3652 error.ReinterpretDeclRef => return null,
3671 // TODO: The writeToMemory function was originally created for the purpose3653 // TODO: The writeToMemory function was originally created for the purpose
src/Zcu/PerThread.zig+12-3
...@@ -2560,12 +2560,17 @@ pub fn populateTestFunctions(...@@ -2560,12 +2560,17 @@ pub fn populateTestFunctions(
2560pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {2560pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
2561 const zcu = pt.zcu;2561 const zcu = pt.zcu;
2562 const comp = zcu.comp;2562 const comp = zcu.comp;
2563 const ip = &zcu.intern_pool;
25632564
2564 const nav = zcu.intern_pool.getNav(nav_index);2565 const nav = zcu.intern_pool.getNav(nav_index);
2565 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(&zcu.intern_pool), 0);2566 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
2566 defer codegen_prog_node.end();2567 defer codegen_prog_node.end();
25672568
2568 if (comp.bin_file) |lf| {2569 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
2570 // The value of this nav failed to resolve. This is a transitive failure.
2571 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
2572 // will fail due to the type error anyway.
2573 } else if (comp.bin_file) |lf| {
2569 lf.updateNav(pt, nav_index) catch |err| switch (err) {2574 lf.updateNav(pt, nav_index) catch |err| switch (err) {
2570 error.OutOfMemory => return error.OutOfMemory,2575 error.OutOfMemory => return error.OutOfMemory,
2571 error.AnalysisFail => {2576 error.AnalysisFail => {
...@@ -2605,7 +2610,11 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void...@@ -2605,7 +2610,11 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void
2605 const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);2610 const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
2606 defer codegen_prog_node.end();2611 defer codegen_prog_node.end();
26072612
2608 if (comp.bin_file) |lf| {2613 if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) {
2614 // This type failed to resolve. This is a transitive failure.
2615 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
2616 // will fail due to the type error anyway.
2617 } else if (comp.bin_file) |lf| {
2609 lf.updateContainerType(pt, ty) catch |err| switch (err) {2618 lf.updateContainerType(pt, ty) catch |err| switch (err) {
2610 error.OutOfMemory => return error.OutOfMemory,2619 error.OutOfMemory => return error.OutOfMemory,
2611 else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}),2620 else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}),
src/arch/wasm/CodeGen.zig+1-1
...@@ -3357,7 +3357,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {...@@ -3357,7 +3357,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
3357 .vector_type => {3357 .vector_type => {
3358 assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct);3358 assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct);
3359 var buf: [16]u8 = undefined;3359 var buf: [16]u8 = undefined;
3360 val.writeToMemory(ty, pt, &buf) catch unreachable;3360 val.writeToMemory(pt, &buf) catch unreachable;
3361 return func.storeSimdImmd(buf);3361 return func.storeSimdImmd(buf);
3362 },3362 },
3363 .struct_type => {3363 .struct_type => {
src/arch/x86_64/CodeGen.zig+112-13
...@@ -1491,6 +1491,46 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {...@@ -1491,6 +1491,46 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
1491 });1491 });
1492}1492}
14931493
1494fn asmPseudoRegister(self: *Self, ops: Mir.Inst.Ops, reg: Register) !void {
1495 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1496 std.mem.endsWith(u8, @tagName(ops), "_r"));
1497 _ = try self.addInst(.{
1498 .tag = .pseudo,
1499 .ops = ops,
1500 .data = .{ .r = .{ .r1 = reg } },
1501 });
1502}
1503
1504fn asmPseudoImmediate(self: *Self, ops: Mir.Inst.Ops, imm: Immediate) !void {
1505 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1506 std.mem.endsWith(u8, @tagName(ops), "_i_s"));
1507 _ = try self.addInst(.{
1508 .tag = .pseudo,
1509 .ops = ops,
1510 .data = .{ .i = .{ .i = @bitCast(imm.signed) } },
1511 });
1512}
1513
1514fn asmPseudoRegisterRegister(self: *Self, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void {
1515 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1516 std.mem.endsWith(u8, @tagName(ops), "_rr"));
1517 _ = try self.addInst(.{
1518 .tag = .pseudo,
1519 .ops = ops,
1520 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
1521 });
1522}
1523
1524fn asmPseudoRegisterImmediate(self: *Self, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void {
1525 assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
1526 std.mem.endsWith(u8, @tagName(ops), "_ri_s"));
1527 _ = try self.addInst(.{
1528 .tag = .pseudo,
1529 .ops = ops,
1530 .data = .{ .ri = .{ .r1 = reg, .i = @bitCast(imm.signed) } },
1531 });
1532}
1533
1494fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {1534fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {
1495 _ = try self.addInst(.{1535 _ = try self.addInst(.{
1496 .tag = tag[1],1536 .tag = tag[1],
...@@ -1877,7 +1917,10 @@ fn gen(self: *Self) InnerError!void {...@@ -1877,7 +1917,10 @@ fn gen(self: *Self) InnerError!void {
1877 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);1917 const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
1878 if (cc != .Naked) {1918 if (cc != .Naked) {
1879 try self.asmRegister(.{ ._, .push }, .rbp);1919 try self.asmRegister(.{ ._, .push }, .rbp);
1920 try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));
1921 try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));
1880 try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);1922 try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
1923 try self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, .rbp);
1881 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();1924 const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
1882 const backpatch_frame_align = try self.asmPlaceholder();1925 const backpatch_frame_align = try self.asmPlaceholder();
1883 const backpatch_frame_align_extra = try self.asmPlaceholder();1926 const backpatch_frame_align_extra = try self.asmPlaceholder();
...@@ -1962,6 +2005,7 @@ fn gen(self: *Self) InnerError!void {...@@ -1962,6 +2005,7 @@ fn gen(self: *Self) InnerError!void {
1962 const backpatch_stack_dealloc = try self.asmPlaceholder();2005 const backpatch_stack_dealloc = try self.asmPlaceholder();
1963 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();2006 const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
1964 try self.asmRegister(.{ ._, .pop }, .rbp);2007 try self.asmRegister(.{ ._, .pop }, .rbp);
2008 try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, Immediate.s(8));
1965 try self.asmOpOnly(.{ ._, .ret });2009 try self.asmOpOnly(.{ ._, .ret });
19662010
1967 const frame_layout = try self.computeFrameLayout(cc);2011 const frame_layout = try self.computeFrameLayout(cc);
...@@ -14038,7 +14082,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14038,7 +14082,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14038 var mnem_it = mem.tokenizeAny(u8, line, " \t");14082 var mnem_it = mem.tokenizeAny(u8, line, " \t");
14039 var prefix: Instruction.Prefix = .none;14083 var prefix: Instruction.Prefix = .none;
14040 const mnem_str = while (mnem_it.next()) |mnem_str| {14084 const mnem_str = while (mnem_it.next()) |mnem_str| {
14041 if (mem.startsWith(u8, mnem_str, "#")) continue :next_line;14085 if (mnem_str[0] == '#') continue :next_line;
14042 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;14086 if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
14043 if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {14087 if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {
14044 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});14088 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
...@@ -14063,8 +14107,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14063,8 +14107,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14063 }14107 }
14064 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);14108 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
14065 } else continue;14109 } else continue;
14110 if (mnem_str[0] == '.') {
14111 if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str });
14112 prefix = .directive;
14113 }
1406614114
14067 var mnem_size: ?Memory.Size = if (mem.endsWith(u8, mnem_str, "b"))14115 var mnem_size: ?Memory.Size = if (prefix == .directive)
14116 null
14117 else if (mem.endsWith(u8, mnem_str, "b"))
14068 .byte14118 .byte
14069 else if (mem.endsWith(u8, mnem_str, "w"))14119 else if (mem.endsWith(u8, mnem_str, "w"))
14070 .word14120 .word
...@@ -14095,7 +14145,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14095,7 +14145,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14095 mnem_size = fixed_mnem_size;14145 mnem_size = fixed_mnem_size;
14096 }14146 }
14097 const mnem_name = @tagName(mnem_tag);14147 const mnem_name = @tagName(mnem_tag);
14098 const mnem_fixed_tag: Mir.Inst.FixedTag = for (std.enums.values(Mir.Inst.Fixes)) |fixes| {14148 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
14149 .{ ._, .pseudo }
14150 else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
14099 const fixes_name = @tagName(fixes);14151 const fixes_name = @tagName(fixes);
14100 const space_i = mem.indexOfScalar(u8, fixes_name, ' ');14152 const space_i = mem.indexOfScalar(u8, fixes_name, ' ');
14101 const fixes_prefix = if (space_i) |i|14153 const fixes_prefix = if (space_i) |i|
...@@ -14116,7 +14168,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14116,7 +14168,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14116 } else {14168 } else {
14117 assert(prefix != .none); // no combination of fixes produced a known mnemonic14169 assert(prefix != .none); // no combination of fixes produced a known mnemonic
14118 return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{14170 return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
14119 @tagName(prefix), mnem_str,14171 @tagName(prefix), mnem_name,
14120 });14172 });
14121 };14173 };
1412214174
...@@ -14324,7 +14376,62 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -14324,7 +14376,62 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
14324 } else return self.fail("invalid operand: '{s}'", .{op_str});14376 } else return self.fail("invalid operand: '{s}'", .{op_str});
14325 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});14377 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
1432614378
14327 (switch (ops[0]) {14379 (if (prefix == .directive) switch (mnem_tag) {
14380 .@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14381 self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, ops[0].reg, ops[1].imm)
14382 else
14383 error.InvalidInstruction,
14384 .@".cfi_def_cfa_register" => if (ops[0] == .reg and ops[1] == .none)
14385 self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, ops[0].reg)
14386 else
14387 error.InvalidInstruction,
14388 .@".cfi_def_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
14389 self.asmPseudoImmediate(.pseudo_cfi_def_cfa_offset_i_s, ops[0].imm)
14390 else
14391 error.InvalidInstruction,
14392 .@".cfi_adjust_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
14393 self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, ops[0].imm)
14394 else
14395 error.InvalidInstruction,
14396 .@".cfi_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14397 self.asmPseudoRegisterImmediate(.pseudo_cfi_offset_ri_s, ops[0].reg, ops[1].imm)
14398 else
14399 error.InvalidInstruction,
14400 .@".cfi_val_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14401 self.asmPseudoRegisterImmediate(.pseudo_cfi_val_offset_ri_s, ops[0].reg, ops[1].imm)
14402 else
14403 error.InvalidInstruction,
14404 .@".cfi_rel_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
14405 self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, ops[0].reg, ops[1].imm)
14406 else
14407 error.InvalidInstruction,
14408 .@".cfi_register" => if (ops[0] == .reg and ops[1] == .reg and ops[2] == .none)
14409 self.asmPseudoRegisterRegister(.pseudo_cfi_register_rr, ops[0].reg, ops[1].reg)
14410 else
14411 error.InvalidInstruction,
14412 .@".cfi_restore" => if (ops[0] == .reg and ops[1] == .none)
14413 self.asmPseudoRegister(.pseudo_cfi_restore_r, ops[0].reg)
14414 else
14415 error.InvalidInstruction,
14416 .@".cfi_undefined" => if (ops[0] == .reg and ops[1] == .none)
14417 self.asmPseudoRegister(.pseudo_cfi_undefined_r, ops[0].reg)
14418 else
14419 error.InvalidInstruction,
14420 .@".cfi_same_value" => if (ops[0] == .reg and ops[1] == .none)
14421 self.asmPseudoRegister(.pseudo_cfi_same_value_r, ops[0].reg)
14422 else
14423 error.InvalidInstruction,
14424 .@".cfi_remember_state" => if (ops[0] == .none)
14425 self.asmPseudo(.pseudo_cfi_remember_state_none)
14426 else
14427 error.InvalidInstruction,
14428 .@".cfi_restore_state" => if (ops[0] == .none)
14429 self.asmPseudo(.pseudo_cfi_restore_state_none)
14430 else
14431 error.InvalidInstruction,
14432 .@".cfi_escape" => error.InvalidInstruction,
14433 else => unreachable,
14434 } else switch (ops[0]) {
14328 .none => self.asmOpOnly(mnem_fixed_tag),14435 .none => self.asmOpOnly(mnem_fixed_tag),
14329 .reg => |reg0| switch (ops[1]) {14436 .reg => |reg0| switch (ops[1]) {
14330 .none => self.asmRegister(mnem_fixed_tag, reg0),14437 .none => self.asmRegister(mnem_fixed_tag, reg0),
...@@ -19210,14 +19317,6 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {...@@ -19210,14 +19317,6 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
19210 return error.CodegenFail;19317 return error.CodegenFail;
19211}19318}
1921219319
19213fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError {
19214 @branchHint(.cold);
19215 assert(self.err_msg == null);
19216 const gpa = self.gpa;
19217 self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args);
19218 return error.CodegenFail;
19219}
19220
19221fn parseRegName(name: []const u8) ?Register {19320fn parseRegName(name: []const u8) ?Register {
19222 if (@hasDecl(Register, "parseRegName")) {19321 if (@hasDecl(Register, "parseRegName")) {
19223 return Register.parseRegName(name);19322 return Register.parseRegName(name);
src/arch/x86_64/Emit.zig+53
...@@ -30,6 +30,59 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -30,6 +30,59 @@ pub fn emitMir(emit: *Emit) Error!void {
30 var lowered_relocs = lowered.relocs;30 var lowered_relocs = lowered.relocs;
31 for (lowered.insts, 0..) |lowered_inst, lowered_index| {31 for (lowered.insts, 0..) |lowered_inst, lowered_index| {
32 const start_offset: u32 = @intCast(emit.code.items.len);32 const start_offset: u32 = @intCast(emit.code.items.len);
33 if (lowered_inst.prefix == .directive) {
34 switch (emit.debug_output) {
35 .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
36 .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
37 .reg = lowered_inst.ops[0].reg.dwarfNum(),
38 .off = lowered_inst.ops[1].imm.signed,
39 } }),
40 .@".cfi_def_cfa_register" => try dwarf.genDebugFrame(start_offset, .{
41 .def_cfa_register = lowered_inst.ops[0].reg.dwarfNum(),
42 }),
43 .@".cfi_def_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
44 .def_cfa_offset = lowered_inst.ops[0].imm.signed,
45 }),
46 .@".cfi_adjust_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
47 .adjust_cfa_offset = lowered_inst.ops[0].imm.signed,
48 }),
49 .@".cfi_offset" => try dwarf.genDebugFrame(start_offset, .{ .offset = .{
50 .reg = lowered_inst.ops[0].reg.dwarfNum(),
51 .off = lowered_inst.ops[1].imm.signed,
52 } }),
53 .@".cfi_val_offset" => try dwarf.genDebugFrame(start_offset, .{ .val_offset = .{
54 .reg = lowered_inst.ops[0].reg.dwarfNum(),
55 .off = lowered_inst.ops[1].imm.signed,
56 } }),
57 .@".cfi_rel_offset" => try dwarf.genDebugFrame(start_offset, .{ .rel_offset = .{
58 .reg = lowered_inst.ops[0].reg.dwarfNum(),
59 .off = lowered_inst.ops[1].imm.signed,
60 } }),
61 .@".cfi_register" => try dwarf.genDebugFrame(start_offset, .{ .register = .{
62 lowered_inst.ops[0].reg.dwarfNum(),
63 lowered_inst.ops[1].reg.dwarfNum(),
64 } }),
65 .@".cfi_restore" => try dwarf.genDebugFrame(start_offset, .{
66 .restore = lowered_inst.ops[0].reg.dwarfNum(),
67 }),
68 .@".cfi_undefined" => try dwarf.genDebugFrame(start_offset, .{
69 .undefined = lowered_inst.ops[0].reg.dwarfNum(),
70 }),
71 .@".cfi_same_value" => try dwarf.genDebugFrame(start_offset, .{
72 .same_value = lowered_inst.ops[0].reg.dwarfNum(),
73 }),
74 .@".cfi_remember_state" => try dwarf.genDebugFrame(start_offset, .remember_state),
75 .@".cfi_restore_state" => try dwarf.genDebugFrame(start_offset, .restore_state),
76 .@".cfi_escape" => try dwarf.genDebugFrame(start_offset, .{
77 .escape = lowered_inst.ops[0].bytes,
78 }),
79 else => unreachable,
80 },
81 .plan9 => {},
82 .none => {},
83 }
84 continue;
85 }
33 try lowered_inst.encode(emit.code.writer(), .{});86 try lowered_inst.encode(emit.code.writer(), .{});
34 const end_offset: u32 = @intCast(emit.code.items.len);87 const end_offset: u32 = @intCast(emit.code.items.len);
35 while (lowered_relocs.len > 0 and88 while (lowered_relocs.len > 0 and
src/arch/x86_64/Encoding.zig+32-7
...@@ -220,6 +220,21 @@ pub fn format(...@@ -220,6 +220,21 @@ pub fn format(
220}220}
221221
222pub const Mnemonic = enum {222pub const Mnemonic = enum {
223 // Directives
224 @".cfi_def_cfa",
225 @".cfi_def_cfa_register",
226 @".cfi_def_cfa_offset",
227 @".cfi_adjust_cfa_offset",
228 @".cfi_offset",
229 @".cfi_val_offset",
230 @".cfi_rel_offset",
231 @".cfi_register",
232 @".cfi_restore",
233 @".cfi_undefined",
234 @".cfi_same_value",
235 @".cfi_remember_state",
236 @".cfi_restore_state",
237 @".cfi_escape",
223 // zig fmt: off238 // zig fmt: off
224 // General-purpose239 // General-purpose
225 adc, add, @"and",240 adc, add, @"and",
...@@ -442,6 +457,7 @@ pub const Op = enum {...@@ -442,6 +457,7 @@ pub const Op = enum {
442 imm8s, imm16s, imm32s,457 imm8s, imm16s, imm32s,
443 al, ax, eax, rax,458 al, ax, eax, rax,
444 cl,459 cl,
460 rip, eip, ip,
445 r8, r16, r32, r64,461 r8, r16, r32, r64,
446 rm8, rm16, rm32, rm64,462 rm8, rm16, rm32, rm64,
447 r32_m8, r32_m16, r64_m16,463 r32_m8, r32_m16, r64_m16,
...@@ -487,7 +503,12 @@ pub const Op = enum {...@@ -487,7 +503,12 @@ pub const Op = enum {
487 256 => .ymm,503 256 => .ymm,
488 else => unreachable,504 else => unreachable,
489 },505 },
490 .ip => unreachable,506 .ip => switch (reg) {
507 .rip => .rip,
508 .eip => .eip,
509 .ip => .ip,
510 else => unreachable,
511 },
491 },512 },
492513
493 .mem => |mem| switch (mem) {514 .mem => |mem| switch (mem) {
...@@ -531,13 +552,15 @@ pub const Op = enum {...@@ -531,13 +552,15 @@ pub const Op = enum {
531 else552 else
532 .imm64,553 .imm64,
533 },554 },
555
556 .bytes => unreachable,
534 };557 };
535 }558 }
536559
537 pub fn immBitSize(op: Op) u64 {560 pub fn immBitSize(op: Op) u64 {
538 return switch (op) {561 return switch (op) {
539 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,562 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
540 .al, .cl, .r8, .rm8, .r32_m8 => unreachable,563 .al, .cl, .rip, .eip, .ip, .r8, .rm8, .r32_m8 => unreachable,
541 .ax, .r16, .rm16 => unreachable,564 .ax, .r16, .rm16 => unreachable,
542 .eax, .r32, .rm32, .r32_m16 => unreachable,565 .eax, .r32, .rm32, .r32_m16 => unreachable,
543 .rax, .r64, .rm64, .r64_m16 => unreachable,566 .rax, .r64, .rm64, .r64_m16 => unreachable,
...@@ -560,9 +583,9 @@ pub const Op = enum {...@@ -560,9 +583,9 @@ pub const Op = enum {
560 .rel8, .rel16, .rel32 => unreachable,583 .rel8, .rel16, .rel32 => unreachable,
561 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,584 .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
562 .al, .cl, .r8, .rm8 => 8,585 .al, .cl, .r8, .rm8 => 8,
563 .ax, .r16, .rm16 => 16,586 .ax, .ip, .r16, .rm16 => 16,
564 .eax, .r32, .rm32, .r32_m8, .r32_m16 => 32,587 .eax, .eip, .r32, .rm32, .r32_m8, .r32_m16 => 32,
565 .rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,588 .rax, .rip, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
566 .st => 80,589 .st => 80,
567 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128,590 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
568 .ymm, .ymm_m256 => 256,591 .ymm, .ymm_m256 => 256,
...@@ -574,7 +597,7 @@ pub const Op = enum {...@@ -574,7 +597,7 @@ pub const Op = enum {
574 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,597 .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
575 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,598 .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
576 .rel8, .rel16, .rel32 => unreachable,599 .rel8, .rel16, .rel32 => unreachable,
577 .al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64 => unreachable,600 .al, .cl, .r8, .ax, .ip, .r16, .eax, .eip, .r32, .rax, .rip, .r64 => unreachable,
578 .st, .mm, .xmm0, .xmm, .ymm => unreachable,601 .st, .mm, .xmm0, .xmm, .ymm => unreachable,
579 .m8, .rm8, .r32_m8, .xmm_m8 => 8,602 .m8, .rm8, .r32_m8, .xmm_m8 => 8,
580 .m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16,603 .m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16,
...@@ -602,8 +625,9 @@ pub const Op = enum {...@@ -602,8 +625,9 @@ pub const Op = enum {
602 pub fn isRegister(op: Op) bool {625 pub fn isRegister(op: Op) bool {
603 // zig fmt: off626 // zig fmt: off
604 return switch (op) {627 return switch (op) {
605 .cl,
606 .al, .ax, .eax, .rax,628 .al, .ax, .eax, .rax,
629 .cl,
630 .ip, .eip, .rip,
607 .r8, .r16, .r32, .r64,631 .r8, .r16, .r32, .r64,
608 .rm8, .rm16, .rm32, .rm64,632 .rm8, .rm16, .rm32, .rm64,
609 .r32_m8, .r32_m16, .r64_m16,633 .r32_m8, .r32_m16, .r64_m16,
...@@ -664,6 +688,7 @@ pub const Op = enum {...@@ -664,6 +688,7 @@ pub const Op = enum {
664 .mm, .mm_m64 => .mmx,688 .mm, .mm_m64 => .mmx,
665 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,689 .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
666 .ymm, .ymm_m256 => .sse,690 .ymm, .ymm_m256 => .sse,
691 .rip, .eip, .ip => .ip,
667 };692 };
668 }693 }
669694
src/arch/x86_64/Lower.zig+87-11
...@@ -12,7 +12,7 @@ src_loc: Zcu.LazySrcLoc,...@@ -12,7 +12,7 @@ src_loc: Zcu.LazySrcLoc,
12result_insts_len: u8 = undefined,12result_insts_len: u8 = undefined,
13result_relocs_len: u8 = undefined,13result_relocs_len: u8 = undefined,
14result_insts: [14result_insts: [
15 std.mem.max(usize, &.{15 @max(
16 1, // non-pseudo instructions16 1, // non-pseudo instructions
17 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode17 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
18 2, // cmovcc: cmovcc \ cmovcc18 2, // cmovcc: cmovcc \ cmovcc
...@@ -22,18 +22,18 @@ result_insts: [...@@ -22,18 +22,18 @@ result_insts: [
22 pseudo_probe_adjust_unrolled_max_insts,22 pseudo_probe_adjust_unrolled_max_insts,
23 pseudo_probe_adjust_setup_insts,23 pseudo_probe_adjust_setup_insts,
24 pseudo_probe_adjust_loop_insts,24 pseudo_probe_adjust_loop_insts,
25 abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs25 abi.Win64.callee_preserved_regs.len * 2, // push_regs/pop_regs
26 abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs26 abi.SysV.callee_preserved_regs.len * 2, // push_regs/pop_regs
27 })27 )
28]Instruction = undefined,28]Instruction = undefined,
29result_relocs: [29result_relocs: [
30 std.mem.max(usize, &.{30 @max(
31 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea31 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea
32 2, // jcc: jcc \ jcc32 2, // jcc: jcc \ jcc
33 2, // test \ jcc \ probe \ sub \ jmp33 2, // test \ jcc \ probe \ sub \ jmp
34 1, // probe \ sub \ jcc34 1, // probe \ sub \ jcc
35 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode35 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
36 })36 )
37]Reloc = undefined,37]Reloc = undefined,
3838
39pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp39pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp
...@@ -265,6 +265,50 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -265,6 +265,50 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
265 .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),265 .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
266 .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),266 .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
267267
268 .pseudo_cfi_def_cfa_ri_s => try lower.emit(.directive, .@".cfi_def_cfa", &.{
269 .{ .reg = inst.data.ri.r1 },
270 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
271 }),
272 .pseudo_cfi_def_cfa_register_r => try lower.emit(.directive, .@".cfi_def_cfa_register", &.{
273 .{ .reg = inst.data.r.r1 },
274 }),
275 .pseudo_cfi_def_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_def_cfa_offset", &.{
276 .{ .imm = lower.imm(.i_s, inst.data.i.i) },
277 }),
278 .pseudo_cfi_adjust_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_adjust_cfa_offset", &.{
279 .{ .imm = lower.imm(.i_s, inst.data.i.i) },
280 }),
281 .pseudo_cfi_offset_ri_s => try lower.emit(.directive, .@".cfi_offset", &.{
282 .{ .reg = inst.data.ri.r1 },
283 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
284 }),
285 .pseudo_cfi_val_offset_ri_s => try lower.emit(.directive, .@".cfi_val_offset", &.{
286 .{ .reg = inst.data.ri.r1 },
287 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
288 }),
289 .pseudo_cfi_rel_offset_ri_s => try lower.emit(.directive, .@".cfi_rel_offset", &.{
290 .{ .reg = inst.data.ri.r1 },
291 .{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
292 }),
293 .pseudo_cfi_register_rr => try lower.emit(.directive, .@".cfi_register", &.{
294 .{ .reg = inst.data.rr.r1 },
295 .{ .reg = inst.data.rr.r2 },
296 }),
297 .pseudo_cfi_restore_r => try lower.emit(.directive, .@".cfi_restore", &.{
298 .{ .reg = inst.data.r.r1 },
299 }),
300 .pseudo_cfi_undefined_r => try lower.emit(.directive, .@".cfi_undefined", &.{
301 .{ .reg = inst.data.r.r1 },
302 }),
303 .pseudo_cfi_same_value_r => try lower.emit(.directive, .@".cfi_same_value", &.{
304 .{ .reg = inst.data.r.r1 },
305 }),
306 .pseudo_cfi_remember_state_none => try lower.emit(.directive, .@".cfi_remember_state", &.{}),
307 .pseudo_cfi_restore_state_none => try lower.emit(.directive, .@".cfi_restore_state", &.{}),
308 .pseudo_cfi_escape_bytes => try lower.emit(.directive, .@".cfi_escape", &.{
309 .{ .bytes = inst.data.bytes.get(lower.mir) },
310 }),
311
268 .pseudo_dbg_prologue_end_none,312 .pseudo_dbg_prologue_end_none,
269 .pseudo_dbg_line_line_column,313 .pseudo_dbg_line_line_column,
270 .pseudo_dbg_epilogue_begin_none,314 .pseudo_dbg_epilogue_begin_none,
...@@ -280,6 +324,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {...@@ -280,6 +324,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
280 .pseudo_dbg_local_af,324 .pseudo_dbg_local_af,
281 .pseudo_dbg_local_am,325 .pseudo_dbg_local_am,
282 .pseudo_dbg_var_args_none,326 .pseudo_dbg_var_args_none,
327
283 .pseudo_dead_none,328 .pseudo_dead_none,
284 => {},329 => {},
285 else => unreachable,330 else => unreachable,
...@@ -665,12 +710,43 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {...@@ -665,12 +710,43 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
665710
666fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {711fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
667 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc);712 const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc);
668 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {713 var off: i32 = switch (mnemonic) {
669 .push => .reverse,714 .push => 0,
670 .pop => .forward,715 .pop => undefined,
671 else => unreachable,716 else => unreachable,
672 } });717 };
673 while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});718 {
719 var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
720 .push => .reverse,
721 .pop => .forward,
722 else => unreachable,
723 } });
724 while (it.next()) |i| {
725 try lower.emit(.none, mnemonic, &.{.{
726 .reg = callee_preserved_regs[i],
727 }});
728 switch (mnemonic) {
729 .push => off -= 8,
730 .pop => {},
731 else => unreachable,
732 }
733 }
734 }
735 switch (mnemonic) {
736 .push => {
737 var it = inst.data.reg_list.iterator(.{});
738 while (it.next()) |i| {
739 try lower.emit(.directive, .@".cfi_rel_offset", &.{
740 .{ .reg = callee_preserved_regs[i] },
741 .{ .imm = Immediate.s(off) },
742 });
743 off += 8;
744 }
745 assert(off == 0);
746 },
747 .pop => {},
748 else => unreachable,
749 }
674}750}
675751
676const page_size: i32 = 1 << 12;752const page_size: i32 = 1 << 12;
src/arch/x86_64/Mir.zig+48-1
...@@ -879,6 +879,7 @@ pub const Inst = struct {...@@ -879,6 +879,7 @@ pub const Inst = struct {
879 /// Probe adjust loop879 /// Probe adjust loop
880 /// Uses `rr` payload.880 /// Uses `rr` payload.
881 pseudo_probe_adjust_loop_rr,881 pseudo_probe_adjust_loop_rr,
882
882 /// Push registers883 /// Push registers
883 /// Uses `reg_list` payload.884 /// Uses `reg_list` payload.
884 pseudo_push_reg_list,885 pseudo_push_reg_list,
...@@ -886,6 +887,47 @@ pub const Inst = struct {...@@ -886,6 +887,47 @@ pub const Inst = struct {
886 /// Uses `reg_list` payload.887 /// Uses `reg_list` payload.
887 pseudo_pop_reg_list,888 pseudo_pop_reg_list,
888889
890 /// Define cfa rule as offset from register.
891 /// Uses `ri` payload.
892 pseudo_cfi_def_cfa_ri_s,
893 /// Modify cfa rule register.
894 /// Uses `r` payload.
895 pseudo_cfi_def_cfa_register_r,
896 /// Modify cfa rule offset.
897 /// Uses `i` payload.
898 pseudo_cfi_def_cfa_offset_i_s,
899 /// Offset cfa rule offset.
900 /// Uses `i` payload.
901 pseudo_cfi_adjust_cfa_offset_i_s,
902 /// Define register rule as stored at offset from cfa.
903 /// Uses `ri` payload.
904 pseudo_cfi_offset_ri_s,
905 /// Define register rule as offset from cfa.
906 /// Uses `ri` payload.
907 pseudo_cfi_val_offset_ri_s,
908 /// Define register rule as stored at offset from cfa rule register.
909 /// Uses `ri` payload.
910 pseudo_cfi_rel_offset_ri_s,
911 /// Define register rule as register.
912 /// Uses `rr` payload.
913 pseudo_cfi_register_rr,
914 /// Define register rule from initial.
915 /// Uses `r` payload.
916 pseudo_cfi_restore_r,
917 /// Define register rule as undefined.
918 /// Uses `r` payload.
919 pseudo_cfi_undefined_r,
920 /// Define register rule as itself.
921 /// Uses `r` payload.
922 pseudo_cfi_same_value_r,
923 /// Push cfi state.
924 pseudo_cfi_remember_state_none,
925 /// Pop cfi state.
926 pseudo_cfi_restore_state_none,
927 /// Raw cfi bytes.
928 /// Uses `bytes` payload.
929 pseudo_cfi_escape_bytes,
930
889 /// End of prologue931 /// End of prologue
890 pseudo_dbg_prologue_end_none,932 pseudo_dbg_prologue_end_none,
891 /// Update debug line933 /// Update debug line
...@@ -1028,8 +1070,13 @@ pub const Inst = struct {...@@ -1028,8 +1070,13 @@ pub const Inst = struct {
1028 fixes: Fixes = ._,1070 fixes: Fixes = ._,
1029 payload: u32,1071 payload: u32,
1030 },1072 },
1031 ix: struct {1073 bytes: struct {
1032 payload: u32,1074 payload: u32,
1075 len: u32,
1076
1077 pub fn get(bytes: @This(), mir: Mir) []const u8 {
1078 return std.mem.sliceAsBytes(mir.extra[bytes.payload..])[0..bytes.len];
1079 }
1033 },1080 },
1034 a: struct {1081 a: struct {
1035 air_inst: Air.Inst.Index,1082 air_inst: Air.Inst.Index,
src/arch/x86_64/bits.zig+1-1
...@@ -371,7 +371,7 @@ pub const Register = enum(u7) {...@@ -371,7 +371,7 @@ pub const Register = enum(u7) {
371 .x87 => 33 + @as(u6, reg.enc()),371 .x87 => 33 + @as(u6, reg.enc()),
372 .mmx => 41 + @as(u6, reg.enc()),372 .mmx => 41 + @as(u6, reg.enc()),
373 .segment => 50 + @as(u6, reg.enc()),373 .segment => 50 + @as(u6, reg.enc()),
374 .ip => unreachable,374 .ip => 16,
375 };375 };
376 }376 }
377};377};
src/arch/x86_64/encoder.zig+43-12
...@@ -25,6 +25,7 @@ pub const Instruction = struct {...@@ -25,6 +25,7 @@ pub const Instruction = struct {
25 repz,25 repz,
26 repne,26 repne,
27 repnz,27 repnz,
28 directive,
28 };29 };
2930
30 pub const Immediate = union(enum) {31 pub const Immediate = union(enum) {
...@@ -180,6 +181,7 @@ pub const Instruction = struct {...@@ -180,6 +181,7 @@ pub const Instruction = struct {
180 reg: Register,181 reg: Register,
181 mem: Memory,182 mem: Memory,
182 imm: Immediate,183 imm: Immediate,
184 bytes: []const u8,
183185
184 /// Returns the bitsize of the operand.186 /// Returns the bitsize of the operand.
185 pub fn bitSize(op: Operand) u64 {187 pub fn bitSize(op: Operand) u64 {
...@@ -188,6 +190,7 @@ pub const Instruction = struct {...@@ -188,6 +190,7 @@ pub const Instruction = struct {
188 .reg => |reg| reg.bitSize(),190 .reg => |reg| reg.bitSize(),
189 .mem => |mem| mem.bitSize(),191 .mem => |mem| mem.bitSize(),
190 .imm => unreachable,192 .imm => unreachable,
193 .bytes => unreachable,
191 };194 };
192 }195 }
193196
...@@ -199,6 +202,7 @@ pub const Instruction = struct {...@@ -199,6 +202,7 @@ pub const Instruction = struct {
199 .reg => |reg| reg.class() == .segment,202 .reg => |reg| reg.class() == .segment,
200 .mem => |mem| mem.isSegmentRegister(),203 .mem => |mem| mem.isSegmentRegister(),
201 .imm => unreachable,204 .imm => unreachable,
205 .bytes => unreachable,
202 };206 };
203 }207 }
204208
...@@ -207,6 +211,7 @@ pub const Instruction = struct {...@@ -207,6 +211,7 @@ pub const Instruction = struct {
207 .none, .imm => false,211 .none, .imm => false,
208 .reg => |reg| reg.isExtended(),212 .reg => |reg| reg.isExtended(),
209 .mem => |mem| mem.base().isExtended(),213 .mem => |mem| mem.base().isExtended(),
214 .bytes => unreachable,
210 };215 };
211 }216 }
212217
...@@ -214,6 +219,7 @@ pub const Instruction = struct {...@@ -214,6 +219,7 @@ pub const Instruction = struct {
214 return switch (op) {219 return switch (op) {
215 .none, .reg, .imm => false,220 .none, .reg, .imm => false,
216 .mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false,221 .mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false,
222 .bytes => unreachable,
217 };223 };
218 }224 }
219225
...@@ -299,6 +305,7 @@ pub const Instruction = struct {...@@ -299,6 +305,7 @@ pub const Instruction = struct {
299 if (imms < 0) try writer.writeByte('-');305 if (imms < 0) try writer.writeByte('-');
300 try writer.print("0x{x}", .{@abs(imms)});306 try writer.print("0x{x}", .{@abs(imms)});
301 } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),307 } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
308 .bytes => unreachable,
302 }309 }
303 }310 }
304311
...@@ -308,20 +315,39 @@ pub const Instruction = struct {...@@ -308,20 +315,39 @@ pub const Instruction = struct {
308 };315 };
309316
310 pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {317 pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
311 const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {318 const encoding: Encoding = switch (prefix) {
312 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{319 else => (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
313 @tagName(prefix),320 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
314 @tagName(mnemonic),321 @tagName(prefix),
315 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),322 @tagName(mnemonic),
316 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),323 @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
317 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),324 @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
318 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),325 @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
319 });326 @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
320 return error.InvalidInstruction;327 });
328 return error.InvalidInstruction;
329 },
330 .directive => .{
331 .mnemonic = mnemonic,
332 .data = .{
333 .op_en = .zo,
334 .ops = .{
335 if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none,
336 if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none,
337 if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none,
338 if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none,
339 },
340 .opc_len = 0,
341 .opc = undefined,
342 .modrm_ext = 0,
343 .mode = .none,
344 .feature = .none,
345 },
346 },
321 };347 };
322 log.debug("selected encoding: {}", .{encoding});348 log.debug("selected encoding: {}", .{encoding});
323349
324 var inst = Instruction{350 var inst: Instruction = .{
325 .prefix = prefix,351 .prefix = prefix,
326 .encoding = encoding,352 .encoding = encoding,
327 .ops = [1]Operand{.none} ** 4,353 .ops = [1]Operand{.none} ** 4,
...@@ -338,7 +364,10 @@ pub const Instruction = struct {...@@ -338,7 +364,10 @@ pub const Instruction = struct {
338 ) @TypeOf(writer).Error!void {364 ) @TypeOf(writer).Error!void {
339 _ = unused_format_string;365 _ = unused_format_string;
340 _ = options;366 _ = options;
341 if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)});367 switch (inst.prefix) {
368 .none, .directive => {},
369 else => try writer.print("{s} ", .{@tagName(inst.prefix)}),
370 }
342 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});371 try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
343 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {372 for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
344 if (op == .none) break;373 if (op == .none) break;
...@@ -349,6 +378,7 @@ pub const Instruction = struct {...@@ -349,6 +378,7 @@ pub const Instruction = struct {
349 }378 }
350379
351 pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void {380 pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void {
381 assert(inst.prefix != .directive);
352 const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer };382 const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer };
353 const enc = inst.encoding;383 const enc = inst.encoding;
354 const data = enc.data;384 const data = enc.data;
...@@ -435,6 +465,7 @@ pub const Instruction = struct {...@@ -435,6 +465,7 @@ pub const Instruction = struct {
435 .lock => legacy.prefix_f0 = true,465 .lock => legacy.prefix_f0 = true,
436 .repne, .repnz => legacy.prefix_f2 = true,466 .repne, .repnz => legacy.prefix_f2 = true,
437 .rep, .repe, .repz => legacy.prefix_f3 = true,467 .rep, .repe, .repz => legacy.prefix_f3 = true,
468 .directive => unreachable,
438 }469 }
439470
440 switch (data.mode) {471 switch (data.mode) {
src/codegen/llvm.zig+1-1
...@@ -9412,7 +9412,7 @@ pub const FuncGen = struct {...@@ -9412,7 +9412,7 @@ pub const FuncGen = struct {
9412 // repeating byte pattern, for example, `@as(u64, 0)` has a9412 // repeating byte pattern, for example, `@as(u64, 0)` has a
9413 // repeating byte pattern of 0 bytes. In such case, the memset9413 // repeating byte pattern of 0 bytes. In such case, the memset
9414 // intrinsic can be used.9414 // intrinsic can be used.
9415 if (try elem_val.hasRepeatedByteRepr(elem_ty, pt)) |byte_val| {9415 if (try elem_val.hasRepeatedByteRepr(pt)) |byte_val| {
9416 const fill_byte = try o.builder.intValue(.i8, byte_val);9416 const fill_byte = try o.builder.intValue(.i8, byte_val);
9417 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);9417 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
9418 if (intrinsic_len0_traps) {9418 if (intrinsic_len0_traps) {
src/link.zig+2-1
...@@ -589,7 +589,8 @@ pub const File = struct {...@@ -589,7 +589,8 @@ pub const File = struct {
589 fs.File.WriteFileError ||589 fs.File.WriteFileError ||
590 fs.File.OpenError ||590 fs.File.OpenError ||
591 std.process.Child.SpawnError ||591 std.process.Child.SpawnError ||
592 fs.Dir.CopyFileError;592 fs.Dir.CopyFileError ||
593 FlushDebugInfoError;
593594
594 /// Commit pending changes and write headers. Takes into account final output mode595 /// Commit pending changes and write headers. Takes into account final output mode
595 /// and `use_lld`, not only `effectiveOutputMode`.596 /// and `use_lld`, not only `effectiveOutputMode`.
src/link/Dwarf.zig+734-148
...@@ -10,6 +10,7 @@ navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),...@@ -10,6 +10,7 @@ navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
1010
11debug_abbrev: DebugAbbrev,11debug_abbrev: DebugAbbrev,
12debug_aranges: DebugAranges,12debug_aranges: DebugAranges,
13debug_frame: DebugFrame,
13debug_info: DebugInfo,14debug_info: DebugInfo,
14debug_line: DebugLine,15debug_line: DebugLine,
15debug_line_str: StringSection,16debug_line_str: StringSection,
...@@ -17,13 +18,21 @@ debug_loclists: DebugLocLists,...@@ -17,13 +18,21 @@ debug_loclists: DebugLocLists,
17debug_rnglists: DebugRngLists,18debug_rnglists: DebugRngLists,
18debug_str: StringSection,19debug_str: StringSection,
1920
20pub const UpdateError =21pub const UpdateError = error{
22 ReinterpretDeclRef,
23 IllDefinedMemoryLayout,
24 Unimplemented,
25 OutOfMemory,
26 EndOfStream,
27 Overflow,
28 Underflow,
29 UnexpectedEndOfFile,
30} ||
21 std.fs.File.OpenError ||31 std.fs.File.OpenError ||
22 std.fs.File.SetEndPosError ||32 std.fs.File.SetEndPosError ||
23 std.fs.File.CopyRangeError ||33 std.fs.File.CopyRangeError ||
24 std.fs.File.PReadError ||34 std.fs.File.PReadError ||
25 std.fs.File.PWriteError ||35 std.fs.File.PWriteError;
26 error{ EndOfStream, Overflow, Underflow, UnexpectedEndOfFile };
2736
28pub const FlushError =37pub const FlushError =
29 UpdateError ||38 UpdateError ||
...@@ -65,11 +74,7 @@ const DebugAranges = struct {...@@ -65,11 +74,7 @@ const DebugAranges = struct {
65 section: Section,74 section: Section,
6675
67 fn headerBytes(dwarf: *Dwarf) u32 {76 fn headerBytes(dwarf: *Dwarf) u32 {
68 return std.mem.alignForwardAnyAlign(77 return dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1;
69 u32,
70 dwarf.unitLengthBytes() + 2 + dwarf.sectionOffsetBytes() + 1 + 1,
71 @intFromEnum(dwarf.address_size) * 2,
72 );
73 }78 }
7479
75 fn trailerBytes(dwarf: *Dwarf) u32 {80 fn trailerBytes(dwarf: *Dwarf) u32 {
...@@ -77,6 +82,47 @@ const DebugAranges = struct {...@@ -77,6 +82,47 @@ const DebugAranges = struct {
77 }82 }
78};83};
7984
85const DebugFrame = struct {
86 header: Header,
87 section: Section,
88
89 const Format = enum { none, debug_frame, eh_frame };
90 const Header = struct {
91 format: Format,
92 code_alignment_factor: u32,
93 data_alignment_factor: i32,
94 return_address_register: u32,
95 initial_instructions: []const Cfa,
96 };
97
98 fn headerBytes(dwarf: *Dwarf) u32 {
99 const target = dwarf.bin_file.comp.root_mod.resolved_target.result;
100 return @intCast(switch (dwarf.debug_frame.header.format) {
101 .none => return 0,
102 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1,
103 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "zR\x00".len +
104 uleb128Bytes(1) + 1,
105 } + switch (target.cpu.arch) {
106 .x86_64 => len: {
107 dev.check(.x86_64_backend);
108 const Register = @import("../arch/x86_64/bits.zig").Register;
109 break :len uleb128Bytes(1) + sleb128Bytes(-8) + uleb128Bytes(Register.rip.dwarfNum()) +
110 1 + uleb128Bytes(Register.rsp.dwarfNum()) + sleb128Bytes(-1) +
111 1 + uleb128Bytes(1);
112 },
113 else => unreachable,
114 });
115 }
116
117 fn trailerBytes(dwarf: *Dwarf) u32 {
118 return @intCast(switch (dwarf.debug_frame.header.format) {
119 .none => 0,
120 .debug_frame => dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() + 1 + "\x00".len + 1 + 1 + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
121 .eh_frame => dwarf.unitLengthBytes() + 4 + 1 + "\x00".len + uleb128Bytes(1) + sleb128Bytes(1) + uleb128Bytes(0),
122 });
123 }
124};
125
80const DebugInfo = struct {126const DebugInfo = struct {
81 section: Section,127 section: Section,
82128
...@@ -219,8 +265,10 @@ pub const Section = struct {...@@ -219,8 +265,10 @@ pub const Section = struct {
219 len: u64,265 len: u64,
220 units: std.ArrayListUnmanaged(Unit),266 units: std.ArrayListUnmanaged(Unit),
221267
222 const Index = enum {268 pub const Index = enum {
223 debug_abbrev,269 debug_abbrev,
270 debug_aranges,
271 debug_frame,
224 debug_info,272 debug_info,
225 debug_line,273 debug_line,
226 debug_line_str,274 debug_line_str,
...@@ -251,15 +299,17 @@ pub const Section = struct {...@@ -251,15 +299,17 @@ pub const Section = struct {
251 const unit: Unit.Index = @enumFromInt(sec.units.items.len);299 const unit: Unit.Index = @enumFromInt(sec.units.items.len);
252 const unit_ptr = try sec.units.addOne(dwarf.gpa);300 const unit_ptr = try sec.units.addOne(dwarf.gpa);
253 errdefer sec.popUnit(dwarf.gpa);301 errdefer sec.popUnit(dwarf.gpa);
302 const aligned_header_len: u32 = @intCast(sec.alignment.forward(header_len));
303 const aligned_trailer_len: u32 = @intCast(sec.alignment.forward(trailer_len));
254 unit_ptr.* = .{304 unit_ptr.* = .{
255 .prev = sec.last,305 .prev = sec.last,
256 .next = .none,306 .next = .none,
257 .first = .none,307 .first = .none,
258 .last = .none,308 .last = .none,
259 .off = 0,309 .off = 0,
260 .header_len = header_len,310 .header_len = aligned_header_len,
261 .trailer_len = trailer_len,311 .trailer_len = aligned_trailer_len,
262 .len = header_len + trailer_len,312 .len = aligned_header_len + aligned_trailer_len,
263 .entries = .{},313 .entries = .{},
264 .cross_unit_relocs = .{},314 .cross_unit_relocs = .{},
265 .cross_section_relocs = .{},315 .cross_section_relocs = .{},
...@@ -280,8 +330,8 @@ pub const Section = struct {...@@ -280,8 +330,8 @@ pub const Section = struct {
280 const unit_ptr = sec.getUnit(unit);330 const unit_ptr = sec.getUnit(unit);
281 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;331 if (unit_ptr.prev.unwrap()) |prev_unit| sec.getUnit(prev_unit).next = unit_ptr.next;
282 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;332 if (unit_ptr.next.unwrap()) |next_unit| sec.getUnit(next_unit).prev = unit_ptr.prev;
283 if (sec.first.unwrap().? == unit) sec.first = unit_ptr.next;333 if (sec.first == unit.toOptional()) sec.first = unit_ptr.next;
284 if (sec.last.unwrap().? == unit) sec.last = unit_ptr.prev;334 if (sec.last == unit.toOptional()) sec.last = unit_ptr.prev;
285 }335 }
286336
287 fn popUnit(sec: *Section, gpa: std.mem.Allocator) void {337 fn popUnit(sec: *Section, gpa: std.mem.Allocator) void {
...@@ -295,10 +345,10 @@ pub const Section = struct {...@@ -295,10 +345,10 @@ pub const Section = struct {
295 return &sec.units.items[@intFromEnum(unit)];345 return &sec.units.items[@intFromEnum(unit)];
296 }346 }
297347
298 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {348 fn resizeEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, len: u32) UpdateError!void {
299 const unit_ptr = sec.getUnit(unit);349 const unit_ptr = sec.getUnit(unit);
300 const entry_ptr = unit_ptr.getEntry(entry);350 const entry_ptr = unit_ptr.getEntry(entry);
301 if (contents.len > 0) {351 if (len > 0) {
302 if (entry_ptr.len == 0) {352 if (entry_ptr.len == 0) {
303 assert(entry_ptr.prev == .none and entry_ptr.next == .none);353 assert(entry_ptr.prev == .none and entry_ptr.next == .none);
304 entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {354 entry_ptr.off = if (unit_ptr.last.unwrap()) |last_entry| off: {
...@@ -308,15 +358,27 @@ pub const Section = struct {...@@ -308,15 +358,27 @@ pub const Section = struct {
308 } else 0;358 } else 0;
309 entry_ptr.prev = unit_ptr.last;359 entry_ptr.prev = unit_ptr.last;
310 unit_ptr.last = entry.toOptional();360 unit_ptr.last = entry.toOptional();
361 if (unit_ptr.first == .none) unit_ptr.first = unit_ptr.last;
362 if (entry_ptr.prev.unwrap()) |prev_entry| try unit_ptr.getEntry(prev_entry).pad(unit_ptr, sec, dwarf);
311 }363 }
312 try entry_ptr.replace(unit_ptr, sec, dwarf, contents);364 try entry_ptr.resize(unit_ptr, sec, dwarf, len);
313 }365 }
314 assert(entry_ptr.len == contents.len);366 assert(entry_ptr.len == len);
367 }
368
369 fn replaceEntry(sec: *Section, unit: Unit.Index, entry: Entry.Index, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
370 try sec.resizeEntry(unit, entry, dwarf, @intCast(contents.len));
371 const unit_ptr = sec.getUnit(unit);
372 try unit_ptr.getEntry(entry).replace(unit_ptr, sec, dwarf, contents);
315 }373 }
316374
317 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {375 fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void {
376 if (len <= sec.len) return;
318 if (dwarf.bin_file.cast(.elf)) |elf_file| {377 if (dwarf.bin_file.cast(.elf)) |elf_file| {
319 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);378 if (sec == &dwarf.debug_frame.section)
379 try elf_file.growAllocSection(sec.index, len)
380 else
381 try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true);
320 const shdr = &elf_file.sections.items(.shdr)[sec.index];382 const shdr = &elf_file.sections.items(.shdr)[sec.index];
321 sec.off = shdr.sh_offset;383 sec.off = shdr.sh_offset;
322 sec.len = shdr.sh_size;384 sec.len = shdr.sh_size;
...@@ -358,7 +420,7 @@ pub const Section = struct {...@@ -358,7 +420,7 @@ pub const Section = struct {
358 }420 }
359421
360 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {422 fn padToIdeal(sec: *Section, actual_size: anytype) @TypeOf(actual_size) {
361 return if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size;423 return @intCast(sec.alignment.forward(if (sec.pad_to_ideal) Dwarf.padToIdeal(actual_size) else actual_size));
362 }424 }
363};425};
364426
...@@ -554,6 +616,43 @@ const Unit = struct {...@@ -554,6 +616,43 @@ const Unit = struct {
554 } else if (sec == &dwarf.debug_aranges.section) fill: {616 } else if (sec == &dwarf.debug_aranges.section) fill: {
555 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);617 trailer.appendNTimesAssumeCapacity(0, @intFromEnum(dwarf.address_size) * 2);
556 break :fill 0;618 break :fill 0;
619 } else if (sec == &dwarf.debug_frame.section) fill: {
620 switch (dwarf.debug_frame.header.format) {
621 .none => {},
622 .debug_frame, .eh_frame => |format| {
623 const unit_len = len - dwarf.unitLengthBytes();
624 switch (dwarf.format) {
625 .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
626 .@"64" => {
627 std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
628 std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
629 },
630 }
631 switch (format) {
632 .none => unreachable,
633 .debug_frame => {
634 switch (dwarf.format) {
635 .@"32" => std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian),
636 .@"64" => std.mem.writeInt(u64, trailer.addManyAsArrayAssumeCapacity(8), std.math.maxInt(u64), dwarf.endian),
637 }
638 trailer.appendAssumeCapacity(4);
639 trailer.appendSliceAssumeCapacity("\x00");
640 trailer.appendAssumeCapacity(@intFromEnum(dwarf.address_size));
641 trailer.appendAssumeCapacity(0);
642 },
643 .eh_frame => {
644 std.mem.writeInt(u32, trailer.addManyAsArrayAssumeCapacity(4), 0, dwarf.endian);
645 trailer.appendAssumeCapacity(1);
646 trailer.appendSliceAssumeCapacity("\x00");
647 },
648 }
649 uleb128(trailer.fixedWriter(), 1) catch unreachable;
650 sleb128(trailer.fixedWriter(), 1) catch unreachable;
651 uleb128(trailer.fixedWriter(), 0) catch unreachable;
652 },
653 }
654 trailer.appendNTimesAssumeCapacity(DW.CFA.nop, unit.trailer_len - trailer.items.len);
655 break :fill DW.CFA.nop;
557 } else if (sec == &dwarf.debug_info.section) fill: {656 } else if (sec == &dwarf.debug_info.section) fill: {
558 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);657 assert(uleb128Bytes(@intFromEnum(AbbrevCode.null)) == 1);
559 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);658 trailer.appendNTimesAssumeCapacity(@intFromEnum(AbbrevCode.null), 2);
...@@ -563,7 +662,7 @@ const Unit = struct {...@@ -563,7 +662,7 @@ const Unit = struct {
563 break :fill DW.RLE.end_of_list;662 break :fill DW.RLE.end_of_list;
564 } else unreachable;663 } else unreachable;
565 assert(trailer.items.len == unit.trailer_len);664 assert(trailer.items.len == unit.trailer_len);
566 trailer.appendNTimesAssumeCapacity(fill_byte, len - trailer.items.len);665 trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len);
567 assert(trailer.items.len == len);666 assert(trailer.items.len == len);
568 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);667 try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start);
569 }668 }
...@@ -647,6 +746,23 @@ const Entry = struct {...@@ -647,6 +746,23 @@ const Entry = struct {
647 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {746 fn pad(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void {
648 assert(entry.len > 0);747 assert(entry.len > 0);
649 const start = entry.off + entry.len;748 const start = entry.off + entry.len;
749 if (sec == &dwarf.debug_frame.section) {
750 const len = if (entry.next.unwrap()) |next_entry|
751 unit.getEntry(next_entry).off - entry.off
752 else
753 entry.len;
754 var unit_len: [8]u8 = undefined;
755 dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes());
756 try dwarf.getFile().?.pwriteAll(
757 unit_len[0..dwarf.sectionOffsetBytes()],
758 sec.off + unit.off + unit.header_len + entry.off,
759 );
760 const buf = try dwarf.gpa.alloc(u8, len - entry.len);
761 defer dwarf.gpa.free(buf);
762 @memset(buf, DW.CFA.nop);
763 try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start);
764 return;
765 }
650 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;766 const len = unit.getEntry(entry.next.unwrap() orelse return).off - start;
651 var buf: [767 var buf: [
652 @max(768 @max(
...@@ -703,18 +819,20 @@ const Entry = struct {...@@ -703,18 +819,20 @@ const Entry = struct {
703 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);819 try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start);
704 }820 }
705821
706 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {822 fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void {
823 assert(len > 0);
824 assert(sec.alignment.check(len));
825 if (entry_ptr.len == len) return;
707 const end = if (entry_ptr.next.unwrap()) |next_entry|826 const end = if (entry_ptr.next.unwrap()) |next_entry|
708 unit.getEntry(next_entry).off827 unit.getEntry(next_entry).off
709 else828 else
710 unit.len -| (unit.header_len + unit.trailer_len);829 unit.len -| (unit.header_len + unit.trailer_len);
711 if (entry_ptr.off + contents.len > end) {830 if (entry_ptr.off + len > end) {
712 if (entry_ptr.next.unwrap()) |next_entry| {831 if (entry_ptr.next.unwrap()) |next_entry| {
713 if (entry_ptr.prev.unwrap()) |prev_entry| {832 if (entry_ptr.prev.unwrap()) |prev_entry|
714 const prev_entry_ptr = unit.getEntry(prev_entry);833 unit.getEntry(prev_entry).next = entry_ptr.next
715 prev_entry_ptr.next = entry_ptr.next;834 else
716 try prev_entry_ptr.pad(unit, sec, dwarf);835 unit.first = entry_ptr.next;
717 } else unit.first = entry_ptr.next;
718 const next_entry_ptr = unit.getEntry(next_entry);836 const next_entry_ptr = unit.getEntry(next_entry);
719 const entry = next_entry_ptr.prev;837 const entry = next_entry_ptr.prev;
720 next_entry_ptr.prev = entry_ptr.prev;838 next_entry_ptr.prev = entry_ptr.prev;
...@@ -725,12 +843,15 @@ const Entry = struct {...@@ -725,12 +843,15 @@ const Entry = struct {
725 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);843 entry_ptr.off = last_entry_ptr.off + sec.padToIdeal(last_entry_ptr.len);
726 unit.last = entry;844 unit.last = entry;
727 }845 }
728 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(contents.len) + unit.trailer_len));846 try unit.resize(sec, dwarf, 0, @intCast(unit.header_len + entry_ptr.off + sec.padToIdeal(len) + unit.trailer_len));
729 }847 }
730 entry_ptr.len = @intCast(contents.len);848 entry_ptr.len = len;
731 if (entry_ptr.prev.unwrap()) |prev_entry| try unit.getEntry(prev_entry).pad(unit, sec, dwarf);
732 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
733 try entry_ptr.pad(unit, sec, dwarf);849 try entry_ptr.pad(unit, sec, dwarf);
850 }
851
852 fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void {
853 assert(contents.len == entry_ptr.len);
854 try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off);
734 if (false) {855 if (false) {
735 const buf = try dwarf.gpa.alloc(u8, sec.len);856 const buf = try dwarf.gpa.alloc(u8, sec.len);
736 defer dwarf.gpa.free(buf);857 defer dwarf.gpa.free(buf);
...@@ -836,6 +957,22 @@ const Entry = struct {...@@ -836,6 +957,22 @@ const Entry = struct {
836 dwarf.sectionOffsetBytes(),957 dwarf.sectionOffsetBytes(),
837 );958 );
838 }959 }
960 if (sec == &dwarf.debug_frame.section) switch (DebugFrame.format(dwarf)) {
961 .none, .debug_frame => {},
962 .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| {
963 const zo = elf_file.zigObjectPtr().?;
964 const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[sec.index].sh_addr);
965 for (entry.external_relocs.items) |reloc| {
966 const symbol = zo.symbol(reloc.target_sym);
967 try dwarf.resolveReloc(
968 entry_off + reloc.source_off,
969 @bitCast((symbol.address(.{}, elf_file) + @as(i64, @intCast(reloc.target_off))) -
970 (entry_addr + reloc.source_off + 4)),
971 4,
972 );
973 }
974 } else unreachable,
975 };
839 if (dwarf.bin_file.cast(.elf)) |elf_file| {976 if (dwarf.bin_file.cast(.elf)) |elf_file| {
840 const zo = elf_file.zigObjectPtr().?;977 const zo = elf_file.zigObjectPtr().?;
841 for (entry.external_relocs.items) |reloc| {978 for (entry.external_relocs.items) |reloc| {
...@@ -863,7 +1000,7 @@ const Entry = struct {...@@ -863,7 +1000,7 @@ const Entry = struct {
8631000
864const CrossEntryReloc = struct {1001const CrossEntryReloc = struct {
865 source_off: u32 = 0,1002 source_off: u32 = 0,
866 target_entry: Entry.Index,1003 target_entry: Entry.Index.Optional = .none,
867 target_off: u32 = 0,1004 target_off: u32 = 0,
868};1005};
869const CrossUnitReloc = struct {1006const CrossUnitReloc = struct {
...@@ -929,14 +1066,14 @@ pub const Loc = union(enum) {...@@ -929,14 +1066,14 @@ pub const Loc = union(enum) {
929 }1066 }
930 }1067 }
9311068
932 fn write(loc: Loc, wip: anytype) UpdateError!void {1069 fn write(loc: Loc, adapter: anytype) UpdateError!void {
933 const writer = wip.infoWriter();1070 const writer = adapter.writer();
934 switch (loc) {1071 switch (loc) {
935 .empty => unreachable,1072 .empty => {},
936 .addr => |addr| {1073 .addr => |addr| {
937 try writer.writeByte(DW.OP.addr);1074 try writer.writeByte(DW.OP.addr);
938 switch (addr) {1075 switch (addr) {
939 .sym => |sym_index| try wip.addrSym(sym_index),1076 .sym => |sym_index| try adapter.addrSym(sym_index),
940 }1077 }
941 },1078 },
942 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {1079 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
...@@ -945,45 +1082,45 @@ pub const Loc = union(enum) {...@@ -945,45 +1082,45 @@ pub const Loc = union(enum) {
945 try writer.writeAll(&.{ DW.OP.const1u, const1u });1082 try writer.writeAll(&.{ DW.OP.const1u, const1u });
946 } else if (std.math.cast(u16, constu)) |const2u| {1083 } else if (std.math.cast(u16, constu)) |const2u| {
947 try writer.writeByte(DW.OP.const2u);1084 try writer.writeByte(DW.OP.const2u);
948 try writer.writeInt(u16, const2u, wip.dwarf.endian);1085 try writer.writeInt(u16, const2u, adapter.endian());
949 } else if (std.math.cast(u21, constu)) |const3u| {1086 } else if (std.math.cast(u21, constu)) |const3u| {
950 try writer.writeByte(DW.OP.constu);1087 try writer.writeByte(DW.OP.constu);
951 try uleb128(writer, const3u);1088 try uleb128(writer, const3u);
952 } else if (std.math.cast(u32, constu)) |const4u| {1089 } else if (std.math.cast(u32, constu)) |const4u| {
953 try writer.writeByte(DW.OP.const4u);1090 try writer.writeByte(DW.OP.const4u);
954 try writer.writeInt(u32, const4u, wip.dwarf.endian);1091 try writer.writeInt(u32, const4u, adapter.endian());
955 } else if (std.math.cast(u49, constu)) |const7u| {1092 } else if (std.math.cast(u49, constu)) |const7u| {
956 try writer.writeByte(DW.OP.constu);1093 try writer.writeByte(DW.OP.constu);
957 try uleb128(writer, const7u);1094 try uleb128(writer, const7u);
958 } else {1095 } else {
959 try writer.writeByte(DW.OP.const8u);1096 try writer.writeByte(DW.OP.const8u);
960 try writer.writeInt(u64, constu, wip.dwarf.endian);1097 try writer.writeInt(u64, constu, adapter.endian());
961 },1098 },
962 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {1099 .consts => |consts| if (std.math.cast(i8, consts)) |const1s| {
963 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });1100 try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) });
964 } else if (std.math.cast(i16, consts)) |const2s| {1101 } else if (std.math.cast(i16, consts)) |const2s| {
965 try writer.writeByte(DW.OP.const2s);1102 try writer.writeByte(DW.OP.const2s);
966 try writer.writeInt(i16, const2s, wip.dwarf.endian);1103 try writer.writeInt(i16, const2s, adapter.endian());
967 } else if (std.math.cast(i21, consts)) |const3s| {1104 } else if (std.math.cast(i21, consts)) |const3s| {
968 try writer.writeByte(DW.OP.consts);1105 try writer.writeByte(DW.OP.consts);
969 try sleb128(writer, const3s);1106 try sleb128(writer, const3s);
970 } else if (std.math.cast(i32, consts)) |const4s| {1107 } else if (std.math.cast(i32, consts)) |const4s| {
971 try writer.writeByte(DW.OP.const4s);1108 try writer.writeByte(DW.OP.const4s);
972 try writer.writeInt(i32, const4s, wip.dwarf.endian);1109 try writer.writeInt(i32, const4s, adapter.endian());
973 } else if (std.math.cast(i49, consts)) |const7s| {1110 } else if (std.math.cast(i49, consts)) |const7s| {
974 try writer.writeByte(DW.OP.consts);1111 try writer.writeByte(DW.OP.consts);
975 try sleb128(writer, const7s);1112 try sleb128(writer, const7s);
976 } else {1113 } else {
977 try writer.writeByte(DW.OP.const8s);1114 try writer.writeByte(DW.OP.const8s);
978 try writer.writeInt(i64, consts, wip.dwarf.endian);1115 try writer.writeInt(i64, consts, adapter.endian());
979 },1116 },
980 .plus => |plus| done: {1117 .plus => |plus| done: {
981 if (plus[0].getConst(u0)) |_| {1118 if (plus[0].getConst(u0)) |_| {
982 try plus[1].write(wip);1119 try plus[1].write(adapter);
983 break :done;1120 break :done;
984 }1121 }
985 if (plus[1].getConst(u0)) |_| {1122 if (plus[1].getConst(u0)) |_| {
986 try plus[0].write(wip);1123 try plus[0].write(adapter);
987 break :done;1124 break :done;
988 }1125 }
989 if (plus[0].getBaseReg()) |breg| {1126 if (plus[0].getBaseReg()) |breg| {
...@@ -1001,19 +1138,19 @@ pub const Loc = union(enum) {...@@ -1001,19 +1138,19 @@ pub const Loc = union(enum) {
1001 }1138 }
1002 }1139 }
1003 if (plus[0].getConst(u64)) |uconst| {1140 if (plus[0].getConst(u64)) |uconst| {
1004 try plus[1].write(wip);1141 try plus[1].write(adapter);
1005 try writer.writeByte(DW.OP.plus_uconst);1142 try writer.writeByte(DW.OP.plus_uconst);
1006 try uleb128(writer, uconst);1143 try uleb128(writer, uconst);
1007 break :done;1144 break :done;
1008 }1145 }
1009 if (plus[1].getConst(u64)) |uconst| {1146 if (plus[1].getConst(u64)) |uconst| {
1010 try plus[0].write(wip);1147 try plus[0].write(adapter);
1011 try writer.writeByte(DW.OP.plus_uconst);1148 try writer.writeByte(DW.OP.plus_uconst);
1012 try uleb128(writer, uconst);1149 try uleb128(writer, uconst);
1013 break :done;1150 break :done;
1014 }1151 }
1015 try plus[0].write(wip);1152 try plus[0].write(adapter);
1016 try plus[1].write(wip);1153 try plus[1].write(adapter);
1017 try writer.writeByte(DW.OP.plus);1154 try writer.writeByte(DW.OP.plus);
1018 },1155 },
1019 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),1156 .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer),
...@@ -1023,7 +1160,7 @@ pub const Loc = union(enum) {...@@ -1023,7 +1160,7 @@ pub const Loc = union(enum) {
1023 },1160 },
1024 .push_object_address => try writer.writeByte(DW.OP.push_object_address),1161 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
1025 .form_tls_address => |addr| {1162 .form_tls_address => |addr| {
1026 try addr.write(wip);1163 try addr.write(adapter);
1027 try writer.writeByte(DW.OP.form_tls_address);1164 try writer.writeByte(DW.OP.form_tls_address);
1028 },1165 },
1029 .implicit_value => |value| {1166 .implicit_value => |value| {
...@@ -1032,7 +1169,7 @@ pub const Loc = union(enum) {...@@ -1032,7 +1169,7 @@ pub const Loc = union(enum) {
1032 try writer.writeAll(value);1169 try writer.writeAll(value);
1033 },1170 },
1034 .stack_value => |value| {1171 .stack_value => |value| {
1035 try value.write(wip);1172 try value.write(adapter);
1036 try writer.writeByte(DW.OP.stack_value);1173 try writer.writeByte(DW.OP.stack_value);
1037 },1174 },
1038 .wasm_ext => |wasm_ext| {1175 .wasm_ext => |wasm_ext| {
...@@ -1047,7 +1184,7 @@ pub const Loc = union(enum) {...@@ -1047,7 +1184,7 @@ pub const Loc = union(enum) {
1047 try uleb128(writer, global_u21);1184 try uleb128(writer, global_u21);
1048 } else {1185 } else {
1049 try writer.writeByte(DW.OP.WASM_global_u32);1186 try writer.writeByte(DW.OP.WASM_global_u32);
1050 try writer.writeInt(u32, global, wip.dwarf.endian);1187 try writer.writeInt(u32, global, adapter.endian());
1051 },1188 },
1052 .operand_stack => |operand_stack| {1189 .operand_stack => |operand_stack| {
1053 try writer.writeByte(DW.OP.WASM_operand_stack);1190 try writer.writeByte(DW.OP.WASM_operand_stack);
...@@ -1059,6 +1196,153 @@ pub const Loc = union(enum) {...@@ -1059,6 +1196,153 @@ pub const Loc = union(enum) {
1059 }1196 }
1060};1197};
10611198
1199pub const Cfa = union(enum) {
1200 nop,
1201 advance_loc: u32,
1202 offset: RegOff,
1203 rel_offset: RegOff,
1204 restore: u32,
1205 undefined: u32,
1206 same_value: u32,
1207 register: [2]u32,
1208 remember_state,
1209 restore_state,
1210 def_cfa: RegOff,
1211 def_cfa_register: u32,
1212 def_cfa_offset: i64,
1213 adjust_cfa_offset: i64,
1214 def_cfa_expression: Loc,
1215 expression: RegExpr,
1216 val_offset: RegOff,
1217 val_expression: RegExpr,
1218 escape: []const u8,
1219
1220 const RegOff = struct { reg: u32, off: i64 };
1221 const RegExpr = struct { reg: u32, expr: Loc };
1222
1223 fn write(cfa: Cfa, wip_nav: *WipNav) UpdateError!void {
1224 const writer = wip_nav.debug_frame.writer(wip_nav.dwarf.gpa);
1225 switch (cfa) {
1226 .nop => try writer.writeByte(DW.CFA.nop),
1227 .advance_loc => |loc| {
1228 const delta = @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.debug_frame.header.code_alignment_factor);
1229 if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta|
1230 try writer.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta)
1231 else if (std.math.cast(u8, delta)) |ubyte_delta|
1232 try writer.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta })
1233 else if (std.math.cast(u16, delta)) |uhalf_delta| {
1234 try writer.writeByte(DW.CFA.advance_loc2);
1235 try writer.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian);
1236 } else if (std.math.cast(u32, delta)) |uword_delta| {
1237 try writer.writeByte(DW.CFA.advance_loc4);
1238 try writer.writeInt(u32, uword_delta, wip_nav.dwarf.endian);
1239 }
1240 wip_nav.cfi.loc = loc;
1241 },
1242 .offset, .rel_offset => |reg_off| {
1243 const factored_off = @divExact(reg_off.off - switch (cfa) {
1244 else => unreachable,
1245 .offset => 0,
1246 .rel_offset => wip_nav.cfi.cfa.off,
1247 }, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1248 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1249 if (std.math.cast(u6, reg_off.reg)) |small_reg| {
1250 try writer.writeByte(@as(u8, DW.CFA.offset) + small_reg);
1251 } else {
1252 try writer.writeByte(DW.CFA.offset_extended);
1253 try uleb128(writer, reg_off.reg);
1254 }
1255 try uleb128(writer, unsigned_off);
1256 } else {
1257 try writer.writeByte(DW.CFA.offset_extended_sf);
1258 try uleb128(writer, reg_off.reg);
1259 try sleb128(writer, factored_off);
1260 }
1261 },
1262 .restore => |reg| if (std.math.cast(u6, reg)) |small_reg|
1263 try writer.writeByte(@as(u8, DW.CFA.restore) + small_reg)
1264 else {
1265 try writer.writeByte(DW.CFA.restore_extended);
1266 try uleb128(writer, reg);
1267 },
1268 .undefined => |reg| {
1269 try writer.writeByte(DW.CFA.undefined);
1270 try uleb128(writer, reg);
1271 },
1272 .same_value => |reg| {
1273 try writer.writeByte(DW.CFA.same_value);
1274 try uleb128(writer, reg);
1275 },
1276 .register => |regs| if (regs[0] != regs[1]) {
1277 try writer.writeByte(DW.CFA.register);
1278 for (regs) |reg| try uleb128(writer, reg);
1279 } else {
1280 try writer.writeByte(DW.CFA.same_value);
1281 try uleb128(writer, regs[0]);
1282 },
1283 .remember_state => try writer.writeByte(DW.CFA.remember_state),
1284 .restore_state => try writer.writeByte(DW.CFA.restore_state),
1285 .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => {
1286 const reg_off: RegOff = switch (cfa) {
1287 else => unreachable,
1288 .def_cfa => |reg_off| reg_off,
1289 .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off },
1290 .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off },
1291 .adjust_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = wip_nav.cfi.cfa.off + off },
1292 };
1293 const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg;
1294 const unsigned_off = std.math.cast(u63, reg_off.off);
1295 if (reg_off.off == wip_nav.cfi.cfa.off) {
1296 if (changed_reg) {
1297 try writer.writeByte(DW.CFA.def_cfa_register);
1298 try uleb128(writer, reg_off.reg);
1299 }
1300 } else if (switch (wip_nav.dwarf.debug_frame.header.data_alignment_factor) {
1301 0 => unreachable,
1302 1 => unsigned_off != null,
1303 else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0,
1304 }) {
1305 try writer.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset);
1306 if (changed_reg) try uleb128(writer, reg_off.reg);
1307 try uleb128(writer, unsigned_off.?);
1308 } else {
1309 try writer.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf);
1310 if (changed_reg) try uleb128(writer, reg_off.reg);
1311 try sleb128(writer, @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor));
1312 }
1313 wip_nav.cfi.cfa = reg_off;
1314 },
1315 .def_cfa_expression => |expr| {
1316 try writer.writeByte(DW.CFA.def_cfa_expression);
1317 try wip_nav.frameExprloc(expr);
1318 },
1319 .expression => |reg_expr| {
1320 try writer.writeByte(DW.CFA.expression);
1321 try uleb128(writer, reg_expr.reg);
1322 try wip_nav.frameExprloc(reg_expr.expr);
1323 },
1324 .val_offset => |reg_off| {
1325 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
1326 if (std.math.cast(u63, factored_off)) |unsigned_off| {
1327 try writer.writeByte(DW.CFA.val_offset);
1328 try uleb128(writer, reg_off.reg);
1329 try uleb128(writer, unsigned_off);
1330 } else {
1331 try writer.writeByte(DW.CFA.val_offset_sf);
1332 try uleb128(writer, reg_off.reg);
1333 try sleb128(writer, factored_off);
1334 }
1335 },
1336 .val_expression => |reg_expr| {
1337 try writer.writeByte(DW.CFA.val_expression);
1338 try uleb128(writer, reg_expr.reg);
1339 try wip_nav.frameExprloc(reg_expr.expr);
1340 },
1341 .escape => |bytes| try writer.writeAll(bytes),
1342 }
1343 }
1344};
1345
1062pub const WipNav = struct {1346pub const WipNav = struct {
1063 dwarf: *Dwarf,1347 dwarf: *Dwarf,
1064 pt: Zcu.PerThread,1348 pt: Zcu.PerThread,
...@@ -1072,6 +1356,11 @@ pub const WipNav = struct {...@@ -1072,6 +1356,11 @@ pub const WipNav = struct {
1072 abbrev_code: u32,1356 abbrev_code: u32,
1073 high_reloc: u32,1357 high_reloc: u32,
1074 }),1358 }),
1359 cfi: struct {
1360 loc: u32,
1361 cfa: Cfa.RegOff,
1362 },
1363 debug_frame: std.ArrayListUnmanaged(u8),
1075 debug_info: std.ArrayListUnmanaged(u8),1364 debug_info: std.ArrayListUnmanaged(u8),
1076 debug_line: std.ArrayListUnmanaged(u8),1365 debug_line: std.ArrayListUnmanaged(u8),
1077 debug_loclists: std.ArrayListUnmanaged(u8),1366 debug_loclists: std.ArrayListUnmanaged(u8),
...@@ -1080,14 +1369,19 @@ pub const WipNav = struct {...@@ -1080,14 +1369,19 @@ pub const WipNav = struct {
1080 pub fn deinit(wip_nav: *WipNav) void {1369 pub fn deinit(wip_nav: *WipNav) void {
1081 const gpa = wip_nav.dwarf.gpa;1370 const gpa = wip_nav.dwarf.gpa;
1082 if (wip_nav.func != .none) wip_nav.inlined_funcs.deinit(gpa);1371 if (wip_nav.func != .none) wip_nav.inlined_funcs.deinit(gpa);
1372 wip_nav.debug_frame.deinit(gpa);
1083 wip_nav.debug_info.deinit(gpa);1373 wip_nav.debug_info.deinit(gpa);
1084 wip_nav.debug_line.deinit(gpa);1374 wip_nav.debug_line.deinit(gpa);
1085 wip_nav.debug_loclists.deinit(gpa);1375 wip_nav.debug_loclists.deinit(gpa);
1086 wip_nav.pending_types.deinit(gpa);1376 wip_nav.pending_types.deinit(gpa);
1087 }1377 }
10881378
1089 pub fn infoWriter(wip_nav: *WipNav) std.ArrayListUnmanaged(u8).Writer {1379 pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
1090 return wip_nav.debug_info.writer(wip_nav.dwarf.gpa);1380 assert(wip_nav.func != .none);
1381 if (wip_nav.dwarf.debug_frame.header.format == .none) return;
1382 const loc_cfa: Cfa = .{ .advance_loc = loc };
1383 try loc_cfa.write(wip_nav);
1384 try cfa.write(wip_nav);
1091 }1385 }
10921386
1093 pub const LocalTag = enum { local_arg, local_var };1387 pub const LocalTag = enum { local_arg, local_var };
...@@ -1293,7 +1587,7 @@ pub const WipNav = struct {...@@ -1293,7 +1587,7 @@ pub const WipNav = struct {
1293 } else {1587 } else {
1294 try entry_ptr.cross_entry_relocs.append(gpa, .{1588 try entry_ptr.cross_entry_relocs.append(gpa, .{
1295 .source_off = @intCast(wip_nav.debug_info.items.len),1589 .source_off = @intCast(wip_nav.debug_info.items.len),
1296 .target_entry = entry,1590 .target_entry = entry.toOptional(),
1297 .target_off = off,1591 .target_off = off,
1298 });1592 });
1299 }1593 }
...@@ -1304,7 +1598,45 @@ pub const WipNav = struct {...@@ -1304,7 +1598,45 @@ pub const WipNav = struct {
1304 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);1598 try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
1305 }1599 }
13061600
1307 fn addrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {1601 const ExprLocCounter = struct {
1602 const Stream = std.io.CountingWriter(std.io.NullWriter);
1603 stream: Stream,
1604 address_size: AddressSize,
1605 fn writer(counter: *ExprLocCounter) Stream.Writer {
1606 return counter.stream.writer();
1607 }
1608 fn endian(_: ExprLocCounter) std.builtin.Endian {
1609 return @import("builtin").cpu.arch.endian();
1610 }
1611 fn addrSym(counter: *ExprLocCounter, _: u32) error{}!void {
1612 counter.stream.bytes_written += @intFromEnum(counter.address_size);
1613 }
1614 };
1615
1616 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1617 var counter: ExprLocCounter = .{
1618 .stream = std.io.countingWriter(std.io.null_writer),
1619 .address_size = wip_nav.dwarf.address_size,
1620 };
1621 try loc.write(&counter);
1622
1623 const adapter: struct {
1624 wip_nav: *WipNav,
1625 fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer {
1626 return ctx.wip_nav.debug_info.writer(ctx.wip_nav.dwarf.gpa);
1627 }
1628 fn endian(ctx: @This()) std.builtin.Endian {
1629 return ctx.wip_nav.dwarf.endian;
1630 }
1631 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1632 try ctx.wip_nav.infoAddrSym(sym_index);
1633 }
1634 } = .{ .wip_nav = wip_nav };
1635 try uleb128(adapter.writer(), counter.stream.bytes_written);
1636 try loc.write(adapter);
1637 }
1638
1639 fn infoAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1308 const dwarf = wip_nav.dwarf;1640 const dwarf = wip_nav.dwarf;
1309 try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{1641 try dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
1310 .source_off = @intCast(wip_nav.debug_info.items.len),1642 .source_off = @intCast(wip_nav.debug_info.items.len),
...@@ -1313,25 +1645,36 @@ pub const WipNav = struct {...@@ -1313,25 +1645,36 @@ pub const WipNav = struct {
1313 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));1645 try wip_nav.debug_info.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
1314 }1646 }
13151647
1316 fn exprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {1648 fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1317 if (loc == .empty) return;1649 var counter: ExprLocCounter = .{
1318 var wip: struct {1650 .stream = std.io.countingWriter(std.io.null_writer),
1319 const Info = std.io.CountingWriter(std.io.NullWriter);1651 .address_size = wip_nav.dwarf.address_size,
1320 dwarf: *Dwarf,1652 };
1321 debug_info: Info,1653 try loc.write(&counter);
1322 fn infoWriter(wip: *@This()) Info.Writer {1654
1323 return wip.debug_info.writer();1655 const adapter: struct {
1656 wip_nav: *WipNav,
1657 fn writer(ctx: @This()) std.ArrayListUnmanaged(u8).Writer {
1658 return ctx.wip_nav.debug_frame.writer(ctx.wip_nav.dwarf.gpa);
1324 }1659 }
1325 fn addrSym(wip: *@This(), _: u32) error{}!void {1660 fn endian(ctx: @This()) std.builtin.Endian {
1326 wip.debug_info.bytes_written += @intFromEnum(wip.dwarf.address_size);1661 return ctx.wip_nav.dwarf.endian;
1327 }1662 }
1328 } = .{1663 fn addrSym(ctx: @This(), sym_index: u32) UpdateError!void {
1329 .dwarf = wip_nav.dwarf,1664 try ctx.wip_nav.frameAddrSym(sym_index);
1330 .debug_info = std.io.countingWriter(std.io.null_writer),1665 }
1331 };1666 } = .{ .wip_nav = wip_nav };
1332 try loc.write(&wip);1667 try uleb128(adapter.writer(), counter.stream.bytes_written);
1333 try uleb128(wip_nav.debug_info.writer(wip_nav.dwarf.gpa), wip.debug_info.bytes_written);1668 try loc.write(adapter);
1334 try loc.write(wip_nav);1669 }
1670
1671 fn frameAddrSym(wip_nav: *WipNav, sym_index: u32) UpdateError!void {
1672 const dwarf = wip_nav.dwarf;
1673 try dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{
1674 .source_off = @intCast(wip_nav.debug_frame.items.len),
1675 .target_sym = sym_index,
1676 });
1677 try wip_nav.debug_frame.appendNTimes(dwarf.gpa, 0, @intFromEnum(dwarf.address_size));
1335 }1678 }
13361679
1337 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {1680 fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
...@@ -1379,7 +1722,7 @@ pub const WipNav = struct {...@@ -1379,7 +1722,7 @@ pub const WipNav = struct {
13791722
1380 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {1723 fn finishForward(wip_nav: *WipNav, reloc_index: u32) void {
1381 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];1724 const reloc = &wip_nav.dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_entry_relocs.items[reloc_index];
1382 reloc.target_entry = wip_nav.entry;1725 reloc.target_entry = wip_nav.entry.toOptional();
1383 reloc.target_off = @intCast(wip_nav.debug_info.items.len);1726 reloc.target_off = @intCast(wip_nav.debug_info.items.len);
1384 }1727 }
13851728
...@@ -1401,7 +1744,7 @@ pub const WipNav = struct {...@@ -1401,7 +1744,7 @@ pub const WipNav = struct {
1401 else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,1744 else => Type.fromInterned(loaded_enum.tag_ty).intInfo(zcu).signedness,
1402 };1745 };
1403 if (loaded_enum.values.len > 0) {1746 if (loaded_enum.values.len > 0) {
1404 var big_int_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;1747 var big_int_space: Value.BigIntSpace = undefined;
1405 const big_int = ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage.toBigInt(&big_int_space);1748 const big_int = ip.indexToKey(loaded_enum.values.get(ip)[field_index]).int.storage.toBigInt(&big_int_space);
1406 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));1749 const bits = @max(1, big_int.bitCountTwosCompForSignedness(signedness));
1407 if (bits <= 64) {1750 if (bits <= 64) {
...@@ -1429,9 +1772,12 @@ pub const WipNav = struct {...@@ -1429,9 +1772,12 @@ pub const WipNav = struct {
1429 }1772 }
1430 } else {1773 } else {
1431 try wip_nav.abbrevCode(abbrev_code.block);1774 try wip_nav.abbrevCode(abbrev_code.block);
1432 const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(wip_nav.pt.zcu);1775 const bytes = Type.fromInterned(loaded_enum.tag_ty).abiSize(zcu);
1433 try uleb128(diw, bytes);1776 try uleb128(diw, bytes);
1434 big_int.writeTwosComplement(try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)), wip_nav.dwarf.endian);1777 big_int.writeTwosComplement(
1778 try wip_nav.debug_info.addManyAsSlice(wip_nav.dwarf.gpa, @intCast(bytes)),
1779 wip_nav.dwarf.endian,
1780 );
1435 }1781 }
1436 } else switch (signedness) {1782 } else switch (signedness) {
1437 .signed => {1783 .signed => {
...@@ -1479,6 +1825,28 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {...@@ -1479,6 +1825,28 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
14791825
1480 .debug_abbrev = .{ .section = Section.init },1826 .debug_abbrev = .{ .section = Section.init },
1481 .debug_aranges = .{ .section = Section.init },1827 .debug_aranges = .{ .section = Section.init },
1828 .debug_frame = .{
1829 .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: {
1830 const Register = @import("../arch/x86_64/bits.zig").Register;
1831 break :header comptime .{
1832 .format = .eh_frame,
1833 .code_alignment_factor = 1,
1834 .data_alignment_factor = -8,
1835 .return_address_register = Register.rip.dwarfNum(),
1836 .initial_instructions = &.{
1837 .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } },
1838 .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } },
1839 },
1840 };
1841 } else .{
1842 .format = .none,
1843 .code_alignment_factor = undefined,
1844 .data_alignment_factor = undefined,
1845 .return_address_register = undefined,
1846 .initial_instructions = &.{},
1847 },
1848 .section = Section.init,
1849 },
1482 .debug_info = .{ .section = Section.init },1850 .debug_info = .{ .section = Section.init },
1483 .debug_line = .{1851 .debug_line = .{
1484 .header = switch (target.cpu.arch) {1852 .header = switch (target.cpu.arch) {
...@@ -1513,6 +1881,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {...@@ -1513,6 +1881,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1513 for ([_]*Section{1881 for ([_]*Section{
1514 &dwarf.debug_abbrev.section,1882 &dwarf.debug_abbrev.section,
1515 &dwarf.debug_aranges.section,1883 &dwarf.debug_aranges.section,
1884 &dwarf.debug_frame.section,
1516 &dwarf.debug_info.section,1885 &dwarf.debug_info.section,
1517 &dwarf.debug_line.section,1886 &dwarf.debug_line.section,
1518 &dwarf.debug_line_str.section,1887 &dwarf.debug_line_str.section,
...@@ -1522,6 +1891,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {...@@ -1522,6 +1891,7 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void {
1522 }, [_]u32{1891 }, [_]u32{
1523 elf_file.debug_abbrev_section_index.?,1892 elf_file.debug_abbrev_section_index.?,
1524 elf_file.debug_aranges_section_index.?,1893 elf_file.debug_aranges_section_index.?,
1894 elf_file.eh_frame_section_index.?,
1525 elf_file.debug_info_section_index.?,1895 elf_file.debug_info_section_index.?,
1526 elf_file.debug_line_section_index.?,1896 elf_file.debug_line_section_index.?,
1527 elf_file.debug_line_str_section_index.?,1897 elf_file.debug_line_str_section_index.?,
...@@ -1601,6 +1971,12 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {...@@ -1601,6 +1971,12 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
1601 dwarf.debug_aranges.section.pad_to_ideal = false;1971 dwarf.debug_aranges.section.pad_to_ideal = false;
1602 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);1972 dwarf.debug_aranges.section.alignment = InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size) * 2);
16031973
1974 dwarf.debug_frame.section.alignment = switch (dwarf.debug_frame.header.format) {
1975 .none => .@"1",
1976 .debug_frame => InternPool.Alignment.fromNonzeroByteUnits(@intFromEnum(dwarf.address_size)),
1977 .eh_frame => .@"4",
1978 };
1979
1604 dwarf.debug_line_str.section.pad_to_ideal = false;1980 dwarf.debug_line_str.section.pad_to_ideal = false;
1605 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);1981 assert(try dwarf.debug_line_str.section.addUnit(0, 0, dwarf) == StringSection.unit);
1606 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);1982 errdefer dwarf.debug_line_str.section.popUnit(dwarf.gpa);
...@@ -1622,6 +1998,7 @@ pub fn deinit(dwarf: *Dwarf) void {...@@ -1622,6 +1998,7 @@ pub fn deinit(dwarf: *Dwarf) void {
1622 dwarf.navs.deinit(gpa);1998 dwarf.navs.deinit(gpa);
1623 dwarf.debug_abbrev.section.deinit(gpa);1999 dwarf.debug_abbrev.section.deinit(gpa);
1624 dwarf.debug_aranges.section.deinit(gpa);2000 dwarf.debug_aranges.section.deinit(gpa);
2001 dwarf.debug_frame.section.deinit(gpa);
1625 dwarf.debug_info.section.deinit(gpa);2002 dwarf.debug_info.section.deinit(gpa);
1626 dwarf.debug_line.section.deinit(gpa);2003 dwarf.debug_line.section.deinit(gpa);
1627 dwarf.debug_line_str.deinit(gpa);2004 dwarf.debug_line_str.deinit(gpa);
...@@ -1649,6 +2026,12 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {...@@ -1649,6 +2026,12 @@ fn getUnit(dwarf: *Dwarf, mod: *Module) UpdateError!Unit.Index {
1649 dwarf,2026 dwarf,
1650 ) == unit);2027 ) == unit);
1651 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);2028 errdefer dwarf.debug_aranges.section.popUnit(dwarf.gpa);
2029 assert(try dwarf.debug_frame.section.addUnit(
2030 DebugFrame.headerBytes(dwarf),
2031 DebugFrame.trailerBytes(dwarf),
2032 dwarf,
2033 ) == unit);
2034 errdefer dwarf.debug_frame.section.popUnit(dwarf.gpa);
1652 assert(try dwarf.debug_info.section.addUnit(2035 assert(try dwarf.debug_info.section.addUnit(
1653 DebugInfo.headerBytes(dwarf),2036 DebugInfo.headerBytes(dwarf),
1654 DebugInfo.trailer_bytes,2037 DebugInfo.trailer_bytes,
...@@ -1718,6 +2101,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In...@@ -1718,6 +2101,8 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
1718 .func_sym_index = undefined,2101 .func_sym_index = undefined,
1719 .func_high_reloc = undefined,2102 .func_high_reloc = undefined,
1720 .inlined_funcs = undefined,2103 .inlined_funcs = undefined,
2104 .cfi = undefined,
2105 .debug_frame = .{},
1721 .debug_info = .{},2106 .debug_info = .{},
1722 .debug_line = .{},2107 .debug_line = .{},
1723 .debug_loclists = .{},2108 .debug_loclists = .{},
...@@ -1859,6 +2244,50 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In...@@ -1859,6 +2244,50 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
1859 wip_nav.func = nav_val.toIntern();2244 wip_nav.func = nav_val.toIntern();
1860 wip_nav.func_sym_index = sym_index;2245 wip_nav.func_sym_index = sym_index;
1861 wip_nav.inlined_funcs = .{};2246 wip_nav.inlined_funcs = .{};
2247 if (dwarf.debug_frame.header.format != .none) wip_nav.cfi = .{
2248 .loc = 0,
2249 .cfa = dwarf.debug_frame.header.initial_instructions[0].def_cfa,
2250 };
2251
2252 switch (dwarf.debug_frame.header.format) {
2253 .none => {},
2254 .debug_frame, .eh_frame => |format| {
2255 const entry = dwarf.debug_frame.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry);
2256 const dfw = wip_nav.debug_frame.writer(dwarf.gpa);
2257 switch (dwarf.format) {
2258 .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian),
2259 .@"64" => {
2260 try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian);
2261 try dfw.writeInt(u64, undefined, dwarf.endian);
2262 },
2263 }
2264 switch (format) {
2265 .none => unreachable,
2266 .debug_frame => {
2267 try entry.cross_entry_relocs.append(dwarf.gpa, .{
2268 .source_off = @intCast(wip_nav.debug_frame.items.len),
2269 });
2270 try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
2271 try entry.external_relocs.append(dwarf.gpa, .{
2272 .source_off = @intCast(wip_nav.debug_frame.items.len),
2273 .target_sym = sym_index,
2274 });
2275 try dfw.writeByteNTimes(0, @intFromEnum(dwarf.address_size));
2276 try dfw.writeByteNTimes(undefined, @intFromEnum(dwarf.address_size));
2277 },
2278 .eh_frame => {
2279 try dfw.writeInt(u32, undefined, dwarf.endian);
2280 try entry.external_relocs.append(dwarf.gpa, .{
2281 .source_off = @intCast(wip_nav.debug_frame.items.len),
2282 .target_sym = sym_index,
2283 });
2284 try dfw.writeByteNTimes(0, dwarf.sectionOffsetBytes());
2285 try dfw.writeInt(u32, undefined, dwarf.endian);
2286 try uleb128(dfw, 0);
2287 },
2288 }
2289 },
2290 }
18622291
1863 const diw = wip_nav.debug_info.writer(dwarf.gpa);2292 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1864 try wip_nav.abbrevCode(.decl_func);2293 try wip_nav.abbrevCode(.decl_func);
...@@ -1942,49 +2371,84 @@ pub fn finishWipNav(...@@ -1942,49 +2371,84 @@ pub fn finishWipNav(
1942 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});2371 log.debug("finishWipNav({})", .{nav.fqn.fmt(ip)});
19432372
1944 if (wip_nav.func != .none) {2373 if (wip_nav.func != .none) {
1945 const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;2374 {
1946 external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;2375 const external_relocs = &dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
1947 if (wip_nav.any_children) {2376 try external_relocs.append(dwarf.gpa, .{ .target_sym = sym.index });
1948 const diw = wip_nav.debug_info.writer(dwarf.gpa);2377 var entry: [8 + 8]u8 = undefined;
1949 try uleb128(diw, @intFromEnum(AbbrevCode.null));2378 @memset(entry[0..@intFromEnum(dwarf.address_size)], 0);
1950 } else std.leb.writeUnsignedFixed(2379 dwarf.writeInt(entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);
1951 AbbrevCode.decl_bytes,2380 try dwarf.debug_aranges.section.replaceEntry(
1952 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],2381 wip_nav.unit,
1953 try dwarf.refAbbrevCode(.decl_empty_func),2382 wip_nav.entry,
1954 );2383 dwarf,
19552384 entry[0 .. @intFromEnum(dwarf.address_size) * 2],
1956 var aranges_entry = [1]u8{0} ** (8 + 8);2385 );
1957 try dwarf.debug_aranges.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.append(dwarf.gpa, .{2386 }
1958 .target_sym = sym.index,2387 switch (dwarf.debug_frame.header.format) {
1959 });2388 .none => {},
1960 dwarf.writeInt(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);2389 .debug_frame, .eh_frame => |format| {
1961 dwarf.writeInt(aranges_entry[@intFromEnum(dwarf.address_size)..][0..@intFromEnum(dwarf.address_size)], sym.size);2390 try wip_nav.debug_frame.appendNTimes(
19622391 dwarf.gpa,
1963 @memset(aranges_entry[0..@intFromEnum(dwarf.address_size)], 0);2392 DW.CFA.nop,
1964 try dwarf.debug_aranges.section.replaceEntry(2393 @intCast(dwarf.debug_frame.section.alignment.forward(wip_nav.debug_frame.items.len) - wip_nav.debug_frame.items.len),
1965 wip_nav.unit,2394 );
1966 wip_nav.entry,2395 const contents = wip_nav.debug_frame.items;
1967 dwarf,2396 try dwarf.debug_frame.section.resizeEntry(wip_nav.unit, wip_nav.entry, dwarf, @intCast(contents.len));
1968 aranges_entry[0 .. @intFromEnum(dwarf.address_size) * 2],2397 const unit = dwarf.debug_frame.section.getUnit(wip_nav.unit);
1969 );2398 const entry = unit.getEntry(wip_nav.entry);
19702399 const unit_len = (if (entry.next.unwrap()) |next_entry|
1971 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{2400 unit.getEntry(next_entry).off - entry.off
1972 .{2401 else
1973 .source_off = 1,2402 entry.len) - dwarf.unitLengthBytes();
1974 .target_sym = sym.index,2403 dwarf.writeInt(contents[dwarf.unitLengthBytes() - dwarf.sectionOffsetBytes() ..][0..dwarf.sectionOffsetBytes()], unit_len);
1975 },2404 switch (format) {
1976 .{2405 .none => unreachable,
1977 .source_off = 1 + @intFromEnum(dwarf.address_size),2406 .debug_frame => dwarf.writeInt(contents[dwarf.unitLengthBytes() + dwarf.sectionOffsetBytes() +
1978 .target_sym = sym.index,2407 @intFromEnum(dwarf.address_size) ..][0..@intFromEnum(dwarf.address_size)], sym.size),
1979 .target_off = sym.size,2408 .eh_frame => {
2409 std.mem.writeInt(
2410 u32,
2411 contents[dwarf.unitLengthBytes()..][0..4],
2412 unit.header_len + entry.off + dwarf.unitLengthBytes(),
2413 dwarf.endian,
2414 );
2415 std.mem.writeInt(u32, contents[dwarf.unitLengthBytes() + 4 + 4 ..][0..4], @intCast(sym.size), dwarf.endian);
2416 },
2417 }
2418 try entry.replace(unit, &dwarf.debug_frame.section, dwarf, contents);
1980 },2419 },
1981 });2420 }
1982 try dwarf.debug_rnglists.section.replaceEntry(2421 {
1983 wip_nav.unit,2422 const external_relocs = &dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs;
1984 wip_nav.entry,2423 external_relocs.items[wip_nav.func_high_reloc].target_off = sym.size;
1985 dwarf,2424 if (wip_nav.any_children) {
1986 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],2425 const diw = wip_nav.debug_info.writer(dwarf.gpa);
1987 );2426 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2427 } else std.leb.writeUnsignedFixed(
2428 AbbrevCode.decl_bytes,
2429 wip_nav.debug_info.items[0..AbbrevCode.decl_bytes],
2430 try dwarf.refAbbrevCode(.decl_empty_func),
2431 );
2432 }
2433 {
2434 try dwarf.debug_rnglists.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).external_relocs.appendSlice(dwarf.gpa, &.{
2435 .{
2436 .source_off = 1,
2437 .target_sym = sym.index,
2438 },
2439 .{
2440 .source_off = 1 + @intFromEnum(dwarf.address_size),
2441 .target_sym = sym.index,
2442 .target_off = sym.size,
2443 },
2444 });
2445 try dwarf.debug_rnglists.section.replaceEntry(
2446 wip_nav.unit,
2447 wip_nav.entry,
2448 dwarf,
2449 ([1]u8{DW.RLE.start_end} ++ [1]u8{0} ** (8 + 8))[0 .. 1 + @intFromEnum(dwarf.address_size) + @intFromEnum(dwarf.address_size)],
2450 );
2451 }
1988 }2452 }
19892453
1990 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);2454 try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.items);
...@@ -2027,6 +2491,8 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool...@@ -2027,6 +2491,8 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
2027 .func_sym_index = undefined,2491 .func_sym_index = undefined,
2028 .func_high_reloc = undefined,2492 .func_high_reloc = undefined,
2029 .inlined_funcs = undefined,2493 .inlined_funcs = undefined,
2494 .cfi = undefined,
2495 .debug_frame = .{},
2030 .debug_info = .{},2496 .debug_info = .{},
2031 .debug_line = .{},2497 .debug_line = .{},
2032 .debug_loclists = .{},2498 .debug_loclists = .{},
...@@ -2535,6 +3001,8 @@ fn updateType(...@@ -2535,6 +3001,8 @@ fn updateType(
2535 .func_sym_index = undefined,3001 .func_sym_index = undefined,
2536 .func_high_reloc = undefined,3002 .func_high_reloc = undefined,
2537 .inlined_funcs = undefined,3003 .inlined_funcs = undefined,
3004 .cfi = undefined,
3005 .debug_frame = .{},
2538 .debug_info = .{},3006 .debug_info = .{},
2539 .debug_line = .{},3007 .debug_line = .{},
2540 .debug_loclists = .{},3008 .debug_loclists = .{},
...@@ -2566,8 +3034,17 @@ fn updateType(...@@ -2566,8 +3034,17 @@ fn updateType(
2566 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {3034 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2567 .One, .Many, .C => {3035 .One, .Many, .C => {
2568 const ptr_child_type = Type.fromInterned(ptr_type.child);3036 const ptr_child_type = Type.fromInterned(ptr_type.child);
2569 try wip_nav.abbrevCode(.ptr_type);3037 try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
2570 try wip_nav.strp(name);3038 try wip_nav.strp(name);
3039 if (ptr_type.sentinel != .none) {
3040 const bytes = ptr_child_type.abiSize(zcu);
3041 try uleb128(diw, bytes);
3042 const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
3043 Value.fromInterned(ptr_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
3044 error.IllDefinedMemoryLayout => @memset(mem, 0),
3045 else => |e| return e,
3046 };
3047 }
2571 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse3048 try uleb128(diw, ptr_type.flags.alignment.toByteUnits() orelse
2572 ptr_child_type.abiAlignment(zcu).toByteUnits().?);3049 ptr_child_type.abiAlignment(zcu).toByteUnits().?);
2573 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));3050 try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
...@@ -2609,16 +3086,34 @@ fn updateType(...@@ -2609,16 +3086,34 @@ fn updateType(
2609 try uleb128(diw, @intFromEnum(AbbrevCode.null));3086 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2610 },3087 },
2611 },3088 },
2612 inline .array_type, .vector_type => |array_type, ty_tag| {3089 .array_type => |array_type| {
2613 try wip_nav.abbrevCode(.array_type);3090 const array_child_type = Type.fromInterned(array_type.child);
3091 try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
2614 try wip_nav.strp(name);3092 try wip_nav.strp(name);
2615 try wip_nav.refType(Type.fromInterned(array_type.child));3093 if (array_type.sentinel != .none) {
2616 try diw.writeByte(@intFromBool(ty_tag == .vector_type));3094 const bytes = array_child_type.abiSize(zcu);
3095 try uleb128(diw, bytes);
3096 const mem = try wip_nav.debug_info.addManyAsSlice(dwarf.gpa, @intCast(bytes));
3097 Value.fromInterned(array_type.sentinel).writeToMemory(pt, mem) catch |err| switch (err) {
3098 error.IllDefinedMemoryLayout => @memset(mem, 0),
3099 else => |e| return e,
3100 };
3101 }
3102 try wip_nav.refType(array_child_type);
2617 try wip_nav.abbrevCode(.array_index);3103 try wip_nav.abbrevCode(.array_index);
2618 try wip_nav.refType(Type.usize);3104 try wip_nav.refType(Type.usize);
2619 try uleb128(diw, array_type.len);3105 try uleb128(diw, array_type.len);
2620 try uleb128(diw, @intFromEnum(AbbrevCode.null));3106 try uleb128(diw, @intFromEnum(AbbrevCode.null));
2621 },3107 },
3108 .vector_type => |vector_type| {
3109 try wip_nav.abbrevCode(.vector_type);
3110 try wip_nav.strp(name);
3111 try wip_nav.refType(Type.fromInterned(vector_type.child));
3112 try wip_nav.abbrevCode(.array_index);
3113 try wip_nav.refType(Type.usize);
3114 try uleb128(diw, vector_type.len);
3115 try uleb128(diw, @intFromEnum(AbbrevCode.null));
3116 },
2622 .opt_type => |opt_child_type_index| {3117 .opt_type => |opt_child_type_index| {
2623 const opt_child_type = Type.fromInterned(opt_child_type_index);3118 const opt_child_type = Type.fromInterned(opt_child_type_index);
2624 try wip_nav.abbrevCode(.union_type);3119 try wip_nav.abbrevCode(.union_type);
...@@ -2660,7 +3155,7 @@ fn updateType(...@@ -2660,7 +3155,7 @@ fn updateType(
2660 .error_set => {3155 .error_set => {
2661 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{3156 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2662 .signedness = .unsigned,3157 .signedness = .unsigned,
2663 .bits = pt.zcu.errorSetBits(),3158 .bits = zcu.errorSetBits(),
2664 } })));3159 } })));
2665 try uleb128(diw, 0);3160 try uleb128(diw, 0);
2666 },3161 },
...@@ -2729,7 +3224,7 @@ fn updateType(...@@ -2729,7 +3224,7 @@ fn updateType(
2729 try wip_nav.strp("is_error");3224 try wip_nav.strp("is_error");
2730 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{3225 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2731 .signedness = .unsigned,3226 .signedness = .unsigned,
2732 .bits = pt.zcu.errorSetBits(),3227 .bits = zcu.errorSetBits(),
2733 } })));3228 } })));
2734 try uleb128(diw, error_union_error_set_offset);3229 try uleb128(diw, error_union_error_set_offset);
27353230
...@@ -2892,7 +3387,7 @@ fn updateType(...@@ -2892,7 +3387,7 @@ fn updateType(
2892 try wip_nav.strp(name);3387 try wip_nav.strp(name);
2893 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{3388 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
2894 .signedness = .unsigned,3389 .signedness = .unsigned,
2895 .bits = pt.zcu.errorSetBits(),3390 .bits = zcu.errorSetBits(),
2896 } })));3391 } })));
2897 for (0..error_set_type.names.len) |field_index| {3392 for (0..error_set_type.names.len) |field_index| {
2898 const field_name = error_set_type.names.get(ip)[field_index];3393 const field_name = error_set_type.names.get(ip)[field_index];
...@@ -2961,6 +3456,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP...@@ -2961,6 +3456,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
2961 .func_sym_index = undefined,3456 .func_sym_index = undefined,
2962 .func_high_reloc = undefined,3457 .func_high_reloc = undefined,
2963 .inlined_funcs = undefined,3458 .inlined_funcs = undefined,
3459 .cfi = undefined,
3460 .debug_frame = .{},
2964 .debug_info = .{},3461 .debug_info = .{},
2965 .debug_line = .{},3462 .debug_line = .{},
2966 .debug_loclists = .{},3463 .debug_loclists = .{},
...@@ -3024,6 +3521,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP...@@ -3024,6 +3521,8 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
3024 .func_sym_index = undefined,3521 .func_sym_index = undefined,
3025 .func_high_reloc = undefined,3522 .func_high_reloc = undefined,
3026 .inlined_funcs = undefined,3523 .inlined_funcs = undefined,
3524 .cfi = undefined,
3525 .debug_frame = .{},
3027 .debug_info = .{},3526 .debug_info = .{},
3028 .debug_line = .{},3527 .debug_line = .{},
3029 .debug_loclists = .{},3528 .debug_loclists = .{},
...@@ -3204,7 +3703,8 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A...@@ -3204,7 +3703,8 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
3204}3703}
32053704
3206pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {3705pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3207 const ip = &pt.zcu.intern_pool;3706 const zcu = pt.zcu;
3707 const ip = &zcu.intern_pool;
3208 if (dwarf.types.get(.anyerror_type)) |entry| {3708 if (dwarf.types.get(.anyerror_type)) |entry| {
3209 var wip_nav: WipNav = .{3709 var wip_nav: WipNav = .{
3210 .dwarf = dwarf,3710 .dwarf = dwarf,
...@@ -3216,6 +3716,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3216,6 +3716,8 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3216 .func_sym_index = undefined,3716 .func_sym_index = undefined,
3217 .func_high_reloc = undefined,3717 .func_high_reloc = undefined,
3218 .inlined_funcs = undefined,3718 .inlined_funcs = undefined,
3719 .cfi = undefined,
3720 .debug_frame = .{},
3219 .debug_info = .{},3721 .debug_info = .{},
3220 .debug_line = .{},3722 .debug_line = .{},
3221 .debug_loclists = .{},3723 .debug_loclists = .{},
...@@ -3228,7 +3730,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3228,7 +3730,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3228 try wip_nav.strp("anyerror");3730 try wip_nav.strp("anyerror");
3229 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{3731 try wip_nav.refType(Type.fromInterned(try pt.intern(.{ .int_type = .{
3230 .signedness = .unsigned,3732 .signedness = .unsigned,
3231 .bits = pt.zcu.errorSetBits(),3733 .bits = zcu.errorSetBits(),
3232 } })));3734 } })));
3233 for (global_error_set_names, 1..) |name, value| {3735 for (global_error_set_names, 1..) |name, value| {
3234 try wip_nav.abbrevCode(.unsigned_enum_field);3736 try wip_nav.abbrevCode(.unsigned_enum_field);
...@@ -3267,13 +3769,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3267,13 +3769,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3267 else3769 else
3268 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();3770 dwarf.debug_aranges.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3269 switch (dwarf.format) {3771 switch (dwarf.format) {
3270 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),3772 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3271 .@"64" => {3773 .@"64" => {
3272 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);3774 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3273 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);3775 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3274 },3776 },
3275 }3777 }
3276 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 2, dwarf.endian);3778 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 2, dwarf.endian);
3277 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{3779 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3278 .source_off = @intCast(header.items.len),3780 .source_off = @intCast(header.items.len),
3279 .target_sec = .debug_info,3781 .target_sec = .debug_info,
...@@ -3287,6 +3789,49 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3287,6 +3789,49 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3287 }3789 }
3288 dwarf.debug_aranges.section.dirty = false;3790 dwarf.debug_aranges.section.dirty = false;
3289 }3791 }
3792 if (dwarf.debug_frame.section.dirty) {
3793 const target = dwarf.bin_file.comp.root_mod.resolved_target.result;
3794 switch (dwarf.debug_frame.header.format) {
3795 .none => {},
3796 .debug_frame => unreachable,
3797 .eh_frame => switch (target.cpu.arch) {
3798 .x86_64 => {
3799 dev.check(.x86_64_backend);
3800 const Register = @import("../arch/x86_64/bits.zig").Register;
3801 for (dwarf.debug_frame.section.units.items) |*unit| {
3802 header.clearRetainingCapacity();
3803 try header.ensureTotalCapacity(unit.header_len);
3804 const unit_len = unit.header_len - dwarf.unitLengthBytes();
3805 switch (dwarf.format) {
3806 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3807 .@"64" => {
3808 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3809 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3810 },
3811 }
3812 header.appendNTimesAssumeCapacity(0, 4);
3813 header.appendAssumeCapacity(1);
3814 header.appendSliceAssumeCapacity("zR\x00");
3815 uleb128(header.fixedWriter(), dwarf.debug_frame.header.code_alignment_factor) catch unreachable;
3816 sleb128(header.fixedWriter(), dwarf.debug_frame.header.data_alignment_factor) catch unreachable;
3817 uleb128(header.fixedWriter(), dwarf.debug_frame.header.return_address_register) catch unreachable;
3818 uleb128(header.fixedWriter(), 1) catch unreachable;
3819 header.appendAssumeCapacity(0x10 | 0x08 | 0x03);
3820 header.appendAssumeCapacity(DW.CFA.def_cfa_sf);
3821 uleb128(header.fixedWriter(), Register.rsp.dwarfNum()) catch unreachable;
3822 sleb128(header.fixedWriter(), -1) catch unreachable;
3823 header.appendAssumeCapacity(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum());
3824 uleb128(header.fixedWriter(), 1) catch unreachable;
3825 header.appendNTimesAssumeCapacity(DW.CFA.nop, unit.header_len - header.items.len);
3826 try unit.replaceHeader(&dwarf.debug_frame.section, dwarf, header.items);
3827 try unit.writeTrailer(&dwarf.debug_frame.section, dwarf);
3828 }
3829 },
3830 else => unreachable,
3831 },
3832 }
3833 dwarf.debug_frame.section.dirty = false;
3834 }
3290 if (dwarf.debug_info.section.dirty) {3835 if (dwarf.debug_info.section.dirty) {
3291 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {3836 for (dwarf.mods.keys(), dwarf.mods.values(), dwarf.debug_info.section.units.items, 0..) |mod, mod_info, *unit_ptr, unit_index| {
3292 const unit: Unit.Index = @enumFromInt(unit_index);3837 const unit: Unit.Index = @enumFromInt(unit_index);
...@@ -3300,13 +3845,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3300,13 +3845,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3300 else3845 else
3301 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();3846 dwarf.debug_info.section.len) - unit_ptr.off - dwarf.unitLengthBytes();
3302 switch (dwarf.format) {3847 switch (dwarf.format) {
3303 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),3848 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3304 .@"64" => {3849 .@"64" => {
3305 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);3850 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3306 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);3851 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3307 },3852 },
3308 }3853 }
3309 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);3854 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
3310 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });3855 header.appendSliceAssumeCapacity(&.{ DW.UT.compile, @intFromEnum(dwarf.address_size) });
3311 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{3856 unit_ptr.cross_section_relocs.appendAssumeCapacity(.{
3312 .source_off = @intCast(header.items.len),3857 .source_off = @intCast(header.items.len),
...@@ -3399,13 +3944,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3399,13 +3944,13 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3399 else3944 else
3400 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();3945 dwarf.debug_line.section.len) - unit.off - dwarf.unitLengthBytes();
3401 switch (dwarf.format) {3946 switch (dwarf.format) {
3402 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),3947 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3403 .@"64" => {3948 .@"64" => {
3404 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);3949 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3405 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);3950 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3406 },3951 },
3407 }3952 }
3408 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);3953 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
3409 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });3954 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3410 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len);3955 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), unit.header_len - header.items.len);
3411 const StandardOpcode = DeclValEnum(DW.LNS);3956 const StandardOpcode = DeclValEnum(DW.LNS);
...@@ -3455,7 +4000,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3455,7 +4000,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3455 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;4000 uleb128(header.fixedWriter(), DW.FORM.line_strp) catch unreachable;
3456 uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;4001 uleb128(header.fixedWriter(), mod_info.files.count()) catch unreachable;
3457 for (mod_info.files.keys()) |file_index| {4002 for (mod_info.files.keys()) |file_index| {
3458 const file = pt.zcu.fileByIndex(file_index);4003 const file = zcu.fileByIndex(file_index);
3459 unit.cross_section_relocs.appendAssumeCapacity(.{4004 unit.cross_section_relocs.appendAssumeCapacity(.{
3460 .source_off = @intCast(header.items.len),4005 .source_off = @intCast(header.items.len),
3461 .target_sec = .debug_line_str,4006 .target_sec = .debug_line_str,
...@@ -3501,15 +4046,15 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3501,15 +4046,15 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3501 else4046 else
3502 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();4047 dwarf.debug_rnglists.section.len) - unit.off - dwarf.unitLengthBytes();
3503 switch (dwarf.format) {4048 switch (dwarf.format) {
3504 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), @intCast(unit_len), dwarf.endian),4049 .@"32" => std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), @intCast(unit_len), dwarf.endian),
3505 .@"64" => {4050 .@"64" => {
3506 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), std.math.maxInt(u32), dwarf.endian);4051 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), std.math.maxInt(u32), dwarf.endian);
3507 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(@sizeOf(u64)), unit_len, dwarf.endian);4052 std.mem.writeInt(u64, header.addManyAsArrayAssumeCapacity(8), unit_len, dwarf.endian);
3508 },4053 },
3509 }4054 }
3510 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(@sizeOf(u16)), 5, dwarf.endian);4055 std.mem.writeInt(u16, header.addManyAsArrayAssumeCapacity(2), 5, dwarf.endian);
3511 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });4056 header.appendSliceAssumeCapacity(&.{ @intFromEnum(dwarf.address_size), 0 });
3512 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(@sizeOf(u32)), 1, dwarf.endian);4057 std.mem.writeInt(u32, header.addManyAsArrayAssumeCapacity(4), 1, dwarf.endian);
3513 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1);4058 dwarf.writeInt(header.addManyAsSliceAssumeCapacity(dwarf.sectionOffsetBytes()), dwarf.sectionOffsetBytes() * 1);
3514 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);4059 try unit.replaceHeader(&dwarf.debug_rnglists.section, dwarf, header.items);
3515 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);4060 try unit.writeTrailer(&dwarf.debug_rnglists.section, dwarf);
...@@ -3518,6 +4063,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -3518,6 +4063,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
3518 }4063 }
3519 assert(!dwarf.debug_abbrev.section.dirty);4064 assert(!dwarf.debug_abbrev.section.dirty);
3520 assert(!dwarf.debug_aranges.section.dirty);4065 assert(!dwarf.debug_aranges.section.dirty);
4066 assert(!dwarf.debug_frame.section.dirty);
3521 assert(!dwarf.debug_info.section.dirty);4067 assert(!dwarf.debug_info.section.dirty);
3522 assert(!dwarf.debug_line.section.dirty);4068 assert(!dwarf.debug_line.section.dirty);
3523 assert(!dwarf.debug_line_str.section.dirty);4069 assert(!dwarf.debug_line_str.section.dirty);
...@@ -3530,6 +4076,7 @@ pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {...@@ -3530,6 +4076,7 @@ pub fn resolveRelocs(dwarf: *Dwarf) RelocError!void {
3530 for ([_]*Section{4076 for ([_]*Section{
3531 &dwarf.debug_abbrev.section,4077 &dwarf.debug_abbrev.section,
3532 &dwarf.debug_aranges.section,4078 &dwarf.debug_aranges.section,
4079 &dwarf.debug_frame.section,
3533 &dwarf.debug_info.section,4080 &dwarf.debug_info.section,
3534 &dwarf.debug_line.section,4081 &dwarf.debug_line.section,
3535 &dwarf.debug_line_str.section,4082 &dwarf.debug_line_str.section,
...@@ -3602,9 +4149,12 @@ const AbbrevCode = enum {...@@ -3602,9 +4149,12 @@ const AbbrevCode = enum {
3602 numeric_type,4149 numeric_type,
3603 inferred_error_set_type,4150 inferred_error_set_type,
3604 ptr_type,4151 ptr_type,
4152 ptr_sentinel_type,
3605 is_const,4153 is_const,
3606 is_volatile,4154 is_volatile,
3607 array_type,4155 array_type,
4156 array_sentinel_type,
4157 vector_type,
3608 array_index,4158 array_index,
3609 nullary_func_type,4159 nullary_func_type,
3610 func_type,4160 func_type,
...@@ -3913,6 +4463,16 @@ const AbbrevCode = enum {...@@ -3913,6 +4463,16 @@ const AbbrevCode = enum {
3913 .{ .type, .ref_addr },4463 .{ .type, .ref_addr },
3914 },4464 },
3915 },4465 },
4466 .ptr_sentinel_type = .{
4467 .tag = .pointer_type,
4468 .attrs = &.{
4469 .{ .name, .strp },
4470 .{ .ZIG_sentinel, .block },
4471 .{ .alignment, .udata },
4472 .{ .address_class, .data1 },
4473 .{ .type, .ref_addr },
4474 },
4475 },
3916 .is_const = .{4476 .is_const = .{
3917 .tag = .const_type,4477 .tag = .const_type,
3918 .attrs = &.{4478 .attrs = &.{
...@@ -3931,7 +4491,24 @@ const AbbrevCode = enum {...@@ -3931,7 +4491,24 @@ const AbbrevCode = enum {
3931 .attrs = &.{4491 .attrs = &.{
3932 .{ .name, .strp },4492 .{ .name, .strp },
3933 .{ .type, .ref_addr },4493 .{ .type, .ref_addr },
3934 .{ .GNU_vector, .flag },4494 },
4495 },
4496 .array_sentinel_type = .{
4497 .tag = .array_type,
4498 .children = true,
4499 .attrs = &.{
4500 .{ .name, .strp },
4501 .{ .ZIG_sentinel, .block },
4502 .{ .type, .ref_addr },
4503 },
4504 },
4505 .vector_type = .{
4506 .tag = .array_type,
4507 .children = true,
4508 .attrs = &.{
4509 .{ .name, .strp },
4510 .{ .type, .ref_addr },
4511 .{ .GNU_vector, .flag_present },
3935 },4512 },
3936 },4513 },
3937 .array_index = .{4514 .array_index = .{
...@@ -4078,6 +4655,7 @@ fn getFile(dwarf: *Dwarf) ?std.fs.File {...@@ -4078,6 +4655,7 @@ fn getFile(dwarf: *Dwarf) ?std.fs.File {
40784655
4079fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {4656fn addCommonEntry(dwarf: *Dwarf, unit: Unit.Index) UpdateError!Entry.Index {
4080 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);4657 const entry = try dwarf.debug_aranges.section.getUnit(unit).addEntry(dwarf.gpa);
4658 assert(try dwarf.debug_frame.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
4081 assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);4659 assert(try dwarf.debug_info.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
4082 assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);4660 assert(try dwarf.debug_line.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
4083 assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);4661 assert(try dwarf.debug_loclists.section.getUnit(unit).addEntry(dwarf.gpa) == entry);
...@@ -4121,6 +4699,12 @@ fn uleb128Bytes(value: anytype) u32 {...@@ -4121,6 +4699,12 @@ fn uleb128Bytes(value: anytype) u32 {
4121 return @intCast(cw.bytes_written);4699 return @intCast(cw.bytes_written);
4122}4700}
41234701
4702fn sleb128Bytes(value: anytype) u32 {
4703 var cw = std.io.countingWriter(std.io.null_writer);
4704 try sleb128(cw.writer(), value);
4705 return @intCast(cw.bytes_written);
4706}
4707
4124/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional4708/// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional
4125const force_incremental = false;4709const force_incremental = false;
4126inline fn incremental(dwarf: Dwarf) bool {4710inline fn incremental(dwarf: Dwarf) bool {
...@@ -4132,10 +4716,12 @@ const Dwarf = @This();...@@ -4132,10 +4716,12 @@ const Dwarf = @This();
4132const InternPool = @import("../InternPool.zig");4716const InternPool = @import("../InternPool.zig");
4133const Module = @import("../Package.zig").Module;4717const Module = @import("../Package.zig").Module;
4134const Type = @import("../Type.zig");4718const Type = @import("../Type.zig");
4719const Value = @import("../Value.zig");
4135const Zcu = @import("../Zcu.zig");4720const Zcu = @import("../Zcu.zig");
4136const Zir = std.zig.Zir;4721const Zir = std.zig.Zir;
4137const assert = std.debug.assert;4722const assert = std.debug.assert;
4138const codegen = @import("../codegen.zig");4723const codegen = @import("../codegen.zig");
4724const dev = @import("../dev.zig");
4139const link = @import("../link.zig");4725const link = @import("../link.zig");
4140const log = std.log.scoped(.dwarf);4726const log = std.log.scoped(.dwarf);
4141const sleb128 = std.leb.writeIleb128;4727const sleb128 = std.leb.writeIleb128;
src/link/Elf.zig+80-53
...@@ -569,9 +569,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {...@@ -569,9 +569,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
569569
570 if (shdr.sh_type != elf.SHT_NOBITS) {570 if (shdr.sh_type != elf.SHT_NOBITS) {
571 const allocated_size = self.allocatedSize(shdr.sh_offset);571 const allocated_size = self.allocatedSize(shdr.sh_offset);
572 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {572 if (needed_size > allocated_size) {
573 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
574 } else if (needed_size > allocated_size) {
575 const existing_size = shdr.sh_size;573 const existing_size = shdr.sh_size;
576 shdr.sh_size = 0;574 shdr.sh_size = 0;
577 // Must move the entire section.575 // Must move the entire section.
...@@ -590,6 +588,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {...@@ -590,6 +588,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
590588
591 shdr.sh_offset = new_offset;589 shdr.sh_offset = new_offset;
592 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;590 if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
591 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
592 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
593 }593 }
594 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;594 if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
595 }595 }
...@@ -621,9 +621,7 @@ pub fn growNonAllocSection(...@@ -621,9 +621,7 @@ pub fn growNonAllocSection(
621 assert(shdr.sh_flags & elf.SHF_ALLOC == 0);621 assert(shdr.sh_flags & elf.SHF_ALLOC == 0);
622622
623 const allocated_size = self.allocatedSize(shdr.sh_offset);623 const allocated_size = self.allocatedSize(shdr.sh_offset);
624 if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {624 if (needed_size > allocated_size) {
625 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
626 } else if (needed_size > allocated_size) {
627 const existing_size = shdr.sh_size;625 const existing_size = shdr.sh_size;
628 shdr.sh_size = 0;626 shdr.sh_size = 0;
629 // Move all the symbols to a new file location.627 // Move all the symbols to a new file location.
...@@ -646,6 +644,8 @@ pub fn growNonAllocSection(...@@ -646,6 +644,8 @@ pub fn growNonAllocSection(
646 }644 }
647645
648 shdr.sh_offset = new_offset;646 shdr.sh_offset = new_offset;
647 } else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
648 try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
649 }649 }
650 shdr.sh_size = needed_size;650 shdr.sh_size = needed_size;
651651
...@@ -699,7 +699,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -699,7 +699,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
699 const sub_prog_node = prog_node.start("ELF Flush", 0);699 const sub_prog_node = prog_node.start("ELF Flush", 0);
700 defer sub_prog_node.end();700 defer sub_prog_node.end();
701701
702 const target = comp.root_mod.resolved_target.result;702 const target = self.getTarget();
703 const link_mode = comp.config.link_mode;703 const link_mode = comp.config.link_mode;
704 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.704 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
705 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});705 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
...@@ -1053,7 +1053,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1053,7 +1053,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1053 defer arena_allocator.deinit();1053 defer arena_allocator.deinit();
1054 const arena = arena_allocator.allocator();1054 const arena = arena_allocator.allocator();
10551055
1056 const target = self.base.comp.root_mod.resolved_target.result;1056 const target = self.getTarget();
1057 const link_mode = self.base.comp.config.link_mode;1057 const link_mode = self.base.comp.config.link_mode;
1058 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.1058 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
1059 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});1059 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
...@@ -1498,15 +1498,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1498,15 +1498,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1498}1498}
14991499
1500pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {1500pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {
1501 const target = self.base.comp.root_mod.resolved_target.result;
1502
1503 if (self.first_eflags == null) {1501 if (self.first_eflags == null) {
1504 self.first_eflags = e_flags;1502 self.first_eflags = e_flags;
1505 return; // there isn't anything to conflict with yet1503 return; // there isn't anything to conflict with yet
1506 }1504 }
1507 const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;1505 const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;
15081506
1509 switch (target.cpu.arch) {1507 switch (self.getTarget().cpu.arch) {
1510 .riscv64 => {1508 .riscv64 => {
1511 if (e_flags != self_eflags.*) {1509 if (e_flags != self_eflags.*) {
1512 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);1510 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
...@@ -1549,7 +1547,7 @@ fn accessLibPath(...@@ -1549,7 +1547,7 @@ fn accessLibPath(
1549 link_mode: ?std.builtin.LinkMode,1547 link_mode: ?std.builtin.LinkMode,
1550) !bool {1548) !bool {
1551 const sep = fs.path.sep_str;1549 const sep = fs.path.sep_str;
1552 const target = self.base.comp.root_mod.resolved_target.result;1550 const target = self.getTarget();
1553 test_path.clearRetainingCapacity();1551 test_path.clearRetainingCapacity();
1554 const prefix = if (link_mode != null) "lib" else "";1552 const prefix = if (link_mode != null) "lib" else "";
1555 const suffix = if (link_mode) |mode| switch (mode) {1553 const suffix = if (link_mode) |mode| switch (mode) {
...@@ -1779,7 +1777,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1779,7 +1777,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1779 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;1777 const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
1780 const have_dynamic_linker = comp.config.link_libc and1778 const have_dynamic_linker = comp.config.link_libc and
1781 link_mode == .dynamic and is_exe_or_dyn_lib;1779 link_mode == .dynamic and is_exe_or_dyn_lib;
1782 const target = comp.root_mod.resolved_target.result;1780 const target = self.getTarget();
1783 const compiler_rt_path: ?[]const u8 = blk: {1781 const compiler_rt_path: ?[]const u8 = blk: {
1784 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;1782 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
1785 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;1783 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
...@@ -2353,8 +2351,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -2353,8 +2351,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
23532351
2354pub fn writeShdrTable(self: *Elf) !void {2352pub fn writeShdrTable(self: *Elf) !void {
2355 const gpa = self.base.comp.gpa;2353 const gpa = self.base.comp.gpa;
2356 const target = self.base.comp.root_mod.resolved_target.result;2354 const target_endian = self.getTarget().cpu.arch.endian();
2357 const target_endian = target.cpu.arch.endian();
2358 const foreign_endian = target_endian != builtin.cpu.arch.endian();2355 const foreign_endian = target_endian != builtin.cpu.arch.endian();
2359 const shsize: u64 = switch (self.ptr_width) {2356 const shsize: u64 = switch (self.ptr_width) {
2360 .p32 => @sizeOf(elf.Elf32_Shdr),2357 .p32 => @sizeOf(elf.Elf32_Shdr),
...@@ -2410,8 +2407,7 @@ pub fn writeShdrTable(self: *Elf) !void {...@@ -2410,8 +2407,7 @@ pub fn writeShdrTable(self: *Elf) !void {
24102407
2411fn writePhdrTable(self: *Elf) !void {2408fn writePhdrTable(self: *Elf) !void {
2412 const gpa = self.base.comp.gpa;2409 const gpa = self.base.comp.gpa;
2413 const target = self.base.comp.root_mod.resolved_target.result;2410 const target_endian = self.getTarget().cpu.arch.endian();
2414 const target_endian = target.cpu.arch.endian();
2415 const foreign_endian = target_endian != builtin.cpu.arch.endian();2411 const foreign_endian = target_endian != builtin.cpu.arch.endian();
2416 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];2412 const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
24172413
...@@ -2464,7 +2460,7 @@ pub fn writeElfHeader(self: *Elf) !void {...@@ -2464,7 +2460,7 @@ pub fn writeElfHeader(self: *Elf) !void {
2464 };2460 };
2465 index += 1;2461 index += 1;
24662462
2467 const target = comp.root_mod.resolved_target.result;2463 const target = self.getTarget();
2468 const endian = target.cpu.arch.endian();2464 const endian = target.cpu.arch.endian();
2469 hdr_buf[index] = switch (endian) {2465 hdr_buf[index] = switch (endian) {
2470 .little => elf.ELFDATA2LSB,2466 .little => elf.ELFDATA2LSB,
...@@ -2772,21 +2768,25 @@ fn initOutputSections(self: *Elf) !void {...@@ -2772,21 +2768,25 @@ fn initOutputSections(self: *Elf) !void {
27722768
2773fn initSyntheticSections(self: *Elf) !void {2769fn initSyntheticSections(self: *Elf) !void {
2774 const comp = self.base.comp;2770 const comp = self.base.comp;
2775 const target = comp.root_mod.resolved_target.result;2771 const target = self.getTarget();
2776 const ptr_size = self.ptrWidthBytes();2772 const ptr_size = self.ptrWidthBytes();
27772773
2778 const needs_eh_frame = for (self.objects.items) |index| {2774 const needs_eh_frame = for (self.objects.items) |index| {
2779 if (self.file(index).?.object.cies.items.len > 0) break true;2775 if (self.file(index).?.object.cies.items.len > 0) break true;
2780 } else false;2776 } else false;
2781 if (needs_eh_frame) {2777 if (needs_eh_frame) {
2782 self.eh_frame_section_index = try self.addSection(.{2778 if (self.eh_frame_section_index == null) {
2783 .name = try self.insertShString(".eh_frame"),2779 self.eh_frame_section_index = try self.addSection(.{
2784 .type = elf.SHT_PROGBITS,2780 .name = try self.insertShString(".eh_frame"),
2785 .flags = elf.SHF_ALLOC,2781 .type = if (target.cpu.arch == .x86_64)
2786 .addralign = ptr_size,2782 elf.SHT_X86_64_UNWIND
2787 .offset = std.math.maxInt(u64),2783 else
2788 });2784 elf.SHT_PROGBITS,
27892785 .flags = elf.SHF_ALLOC,
2786 .addralign = ptr_size,
2787 .offset = std.math.maxInt(u64),
2788 });
2789 }
2790 if (comp.link_eh_frame_hdr) {2790 if (comp.link_eh_frame_hdr) {
2791 self.eh_frame_hdr_section_index = try self.addSection(.{2791 self.eh_frame_hdr_section_index = try self.addSection(.{
2792 .name = try self.insertShString(".eh_frame_hdr"),2792 .name = try self.insertShString(".eh_frame_hdr"),
...@@ -3446,7 +3446,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {...@@ -3446,7 +3446,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
3446}3446}
34473447
3448fn updateSectionSizes(self: *Elf) !void {3448fn updateSectionSizes(self: *Elf) !void {
3449 const target = self.base.comp.root_mod.resolved_target.result;
3450 const slice = self.sections.slice();3449 const slice = self.sections.slice();
3451 for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {3450 for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
3452 if (atom_list.items.len == 0) continue;3451 if (atom_list.items.len == 0) continue;
...@@ -3474,7 +3473,11 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3474,7 +3473,11 @@ fn updateSectionSizes(self: *Elf) !void {
34743473
3475 const shdrs = slice.items(.shdr);3474 const shdrs = slice.items(.shdr);
3476 if (self.eh_frame_section_index) |index| {3475 if (self.eh_frame_section_index) |index| {
3477 shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self);3476 shdrs[index].sh_size = existing_size: {
3477 const zo = self.zigObjectPtr() orelse break :existing_size 0;
3478 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
3479 break :existing_size sym.atom(self).?.size;
3480 } + try eh_frame.calcEhFrameSize(self);
3478 }3481 }
34793482
3480 if (self.eh_frame_hdr_section_index) |index| {3483 if (self.eh_frame_hdr_section_index) |index| {
...@@ -3517,7 +3520,7 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -3517,7 +3520,7 @@ fn updateSectionSizes(self: *Elf) !void {
3517 }3520 }
35183521
3519 if (self.interp_section_index) |index| {3522 if (self.interp_section_index) |index| {
3520 shdrs[index].sh_size = target.dynamic_linker.get().?.len + 1;3523 shdrs[index].sh_size = self.getTarget().dynamic_linker.get().?.len + 1;
3521 }3524 }
35223525
3523 if (self.hash_section_index) |index| {3526 if (self.hash_section_index) |index| {
...@@ -3759,10 +3762,10 @@ pub fn allocateAllocSections(self: *Elf) !void {...@@ -3759,10 +3762,10 @@ pub fn allocateAllocSections(self: *Elf) !void {
3759 }3762 }
37603763
3761 const first = slice.items(.shdr)[cover.items[0]];3764 const first = slice.items(.shdr)[cover.items[0]];
3762 var off = try self.findFreeSpace(filesz, @"align");3765 var new_offset = try self.findFreeSpace(filesz, @"align");
3763 const phndx = try self.addPhdr(.{3766 const phndx = try self.addPhdr(.{
3764 .type = elf.PT_LOAD,3767 .type = elf.PT_LOAD,
3765 .offset = off,3768 .offset = new_offset,
3766 .addr = first.sh_addr,3769 .addr = first.sh_addr,
3767 .memsz = memsz,3770 .memsz = memsz,
3768 .filesz = filesz,3771 .filesz = filesz,
...@@ -3777,9 +3780,28 @@ pub fn allocateAllocSections(self: *Elf) !void {...@@ -3777,9 +3780,28 @@ pub fn allocateAllocSections(self: *Elf) !void {
3777 shdr.sh_offset = 0;3780 shdr.sh_offset = 0;
3778 continue;3781 continue;
3779 }3782 }
3780 off = alignment.@"align"(shndx, shdr.sh_addralign, off);3783 new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
3781 shdr.sh_offset = off;3784
3782 off += shdr.sh_size;3785 if (shndx == self.eh_frame_section_index) eh_frame: {
3786 const zo = self.zigObjectPtr() orelse break :eh_frame;
3787 const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame);
3788 const existing_size = sym.atom(self).?.size;
3789 log.debug("moving {s} from 0x{x} to 0x{x}", .{
3790 self.getShString(shdr.sh_name),
3791 shdr.sh_offset,
3792 new_offset,
3793 });
3794 const amt = try self.base.file.?.copyRangeAll(
3795 shdr.sh_offset,
3796 self.base.file.?,
3797 new_offset,
3798 existing_size,
3799 );
3800 if (amt != existing_size) return error.InputOutput;
3801 }
3802
3803 shdr.sh_offset = new_offset;
3804 new_offset += shdr.sh_size;
3783 }3805 }
37843806
3785 addr = mem.alignForward(u64, addr, self.page_size);3807 addr = mem.alignForward(u64, addr, self.page_size);
...@@ -3910,9 +3932,9 @@ fn writeAtoms(self: *Elf) !void {...@@ -3910,9 +3932,9 @@ fn writeAtoms(self: *Elf) !void {
3910 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});3932 log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
39113933
3912 // TODO really, really handle debug section separately3934 // TODO really, really handle debug section separately
3913 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {3935 const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: {
3914 const zo = self.zigObjectPtr().?;3936 const zo = self.zigObjectPtr().?;
3915 break :blk for ([_]Symbol.Index{3937 for ([_]Symbol.Index{
3916 zo.debug_info_index.?,3938 zo.debug_info_index.?,
3917 zo.debug_abbrev_index.?,3939 zo.debug_abbrev_index.?,
3918 zo.debug_aranges_index.?,3940 zo.debug_aranges_index.?,
...@@ -3924,8 +3946,13 @@ fn writeAtoms(self: *Elf) !void {...@@ -3924,8 +3946,13 @@ fn writeAtoms(self: *Elf) !void {
3924 }) |sym_index| {3946 }) |sym_index| {
3925 const sym = zo.symbol(sym_index);3947 const sym = zo.symbol(sym_index);
3926 const atom_ptr = sym.atom(self).?;3948 const atom_ptr = sym.atom(self).?;
3927 if (atom_ptr.output_section_index == shndx) break atom_ptr.size;3949 if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size;
3928 } else 0;3950 }
3951 break :base_offset 0;
3952 } else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: {
3953 const zo = self.zigObjectPtr() orelse break :base_offset 0;
3954 const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0);
3955 break :base_offset sym.atom(self).?.size;
3929 } else 0;3956 } else 0;
3930 const sh_offset = shdr.sh_offset + base_offset;3957 const sh_offset = shdr.sh_offset + base_offset;
3931 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;3958 const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
...@@ -4082,12 +4109,11 @@ pub fn updateSymtabSize(self: *Elf) !void {...@@ -4082,12 +4109,11 @@ pub fn updateSymtabSize(self: *Elf) !void {
40824109
4083fn writeSyntheticSections(self: *Elf) !void {4110fn writeSyntheticSections(self: *Elf) !void {
4084 const gpa = self.base.comp.gpa;4111 const gpa = self.base.comp.gpa;
4085 const target = self.getTarget();
4086 const slice = self.sections.slice();4112 const slice = self.sections.slice();
40874113
4088 if (self.interp_section_index) |shndx| {4114 if (self.interp_section_index) |shndx| {
4089 var buffer: [256]u8 = undefined;4115 var buffer: [256]u8 = undefined;
4090 const interp = target.dynamic_linker.get().?;4116 const interp = self.getTarget().dynamic_linker.get().?;
4091 @memcpy(buffer[0..interp.len], interp);4117 @memcpy(buffer[0..interp.len], interp);
4092 buffer[interp.len] = 0;4118 buffer[interp.len] = 0;
4093 const contents = buffer[0 .. interp.len + 1];4119 const contents = buffer[0 .. interp.len + 1];
...@@ -4144,12 +4170,18 @@ fn writeSyntheticSections(self: *Elf) !void {...@@ -4144,12 +4170,18 @@ fn writeSyntheticSections(self: *Elf) !void {
4144 }4170 }
41454171
4146 if (self.eh_frame_section_index) |shndx| {4172 if (self.eh_frame_section_index) |shndx| {
4173 const existing_size = existing_size: {
4174 const zo = self.zigObjectPtr() orelse break :existing_size 0;
4175 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
4176 break :existing_size sym.atom(self).?.size;
4177 };
4147 const shdr = slice.items(.shdr)[shndx];4178 const shdr = slice.items(.shdr)[shndx];
4148 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;4179 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
4149 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);4180 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
4150 defer buffer.deinit();4181 defer buffer.deinit();
4151 try eh_frame.writeEhFrame(self, buffer.writer());4182 try eh_frame.writeEhFrame(self, buffer.writer());
4152 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);4183 assert(buffer.items.len == sh_size - existing_size);
4184 try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
4153 }4185 }
41544186
4155 if (self.eh_frame_hdr_section_index) |shndx| {4187 if (self.eh_frame_hdr_section_index) |shndx| {
...@@ -4222,7 +4254,6 @@ pub fn writeShStrtab(self: *Elf) !void {...@@ -4222,7 +4254,6 @@ pub fn writeShStrtab(self: *Elf) !void {
42224254
4223pub fn writeSymtab(self: *Elf) !void {4255pub fn writeSymtab(self: *Elf) !void {
4224 const gpa = self.base.comp.gpa;4256 const gpa = self.base.comp.gpa;
4225 const target = self.getTarget();
4226 const slice = self.sections.slice();4257 const slice = self.sections.slice();
4227 const symtab_shdr = slice.items(.shdr)[self.symtab_section_index.?];4258 const symtab_shdr = slice.items(.shdr)[self.symtab_section_index.?];
4228 const strtab_shdr = slice.items(.shdr)[self.strtab_section_index.?];4259 const strtab_shdr = slice.items(.shdr)[self.strtab_section_index.?];
...@@ -4292,7 +4323,7 @@ pub fn writeSymtab(self: *Elf) !void {...@@ -4292,7 +4323,7 @@ pub fn writeSymtab(self: *Elf) !void {
4292 self.plt_got.writeSymtab(self);4323 self.plt_got.writeSymtab(self);
4293 }4324 }
42944325
4295 const foreign_endian = target.cpu.arch.endian() != builtin.cpu.arch.endian();4326 const foreign_endian = self.getTarget().cpu.arch.endian() != builtin.cpu.arch.endian();
4296 switch (self.ptr_width) {4327 switch (self.ptr_width) {
4297 .p32 => {4328 .p32 => {
4298 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);4329 const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
...@@ -4630,10 +4661,8 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {...@@ -4630,10 +4661,8 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
4630 self.zig_data_rel_ro_section_index,4661 self.zig_data_rel_ro_section_index,
4631 self.zig_data_section_index,4662 self.zig_data_section_index,
4632 self.zig_bss_section_index,4663 self.zig_bss_section_index,
4633 }) |maybe_index| {4664 }) |index| {
4634 if (maybe_index) |index| {4665 if (index == shndx) return true;
4635 if (index == shndx) return true;
4636 }
4637 }4666 }
4638 return false;4667 return false;
4639}4668}
...@@ -4648,10 +4677,8 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {...@@ -4648,10 +4677,8 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {
4648 self.debug_line_str_section_index,4677 self.debug_line_str_section_index,
4649 self.debug_loclists_section_index,4678 self.debug_loclists_section_index,
4650 self.debug_rnglists_section_index,4679 self.debug_rnglists_section_index,
4651 }) |maybe_index| {4680 }) |index| {
4652 if (maybe_index) |index| {4681 if (index == shndx) return true;
4653 if (index == shndx) return true;
4654 }
4655 }4682 }
4656 return false;4683 return false;
4657}4684}
src/link/Elf/ZigObject.zig+42-9
...@@ -49,6 +49,7 @@ debug_line_section_dirty: bool = false,...@@ -49,6 +49,7 @@ debug_line_section_dirty: bool = false,
49debug_line_str_section_dirty: bool = false,49debug_line_str_section_dirty: bool = false,
50debug_loclists_section_dirty: bool = false,50debug_loclists_section_dirty: bool = false,
51debug_rnglists_section_dirty: bool = false,51debug_rnglists_section_dirty: bool = false,
52eh_frame_section_dirty: bool = false,
5253
53debug_info_index: ?Symbol.Index = null,54debug_info_index: ?Symbol.Index = null,
54debug_abbrev_index: ?Symbol.Index = null,55debug_abbrev_index: ?Symbol.Index = null,
...@@ -58,6 +59,7 @@ debug_line_index: ?Symbol.Index = null,...@@ -58,6 +59,7 @@ debug_line_index: ?Symbol.Index = null,
58debug_line_str_index: ?Symbol.Index = null,59debug_line_str_index: ?Symbol.Index = null,
59debug_loclists_index: ?Symbol.Index = null,60debug_loclists_index: ?Symbol.Index = null,
60debug_rnglists_index: ?Symbol.Index = null,61debug_rnglists_index: ?Symbol.Index = null,
62eh_frame_index: ?Symbol.Index = null,
6163
62pub const global_symbol_bit: u32 = 0x80000000;64pub const global_symbol_bit: u32 = 0x80000000;
63pub const symbol_mask: u32 = 0x7fffffff;65pub const symbol_mask: u32 = 0x7fffffff;
...@@ -72,8 +74,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -72,8 +74,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
72 const comp = elf_file.base.comp;74 const comp = elf_file.base.comp;
73 const gpa = comp.gpa;75 const gpa = comp.gpa;
74 const ptr_size = elf_file.ptrWidthBytes();76 const ptr_size = elf_file.ptrWidthBytes();
75 const target = elf_file.getTarget();
76 const ptr_bit_width = target.ptrBitWidth();
7777
78 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section78 try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
79 try self.relocs.append(gpa, .{}); // null relocs section79 try self.relocs.append(gpa, .{}); // null relocs section
...@@ -113,7 +113,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -113,7 +113,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
113 .type = elf.PT_LOAD,113 .type = elf.PT_LOAD,
114 .offset = off,114 .offset = off,
115 .filesz = filesz,115 .filesz = filesz,
116 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,116 .addr = if (ptr_size >= 4) 0x4000000 else 0x4000,
117 .memsz = filesz,117 .memsz = filesz,
118 .@"align" = elf_file.page_size,118 .@"align" = elf_file.page_size,
119 .flags = elf.PF_X | elf.PF_R | elf.PF_W,119 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
...@@ -128,7 +128,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -128,7 +128,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
128 .type = elf.PT_LOAD,128 .type = elf.PT_LOAD,
129 .offset = off,129 .offset = off,
130 .filesz = filesz,130 .filesz = filesz,
131 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,131 .addr = if (ptr_size >= 4) 0xc000000 else 0xa000,
132 .memsz = filesz,132 .memsz = filesz,
133 .@"align" = alignment,133 .@"align" = alignment,
134 .flags = elf.PF_R | elf.PF_W,134 .flags = elf.PF_R | elf.PF_W,
...@@ -143,7 +143,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -143,7 +143,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
143 .type = elf.PT_LOAD,143 .type = elf.PT_LOAD,
144 .offset = off,144 .offset = off,
145 .filesz = filesz,145 .filesz = filesz,
146 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,146 .addr = if (ptr_size >= 4) 0x10000000 else 0xc000,
147 .memsz = filesz,147 .memsz = filesz,
148 .@"align" = alignment,148 .@"align" = alignment,
149 .flags = elf.PF_R | elf.PF_W,149 .flags = elf.PF_R | elf.PF_W,
...@@ -154,7 +154,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -154,7 +154,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
154 const alignment = elf_file.page_size;154 const alignment = elf_file.page_size;
155 elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{155 elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{
156 .type = elf.PT_LOAD,156 .type = elf.PT_LOAD,
157 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,157 .addr = if (ptr_size >= 4) 0x14000000 else 0xf000,
158 .memsz = 1024,158 .memsz = 1024,
159 .@"align" = alignment,159 .@"align" = alignment,
160 .flags = elf.PF_R | elf.PF_W,160 .flags = elf.PF_R | elf.PF_W,
...@@ -354,6 +354,20 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {...@@ -354,6 +354,20 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
354 self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);354 self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);
355 }355 }
356356
357 if (elf_file.eh_frame_section_index == null) {
358 elf_file.eh_frame_section_index = try elf_file.addSection(.{
359 .name = try elf_file.insertShString(".eh_frame"),
360 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
361 elf.SHT_X86_64_UNWIND
362 else
363 elf.SHT_PROGBITS,
364 .flags = elf.SHF_ALLOC,
365 .addralign = ptr_size,
366 });
367 self.eh_frame_section_dirty = true;
368 self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?);
369 }
370
357 try dwarf.initMetadata();371 try dwarf.initMetadata();
358 self.dwarf = dwarf;372 self.dwarf = dwarf;
359 },373 },
...@@ -460,6 +474,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -460,6 +474,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
460 self.debug_line_str_index.?,474 self.debug_line_str_index.?,
461 self.debug_loclists_index.?,475 self.debug_loclists_index.?,
462 self.debug_rnglists_index.?,476 self.debug_rnglists_index.?,
477 self.eh_frame_index.?,
463 }, [_]*Dwarf.Section{478 }, [_]*Dwarf.Section{
464 &dwarf.debug_info.section,479 &dwarf.debug_info.section,
465 &dwarf.debug_abbrev.section,480 &dwarf.debug_abbrev.section,
...@@ -469,7 +484,18 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -469,7 +484,18 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
469 &dwarf.debug_line_str.section,484 &dwarf.debug_line_str.section,
470 &dwarf.debug_loclists.section,485 &dwarf.debug_loclists.section,
471 &dwarf.debug_rnglists.section,486 &dwarf.debug_rnglists.section,
472 }) |sym_index, sect| {487 &dwarf.debug_frame.section,
488 }, [_]Dwarf.Section.Index{
489 .debug_info,
490 .debug_abbrev,
491 .debug_str,
492 .debug_aranges,
493 .debug_line,
494 .debug_line_str,
495 .debug_loclists,
496 .debug_rnglists,
497 .debug_frame,
498 }) |sym_index, sect, sect_index| {
473 const sym = self.symbol(sym_index);499 const sym = self.symbol(sym_index);
474 const atom_ptr = self.atom(sym.ref.index).?;500 const atom_ptr = self.atom(sym.ref.index).?;
475 if (!atom_ptr.alive) continue;501 if (!atom_ptr.alive) continue;
...@@ -509,6 +535,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -509,6 +535,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
509 for (unit.cross_section_relocs.items) |reloc| {535 for (unit.cross_section_relocs.items) |reloc| {
510 const target_sym_index = switch (reloc.target_sec) {536 const target_sym_index = switch (reloc.target_sec) {
511 .debug_abbrev => self.debug_abbrev_index.?,537 .debug_abbrev => self.debug_abbrev_index.?,
538 .debug_aranges => self.debug_aranges_index.?,
539 .debug_frame => self.eh_frame_index.?,
512 .debug_info => self.debug_info_index.?,540 .debug_info => self.debug_info_index.?,
513 .debug_line => self.debug_line_index.?,541 .debug_line => self.debug_line_index.?,
514 .debug_line_str => self.debug_line_str_index.?,542 .debug_line_str => self.debug_line_str_index.?,
...@@ -547,7 +575,10 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -547,7 +575,10 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
547 entry.external_relocs.items.len);575 entry.external_relocs.items.len);
548 for (entry.cross_entry_relocs.items) |reloc| {576 for (entry.cross_entry_relocs.items) |reloc| {
549 const r_offset = entry_off + reloc.source_off;577 const r_offset = entry_off + reloc.source_off;
550 const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off);578 const r_addend: i64 = @intCast(unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
579 unit.header_len + unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
580 else
581 0));
551 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);582 const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
552 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{583 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
553 self.symbol(sym_index).name(elf_file),584 self.symbol(sym_index).name(elf_file),
...@@ -584,6 +615,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -584,6 +615,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
584 for (entry.cross_section_relocs.items) |reloc| {615 for (entry.cross_section_relocs.items) |reloc| {
585 const target_sym_index = switch (reloc.target_sec) {616 const target_sym_index = switch (reloc.target_sec) {
586 .debug_abbrev => self.debug_abbrev_index.?,617 .debug_abbrev => self.debug_abbrev_index.?,
618 .debug_aranges => self.debug_aranges_index.?,
619 .debug_frame => self.eh_frame_index.?,
587 .debug_info => self.debug_info_index.?,620 .debug_info => self.debug_info_index.?,
588 .debug_line => self.debug_line_index.?,621 .debug_line => self.debug_line_index.?,
589 .debug_line_str => self.debug_line_str_index.?,622 .debug_line_str => self.debug_line_str_index.?,
...@@ -617,7 +650,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi...@@ -617,7 +650,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
617 const target_sym = self.symbol(reloc.target_sym);650 const target_sym = self.symbol(reloc.target_sym);
618 const r_offset = entry_off + reloc.source_off;651 const r_offset = entry_off + reloc.source_off;
619 const r_addend: i64 = @intCast(reloc.target_off);652 const r_addend: i64 = @intCast(reloc.target_off);
620 const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);653 const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
621 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{654 log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
622 target_sym.name(elf_file),655 target_sym.name(elf_file),
623 r_offset,656 r_offset,
src/link/Elf/relocatable.zig+27-15
...@@ -289,8 +289,6 @@ fn claimUnresolved(elf_file: *Elf) void {...@@ -289,8 +289,6 @@ fn claimUnresolved(elf_file: *Elf) void {
289}289}
290290
291fn initSections(elf_file: *Elf) !void {291fn initSections(elf_file: *Elf) !void {
292 const ptr_size = elf_file.ptrWidthBytes();
293
294 for (elf_file.objects.items) |index| {292 for (elf_file.objects.items) |index| {
295 const object = elf_file.file(index).?.object;293 const object = elf_file.file(index).?.object;
296 try object.initOutputSections(elf_file);294 try object.initOutputSections(elf_file);
...@@ -306,13 +304,18 @@ fn initSections(elf_file: *Elf) !void {...@@ -306,13 +304,18 @@ fn initSections(elf_file: *Elf) !void {
306 if (elf_file.file(index).?.object.cies.items.len > 0) break true;304 if (elf_file.file(index).?.object.cies.items.len > 0) break true;
307 } else false;305 } else false;
308 if (needs_eh_frame) {306 if (needs_eh_frame) {
309 elf_file.eh_frame_section_index = try elf_file.addSection(.{307 if (elf_file.eh_frame_section_index == null) {
310 .name = try elf_file.insertShString(".eh_frame"),308 elf_file.eh_frame_section_index = try elf_file.addSection(.{
311 .type = elf.SHT_PROGBITS,309 .name = try elf_file.insertShString(".eh_frame"),
312 .flags = elf.SHF_ALLOC,310 .type = if (elf_file.getTarget().cpu.arch == .x86_64)
313 .addralign = ptr_size,311 elf.SHT_X86_64_UNWIND
314 .offset = std.math.maxInt(u64),312 else
315 });313 elf.SHT_PROGBITS,
314 .flags = elf.SHF_ALLOC,
315 .addralign = elf_file.ptrWidthBytes(),
316 .offset = std.math.maxInt(u64),
317 });
318 }
316 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(319 elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
317 try elf_file.insertShString(".rela.eh_frame"),320 try elf_file.insertShString(".rela.eh_frame"),
318 elf_file.eh_frame_section_index.?,321 elf_file.eh_frame_section_index.?,
...@@ -373,7 +376,11 @@ fn updateSectionSizes(elf_file: *Elf) !void {...@@ -373,7 +376,11 @@ fn updateSectionSizes(elf_file: *Elf) !void {
373 }376 }
374377
375 if (elf_file.eh_frame_section_index) |index| {378 if (elf_file.eh_frame_section_index) |index| {
376 slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file);379 slice.items(.shdr)[index].sh_size = existing_size: {
380 const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
381 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
382 break :existing_size sym.atom(elf_file).?.size;
383 } + try eh_frame.calcEhFrameSize(elf_file);
377 }384 }
378 if (elf_file.eh_frame_rela_section_index) |index| {385 if (elf_file.eh_frame_rela_section_index) |index| {
379 const shdr = &slice.items(.shdr)[index];386 const shdr = &slice.items(.shdr)[index];
...@@ -526,17 +533,22 @@ fn writeSyntheticSections(elf_file: *Elf) !void {...@@ -526,17 +533,22 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
526 }533 }
527534
528 if (elf_file.eh_frame_section_index) |shndx| {535 if (elf_file.eh_frame_section_index) |shndx| {
536 const existing_size = existing_size: {
537 const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
538 const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
539 break :existing_size sym.atom(elf_file).?.size;
540 };
529 const shdr = slice.items(.shdr)[shndx];541 const shdr = slice.items(.shdr)[shndx];
530 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;542 const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
531 var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);543 var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
532 defer buffer.deinit();544 defer buffer.deinit();
533 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());545 try eh_frame.writeEhFrameObject(elf_file, buffer.writer());
534 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{546 log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
535 shdr.sh_offset,547 shdr.sh_offset + existing_size,
536 shdr.sh_offset + shdr.sh_size,548 shdr.sh_offset + sh_size,
537 });549 });
538 assert(buffer.items.len == sh_size);550 assert(buffer.items.len == sh_size - existing_size);
539 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);551 try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
540 }552 }
541 if (elf_file.eh_frame_rela_section_index) |shndx| {553 if (elf_file.eh_frame_rela_section_index) |shndx| {
542 const shdr = slice.items(.shdr)[shndx];554 const shdr = slice.items(.shdr)[shndx];
src/link/Elf/relocation.zig+17-10
...@@ -108,20 +108,27 @@ pub const dwarf = struct {...@@ -108,20 +108,27 @@ pub const dwarf = struct {
108108
109 pub fn externalRelocType(109 pub fn externalRelocType(
110 target: Symbol,110 target: Symbol,
111 source_section: Dwarf.Section.Index,
111 address_size: Dwarf.AddressSize,112 address_size: Dwarf.AddressSize,
112 cpu_arch: std.Target.Cpu.Arch,113 cpu_arch: std.Target.Cpu.Arch,
113 ) u32 {114 ) u32 {
114 return switch (cpu_arch) {115 return switch (cpu_arch) {
115 .x86_64 => @intFromEnum(switch (address_size) {116 .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) {
116 .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32",117 else => switch (address_size) {
117 .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64",118 .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
118 else => unreachable,119 .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
119 }),120 else => unreachable,
120 .riscv64 => @intFromEnum(switch (address_size) {121 },
121 .@"32" => elf.R_RISCV.@"32",122 .debug_frame => .PC32,
122 .@"64" => elf.R_RISCV.@"64",123 })),
123 else => unreachable,124 .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
124 }),125 else => switch (address_size) {
126 .@"32" => .@"32",
127 .@"64" => .@"64",
128 else => unreachable,
129 },
130 .debug_frame => unreachable,
131 })),
125 else => @panic("TODO unhandled cpu arch"),132 else => @panic("TODO unhandled cpu arch"),
126 };133 };
127 }134 }
src/link/MachO.zig+6-6
...@@ -3411,9 +3411,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3411,9 +3411,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
34113411
3412 if (!sect.isZerofill()) {3412 if (!sect.isZerofill()) {
3413 const allocated_size = self.allocatedSize(sect.offset);3413 const allocated_size = self.allocatedSize(sect.offset);
3414 if (sect.offset + allocated_size == std.math.maxInt(u64)) {3414 if (needed_size > allocated_size) {
3415 try self.base.file.?.setEndPos(sect.offset + needed_size);
3416 } else if (needed_size > allocated_size) {
3417 const existing_size = sect.size;3415 const existing_size = sect.size;
3418 sect.size = 0;3416 sect.size = 0;
34193417
...@@ -3431,6 +3429,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo...@@ -3431,6 +3429,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
3431 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);3429 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
34323430
3433 sect.offset = @intCast(new_offset);3431 sect.offset = @intCast(new_offset);
3432 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3433 try self.base.file.?.setEndPos(sect.offset + needed_size);
3434 }3434 }
3435 seg.filesize = needed_size;3435 seg.filesize = needed_size;
3436 }3436 }
...@@ -3456,9 +3456,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void...@@ -3456,9 +3456,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34563456
3457 if (!sect.isZerofill()) {3457 if (!sect.isZerofill()) {
3458 const allocated_size = self.allocatedSize(sect.offset);3458 const allocated_size = self.allocatedSize(sect.offset);
3459 if (sect.offset + allocated_size == std.math.maxInt(u64)) {3459 if (needed_size > allocated_size) {
3460 try self.base.file.?.setEndPos(sect.offset + needed_size);
3461 } else if (needed_size > allocated_size) {
3462 const existing_size = sect.size;3460 const existing_size = sect.size;
3463 sect.size = 0;3461 sect.size = 0;
34643462
...@@ -3480,6 +3478,8 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void...@@ -3480,6 +3478,8 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
34803478
3481 sect.offset = @intCast(new_offset);3479 sect.offset = @intCast(new_offset);
3482 sect.addr = new_addr;3480 sect.addr = new_addr;
3481 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
3482 try self.base.file.?.setEndPos(sect.offset + needed_size);
3483 }3483 }
3484 }3484 }
3485 sect.size = needed_size;3485 sect.size = needed_size;
src/link/MachO/DebugSymbols.zig+3-3
...@@ -105,9 +105,7 @@ pub fn growSection(...@@ -105,9 +105,7 @@ pub fn growSection(
105 const sect = self.getSectionPtr(sect_index);105 const sect = self.getSectionPtr(sect_index);
106106
107 const allocated_size = self.allocatedSize(sect.offset);107 const allocated_size = self.allocatedSize(sect.offset);
108 if (sect.offset + allocated_size == std.math.maxInt(u64)) {108 if (needed_size > allocated_size) {
109 try self.file.setEndPos(sect.offset + needed_size);
110 } else if (needed_size > allocated_size) {
111 const existing_size = sect.size;109 const existing_size = sect.size;
112 sect.size = 0; // free the space110 sect.size = 0; // free the space
113 const new_offset = try self.findFreeSpace(needed_size, 1);111 const new_offset = try self.findFreeSpace(needed_size, 1);
...@@ -130,6 +128,8 @@ pub fn growSection(...@@ -130,6 +128,8 @@ pub fn growSection(
130 }128 }
131129
132 sect.offset = @intCast(new_offset);130 sect.offset = @intCast(new_offset);
131 } else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
132 try self.file.setEndPos(sect.offset + needed_size);
133 }133 }
134134
135 sect.size = needed_size;135 sect.size = needed_size;
test/src/Debugger.zig+76
...@@ -305,6 +305,82 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {...@@ -305,6 +305,82 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
305 \\1 breakpoints deleted; 0 breakpoint locations disabled.305 \\1 breakpoints deleted; 0 breakpoint locations disabled.
306 },306 },
307 );307 );
308 db.addLldbTest(
309 "strings",
310 target,
311 &.{
312 .{
313 .path = "strings.zig",
314 .source =
315 \\const Strings = struct {
316 \\ c_ptr: [*c]const u8 = "c_ptr\x07\x08\t",
317 \\ many_ptr: [*:0]const u8 = "many_ptr\n\x0b\x0c",
318 \\ ptr_array: *const [12:0]u8 = "ptr_array\x00\r\x1b",
319 \\ slice: [:0]const u8 = "slice\"\'\\\x00",
320 \\};
321 \\fn testStrings(strings: Strings) void {
322 \\ _ = strings;
323 \\}
324 \\pub fn main() void {
325 \\ testStrings(.{});
326 \\}
327 \\
328 ,
329 },
330 },
331 \\breakpoint set --file strings.zig --source-pattern-regexp '_ = strings;'
332 \\process launch
333 \\frame variable --show-types strings.slice
334 \\frame variable --show-types --format character strings.slice
335 \\frame variable --show-types --format c-string strings
336 \\breakpoint delete --force 1
337 ,
338 &.{
339 \\(lldb) frame variable --show-types strings.slice
340 \\([:0]const u8) strings.slice = len=9 {
341 \\ (u8) [0] = 115
342 \\ (u8) [1] = 108
343 \\ (u8) [2] = 105
344 \\ (u8) [3] = 99
345 \\ (u8) [4] = 101
346 \\ (u8) [5] = 34
347 \\ (u8) [6] = 39
348 \\ (u8) [7] = 92
349 \\ (u8) [8] = 0
350 \\}
351 \\(lldb) frame variable --show-types --format character strings.slice
352 \\([:0]const u8) strings.slice = len=9 {
353 \\ (u8) [0] = 's'
354 \\ (u8) [1] = 'l'
355 \\ (u8) [2] = 'i'
356 \\ (u8) [3] = 'c'
357 \\ (u8) [4] = 'e'
358 \\ (u8) [5] = '\"'
359 \\ (u8) [6] = '\''
360 \\ (u8) [7] = '\\'
361 \\ (u8) [8] = '\x00'
362 \\}
363 \\(lldb) frame variable --show-types --format c-string strings
364 \\(root.strings.Strings) strings = {
365 \\ ([*c]const u8) c_ptr = "c_ptr\x07\x08\t"
366 \\ ([*:0]const u8) many_ptr = "many_ptr\n\x0b\x0c"
367 \\ (*const [12:0]u8) ptr_array = "ptr_array\x00\r\x1b"
368 \\ ([:0]const u8) slice = "slice\"\'\\\x00" len=9 {
369 \\ (u8) [0] = "s"
370 \\ (u8) [1] = "l"
371 \\ (u8) [2] = "i"
372 \\ (u8) [3] = "c"
373 \\ (u8) [4] = "e"
374 \\ (u8) [5] = "\""
375 \\ (u8) [6] = "\'"
376 \\ (u8) [7] = "\\"
377 \\ (u8) [8] = "\x00"
378 \\ }
379 \\}
380 \\(lldb) breakpoint delete --force 1
381 \\1 breakpoints deleted; 0 breakpoint locations disabled.
382 },
383 );
308 db.addLldbTest(384 db.addLldbTest(
309 "enums",385 "enums",
310 target,386 target,