authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 00:35:14+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
log601f2147e0344621d238e5209e0d36c69be3cc03
treef7addabfa5d2ae5575532d5957fd1aa6333b57f0
parentebdb2867363256a265646f2a1b66d3762a51b7ba

coff: cleanup relocations; remove COFF support from other backends

Given that COFF will want to support PIC from ground-up, there is no point in leaving outdated code for COFF in other backends such as arm or aarch64. Instead, when we are ready to look into those, we can start figuring out what to add and where.

8 files changed, 89 insertions(+), 88 deletions(-)

src/arch/aarch64/CodeGen.zig+7-11
......@@ -3466,20 +3466,16 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
34663466 // on linking.
34673467 const mod = self.bin_file.options.module.?;
34683468 if (self.air.value(callee)) |func_value| {
3469 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {
3469 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
34703470 if (func_value.castTag(.function)) |func_payload| {
34713471 const func = func_payload.data;
34723472 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
34733473 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
34743474 const fn_owner_decl = mod.declPtr(func.owner_decl);
3475 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
3475 const got_addr = blk: {
34763476 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
34773477 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
3478 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3479 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
3480 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
3481 break :blk got_sym.value;
3482 } else unreachable;
3478 };
34833479
34843480 try self.genSetReg(Type.initTag(.usize), .x30, .{ .memory = got_addr });
34853481
......@@ -3547,6 +3543,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
35473543 } else {
35483544 return self.fail("TODO implement calling bitcasted functions", .{});
35493545 }
3546 } else if (self.bin_file.cast(link.File.Coff)) |_| {
3547 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
35503548 } else unreachable;
35513549 } else {
35523550 assert(ty.zigTypeTag() == .Pointer);
......@@ -5110,10 +5108,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
51105108 // the linker has enough info to perform relocations.
51115109 assert(decl.link.macho.sym_index != 0);
51125110 return MCValue{ .got_load = decl.link.macho.sym_index };
5113 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5114 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;
5115 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
5116 return MCValue{ .memory = got_sym.value };
5111 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5112 return self.fail("TODO codegen COFF const Decl pointer", .{});
51175113 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
51185114 try p9.seeDecl(decl_index);
51195115 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/arm/CodeGen.zig+4-10
......@@ -3698,7 +3698,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
36983698 // Due to incremental compilation, how function calls are generated depends
36993699 // on linking.
37003700 switch (self.bin_file.tag) {
3701 .elf, .coff => {
3701 .elf => {
37023702 if (self.air.value(callee)) |func_value| {
37033703 if (func_value.castTag(.function)) |func_payload| {
37043704 const func = func_payload.data;
......@@ -3709,12 +3709,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
37093709 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
37103710 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
37113711 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
3712 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
3713 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
3714 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
3715 break :blk @intCast(u32, got_sym.value);
37163712 } else unreachable;
3717
37183713 try self.genSetReg(Type.initTag(.usize), .lr, .{ .memory = got_addr });
37193714 } else if (func_value.castTag(.extern_fn)) |_| {
37203715 return self.fail("TODO implement calling extern functions", .{});
......@@ -3752,6 +3747,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
37523747 }
37533748 },
37543749 .macho => unreachable, // unsupported architecture for MachO
3750 .coff => return self.fail("TODO implement call in COFF for {}", .{self.target.cpu.arch}),
37553751 .plan9 => return self.fail("TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
37563752 else => unreachable,
37573753 }
......@@ -5549,10 +5545,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
55495545 return MCValue{ .memory = got_addr };
55505546 } else if (self.bin_file.cast(link.File.MachO)) |_| {
55515547 unreachable; // unsupported architecture for MachO
5552 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
5553 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;
5554 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
5555 return MCValue{ .memory = got_sym.value };
5548 } else if (self.bin_file.cast(link.File.Coff)) |_| {
5549 return self.fail("TODO codegen COFF const Decl pointer", .{});
55565550 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
55575551 try p9.seeDecl(decl_index);
55585552 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/riscv64/CodeGen.zig+7-11
......@@ -1718,7 +1718,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17181718
17191719 // Due to incremental compilation, how function calls are generated depends
17201720 // on linking.
1721 if (self.bin_file.tag == link.File.Elf.base_tag or self.bin_file.tag == link.File.Coff.base_tag) {
1721 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
17221722 for (info.args) |mc_arg, arg_i| {
17231723 const arg = args[arg_i];
17241724 const arg_ty = self.air.typeOf(arg);
......@@ -1752,14 +1752,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17521752 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
17531753 const mod = self.bin_file.options.module.?;
17541754 const fn_owner_decl = mod.declPtr(func.owner_decl);
1755 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1755 const got_addr = blk: {
17561756 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
17571757 break :blk @intCast(u32, got.p_vaddr + fn_owner_decl.link.elf.offset_table_index * ptr_bytes);
1758 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
1759 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = fn_owner_decl.link.coff.sym_index, .file = null }).?;
1760 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
1761 break :blk got_sym.value;
1762 } else unreachable;
1758 };
17631759
17641760 try self.genSetReg(Type.initTag(.usize), .ra, .{ .memory = got_addr });
17651761 _ = try self.addInst(.{
......@@ -1778,6 +1774,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
17781774 } else {
17791775 return self.fail("TODO implement calling runtime known function pointer", .{});
17801776 }
1777 } else if (self.bin_file.cast(link.File.Coff)) |_| {
1778 return self.fail("TODO implement calling in COFF for {}", .{self.target.cpu.arch});
17811779 } else if (self.bin_file.cast(link.File.MachO)) |_| {
17821780 unreachable; // unsupported architecture for MachO
17831781 } else if (self.bin_file.cast(link.File.Plan9)) |_| {
......@@ -2592,10 +2590,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
25922590 // TODO I'm hacking my way through here by repurposing .memory for storing
25932591 // index to the GOT target symbol index.
25942592 return MCValue{ .memory = decl.link.macho.sym_index };
2595 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
2596 const got_atom = coff_file.getGotAtomForSymbol(.{ .sym_index = decl.link.coff.sym_index, .file = null }).?;
2597 const got_sym = coff_file.getSymbol(got_atom.getSymbolWithLoc());
2598 return MCValue{ .memory = got_sym.value };
2593 } else if (self.bin_file.cast(link.File.Coff)) |_| {
2594 return self.fail("TODO codegen COFF const Decl pointer", .{});
25992595 } else if (self.bin_file.cast(link.File.Plan9)) |p9| {
26002596 try p9.seeDecl(decl_index);
26012597 const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
src/arch/x86_64/CodeGen.zig+9-11
......@@ -2657,19 +2657,19 @@ fn loadMemPtrIntoRegister(self: *Self, reg: Register, ptr_ty: Type, ptr: MCValue
26572657 .direct_load,
26582658 => |sym_index| {
26592659 const abi_size = @intCast(u32, ptr_ty.abiSize(self.target.*));
2660 const flags: u2 = switch (ptr) {
2661 .got_load => 0b00,
2662 .direct_load => 0b01,
2663 else => unreachable,
2664 };
26652660 const mod = self.bin_file.options.module.?;
26662661 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
26672662 const atom_index = if (self.bin_file.tag == link.File.MachO.base_tag)
26682663 fn_owner_decl.link.macho.sym_index
26692664 else
26702665 fn_owner_decl.link.coff.sym_index;
2666 const flags: u2 = switch (ptr) {
2667 .got_load => 0b00,
2668 .direct_load => 0b01,
2669 else => unreachable,
2670 };
26712671 _ = try self.addInst(.{
2672 .tag = .lea_pie,
2672 .tag = .lea_pic,
26732673 .ops = Mir.Inst.Ops.encode(.{
26742674 .reg1 = registerAlias(reg, abi_size),
26752675 .flags = flags,
......@@ -4004,9 +4004,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
40044004 if (func_value.castTag(.function)) |func_payload| {
40054005 const func = func_payload.data;
40064006 const fn_owner_decl = mod.declPtr(func.owner_decl);
4007 const sym_index = fn_owner_decl.link.coff.sym_index;
4008 try self.genSetReg(Type.initTag(.usize), .rax, .{ .got_load = sym_index });
4009 // callq *%rax
4007 try self.genSetReg(Type.initTag(.usize), .rax, .{
4008 .got_load = fn_owner_decl.link.coff.sym_index,
4009 });
40104010 _ = try self.addInst(.{
40114011 .tag = .call,
40124012 .ops = Mir.Inst.Ops.encode(.{
......@@ -6876,8 +6876,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) Inne
68766876 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
68776877 return MCValue{ .memory = got_addr };
68786878 } else if (self.bin_file.cast(link.File.MachO)) |_| {
6879 // Because MachO is PIE-always-on, we defer memory address resolution until
6880 // the linker has enough info to perform relocations.
68816879 assert(decl.link.macho.sym_index != 0);
68826880 return MCValue{ .got_load = decl.link.macho.sym_index };
68836881 } else if (self.bin_file.cast(link.File.Coff)) |_| {
src/arch/x86_64/Emit.zig+17-18
......@@ -137,7 +137,7 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
137137 .fld => try emit.mirFld(inst),
138138
139139 .lea => try emit.mirLea(inst),
140 .lea_pie => try emit.mirLeaPie(inst),
140 .lea_pic => try emit.mirLeaPic(inst),
141141
142142 .shl => try emit.mirShift(.shl, inst),
143143 .sal => try emit.mirShift(.sal, inst),
......@@ -338,7 +338,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
338338 .base = ops.reg1,
339339 }), emit.code);
340340 },
341 0b11 => return emit.fail("TODO unused JMP/CALL variant 0b11", .{}),
341 0b11 => return emit.fail("TODO unused variant jmp/call 0b11", .{}),
342342 }
343343}
344344
......@@ -784,7 +784,7 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
784784 // FD
785785 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
786786 },
787 else => return emit.fail("TODO unused variant: movabs 0b{b}", .{ops.flags}),
787 else => return emit.fail("TODO unused movabs variant", .{}),
788788 }
789789}
790790
......@@ -978,12 +978,17 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
978978 }
979979}
980980
981fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
981fn mirLeaPic(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
982982 const tag = emit.mir.instructions.items(.tag)[inst];
983 assert(tag == .lea_pie);
983 assert(tag == .lea_pic);
984984 const ops = emit.mir.instructions.items(.ops)[inst].decode();
985985 const relocation = emit.mir.instructions.items(.data)[inst].relocation;
986986
987 switch (ops.flags) {
988 0b00, 0b01 => {},
989 else => return emit.fail("TODO unused LEA PIC variants 0b10 and 0b11", .{}),
990 }
991
987992 // lea reg1, [rip + reloc]
988993 // RM
989994 try lowerToRmEnc(
......@@ -1000,7 +1005,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
10001005 const reloc_type = switch (ops.flags) {
10011006 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
10021007 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
1003 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
1008 else => unreachable,
10041009 };
10051010 const atom = macho_file.atom_by_index_table.get(relocation.atom_index).?;
10061011 log.debug("adding reloc of type {} to local @{d}", .{ reloc_type, relocation.sym_index });
......@@ -1015,27 +1020,21 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
10151020 });
10161021 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
10171022 const atom = coff_file.atom_by_index_table.get(relocation.atom_index).?;
1018 log.debug("adding reloc to local @{d}", .{relocation.sym_index});
1019 const gop = try coff_file.relocs.getOrPut(gpa, atom);
1020 if (!gop.found_existing) {
1021 gop.value_ptr.* = .{};
1022 }
1023 try gop.value_ptr.append(gpa, .{
1023 try atom.addRelocation(coff_file, .{
10241024 .@"type" = switch (ops.flags) {
1025 0b00 => .got_pcrel,
1025 0b00 => .got,
10261026 0b01 => .direct,
1027 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
1027 else => unreachable,
10281028 },
10291029 .target = .{ .sym_index = relocation.sym_index, .file = null },
10301030 .offset = @intCast(u32, end_offset - 4),
10311031 .addend = 0,
1032 .pcrel = true,
1033 .length = 2,
10321034 .prev_vaddr = atom.getSymbol(coff_file).value,
10331035 });
10341036 } else {
1035 return emit.fail(
1036 "TODO implement lea reg, [rip + reloc] for linking backends different than MachO",
1037 .{},
1038 );
1037 return emit.fail("TODO implement lea reg, [rip + reloc] for linking backends different than MachO", .{});
10391038 }
10401039}
10411040
src/arch/x86_64/Mir.zig+6-7
......@@ -178,11 +178,11 @@ pub const Inst = struct {
178178 lea,
179179
180180 /// ops flags: form:
181 /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation
182 /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation
181 /// 0b00 reg1, [rip + reloc] // via GOT PIC
182 /// 0b01 reg1, [rip + reloc] // direct load PIC
183183 /// Notes:
184184 /// * `Data` contains `relocation`
185 lea_pie,
185 lea_pic,
186186
187187 /// ops flags: form:
188188 /// 0b00 reg1, 1
......@@ -242,15 +242,14 @@ pub const Inst = struct {
242242 imul_complex,
243243
244244 /// ops flags: form:
245 /// 0bX0 reg1, imm64
246 /// 0bX1 rax, moffs64
245 /// 0b00 reg1, imm64
246 /// 0b01 rax, moffs64
247247 /// Notes:
248248 /// * If reg1 is 64-bit, the immediate is 64-bit and stored
249249 /// within extra data `Imm64`.
250 /// * For 0bX1, reg1 (or reg2) need to be
250 /// * For 0b01, reg1 (or reg2) need to be
251251 /// a version of rax. If reg1 == .none, then reg2 == .rax,
252252 /// or vice versa.
253 /// TODO handle scaling
254253 movabs,
255254
256255 /// ops flags: form:
src/link/Coff.zig+27-20
......@@ -103,14 +103,16 @@ unnamed_const_atoms: UnnamedConstTable = .{},
103103/// this will be a table indexed by index into the list of Atoms.
104104relocs: RelocTable = .{},
105105
106const Reloc = struct {
106pub const Reloc = struct {
107107 @"type": enum {
108 got_pcrel,
108 got,
109109 direct,
110110 },
111111 target: SymbolWithLoc,
112112 offset: u32,
113113 addend: u32,
114 pcrel: bool,
115 length: u2,
114116 prev_vaddr: u32,
115117};
116118
......@@ -593,15 +595,13 @@ fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
593595
594596 log.debug("allocated GOT atom at 0x{x}", .{sym.value});
595597
596 const gop_relocs = try self.relocs.getOrPut(gpa, atom);
597 if (!gop_relocs.found_existing) {
598 gop_relocs.value_ptr.* = .{};
599 }
600 try gop_relocs.value_ptr.append(gpa, .{
598 try atom.addRelocation(self, .{
601599 .@"type" = .direct,
602600 .target = target,
603601 .offset = 0,
604602 .addend = 0,
603 .pcrel = false,
604 .length = 3,
605605 .prev_vaddr = sym.value,
606606 });
607607
......@@ -656,7 +656,7 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
656656
657657 for (relocs.items) |*reloc| {
658658 const target_vaddr = switch (reloc.@"type") {
659 .got_pcrel => blk: {
659 .got => blk: {
660660 const got_atom = self.getGotAtomForSymbol(reloc.target) orelse continue;
661661 break :blk got_atom.getSymbol(self).value;
662662 },
......@@ -673,21 +673,28 @@ fn resolveRelocs(self: *Coff, atom: *Atom) !void {
673673 @tagName(reloc.@"type"),
674674 });
675675
676 switch (reloc.@"type") {
677 .got_pcrel => {
678 const source_vaddr = source_sym.value + reloc.offset;
679 const disp = target_vaddr_with_addend - source_vaddr - 4;
680 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);
681 },
682 .direct => switch (self.ptr_width) {
683 .p32 => try self.base.file.?.pwriteAll(
684 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),
676 if (reloc.pcrel) {
677 const source_vaddr = source_sym.value + reloc.offset;
678 const disp = target_vaddr_with_addend - source_vaddr - 4;
679 try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, disp)), file_offset + reloc.offset);
680 return;
681 }
682
683 switch (self.ptr_width) {
684 .p32 => try self.base.file.?.pwriteAll(
685 mem.asBytes(&@intCast(u32, target_vaddr_with_addend + default_image_base_exe)),
686 file_offset + reloc.offset,
687 ),
688 .p64 => switch (reloc.length) {
689 2 => try self.base.file.?.pwriteAll(
690 mem.asBytes(&@truncate(u32, target_vaddr_with_addend + default_image_base_exe)),
685691 file_offset + reloc.offset,
686692 ),
687 .p64 => try self.base.file.?.pwriteAll(
693 3 => try self.base.file.?.pwriteAll(
688694 mem.asBytes(&(target_vaddr_with_addend + default_image_base_exe)),
689695 file_offset + reloc.offset,
690696 ),
697 else => unreachable,
691698 },
692699 }
693700
......@@ -1270,8 +1277,8 @@ fn writeHeader(self: *Coff) !void {
12701277 writer.writeAll(mem.asBytes(&coff_header)) catch unreachable;
12711278
12721279 const dll_flags: coff.DllFlags = .{
1273 .HIGH_ENTROPY_VA = 0, // TODO handle ASLR
1274 .DYNAMIC_BASE = 0, // TODO handle ASLR
1280 .HIGH_ENTROPY_VA = 0, //@boolToInt(self.base.options.pie),
1281 .DYNAMIC_BASE = 0,
12751282 .TERMINAL_SERVER_AWARE = 1, // We are not a legacy app
12761283 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
12771284 };
src/link/Coff/Atom.zig+12
......@@ -6,6 +6,7 @@ const coff = std.coff;
66const Allocator = std.mem.Allocator;
77
88const Coff = @import("../Coff.zig");
9const Reloc = Coff.Reloc;
910const SymbolWithLoc = Coff.SymbolWithLoc;
1011
1112/// Each decl always gets a local symbol with the fully qualified name.
......@@ -96,3 +97,14 @@ pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
9697 const surplus = cap - ideal_cap;
9798 return surplus >= Coff.min_text_capacity;
9899}
100
101pub fn addRelocation(self: *Atom, coff_file: *Coff, reloc: Reloc) !void {
102 const gpa = coff_file.base.allocator;
103 // TODO causes a segfault on Windows
104 // log.debug("adding reloc of type {s} to target %{d}", .{ @tagName(reloc.@"type"), reloc.target.sym_index });
105 const gop = try coff_file.relocs.getOrPut(gpa, self);
106 if (!gop.found_existing) {
107 gop.value_ptr.* = .{};
108 }
109 try gop.value_ptr.append(gpa, reloc);
110}