authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-29 09:21:52+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-29 09:21:52+02:00
log46b2f1f705bec886ffb8b0473e0ce43c74145a8d
tree0b542353cbe2c5aa438c605832838179e3f46281
parentdd66e0addb30d795a04324096c913ca89ccbcf40
parent17ec2cea6455148526f56fa17cb704fd1d656b06
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15105 from ziglang/hcs-win-poc

coff: improve handling of relocs and general linker fixes

8 files changed, 134 insertions(+), 185 deletions(-)

src/link.zig+2
...@@ -395,6 +395,7 @@ pub const File = struct {...@@ -395,6 +395,7 @@ pub const File = struct {
395 .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {395 .macos => base.cast(MachO).?.ptraceAttach(pid) catch |err| {
396 log.warn("attaching failed with error: {s}", .{@errorName(err)});396 log.warn("attaching failed with error: {s}", .{@errorName(err)});
397 },397 },
398 .windows => {},
398 else => return error.HotSwapUnavailableOnHostOperatingSystem,399 else => return error.HotSwapUnavailableOnHostOperatingSystem,
399 }400 }
400 }401 }
...@@ -436,6 +437,7 @@ pub const File = struct {...@@ -436,6 +437,7 @@ pub const File = struct {
436 .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {437 .macos => base.cast(MachO).?.ptraceDetach(pid) catch |err| {
437 log.warn("detaching failed with error: {s}", .{@errorName(err)});438 log.warn("detaching failed with error: {s}", .{@errorName(err)});
438 },439 },
440 .windows => {},
439 else => return error.HotSwapUnavailableOnHostOperatingSystem,441 else => return error.HotSwapUnavailableOnHostOperatingSystem,
440 }442 }
441 }443 }
src/link/Coff.zig+98-115
...@@ -49,11 +49,8 @@ imports_count_dirty: bool = true,...@@ -49,11 +49,8 @@ imports_count_dirty: bool = true,
49/// Virtual address of the entry point procedure relative to image base.49/// Virtual address of the entry point procedure relative to image base.
50entry_addr: ?u32 = null,50entry_addr: ?u32 = null,
5151
52/// Table of Decls that are currently alive.52/// Table of tracked Decls.
53/// We store them here so that we can properly dispose of any allocated53decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
54/// memory within the atom in the incremental linker.
55/// TODO consolidate this.
56decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
5754
58/// List of atoms that are either synthetic or map directly to the Zig source program.55/// List of atoms that are either synthetic or map directly to the Zig source program.
59atoms: std.ArrayListUnmanaged(Atom) = .{},56atoms: std.ArrayListUnmanaged(Atom) = .{},
...@@ -98,9 +95,9 @@ const Entry = struct {...@@ -98,9 +95,9 @@ const Entry = struct {
98 sym_index: u32,95 sym_index: u32,
99};96};
10097
101const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));98const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
102const BaseRelocationTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));99const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
103const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));100const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
104101
105const default_file_alignment: u16 = 0x200;102const default_file_alignment: u16 = 0x200;
106const default_size_of_stack_reserve: u32 = 0x1000000;103const default_size_of_stack_reserve: u32 = 0x1000000;
...@@ -137,6 +134,10 @@ const DeclMetadata = struct {...@@ -137,6 +134,10 @@ const DeclMetadata = struct {
137 /// A list of all exports aliases of this Decl.134 /// A list of all exports aliases of this Decl.
138 exports: std.ArrayListUnmanaged(u32) = .{},135 exports: std.ArrayListUnmanaged(u32) = .{},
139136
137 fn deinit(m: *DeclMetadata, allocator: Allocator) void {
138 m.exports.deinit(allocator);
139 }
140
140 fn getExport(m: DeclMetadata, coff_file: *const Coff, name: []const u8) ?u32 {141 fn getExport(m: DeclMetadata, coff_file: *const Coff, name: []const u8) ?u32 {
141 for (m.exports.items) |exp| {142 for (m.exports.items) |exp| {
142 if (mem.eql(u8, name, coff_file.getSymbolName(.{143 if (mem.eql(u8, name, coff_file.getSymbolName(.{
...@@ -293,39 +294,27 @@ pub fn deinit(self: *Coff) void {...@@ -293,39 +294,27 @@ pub fn deinit(self: *Coff) void {
293 }294 }
294 self.import_tables.deinit(gpa);295 self.import_tables.deinit(gpa);
295296
296 {297 for (self.decls.values()) |*metadata| {
297 var it = self.decls.iterator();298 metadata.deinit(gpa);
298 while (it.next()) |entry| {
299 entry.value_ptr.exports.deinit(gpa);
300 }
301 self.decls.deinit(gpa);
302 }299 }
300 self.decls.deinit(gpa);
303301
304 self.atom_by_index_table.deinit(gpa);302 self.atom_by_index_table.deinit(gpa);
305303
306 {304 for (self.unnamed_const_atoms.values()) |*atoms| {
307 var it = self.unnamed_const_atoms.valueIterator();305 atoms.deinit(gpa);
308 while (it.next()) |atoms| {
309 atoms.deinit(gpa);
310 }
311 self.unnamed_const_atoms.deinit(gpa);
312 }306 }
307 self.unnamed_const_atoms.deinit(gpa);
313308
314 {309 for (self.relocs.values()) |*relocs| {
315 var it = self.relocs.valueIterator();310 relocs.deinit(gpa);
316 while (it.next()) |relocs| {
317 relocs.deinit(gpa);
318 }
319 self.relocs.deinit(gpa);
320 }311 }
312 self.relocs.deinit(gpa);
321313
322 {314 for (self.base_relocs.values()) |*relocs| {
323 var it = self.base_relocs.valueIterator();315 relocs.deinit(gpa);
324 while (it.next()) |relocs| {
325 relocs.deinit(gpa);
326 }
327 self.base_relocs.deinit(gpa);
328 }316 }
317 self.base_relocs.deinit(gpa);
329}318}
330319
331fn populateMissingMetadata(self: *Coff) !void {320fn populateMissingMetadata(self: *Coff) !void {
...@@ -455,7 +444,44 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section...@@ -455,7 +444,44 @@ fn allocateSection(self: *Coff, name: []const u8, size: u32, flags: coff.Section
455 return index;444 return index;
456}445}
457446
458fn growSectionVM(self: *Coff, sect_id: u32, needed_size: u32) !void {447fn growSection(self: *Coff, sect_id: u32, needed_size: u32) !void {
448 const header = &self.sections.items(.header)[sect_id];
449 const maybe_last_atom_index = self.sections.items(.last_atom_index)[sect_id];
450 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
451
452 if (needed_size > sect_capacity) {
453 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
454 const current_size = if (maybe_last_atom_index) |last_atom_index| blk: {
455 const last_atom = self.getAtom(last_atom_index);
456 const sym = last_atom.getSymbol(self);
457 break :blk (sym.value + last_atom.size) - header.virtual_address;
458 } else 0;
459 log.debug("moving {s} from 0x{x} to 0x{x}", .{
460 self.getSectionName(header),
461 header.pointer_to_raw_data,
462 new_offset,
463 });
464 const amt = try self.base.file.?.copyRangeAll(
465 header.pointer_to_raw_data,
466 self.base.file.?,
467 new_offset,
468 current_size,
469 );
470 if (amt != current_size) return error.InputOutput;
471 header.pointer_to_raw_data = new_offset;
472 }
473
474 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
475 if (needed_size > sect_vm_capacity) {
476 try self.growSectionVirtualMemory(sect_id, needed_size);
477 self.markRelocsDirtyByAddress(header.virtual_address + needed_size);
478 }
479
480 header.virtual_size = @max(header.virtual_size, needed_size);
481 header.size_of_raw_data = needed_size;
482}
483
484fn growSectionVirtualMemory(self: *Coff, sect_id: u32, needed_size: u32) !void {
459 const header = &self.sections.items(.header)[sect_id];485 const header = &self.sections.items(.header)[sect_id];
460 const increased_size = padToIdeal(needed_size);486 const increased_size = padToIdeal(needed_size);
461 const old_aligned_end = header.virtual_address + mem.alignForwardGeneric(u32, header.virtual_size, self.page_size);487 const old_aligned_end = header.virtual_address + mem.alignForwardGeneric(u32, header.virtual_size, self.page_size);
...@@ -562,38 +588,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme...@@ -562,38 +588,8 @@ fn allocateAtom(self: *Coff, atom_index: Atom.Index, new_atom_size: u32, alignme
562 else588 else
563 true;589 true;
564 if (expand_section) {590 if (expand_section) {
565 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
566 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;591 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
567 if (needed_size > sect_capacity) {592 try self.growSection(sect_id, needed_size);
568 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
569 const current_size = if (maybe_last_atom_index.*) |last_atom_index| blk: {
570 const last_atom = self.getAtom(last_atom_index);
571 const sym = last_atom.getSymbol(self);
572 break :blk (sym.value + last_atom.size) - header.virtual_address;
573 } else 0;
574 log.debug("moving {s} from 0x{x} to 0x{x}", .{
575 self.getSectionName(header),
576 header.pointer_to_raw_data,
577 new_offset,
578 });
579 const amt = try self.base.file.?.copyRangeAll(
580 header.pointer_to_raw_data,
581 self.base.file.?,
582 new_offset,
583 current_size,
584 );
585 if (amt != current_size) return error.InputOutput;
586 header.pointer_to_raw_data = new_offset;
587 }
588
589 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
590 if (needed_size > sect_vm_capacity) {
591 try self.growSectionVM(sect_id, needed_size);
592 self.markRelocsDirtyByAddress(header.virtual_address + needed_size);
593 }
594
595 header.virtual_size = @max(header.virtual_size, needed_size);
596 header.size_of_raw_data = needed_size;
597 maybe_last_atom_index.* = atom_index;593 maybe_last_atom_index.* = atom_index;
598 }594 }
599595
...@@ -771,7 +767,7 @@ fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {...@@ -771,7 +767,7 @@ fn shrinkAtom(self: *Coff, atom_index: Atom.Index, new_block_size: u32) void {
771 // capacity, insert a free list node for it.767 // capacity, insert a free list node for it.
772}768}
773769
774fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {770fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []u8) !void {
775 const atom = self.getAtom(atom_index);771 const atom = self.getAtom(atom_index);
776 const sym = atom.getSymbol(self);772 const sym = atom.getSymbol(self);
777 const section = self.sections.get(@enumToInt(sym.section_number) - 1);773 const section = self.sections.get(@enumToInt(sym.section_number) - 1);
...@@ -781,8 +777,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {...@@ -781,8 +777,8 @@ fn writeAtom(self: *Coff, atom_index: Atom.Index, code: []const u8) !void {
781 file_offset,777 file_offset,
782 file_offset + code.len,778 file_offset + code.len,
783 });779 });
780 self.resolveRelocs(atom_index, code);
784 try self.base.file.?.pwriteAll(code, file_offset);781 try self.base.file.?.pwriteAll(code, file_offset);
785 try self.resolveRelocs(atom_index);
786}782}
787783
788fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {784fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
...@@ -800,8 +796,7 @@ fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {...@@ -800,8 +796,7 @@ fn writePtrWidthAtom(self: *Coff, atom_index: Atom.Index) !void {
800796
801fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {797fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
802 // TODO: reverse-lookup might come in handy here798 // TODO: reverse-lookup might come in handy here
803 var it = self.relocs.valueIterator();799 for (self.relocs.values()) |*relocs| {
804 while (it.next()) |relocs| {
805 for (relocs.items) |*reloc| {800 for (relocs.items) |*reloc| {
806 if (!reloc.target.eql(target)) continue;801 if (!reloc.target.eql(target)) continue;
807 reloc.dirty = true;802 reloc.dirty = true;
...@@ -810,8 +805,7 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {...@@ -810,8 +805,7 @@ fn markRelocsDirtyByTarget(self: *Coff, target: SymbolWithLoc) void {
810}805}
811806
812fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {807fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
813 var it = self.relocs.valueIterator();808 for (self.relocs.values()) |*relocs| {
814 while (it.next()) |relocs| {
815 for (relocs.items) |*reloc| {809 for (relocs.items) |*reloc| {
816 const target_vaddr = reloc.getTargetAddress(self) orelse continue;810 const target_vaddr = reloc.getTargetAddress(self) orelse continue;
817 if (target_vaddr < addr) continue;811 if (target_vaddr < addr) continue;
...@@ -820,14 +814,16 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {...@@ -820,14 +814,16 @@ fn markRelocsDirtyByAddress(self: *Coff, addr: u32) void {
820 }814 }
821}815}
822816
823fn resolveRelocs(self: *Coff, atom_index: Atom.Index) !void {817fn resolveRelocs(self: *Coff, atom_index: Atom.Index, code: []u8) void {
824 const relocs = self.relocs.get(atom_index) orelse return;818 const relocs = self.relocs.getPtr(atom_index) orelse return;
825819
826 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});820 log.debug("relocating '{s}'", .{self.getAtom(atom_index).getName(self)});
827821
828 for (relocs.items) |*reloc| {822 for (relocs.items) |*reloc| {
829 if (!reloc.dirty) continue;823 if (!reloc.dirty) continue;
830 try reloc.resolve(atom_index, self);824 if (reloc.resolve(atom_index, code, self)) {
825 reloc.dirty = false;
826 }
831 }827 }
832}828}
833829
...@@ -944,7 +940,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -944,7 +940,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
944 &code_buffer,940 &code_buffer,
945 .none,941 .none,
946 );942 );
947 const code = switch (res) {943 var code = switch (res) {
948 .ok => code_buffer.items,944 .ok => code_buffer.items,
949 .fail => |em| {945 .fail => |em| {
950 decl.analysis = .codegen_failure;946 decl.analysis = .codegen_failure;
...@@ -994,7 +990,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -994,7 +990,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
994 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{990 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), tv, &code_buffer, .none, .{
995 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,991 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
996 });992 });
997 const code = switch (res) {993 var code = switch (res) {
998 .ok => code_buffer.items,994 .ok => code_buffer.items,
999 .fail => |em| {995 .fail => |em| {
1000 decl.analysis = .codegen_failure;996 decl.analysis = .codegen_failure;
...@@ -1057,7 +1053,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -1057,7 +1053,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
1057 }, &code_buffer, .none, .{1053 }, &code_buffer, .none, .{
1058 .parent_atom_index = atom.getSymbolIndex().?,1054 .parent_atom_index = atom.getSymbolIndex().?,
1059 });1055 });
1060 const code = switch (res) {1056 var code = switch (res) {
1061 .ok => code_buffer.items,1057 .ok => code_buffer.items,
1062 .fail => |em| {1058 .fail => |em| {
1063 decl.analysis = .codegen_failure;1059 decl.analysis = .codegen_failure;
...@@ -1110,7 +1106,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {...@@ -1110,7 +1106,7 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 {
1110 return index;1106 return index;
1111}1107}
11121108
1113fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8, complex_type: coff.ComplexType) !void {1109fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void {
1114 const gpa = self.base.allocator;1110 const gpa = self.base.allocator;
1115 const mod = self.base.options.module.?;1111 const mod = self.base.options.module.?;
1116 const decl = mod.declPtr(decl_index);1112 const decl = mod.declPtr(decl_index);
...@@ -1195,7 +1191,7 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {...@@ -1195,7 +1191,7 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
11951191
1196 log.debug("freeDecl {*}", .{decl});1192 log.debug("freeDecl {*}", .{decl});
11971193
1198 if (self.decls.fetchRemove(decl_index)) |const_kv| {1194 if (self.decls.fetchOrderedRemove(decl_index)) |const_kv| {
1199 var kv = const_kv;1195 var kv = const_kv;
1200 self.freeAtom(kv.value.atom);1196 self.freeAtom(kv.value.atom);
1201 self.freeUnnamedConsts(decl_index);1197 self.freeUnnamedConsts(decl_index);
...@@ -1422,12 +1418,29 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1422,12 +1418,29 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1422 }1418 }
14231419
1424 try self.writeImportTables();1420 try self.writeImportTables();
1425 {1421
1426 var it = self.relocs.keyIterator();1422 for (self.relocs.keys(), self.relocs.values()) |atom_index, relocs| {
1427 while (it.next()) |atom| {1423 const needs_update = for (relocs.items) |reloc| {
1428 try self.resolveRelocs(atom.*);1424 if (reloc.dirty) break true;
1429 }1425 } else false;
1426
1427 if (!needs_update) continue;
1428
1429 const atom = self.getAtom(atom_index);
1430 const sym = atom.getSymbol(self);
1431 const section = self.sections.get(@enumToInt(sym.section_number) - 1).header;
1432 const file_offset = section.pointer_to_raw_data + sym.value - section.virtual_address;
1433
1434 var code = std.ArrayList(u8).init(gpa);
1435 defer code.deinit();
1436 try code.resize(math.cast(usize, atom.size) orelse return error.Overflow);
1437
1438 const amt = try self.base.file.?.preadAll(code.items, file_offset);
1439 if (amt != code.items.len) return error.InputOutput;
1440
1441 try self.writeAtom(atom_index, code.items);
1430 }1442 }
1443
1431 try self.writeBaseRelocations();1444 try self.writeBaseRelocations();
14321445
1433 if (self.getEntryPoint()) |entry_sym_loc| {1446 if (self.getEntryPoint()) |entry_sym_loc| {
...@@ -1576,25 +1589,8 @@ fn writeBaseRelocations(self: *Coff) !void {...@@ -1576,25 +1589,8 @@ fn writeBaseRelocations(self: *Coff) !void {
1576 }1589 }
15771590
1578 const header = &self.sections.items(.header)[self.reloc_section_index.?];1591 const header = &self.sections.items(.header)[self.reloc_section_index.?];
1579 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
1580 const needed_size = @intCast(u32, buffer.items.len);1592 const needed_size = @intCast(u32, buffer.items.len);
1581 if (needed_size > sect_capacity) {1593 try self.growSection(self.reloc_section_index.?, needed_size);
1582 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
1583 log.debug("moving {s} from 0x{x} to 0x{x}", .{
1584 self.getSectionName(header),
1585 header.pointer_to_raw_data,
1586 new_offset,
1587 });
1588 header.pointer_to_raw_data = new_offset;
1589
1590 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
1591 if (needed_size > sect_vm_capacity) {
1592 // TODO: we want to enforce .reloc after every alloc section.
1593 try self.growSectionVM(self.reloc_section_index.?, needed_size);
1594 }
1595 }
1596 header.virtual_size = @max(header.virtual_size, needed_size);
1597 header.size_of_raw_data = needed_size;
15981594
1599 try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);1595 try self.base.file.?.pwriteAll(buffer.items, header.pointer_to_raw_data);
16001596
...@@ -1633,20 +1629,7 @@ fn writeImportTables(self: *Coff) !void {...@@ -1633,20 +1629,7 @@ fn writeImportTables(self: *Coff) !void {
1633 }1629 }
16341630
1635 const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size;1631 const needed_size = iat_size + dir_table_size + lookup_table_size + names_table_size + dll_names_size;
1636 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);1632 try self.growSection(self.idata_section_index.?, needed_size);
1637 if (needed_size > sect_capacity) {
1638 const new_offset = self.findFreeSpace(needed_size, default_file_alignment);
1639 log.debug("moving .idata from 0x{x} to 0x{x}", .{ header.pointer_to_raw_data, new_offset });
1640 header.pointer_to_raw_data = new_offset;
1641
1642 const sect_vm_capacity = self.allocatedVirtualSize(header.virtual_address);
1643 if (needed_size > sect_vm_capacity) {
1644 try self.growSectionVM(self.idata_section_index.?, needed_size);
1645 }
1646
1647 header.virtual_size = @max(header.virtual_size, needed_size);
1648 header.size_of_raw_data = needed_size;
1649 }
16501633
1651 // Do the actual writes1634 // Do the actual writes
1652 var buffer = std.ArrayList(u8).init(gpa);1635 var buffer = std.ArrayList(u8).init(gpa);
src/link/Coff/Atom.zig+2-2
...@@ -121,8 +121,8 @@ pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void...@@ -121,8 +121,8 @@ pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void
121121
122pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void {122pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void {
123 const gpa = coff_file.base.allocator;123 const gpa = coff_file.base.allocator;
124 var removed_relocs = coff_file.relocs.fetchRemove(atom_index);124 var removed_relocs = coff_file.relocs.fetchOrderedRemove(atom_index);
125 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);125 if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
126 var removed_base_relocs = coff_file.base_relocs.fetchRemove(atom_index);126 var removed_base_relocs = coff_file.base_relocs.fetchOrderedRemove(atom_index);
127 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);127 if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);
128}128}
src/link/Coff/ImportTable.zig+1-1
...@@ -121,7 +121,7 @@ pub fn fmtDebug(itab: ImportTable, ctx: Context) std.fmt.Formatter(fmt) {...@@ -121,7 +121,7 @@ pub fn fmtDebug(itab: ImportTable, ctx: Context) std.fmt.Formatter(fmt) {
121 return .{ .data = .{ .itab = itab, .ctx = ctx } };121 return .{ .data = .{ .itab = itab, .ctx = ctx } };
122}122}
123123
124const ImportIndex = u32;124pub const ImportIndex = u32;
125const ImportTable = @This();125const ImportTable = @This();
126126
127const std = @import("std");127const std = @import("std");
src/link/Coff/Relocation.zig+23-49
...@@ -72,62 +72,50 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {...@@ -72,62 +72,50 @@ pub fn getTargetAddress(self: Relocation, coff_file: *const Coff) ?u32 {
72 }72 }
73}73}
7474
75pub fn resolve(self: *Relocation, atom_index: Atom.Index, coff_file: *Coff) !void {75/// Returns `false` if obtaining the target address has been deferred until `flushModule`.
76/// This can happen when trying to resolve address of an import table entry ahead of time.
77pub fn resolve(self: Relocation, atom_index: Atom.Index, code: []u8, coff_file: *Coff) bool {
76 const atom = coff_file.getAtom(atom_index);78 const atom = coff_file.getAtom(atom_index);
77 const source_sym = atom.getSymbol(coff_file);79 const source_sym = atom.getSymbol(coff_file);
78 const source_section = coff_file.sections.get(@enumToInt(source_sym.section_number) - 1).header;
79 const source_vaddr = source_sym.value + self.offset;80 const source_vaddr = source_sym.value + self.offset;
8081
81 const file_offset = source_section.pointer_to_raw_data + source_sym.value - source_section.virtual_address;82 const target_vaddr = self.getTargetAddress(coff_file) orelse return false;
82
83 const target_vaddr = self.getTargetAddress(coff_file) orelse return;
84 const target_vaddr_with_addend = target_vaddr + self.addend;83 const target_vaddr_with_addend = target_vaddr + self.addend;
8584
86 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{85 log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) ", .{
87 source_vaddr,86 source_vaddr,
88 target_vaddr_with_addend,87 target_vaddr_with_addend,
89 coff_file.getSymbolName(self.target),88 coff_file.getSymbolName(self.target),
90 @tagName(self.type),89 @tagName(self.type),
91 file_offset + self.offset,
92 });90 });
9391
94 const ctx: Context = .{92 const ctx: Context = .{
95 .source_vaddr = source_vaddr,93 .source_vaddr = source_vaddr,
96 .target_vaddr = target_vaddr_with_addend,94 .target_vaddr = target_vaddr_with_addend,
97 .file_offset = file_offset,
98 .image_base = coff_file.getImageBase(),95 .image_base = coff_file.getImageBase(),
96 .code = code,
97 .ptr_width = coff_file.ptr_width,
99 };98 };
10099
101 switch (coff_file.base.options.target.cpu.arch) {100 switch (coff_file.base.options.target.cpu.arch) {
102 .aarch64 => try self.resolveAarch64(ctx, coff_file),101 .aarch64 => self.resolveAarch64(ctx),
103 .x86, .x86_64 => try self.resolveX86(ctx, coff_file),102 .x86, .x86_64 => self.resolveX86(ctx),
104 else => unreachable, // unhandled target architecture103 else => unreachable, // unhandled target architecture
105 }104 }
106105
107 self.dirty = false;106 return true;
108}107}
109108
110const Context = struct {109const Context = struct {
111 source_vaddr: u32,110 source_vaddr: u32,
112 target_vaddr: u32,111 target_vaddr: u32,
113 file_offset: u32,
114 image_base: u64,112 image_base: u64,
113 code: []u8,
114 ptr_width: Coff.PtrWidth,
115};115};
116116
117fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {117fn resolveAarch64(self: Relocation, ctx: Context) void {
118 var buffer: [@sizeOf(u64)]u8 = undefined;118 var buffer = ctx.code[self.offset..];
119 switch (self.length) {
120 2 => {
121 const amt = try coff_file.base.file.?.preadAll(buffer[0..4], ctx.file_offset + self.offset);
122 if (amt != 4) return error.InputOutput;
123 },
124 3 => {
125 const amt = try coff_file.base.file.?.preadAll(&buffer, ctx.file_offset + self.offset);
126 if (amt != 8) return error.InputOutput;
127 },
128 else => unreachable,
129 }
130
131 switch (self.type) {119 switch (self.type) {
132 .got_page, .import_page, .page => {120 .got_page, .import_page, .page => {
133 const source_page = @intCast(i32, ctx.source_vaddr >> 12);121 const source_page = @intCast(i32, ctx.source_vaddr >> 12);
...@@ -188,7 +176,7 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -188,7 +176,7 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
188 buffer[0..4],176 buffer[0..4],
189 @truncate(u32, ctx.target_vaddr + ctx.image_base),177 @truncate(u32, ctx.target_vaddr + ctx.image_base),
190 ),178 ),
191 3 => mem.writeIntLittle(u64, &buffer, ctx.target_vaddr + ctx.image_base),179 3 => mem.writeIntLittle(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base),
192 else => unreachable,180 else => unreachable,
193 }181 }
194 },182 },
...@@ -196,15 +184,10 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -196,15 +184,10 @@ fn resolveAarch64(self: Relocation, ctx: Context, coff_file: *Coff) !void {
196 .got => unreachable,184 .got => unreachable,
197 .import => unreachable,185 .import => unreachable,
198 }186 }
199
200 switch (self.length) {
201 2 => try coff_file.base.file.?.pwriteAll(buffer[0..4], ctx.file_offset + self.offset),
202 3 => try coff_file.base.file.?.pwriteAll(&buffer, ctx.file_offset + self.offset),
203 else => unreachable,
204 }
205}187}
206188
207fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {189fn resolveX86(self: Relocation, ctx: Context) void {
190 var buffer = ctx.code[self.offset..];
208 switch (self.type) {191 switch (self.type) {
209 .got_page => unreachable,192 .got_page => unreachable,
210 .got_pageoff => unreachable,193 .got_pageoff => unreachable,
...@@ -216,26 +199,17 @@ fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {...@@ -216,26 +199,17 @@ fn resolveX86(self: Relocation, ctx: Context, coff_file: *Coff) !void {
216 .got, .import => {199 .got, .import => {
217 assert(self.pcrel);200 assert(self.pcrel);
218 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;201 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;
219 try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset);202 mem.writeIntLittle(i32, buffer[0..4], disp);
220 },203 },
221 .direct => {204 .direct => {
222 if (self.pcrel) {205 if (self.pcrel) {
223 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;206 const disp = @intCast(i32, ctx.target_vaddr) - @intCast(i32, ctx.source_vaddr) - 4;
224 try coff_file.base.file.?.pwriteAll(mem.asBytes(&disp), ctx.file_offset + self.offset);207 mem.writeIntLittle(i32, buffer[0..4], disp);
225 } else switch (coff_file.ptr_width) {208 } else switch (ctx.ptr_width) {
226 .p32 => try coff_file.base.file.?.pwriteAll(209 .p32 => mem.writeIntLittle(u32, buffer[0..4], @intCast(u32, ctx.target_vaddr + ctx.image_base)),
227 mem.asBytes(&@intCast(u32, ctx.target_vaddr + ctx.image_base)),
228 ctx.file_offset + self.offset,
229 ),
230 .p64 => switch (self.length) {210 .p64 => switch (self.length) {
231 2 => try coff_file.base.file.?.pwriteAll(211 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, ctx.target_vaddr + ctx.image_base)),
232 mem.asBytes(&@truncate(u32, ctx.target_vaddr + ctx.image_base)),212 3 => mem.writeIntLittle(u64, buffer[0..8], ctx.target_vaddr + ctx.image_base),
233 ctx.file_offset + self.offset,
234 ),
235 3 => try coff_file.base.file.?.pwriteAll(
236 mem.asBytes(&(ctx.target_vaddr + ctx.image_base)),
237 ctx.file_offset + self.offset,
238 ),
239 else => unreachable,213 else => unreachable,
240 },214 },
241 }215 }
src/link/MachO.zig+1-1
...@@ -1091,7 +1091,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {...@@ -1091,7 +1091,7 @@ pub fn writeAtom(self: *MachO, atom_index: Atom.Index, code: []u8) !void {
1091 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });1091 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
10921092
1093 if (self.relocs.get(atom_index)) |relocs| {1093 if (self.relocs.get(atom_index)) |relocs| {
1094 try Atom.resolveRelocations(self, atom_index, relocs.items, code);1094 Atom.resolveRelocations(self, atom_index, relocs.items, code);
1095 }1095 }
10961096
1097 if (is_hot_update_compatible) {1097 if (is_hot_update_compatible) {
src/link/MachO/Atom.zig+2-2
...@@ -183,11 +183,11 @@ pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !...@@ -183,11 +183,11 @@ pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !
183 try gop.value_ptr.append(gpa, binding);183 try gop.value_ptr.append(gpa, binding);
184}184}
185185
186pub fn resolveRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation, code: []u8) !void {186pub fn resolveRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation, code: []u8) void {
187 log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});187 log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});
188 for (relocs) |*reloc| {188 for (relocs) |*reloc| {
189 if (!reloc.dirty) continue;189 if (!reloc.dirty) continue;
190 try reloc.resolve(macho_file, atom_index, code);190 reloc.resolve(macho_file, atom_index, code);
191 reloc.dirty = false;191 reloc.dirty = false;
192 }192 }
193}193}
src/link/MachO/Relocation.zig+5-15
...@@ -50,7 +50,7 @@ pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {...@@ -50,7 +50,7 @@ pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
50 return macho_file.getAtomIndexForSymbol(self.target);50 return macho_file.getAtomIndexForSymbol(self.target);
51}51}
5252
53pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) !void {53pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, code: []u8) void {
54 const arch = macho_file.base.options.target.cpu.arch;54 const arch = macho_file.base.options.target.cpu.arch;
55 const atom = macho_file.getAtom(atom_index);55 const atom = macho_file.getAtom(atom_index);
56 const source_sym = atom.getSymbol(macho_file);56 const source_sym = atom.getSymbol(macho_file);
...@@ -68,18 +68,13 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -68,18 +68,13 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
68 });68 });
6969
70 switch (arch) {70 switch (arch) {
71 .aarch64 => return self.resolveAarch64(source_addr, target_addr, code),71 .aarch64 => self.resolveAarch64(source_addr, target_addr, code),
72 .x86_64 => return self.resolveX8664(source_addr, target_addr, code),72 .x86_64 => self.resolveX8664(source_addr, target_addr, code),
73 else => unreachable,73 else => unreachable,
74 }74 }
75}75}
7676
77fn resolveAarch64(77fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
78 self: Relocation,
79 source_addr: u64,
80 target_addr: i64,
81 code: []u8,
82) !void {
83 const rel_type = @intToEnum(macho.reloc_type_arm64, self.type);78 const rel_type = @intToEnum(macho.reloc_type_arm64, self.type);
84 if (rel_type == .ARM64_RELOC_UNSIGNED) {79 if (rel_type == .ARM64_RELOC_UNSIGNED) {
85 return switch (self.length) {80 return switch (self.length) {
...@@ -212,12 +207,7 @@ fn resolveAarch64(...@@ -212,12 +207,7 @@ fn resolveAarch64(
212 }207 }
213}208}
214209
215fn resolveX8664(210fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
216 self: Relocation,
217 source_addr: u64,
218 target_addr: i64,
219 code: []u8,
220) !void {
221 const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type);211 const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type);
222 switch (rel_type) {212 switch (rel_type) {
223 .X86_64_RELOC_BRANCH,213 .X86_64_RELOC_BRANCH,