Merge pull request #21210 from jacobly0/eh-frame

Dwarf: implement .eh_frame
This commit is contained in:
Jacob Young authored and GitHub committed 2024-08-27 15:06:07 -04:00
commit 1a178d4995
27 files changed
+1420 -347

No files matched your search

+1 -1
View File
@@ -64,7 +64,7 @@ stage3-debug/bin/zig build \
stage3-debug/bin/zig build test docs \ stage3-debug/bin/zig build test docs \
--maxrss 21000000000 \ --maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Debug-62538077d/bin/lldb \ -Dlldb=$HOME/deps/lldb-zig/Debug-70b8227f1/bin/lldb \
-fqemu \ -fqemu \
-fwasmtime \ -fwasmtime \
-Dstatic-llvm \ -Dstatic-llvm \
+1 -1
View File
@@ -64,7 +64,7 @@ stage3-release/bin/zig build \
stage3-release/bin/zig build test docs \ stage3-release/bin/zig build test docs \
--maxrss 21000000000 \ --maxrss 21000000000 \
-Dlldb=$HOME/deps/lldb-zig/Release-62538077d/bin/lldb \ -Dlldb=$HOME/deps/lldb-zig/Release-70b8227f1/bin/lldb \
-fqemu \ -fqemu \
-fwasmtime \ -fwasmtime \
-Dstatic-llvm \ -Dstatic-llvm \
+1 -1
View File
@@ -125,7 +125,7 @@ pub const readILEB128 = readIleb128;
pub fn writeIleb128(writer: anytype, arg: anytype) !void { pub fn writeIleb128(writer: anytype, arg: anytype) !void {
const Arg = @TypeOf(arg); const Arg = @TypeOf(arg);
const Int = switch (Arg) { const Int = switch (Arg) {
comptime_int => std.math.IntFittingRange(-arg - 1, arg), comptime_int => std.math.IntFittingRange(-@abs(arg), @abs(arg)),
else => Arg, else => Arg,
}; };
const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int; const Signed = if (@typeInfo(Int).Int.bits < 8) i8 else Int;
+3 -2
View File
@@ -114,14 +114,15 @@ pub fn clone() callconv(.Naked) usize {
\\ movq %%rcx,(%%rsi) \\ movq %%rcx,(%%rsi)
\\ syscall \\ syscall
\\ testq %%rax,%%rax \\ testq %%rax,%%rax
\\ jnz 1f \\ jz 1f
\\ retq
\\1: .cfi_undefined %%rip
\\ xorl %%ebp,%%ebp \\ xorl %%ebp,%%ebp
\\ popq %%rdi \\ popq %%rdi
\\ callq *%%r9 \\ callq *%%r9
\\ movl %%eax,%%edi \\ movl %%eax,%%edi
\\ movl $60,%%eax // SYS_exit \\ movl $60,%%eax // SYS_exit
\\ syscall \\ syscall
\\1: ret
\\ \\
); );
} }
+1
View File
@@ -249,6 +249,7 @@ fn _start() callconv(.Naked) noreturn {
// linker explicitly. // linker explicitly.
asm volatile (switch (native_arch) { asm volatile (switch (native_arch) {
.x86_64 => .x86_64 =>
\\ .cfi_undefined %%rip
\\ xorl %%ebp, %%ebp \\ xorl %%ebp, %%ebp
\\ movq %%rsp, %%rdi \\ movq %%rsp, %%rdi
\\ andq $-16, %%rsp \\ andq $-16, %%rsp
+4 -1
View File
@@ -13,6 +13,7 @@ const Value = @import("Value.zig");
const Type = @import("Type.zig"); const Type = @import("Type.zig");
const InternPool = @import("InternPool.zig"); const InternPool = @import("InternPool.zig");
const Zcu = @import("Zcu.zig"); const Zcu = @import("Zcu.zig");
const types_resolved = @import("Air/types_resolved.zig");
instructions: std.MultiArrayList(Inst).Slice, instructions: std.MultiArrayList(Inst).Slice,
/// The meaning of this data is determined by `Inst.Tag` value. /// 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 {
}; };
} }
pub const typesFullyResolved = @import("Air/types_resolved.zig").typesFullyResolved; pub const typesFullyResolved = types_resolved.typesFullyResolved;
pub const typeFullyResolved = types_resolved.checkType;
pub const valFullyResolved = types_resolved.checkVal;
+8 -4
View File
@@ -432,8 +432,10 @@ fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
return checkVal(Value.fromInterned(ip_index), zcu); return checkVal(Value.fromInterned(ip_index), zcu);
} }
fn checkVal(val: Value, zcu: *Zcu) bool { pub fn checkVal(val: Value, zcu: *Zcu) bool {
if (!checkType(val.typeOf(zcu), zcu)) return false; const ty = val.typeOf(zcu);
if (!checkType(ty, zcu)) return false;
if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false;
// Check for lazy values // Check for lazy values
switch (zcu.intern_pool.indexToKey(val.toIntern())) { switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.int => |int| switch (int.storage) { .int => |int| switch (int.storage) {
@@ -446,9 +448,11 @@ fn checkVal(val: Value, zcu: *Zcu) bool {
} }
} }
fn checkType(ty: Type, zcu: *Zcu) bool { pub fn checkType(ty: Type, zcu: *Zcu) bool {
const ip = &zcu.intern_pool; const ip = &zcu.intern_pool;
return switch (ty.zigTypeTag(zcu)) { return switch (ty.zigTypeTagOrPoison(zcu) catch |err| switch (err) {
error.GenericPoison => return true,
}) {
.Type, .Type,
.Void, .Void,
.Bool, .Bool,
+23 -41
View File
@@ -192,11 +192,12 @@ pub fn toBigIntAdvanced(
zcu: *Zcu, zcu: *Zcu,
tid: strat.Tid(), tid: strat.Tid(),
) Zcu.CompileError!BigIntConst { ) Zcu.CompileError!BigIntConst {
const ip = &zcu.intern_pool;
return switch (val.toIntern()) { return switch (val.toIntern()) {
.bool_false => BigIntMutable.init(&space.limbs, 0).toConst(), .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
.bool_true => BigIntMutable.init(&space.limbs, 1).toConst(), .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),
.null_value => BigIntMutable.init(&space.limbs, 0).toConst(), .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) { else => switch (ip.indexToKey(val.toIntern())) {
.int => |int| switch (int.storage) { .int => |int| switch (int.storage) {
.u64, .i64, .big_int => int.storage.toBigInt(space), .u64, .i64, .big_int => int.storage.toBigInt(space),
.lazy_align, .lazy_size => |ty| { .lazy_align, .lazy_size => |ty| {
@@ -214,6 +215,7 @@ pub fn toBigIntAdvanced(
&space.limbs, &space.limbs,
(try val.getUnsignedIntInner(strat, zcu, tid)).?, (try val.getUnsignedIntInner(strat, zcu, tid)).?,
).toConst(), ).toConst(),
.err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
else => unreachable, else => unreachable,
}, },
}; };
@@ -326,15 +328,11 @@ pub fn toBool(val: Value) bool {
}; };
} }
fn ptrHasIntAddr(val: Value, zcu: *Zcu) bool {
return zcu.intern_pool.getBackingAddrTag(val.toIntern()).? == .int;
}
/// Write a Value's contents to `buffer`. /// Write a Value's contents to `buffer`.
/// ///
/// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past
/// the end of the value in memory. /// the end of the value in memory.
pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) error{ pub fn writeToMemory(val: Value, pt: Zcu.PerThread, buffer: []u8) error{
ReinterpretDeclRef, ReinterpretDeclRef,
IllDefinedMemoryLayout, IllDefinedMemoryLayout,
Unimplemented, Unimplemented,
@@ -343,19 +341,25 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const zcu = pt.zcu; const zcu = pt.zcu;
const target = zcu.getTarget(); const target = zcu.getTarget();
const endian = target.cpu.arch.endian(); const endian = target.cpu.arch.endian();
const ip = &zcu.intern_pool;
const ty = val.typeOf(zcu);
if (val.isUndef(zcu)) { if (val.isUndef(zcu)) {
const size: usize = @intCast(ty.abiSize(zcu)); const size: usize = @intCast(ty.abiSize(zcu));
@memset(buffer[0..size], 0xaa); @memset(buffer[0..size], 0xaa);
return; return;
} }
const ip = &zcu.intern_pool;
switch (ty.zigTypeTag(zcu)) { switch (ty.zigTypeTag(zcu)) {
.Void => {}, .Void => {},
.Bool => { .Bool => {
buffer[0] = @intFromBool(val.toBool()); buffer[0] = @intFromBool(val.toBool());
}, },
.Int, .Enum => { .Int, .Enum, .ErrorSet, .Pointer => |tag| {
const int_info = ty.intInfo(zcu); const int_ty = if (tag == .Pointer) int_ty: {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
break :int_ty Type.usize;
} else ty;
const int_info = int_ty.intInfo(zcu);
const bits = int_info.bits; const bits = int_info.bits;
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8); const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
@@ -379,7 +383,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
var buf_off: usize = 0; var buf_off: usize = 0;
while (elem_i < len) : (elem_i += 1) { while (elem_i < len) : (elem_i += 1) {
const elem_val = try val.elemValue(pt, elem_i); const elem_val = try val.elemValue(pt, elem_i);
try elem_val.writeToMemory(elem_ty, pt, buffer[buf_off..]); try elem_val.writeToMemory(pt, buffer[buf_off..]);
buf_off += elem_size; buf_off += elem_size;
} }
}, },
@@ -403,8 +407,7 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
.elems => |elems| elems[field_index], .elems => |elems| elems[field_index],
.repeated_elem => |elem| elem, .repeated_elem => |elem| elem,
}); });
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]); try writeToMemory(field_val, pt, buffer[off..]);
try writeToMemory(field_val, field_ty, pt, buffer[off..]);
}, },
.@"packed" => { .@"packed" => {
const byte_count = (@as(usize, @intCast(ty.bitSize(zcu))) + 7) / 8; 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
}, },
} }
}, },
.ErrorSet => {
const bits = zcu.errorSetBits();
const byte_count: u16 = @intCast((@as(u17, bits) + 7) / 8);
const name = switch (ip.indexToKey(val.toIntern())) {
.err => |err| err.name,
.error_union => |error_union| error_union.val.err_name,
else => unreachable,
};
var bigint_buffer: BigIntSpace = undefined;
const bigint = BigIntMutable.init(
&bigint_buffer.limbs,
ip.getErrorValueIfExists(name).?,
).toConst();
bigint.writeTwosComplement(buffer[0..byte_count], endian);
},
.Union => switch (ty.containerLayout(zcu)) { .Union => switch (ty.containerLayout(zcu)) {
.auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already .auto => return error.IllDefinedMemoryLayout, // Sema is supposed to have emitted a compile error already
.@"extern" => { .@"extern" => {
@@ -437,11 +424,11 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
const field_val = try val.fieldValue(pt, field_index); const field_val = try val.fieldValue(pt, field_index);
const byte_count: usize = @intCast(field_type.abiSize(zcu)); const byte_count: usize = @intCast(field_type.abiSize(zcu));
return writeToMemory(field_val, field_type, pt, buffer[0..byte_count]); return writeToMemory(field_val, pt, buffer[0..byte_count]);
} else { } else {
const backing_ty = try ty.unionBackingType(pt); const backing_ty = try ty.unionBackingType(pt);
const byte_count: usize = @intCast(backing_ty.abiSize(zcu)); const byte_count: usize = @intCast(backing_ty.abiSize(zcu));
return writeToMemory(val.unionValue(zcu), backing_ty, pt, buffer[0..byte_count]); return writeToMemory(val.unionValue(zcu), pt, buffer[0..byte_count]);
} }
}, },
.@"packed" => { .@"packed" => {
@@ -450,19 +437,13 @@ pub fn writeToMemory(val: Value, ty: Type, pt: Zcu.PerThread, buffer: []u8) erro
return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0); return writeToPackedMemory(val, ty, pt, buffer[0..byte_count], 0);
}, },
}, },
.Pointer => {
if (ty.isSlice(zcu)) return error.IllDefinedMemoryLayout;
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef;
return val.writeToMemory(Type.usize, pt, buffer);
},
.Optional => { .Optional => {
if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout; if (!ty.isPtrLikeOptional(zcu)) return error.IllDefinedMemoryLayout;
const child = ty.optionalChild(zcu);
const opt_val = val.optionalValue(zcu); const opt_val = val.optionalValue(zcu);
if (opt_val) |some| { if (opt_val) |some| {
return some.writeToMemory(child, pt, buffer); return some.writeToMemory(pt, buffer);
} else { } else {
return writeToMemory(try pt.intValue(Type.usize, 0), Type.usize, pt, buffer); return writeToMemory(try pt.intValue(Type.usize, 0), pt, buffer);
} }
}, },
else => return error.Unimplemented, else => return error.Unimplemented,
@@ -582,7 +563,7 @@ pub fn writeToPackedMemory(
}, },
.Pointer => { .Pointer => {
assert(!ty.isSlice(zcu)); // No well defined layout. assert(!ty.isSlice(zcu)); // No well defined layout.
if (!val.ptrHasIntAddr(zcu)) return error.ReinterpretDeclRef; if (ip.getBackingAddrTag(val.toIntern()).? != .int) return error.ReinterpretDeclRef;
return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset); return val.writeToPackedMemory(Type.usize, pt, buffer, bit_offset);
}, },
.Optional => { .Optional => {
@@ -3658,14 +3639,15 @@ pub fn mulAddScalar(
/// If the value is represented in-memory as a series of bytes that all /// If the value is represented in-memory as a series of bytes that all
/// have the same value, return that byte value, otherwise null. /// have the same value, return that byte value, otherwise null.
pub fn hasRepeatedByteRepr(val: Value, ty: Type, pt: Zcu.PerThread) !?u8 { pub fn hasRepeatedByteRepr(val: Value, pt: Zcu.PerThread) !?u8 {
const zcu = pt.zcu; const zcu = pt.zcu;
const ty = val.typeOf(zcu);
const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null; const abi_size = std.math.cast(usize, ty.abiSize(zcu)) orelse return null;
assert(abi_size >= 1); assert(abi_size >= 1);
const byte_buffer = try zcu.gpa.alloc(u8, abi_size); const byte_buffer = try zcu.gpa.alloc(u8, abi_size);
defer zcu.gpa.free(byte_buffer); defer zcu.gpa.free(byte_buffer);
writeToMemory(val, ty, pt, byte_buffer) catch |err| switch (err) { writeToMemory(val, pt, byte_buffer) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => return null, error.ReinterpretDeclRef => return null,
// TODO: The writeToMemory function was originally created for the purpose // TODO: The writeToMemory function was originally created for the purpose
+12 -3
View File
@@ -2560,12 +2560,17 @@ pub fn populateTestFunctions(
pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {
const zcu = pt.zcu; const zcu = pt.zcu;
const comp = zcu.comp; const comp = zcu.comp;
const ip = &zcu.intern_pool;
const nav = zcu.intern_pool.getNav(nav_index); const nav = zcu.intern_pool.getNav(nav_index);
const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(&zcu.intern_pool), 0); const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
defer codegen_prog_node.end(); defer codegen_prog_node.end();
if (comp.bin_file) |lf| { if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
// The value of this nav failed to resolve. This is a transitive failure.
// TODO: do we need to mark this failure anywhere? I don't think so, since compilation
// will fail due to the type error anyway.
} else if (comp.bin_file) |lf| {
lf.updateNav(pt, nav_index) catch |err| switch (err) { lf.updateNav(pt, nav_index) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
error.AnalysisFail => { error.AnalysisFail => {
@@ -2605,7 +2610,11 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void
const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0); const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
defer codegen_prog_node.end(); defer codegen_prog_node.end();
if (comp.bin_file) |lf| { if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) {
// This type failed to resolve. This is a transitive failure.
// TODO: do we need to mark this failure anywhere? I don't think so, since compilation
// will fail due to the type error anyway.
} else if (comp.bin_file) |lf| {
lf.updateContainerType(pt, ty) catch |err| switch (err) { lf.updateContainerType(pt, ty) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory, error.OutOfMemory => return error.OutOfMemory,
else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}), else => |e| log.err("codegen type failed: {s}", .{@errorName(e)}),
+1 -1
View File
@@ -3357,7 +3357,7 @@ fn lowerConstant(func: *CodeGen, val: Value, ty: Type) InnerError!WValue {
.vector_type => { .vector_type => {
assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct); assert(determineSimdStoreStrategy(ty, zcu, func.target.*) == .direct);
var buf: [16]u8 = undefined; var buf: [16]u8 = undefined;
val.writeToMemory(ty, pt, &buf) catch unreachable; val.writeToMemory(pt, &buf) catch unreachable;
return func.storeSimdImmd(buf); return func.storeSimdImmd(buf);
}, },
.struct_type => { .struct_type => {
+112 -13
View File
@@ -1491,6 +1491,46 @@ fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
}); });
} }
fn asmPseudoRegister(self: *Self, ops: Mir.Inst.Ops, reg: Register) !void {
assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
std.mem.endsWith(u8, @tagName(ops), "_r"));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
.data = .{ .r = .{ .r1 = reg } },
});
}
fn asmPseudoImmediate(self: *Self, ops: Mir.Inst.Ops, imm: Immediate) !void {
assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
std.mem.endsWith(u8, @tagName(ops), "_i_s"));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
.data = .{ .i = .{ .i = @bitCast(imm.signed) } },
});
}
fn asmPseudoRegisterRegister(self: *Self, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void {
assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
std.mem.endsWith(u8, @tagName(ops), "_rr"));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
.data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
});
}
fn asmPseudoRegisterImmediate(self: *Self, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void {
assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
std.mem.endsWith(u8, @tagName(ops), "_ri_s"));
_ = try self.addInst(.{
.tag = .pseudo,
.ops = ops,
.data = .{ .ri = .{ .r1 = reg, .i = @bitCast(imm.signed) } },
});
}
fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void { fn asmRegister(self: *Self, tag: Mir.Inst.FixedTag, reg: Register) !void {
_ = try self.addInst(.{ _ = try self.addInst(.{
.tag = tag[1], .tag = tag[1],
@@ -1877,7 +1917,10 @@ fn gen(self: *Self) InnerError!void {
const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*); const cc = abi.resolveCallingConvention(fn_info.cc, self.target.*);
if (cc != .Naked) { if (cc != .Naked) {
try self.asmRegister(.{ ._, .push }, .rbp); try self.asmRegister(.{ ._, .push }, .rbp);
try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, Immediate.s(8));
try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, Immediate.s(0));
try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp); try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
try self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, .rbp);
const backpatch_push_callee_preserved_regs = try self.asmPlaceholder(); const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
const backpatch_frame_align = try self.asmPlaceholder(); const backpatch_frame_align = try self.asmPlaceholder();
const backpatch_frame_align_extra = try self.asmPlaceholder(); const backpatch_frame_align_extra = try self.asmPlaceholder();
@@ -1962,6 +2005,7 @@ fn gen(self: *Self) InnerError!void {
const backpatch_stack_dealloc = try self.asmPlaceholder(); const backpatch_stack_dealloc = try self.asmPlaceholder();
const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder(); const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
try self.asmRegister(.{ ._, .pop }, .rbp); try self.asmRegister(.{ ._, .pop }, .rbp);
try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, Immediate.s(8));
try self.asmOpOnly(.{ ._, .ret }); try self.asmOpOnly(.{ ._, .ret });
const frame_layout = try self.computeFrameLayout(cc); const frame_layout = try self.computeFrameLayout(cc);
@@ -14038,7 +14082,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
var mnem_it = mem.tokenizeAny(u8, line, " \t"); var mnem_it = mem.tokenizeAny(u8, line, " \t");
var prefix: Instruction.Prefix = .none; var prefix: Instruction.Prefix = .none;
const mnem_str = while (mnem_it.next()) |mnem_str| { const mnem_str = while (mnem_it.next()) |mnem_str| {
if (mem.startsWith(u8, mnem_str, "#")) continue :next_line; if (mnem_str[0] == '#') continue :next_line;
if (mem.startsWith(u8, mnem_str, "//")) continue :next_line; if (mem.startsWith(u8, mnem_str, "//")) continue :next_line;
if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| { if (std.meta.stringToEnum(Instruction.Prefix, mnem_str)) |pre| {
if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str}); if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
@@ -14063,8 +14107,14 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} }
label_gop.value_ptr.target = @intCast(self.mir_instructions.len); label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
} else continue; } else continue;
if (mnem_str[0] == '.') {
if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str });
prefix = .directive;
}
var mnem_size: ?Memory.Size = if (mem.endsWith(u8, mnem_str, "b")) var mnem_size: ?Memory.Size = if (prefix == .directive)
null
else if (mem.endsWith(u8, mnem_str, "b"))
.byte .byte
else if (mem.endsWith(u8, mnem_str, "w")) else if (mem.endsWith(u8, mnem_str, "w"))
.word .word
@@ -14095,7 +14145,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
mnem_size = fixed_mnem_size; mnem_size = fixed_mnem_size;
} }
const mnem_name = @tagName(mnem_tag); const mnem_name = @tagName(mnem_tag);
const mnem_fixed_tag: Mir.Inst.FixedTag = for (std.enums.values(Mir.Inst.Fixes)) |fixes| { const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
.{ ._, .pseudo }
else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
const fixes_name = @tagName(fixes); const fixes_name = @tagName(fixes);
const space_i = mem.indexOfScalar(u8, fixes_name, ' '); const space_i = mem.indexOfScalar(u8, fixes_name, ' ');
const fixes_prefix = if (space_i) |i| const fixes_prefix = if (space_i) |i|
@@ -14116,7 +14168,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else { } else {
assert(prefix != .none); // no combination of fixes produced a known mnemonic assert(prefix != .none); // no combination of fixes produced a known mnemonic
return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{ return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
@tagName(prefix), mnem_str, @tagName(prefix), mnem_name,
}); });
}; };
@@ -14324,7 +14376,62 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
} else return self.fail("invalid operand: '{s}'", .{op_str}); } else return self.fail("invalid operand: '{s}'", .{op_str});
} else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str}); } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
(switch (ops[0]) { (if (prefix == .directive) switch (mnem_tag) {
.@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, ops[0].reg, ops[1].imm)
else
error.InvalidInstruction,
.@".cfi_def_cfa_register" => if (ops[0] == .reg and ops[1] == .none)
self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, ops[0].reg)
else
error.InvalidInstruction,
.@".cfi_def_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
self.asmPseudoImmediate(.pseudo_cfi_def_cfa_offset_i_s, ops[0].imm)
else
error.InvalidInstruction,
.@".cfi_adjust_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, ops[0].imm)
else
error.InvalidInstruction,
.@".cfi_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
self.asmPseudoRegisterImmediate(.pseudo_cfi_offset_ri_s, ops[0].reg, ops[1].imm)
else
error.InvalidInstruction,
.@".cfi_val_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
self.asmPseudoRegisterImmediate(.pseudo_cfi_val_offset_ri_s, ops[0].reg, ops[1].imm)
else
error.InvalidInstruction,
.@".cfi_rel_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, ops[0].reg, ops[1].imm)
else
error.InvalidInstruction,
.@".cfi_register" => if (ops[0] == .reg and ops[1] == .reg and ops[2] == .none)
self.asmPseudoRegisterRegister(.pseudo_cfi_register_rr, ops[0].reg, ops[1].reg)
else
error.InvalidInstruction,
.@".cfi_restore" => if (ops[0] == .reg and ops[1] == .none)
self.asmPseudoRegister(.pseudo_cfi_restore_r, ops[0].reg)
else
error.InvalidInstruction,
.@".cfi_undefined" => if (ops[0] == .reg and ops[1] == .none)
self.asmPseudoRegister(.pseudo_cfi_undefined_r, ops[0].reg)
else
error.InvalidInstruction,
.@".cfi_same_value" => if (ops[0] == .reg and ops[1] == .none)
self.asmPseudoRegister(.pseudo_cfi_same_value_r, ops[0].reg)
else
error.InvalidInstruction,
.@".cfi_remember_state" => if (ops[0] == .none)
self.asmPseudo(.pseudo_cfi_remember_state_none)
else
error.InvalidInstruction,
.@".cfi_restore_state" => if (ops[0] == .none)
self.asmPseudo(.pseudo_cfi_restore_state_none)
else
error.InvalidInstruction,
.@".cfi_escape" => error.InvalidInstruction,
else => unreachable,
} else switch (ops[0]) {
.none => self.asmOpOnly(mnem_fixed_tag), .none => self.asmOpOnly(mnem_fixed_tag),
.reg => |reg0| switch (ops[1]) { .reg => |reg0| switch (ops[1]) {
.none => self.asmRegister(mnem_fixed_tag, reg0), .none => self.asmRegister(mnem_fixed_tag, reg0),
@@ -19210,14 +19317,6 @@ fn fail(self: *Self, comptime format: []const u8, args: anytype) InnerError {
return error.CodegenFail; return error.CodegenFail;
} }
fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError {
@branchHint(.cold);
assert(self.err_msg == null);
const gpa = self.gpa;
self.err_msg = try ErrorMsg.create(gpa, self.src_loc, format, args);
return error.CodegenFail;
}
fn parseRegName(name: []const u8) ?Register { fn parseRegName(name: []const u8) ?Register {
if (@hasDecl(Register, "parseRegName")) { if (@hasDecl(Register, "parseRegName")) {
return Register.parseRegName(name); return Register.parseRegName(name);
+53
View File
@@ -30,6 +30,59 @@ pub fn emitMir(emit: *Emit) Error!void {
var lowered_relocs = lowered.relocs; var lowered_relocs = lowered.relocs;
for (lowered.insts, 0..) |lowered_inst, lowered_index| { for (lowered.insts, 0..) |lowered_inst, lowered_index| {
const start_offset: u32 = @intCast(emit.code.items.len); const start_offset: u32 = @intCast(emit.code.items.len);
if (lowered_inst.prefix == .directive) {
switch (emit.debug_output) {
.dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) {
.@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{
.reg = lowered_inst.ops[0].reg.dwarfNum(),
.off = lowered_inst.ops[1].imm.signed,
} }),
.@".cfi_def_cfa_register" => try dwarf.genDebugFrame(start_offset, .{
.def_cfa_register = lowered_inst.ops[0].reg.dwarfNum(),
}),
.@".cfi_def_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
.def_cfa_offset = lowered_inst.ops[0].imm.signed,
}),
.@".cfi_adjust_cfa_offset" => try dwarf.genDebugFrame(start_offset, .{
.adjust_cfa_offset = lowered_inst.ops[0].imm.signed,
}),
.@".cfi_offset" => try dwarf.genDebugFrame(start_offset, .{ .offset = .{
.reg = lowered_inst.ops[0].reg.dwarfNum(),
.off = lowered_inst.ops[1].imm.signed,
} }),
.@".cfi_val_offset" => try dwarf.genDebugFrame(start_offset, .{ .val_offset = .{
.reg = lowered_inst.ops[0].reg.dwarfNum(),
.off = lowered_inst.ops[1].imm.signed,
} }),
.@".cfi_rel_offset" => try dwarf.genDebugFrame(start_offset, .{ .rel_offset = .{
.reg = lowered_inst.ops[0].reg.dwarfNum(),
.off = lowered_inst.ops[1].imm.signed,
} }),
.@".cfi_register" => try dwarf.genDebugFrame(start_offset, .{ .register = .{
lowered_inst.ops[0].reg.dwarfNum(),
lowered_inst.ops[1].reg.dwarfNum(),
} }),
.@".cfi_restore" => try dwarf.genDebugFrame(start_offset, .{
.restore = lowered_inst.ops[0].reg.dwarfNum(),
}),
.@".cfi_undefined" => try dwarf.genDebugFrame(start_offset, .{
.undefined = lowered_inst.ops[0].reg.dwarfNum(),
}),
.@".cfi_same_value" => try dwarf.genDebugFrame(start_offset, .{
.same_value = lowered_inst.ops[0].reg.dwarfNum(),
}),
.@".cfi_remember_state" => try dwarf.genDebugFrame(start_offset, .remember_state),
.@".cfi_restore_state" => try dwarf.genDebugFrame(start_offset, .restore_state),
.@".cfi_escape" => try dwarf.genDebugFrame(start_offset, .{
.escape = lowered_inst.ops[0].bytes,
}),
else => unreachable,
},
.plan9 => {},
.none => {},
}
continue;
}
try lowered_inst.encode(emit.code.writer(), .{}); try lowered_inst.encode(emit.code.writer(), .{});
const end_offset: u32 = @intCast(emit.code.items.len); const end_offset: u32 = @intCast(emit.code.items.len);
while (lowered_relocs.len > 0 and while (lowered_relocs.len > 0 and
+32 -7
View File
@@ -220,6 +220,21 @@ pub fn format(
} }
pub const Mnemonic = enum { pub const Mnemonic = enum {
// Directives
@".cfi_def_cfa",
@".cfi_def_cfa_register",
@".cfi_def_cfa_offset",
@".cfi_adjust_cfa_offset",
@".cfi_offset",
@".cfi_val_offset",
@".cfi_rel_offset",
@".cfi_register",
@".cfi_restore",
@".cfi_undefined",
@".cfi_same_value",
@".cfi_remember_state",
@".cfi_restore_state",
@".cfi_escape",
// zig fmt: off // zig fmt: off
// General-purpose // General-purpose
adc, add, @"and", adc, add, @"and",
@@ -442,6 +457,7 @@ pub const Op = enum {
imm8s, imm16s, imm32s, imm8s, imm16s, imm32s,
al, ax, eax, rax, al, ax, eax, rax,
cl, cl,
rip, eip, ip,
r8, r16, r32, r64, r8, r16, r32, r64,
rm8, rm16, rm32, rm64, rm8, rm16, rm32, rm64,
r32_m8, r32_m16, r64_m16, r32_m8, r32_m16, r64_m16,
@@ -487,7 +503,12 @@ pub const Op = enum {
256 => .ymm, 256 => .ymm,
else => unreachable, else => unreachable,
}, },
.ip => unreachable, .ip => switch (reg) {
.rip => .rip,
.eip => .eip,
.ip => .ip,
else => unreachable,
},
}, },
.mem => |mem| switch (mem) { .mem => |mem| switch (mem) {
@@ -531,13 +552,15 @@ pub const Op = enum {
else else
.imm64, .imm64,
}, },
.bytes => unreachable,
}; };
} }
pub fn immBitSize(op: Op) u64 { pub fn immBitSize(op: Op) u64 {
return switch (op) { return switch (op) {
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable, .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
.al, .cl, .r8, .rm8, .r32_m8 => unreachable, .al, .cl, .rip, .eip, .ip, .r8, .rm8, .r32_m8 => unreachable,
.ax, .r16, .rm16 => unreachable, .ax, .r16, .rm16 => unreachable,
.eax, .r32, .rm32, .r32_m16 => unreachable, .eax, .r32, .rm32, .r32_m16 => unreachable,
.rax, .r64, .rm64, .r64_m16 => unreachable, .rax, .r64, .rm64, .r64_m16 => unreachable,
@@ -560,9 +583,9 @@ pub const Op = enum {
.rel8, .rel16, .rel32 => unreachable, .rel8, .rel16, .rel32 => unreachable,
.m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable, .m8, .m16, .m32, .m64, .m80, .m128, .m256 => unreachable,
.al, .cl, .r8, .rm8 => 8, .al, .cl, .r8, .rm8 => 8,
.ax, .r16, .rm16 => 16, .ax, .ip, .r16, .rm16 => 16,
.eax, .r32, .rm32, .r32_m8, .r32_m16 => 32, .eax, .eip, .r32, .rm32, .r32_m8, .r32_m16 => 32,
.rax, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64, .rax, .rip, .r64, .rm64, .r64_m16, .mm, .mm_m64 => 64,
.st => 80, .st => 80,
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128, .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => 128,
.ymm, .ymm_m256 => 256, .ymm, .ymm_m256 => 256,
@@ -574,7 +597,7 @@ pub const Op = enum {
.none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable, .none, .o16, .o32, .o64, .moffs, .m, .sreg => unreachable,
.unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable, .unity, .imm8, .imm8s, .imm16, .imm16s, .imm32, .imm32s, .imm64 => unreachable,
.rel8, .rel16, .rel32 => unreachable, .rel8, .rel16, .rel32 => unreachable,
.al, .cl, .r8, .ax, .r16, .eax, .r32, .rax, .r64 => unreachable, .al, .cl, .r8, .ax, .ip, .r16, .eax, .eip, .r32, .rax, .rip, .r64 => unreachable,
.st, .mm, .xmm0, .xmm, .ymm => unreachable, .st, .mm, .xmm0, .xmm, .ymm => unreachable,
.m8, .rm8, .r32_m8, .xmm_m8 => 8, .m8, .rm8, .r32_m8, .xmm_m8 => 8,
.m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16, .m16, .rm16, .r32_m16, .r64_m16, .xmm_m16 => 16,
@@ -602,8 +625,9 @@ pub const Op = enum {
pub fn isRegister(op: Op) bool { pub fn isRegister(op: Op) bool {
// zig fmt: off // zig fmt: off
return switch (op) { return switch (op) {
.cl,
.al, .ax, .eax, .rax, .al, .ax, .eax, .rax,
.cl,
.ip, .eip, .rip,
.r8, .r16, .r32, .r64, .r8, .r16, .r32, .r64,
.rm8, .rm16, .rm32, .rm64, .rm8, .rm16, .rm32, .rm64,
.r32_m8, .r32_m16, .r64_m16, .r32_m8, .r32_m16, .r64_m16,
@@ -664,6 +688,7 @@ pub const Op = enum {
.mm, .mm_m64 => .mmx, .mm, .mm_m64 => .mmx,
.xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse, .xmm0, .xmm, .xmm_m8, .xmm_m16, .xmm_m32, .xmm_m64, .xmm_m128 => .sse,
.ymm, .ymm_m256 => .sse, .ymm, .ymm_m256 => .sse,
.rip, .eip, .ip => .ip,
}; };
} }
+87 -11
View File
@@ -12,7 +12,7 @@ src_loc: Zcu.LazySrcLoc,
result_insts_len: u8 = undefined, result_insts_len: u8 = undefined,
result_relocs_len: u8 = undefined, result_relocs_len: u8 = undefined,
result_insts: [ result_insts: [
std.mem.max(usize, &.{ @max(
1, // non-pseudo instructions 1, // non-pseudo instructions
3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
2, // cmovcc: cmovcc \ cmovcc 2, // cmovcc: cmovcc \ cmovcc
@@ -22,18 +22,18 @@ result_insts: [
pseudo_probe_adjust_unrolled_max_insts, pseudo_probe_adjust_unrolled_max_insts,
pseudo_probe_adjust_setup_insts, pseudo_probe_adjust_setup_insts,
pseudo_probe_adjust_loop_insts, pseudo_probe_adjust_loop_insts,
abi.Win64.callee_preserved_regs.len, // push_regs/pop_regs abi.Win64.callee_preserved_regs.len * 2, // push_regs/pop_regs
abi.SysV.callee_preserved_regs.len, // push_regs/pop_regs abi.SysV.callee_preserved_regs.len * 2, // push_regs/pop_regs
}) )
]Instruction = undefined, ]Instruction = undefined,
result_relocs: [ result_relocs: [
std.mem.max(usize, &.{ @max(
1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea 1, // jmp/jcc/call/mov/lea: jmp/jcc/call/mov/lea
2, // jcc: jcc \ jcc 2, // jcc: jcc \ jcc
2, // test \ jcc \ probe \ sub \ jmp 2, // test \ jcc \ probe \ sub \ jmp
1, // probe \ sub \ jcc 1, // probe \ sub \ jcc
3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode 3, // (ELF only) TLS local dynamic (LD) sequence in PIC mode
}) )
]Reloc = undefined, ]Reloc = undefined,
pub const pseudo_probe_align_insts = 5; // test \ jcc \ probe \ sub \ jmp pub 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 {
.pseudo_push_reg_list => try lower.pushPopRegList(.push, inst), .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
.pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst), .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
.pseudo_cfi_def_cfa_ri_s => try lower.emit(.directive, .@".cfi_def_cfa", &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
}),
.pseudo_cfi_def_cfa_register_r => try lower.emit(.directive, .@".cfi_def_cfa_register", &.{
.{ .reg = inst.data.r.r1 },
}),
.pseudo_cfi_def_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_def_cfa_offset", &.{
.{ .imm = lower.imm(.i_s, inst.data.i.i) },
}),
.pseudo_cfi_adjust_cfa_offset_i_s => try lower.emit(.directive, .@".cfi_adjust_cfa_offset", &.{
.{ .imm = lower.imm(.i_s, inst.data.i.i) },
}),
.pseudo_cfi_offset_ri_s => try lower.emit(.directive, .@".cfi_offset", &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
}),
.pseudo_cfi_val_offset_ri_s => try lower.emit(.directive, .@".cfi_val_offset", &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
}),
.pseudo_cfi_rel_offset_ri_s => try lower.emit(.directive, .@".cfi_rel_offset", &.{
.{ .reg = inst.data.ri.r1 },
.{ .imm = lower.imm(.ri_s, inst.data.ri.i) },
}),
.pseudo_cfi_register_rr => try lower.emit(.directive, .@".cfi_register", &.{
.{ .reg = inst.data.rr.r1 },
.{ .reg = inst.data.rr.r2 },
}),
.pseudo_cfi_restore_r => try lower.emit(.directive, .@".cfi_restore", &.{
.{ .reg = inst.data.r.r1 },
}),
.pseudo_cfi_undefined_r => try lower.emit(.directive, .@".cfi_undefined", &.{
.{ .reg = inst.data.r.r1 },
}),
.pseudo_cfi_same_value_r => try lower.emit(.directive, .@".cfi_same_value", &.{
.{ .reg = inst.data.r.r1 },
}),
.pseudo_cfi_remember_state_none => try lower.emit(.directive, .@".cfi_remember_state", &.{}),
.pseudo_cfi_restore_state_none => try lower.emit(.directive, .@".cfi_restore_state", &.{}),
.pseudo_cfi_escape_bytes => try lower.emit(.directive, .@".cfi_escape", &.{
.{ .bytes = inst.data.bytes.get(lower.mir) },
}),
.pseudo_dbg_prologue_end_none, .pseudo_dbg_prologue_end_none,
.pseudo_dbg_line_line_column, .pseudo_dbg_line_line_column,
.pseudo_dbg_epilogue_begin_none, .pseudo_dbg_epilogue_begin_none,
@@ -280,6 +324,7 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
.pseudo_dbg_local_af, .pseudo_dbg_local_af,
.pseudo_dbg_local_am, .pseudo_dbg_local_am,
.pseudo_dbg_var_args_none, .pseudo_dbg_var_args_none,
.pseudo_dead_none, .pseudo_dead_none,
=> {}, => {},
else => unreachable, else => unreachable,
@@ -665,12 +710,43 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void { fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc); const callee_preserved_regs = abi.getCalleePreservedRegs(lower.cc);
var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) { var off: i32 = switch (mnemonic) {
.push => .reverse, .push => 0,
.pop => .forward, .pop => undefined,
else => unreachable, else => unreachable,
} }); };
while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }}); {
var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
.push => .reverse,
.pop => .forward,
else => unreachable,
} });
while (it.next()) |i| {
try lower.emit(.none, mnemonic, &.{.{
.reg = callee_preserved_regs[i],
}});
switch (mnemonic) {
.push => off -= 8,
.pop => {},
else => unreachable,
}
}
}
switch (mnemonic) {
.push => {
var it = inst.data.reg_list.iterator(.{});
while (it.next()) |i| {
try lower.emit(.directive, .@".cfi_rel_offset", &.{
.{ .reg = callee_preserved_regs[i] },
.{ .imm = Immediate.s(off) },
});
off += 8;
}
assert(off == 0);
},
.pop => {},
else => unreachable,
}
} }
const page_size: i32 = 1 << 12; const page_size: i32 = 1 << 12;
+48 -1
View File
@@ -879,6 +879,7 @@ pub const Inst = struct {
/// Probe adjust loop /// Probe adjust loop
/// Uses `rr` payload. /// Uses `rr` payload.
pseudo_probe_adjust_loop_rr, pseudo_probe_adjust_loop_rr,
/// Push registers /// Push registers
/// Uses `reg_list` payload. /// Uses `reg_list` payload.
pseudo_push_reg_list, pseudo_push_reg_list,
@@ -886,6 +887,47 @@ pub const Inst = struct {
/// Uses `reg_list` payload. /// Uses `reg_list` payload.
pseudo_pop_reg_list, pseudo_pop_reg_list,
/// Define cfa rule as offset from register.
/// Uses `ri` payload.
pseudo_cfi_def_cfa_ri_s,
/// Modify cfa rule register.
/// Uses `r` payload.
pseudo_cfi_def_cfa_register_r,
/// Modify cfa rule offset.
/// Uses `i` payload.
pseudo_cfi_def_cfa_offset_i_s,
/// Offset cfa rule offset.
/// Uses `i` payload.
pseudo_cfi_adjust_cfa_offset_i_s,
/// Define register rule as stored at offset from cfa.
/// Uses `ri` payload.
pseudo_cfi_offset_ri_s,
/// Define register rule as offset from cfa.
/// Uses `ri` payload.
pseudo_cfi_val_offset_ri_s,
/// Define register rule as stored at offset from cfa rule register.
/// Uses `ri` payload.
pseudo_cfi_rel_offset_ri_s,
/// Define register rule as register.
/// Uses `rr` payload.
pseudo_cfi_register_rr,
/// Define register rule from initial.
/// Uses `r` payload.
pseudo_cfi_restore_r,
/// Define register rule as undefined.
/// Uses `r` payload.
pseudo_cfi_undefined_r,
/// Define register rule as itself.
/// Uses `r` payload.
pseudo_cfi_same_value_r,
/// Push cfi state.
pseudo_cfi_remember_state_none,
/// Pop cfi state.
pseudo_cfi_restore_state_none,
/// Raw cfi bytes.
/// Uses `bytes` payload.
pseudo_cfi_escape_bytes,
/// End of prologue /// End of prologue
pseudo_dbg_prologue_end_none, pseudo_dbg_prologue_end_none,
/// Update debug line /// Update debug line
@@ -1028,8 +1070,13 @@ pub const Inst = struct {
fixes: Fixes = ._, fixes: Fixes = ._,
payload: u32, payload: u32,
}, },
ix: struct { bytes: struct {
payload: u32, payload: u32,
len: u32,
pub fn get(bytes: @This(), mir: Mir) []const u8 {
return std.mem.sliceAsBytes(mir.extra[bytes.payload..])[0..bytes.len];
}
}, },
a: struct { a: struct {
air_inst: Air.Inst.Index, air_inst: Air.Inst.Index,
+1 -1
View File
@@ -371,7 +371,7 @@ pub const Register = enum(u7) {
.x87 => 33 + @as(u6, reg.enc()), .x87 => 33 + @as(u6, reg.enc()),
.mmx => 41 + @as(u6, reg.enc()), .mmx => 41 + @as(u6, reg.enc()),
.segment => 50 + @as(u6, reg.enc()), .segment => 50 + @as(u6, reg.enc()),
.ip => unreachable, .ip => 16,
}; };
} }
}; };
+43 -12
View File
@@ -25,6 +25,7 @@ pub const Instruction = struct {
repz, repz,
repne, repne,
repnz, repnz,
directive,
}; };
pub const Immediate = union(enum) { pub const Immediate = union(enum) {
@@ -180,6 +181,7 @@ pub const Instruction = struct {
reg: Register, reg: Register,
mem: Memory, mem: Memory,
imm: Immediate, imm: Immediate,
bytes: []const u8,
/// Returns the bitsize of the operand. /// Returns the bitsize of the operand.
pub fn bitSize(op: Operand) u64 { pub fn bitSize(op: Operand) u64 {
@@ -188,6 +190,7 @@ pub const Instruction = struct {
.reg => |reg| reg.bitSize(), .reg => |reg| reg.bitSize(),
.mem => |mem| mem.bitSize(), .mem => |mem| mem.bitSize(),
.imm => unreachable, .imm => unreachable,
.bytes => unreachable,
}; };
} }
@@ -199,6 +202,7 @@ pub const Instruction = struct {
.reg => |reg| reg.class() == .segment, .reg => |reg| reg.class() == .segment,
.mem => |mem| mem.isSegmentRegister(), .mem => |mem| mem.isSegmentRegister(),
.imm => unreachable, .imm => unreachable,
.bytes => unreachable,
}; };
} }
@@ -207,6 +211,7 @@ pub const Instruction = struct {
.none, .imm => false, .none, .imm => false,
.reg => |reg| reg.isExtended(), .reg => |reg| reg.isExtended(),
.mem => |mem| mem.base().isExtended(), .mem => |mem| mem.base().isExtended(),
.bytes => unreachable,
}; };
} }
@@ -214,6 +219,7 @@ pub const Instruction = struct {
return switch (op) { return switch (op) {
.none, .reg, .imm => false, .none, .reg, .imm => false,
.mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false, .mem => |mem| if (mem.scaleIndex()) |si| si.index.isExtended() else false,
.bytes => unreachable,
}; };
} }
@@ -299,6 +305,7 @@ pub const Instruction = struct {
if (imms < 0) try writer.writeByte('-'); if (imms < 0) try writer.writeByte('-');
try writer.print("0x{x}", .{@abs(imms)}); try writer.print("0x{x}", .{@abs(imms)});
} else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}), } else try writer.print("0x{x}", .{imm.asUnsigned(enc_op.immBitSize())}),
.bytes => unreachable,
} }
} }
@@ -308,20 +315,39 @@ pub const Instruction = struct {
}; };
pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction { pub fn new(prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) !Instruction {
const encoding = (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse { const encoding: Encoding = switch (prefix) {
log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{ else => (try Encoding.findByMnemonic(prefix, mnemonic, ops)) orelse {
@tagName(prefix), log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
@tagName(mnemonic), @tagName(prefix),
@tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none), @tagName(mnemonic),
@tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none), @tagName(if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none),
@tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none), @tagName(if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none),
@tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none), @tagName(if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none),
}); @tagName(if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none),
return error.InvalidInstruction; });
return error.InvalidInstruction;
},
.directive => .{
.mnemonic = mnemonic,
.data = .{
.op_en = .zo,
.ops = .{
if (ops.len > 0) Encoding.Op.fromOperand(ops[0]) else .none,
if (ops.len > 1) Encoding.Op.fromOperand(ops[1]) else .none,
if (ops.len > 2) Encoding.Op.fromOperand(ops[2]) else .none,
if (ops.len > 3) Encoding.Op.fromOperand(ops[3]) else .none,
},
.opc_len = 0,
.opc = undefined,
.modrm_ext = 0,
.mode = .none,
.feature = .none,
},
},
}; };
log.debug("selected encoding: {}", .{encoding}); log.debug("selected encoding: {}", .{encoding});
var inst = Instruction{ var inst: Instruction = .{
.prefix = prefix, .prefix = prefix,
.encoding = encoding, .encoding = encoding,
.ops = [1]Operand{.none} ** 4, .ops = [1]Operand{.none} ** 4,
@@ -338,7 +364,10 @@ pub const Instruction = struct {
) @TypeOf(writer).Error!void { ) @TypeOf(writer).Error!void {
_ = unused_format_string; _ = unused_format_string;
_ = options; _ = options;
if (inst.prefix != .none) try writer.print("{s} ", .{@tagName(inst.prefix)}); switch (inst.prefix) {
.none, .directive => {},
else => try writer.print("{s} ", .{@tagName(inst.prefix)}),
}
try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)}); try writer.print("{s}", .{@tagName(inst.encoding.mnemonic)});
for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| { for (inst.ops, inst.encoding.data.ops, 0..) |op, enc, i| {
if (op == .none) break; if (op == .none) break;
@@ -349,6 +378,7 @@ pub const Instruction = struct {
} }
pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void { pub fn encode(inst: Instruction, writer: anytype, comptime opts: Options) !void {
assert(inst.prefix != .directive);
const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer }; const encoder = Encoder(@TypeOf(writer), opts){ .writer = writer };
const enc = inst.encoding; const enc = inst.encoding;
const data = enc.data; const data = enc.data;
@@ -435,6 +465,7 @@ pub const Instruction = struct {
.lock => legacy.prefix_f0 = true, .lock => legacy.prefix_f0 = true,
.repne, .repnz => legacy.prefix_f2 = true, .repne, .repnz => legacy.prefix_f2 = true,
.rep, .repe, .repz => legacy.prefix_f3 = true, .rep, .repe, .repz => legacy.prefix_f3 = true,
.directive => unreachable,
} }
switch (data.mode) { switch (data.mode) {
+1 -1
View File
@@ -9412,7 +9412,7 @@ pub const FuncGen = struct {
// repeating byte pattern, for example, `@as(u64, 0)` has a // repeating byte pattern, for example, `@as(u64, 0)` has a
// repeating byte pattern of 0 bytes. In such case, the memset // repeating byte pattern of 0 bytes. In such case, the memset
// intrinsic can be used. // intrinsic can be used.
if (try elem_val.hasRepeatedByteRepr(elem_ty, pt)) |byte_val| { if (try elem_val.hasRepeatedByteRepr(pt)) |byte_val| {
const fill_byte = try o.builder.intValue(.i8, byte_val); const fill_byte = try o.builder.intValue(.i8, byte_val);
const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
if (intrinsic_len0_traps) { if (intrinsic_len0_traps) {
+2 -1
View File
@@ -589,7 +589,8 @@ pub const File = struct {
fs.File.WriteFileError || fs.File.WriteFileError ||
fs.File.OpenError || fs.File.OpenError ||
std.process.Child.SpawnError || std.process.Child.SpawnError ||
fs.Dir.CopyFileError; fs.Dir.CopyFileError ||
FlushDebugInfoError;
/// Commit pending changes and write headers. Takes into account final output mode /// Commit pending changes and write headers. Takes into account final output mode
/// and `use_lld`, not only `effectiveOutputMode`. /// and `use_lld`, not only `effectiveOutputMode`.
+735 -149
View File
File diff suppressed because it is too large. Load diff
+80 -53
View File
@@ -569,9 +569,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
if (shdr.sh_type != elf.SHT_NOBITS) { if (shdr.sh_type != elf.SHT_NOBITS) {
const allocated_size = self.allocatedSize(shdr.sh_offset); const allocated_size = self.allocatedSize(shdr.sh_offset);
if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) { if (needed_size > allocated_size) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
} else if (needed_size > allocated_size) {
const existing_size = shdr.sh_size; const existing_size = shdr.sh_size;
shdr.sh_size = 0; shdr.sh_size = 0;
// Must move the entire section. // Must move the entire section.
@@ -590,6 +588,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void {
shdr.sh_offset = new_offset; shdr.sh_offset = new_offset;
if (maybe_phdr) |phdr| phdr.p_offset = new_offset; if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
} else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
} }
if (maybe_phdr) |phdr| phdr.p_filesz = needed_size; if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
} }
@@ -621,9 +621,7 @@ pub fn growNonAllocSection(
assert(shdr.sh_flags & elf.SHF_ALLOC == 0); assert(shdr.sh_flags & elf.SHF_ALLOC == 0);
const allocated_size = self.allocatedSize(shdr.sh_offset); const allocated_size = self.allocatedSize(shdr.sh_offset);
if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) { if (needed_size > allocated_size) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
} else if (needed_size > allocated_size) {
const existing_size = shdr.sh_size; const existing_size = shdr.sh_size;
shdr.sh_size = 0; shdr.sh_size = 0;
// Move all the symbols to a new file location. // Move all the symbols to a new file location.
@@ -646,6 +644,8 @@ pub fn growNonAllocSection(
} }
shdr.sh_offset = new_offset; shdr.sh_offset = new_offset;
} else if (shdr.sh_offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(shdr.sh_offset + needed_size);
} }
shdr.sh_size = needed_size; shdr.sh_size = needed_size;
@@ -699,7 +699,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
const sub_prog_node = prog_node.start("ELF Flush", 0); const sub_prog_node = prog_node.start("ELF Flush", 0);
defer sub_prog_node.end(); defer sub_prog_node.end();
const target = comp.root_mod.resolved_target.result; const target = self.getTarget();
const link_mode = comp.config.link_mode; const link_mode = comp.config.link_mode;
const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); 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 {
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = arena_allocator.allocator(); const arena = arena_allocator.allocator();
const target = self.base.comp.root_mod.resolved_target.result; const target = self.getTarget();
const link_mode = self.base.comp.config.link_mode; const link_mode = self.base.comp.config.link_mode;
const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type. const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); 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 {
} }
pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void { pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Word) !void {
const target = self.base.comp.root_mod.resolved_target.result;
if (self.first_eflags == null) { if (self.first_eflags == null) {
self.first_eflags = e_flags; self.first_eflags = e_flags;
return; // there isn't anything to conflict with yet return; // there isn't anything to conflict with yet
} }
const self_eflags: *elf.Elf64_Word = &self.first_eflags.?; const self_eflags: *elf.Elf64_Word = &self.first_eflags.?;
switch (target.cpu.arch) { switch (self.getTarget().cpu.arch) {
.riscv64 => { .riscv64 => {
if (e_flags != self_eflags.*) { if (e_flags != self_eflags.*) {
const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags); const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
@@ -1549,7 +1547,7 @@ fn accessLibPath(
link_mode: ?std.builtin.LinkMode, link_mode: ?std.builtin.LinkMode,
) !bool { ) !bool {
const sep = fs.path.sep_str; const sep = fs.path.sep_str;
const target = self.base.comp.root_mod.resolved_target.result; const target = self.getTarget();
test_path.clearRetainingCapacity(); test_path.clearRetainingCapacity();
const prefix = if (link_mode != null) "lib" else ""; const prefix = if (link_mode != null) "lib" else "";
const suffix = if (link_mode) |mode| switch (mode) { 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
const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe; const is_exe_or_dyn_lib = is_dyn_lib or output_mode == .Exe;
const have_dynamic_linker = comp.config.link_libc and const have_dynamic_linker = comp.config.link_libc and
link_mode == .dynamic and is_exe_or_dyn_lib; link_mode == .dynamic and is_exe_or_dyn_lib;
const target = comp.root_mod.resolved_target.result; const target = self.getTarget();
const compiler_rt_path: ?[]const u8 = blk: { const compiler_rt_path: ?[]const u8 = blk: {
if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; 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
pub fn writeShdrTable(self: *Elf) !void { pub fn writeShdrTable(self: *Elf) !void {
const gpa = self.base.comp.gpa; const gpa = self.base.comp.gpa;
const target = self.base.comp.root_mod.resolved_target.result; const target_endian = self.getTarget().cpu.arch.endian();
const target_endian = target.cpu.arch.endian();
const foreign_endian = target_endian != builtin.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian();
const shsize: u64 = switch (self.ptr_width) { const shsize: u64 = switch (self.ptr_width) {
.p32 => @sizeOf(elf.Elf32_Shdr), .p32 => @sizeOf(elf.Elf32_Shdr),
@@ -2410,8 +2407,7 @@ pub fn writeShdrTable(self: *Elf) !void {
fn writePhdrTable(self: *Elf) !void { fn writePhdrTable(self: *Elf) !void {
const gpa = self.base.comp.gpa; const gpa = self.base.comp.gpa;
const target = self.base.comp.root_mod.resolved_target.result; const target_endian = self.getTarget().cpu.arch.endian();
const target_endian = target.cpu.arch.endian();
const foreign_endian = target_endian != builtin.cpu.arch.endian(); const foreign_endian = target_endian != builtin.cpu.arch.endian();
const phdr_table = &self.phdrs.items[self.phdr_table_index.?]; const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
@@ -2464,7 +2460,7 @@ pub fn writeElfHeader(self: *Elf) !void {
}; };
index += 1; index += 1;
const target = comp.root_mod.resolved_target.result; const target = self.getTarget();
const endian = target.cpu.arch.endian(); const endian = target.cpu.arch.endian();
hdr_buf[index] = switch (endian) { hdr_buf[index] = switch (endian) {
.little => elf.ELFDATA2LSB, .little => elf.ELFDATA2LSB,
@@ -2772,21 +2768,25 @@ fn initOutputSections(self: *Elf) !void {
fn initSyntheticSections(self: *Elf) !void { fn initSyntheticSections(self: *Elf) !void {
const comp = self.base.comp; const comp = self.base.comp;
const target = comp.root_mod.resolved_target.result; const target = self.getTarget();
const ptr_size = self.ptrWidthBytes(); const ptr_size = self.ptrWidthBytes();
const needs_eh_frame = for (self.objects.items) |index| { const needs_eh_frame = for (self.objects.items) |index| {
if (self.file(index).?.object.cies.items.len > 0) break true; if (self.file(index).?.object.cies.items.len > 0) break true;
} else false; } else false;
if (needs_eh_frame) { if (needs_eh_frame) {
self.eh_frame_section_index = try self.addSection(.{ if (self.eh_frame_section_index == null) {
.name = try self.insertShString(".eh_frame"), self.eh_frame_section_index = try self.addSection(.{
.type = elf.SHT_PROGBITS, .name = try self.insertShString(".eh_frame"),
.flags = elf.SHF_ALLOC, .type = if (target.cpu.arch == .x86_64)
.addralign = ptr_size, elf.SHT_X86_64_UNWIND
.offset = std.math.maxInt(u64), else
}); elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = ptr_size,
.offset = std.math.maxInt(u64),
});
}
if (comp.link_eh_frame_hdr) { if (comp.link_eh_frame_hdr) {
self.eh_frame_hdr_section_index = try self.addSection(.{ self.eh_frame_hdr_section_index = try self.addSection(.{
.name = try self.insertShString(".eh_frame_hdr"), .name = try self.insertShString(".eh_frame_hdr"),
@@ -3446,7 +3446,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void {
} }
fn updateSectionSizes(self: *Elf) !void { fn updateSectionSizes(self: *Elf) !void {
const target = self.base.comp.root_mod.resolved_target.result;
const slice = self.sections.slice(); const slice = self.sections.slice();
for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| {
if (atom_list.items.len == 0) continue; if (atom_list.items.len == 0) continue;
@@ -3474,7 +3473,11 @@ fn updateSectionSizes(self: *Elf) !void {
const shdrs = slice.items(.shdr); const shdrs = slice.items(.shdr);
if (self.eh_frame_section_index) |index| { if (self.eh_frame_section_index) |index| {
shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self); shdrs[index].sh_size = existing_size: {
const zo = self.zigObjectPtr() orelse break :existing_size 0;
const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
break :existing_size sym.atom(self).?.size;
} + try eh_frame.calcEhFrameSize(self);
} }
if (self.eh_frame_hdr_section_index) |index| { if (self.eh_frame_hdr_section_index) |index| {
@@ -3517,7 +3520,7 @@ fn updateSectionSizes(self: *Elf) !void {
} }
if (self.interp_section_index) |index| { if (self.interp_section_index) |index| {
shdrs[index].sh_size = target.dynamic_linker.get().?.len + 1; shdrs[index].sh_size = self.getTarget().dynamic_linker.get().?.len + 1;
} }
if (self.hash_section_index) |index| { if (self.hash_section_index) |index| {
@@ -3759,10 +3762,10 @@ pub fn allocateAllocSections(self: *Elf) !void {
} }
const first = slice.items(.shdr)[cover.items[0]]; const first = slice.items(.shdr)[cover.items[0]];
var off = try self.findFreeSpace(filesz, @"align"); var new_offset = try self.findFreeSpace(filesz, @"align");
const phndx = try self.addPhdr(.{ const phndx = try self.addPhdr(.{
.type = elf.PT_LOAD, .type = elf.PT_LOAD,
.offset = off, .offset = new_offset,
.addr = first.sh_addr, .addr = first.sh_addr,
.memsz = memsz, .memsz = memsz,
.filesz = filesz, .filesz = filesz,
@@ -3777,9 +3780,28 @@ pub fn allocateAllocSections(self: *Elf) !void {
shdr.sh_offset = 0; shdr.sh_offset = 0;
continue; continue;
} }
off = alignment.@"align"(shndx, shdr.sh_addralign, off); new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset);
shdr.sh_offset = off;
off += shdr.sh_size; if (shndx == self.eh_frame_section_index) eh_frame: {
const zo = self.zigObjectPtr() orelse break :eh_frame;
const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame);
const existing_size = sym.atom(self).?.size;
log.debug("moving {s} from 0x{x} to 0x{x}", .{
self.getShString(shdr.sh_name),
shdr.sh_offset,
new_offset,
});
const amt = try self.base.file.?.copyRangeAll(
shdr.sh_offset,
self.base.file.?,
new_offset,
existing_size,
);
if (amt != existing_size) return error.InputOutput;
}
shdr.sh_offset = new_offset;
new_offset += shdr.sh_size;
} }
addr = mem.alignForward(u64, addr, self.page_size); addr = mem.alignForward(u64, addr, self.page_size);
@@ -3910,9 +3932,9 @@ fn writeAtoms(self: *Elf) !void {
log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
// TODO really, really handle debug section separately // TODO really, really handle debug section separately
const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: { const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: {
const zo = self.zigObjectPtr().?; const zo = self.zigObjectPtr().?;
break :blk for ([_]Symbol.Index{ for ([_]Symbol.Index{
zo.debug_info_index.?, zo.debug_info_index.?,
zo.debug_abbrev_index.?, zo.debug_abbrev_index.?,
zo.debug_aranges_index.?, zo.debug_aranges_index.?,
@@ -3924,8 +3946,13 @@ fn writeAtoms(self: *Elf) !void {
}) |sym_index| { }) |sym_index| {
const sym = zo.symbol(sym_index); const sym = zo.symbol(sym_index);
const atom_ptr = sym.atom(self).?; const atom_ptr = sym.atom(self).?;
if (atom_ptr.output_section_index == shndx) break atom_ptr.size; if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size;
} else 0; }
break :base_offset 0;
} else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: {
const zo = self.zigObjectPtr() orelse break :base_offset 0;
const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0);
break :base_offset sym.atom(self).?.size;
} else 0; } else 0;
const sh_offset = shdr.sh_offset + base_offset; const sh_offset = shdr.sh_offset + base_offset;
const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; 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 {
fn writeSyntheticSections(self: *Elf) !void { fn writeSyntheticSections(self: *Elf) !void {
const gpa = self.base.comp.gpa; const gpa = self.base.comp.gpa;
const target = self.getTarget();
const slice = self.sections.slice(); const slice = self.sections.slice();
if (self.interp_section_index) |shndx| { if (self.interp_section_index) |shndx| {
var buffer: [256]u8 = undefined; var buffer: [256]u8 = undefined;
const interp = target.dynamic_linker.get().?; const interp = self.getTarget().dynamic_linker.get().?;
@memcpy(buffer[0..interp.len], interp); @memcpy(buffer[0..interp.len], interp);
buffer[interp.len] = 0; buffer[interp.len] = 0;
const contents = buffer[0 .. interp.len + 1]; const contents = buffer[0 .. interp.len + 1];
@@ -4144,12 +4170,18 @@ fn writeSyntheticSections(self: *Elf) !void {
} }
if (self.eh_frame_section_index) |shndx| { if (self.eh_frame_section_index) |shndx| {
const existing_size = existing_size: {
const zo = self.zigObjectPtr() orelse break :existing_size 0;
const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
break :existing_size sym.atom(self).?.size;
};
const shdr = slice.items(.shdr)[shndx]; const shdr = slice.items(.shdr)[shndx];
const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
defer buffer.deinit(); defer buffer.deinit();
try eh_frame.writeEhFrame(self, buffer.writer()); try eh_frame.writeEhFrame(self, buffer.writer());
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); assert(buffer.items.len == sh_size - existing_size);
try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
} }
if (self.eh_frame_hdr_section_index) |shndx| { if (self.eh_frame_hdr_section_index) |shndx| {
@@ -4222,7 +4254,6 @@ pub fn writeShStrtab(self: *Elf) !void {
pub fn writeSymtab(self: *Elf) !void { pub fn writeSymtab(self: *Elf) !void {
const gpa = self.base.comp.gpa; const gpa = self.base.comp.gpa;
const target = self.getTarget();
const slice = self.sections.slice(); const slice = self.sections.slice();
const symtab_shdr = slice.items(.shdr)[self.symtab_section_index.?]; const symtab_shdr = slice.items(.shdr)[self.symtab_section_index.?];
const strtab_shdr = slice.items(.shdr)[self.strtab_section_index.?]; const strtab_shdr = slice.items(.shdr)[self.strtab_section_index.?];
@@ -4292,7 +4323,7 @@ pub fn writeSymtab(self: *Elf) !void {
self.plt_got.writeSymtab(self); self.plt_got.writeSymtab(self);
} }
const foreign_endian = target.cpu.arch.endian() != builtin.cpu.arch.endian(); const foreign_endian = self.getTarget().cpu.arch.endian() != builtin.cpu.arch.endian();
switch (self.ptr_width) { switch (self.ptr_width) {
.p32 => { .p32 => {
const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len); const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
@@ -4630,10 +4661,8 @@ pub fn isZigSection(self: Elf, shndx: u32) bool {
self.zig_data_rel_ro_section_index, self.zig_data_rel_ro_section_index,
self.zig_data_section_index, self.zig_data_section_index,
self.zig_bss_section_index, self.zig_bss_section_index,
}) |maybe_index| { }) |index| {
if (maybe_index) |index| { if (index == shndx) return true;
if (index == shndx) return true;
}
} }
return false; return false;
} }
@@ -4648,10 +4677,8 @@ pub fn isDebugSection(self: Elf, shndx: u32) bool {
self.debug_line_str_section_index, self.debug_line_str_section_index,
self.debug_loclists_section_index, self.debug_loclists_section_index,
self.debug_rnglists_section_index, self.debug_rnglists_section_index,
}) |maybe_index| { }) |index| {
if (maybe_index) |index| { if (index == shndx) return true;
if (index == shndx) return true;
}
} }
return false; return false;
} }
+42 -9
View File
@@ -49,6 +49,7 @@ debug_line_section_dirty: bool = false,
debug_line_str_section_dirty: bool = false, debug_line_str_section_dirty: bool = false,
debug_loclists_section_dirty: bool = false, debug_loclists_section_dirty: bool = false,
debug_rnglists_section_dirty: bool = false, debug_rnglists_section_dirty: bool = false,
eh_frame_section_dirty: bool = false,
debug_info_index: ?Symbol.Index = null, debug_info_index: ?Symbol.Index = null,
debug_abbrev_index: ?Symbol.Index = null, debug_abbrev_index: ?Symbol.Index = null,
@@ -58,6 +59,7 @@ debug_line_index: ?Symbol.Index = null,
debug_line_str_index: ?Symbol.Index = null, debug_line_str_index: ?Symbol.Index = null,
debug_loclists_index: ?Symbol.Index = null, debug_loclists_index: ?Symbol.Index = null,
debug_rnglists_index: ?Symbol.Index = null, debug_rnglists_index: ?Symbol.Index = null,
eh_frame_index: ?Symbol.Index = null,
pub const global_symbol_bit: u32 = 0x80000000; pub const global_symbol_bit: u32 = 0x80000000;
pub const symbol_mask: u32 = 0x7fffffff; pub const symbol_mask: u32 = 0x7fffffff;
@@ -72,8 +74,6 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
const comp = elf_file.base.comp; const comp = elf_file.base.comp;
const gpa = comp.gpa; const gpa = comp.gpa;
const ptr_size = elf_file.ptrWidthBytes(); const ptr_size = elf_file.ptrWidthBytes();
const target = elf_file.getTarget();
const ptr_bit_width = target.ptrBitWidth();
try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
try self.relocs.append(gpa, .{}); // null relocs section try self.relocs.append(gpa, .{}); // null relocs section
@@ -113,7 +113,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.type = elf.PT_LOAD, .type = elf.PT_LOAD,
.offset = off, .offset = off,
.filesz = filesz, .filesz = filesz,
.addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000, .addr = if (ptr_size >= 4) 0x4000000 else 0x4000,
.memsz = filesz, .memsz = filesz,
.@"align" = elf_file.page_size, .@"align" = elf_file.page_size,
.flags = elf.PF_X | elf.PF_R | elf.PF_W, .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 {
.type = elf.PT_LOAD, .type = elf.PT_LOAD,
.offset = off, .offset = off,
.filesz = filesz, .filesz = filesz,
.addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000, .addr = if (ptr_size >= 4) 0xc000000 else 0xa000,
.memsz = filesz, .memsz = filesz,
.@"align" = alignment, .@"align" = alignment,
.flags = elf.PF_R | elf.PF_W, .flags = elf.PF_R | elf.PF_W,
@@ -143,7 +143,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
.type = elf.PT_LOAD, .type = elf.PT_LOAD,
.offset = off, .offset = off,
.filesz = filesz, .filesz = filesz,
.addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000, .addr = if (ptr_size >= 4) 0x10000000 else 0xc000,
.memsz = filesz, .memsz = filesz,
.@"align" = alignment, .@"align" = alignment,
.flags = elf.PF_R | elf.PF_W, .flags = elf.PF_R | elf.PF_W,
@@ -154,7 +154,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
const alignment = elf_file.page_size; const alignment = elf_file.page_size;
elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{ elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{
.type = elf.PT_LOAD, .type = elf.PT_LOAD,
.addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000, .addr = if (ptr_size >= 4) 0x14000000 else 0xf000,
.memsz = 1024, .memsz = 1024,
.@"align" = alignment, .@"align" = alignment,
.flags = elf.PF_R | elf.PF_W, .flags = elf.PF_R | elf.PF_W,
@@ -354,6 +354,20 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);
} }
if (elf_file.eh_frame_section_index == null) {
elf_file.eh_frame_section_index = try elf_file.addSection(.{
.name = try elf_file.insertShString(".eh_frame"),
.type = if (elf_file.getTarget().cpu.arch == .x86_64)
elf.SHT_X86_64_UNWIND
else
elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = ptr_size,
});
self.eh_frame_section_dirty = true;
self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?);
}
try dwarf.initMetadata(); try dwarf.initMetadata();
self.dwarf = dwarf; self.dwarf = dwarf;
}, },
@@ -460,6 +474,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
self.debug_line_str_index.?, self.debug_line_str_index.?,
self.debug_loclists_index.?, self.debug_loclists_index.?,
self.debug_rnglists_index.?, self.debug_rnglists_index.?,
self.eh_frame_index.?,
}, [_]*Dwarf.Section{ }, [_]*Dwarf.Section{
&dwarf.debug_info.section, &dwarf.debug_info.section,
&dwarf.debug_abbrev.section, &dwarf.debug_abbrev.section,
@@ -469,7 +484,18 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
&dwarf.debug_line_str.section, &dwarf.debug_line_str.section,
&dwarf.debug_loclists.section, &dwarf.debug_loclists.section,
&dwarf.debug_rnglists.section, &dwarf.debug_rnglists.section,
}) |sym_index, sect| { &dwarf.debug_frame.section,
}, [_]Dwarf.Section.Index{
.debug_info,
.debug_abbrev,
.debug_str,
.debug_aranges,
.debug_line,
.debug_line_str,
.debug_loclists,
.debug_rnglists,
.debug_frame,
}) |sym_index, sect, sect_index| {
const sym = self.symbol(sym_index); const sym = self.symbol(sym_index);
const atom_ptr = self.atom(sym.ref.index).?; const atom_ptr = self.atom(sym.ref.index).?;
if (!atom_ptr.alive) continue; if (!atom_ptr.alive) continue;
@@ -509,6 +535,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
for (unit.cross_section_relocs.items) |reloc| { for (unit.cross_section_relocs.items) |reloc| {
const target_sym_index = switch (reloc.target_sec) { const target_sym_index = switch (reloc.target_sec) {
.debug_abbrev => self.debug_abbrev_index.?, .debug_abbrev => self.debug_abbrev_index.?,
.debug_aranges => self.debug_aranges_index.?,
.debug_frame => self.eh_frame_index.?,
.debug_info => self.debug_info_index.?, .debug_info => self.debug_info_index.?,
.debug_line => self.debug_line_index.?, .debug_line => self.debug_line_index.?,
.debug_line_str => self.debug_line_str_index.?, .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
entry.external_relocs.items.len); entry.external_relocs.items.len);
for (entry.cross_entry_relocs.items) |reloc| { for (entry.cross_entry_relocs.items) |reloc| {
const r_offset = entry_off + reloc.source_off; const r_offset = entry_off + reloc.source_off;
const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off); const r_addend: i64 = @intCast(unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
unit.header_len + unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
else
0));
const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch); const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
self.symbol(sym_index).name(elf_file), self.symbol(sym_index).name(elf_file),
@@ -584,6 +615,8 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi
for (entry.cross_section_relocs.items) |reloc| { for (entry.cross_section_relocs.items) |reloc| {
const target_sym_index = switch (reloc.target_sec) { const target_sym_index = switch (reloc.target_sec) {
.debug_abbrev => self.debug_abbrev_index.?, .debug_abbrev => self.debug_abbrev_index.?,
.debug_aranges => self.debug_aranges_index.?,
.debug_frame => self.eh_frame_index.?,
.debug_info => self.debug_info_index.?, .debug_info => self.debug_info_index.?,
.debug_line => self.debug_line_index.?, .debug_line => self.debug_line_index.?,
.debug_line_str => self.debug_line_str_index.?, .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
const target_sym = self.symbol(reloc.target_sym); const target_sym = self.symbol(reloc.target_sym);
const r_offset = entry_off + reloc.source_off; const r_offset = entry_off + reloc.source_off;
const r_addend: i64 = @intCast(reloc.target_off); const r_addend: i64 = @intCast(reloc.target_off);
const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch); const r_type = relocation.dwarf.externalRelocType(target_sym.*, sect_index, dwarf.address_size, cpu_arch);
log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{
target_sym.name(elf_file), target_sym.name(elf_file),
r_offset, r_offset,
+27 -15
View File
@@ -289,8 +289,6 @@ fn claimUnresolved(elf_file: *Elf) void {
} }
fn initSections(elf_file: *Elf) !void { fn initSections(elf_file: *Elf) !void {
const ptr_size = elf_file.ptrWidthBytes();
for (elf_file.objects.items) |index| { for (elf_file.objects.items) |index| {
const object = elf_file.file(index).?.object; const object = elf_file.file(index).?.object;
try object.initOutputSections(elf_file); try object.initOutputSections(elf_file);
@@ -306,13 +304,18 @@ fn initSections(elf_file: *Elf) !void {
if (elf_file.file(index).?.object.cies.items.len > 0) break true; if (elf_file.file(index).?.object.cies.items.len > 0) break true;
} else false; } else false;
if (needs_eh_frame) { if (needs_eh_frame) {
elf_file.eh_frame_section_index = try elf_file.addSection(.{ if (elf_file.eh_frame_section_index == null) {
.name = try elf_file.insertShString(".eh_frame"), elf_file.eh_frame_section_index = try elf_file.addSection(.{
.type = elf.SHT_PROGBITS, .name = try elf_file.insertShString(".eh_frame"),
.flags = elf.SHF_ALLOC, .type = if (elf_file.getTarget().cpu.arch == .x86_64)
.addralign = ptr_size, elf.SHT_X86_64_UNWIND
.offset = std.math.maxInt(u64), else
}); elf.SHT_PROGBITS,
.flags = elf.SHF_ALLOC,
.addralign = elf_file.ptrWidthBytes(),
.offset = std.math.maxInt(u64),
});
}
elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr( elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr(
try elf_file.insertShString(".rela.eh_frame"), try elf_file.insertShString(".rela.eh_frame"),
elf_file.eh_frame_section_index.?, elf_file.eh_frame_section_index.?,
@@ -373,7 +376,11 @@ fn updateSectionSizes(elf_file: *Elf) !void {
} }
if (elf_file.eh_frame_section_index) |index| { if (elf_file.eh_frame_section_index) |index| {
slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file); slice.items(.shdr)[index].sh_size = existing_size: {
const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
break :existing_size sym.atom(elf_file).?.size;
} + try eh_frame.calcEhFrameSize(elf_file);
} }
if (elf_file.eh_frame_rela_section_index) |index| { if (elf_file.eh_frame_rela_section_index) |index| {
const shdr = &slice.items(.shdr)[index]; const shdr = &slice.items(.shdr)[index];
@@ -526,17 +533,22 @@ fn writeSyntheticSections(elf_file: *Elf) !void {
} }
if (elf_file.eh_frame_section_index) |shndx| { if (elf_file.eh_frame_section_index) |shndx| {
const existing_size = existing_size: {
const zo = elf_file.zigObjectPtr() orelse break :existing_size 0;
const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0);
break :existing_size sym.atom(elf_file).?.size;
};
const shdr = slice.items(.shdr)[shndx]; const shdr = slice.items(.shdr)[shndx];
const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size));
defer buffer.deinit(); defer buffer.deinit();
try eh_frame.writeEhFrameObject(elf_file, buffer.writer()); try eh_frame.writeEhFrameObject(elf_file, buffer.writer());
log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{
shdr.sh_offset, shdr.sh_offset + existing_size,
shdr.sh_offset + shdr.sh_size, shdr.sh_offset + sh_size,
}); });
assert(buffer.items.len == sh_size); assert(buffer.items.len == sh_size - existing_size);
try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); try elf_file.base.file.?.pwriteAll(buffer.items, shdr.sh_offset + existing_size);
} }
if (elf_file.eh_frame_rela_section_index) |shndx| { if (elf_file.eh_frame_rela_section_index) |shndx| {
const shdr = slice.items(.shdr)[shndx]; const shdr = slice.items(.shdr)[shndx];
+17 -10
View File
@@ -108,20 +108,27 @@ pub const dwarf = struct {
pub fn externalRelocType( pub fn externalRelocType(
target: Symbol, target: Symbol,
source_section: Dwarf.Section.Index,
address_size: Dwarf.AddressSize, address_size: Dwarf.AddressSize,
cpu_arch: std.Target.Cpu.Arch, cpu_arch: std.Target.Cpu.Arch,
) u32 { ) u32 {
return switch (cpu_arch) { return switch (cpu_arch) {
.x86_64 => @intFromEnum(switch (address_size) { .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (source_section) {
.@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32", else => switch (address_size) {
.@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64", .@"32" => if (target.flags.is_tls) .DTPOFF32 else .@"32",
else => unreachable, .@"64" => if (target.flags.is_tls) .DTPOFF64 else .@"64",
}), else => unreachable,
.riscv64 => @intFromEnum(switch (address_size) { },
.@"32" => elf.R_RISCV.@"32", .debug_frame => .PC32,
.@"64" => elf.R_RISCV.@"64", })),
else => unreachable, .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) {
}), else => switch (address_size) {
.@"32" => .@"32",
.@"64" => .@"64",
else => unreachable,
},
.debug_frame => unreachable,
})),
else => @panic("TODO unhandled cpu arch"), else => @panic("TODO unhandled cpu arch"),
}; };
} }
+6 -6
View File
@@ -3411,9 +3411,7 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
if (!sect.isZerofill()) { if (!sect.isZerofill()) {
const allocated_size = self.allocatedSize(sect.offset); const allocated_size = self.allocatedSize(sect.offset);
if (sect.offset + allocated_size == std.math.maxInt(u64)) { if (needed_size > allocated_size) {
try self.base.file.?.setEndPos(sect.offset + needed_size);
} else if (needed_size > allocated_size) {
const existing_size = sect.size; const existing_size = sect.size;
sect.size = 0; sect.size = 0;
@@ -3431,6 +3429,8 @@ fn growSectionNonRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !vo
try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size); try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
sect.offset = @intCast(new_offset); sect.offset = @intCast(new_offset);
} else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(sect.offset + needed_size);
} }
seg.filesize = needed_size; seg.filesize = needed_size;
} }
@@ -3456,9 +3456,7 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
if (!sect.isZerofill()) { if (!sect.isZerofill()) {
const allocated_size = self.allocatedSize(sect.offset); const allocated_size = self.allocatedSize(sect.offset);
if (sect.offset + allocated_size == std.math.maxInt(u64)) { if (needed_size > allocated_size) {
try self.base.file.?.setEndPos(sect.offset + needed_size);
} else if (needed_size > allocated_size) {
const existing_size = sect.size; const existing_size = sect.size;
sect.size = 0; sect.size = 0;
@@ -3480,6 +3478,8 @@ fn growSectionRelocatable(self: *MachO, sect_index: u8, needed_size: u64) !void
sect.offset = @intCast(new_offset); sect.offset = @intCast(new_offset);
sect.addr = new_addr; sect.addr = new_addr;
} else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
try self.base.file.?.setEndPos(sect.offset + needed_size);
} }
} }
sect.size = needed_size; sect.size = needed_size;
+3 -3
View File
@@ -105,9 +105,7 @@ pub fn growSection(
const sect = self.getSectionPtr(sect_index); const sect = self.getSectionPtr(sect_index);
const allocated_size = self.allocatedSize(sect.offset); const allocated_size = self.allocatedSize(sect.offset);
if (sect.offset + allocated_size == std.math.maxInt(u64)) { if (needed_size > allocated_size) {
try self.file.setEndPos(sect.offset + needed_size);
} else if (needed_size > allocated_size) {
const existing_size = sect.size; const existing_size = sect.size;
sect.size = 0; // free the space sect.size = 0; // free the space
const new_offset = try self.findFreeSpace(needed_size, 1); const new_offset = try self.findFreeSpace(needed_size, 1);
@@ -130,6 +128,8 @@ pub fn growSection(
} }
sect.offset = @intCast(new_offset); sect.offset = @intCast(new_offset);
} else if (sect.offset + allocated_size == std.math.maxInt(u64)) {
try self.file.setEndPos(sect.offset + needed_size);
} }
sect.size = needed_size; sect.size = needed_size;
+76
View File
@@ -305,6 +305,82 @@ pub fn addTestsForTarget(db: *Debugger, target: Target) void {
\\1 breakpoints deleted; 0 breakpoint locations disabled. \\1 breakpoints deleted; 0 breakpoint locations disabled.
}, },
); );
db.addLldbTest(
"strings",
target,
&.{
.{
.path = "strings.zig",
.source =
\\const Strings = struct {
\\ c_ptr: [*c]const u8 = "c_ptr\x07\x08\t",
\\ many_ptr: [*:0]const u8 = "many_ptr\n\x0b\x0c",
\\ ptr_array: *const [12:0]u8 = "ptr_array\x00\r\x1b",
\\ slice: [:0]const u8 = "slice\"\'\\\x00",
\\};
\\fn testStrings(strings: Strings) void {
\\ _ = strings;
\\}
\\pub fn main() void {
\\ testStrings(.{});
\\}
\\
,
},
},
\\breakpoint set --file strings.zig --source-pattern-regexp '_ = strings;'
\\process launch
\\frame variable --show-types strings.slice
\\frame variable --show-types --format character strings.slice
\\frame variable --show-types --format c-string strings
\\breakpoint delete --force 1
,
&.{
\\(lldb) frame variable --show-types strings.slice
\\([:0]const u8) strings.slice = len=9 {
\\ (u8) [0] = 115
\\ (u8) [1] = 108
\\ (u8) [2] = 105
\\ (u8) [3] = 99
\\ (u8) [4] = 101
\\ (u8) [5] = 34
\\ (u8) [6] = 39
\\ (u8) [7] = 92
\\ (u8) [8] = 0
\\}
\\(lldb) frame variable --show-types --format character strings.slice
\\([:0]const u8) strings.slice = len=9 {
\\ (u8) [0] = 's'
\\ (u8) [1] = 'l'
\\ (u8) [2] = 'i'
\\ (u8) [3] = 'c'
\\ (u8) [4] = 'e'
\\ (u8) [5] = '\"'
\\ (u8) [6] = '\''
\\ (u8) [7] = '\\'
\\ (u8) [8] = '\x00'
\\}
\\(lldb) frame variable --show-types --format c-string strings
\\(root.strings.Strings) strings = {
\\ ([*c]const u8) c_ptr = "c_ptr\x07\x08\t"
\\ ([*:0]const u8) many_ptr = "many_ptr\n\x0b\x0c"
\\ (*const [12:0]u8) ptr_array = "ptr_array\x00\r\x1b"
\\ ([:0]const u8) slice = "slice\"\'\\\x00" len=9 {
\\ (u8) [0] = "s"
\\ (u8) [1] = "l"
\\ (u8) [2] = "i"
\\ (u8) [3] = "c"
\\ (u8) [4] = "e"
\\ (u8) [5] = "\""
\\ (u8) [6] = "\'"
\\ (u8) [7] = "\\"
\\ (u8) [8] = "\x00"
\\ }
\\}
\\(lldb) breakpoint delete --force 1
\\1 breakpoints deleted; 0 breakpoint locations disabled.
},
);
db.addLldbTest( db.addLldbTest(
"enums", "enums",
target, target,