authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-28 16:10:02+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-08-30 10:42:21+02:00
loge5b8a1ac27367402c703a25774bc228499cfeb37
tree673ac4cad74ecb4dd3cfabd295870fe2ffed49db
parent2a994ba4a713f0bd469265ea3c55e335048d4c91

coff: allocate and write atoms to file


2 files changed, 347 insertions(+), 112 deletions(-)

src/link/Coff.zig+334-109
...@@ -23,6 +23,7 @@ const Compilation = @import("../Compilation.zig");...@@ -23,6 +23,7 @@ const Compilation = @import("../Compilation.zig");
23const Liveness = @import("../Liveness.zig");23const Liveness = @import("../Liveness.zig");
24const LlvmObject = @import("../codegen/llvm.zig").Object;24const LlvmObject = @import("../codegen/llvm.zig").Object;
25const Module = @import("../Module.zig");25const Module = @import("../Module.zig");
26const Object = @import("Coff/Object.zig");
26const StringTable = @import("strtab.zig").StringTable;27const StringTable = @import("strtab.zig").StringTable;
27const TypedValue = @import("../TypedValue.zig");28const TypedValue = @import("../TypedValue.zig");
2829
...@@ -39,6 +40,8 @@ error_flags: link.File.ErrorFlags = .{},...@@ -39,6 +40,8 @@ error_flags: link.File.ErrorFlags = .{},
39ptr_width: PtrWidth,40ptr_width: PtrWidth,
40page_size: u32,41page_size: u32,
4142
43objects: std.ArrayListUnmanaged(Object) = .{},
44
42sections: std.MultiArrayList(Section) = .{},45sections: std.MultiArrayList(Section) = .{},
43data_directories: [16]coff.ImageDataDirectory,46data_directories: [16]coff.ImageDataDirectory,
4447
...@@ -185,6 +188,11 @@ pub fn deinit(self: *Coff) void {...@@ -185,6 +188,11 @@ pub fn deinit(self: *Coff) void {
185 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);188 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
186 }189 }
187190
191 for (self.objects.items) |*object| {
192 object.deinit(gpa);
193 }
194 self.objects.deinit(gpa);
195
188 for (self.sections.items(.free_list)) |*free_list| {196 for (self.sections.items(.free_list)) |*free_list| {
189 free_list.deinit(gpa);197 free_list.deinit(gpa);
190 }198 }
...@@ -211,15 +219,15 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -211,15 +219,15 @@ fn populateMissingMetadata(self: *Coff) !void {
211219
212 if (self.text_section_index == null) {220 if (self.text_section_index == null) {
213 self.text_section_index = @intCast(u16, self.sections.slice().len);221 self.text_section_index = @intCast(u16, self.sections.slice().len);
214 const file_size = self.base.options.program_code_size_hint;222 const file_size = @intCast(u32, self.base.options.program_code_size_hint);
215 const off = self.findFreeSpace(file_size, self.page_size); // TODO we are over-aligning in file; we should track both in file and in memory pointers223 const off = self.findFreeSpace(file_size, self.page_size); // TODO we are over-aligning in file; we should track both in file and in memory pointers
216 log.debug("found .text free space 0x{x} to 0x{x}", .{ off, off + file_size });224 log.debug("found .text free space 0x{x} to 0x{x}", .{ off, off + file_size });
217 var header = coff.SectionHeader{225 var header = coff.SectionHeader{
218 .name = undefined,226 .name = undefined,
219 .virtual_size = @intCast(u32, file_size),227 .virtual_size = file_size,
220 .virtual_address = @intCast(u32, off),228 .virtual_address = off,
221 .size_of_raw_data = @intCast(u32, file_size),229 .size_of_raw_data = file_size,
222 .pointer_to_raw_data = @intCast(u32, off),230 .pointer_to_raw_data = off,
223 .pointer_to_relocations = 0,231 .pointer_to_relocations = 0,
224 .pointer_to_linenumbers = 0,232 .pointer_to_linenumbers = 0,
225 .number_of_relocations = 0,233 .number_of_relocations = 0,
...@@ -236,15 +244,15 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -236,15 +244,15 @@ fn populateMissingMetadata(self: *Coff) !void {
236244
237 if (self.pdata_section_index == null) {245 if (self.pdata_section_index == null) {
238 self.pdata_section_index = @intCast(u16, self.sections.slice().len);246 self.pdata_section_index = @intCast(u16, self.sections.slice().len);
239 const file_size = self.base.options.symbol_count_hint;247 const file_size = @intCast(u32, self.base.options.symbol_count_hint);
240 const off = self.findFreeSpace(file_size, self.page_size);248 const off = self.findFreeSpace(file_size, self.page_size);
241 log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });249 log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
242 var header = coff.SectionHeader{250 var header = coff.SectionHeader{
243 .name = undefined,251 .name = undefined,
244 .virtual_size = @intCast(u32, file_size),252 .virtual_size = file_size,
245 .virtual_address = @intCast(u32, off),253 .virtual_address = off,
246 .size_of_raw_data = @intCast(u32, file_size),254 .size_of_raw_data = file_size,
247 .pointer_to_raw_data = @intCast(u32, off),255 .pointer_to_raw_data = off,
248 .pointer_to_relocations = 0,256 .pointer_to_relocations = 0,
249 .pointer_to_linenumbers = 0,257 .pointer_to_linenumbers = 0,
250 .number_of_relocations = 0,258 .number_of_relocations = 0,
...@@ -260,15 +268,15 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -260,15 +268,15 @@ fn populateMissingMetadata(self: *Coff) !void {
260268
261 if (self.rdata_section_index == null) {269 if (self.rdata_section_index == null) {
262 self.rdata_section_index = @intCast(u16, self.sections.slice().len);270 self.rdata_section_index = @intCast(u16, self.sections.slice().len);
263 const file_size = 1024;271 const file_size: u32 = 1024;
264 const off = self.findFreeSpace(file_size, self.page_size);272 const off = self.findFreeSpace(file_size, self.page_size);
265 log.debug("found .rdata free space 0x{x} to 0x{x}", .{ off, off + file_size });273 log.debug("found .rdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
266 var header = coff.SectionHeader{274 var header = coff.SectionHeader{
267 .name = undefined,275 .name = undefined,
268 .virtual_size = @intCast(u32, file_size),276 .virtual_size = file_size,
269 .virtual_address = @intCast(u32, off),277 .virtual_address = off,
270 .size_of_raw_data = @intCast(u32, file_size),278 .size_of_raw_data = file_size,
271 .pointer_to_raw_data = @intCast(u32, off),279 .pointer_to_raw_data = off,
272 .pointer_to_relocations = 0,280 .pointer_to_relocations = 0,
273 .pointer_to_linenumbers = 0,281 .pointer_to_linenumbers = 0,
274 .number_of_relocations = 0,282 .number_of_relocations = 0,
...@@ -284,15 +292,15 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -284,15 +292,15 @@ fn populateMissingMetadata(self: *Coff) !void {
284292
285 if (self.data_section_index == null) {293 if (self.data_section_index == null) {
286 self.data_section_index = @intCast(u16, self.sections.slice().len);294 self.data_section_index = @intCast(u16, self.sections.slice().len);
287 const file_size = 1024;295 const file_size: u32 = 1024;
288 const off = self.findFreeSpace(file_size, self.page_size);296 const off = self.findFreeSpace(file_size, self.page_size);
289 log.debug("found .data free space 0x{x} to 0x{x}", .{ off, off + file_size });297 log.debug("found .data free space 0x{x} to 0x{x}", .{ off, off + file_size });
290 var header = coff.SectionHeader{298 var header = coff.SectionHeader{
291 .name = undefined,299 .name = undefined,
292 .virtual_size = @intCast(u32, file_size),300 .virtual_size = file_size,
293 .virtual_address = @intCast(u32, off),301 .virtual_address = off,
294 .size_of_raw_data = @intCast(u32, file_size),302 .size_of_raw_data = file_size,
295 .pointer_to_raw_data = @intCast(u32, off),303 .pointer_to_raw_data = off,
296 .pointer_to_relocations = 0,304 .pointer_to_relocations = 0,
297 .pointer_to_linenumbers = 0,305 .pointer_to_linenumbers = 0,
298 .number_of_relocations = 0,306 .number_of_relocations = 0,
...@@ -309,7 +317,7 @@ fn populateMissingMetadata(self: *Coff) !void {...@@ -309,7 +317,7 @@ fn populateMissingMetadata(self: *Coff) !void {
309317
310 if (self.strtab_offset == null) {318 if (self.strtab_offset == null) {
311 try self.strtab.buffer.append(gpa, 0);319 try self.strtab.buffer.append(gpa, 0);
312 self.strtab_offset = @intCast(u32, self.findFreeSpace(self.strtab.len(), 1));320 self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
313 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + self.strtab.len() });321 log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + self.strtab.len() });
314 }322 }
315323
...@@ -334,7 +342,7 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {...@@ -334,7 +342,7 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
334 try self.decls.putNoClobber(gpa, decl_index, null);342 try self.decls.putNoClobber(gpa, decl_index, null);
335}343}
336344
337fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {345fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
338 const tracy = trace(@src());346 const tracy = trace(@src());
339 defer tracy.end();347 defer tracy.end();
340348
...@@ -362,10 +370,10 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se...@@ -362,10 +370,10 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se
362 const sym = big_atom.getSymbol(self);370 const sym = big_atom.getSymbol(self);
363 const capacity = big_atom.capacity(self);371 const capacity = big_atom.capacity(self);
364 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;372 const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
365 const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;373 const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;
366 const capacity_end_vaddr = sym.n_value + capacity;374 const capacity_end_vaddr = sym.value + capacity;
367 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;375 const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
368 const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);376 const new_start_vaddr = mem.alignBackwardGeneric(u32, new_start_vaddr_unaligned, alignment);
369 if (new_start_vaddr < ideal_capacity_end_vaddr) {377 if (new_start_vaddr < ideal_capacity_end_vaddr) {
370 // Additional bookkeeping here to notice if this free list node378 // Additional bookkeeping here to notice if this free list node
371 // should be deleted because the atom that it points to has grown to take up379 // should be deleted because the atom that it points to has grown to take up
...@@ -392,23 +400,30 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se...@@ -392,23 +400,30 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se
392 } else if (maybe_last_atom.*) |last| {400 } else if (maybe_last_atom.*) |last| {
393 const last_symbol = last.getSymbol(self);401 const last_symbol = last.getSymbol(self);
394 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;402 const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
395 const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;403 const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
396 const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);404 const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
397 atom_placement = last;405 atom_placement = last;
398 break :blk new_start_vaddr;406 break :blk new_start_vaddr;
399 } else {407 } else {
400 break :blk mem.alignForwardGeneric(u64, header.addr, alignment);408 break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
401 }409 }
402 };410 };
403411
404 const expand_section = atom_placement == null or atom_placement.?.next == null;412 const expand_section = atom_placement == null or atom_placement.?.next == null;
405 if (expand_section) {413 if (expand_section) {
406 @panic("TODO expand section in allocateAtom");414 const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
415 const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
416 if (needed_size > sect_capacity) {
417 @panic("TODO move section");
418 }
419 maybe_last_atom.* = atom;
420 header.virtual_size = needed_size;
421 header.size_of_raw_data = needed_size;
407 }422 }
408423
409 if (header.getAlignment() < alignment) {424 // if (header.getAlignment().? < alignment) {
410 header.setAlignment(alignment);425 // header.setAlignment(alignment);
411 }426 // }
412 atom.size = new_atom_size;427 atom.size = new_atom_size;
413 atom.alignment = alignment;428 atom.alignment = alignment;
414429
...@@ -465,30 +480,39 @@ fn allocateSymbol(self: *Coff) !u32 {...@@ -465,30 +480,39 @@ fn allocateSymbol(self: *Coff) !u32 {
465pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {480pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
466 const gpa = self.base.allocator;481 const gpa = self.base.allocator;
467 try self.got_entries.ensureUnusedCapacity(gpa, 1);482 try self.got_entries.ensureUnusedCapacity(gpa, 1);
468 if (self.got_entries_free_list.popOrNull()) |index| {483 const index: u32 = blk: {
469 log.debug(" (reusing GOT entry index {d})", .{index});484 if (self.got_entries_free_list.popOrNull()) |index| {
470 if (self.got_entries.getIndex(target)) |existing| {485 log.debug(" (reusing GOT entry index {d})", .{index});
471 assert(existing == index);486 if (self.got_entries.getIndex(target)) |existing| {
487 assert(existing == index);
488 }
489 break :blk index;
490 } else {
491 log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});
492 const index = @intCast(u32, self.got_entries.keys().len);
493 self.got_entries.putAssumeCapacityNoClobber(target, 0);
494 break :blk index;
472 }495 }
473 self.got_entries.keys()[index] = target;496 };
474 return index;497 self.got_entries.keys()[index] = target;
475 } else {498 return index;
476 log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});499}
477 const index = @intCast(u32, self.got_entries.keys().len);500
478 try self.got_entries.putAssumeCapacityNoClobber(target, 0);501fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
479 return index;502 _ = self;
480 }503 _ = target;
504 @panic("TODO createGotAtom");
481}505}
482506
483fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {507fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
484 const sym = atom.getSymbol(self);508 const sym = atom.getSymbol(self);
485 const align_ok = mem.alignBackwardGeneric(u64, sym.value, alignment) == sym.value;509 const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
486 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);510 const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
487 if (!need_realloc) return sym.value;511 if (!need_realloc) return sym.value;
488 return self.allocateAtom(atom, new_atom_size, alignment, sect_id);512 return self.allocateAtom(atom, new_atom_size, alignment, sect_id);
489}513}
490514
491fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void {515fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32, sect_id: u16) void {
492 _ = self;516 _ = self;
493 _ = atom;517 _ = atom;
494 _ = new_block_size;518 _ = new_block_size;
...@@ -497,6 +521,22 @@ fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void...@@ -497,6 +521,22 @@ fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void
497 // capacity, insert a free list node for it.521 // capacity, insert a free list node for it.
498}522}
499523
524fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void {
525 const section = self.sections.get(sect_id);
526 const sym = atom.getSymbol(self);
527 const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
528 try self.resolveRelocs(atom, code);
529 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
530 try self.base.file.?.pwriteAll(code, file_offset);
531}
532
533fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) !void {
534 _ = self;
535 _ = atom;
536 _ = code;
537 log.debug("TODO resolveRelocs", .{});
538}
539
500fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {540fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {
501 log.debug("freeAtom {*}", .{atom});541 log.debug("freeAtom {*}", .{atom});
502542
...@@ -583,8 +623,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -583,8 +623,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
583 },623 },
584 };624 };
585625
586 const sym = try self.updateDeclCode(decl_index, code);626 try self.updateDeclCode(decl_index, code);
587 log.debug("updated decl code has sym {}", .{sym});
588627
589 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.628 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
590 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};629 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
...@@ -640,20 +679,104 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !...@@ -640,20 +679,104 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
640 },679 },
641 };680 };
642681
643 const sym = try self.updateDeclCode(decl_index, code);682 try self.updateDeclCode(decl_index, code);
644 log.debug("updated decl code for {}", .{sym});
645683
646 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.684 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
647 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};685 const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
648 return self.updateDeclExports(module, decl_index, decl_exports);686 return self.updateDeclExports(module, decl_index, decl_exports);
649}687}
650688
651fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !*coff.Symbol {689fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
652 _ = self;690 const ty = decl.ty;
653 _ = decl_index;691 const zig_ty = ty.zigTypeTag();
654 _ = code;692 const val = decl.val;
655 log.debug("TODO updateDeclCode", .{});693 const index: u16 = blk: {
656 return &self.locals.items[0];694 if (val.isUndefDeep()) {
695 // TODO in release-fast and release-small, we should put undef in .bss
696 break :blk self.data_section_index.?;
697 }
698
699 switch (zig_ty) {
700 .Fn => break :blk self.text_section_index.?,
701 else => {
702 if (val.castTag(.variable)) |_| {
703 break :blk self.data_section_index.?;
704 }
705 break :blk self.rdata_section_index.?;
706 },
707 }
708 };
709 return index;
710}
711
712fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !void {
713 const gpa = self.base.allocator;
714 const mod = self.base.options.module.?;
715 const decl = mod.declPtr(decl_index);
716
717 const decl_name = try decl.getFullyQualifiedName(mod);
718 defer gpa.free(decl_name);
719
720 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
721 const required_alignment = decl.getAlignment(self.base.options.target);
722
723 const decl_ptr = self.decls.getPtr(decl_index).?;
724 if (decl_ptr.* == null) {
725 decl_ptr.* = self.getDeclOutputSection(decl);
726 }
727 const sect_index = decl_ptr.*.?;
728
729 const code_len = @intCast(u32, code.len);
730 const atom = &decl.link.coff;
731 assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes()
732 if (atom.size != 0) {
733 const sym = atom.getSymbolPtr(self);
734 const capacity = atom.capacity(self);
735 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
736
737 if (need_realloc) {
738 const vaddr = try self.growAtom(atom, code_len, required_alignment, sect_index);
739 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
740 log.debug(" (required alignment 0x{x}", .{required_alignment});
741
742 if (vaddr != sym.value) {
743 sym.value = vaddr;
744 log.debug(" (updating GOT entry)", .{});
745 var buffer: [@sizeOf(u64)]u8 = undefined;
746 const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?;
747 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
748 }
749 } else if (code_len < atom.size) {
750 self.shrinkAtom(atom, code_len, sect_index);
751 }
752 atom.size = code_len;
753 try self.setSymbolName(sym, decl_name);
754 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
755 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
756 sym.storage_class = .NULL;
757 } else {
758 const sym = atom.getSymbolPtr(self);
759 try self.setSymbolName(sym, decl_name);
760 const vaddr = try self.allocateAtom(atom, code_len, required_alignment, sect_index);
761 errdefer self.freeAtom(atom, sect_index);
762
763 log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
764
765 atom.size = code_len;
766 sym.value = vaddr;
767 sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
768 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
769 sym.storage_class = .NULL;
770
771 const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
772 _ = try self.allocateGotEntry(got_target);
773 const got_atom = try self.createGotAtom(got_target);
774
775 var buffer: [@sizeOf(u64)]u8 = undefined;
776 try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
777 }
778
779 try self.writeAtom(atom, code, sect_index);
657}780}
658781
659pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {782pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
...@@ -701,40 +824,142 @@ pub fn updateDeclExports(...@@ -701,40 +824,142 @@ pub fn updateDeclExports(
701 @panic("Attempted to compile for object format that was disabled by build configuration");824 @panic("Attempted to compile for object format that was disabled by build configuration");
702 }825 }
703826
704 // Even in the case of LLVM, we need to notice certain exported symbols in order to827 if (build_options.have_llvm) {
705 // detect the default subsystem.828 // Even in the case of LLVM, we need to notice certain exported symbols in order to
829 // detect the default subsystem.
830 for (exports) |exp| {
831 const exported_decl = module.declPtr(exp.exported_decl);
832 if (exported_decl.getFunction() == null) continue;
833 const winapi_cc = switch (self.base.options.target.cpu.arch) {
834 .i386 => std.builtin.CallingConvention.Stdcall,
835 else => std.builtin.CallingConvention.C,
836 };
837 const decl_cc = exported_decl.ty.fnCallingConvention();
838 if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and
839 self.base.options.link_libc)
840 {
841 module.stage1_flags.have_c_main = true;
842 } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {
843 if (mem.eql(u8, exp.options.name, "WinMain")) {
844 module.stage1_flags.have_winmain = true;
845 } else if (mem.eql(u8, exp.options.name, "wWinMain")) {
846 module.stage1_flags.have_wwinmain = true;
847 } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
848 module.stage1_flags.have_winmain_crt_startup = true;
849 } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
850 module.stage1_flags.have_wwinmain_crt_startup = true;
851 } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
852 module.stage1_flags.have_dllmain_crt_startup = true;
853 }
854 }
855 }
856
857 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
858 }
859
860 const tracy = trace(@src());
861 defer tracy.end();
862
863 const gpa = self.base.allocator;
864
865 const decl = module.declPtr(decl_index);
866 const atom = &decl.link.coff;
867 if (atom.sym_index == 0) return;
868 const decl_sym = atom.getSymbol(self);
869
706 for (exports) |exp| {870 for (exports) |exp| {
707 const exported_decl = module.declPtr(exp.exported_decl);871 log.debug("adding new export '{s}'", .{exp.options.name});
708 if (exported_decl.getFunction() == null) continue;872
709 const winapi_cc = switch (self.base.options.target.cpu.arch) {873 if (exp.options.section) |section_name| {
710 .i386 => std.builtin.CallingConvention.Stdcall,874 if (!mem.eql(u8, section_name, ".text")) {
711 else => std.builtin.CallingConvention.C,875 try module.failed_exports.putNoClobber(
712 };876 module.gpa,
713 const decl_cc = exported_decl.ty.fnCallingConvention();877 exp,
714 if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and878 try Module.ErrorMsg.create(
715 self.base.options.link_libc)879 gpa,
716 {880 decl.srcLoc(),
717 module.stage1_flags.have_c_main = true;881 "Unimplemented: ExportOptions.section",
718 } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {882 .{},
719 if (mem.eql(u8, exp.options.name, "WinMain")) {883 ),
720 module.stage1_flags.have_winmain = true;884 );
721 } else if (mem.eql(u8, exp.options.name, "wWinMain")) {885 continue;
722 module.stage1_flags.have_wwinmain = true;
723 } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
724 module.stage1_flags.have_winmain_crt_startup = true;
725 } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
726 module.stage1_flags.have_wwinmain_crt_startup = true;
727 } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
728 module.stage1_flags.have_dllmain_crt_startup = true;
729 }886 }
730 }887 }
888
889 if (exp.options.linkage == .LinkOnce) {
890 try module.failed_exports.putNoClobber(
891 module.gpa,
892 exp,
893 try Module.ErrorMsg.create(
894 gpa,
895 decl.srcLoc(),
896 "Unimplemented: GlobalLinkage.LinkOnce",
897 .{},
898 ),
899 );
900 continue;
901 }
902
903 const sym_index = exp.link.macho.sym_index orelse blk: {
904 const sym_index = try self.allocateSymbol();
905 exp.link.coff.sym_index = sym_index;
906 break :blk sym_index;
907 };
908 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
909 const sym = self.getSymbolPtr(sym_loc);
910 try self.setSymbolName(sym, exp.options.name);
911 sym.value = decl_sym.value;
912 sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1);
913 sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
914
915 switch (exp.options.linkage) {
916 .Strong => {
917 sym.storage_class = .EXTERNAL;
918 },
919 .Internal => @panic("TODO Internal"),
920 .Weak => @panic("TODO WeakExternal"),
921 else => unreachable,
922 }
923
924 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
925 error.MultipleSymbolDefinitions => {
926 const global = self.globals.get(exp.options.name).?;
927 if (sym_loc.sym_index != global.sym_index and global.file != null) {
928 _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
929 gpa,
930 decl.srcLoc(),
931 \\LinkError: symbol '{s}' defined multiple times
932 \\ first definition in '{s}'
933 ,
934 .{ exp.options.name, self.objects.items[global.file.?].name },
935 ));
936 }
937 },
938 else => |e| return e,
939 };
731 }940 }
941}
732942
733 if (build_options.have_llvm) {943fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
734 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);944 const gpa = self.base.allocator;
945 const sym = self.getSymbol(current);
946 _ = sym;
947 const sym_name = self.getSymbolName(current);
948
949 const name = try gpa.dupe(u8, sym_name);
950 const global_index = @intCast(u32, self.globals.values().len);
951 _ = global_index;
952 const gop = try self.globals.getOrPut(gpa, name);
953 defer if (gop.found_existing) gpa.free(name);
954
955 if (!gop.found_existing) {
956 gop.value_ptr.* = current;
957 // TODO undef + tentative
958 return;
735 }959 }
736960
737 log.debug("TODO updateDeclExports", .{});961 log.debug("TODO finish resolveGlobalSymbols implementation", .{});
962 return error.MultipleSymbolDefinitions;
738}963}
739964
740pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {965pub fn flush(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Node) !void {
...@@ -805,7 +1030,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v...@@ -805,7 +1030,7 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
8051030
806fn writeStrtab(self: *Coff) !void {1031fn writeStrtab(self: *Coff) !void {
807 const allocated_size = self.allocatedSize(self.strtab_offset.?);1032 const allocated_size = self.allocatedSize(self.strtab_offset.?);
808 const needed_size = self.strtab.len();1033 const needed_size = @intCast(u32, self.strtab.len());
8091034
810 if (needed_size > allocated_size) {1035 if (needed_size > allocated_size) {
811 self.strtab_offset = null;1036 self.strtab_offset = null;
...@@ -870,7 +1095,7 @@ fn writeHeader(self: *Coff) !void {...@@ -870,7 +1095,7 @@ fn writeHeader(self: *Coff) !void {
870 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention1095 .NX_COMPAT = 1, // We are compatible with Data Execution Prevention
871 };1096 };
872 const subsystem: coff.Subsystem = .WINDOWS_CUI;1097 const subsystem: coff.Subsystem = .WINDOWS_CUI;
873 const size_of_headers: u32 = @intCast(u32, self.getSizeOfHeaders());1098 const size_of_headers: u32 = self.getSizeOfHeaders();
874 const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, self.page_size);1099 const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, self.page_size);
875 const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment);1100 const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment);
876 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {1101 const image_base = self.base.options.image_base_override orelse switch (self.base.options.output_mode) {
...@@ -968,7 +1193,7 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -968,7 +1193,7 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
968 math.maxInt(@TypeOf(actual_size));1193 math.maxInt(@TypeOf(actual_size));
969}1194}
9701195
971fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {1196fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
972 const headers_size = self.getSizeOfHeaders();1197 const headers_size = self.getSizeOfHeaders();
973 if (start < headers_size)1198 if (start < headers_size)
974 return headers_size;1199 return headers_size;
...@@ -976,7 +1201,7 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {...@@ -976,7 +1201,7 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
976 const end = start + padToIdeal(size);1201 const end = start + padToIdeal(size);
9771202
978 if (self.strtab_offset) |off| {1203 if (self.strtab_offset) |off| {
979 const increased_size = padToIdeal(self.strtab.len());1204 const increased_size = padToIdeal(@intCast(u32, self.strtab.len()));
980 const test_end = off + increased_size;1205 const test_end = off + increased_size;
981 if (end > off and start < test_end) {1206 if (end > off and start < test_end) {
982 return test_end;1207 return test_end;
...@@ -994,10 +1219,10 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {...@@ -994,10 +1219,10 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
994 return null;1219 return null;
995}1220}
9961221
997pub fn allocatedSize(self: *Coff, start: u64) u64 {1222pub fn allocatedSize(self: *Coff, start: u32) u32 {
998 if (start == 0)1223 if (start == 0)
999 return 0;1224 return 0;
1000 var min_pos: u64 = std.math.maxInt(u64);1225 var min_pos: u32 = std.math.maxInt(u32);
1001 if (self.strtab_offset) |off| {1226 if (self.strtab_offset) |off| {
1002 if (off > start and off < min_pos) min_pos = off;1227 if (off > start and off < min_pos) min_pos = off;
1003 }1228 }
...@@ -1008,41 +1233,41 @@ pub fn allocatedSize(self: *Coff, start: u64) u64 {...@@ -1008,41 +1233,41 @@ pub fn allocatedSize(self: *Coff, start: u64) u64 {
1008 return min_pos - start;1233 return min_pos - start;
1009}1234}
10101235
1011pub fn findFreeSpace(self: *Coff, object_size: u64, min_alignment: u32) u64 {1236pub fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 {
1012 var start: u64 = 0;1237 var start: u32 = 0;
1013 while (self.detectAllocCollision(start, object_size)) |item_end| {1238 while (self.detectAllocCollision(start, object_size)) |item_end| {
1014 start = mem.alignForwardGeneric(u64, item_end, min_alignment);1239 start = mem.alignForwardGeneric(u32, item_end, min_alignment);
1015 }1240 }
1016 return start;1241 return start;
1017}1242}
10181243
1019inline fn getSizeOfHeaders(self: Coff) usize {1244inline fn getSizeOfHeaders(self: Coff) u32 {
1020 const msdos_hdr_size = msdos_stub.len + 8;1245 const msdos_hdr_size = msdos_stub.len + 8;
1021 return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +1246 return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
1022 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize();1247 self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize());
1023}1248}
10241249
1025inline fn getOptionalHeaderSize(self: Coff) usize {1250inline fn getOptionalHeaderSize(self: Coff) u32 {
1026 return switch (self.ptr_width) {1251 return switch (self.ptr_width) {
1027 .p32 => @sizeOf(coff.OptionalHeaderPE32),1252 .p32 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE32)),
1028 .p64 => @sizeOf(coff.OptionalHeaderPE64),1253 .p64 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE64)),
1029 };1254 };
1030}1255}
10311256
1032inline fn getDataDirectoryHeadersSize(self: Coff) usize {1257inline fn getDataDirectoryHeadersSize(self: Coff) u32 {
1033 return self.data_directories.len * @sizeOf(coff.ImageDataDirectory);1258 return @intCast(u32, self.data_directories.len * @sizeOf(coff.ImageDataDirectory));
1034}1259}
10351260
1036inline fn getSectionHeadersSize(self: Coff) usize {1261inline fn getSectionHeadersSize(self: Coff) u32 {
1037 return self.sections.slice().len * @sizeOf(coff.SectionHeader);1262 return @intCast(u32, self.sections.slice().len * @sizeOf(coff.SectionHeader));
1038}1263}
10391264
1040inline fn getDataDirectoryHeadersOffset(self: Coff) usize {1265inline fn getDataDirectoryHeadersOffset(self: Coff) u32 {
1041 const msdos_hdr_size = msdos_stub.len + 8;1266 const msdos_hdr_size = msdos_stub.len + 8;
1042 return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize();1267 return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize());
1043}1268}
10441269
1045inline fn getSectionHeadersOffset(self: Coff) usize {1270inline fn getSectionHeadersOffset(self: Coff) u32 {
1046 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();1271 return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();
1047}1272}
10481273
...@@ -1086,7 +1311,7 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v...@@ -1086,7 +1311,7 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v
1086 return;1311 return;
1087 }1312 }
1088 const offset = try self.strtab.insert(self.base.allocator, name);1313 const offset = try self.strtab.insert(self.base.allocator, name);
1089 const name_offset = try fmt.bufPrint(&header.name, "/{d}", .{offset});1314 const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
1090 mem.set(u8, header.name[name_offset.len..], 0);1315 mem.set(u8, header.name[name_offset.len..], 0);
1091}1316}
10921317
...@@ -1097,6 +1322,6 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {...@@ -1097,6 +1322,6 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
1097 return;1322 return;
1098 }1323 }
1099 const offset = try self.strtab.insert(self.base.allocator, name);1324 const offset = try self.strtab.insert(self.base.allocator, name);
1100 mem.copy(u8, symbol.name[0..4], 0);1325 mem.set(u8, symbol.name[0..4], 0);
1101 _ = try fmt.bufPrint(symbol.name[4..], "{d}", .{offset});1326 _ = fmt.bufPrint(symbol.name[4..], "{d}", .{offset}) catch unreachable;
1102}1327}
src/link/Coff/Atom.zig+13-3
...@@ -20,7 +20,7 @@ sym_index: u32,...@@ -20,7 +20,7 @@ sym_index: u32,
20file: ?u32,20file: ?u32,
2121
22/// Used size of the atom22/// Used size of the atom
23size: u64,23size: u32,
2424
25/// Alignment of the atom25/// Alignment of the atom
26alignment: u32,26alignment: u32,
...@@ -44,10 +44,12 @@ pub fn deinit(self: *Atom, gpa: Allocator) void {...@@ -44,10 +44,12 @@ pub fn deinit(self: *Atom, gpa: Allocator) void {
44 _ = gpa;44 _ = gpa;
45}45}
4646
47/// Returns symbol referencing this atom.
47pub fn getSymbol(self: Atom, coff_file: *Coff) coff.Symbol {48pub fn getSymbol(self: Atom, coff_file: *Coff) coff.Symbol {
48 return self.getSymbolPtr(coff_file).*;49 return self.getSymbolPtr(coff_file).*;
49}50}
5051
52/// Returns pointer-to-symbol referencing this atom.
51pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {53pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
52 return coff_file.getSymbolPtr(.{54 return coff_file.getSymbolPtr(.{
53 .sym_index = self.sym_index,55 .sym_index = self.sym_index,
...@@ -59,8 +61,16 @@ pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {...@@ -59,8 +61,16 @@ pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
59 return .{ .sym_index = self.sym_index, .file = self.file };61 return .{ .sym_index = self.sym_index, .file = self.file };
60}62}
6163
64/// Returns the name of this atom.
65pub fn getName(self: Atom, coff_file: *Coff) []const u8 {
66 return coff_file.getSymbolName(.{
67 .sym_index = self.sym_index,
68 .file = self.file,
69 });
70}
71
62/// Returns how much room there is to grow in virtual address space.72/// Returns how much room there is to grow in virtual address space.
63pub fn capacity(self: Atom, coff_file: *Coff) u64 {73pub fn capacity(self: Atom, coff_file: *Coff) u32 {
64 const self_sym = self.getSymbol(coff_file);74 const self_sym = self.getSymbol(coff_file);
65 if (self.next) |next| {75 if (self.next) |next| {
66 const next_sym = next.getSymbol(coff_file);76 const next_sym = next.getSymbol(coff_file);
...@@ -68,7 +78,7 @@ pub fn capacity(self: Atom, coff_file: *Coff) u64 {...@@ -68,7 +78,7 @@ pub fn capacity(self: Atom, coff_file: *Coff) u64 {
68 } else {78 } else {
69 // We are the last atom.79 // We are the last atom.
70 // The capacity is limited only by virtual address space.80 // The capacity is limited only by virtual address space.
71 return std.math.maxInt(u64) - self_sym.value;81 return std.math.maxInt(u32) - self_sym.value;
72 }82 }
73}83}
7484