Commit e5b8a1ac27
src/link/Coff/Atom.zig
@@ -20,7 +20,7 @@ sym_index: u32,
file: ?u32,
/// Used size of the atom
-size: u64,
+size: u32,
/// Alignment of the atom
alignment: u32,
@@ -44,10 +44,12 @@ pub fn deinit(self: *Atom, gpa: Allocator) void {
_ = gpa;
}
+/// Returns symbol referencing this atom.
pub fn getSymbol(self: Atom, coff_file: *Coff) coff.Symbol {
return self.getSymbolPtr(coff_file).*;
}
+/// Returns pointer-to-symbol referencing this atom.
pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
return coff_file.getSymbolPtr(.{
.sym_index = self.sym_index,
@@ -59,8 +61,16 @@ pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
return .{ .sym_index = self.sym_index, .file = self.file };
}
+/// Returns the name of this atom.
+pub fn getName(self: Atom, coff_file: *Coff) []const u8 {
+ return coff_file.getSymbolName(.{
+ .sym_index = self.sym_index,
+ .file = self.file,
+ });
+}
+
/// Returns how much room there is to grow in virtual address space.
-pub fn capacity(self: Atom, coff_file: *Coff) u64 {
+pub fn capacity(self: Atom, coff_file: *Coff) u32 {
const self_sym = self.getSymbol(coff_file);
if (self.next) |next| {
const next_sym = next.getSymbol(coff_file);
@@ -68,7 +78,7 @@ pub fn capacity(self: Atom, coff_file: *Coff) u64 {
} else {
// We are the last atom.
// The capacity is limited only by virtual address space.
- return std.math.maxInt(u64) - self_sym.value;
+ return std.math.maxInt(u32) - self_sym.value;
}
}
src/link/Coff.zig
@@ -23,6 +23,7 @@ const Compilation = @import("../Compilation.zig");
const Liveness = @import("../Liveness.zig");
const LlvmObject = @import("../codegen/llvm.zig").Object;
const Module = @import("../Module.zig");
+const Object = @import("Coff/Object.zig");
const StringTable = @import("strtab.zig").StringTable;
const TypedValue = @import("../TypedValue.zig");
@@ -39,6 +40,8 @@ error_flags: link.File.ErrorFlags = .{},
ptr_width: PtrWidth,
page_size: u32,
+objects: std.ArrayListUnmanaged(Object) = .{},
+
sections: std.MultiArrayList(Section) = .{},
data_directories: [16]coff.ImageDataDirectory,
@@ -185,6 +188,11 @@ pub fn deinit(self: *Coff) void {
if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
}
+ for (self.objects.items) |*object| {
+ object.deinit(gpa);
+ }
+ self.objects.deinit(gpa);
+
for (self.sections.items(.free_list)) |*free_list| {
free_list.deinit(gpa);
}
@@ -211,15 +219,15 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.text_section_index == null) {
self.text_section_index = @intCast(u16, self.sections.slice().len);
- const file_size = self.base.options.program_code_size_hint;
+ const file_size = @intCast(u32, self.base.options.program_code_size_hint);
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
log.debug("found .text free space 0x{x} to 0x{x}", .{ off, off + file_size });
var header = coff.SectionHeader{
.name = undefined,
- .virtual_size = @intCast(u32, file_size),
- .virtual_address = @intCast(u32, off),
- .size_of_raw_data = @intCast(u32, file_size),
- .pointer_to_raw_data = @intCast(u32, off),
+ .virtual_size = file_size,
+ .virtual_address = off,
+ .size_of_raw_data = file_size,
+ .pointer_to_raw_data = off,
.pointer_to_relocations = 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = 0,
@@ -236,15 +244,15 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.pdata_section_index == null) {
self.pdata_section_index = @intCast(u16, self.sections.slice().len);
- const file_size = self.base.options.symbol_count_hint;
+ const file_size = @intCast(u32, self.base.options.symbol_count_hint);
const off = self.findFreeSpace(file_size, self.page_size);
log.debug("found .pdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
var header = coff.SectionHeader{
.name = undefined,
- .virtual_size = @intCast(u32, file_size),
- .virtual_address = @intCast(u32, off),
- .size_of_raw_data = @intCast(u32, file_size),
- .pointer_to_raw_data = @intCast(u32, off),
+ .virtual_size = file_size,
+ .virtual_address = off,
+ .size_of_raw_data = file_size,
+ .pointer_to_raw_data = off,
.pointer_to_relocations = 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = 0,
@@ -260,15 +268,15 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.rdata_section_index == null) {
self.rdata_section_index = @intCast(u16, self.sections.slice().len);
- const file_size = 1024;
+ const file_size: u32 = 1024;
const off = self.findFreeSpace(file_size, self.page_size);
log.debug("found .rdata free space 0x{x} to 0x{x}", .{ off, off + file_size });
var header = coff.SectionHeader{
.name = undefined,
- .virtual_size = @intCast(u32, file_size),
- .virtual_address = @intCast(u32, off),
- .size_of_raw_data = @intCast(u32, file_size),
- .pointer_to_raw_data = @intCast(u32, off),
+ .virtual_size = file_size,
+ .virtual_address = off,
+ .size_of_raw_data = file_size,
+ .pointer_to_raw_data = off,
.pointer_to_relocations = 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = 0,
@@ -284,15 +292,15 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.data_section_index == null) {
self.data_section_index = @intCast(u16, self.sections.slice().len);
- const file_size = 1024;
+ const file_size: u32 = 1024;
const off = self.findFreeSpace(file_size, self.page_size);
log.debug("found .data free space 0x{x} to 0x{x}", .{ off, off + file_size });
var header = coff.SectionHeader{
.name = undefined,
- .virtual_size = @intCast(u32, file_size),
- .virtual_address = @intCast(u32, off),
- .size_of_raw_data = @intCast(u32, file_size),
- .pointer_to_raw_data = @intCast(u32, off),
+ .virtual_size = file_size,
+ .virtual_address = off,
+ .size_of_raw_data = file_size,
+ .pointer_to_raw_data = off,
.pointer_to_relocations = 0,
.pointer_to_linenumbers = 0,
.number_of_relocations = 0,
@@ -309,7 +317,7 @@ fn populateMissingMetadata(self: *Coff) !void {
if (self.strtab_offset == null) {
try self.strtab.buffer.append(gpa, 0);
- self.strtab_offset = @intCast(u32, self.findFreeSpace(self.strtab.len(), 1));
+ self.strtab_offset = self.findFreeSpace(@intCast(u32, self.strtab.len()), 1);
log.debug("found strtab free space 0x{x} to 0x{x}", .{ self.strtab_offset.?, self.strtab_offset.? + self.strtab.len() });
}
@@ -334,7 +342,7 @@ pub fn allocateDeclIndexes(self: *Coff, decl_index: Module.Decl.Index) !void {
try self.decls.putNoClobber(gpa, decl_index, null);
}
-fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {
+fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
const tracy = trace(@src());
defer tracy.end();
@@ -362,10 +370,10 @@ fn allocateAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, se
const sym = big_atom.getSymbol(self);
const capacity = big_atom.capacity(self);
const ideal_capacity = if (header.isCode()) padToIdeal(capacity) else capacity;
- const ideal_capacity_end_vaddr = math.add(u64, sym.n_value, ideal_capacity) catch ideal_capacity;
- const capacity_end_vaddr = sym.n_value + capacity;
+ const ideal_capacity_end_vaddr = math.add(u32, sym.value, ideal_capacity) catch ideal_capacity;
+ const capacity_end_vaddr = sym.value + capacity;
const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
- const new_start_vaddr = mem.alignBackwardGeneric(u64, new_start_vaddr_unaligned, alignment);
+ const new_start_vaddr = mem.alignBackwardGeneric(u32, new_start_vaddr_unaligned, alignment);
if (new_start_vaddr < ideal_capacity_end_vaddr) {
// Additional bookkeeping here to notice if this free list node
// 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
} else if (maybe_last_atom.*) |last| {
const last_symbol = last.getSymbol(self);
const ideal_capacity = if (header.isCode()) padToIdeal(last.size) else last.size;
- const ideal_capacity_end_vaddr = last_symbol.n_value + ideal_capacity;
- const new_start_vaddr = mem.alignForwardGeneric(u64, ideal_capacity_end_vaddr, alignment);
+ const ideal_capacity_end_vaddr = last_symbol.value + ideal_capacity;
+ const new_start_vaddr = mem.alignForwardGeneric(u32, ideal_capacity_end_vaddr, alignment);
atom_placement = last;
break :blk new_start_vaddr;
} else {
- break :blk mem.alignForwardGeneric(u64, header.addr, alignment);
+ break :blk mem.alignForwardGeneric(u32, header.virtual_address, alignment);
}
};
const expand_section = atom_placement == null or atom_placement.?.next == null;
if (expand_section) {
- @panic("TODO expand section in allocateAtom");
+ const sect_capacity = self.allocatedSize(header.pointer_to_raw_data);
+ const needed_size: u32 = (vaddr + new_atom_size) - header.virtual_address;
+ if (needed_size > sect_capacity) {
+ @panic("TODO move section");
+ }
+ maybe_last_atom.* = atom;
+ header.virtual_size = needed_size;
+ header.size_of_raw_data = needed_size;
}
- if (header.getAlignment() < alignment) {
- header.setAlignment(alignment);
- }
+ // if (header.getAlignment().? < alignment) {
+ // header.setAlignment(alignment);
+ // }
atom.size = new_atom_size;
atom.alignment = alignment;
@@ -465,30 +480,39 @@ fn allocateSymbol(self: *Coff) !u32 {
pub fn allocateGotEntry(self: *Coff, target: SymbolWithLoc) !u32 {
const gpa = self.base.allocator;
try self.got_entries.ensureUnusedCapacity(gpa, 1);
- if (self.got_entries_free_list.popOrNull()) |index| {
- log.debug(" (reusing GOT entry index {d})", .{index});
- if (self.got_entries.getIndex(target)) |existing| {
- assert(existing == index);
+ const index: u32 = blk: {
+ if (self.got_entries_free_list.popOrNull()) |index| {
+ log.debug(" (reusing GOT entry index {d})", .{index});
+ if (self.got_entries.getIndex(target)) |existing| {
+ assert(existing == index);
+ }
+ break :blk index;
+ } else {
+ log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});
+ const index = @intCast(u32, self.got_entries.keys().len);
+ self.got_entries.putAssumeCapacityNoClobber(target, 0);
+ break :blk index;
}
- self.got_entries.keys()[index] = target;
- return index;
- } else {
- log.debug(" (allocating GOT entry at index {d})", .{self.got_entries.keys().len});
- const index = @intCast(u32, self.got_entries.keys().len);
- try self.got_entries.putAssumeCapacityNoClobber(target, 0);
- return index;
- }
+ };
+ self.got_entries.keys()[index] = target;
+ return index;
+}
+
+fn createGotAtom(self: *Coff, target: SymbolWithLoc) !*Atom {
+ _ = self;
+ _ = target;
+ @panic("TODO createGotAtom");
}
-fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u64, alignment: u64, sect_id: u16) !u64 {
+fn growAtom(self: *Coff, atom: *Atom, new_atom_size: u32, alignment: u32, sect_id: u16) !u32 {
const sym = atom.getSymbol(self);
- const align_ok = mem.alignBackwardGeneric(u64, sym.value, alignment) == sym.value;
+ const align_ok = mem.alignBackwardGeneric(u32, sym.value, alignment) == sym.value;
const need_realloc = !align_ok or new_atom_size > atom.capacity(self);
if (!need_realloc) return sym.value;
return self.allocateAtom(atom, new_atom_size, alignment, sect_id);
}
-fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void {
+fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u32, sect_id: u16) void {
_ = self;
_ = atom;
_ = new_block_size;
@@ -497,6 +521,22 @@ fn shrinkAtom(self: *Coff, atom: *Atom, new_block_size: u64, sect_id: u16) void
// capacity, insert a free list node for it.
}
+fn writeAtom(self: *Coff, atom: *Atom, code: []const u8, sect_id: u16) !void {
+ const section = self.sections.get(sect_id);
+ const sym = atom.getSymbol(self);
+ const file_offset = section.header.pointer_to_raw_data + sym.value - section.header.virtual_address;
+ try self.resolveRelocs(atom, code);
+ log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset });
+ try self.base.file.?.pwriteAll(code, file_offset);
+}
+
+fn resolveRelocs(self: *Coff, atom: *Atom, code: []const u8) !void {
+ _ = self;
+ _ = atom;
+ _ = code;
+ log.debug("TODO resolveRelocs", .{});
+}
+
fn freeAtom(self: *Coff, atom: *Atom, sect_id: u16) void {
log.debug("freeAtom {*}", .{atom});
@@ -583,8 +623,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
},
};
- const sym = try self.updateDeclCode(decl_index, code);
- log.debug("updated decl code has sym {}", .{sym});
+ try self.updateDeclCode(decl_index, code);
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
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) !
},
};
- const sym = try self.updateDeclCode(decl_index, code);
- log.debug("updated decl code for {}", .{sym});
+ try self.updateDeclCode(decl_index, code);
// Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
const decl_exports = module.decl_exports.get(decl_index) orelse &[0]*Module.Export{};
return self.updateDeclExports(module, decl_index, decl_exports);
}
-fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !*coff.Symbol {
- _ = self;
- _ = decl_index;
- _ = code;
- log.debug("TODO updateDeclCode", .{});
- return &self.locals.items[0];
+fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 {
+ const ty = decl.ty;
+ const zig_ty = ty.zigTypeTag();
+ const val = decl.val;
+ const index: u16 = blk: {
+ if (val.isUndefDeep()) {
+ // TODO in release-fast and release-small, we should put undef in .bss
+ break :blk self.data_section_index.?;
+ }
+
+ switch (zig_ty) {
+ .Fn => break :blk self.text_section_index.?,
+ else => {
+ if (val.castTag(.variable)) |_| {
+ break :blk self.data_section_index.?;
+ }
+ break :blk self.rdata_section_index.?;
+ },
+ }
+ };
+ return index;
+}
+
+fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []const u8) !void {
+ const gpa = self.base.allocator;
+ const mod = self.base.options.module.?;
+ const decl = mod.declPtr(decl_index);
+
+ const decl_name = try decl.getFullyQualifiedName(mod);
+ defer gpa.free(decl_name);
+
+ log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
+ const required_alignment = decl.getAlignment(self.base.options.target);
+
+ const decl_ptr = self.decls.getPtr(decl_index).?;
+ if (decl_ptr.* == null) {
+ decl_ptr.* = self.getDeclOutputSection(decl);
+ }
+ const sect_index = decl_ptr.*.?;
+
+ const code_len = @intCast(u32, code.len);
+ const atom = &decl.link.coff;
+ assert(atom.sym_index != 0); // Caller forgot to allocateDeclIndexes()
+ if (atom.size != 0) {
+ const sym = atom.getSymbolPtr(self);
+ const capacity = atom.capacity(self);
+ const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, sym.value, required_alignment);
+
+ if (need_realloc) {
+ const vaddr = try self.growAtom(atom, code_len, required_alignment, sect_index);
+ log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, sym.value, vaddr });
+ log.debug(" (required alignment 0x{x}", .{required_alignment});
+
+ if (vaddr != sym.value) {
+ sym.value = vaddr;
+ log.debug(" (updating GOT entry)", .{});
+ var buffer: [@sizeOf(u64)]u8 = undefined;
+ const got_atom = self.getGotAtomForSymbol(.{ .sym_index = atom.sym_index, .file = null }).?;
+ try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
+ }
+ } else if (code_len < atom.size) {
+ self.shrinkAtom(atom, code_len, sect_index);
+ }
+ atom.size = code_len;
+ try self.setSymbolName(sym, decl_name);
+ sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
+ sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
+ sym.storage_class = .NULL;
+ } else {
+ const sym = atom.getSymbolPtr(self);
+ try self.setSymbolName(sym, decl_name);
+ const vaddr = try self.allocateAtom(atom, code_len, required_alignment, sect_index);
+ errdefer self.freeAtom(atom, sect_index);
+
+ log.debug("allocated atom for {s} at 0x{x}", .{ decl_name, vaddr });
+
+ atom.size = code_len;
+ sym.value = vaddr;
+ sym.section_number = @intToEnum(coff.SectionNumber, sect_index + 1);
+ sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
+ sym.storage_class = .NULL;
+
+ const got_target = SymbolWithLoc{ .sym_index = atom.sym_index, .file = null };
+ _ = try self.allocateGotEntry(got_target);
+ const got_atom = try self.createGotAtom(got_target);
+
+ var buffer: [@sizeOf(u64)]u8 = undefined;
+ try self.writeAtom(got_atom, &buffer, self.pdata_section_index.?);
+ }
+
+ try self.writeAtom(atom, code, sect_index);
}
pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
@@ -701,40 +824,142 @@ pub fn updateDeclExports(
@panic("Attempted to compile for object format that was disabled by build configuration");
}
- // Even in the case of LLVM, we need to notice certain exported symbols in order to
- // detect the default subsystem.
+ if (build_options.have_llvm) {
+ // Even in the case of LLVM, we need to notice certain exported symbols in order to
+ // detect the default subsystem.
+ for (exports) |exp| {
+ const exported_decl = module.declPtr(exp.exported_decl);
+ if (exported_decl.getFunction() == null) continue;
+ const winapi_cc = switch (self.base.options.target.cpu.arch) {
+ .i386 => std.builtin.CallingConvention.Stdcall,
+ else => std.builtin.CallingConvention.C,
+ };
+ const decl_cc = exported_decl.ty.fnCallingConvention();
+ if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and
+ self.base.options.link_libc)
+ {
+ module.stage1_flags.have_c_main = true;
+ } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {
+ if (mem.eql(u8, exp.options.name, "WinMain")) {
+ module.stage1_flags.have_winmain = true;
+ } else if (mem.eql(u8, exp.options.name, "wWinMain")) {
+ module.stage1_flags.have_wwinmain = true;
+ } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
+ module.stage1_flags.have_winmain_crt_startup = true;
+ } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
+ module.stage1_flags.have_wwinmain_crt_startup = true;
+ } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
+ module.stage1_flags.have_dllmain_crt_startup = true;
+ }
+ }
+ }
+
+ if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
+ }
+
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const gpa = self.base.allocator;
+
+ const decl = module.declPtr(decl_index);
+ const atom = &decl.link.coff;
+ if (atom.sym_index == 0) return;
+ const decl_sym = atom.getSymbol(self);
+
for (exports) |exp| {
- const exported_decl = module.declPtr(exp.exported_decl);
- if (exported_decl.getFunction() == null) continue;
- const winapi_cc = switch (self.base.options.target.cpu.arch) {
- .i386 => std.builtin.CallingConvention.Stdcall,
- else => std.builtin.CallingConvention.C,
- };
- const decl_cc = exported_decl.ty.fnCallingConvention();
- if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and
- self.base.options.link_libc)
- {
- module.stage1_flags.have_c_main = true;
- } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) {
- if (mem.eql(u8, exp.options.name, "WinMain")) {
- module.stage1_flags.have_winmain = true;
- } else if (mem.eql(u8, exp.options.name, "wWinMain")) {
- module.stage1_flags.have_wwinmain = true;
- } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) {
- module.stage1_flags.have_winmain_crt_startup = true;
- } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) {
- module.stage1_flags.have_wwinmain_crt_startup = true;
- } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) {
- module.stage1_flags.have_dllmain_crt_startup = true;
+ log.debug("adding new export '{s}'", .{exp.options.name});
+
+ if (exp.options.section) |section_name| {
+ if (!mem.eql(u8, section_name, ".text")) {
+ try module.failed_exports.putNoClobber(
+ module.gpa,
+ exp,
+ try Module.ErrorMsg.create(
+ gpa,
+ decl.srcLoc(),
+ "Unimplemented: ExportOptions.section",
+ .{},
+ ),
+ );
+ continue;
}
}
+
+ if (exp.options.linkage == .LinkOnce) {
+ try module.failed_exports.putNoClobber(
+ module.gpa,
+ exp,
+ try Module.ErrorMsg.create(
+ gpa,
+ decl.srcLoc(),
+ "Unimplemented: GlobalLinkage.LinkOnce",
+ .{},
+ ),
+ );
+ continue;
+ }
+
+ const sym_index = exp.link.macho.sym_index orelse blk: {
+ const sym_index = try self.allocateSymbol();
+ exp.link.coff.sym_index = sym_index;
+ break :blk sym_index;
+ };
+ const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
+ const sym = self.getSymbolPtr(sym_loc);
+ try self.setSymbolName(sym, exp.options.name);
+ sym.value = decl_sym.value;
+ sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1);
+ sym.@"type" = .{ .complex_type = .FUNCTION, .base_type = .NULL };
+
+ switch (exp.options.linkage) {
+ .Strong => {
+ sym.storage_class = .EXTERNAL;
+ },
+ .Internal => @panic("TODO Internal"),
+ .Weak => @panic("TODO WeakExternal"),
+ else => unreachable,
+ }
+
+ self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
+ error.MultipleSymbolDefinitions => {
+ const global = self.globals.get(exp.options.name).?;
+ if (sym_loc.sym_index != global.sym_index and global.file != null) {
+ _ = try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(
+ gpa,
+ decl.srcLoc(),
+ \\LinkError: symbol '{s}' defined multiple times
+ \\ first definition in '{s}'
+ ,
+ .{ exp.options.name, self.objects.items[global.file.?].name },
+ ));
+ }
+ },
+ else => |e| return e,
+ };
}
+}
- if (build_options.have_llvm) {
- if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(module, decl_index, exports);
+fn resolveGlobalSymbol(self: *Coff, current: SymbolWithLoc) !void {
+ const gpa = self.base.allocator;
+ const sym = self.getSymbol(current);
+ _ = sym;
+ const sym_name = self.getSymbolName(current);
+
+ const name = try gpa.dupe(u8, sym_name);
+ const global_index = @intCast(u32, self.globals.values().len);
+ _ = global_index;
+ const gop = try self.globals.getOrPut(gpa, name);
+ defer if (gop.found_existing) gpa.free(name);
+
+ if (!gop.found_existing) {
+ gop.value_ptr.* = current;
+ // TODO undef + tentative
+ return;
}
- log.debug("TODO updateDeclExports", .{});
+ log.debug("TODO finish resolveGlobalSymbols implementation", .{});
+ return error.MultipleSymbolDefinitions;
}
pub 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
fn writeStrtab(self: *Coff) !void {
const allocated_size = self.allocatedSize(self.strtab_offset.?);
- const needed_size = self.strtab.len();
+ const needed_size = @intCast(u32, self.strtab.len());
if (needed_size > allocated_size) {
self.strtab_offset = null;
@@ -870,7 +1095,7 @@ fn writeHeader(self: *Coff) !void {
.NX_COMPAT = 1, // We are compatible with Data Execution Prevention
};
const subsystem: coff.Subsystem = .WINDOWS_CUI;
- const size_of_headers: u32 = @intCast(u32, self.getSizeOfHeaders());
+ const size_of_headers: u32 = self.getSizeOfHeaders();
const size_of_image_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, self.page_size);
const size_of_headers_aligned: u32 = mem.alignForwardGeneric(u32, size_of_headers, default_file_alignment);
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) {
math.maxInt(@TypeOf(actual_size));
}
-fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
+fn detectAllocCollision(self: *Coff, start: u32, size: u32) ?u32 {
const headers_size = self.getSizeOfHeaders();
if (start < headers_size)
return headers_size;
@@ -976,7 +1201,7 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
const end = start + padToIdeal(size);
if (self.strtab_offset) |off| {
- const increased_size = padToIdeal(self.strtab.len());
+ const increased_size = padToIdeal(@intCast(u32, self.strtab.len()));
const test_end = off + increased_size;
if (end > off and start < test_end) {
return test_end;
@@ -994,10 +1219,10 @@ fn detectAllocCollision(self: *Coff, start: u64, size: u64) ?u64 {
return null;
}
-pub fn allocatedSize(self: *Coff, start: u64) u64 {
+pub fn allocatedSize(self: *Coff, start: u32) u32 {
if (start == 0)
return 0;
- var min_pos: u64 = std.math.maxInt(u64);
+ var min_pos: u32 = std.math.maxInt(u32);
if (self.strtab_offset) |off| {
if (off > start and off < min_pos) min_pos = off;
}
@@ -1008,41 +1233,41 @@ pub fn allocatedSize(self: *Coff, start: u64) u64 {
return min_pos - start;
}
-pub fn findFreeSpace(self: *Coff, object_size: u64, min_alignment: u32) u64 {
- var start: u64 = 0;
+pub fn findFreeSpace(self: *Coff, object_size: u32, min_alignment: u32) u32 {
+ var start: u32 = 0;
while (self.detectAllocCollision(start, object_size)) |item_end| {
- start = mem.alignForwardGeneric(u64, item_end, min_alignment);
+ start = mem.alignForwardGeneric(u32, item_end, min_alignment);
}
return start;
}
-inline fn getSizeOfHeaders(self: Coff) usize {
+inline fn getSizeOfHeaders(self: Coff) u32 {
const msdos_hdr_size = msdos_stub.len + 8;
- return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
- self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize();
+ return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize() +
+ self.getDataDirectoryHeadersSize() + self.getSectionHeadersSize());
}
-inline fn getOptionalHeaderSize(self: Coff) usize {
+inline fn getOptionalHeaderSize(self: Coff) u32 {
return switch (self.ptr_width) {
- .p32 => @sizeOf(coff.OptionalHeaderPE32),
- .p64 => @sizeOf(coff.OptionalHeaderPE64),
+ .p32 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE32)),
+ .p64 => @intCast(u32, @sizeOf(coff.OptionalHeaderPE64)),
};
}
-inline fn getDataDirectoryHeadersSize(self: Coff) usize {
- return self.data_directories.len * @sizeOf(coff.ImageDataDirectory);
+inline fn getDataDirectoryHeadersSize(self: Coff) u32 {
+ return @intCast(u32, self.data_directories.len * @sizeOf(coff.ImageDataDirectory));
}
-inline fn getSectionHeadersSize(self: Coff) usize {
- return self.sections.slice().len * @sizeOf(coff.SectionHeader);
+inline fn getSectionHeadersSize(self: Coff) u32 {
+ return @intCast(u32, self.sections.slice().len * @sizeOf(coff.SectionHeader));
}
-inline fn getDataDirectoryHeadersOffset(self: Coff) usize {
+inline fn getDataDirectoryHeadersOffset(self: Coff) u32 {
const msdos_hdr_size = msdos_stub.len + 8;
- return msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize();
+ return @intCast(u32, msdos_hdr_size + @sizeOf(coff.CoffHeader) + self.getOptionalHeaderSize());
}
-inline fn getSectionHeadersOffset(self: Coff) usize {
+inline fn getSectionHeadersOffset(self: Coff) u32 {
return self.getDataDirectoryHeadersOffset() + self.getDataDirectoryHeadersSize();
}
@@ -1086,7 +1311,7 @@ fn setSectionName(self: *Coff, header: *coff.SectionHeader, name: []const u8) !v
return;
}
const offset = try self.strtab.insert(self.base.allocator, name);
- const name_offset = try fmt.bufPrint(&header.name, "/{d}", .{offset});
+ const name_offset = fmt.bufPrint(&header.name, "/{d}", .{offset}) catch unreachable;
mem.set(u8, header.name[name_offset.len..], 0);
}
@@ -1097,6 +1322,6 @@ fn setSymbolName(self: *Coff, symbol: *coff.Symbol, name: []const u8) !void {
return;
}
const offset = try self.strtab.insert(self.base.allocator, name);
- mem.copy(u8, symbol.name[0..4], 0);
- _ = try fmt.bufPrint(symbol.name[4..], "{d}", .{offset});
+ mem.set(u8, symbol.name[0..4], 0);
+ _ = fmt.bufPrint(symbol.name[4..], "{d}", .{offset}) catch unreachable;
}