macho: refactor markExports, markImportsExports and claimUnresolved

This commit is contained in:
Jakub Konka 2024-02-06 13:56:28 +01:00
parent 352e27c55c
commit bdbb1dbe15
4 changed files with 151 additions and 110 deletions

View File

@ -379,6 +379,10 @@ pub fn deinit(self: *MachO) void {
}
pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void {
// TODO: I think this is just a temp and can be removed once we can emit static archives
if (self.base.isStaticLib() and build_options.have_llvm) {
return self.base.linkAsArchive(arena, prog_node);
}
try self.flushModule(arena, prog_node);
}
@ -391,6 +395,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
if (self.llvm_object) |llvm_object| {
try self.base.emitLlvmObject(arena, llvm_object, prog_node);
// TODO: I think this is just a temp and can be removed once we can emit static archives
if (self.base.isStaticLib() and build_options.have_llvm) return;
}
var sub_prog_node = prog_node.start("MachO Flush", 0);
@ -571,7 +577,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
},
};
try self.markImportsAndExports();
self.markImportsAndExports();
self.deadStripDylibs();
for (self.dylibs.items, 1..) |index, ord| {
@ -1509,46 +1515,11 @@ fn createObjcSections(self: *MachO) !void {
}
fn claimUnresolved(self: *MachO) error{OutOfMemory}!void {
const gpa = self.base.comp.gpa;
var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
defer objects.deinit();
if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
objects.appendSliceAssumeCapacity(self.objects.items);
for (objects.items) |index| {
const file = self.getFile(index).?;
for (file.getSymbols(), 0..) |sym_index, i| {
const nlist_idx = @as(Symbol.Index, @intCast(i));
const nlist = switch (file) {
.object => |x| x.symtab.items(.nlist)[nlist_idx],
.zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
else => unreachable,
};
if (!nlist.ext()) continue;
if (!nlist.undf()) continue;
const sym = self.getSymbol(sym_index);
if (sym.getFile(self) != null) continue;
const is_import = switch (self.undefined_treatment) {
.@"error" => false,
.warn, .suppress => nlist.weakRef(),
.dynamic_lookup => true,
};
if (is_import) {
sym.value = 0;
sym.atom = 0;
sym.nlist_idx = 0;
sym.file = self.internal_object.?;
sym.flags.weak = false;
sym.flags.weak_ref = nlist.weakRef();
sym.flags.import = is_import;
sym.visibility = .global;
try self.getInternalObject().?.symbols.append(self.base.comp.gpa, sym_index);
}
}
if (self.getZigObject()) |zo| {
try zo.asFile().claimUnresolved(self);
}
for (self.objects.items) |index| {
try self.getFile(index).?.claimUnresolved(self);
}
}
@ -1574,26 +1545,12 @@ fn checkDuplicates(self: *MachO) !void {
try self.reportDuplicates(dupes);
}
fn markImportsAndExports(self: *MachO) error{OutOfMemory}!void {
const gpa = self.base.comp.gpa;
var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
defer objects.deinit();
if (self.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
objects.appendSliceAssumeCapacity(self.objects.items);
for (objects.items) |index| {
for (self.getFile(index).?.getSymbols()) |sym_index| {
const sym = self.getSymbol(sym_index);
const file = sym.getFile(self) orelse continue;
if (sym.visibility != .global) continue;
if (file == .dylib and !sym.flags.abs) {
sym.flags.import = true;
continue;
}
if (file.getIndex() == index) {
sym.flags.@"export" = true;
}
}
fn markImportsAndExports(self: *MachO) void {
if (self.getZigObject()) |zo| {
zo.asFile().markImportsExports(self);
}
for (self.objects.items) |index| {
self.getFile(index).?.markImportsExports(self);
}
for (self.undefined_symbols.items) |index| {

View File

@ -144,8 +144,32 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index:
}
pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
_ = comp;
_ = module_obj_path;
const gpa = comp.gpa;
var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);
defer positionals.deinit();
try positionals.ensureUnusedCapacity(comp.objects.len);
positionals.appendSliceAssumeCapacity(comp.objects);
for (comp.c_object_table.keys()) |key| {
try positionals.append(.{ .path = key.status.success.object_path });
}
if (module_obj_path) |path| try positionals.append(.{ .path = path });
for (positionals.items) |obj| {
// TODO: parse for archive meaning don't unpack objects
_ = obj;
}
if (comp.link_errors.items.len > 0) return error.FlushFailure;
// First, we flush relocatable object file generated with our backends.
if (macho_file.getZigObject()) |zo| {
zo.resolveSymbols(macho_file);
zo.asFile().claimUnresolvedRelocatable(macho_file);
}
var err = try macho_file.addErrorWithNotes(0);
try err.addMsg(macho_file, "TODO implement flushStaticLib", .{});
@ -158,6 +182,7 @@ const link = @import("../../link.zig");
const log = std.log.scoped(.link);
const macho = std.macho;
const mem = std.mem;
const relocatable = @import("relocatable.zig");
const std = @import("std");
const Allocator = mem.Allocator;

View File

@ -44,6 +44,97 @@ pub const File = union(enum) {
}
}
pub fn claimUnresolved(file: File, macho_file: *MachO) error{OutOfMemory}!void {
assert(file == .object or file == .zig_object);
for (file.getSymbols(), 0..) |sym_index, i| {
const nlist_idx = @as(Symbol.Index, @intCast(i));
const nlist = switch (file) {
.object => |x| x.symtab.items(.nlist)[nlist_idx],
.zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
else => unreachable,
};
if (!nlist.ext()) continue;
if (!nlist.undf()) continue;
const sym = macho_file.getSymbol(sym_index);
if (sym.getFile(macho_file) != null) continue;
const is_import = switch (macho_file.undefined_treatment) {
.@"error" => false,
.warn, .suppress => nlist.weakRef(),
.dynamic_lookup => true,
};
if (is_import) {
sym.value = 0;
sym.atom = 0;
sym.nlist_idx = 0;
sym.file = macho_file.internal_object.?;
sym.flags.weak = false;
sym.flags.weak_ref = nlist.weakRef();
sym.flags.import = is_import;
sym.visibility = .global;
try macho_file.getInternalObject().?.symbols.append(macho_file.base.comp.gpa, sym_index);
}
}
}
pub fn claimUnresolvedRelocatable(file: File, macho_file: *MachO) void {
assert(file == .object or file == .zig_object);
for (file.getSymbols(), 0..) |sym_index, i| {
const nlist_idx = @as(Symbol.Index, @intCast(i));
const nlist = switch (file) {
.object => |x| x.symtab.items(.nlist)[nlist_idx],
.zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
else => unreachable,
};
if (!nlist.ext()) continue;
if (!nlist.undf()) continue;
const sym = macho_file.getSymbol(sym_index);
if (sym.getFile(macho_file) != null) continue;
sym.value = 0;
sym.atom = 0;
sym.nlist_idx = nlist_idx;
sym.file = file.getIndex();
sym.flags.weak_ref = nlist.weakRef();
sym.flags.import = true;
sym.visibility = .global;
}
}
pub fn markImportsExports(file: File, macho_file: *MachO) void {
assert(file == .object or file == .zig_object);
for (file.getSymbols()) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
const other_file = sym.getFile(macho_file) orelse continue;
if (sym.visibility != .global) continue;
if (other_file == .dylib and !sym.flags.abs) {
sym.flags.import = true;
continue;
}
if (other_file.getIndex() == file.getIndex()) {
sym.flags.@"export" = true;
}
}
}
pub fn markExportsRelocatable(file: File, macho_file: *MachO) void {
assert(file == .object or file == .zig_object);
for (file.getSymbols()) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
const other_file = sym.getFile(macho_file) orelse continue;
if (sym.visibility != .global) continue;
if (other_file.getIndex() == file.getIndex()) {
sym.flags.@"export" = true;
}
}
}
/// Encodes symbol rank so that the following ordering applies:
/// * strong in object
/// * weak in object
@ -110,6 +201,7 @@ pub const File = union(enum) {
pub const HandleIndex = Index;
};
const assert = std.debug.assert;
const macho = std.macho;
const std = @import("std");

View File

@ -46,8 +46,8 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
try macho_file.addUndefinedGlobals();
try macho_file.resolveSymbols();
try markExports(macho_file);
try claimUnresolved(macho_file);
markExports(macho_file);
claimUnresolved(macho_file);
try initOutputSections(macho_file);
try macho_file.sortSections();
try macho_file.addAtomsToSections();
@ -86,54 +86,21 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
try writeHeader(macho_file, ncmds, sizeofcmds);
}
fn markExports(macho_file: *MachO) error{OutOfMemory}!void {
var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
defer objects.deinit();
if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
objects.appendSliceAssumeCapacity(macho_file.objects.items);
for (objects.items) |index| {
for (macho_file.getFile(index).?.getSymbols()) |sym_index| {
const sym = macho_file.getSymbol(sym_index);
const file = sym.getFile(macho_file) orelse continue;
if (sym.visibility != .global) continue;
if (file.getIndex() == index) {
sym.flags.@"export" = true;
}
}
fn markExports(macho_file: *MachO) void {
if (macho_file.getZigObject()) |zo| {
zo.asFile().markExportsRelocatable(macho_file);
}
for (macho_file.objects.items) |index| {
macho_file.getFile(index).?.markExportsRelocatable(macho_file);
}
}
fn claimUnresolved(macho_file: *MachO) error{OutOfMemory}!void {
var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
defer objects.deinit();
if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
objects.appendSliceAssumeCapacity(macho_file.objects.items);
for (objects.items) |index| {
const file = macho_file.getFile(index).?;
for (file.getSymbols(), 0..) |sym_index, i| {
const nlist_idx = @as(Symbol.Index, @intCast(i));
const nlist = switch (file) {
.object => |x| x.symtab.items(.nlist)[nlist_idx],
.zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
else => unreachable,
};
if (!nlist.ext()) continue;
if (!nlist.undf()) continue;
const sym = macho_file.getSymbol(sym_index);
if (sym.getFile(macho_file) != null) continue;
sym.value = 0;
sym.atom = 0;
sym.nlist_idx = nlist_idx;
sym.file = index;
sym.flags.weak_ref = nlist.weakRef();
sym.flags.import = true;
sym.visibility = .global;
}
pub fn claimUnresolved(macho_file: *MachO) void {
if (macho_file.getZigObject()) |zo| {
zo.asFile().claimUnresolvedRelocatable(macho_file);
}
for (macho_file.objects.items) |index| {
macho_file.getFile(index).?.claimUnresolvedRelocatable(macho_file);
}
}