diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2025-08-30 12:08:18 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-09-21 14:09:14 -0700 |
| commit | f58200e3f2967a06f343c9fc9dcae9de18def92a (patch) | |
| tree | 84257e40a7a0186fbc10cf7467e65f004036d3e3 /src/codegen.zig | |
| parent | 2a97e0af6d42e038d962890a320e262e676d44cb (diff) | |
| download | zig-f58200e3f2967a06f343c9fc9dcae9de18def92a.tar.gz zig-f58200e3f2967a06f343c9fc9dcae9de18def92a.zip | |
Elf2: create a new linker from scratch
This iteration already has significantly better incremental support.
Closes #24110
Diffstat (limited to 'src/codegen.zig')
| -rw-r--r-- | src/codegen.zig | 271 |
1 files changed, 133 insertions, 138 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 56e6e7c99f..4cbf3f5616 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -6,7 +6,6 @@ const link = @import("link.zig"); const log = std.log.scoped(.codegen); const mem = std.mem; const math = std.math; -const ArrayList = std.ArrayList; const target_util = @import("target.zig"); const trace = @import("tracy.zig").trace; @@ -179,10 +178,11 @@ pub fn emitFunction( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, func_index: InternPool.Index, + atom_index: u32, any_mir: *const AnyMir, - code: *ArrayList(u8), + w: *std.Io.Writer, debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { +) (CodeGenError || std.Io.Writer.Error)!void { const zcu = pt.zcu; const func = zcu.funcInfo(func_index); const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; @@ -195,7 +195,7 @@ pub fn emitFunction( => |backend| { dev.check(devFeatureForBackend(backend)); const mir = &@field(any_mir, AnyMir.tag(backend)); - return mir.emit(lf, pt, src_loc, func_index, code, debug_output); + return mir.emit(lf, pt, src_loc, func_index, atom_index, w, debug_output); }, } } @@ -205,9 +205,10 @@ pub fn generateLazyFunction( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, lazy_sym: link.File.LazySymbol, - code: *ArrayList(u8), + atom_index: u32, + w: *std.Io.Writer, debug_output: link.File.DebugInfoOutput, -) CodeGenError!void { +) (CodeGenError || std.Io.Writer.Error)!void { const zcu = pt.zcu; const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index| &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result @@ -217,19 +218,11 @@ pub fn generateLazyFunction( else => unreachable, inline .stage2_riscv64, .stage2_x86_64 => |backend| { dev.check(devFeatureForBackend(backend)); - return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, code, debug_output); + return importBackend(backend).generateLazy(lf, pt, src_loc, lazy_sym, atom_index, w, debug_output); }, } } -fn writeFloat(comptime F: type, f: F, target: *const std.Target, endian: std.builtin.Endian, code: []u8) void { - _ = target; - const bits = @typeInfo(F).float.bits; - const Int = @Type(.{ .int = .{ .signedness = .unsigned, .bits = bits } }); - const int: Int = @bitCast(f); - mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); -} - pub fn generateLazySymbol( bin_file: *link.File, pt: Zcu.PerThread, @@ -237,17 +230,14 @@ pub fn generateLazySymbol( lazy_sym: link.File.LazySymbol, // TODO don't use an "out" parameter like this; put it in the result instead alignment: *Alignment, - code: *ArrayList(u8), + w: *std.Io.Writer, debug_output: link.File.DebugInfoOutput, reloc_parent: link.File.RelocInfo.Parent, -) CodeGenError!void { - _ = reloc_parent; - +) (CodeGenError || std.Io.Writer.Error)!void { const tracy = trace(@src()); defer tracy.end(); const comp = bin_file.comp; - const gpa = comp.gpa; const zcu = pt.zcu; const ip = &zcu.intern_pool; const target = &comp.root_mod.resolved_target.result; @@ -260,37 +250,36 @@ pub fn generateLazySymbol( if (lazy_sym.kind == .code) { alignment.* = target_util.defaultFunctionAlignment(target); - return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, code, debug_output); + return generateLazyFunction(bin_file, pt, src_loc, lazy_sym, reloc_parent.atom_index, w, debug_output); } if (lazy_sym.ty == .anyerror_type) { alignment.* = .@"4"; const err_names = ip.global_error_set.getNamesFromMainThread(); - var offset_index: u32 = @intCast(code.items.len); - var string_index: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); - try code.resize(gpa, offset_index + string_index); - mem.writeInt(u32, code.items[offset_index..][0..4], @intCast(err_names.len), endian); + const strings_start: u32 = @intCast(4 * (1 + err_names.len + @intFromBool(err_names.len > 0))); + var string_index = strings_start; + try w.rebase(w.end, string_index); + w.writeInt(u32, @intCast(err_names.len), endian) catch unreachable; if (err_names.len == 0) return; - offset_index += 4; for (err_names) |err_name_nts| { - const err_name = err_name_nts.toSlice(ip); - mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); - offset_index += 4; - try code.ensureUnusedCapacity(gpa, err_name.len + 1); - code.appendSliceAssumeCapacity(err_name); - code.appendAssumeCapacity(0); - string_index += @intCast(err_name.len + 1); + w.writeInt(u32, string_index, endian) catch unreachable; + string_index += @intCast(err_name_nts.toSlice(ip).len + 1); + } + w.writeInt(u32, string_index, endian) catch unreachable; + try w.rebase(w.end, string_index - strings_start); + for (err_names) |err_name_nts| { + w.writeAll(err_name_nts.toSlice(ip)) catch unreachable; + w.writeByte(0) catch unreachable; } - mem.writeInt(u32, code.items[offset_index..][0..4], string_index, endian); } else if (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu) == .@"enum") { alignment.* = .@"1"; const enum_ty = Type.fromInterned(lazy_sym.ty); const tag_names = enum_ty.enumFields(zcu); for (0..tag_names.len) |tag_index| { const tag_name = tag_names.get(ip)[tag_index].toSlice(ip); - try code.ensureUnusedCapacity(gpa, tag_name.len + 1); - code.appendSliceAssumeCapacity(tag_name); - code.appendAssumeCapacity(0); + try w.rebase(w.end, tag_name.len + 1); + w.writeAll(tag_name) catch unreachable; + w.writeByte(0) catch unreachable; } } else { return zcu.codegenFailType(lazy_sym.ty, "TODO implement generateLazySymbol for {s} {f}", .{ @@ -312,14 +301,13 @@ pub fn generateSymbol( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, val: Value, - code: *ArrayList(u8), + w: *std.Io.Writer, reloc_parent: link.File.RelocInfo.Parent, -) GenerateSymbolError!void { +) (GenerateSymbolError || std.Io.Writer.Error)!void { const tracy = trace(@src()); defer tracy.end(); const zcu = pt.zcu; - const gpa = zcu.gpa; const ip = &zcu.intern_pool; const ty = val.typeOf(zcu); @@ -330,7 +318,7 @@ pub fn generateSymbol( if (val.isUndef(zcu)) { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - try code.appendNTimes(gpa, 0xaa, abi_size); + try w.splatByteAll(0xaa, abi_size); return; } @@ -360,7 +348,7 @@ pub fn generateSymbol( .null => unreachable, // non-runtime value .@"unreachable" => unreachable, // non-runtime value .empty_tuple => return, - .false, .true => try code.append(gpa, switch (simple_value) { + .false, .true => try w.writeByte(switch (simple_value) { .false => 0, .true => 1, else => unreachable, @@ -376,11 +364,11 @@ pub fn generateSymbol( const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; var space: Value.BigIntSpace = undefined; const int_val = val.toBigInt(&space, zcu); - int_val.writeTwosComplement(try code.addManyAsSlice(gpa, abi_size), endian); + int_val.writeTwosComplement(try w.writableSlice(abi_size), endian); }, .err => |err| { const int = try pt.getErrorValue(err.name); - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), @intCast(int), endian); + try w.writeInt(u16, @intCast(int), endian); }, .error_union => |error_union| { const payload_ty = ty.errorUnionPayload(zcu); @@ -390,7 +378,7 @@ pub fn generateSymbol( }; if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); + try w.writeInt(u16, err_val, endian); return; } @@ -400,63 +388,63 @@ pub fn generateSymbol( // error value first when its type is larger than the error union's payload if (error_align.order(payload_align) == .gt) { - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); + try w.writeInt(u16, err_val, endian); } // emit payload part of the error union { - const begin = code.items.len; + const begin = w.end; try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(switch (error_union.val) { .err_name => try pt.intern(.{ .undef = payload_ty.toIntern() }), .payload => |payload| payload, - }), code, reloc_parent); - const unpadded_end = code.items.len - begin; + }), w, reloc_parent); + const unpadded_end = w.end - begin; const padded_end = abi_align.forward(unpadded_end); const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); + try w.splatByteAll(0, padding); } } // Payload size is larger than error set, so emit our error set last if (error_align.compare(.lte, payload_align)) { - const begin = code.items.len; - mem.writeInt(u16, try code.addManyAsArray(gpa, 2), err_val, endian); - const unpadded_end = code.items.len - begin; + const begin = w.end; + try w.writeInt(u16, err_val, endian); + const unpadded_end = w.end - begin; const padded_end = abi_align.forward(unpadded_end); const padding = math.cast(usize, padded_end - unpadded_end) orelse return error.Overflow; if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); + try w.splatByteAll(0, padding); } } }, .enum_tag => |enum_tag| { const int_tag_ty = ty.intTagType(zcu); - try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, try pt.getCoerced(Value.fromInterned(enum_tag.int), int_tag_ty), w, reloc_parent); }, .float => |float| storage: switch (float.storage) { - .f16 => |f16_val| writeFloat(f16, f16_val, target, endian, try code.addManyAsArray(gpa, 2)), - .f32 => |f32_val| writeFloat(f32, f32_val, target, endian, try code.addManyAsArray(gpa, 4)), - .f64 => |f64_val| writeFloat(f64, f64_val, target, endian, try code.addManyAsArray(gpa, 8)), + .f16 => |f16_val| try w.writeInt(u16, @bitCast(f16_val), endian), + .f32 => |f32_val| try w.writeInt(u32, @bitCast(f32_val), endian), + .f64 => |f64_val| try w.writeInt(u64, @bitCast(f64_val), endian), .f80 => |f80_val| { - writeFloat(f80, f80_val, target, endian, try code.addManyAsArray(gpa, 10)); + try w.writeInt(u80, @bitCast(f80_val), endian); const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - try code.appendNTimes(gpa, 0, abi_size - 10); + try w.splatByteAll(0, abi_size - 10); }, .f128 => |f128_val| switch (Type.fromInterned(float.ty).floatBits(target)) { else => unreachable, 16 => continue :storage .{ .f16 = @floatCast(f128_val) }, 32 => continue :storage .{ .f32 = @floatCast(f128_val) }, 64 => continue :storage .{ .f64 = @floatCast(f128_val) }, - 128 => writeFloat(f128, f128_val, target, endian, try code.addManyAsArray(gpa, 16)), + 128 => try w.writeInt(u128, @bitCast(f128_val), endian), }, }, - .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), code, reloc_parent, 0), + .ptr => try lowerPtr(bin_file, pt, src_loc, val.toIntern(), w, reloc_parent, 0), .slice => |slice| { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), code, reloc_parent); - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.ptr), w, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(slice.len), w, reloc_parent); }, .opt => { const payload_type = ty.optionalChild(zcu); @@ -465,9 +453,9 @@ pub fn generateSymbol( if (ty.optionalReprIsPayload(zcu)) { if (payload_val) |value| { - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); } else { - try code.appendNTimes(gpa, 0, abi_size); + try w.splatByteAll(0, abi_size); } } else { const padding = abi_size - (math.cast(usize, payload_type.abiSize(zcu)) orelse return error.Overflow) - 1; @@ -475,15 +463,15 @@ pub fn generateSymbol( const value = payload_val orelse Value.fromInterned(try pt.intern(.{ .undef = payload_type.toIntern(), })); - try generateSymbol(bin_file, pt, src_loc, value, code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, value, w, reloc_parent); } - try code.append(gpa, @intFromBool(payload_val != null)); - try code.appendNTimes(gpa, 0, padding); + try w.writeByte(@intFromBool(payload_val != null)); + try w.splatByteAll(0, padding); } }, .aggregate => |aggregate| switch (ip.indexToKey(ty.toIntern())) { .array_type => |array_type| switch (aggregate.storage) { - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(array_type.lenIncludingSentinel(), ip)), + .bytes => |bytes| try w.writeAll(bytes.toSlice(array_type.lenIncludingSentinel(), ip)), .elems, .repeated_elem => { var index: u64 = 0; while (index < array_type.lenIncludingSentinel()) : (index += 1) { @@ -494,14 +482,14 @@ pub fn generateSymbol( elem else array_type.sentinel, - }), code, reloc_parent); + }), w, reloc_parent); } }, }, .vector_type => |vector_type| { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; if (vector_type.child == .bool_type) { - const bytes = try code.addManyAsSlice(gpa, abi_size); + const bytes = try w.writableSlice(abi_size); @memset(bytes, 0xaa); var index: usize = 0; const len = math.cast(usize, vector_type.len) orelse return error.Overflow; @@ -540,7 +528,7 @@ pub fn generateSymbol( } } else { switch (aggregate.storage) { - .bytes => |bytes| try code.appendSlice(gpa, bytes.toSlice(vector_type.len, ip)), + .bytes => |bytes| try w.writeAll(bytes.toSlice(vector_type.len, ip)), .elems, .repeated_elem => { var index: u64 = 0; while (index < vector_type.len) : (index += 1) { @@ -550,7 +538,7 @@ pub fn generateSymbol( math.cast(usize, index) orelse return error.Overflow ], .repeated_elem => |elem| elem, - }), code, reloc_parent); + }), w, reloc_parent); } }, } @@ -558,11 +546,11 @@ pub fn generateSymbol( const padding = abi_size - (math.cast(usize, Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len) orelse return error.Overflow); - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + if (padding > 0) try w.splatByteAll(0, padding); } }, .tuple_type => |tuple| { - const struct_begin = code.items.len; + const struct_begin = w.end; for ( tuple.types.get(ip), tuple.values.get(ip), @@ -580,8 +568,8 @@ pub fn generateSymbol( .repeated_elem => |elem| elem, }; - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); - const unpadded_field_end = code.items.len - struct_begin; + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); + const unpadded_field_end = w.end - struct_begin; // Pad struct members if required const padded_field_end = ty.structFieldOffset(index + 1, zcu); @@ -589,7 +577,7 @@ pub fn generateSymbol( return error.Overflow; if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); + try w.splatByteAll(0, padding); } } }, @@ -598,8 +586,9 @@ pub fn generateSymbol( switch (struct_type.layout) { .@"packed" => { const abi_size = math.cast(usize, ty.abiSize(zcu)) orelse return error.Overflow; - const current_pos = code.items.len; - try code.appendNTimes(gpa, 0, abi_size); + const start = w.end; + const buffer = try w.writableSlice(abi_size); + @memset(buffer, 0); var bits: u16 = 0; for (struct_type.field_types.get(ip), 0..) |field_ty, index| { @@ -619,22 +608,20 @@ pub fn generateSymbol( error.DivisionByZero => unreachable, error.UnexpectedRemainder => return error.RelocationNotByteAligned, }; - code.items.len = current_pos + field_offset; - // TODO: code.lockPointers(); + w.end = start + field_offset; defer { - assert(code.items.len == current_pos + field_offset + @divExact(target.ptrBitWidth(), 8)); - // TODO: code.unlockPointers(); - code.items.len = current_pos + abi_size; + assert(w.end == start + field_offset + @divExact(target.ptrBitWidth(), 8)); + w.end = start + abi_size; } - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); } else { - Value.fromInterned(field_val).writeToPackedMemory(Type.fromInterned(field_ty), pt, code.items[current_pos..], bits) catch unreachable; + Value.fromInterned(field_val).writeToPackedMemory(.fromInterned(field_ty), pt, buffer, bits) catch unreachable; } bits += @intCast(Type.fromInterned(field_ty).bitSize(zcu)); } }, .auto, .@"extern" => { - const struct_begin = code.items.len; + const struct_begin = w.end; const field_types = struct_type.field_types.get(ip); const offsets = struct_type.offsets.get(ip); @@ -654,11 +641,11 @@ pub fn generateSymbol( const padding = math.cast( usize, - offsets[field_index] - (code.items.len - struct_begin), + offsets[field_index] - (w.end - struct_begin), ) orelse return error.Overflow; - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + if (padding > 0) try w.splatByteAll(0, padding); - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(field_val), w, reloc_parent); } const size = struct_type.sizeUnordered(ip); @@ -666,10 +653,9 @@ pub fn generateSymbol( const padding = math.cast( usize, - std.mem.alignForward(u64, size, @max(alignment, 1)) - - (code.items.len - struct_begin), + std.mem.alignForward(u64, size, @max(alignment, 1)) - (w.end - struct_begin), ) orelse return error.Overflow; - if (padding > 0) try code.appendNTimes(gpa, 0, padding); + if (padding > 0) try w.splatByteAll(0, padding); }, } }, @@ -679,12 +665,12 @@ pub fn generateSymbol( const layout = ty.unionGetLayout(zcu); if (layout.payload_size == 0) { - return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); + return generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); } // Check if we should store the tag first. if (layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align)) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); } const union_obj = zcu.typeToUnion(ty).?; @@ -692,24 +678,24 @@ pub fn generateSymbol( const field_index = ty.unionTagFieldIndex(Value.fromInterned(un.tag), zcu).?; const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]); if (!field_ty.hasRuntimeBits(zcu)) { - try code.appendNTimes(gpa, 0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); + try w.splatByteAll(0xaa, math.cast(usize, layout.payload_size) orelse return error.Overflow); } else { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); const padding = math.cast(usize, layout.payload_size - field_ty.abiSize(zcu)) orelse return error.Overflow; if (padding > 0) { - try code.appendNTimes(gpa, 0, padding); + try w.splatByteAll(0, padding); } } } else { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.val), w, reloc_parent); } if (layout.tag_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) { - try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), code, reloc_parent); + try generateSymbol(bin_file, pt, src_loc, Value.fromInterned(un.tag), w, reloc_parent); if (layout.padding > 0) { - try code.appendNTimes(gpa, 0, layout.padding); + try w.splatByteAll(0, layout.padding); } } }, @@ -722,30 +708,30 @@ fn lowerPtr( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, ptr_val: InternPool.Index, - code: *ArrayList(u8), + w: *std.Io.Writer, reloc_parent: link.File.RelocInfo.Parent, prev_offset: u64, -) GenerateSymbolError!void { +) (GenerateSymbolError || std.Io.Writer.Error)!void { const zcu = pt.zcu; const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; const offset: u64 = prev_offset + ptr.byte_offset; return switch (ptr.base_addr) { - .nav => |nav| try lowerNavRef(bin_file, pt, nav, code, reloc_parent, offset), - .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, code, reloc_parent, offset), - .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), code, reloc_parent), + .nav => |nav| try lowerNavRef(bin_file, pt, nav, w, reloc_parent, offset), + .uav => |uav| try lowerUavRef(bin_file, pt, src_loc, uav, w, reloc_parent, offset), + .int => try generateSymbol(bin_file, pt, src_loc, try pt.intValue(Type.usize, offset), w, reloc_parent), .eu_payload => |eu_ptr| try lowerPtr( bin_file, pt, src_loc, eu_ptr, - code, + w, reloc_parent, offset + errUnionPayloadOffset( Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu).errorUnionPayload(zcu), zcu, ), ), - .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, code, reloc_parent, offset), + .opt_payload => |opt_ptr| try lowerPtr(bin_file, pt, src_loc, opt_ptr, w, reloc_parent, offset), .field => |field| { const base_ptr = Value.fromInterned(field.base); const base_ty = base_ptr.typeOf(zcu).childType(zcu); @@ -764,7 +750,7 @@ fn lowerPtr( }, else => unreachable, }; - return lowerPtr(bin_file, pt, src_loc, field.base, code, reloc_parent, offset + field_off); + return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off); }, .arr_elem, .comptime_field, .comptime_alloc => unreachable, }; @@ -775,12 +761,11 @@ fn lowerUavRef( pt: Zcu.PerThread, src_loc: Zcu.LazySrcLoc, uav: InternPool.Key.Ptr.BaseAddr.Uav, - code: *ArrayList(u8), + w: *std.Io.Writer, reloc_parent: link.File.RelocInfo.Parent, offset: u64, -) GenerateSymbolError!void { +) (GenerateSymbolError || std.Io.Writer.Error)!void { const zcu = pt.zcu; - const gpa = zcu.gpa; const ip = &zcu.intern_pool; const comp = lf.comp; const target = &comp.root_mod.resolved_target.result; @@ -790,10 +775,9 @@ fn lowerUavRef( const is_fn_body = uav_ty.zigTypeTag(zcu) == .@"fn"; log.debug("lowerUavRef: ty = {f}", .{uav_ty.fmt(pt)}); - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); if (!is_fn_body and !uav_ty.hasRuntimeBits(zcu)) { - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); + try w.splatByteAll(0xaa, ptr_width_bytes); return; } @@ -804,29 +788,32 @@ fn lowerUavRef( dev.check(link.File.Tag.wasm.devFeature()); const wasm = lf.cast(.wasm).?; assert(reloc_parent == .none); - try wasm.addUavReloc(code.items.len, uav.val, uav.orig_ty, @intCast(offset)); - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); + try wasm.addUavReloc(w.end, uav.val, uav.orig_ty, @intCast(offset)); + try w.splatByteAll(0, ptr_width_bytes); return; }, else => {}, } - const uav_align = ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment; + const uav_align = Type.fromInterned(uav.orig_ty).ptrAlignment(zcu); switch (try lf.lowerUav(pt, uav_val, uav_align, src_loc)) { .sym_index => {}, .fail => |em| std.debug.panic("TODO rework lowerUav. internal error: {s}", .{em.msg}), } - const vaddr = try lf.getUavVAddr(uav_val, .{ + const vaddr = lf.getUavVAddr(uav_val, .{ .parent = reloc_parent, - .offset = code.items.len, + .offset = w.end, .addend = @intCast(offset), - }); + }) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| std.debug.panic("TODO rework lowerUav. internal error: {t}", .{e}), + }; const endian = target.cpu.arch.endian(); switch (ptr_width_bytes) { - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), + 2 => try w.writeInt(u16, @intCast(vaddr), endian), + 4 => try w.writeInt(u32, @intCast(vaddr), endian), + 8 => try w.writeInt(u64, vaddr, endian), else => unreachable, } } @@ -835,10 +822,10 @@ fn lowerNavRef( lf: *link.File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, - code: *ArrayList(u8), + w: *std.Io.Writer, reloc_parent: link.File.RelocInfo.Parent, offset: u64, -) GenerateSymbolError!void { +) (GenerateSymbolError || std.Io.Writer.Error)!void { const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; @@ -848,10 +835,8 @@ fn lowerNavRef( const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip)); const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; - try code.ensureUnusedCapacity(gpa, ptr_width_bytes); - if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) { - code.appendNTimesAssumeCapacity(0xaa, ptr_width_bytes); + try w.splatByteAll(0xaa, ptr_width_bytes); return; } @@ -870,13 +855,13 @@ fn lowerNavRef( } else { try wasm.func_table_fixups.append(gpa, .{ .table_index = @enumFromInt(gop.index), - .offset = @intCast(code.items.len), + .offset = @intCast(w.end), }); } } else { if (is_obj) { try wasm.out_relocs.append(gpa, .{ - .offset = @intCast(code.items.len), + .offset = @intCast(w.end), .pointee = .{ .symbol_index = try wasm.navSymbolIndex(nav_index) }, .tag = if (ptr_width_bytes == 4) .memory_addr_i32 else .memory_addr_i64, .addend = @intCast(offset), @@ -885,12 +870,12 @@ fn lowerNavRef( try wasm.nav_fixups.ensureUnusedCapacity(gpa, 1); wasm.nav_fixups.appendAssumeCapacity(.{ .navs_exe_index = try wasm.refNavExe(nav_index), - .offset = @intCast(code.items.len), + .offset = @intCast(w.end), .addend = @intCast(offset), }); } } - code.appendNTimesAssumeCapacity(0, ptr_width_bytes); + try w.splatByteAll(0, ptr_width_bytes); return; }, else => {}, @@ -898,14 +883,14 @@ fn lowerNavRef( const vaddr = lf.getNavVAddr(pt, nav_index, .{ .parent = reloc_parent, - .offset = code.items.len, + .offset = w.end, .addend = @intCast(offset), }) catch @panic("TODO rework getNavVAddr"); const endian = target.cpu.arch.endian(); switch (ptr_width_bytes) { - 2 => mem.writeInt(u16, code.addManyAsArrayAssumeCapacity(2), @intCast(vaddr), endian), - 4 => mem.writeInt(u32, code.addManyAsArrayAssumeCapacity(4), @intCast(vaddr), endian), - 8 => mem.writeInt(u64, code.addManyAsArrayAssumeCapacity(8), vaddr, endian), + 2 => try w.writeInt(u16, @intCast(vaddr), endian), + 4 => try w.writeInt(u32, @intCast(vaddr), endian), + 8 => try w.writeInt(u64, vaddr, endian), else => unreachable, } } @@ -962,6 +947,16 @@ pub fn genNavRef( }, .link_once => unreachable, } + } else if (lf.cast(.elf2)) |elf| { + return .{ .sym_index = @intFromEnum(elf.navSymbol(zcu, nav_index) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => |e| return .{ .fail = try ErrorMsg.create( + zcu.gpa, + src_loc, + "linker failed to create a nav: {t}", + .{e}, + ) }, + }) }; } else if (lf.cast(.macho)) |macho_file| { const zo = macho_file.getZigObject().?; switch (linkage) { |
