authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-30 17:29:05+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-30 17:29:05+01:00
log10d03acdb5ff81c112280854629c9f9032e14330
treeed9c38b4c3c6ff17a1eaecacce35114219005bdb
parent91e117697ad90430d9266203415712b6cc59f669
parent324a93e673afcf1bcaac1163379d385952e52a27
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17773 from ziglang/elf-exports

link: implement exporting anon decls

10 files changed, 373 insertions(+), 227 deletions(-)

src/arch/x86_64/CodeGen.zig+4-2
...@@ -13063,6 +13063,7 @@ fn genExternSymbolRef(...@@ -13063,6 +13063,7 @@ fn genExternSymbolRef(
13063 } },13063 } },
13064 });13064 });
13065 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {13065 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
13066 const global_index = try coff_file.getGlobalSymbol(callee, lib);
13066 _ = try self.addInst(.{13067 _ = try self.addInst(.{
13067 .tag = .mov,13068 .tag = .mov,
13068 .ops = .import_reloc,13069 .ops = .import_reloc,
...@@ -13070,7 +13071,7 @@ fn genExternSymbolRef(...@@ -13070,7 +13071,7 @@ fn genExternSymbolRef(
13070 .r1 = .rax,13071 .r1 = .rax,
13071 .payload = try self.addExtra(bits.Symbol{13072 .payload = try self.addExtra(bits.Symbol{
13072 .atom_index = atom_index,13073 .atom_index = atom_index,
13073 .sym_index = try coff_file.getGlobalSymbol(callee, lib),13074 .sym_index = link.File.Coff.global_symbol_bit | global_index,
13074 }),13075 }),
13075 } },13076 } },
13076 });13077 });
...@@ -13080,12 +13081,13 @@ fn genExternSymbolRef(...@@ -13080,12 +13081,13 @@ fn genExternSymbolRef(
13080 else => unreachable,13081 else => unreachable,
13081 }13082 }
13082 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {13083 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
13084 const global_index = try macho_file.getGlobalSymbol(callee, lib);
13083 _ = try self.addInst(.{13085 _ = try self.addInst(.{
13084 .tag = .call,13086 .tag = .call,
13085 .ops = .extern_fn_reloc,13087 .ops = .extern_fn_reloc,
13086 .data = .{ .reloc = .{13088 .data = .{ .reloc = .{
13087 .atom_index = atom_index,13089 .atom_index = atom_index,
13088 .sym_index = try macho_file.getGlobalSymbol(callee, lib),13090 .sym_index = link.File.MachO.global_symbol_bit | global_index,
13089 } },13091 } },
13090 });13092 });
13091 } else return self.fail("TODO implement calling extern functions", .{});13093 } else return self.fail("TODO implement calling extern functions", .{});
src/arch/x86_64/Emit.zig+18-10
...@@ -52,7 +52,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -52,7 +52,10 @@ pub fn emitMir(emit: *Emit) Error!void {
52 // Add relocation to the decl.52 // Add relocation to the decl.
53 const atom_index =53 const atom_index =
54 macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;54 macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
55 const target = macho_file.getGlobalByIndex(symbol.sym_index);55 const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0)
56 macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index)
57 else
58 link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index };
56 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{59 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
57 .type = .branch,60 .type = .branch,
58 .target = target,61 .target = target,
...@@ -66,7 +69,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -66,7 +69,10 @@ pub fn emitMir(emit: *Emit) Error!void {
66 const atom_index = coff_file.getAtomIndexForSymbol(69 const atom_index = coff_file.getAtomIndexForSymbol(
67 .{ .sym_index = symbol.atom_index, .file = null },70 .{ .sym_index = symbol.atom_index, .file = null },
68 ).?;71 ).?;
69 const target = coff_file.getGlobalByIndex(symbol.sym_index);72 const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
73 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
74 else
75 link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
70 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{76 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
71 .type = .direct,77 .type = .direct,
72 .target = target,78 .target = target,
...@@ -116,6 +122,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -116,6 +122,10 @@ pub fn emitMir(emit: *Emit) Error!void {
116 } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {122 } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
117 const atom_index =123 const atom_index =
118 macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;124 macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
125 const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0)
126 macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index)
127 else
128 link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index };
119 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{129 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
120 .type = switch (lowered_relocs[0].target) {130 .type = switch (lowered_relocs[0].target) {
121 .linker_got => .got,131 .linker_got => .got,
...@@ -123,7 +133,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -123,7 +133,7 @@ pub fn emitMir(emit: *Emit) Error!void {
123 .linker_tlv => .tlv,133 .linker_tlv => .tlv,
124 else => unreachable,134 else => unreachable,
125 },135 },
126 .target = .{ .sym_index = symbol.sym_index },136 .target = target,
127 .offset = @as(u32, @intCast(end_offset - 4)),137 .offset = @as(u32, @intCast(end_offset - 4)),
128 .addend = 0,138 .addend = 0,
129 .pcrel = true,139 .pcrel = true,
...@@ -134,6 +144,10 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -134,6 +144,10 @@ pub fn emitMir(emit: *Emit) Error!void {
134 .sym_index = symbol.atom_index,144 .sym_index = symbol.atom_index,
135 .file = null,145 .file = null,
136 }).?;146 }).?;
147 const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
148 coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
149 else
150 link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
137 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{151 try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
138 .type = switch (lowered_relocs[0].target) {152 .type = switch (lowered_relocs[0].target) {
139 .linker_got => .got,153 .linker_got => .got,
...@@ -141,13 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -141,13 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void {
141 .linker_import => .import,155 .linker_import => .import,
142 else => unreachable,156 else => unreachable,
143 },157 },
144 .target = switch (lowered_relocs[0].target) {158 .target = target,
145 .linker_got,
146 .linker_direct,
147 => .{ .sym_index = symbol.sym_index, .file = null },
148 .linker_import => coff_file.getGlobalByIndex(symbol.sym_index),
149 else => unreachable,
150 },
151 .offset = @as(u32, @intCast(end_offset - 4)),159 .offset = @as(u32, @intCast(end_offset - 4)),
152 .addend = 0,160 .addend = 0,
153 .pcrel = true,161 .pcrel = true,
src/codegen.zig+20
...@@ -721,6 +721,7 @@ fn lowerAnonDeclRef(...@@ -721,6 +721,7 @@ fn lowerAnonDeclRef(
721 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);721 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
722 const decl_val = anon_decl.val;722 const decl_val = anon_decl.val;
723 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();723 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
724 log.debug("lowerAnonDecl: ty = {}", .{decl_ty.fmt(mod)});
724 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;725 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
725 if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {726 if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {
726 try code.appendNTimes(0xaa, ptr_width_bytes);727 try code.appendNTimes(0xaa, ptr_width_bytes);
...@@ -911,6 +912,14 @@ fn genDeclRef(...@@ -911,6 +912,14 @@ fn genDeclRef(
911 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
912 return GenResult.mcv(.{ .load_symbol = sym.esym_index });913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });
913 } else if (bin_file.cast(link.File.MachO)) |macho_file| {914 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
915 if (is_extern) {
916 // TODO make this part of getGlobalSymbol
917 const name = mod.intern_pool.stringToSlice(decl.name);
918 const sym_name = try std.fmt.allocPrint(bin_file.allocator, "_{s}", .{name});
919 defer bin_file.allocator.free(sym_name);
920 const global_index = try macho_file.addUndefined(sym_name, .{ .add_got = true });
921 return GenResult.mcv(.{ .load_got = link.File.MachO.global_symbol_bit | global_index });
922 }
914 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);923 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
915 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;924 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
916 if (is_threadlocal) {925 if (is_threadlocal) {
...@@ -918,6 +927,17 @@ fn genDeclRef(...@@ -918,6 +927,17 @@ fn genDeclRef(
918 }927 }
919 return GenResult.mcv(.{ .load_got = sym_index });928 return GenResult.mcv(.{ .load_got = sym_index });
920 } else if (bin_file.cast(link.File.Coff)) |coff_file| {929 } else if (bin_file.cast(link.File.Coff)) |coff_file| {
930 if (is_extern) {
931 const name = mod.intern_pool.stringToSlice(decl.name);
932 // TODO audit this
933 const lib_name = if (decl.getOwnedVariable(mod)) |ov|
934 mod.intern_pool.stringToSliceUnwrap(ov.lib_name)
935 else
936 null;
937 const global_index = try coff_file.getGlobalSymbol(name, lib_name);
938 try coff_file.need_got_table.put(bin_file.allocator, global_index, {}); // needs GOT
939 return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index });
940 }
921 const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);941 const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
922 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;942 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
923 return GenResult.mcv(.{ .load_got = sym_index });943 return GenResult.mcv(.{ .load_got = sym_index });
src/link/Coff.zig+87-45
...@@ -28,6 +28,7 @@ locals: std.ArrayListUnmanaged(coff.Symbol) = .{},...@@ -28,6 +28,7 @@ locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
28globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},28globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
29resolver: std.StringHashMapUnmanaged(u32) = .{},29resolver: std.StringHashMapUnmanaged(u32) = .{},
30unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},30unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
31need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},
3132
32locals_free_list: std.ArrayListUnmanaged(u32) = .{},33locals_free_list: std.ArrayListUnmanaged(u32) = .{},
33globals_free_list: std.ArrayListUnmanaged(u32) = .{},34globals_free_list: std.ArrayListUnmanaged(u32) = .{},
...@@ -54,7 +55,7 @@ entry_addr: ?u32 = null,...@@ -54,7 +55,7 @@ entry_addr: ?u32 = null,
54lazy_syms: LazySymbolTable = .{},55lazy_syms: LazySymbolTable = .{},
5556
56/// Table of tracked Decls.57/// Table of tracked Decls.
57decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},58decls: DeclTable = .{},
5859
59/// List of atoms that are either synthetic or map directly to the Zig source program.60/// List of atoms that are either synthetic or map directly to the Zig source program.
60atoms: std.ArrayListUnmanaged(Atom) = .{},61atoms: std.ArrayListUnmanaged(Atom) = .{},
...@@ -108,7 +109,8 @@ const HotUpdateState = struct {...@@ -108,7 +109,8 @@ const HotUpdateState = struct {
108 loaded_base_address: ?std.os.windows.HMODULE = null,109 loaded_base_address: ?std.os.windows.HMODULE = null,
109};110};
110111
111const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);112const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
113const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
112const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));114const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
113const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));115const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
114const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));116const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
...@@ -325,7 +327,14 @@ pub fn deinit(self: *Coff) void {...@@ -325,7 +327,14 @@ pub fn deinit(self: *Coff) void {
325 atoms.deinit(gpa);327 atoms.deinit(gpa);
326 }328 }
327 self.unnamed_const_atoms.deinit(gpa);329 self.unnamed_const_atoms.deinit(gpa);
328 self.anon_decls.deinit(gpa);330
331 {
332 var it = self.anon_decls.iterator();
333 while (it.next()) |entry| {
334 entry.value_ptr.exports.deinit(gpa);
335 }
336 self.anon_decls.deinit(gpa);
337 }
329338
330 for (self.relocs.values()) |*relocs| {339 for (self.relocs.values()) |*relocs| {
331 relocs.deinit(gpa);340 relocs.deinit(gpa);
...@@ -1160,12 +1169,17 @@ pub fn updateDecl(...@@ -1160,12 +1169,17 @@ pub fn updateDecl(
1160 const decl = mod.declPtr(decl_index);1169 const decl = mod.declPtr(decl_index);
11611170
1162 if (decl.val.getExternFunc(mod)) |_| {1171 if (decl.val.getExternFunc(mod)) |_| {
1163 return; // TODO Should we do more when front-end analyzed extern decl?1172 return;
1164 }1173 }
1165 if (decl.val.getVariable(mod)) |variable| {1174
1166 if (variable.is_extern) {1175 if (decl.isExtern(mod)) {
1167 return; // TODO Should we do more when front-end analyzed extern decl?1176 // TODO make this part of getGlobalSymbol
1168 }1177 const variable = decl.getOwnedVariable(mod).?;
1178 const name = mod.intern_pool.stringToSlice(decl.name);
1179 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
1180 const global_index = try self.getGlobalSymbol(name, lib_name);
1181 try self.need_got_table.put(self.base.allocator, global_index, {});
1182 return;
1169 }1183 }
11701184
1171 const atom_index = try self.getOrCreateAtomForDecl(decl_index);1185 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
...@@ -1462,62 +1476,77 @@ pub fn updateExports(...@@ -1462,62 +1476,77 @@ pub fn updateExports(
14621476
1463 const gpa = self.base.allocator;1477 const gpa = self.base.allocator;
14641478
1465 const decl_index = switch (exported) {1479 const metadata = switch (exported) {
1466 .decl_index => |i| i,1480 .decl_index => |decl_index| blk: {
1467 .value => |val| {1481 _ = try self.getOrCreateAtomForDecl(decl_index);
1468 _ = val;1482 break :blk self.decls.getPtr(decl_index).?;
1469 @panic("TODO: implement COFF linker code for exporting a constant value");1483 },
1484 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1485 const first_exp = exports[0];
1486 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
1487 switch (res) {
1488 .ok => {},
1489 .fail => |em| {
1490 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1491 // handle the error?
1492 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1493 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1494 return;
1495 },
1496 }
1497 break :blk self.anon_decls.getPtr(value).?;
1470 },1498 },
1471 };1499 };
1472 const decl = mod.declPtr(decl_index);1500 const atom_index = metadata.atom;
1473 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
1474 const atom = self.getAtom(atom_index);1501 const atom = self.getAtom(atom_index);
1475 const decl_metadata = self.decls.getPtr(decl_index).?;
14761502
1477 for (exports) |exp| {1503 for (exports) |exp| {
1478 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});1504 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
14791505
1480 if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {1506 if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {
1481 if (!mem.eql(u8, section_name, ".text")) {1507 if (!mem.eql(u8, section_name, ".text")) {
1482 try mod.failed_exports.putNoClobber(1508 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1483 gpa,1509 gpa,
1484 exp,1510 exp.getSrcLoc(mod),
1485 try Module.ErrorMsg.create(1511 "Unimplemented: ExportOptions.section",
1486 gpa,1512 .{},
1487 decl.srcLoc(mod),1513 ));
1488 "Unimplemented: ExportOptions.section",
1489 .{},
1490 ),
1491 );
1492 continue;1514 continue;
1493 }1515 }
1494 }1516 }
14951517
1496 if (exp.opts.linkage == .LinkOnce) {1518 if (exp.opts.linkage == .LinkOnce) {
1497 try mod.failed_exports.putNoClobber(1519 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1498 gpa,1520 gpa,
1499 exp,1521 exp.getSrcLoc(mod),
1500 try Module.ErrorMsg.create(1522 "Unimplemented: GlobalLinkage.LinkOnce",
1501 gpa,1523 .{},
1502 decl.srcLoc(mod),1524 ));
1503 "Unimplemented: GlobalLinkage.LinkOnce",
1504 .{},
1505 ),
1506 );
1507 continue;1525 continue;
1508 }1526 }
15091527
1510 const sym_index = decl_metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: {1528 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1511 const sym_index = try self.allocateSymbol();1529 const sym_index = metadata.getExport(self, exp_name) orelse blk: {
1512 try decl_metadata.exports.append(gpa, sym_index);1530 const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
1531 const global = self.globals.items[global_index];
1532 // TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
1533 // pass. This will go away once we abstact away Zig's incremental compilation into
1534 // its own module.
1535 if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) {
1536 _ = self.unresolved.swapRemove(global_index);
1537 break :ind global.sym_index;
1538 }
1539 break :ind try self.allocateSymbol();
1540 } else try self.allocateSymbol();
1541 try metadata.exports.append(gpa, sym_index);
1513 break :blk sym_index;1542 break :blk sym_index;
1514 };1543 };
1515 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };1544 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1516 const sym = self.getSymbolPtr(sym_loc);1545 const sym = self.getSymbolPtr(sym_loc);
1517 try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name));1546 try self.setSymbolName(sym, exp_name);
1518 sym.value = atom.getSymbol(self).value;1547 sym.value = atom.getSymbol(self).value;
1519 sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.text_section_index.? + 1));1548 sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1));
1520 sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL };1549 sym.type = atom.getSymbol(self).type;
15211550
1522 switch (exp.opts.linkage) {1551 switch (exp.opts.linkage) {
1523 .Strong => {1552 .Strong => {
...@@ -1651,8 +1680,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -1651,8 +1680,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
1651 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;1680 if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
1652 }1681 }
16531682
1683 {
1684 var it = self.need_got_table.iterator();
1685 while (it.next()) |entry| {
1686 const global = self.globals.items[entry.key_ptr.*];
1687 try self.addGotEntry(global);
1688 }
1689 }
1690
1654 while (self.unresolved.popOrNull()) |entry| {1691 while (self.unresolved.popOrNull()) |entry| {
1655 assert(entry.value); // We only expect imports generated by the incremental linker for now.1692 assert(entry.value);
1656 const global = self.globals.items[entry.key];1693 const global = self.globals.items[entry.key];
1657 const sym = self.getSymbol(global);1694 const sym = self.getSymbol(global);
1658 const res = try self.import_tables.getOrPut(gpa, sym.value);1695 const res = try self.import_tables.getOrPut(gpa, sym.value);
...@@ -1761,8 +1798,8 @@ pub fn lowerAnonDecl(...@@ -1761,8 +1798,8 @@ pub fn lowerAnonDecl(
1761 .none => ty.abiAlignment(mod),1798 .none => ty.abiAlignment(mod),
1762 else => explicit_alignment,1799 else => explicit_alignment,
1763 };1800 };
1764 if (self.anon_decls.get(decl_val)) |atom_index| {1801 if (self.anon_decls.get(decl_val)) |metadata| {
1765 const existing_addr = self.getAtom(atom_index).getSymbol(self).value;1802 const existing_addr = self.getAtom(metadata.atom).getSymbol(self).value;
1766 if (decl_alignment.check(existing_addr))1803 if (decl_alignment.check(existing_addr))
1767 return .ok;1804 return .ok;
1768 }1805 }
...@@ -1792,14 +1829,14 @@ pub fn lowerAnonDecl(...@@ -1792,14 +1829,14 @@ pub fn lowerAnonDecl(
1792 .ok => |atom_index| atom_index,1829 .ok => |atom_index| atom_index,
1793 .fail => |em| return .{ .fail = em },1830 .fail => |em| return .{ .fail = em },
1794 };1831 };
1795 try self.anon_decls.put(gpa, decl_val, atom_index);1832 try self.anon_decls.put(gpa, decl_val, .{ .atom = atom_index, .section = self.rdata_section_index.? });
1796 return .ok;1833 return .ok;
1797}1834}
17981835
1799pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {1836pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1800 assert(self.llvm_object == null);1837 assert(self.llvm_object == null);
18011838
1802 const this_atom_index = self.anon_decls.get(decl_val).?;1839 const this_atom_index = self.anon_decls.get(decl_val).?.atom;
1803 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;1840 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1804 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;1841 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1805 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };1842 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
...@@ -2447,6 +2484,11 @@ const GetOrPutGlobalPtrResult = struct {...@@ -2447,6 +2484,11 @@ const GetOrPutGlobalPtrResult = struct {
2447 value_ptr: *SymbolWithLoc,2484 value_ptr: *SymbolWithLoc,
2448};2485};
24492486
2487/// Used only for disambiguating local from global at relocation level.
2488/// TODO this must go away.
2489pub const global_symbol_bit: u32 = 0x80000000;
2490pub const global_symbol_mask: u32 = 0x7fffffff;
2491
2450/// Return pointer to the global entry for `name` if one exists.2492/// Return pointer to the global entry for `name` if one exists.
2451/// Puts a new global entry for `name` if one doesn't exist, and2493/// Puts a new global entry for `name` if one doesn't exist, and
2452/// returns a pointer to it.2494/// returns a pointer to it.
src/link/Elf.zig+69-48
...@@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},...@@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
185lazy_syms: LazySymbolTable = .{},185lazy_syms: LazySymbolTable = .{},
186186
187/// Table of tracked Decls.187/// Table of tracked Decls.
188decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},188decls: DeclTable = .{},
189189
190/// List of atoms that are owned directly by the linker.190/// List of atoms that are owned directly by the linker.
191atoms: std.ArrayListUnmanaged(Atom) = .{},191atoms: std.ArrayListUnmanaged(Atom) = .{},
192/// Table of last atom index in a section and matching atom free list if any.192/// Table of last atom index in a section and matching atom free list if any.
193last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{},193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
194194
195/// Table of unnamed constants associated with a parent `Decl`.195/// Table of unnamed constants associated with a parent `Decl`.
196/// We store them here so that we can free the constants whenever the `Decl`196/// We store them here so that we can free the constants whenever the `Decl`
...@@ -220,8 +220,10 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}...@@ -220,8 +220,10 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
220220
221const AtomList = std.ArrayListUnmanaged(Atom.Index);221const AtomList = std.ArrayListUnmanaged(Atom.Index);
222const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));222const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
223const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);223const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
224const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
224const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);225const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
226const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
225227
226/// When allocating, the ideal_capacity is calculated by228/// When allocating, the ideal_capacity is calculated by
227/// actual_capacity + (actual_capacity / ideal_factor)229/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {...@@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {
445 }447 }
446 self.unnamed_consts.deinit(gpa);448 self.unnamed_consts.deinit(gpa);
447 }449 }
448 self.anon_decls.deinit(gpa);450
451 {
452 var it = self.anon_decls.iterator();
453 while (it.next()) |entry| {
454 entry.value_ptr.exports.deinit(gpa);
455 }
456 self.anon_decls.deinit(gpa);
457 }
449458
450 if (self.dwarf) |*dw| {459 if (self.dwarf) |*dw| {
451 dw.deinit();460 dw.deinit();
...@@ -497,8 +506,8 @@ pub fn lowerAnonDecl(...@@ -497,8 +506,8 @@ pub fn lowerAnonDecl(
497 .none => ty.abiAlignment(mod),506 .none => ty.abiAlignment(mod),
498 else => explicit_alignment,507 else => explicit_alignment,
499 };508 };
500 if (self.anon_decls.get(decl_val)) |sym_index| {509 if (self.anon_decls.get(decl_val)) |metadata| {
501 const existing_alignment = self.symbol(sym_index).atom(self).?.alignment;510 const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
502 if (decl_alignment.order(existing_alignment).compare(.lte))511 if (decl_alignment.order(existing_alignment).compare(.lte))
503 return .ok;512 return .ok;
504 }513 }
...@@ -528,13 +537,13 @@ pub fn lowerAnonDecl(...@@ -528,13 +537,13 @@ pub fn lowerAnonDecl(
528 .ok => |sym_index| sym_index,537 .ok => |sym_index| sym_index,
529 .fail => |em| return .{ .fail = em },538 .fail => |em| return .{ .fail = em },
530 };539 };
531 try self.anon_decls.put(gpa, decl_val, sym_index);540 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
532 return .ok;541 return .ok;
533}542}
534543
535pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {544pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
536 assert(self.llvm_object == null);545 assert(self.llvm_object == null);
537 const sym_index = self.anon_decls.get(decl_val).?;546 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
538 const sym = self.symbol(sym_index);547 const sym = self.symbol(sym_index);
539 const vaddr = sym.value;548 const vaddr = sym.value;
540 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;549 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
...@@ -3122,10 +3131,7 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy...@@ -3122,10 +3131,7 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
3122 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);3131 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
3123 if (!gop.found_existing) {3132 if (!gop.found_existing) {
3124 const zig_module = self.file(self.zig_module_index.?).?.zig_module;3133 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3125 gop.value_ptr.* = .{3134 gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) };
3126 .symbol_index = try zig_module.addAtom(self),
3127 .exports = .{},
3128 };
3129 }3135 }
3130 return gop.value_ptr.symbol_index;3136 return gop.value_ptr.symbol_index;
3131}3137}
...@@ -3573,31 +3579,43 @@ pub fn updateExports(...@@ -3573,31 +3579,43 @@ pub fn updateExports(
3573 defer tracy.end();3579 defer tracy.end();
35743580
3575 const gpa = self.base.allocator;3581 const gpa = self.base.allocator;
35763582 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3577 const decl_index = switch (exported) {3583 const metadata = switch (exported) {
3578 .decl_index => |i| i,3584 .decl_index => |decl_index| blk: {
3579 .value => |val| {3585 _ = try self.getOrCreateMetadataForDecl(decl_index);
3580 _ = val;3586 break :blk self.decls.getPtr(decl_index).?;
3581 @panic("TODO: implement ELF linker code for exporting a constant value");3587 },
3588 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
3589 const first_exp = exports[0];
3590 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
3591 switch (res) {
3592 .ok => {},
3593 .fail => |em| {
3594 // TODO maybe it's enough to return an error here and let Module.processExportsInner
3595 // handle the error?
3596 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3597 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
3598 return;
3599 },
3600 }
3601 break :blk self.anon_decls.getPtr(value).?;
3582 },3602 },
3583 };3603 };
3584 const zig_module = self.file(self.zig_module_index.?).?.zig_module;3604 const sym_index = metadata.symbol_index;
3585 const decl = mod.declPtr(decl_index);3605 const esym_index = self.symbol(sym_index).esym_index;
3586 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);3606 const esym = zig_module.local_esyms.items(.elf_sym)[esym_index];
3587 const decl_esym_index = self.symbol(decl_sym_index).esym_index;3607 const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index];
3588 const decl_esym = zig_module.local_esyms.items(.elf_sym)[decl_esym_index];
3589 const decl_esym_shndx = zig_module.local_esyms.items(.shndx)[decl_esym_index];
3590 const decl_metadata = self.decls.getPtr(decl_index).?;
35913608
3592 for (exports) |exp| {3609 for (exports) |exp| {
3593 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3594 if (exp.opts.section.unwrap()) |section_name| {3610 if (exp.opts.section.unwrap()) |section_name| {
3595 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {3611 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
3596 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);3612 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3597 mod.failed_exports.putAssumeCapacityNoClobber(3613 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3598 exp,3614 gpa,
3599 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}),3615 exp.getSrcLoc(mod),
3600 );3616 "Unimplemented: ExportOptions.section",
3617 .{},
3618 ));
3601 continue;3619 continue;
3602 }3620 }
3603 }3621 }
...@@ -3607,34 +3625,37 @@ pub fn updateExports(...@@ -3607,34 +3625,37 @@ pub fn updateExports(
3607 .Weak => elf.STB_WEAK,3625 .Weak => elf.STB_WEAK,
3608 .LinkOnce => {3626 .LinkOnce => {
3609 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);3627 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3610 mod.failed_exports.putAssumeCapacityNoClobber(3628 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3611 exp,3629 gpa,
3612 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}),3630 exp.getSrcLoc(mod),
3613 );3631 "Unimplemented: GlobalLinkage.LinkOnce",
3632 .{},
3633 ));
3614 continue;3634 continue;
3615 },3635 },
3616 };3636 };
3617 const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));3637 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
36183638 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3619 const name_off = try self.strtab.insert(gpa, exp_name);3639 const name_off = try self.strtab.insert(gpa, exp_name);
3620 const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {3640 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3621 const sym_index = try zig_module.addGlobalEsym(gpa);3641 const global_esym_index = try zig_module.addGlobalEsym(gpa);
3622 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);3642 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
3623 const esym = zig_module.elfSym(sym_index);3643 const global_esym = zig_module.elfSym(global_esym_index);
3624 esym.st_name = name_off;3644 global_esym.st_name = name_off;
3625 lookup_gop.value_ptr.* = sym_index;3645 lookup_gop.value_ptr.* = global_esym_index;
3626 try decl_metadata.exports.append(gpa, sym_index);3646 try metadata.exports.append(gpa, global_esym_index);
3627 const gop = try self.getOrPutGlobal(name_off);3647 const gop = try self.getOrPutGlobal(name_off);
3628 try zig_module.global_symbols.append(gpa, gop.index);3648 try zig_module.global_symbols.append(gpa, gop.index);
3629 break :blk sym_index;3649 break :blk global_esym_index;
3630 };3650 };
3631 const global_esym_index = sym_index & ZigModule.symbol_mask;3651
3632 const global_esym = &zig_module.global_esyms.items(.elf_sym)[global_esym_index];3652 const actual_esym_index = global_esym_index & ZigModule.symbol_mask;
3633 global_esym.st_value = self.symbol(decl_sym_index).value;3653 const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index];
3634 global_esym.st_shndx = decl_esym.st_shndx;3654 global_esym.st_value = self.symbol(sym_index).value;
3655 global_esym.st_shndx = esym.st_shndx;
3635 global_esym.st_info = (stb_bits << 4) | stt_bits;3656 global_esym.st_info = (stb_bits << 4) | stt_bits;
3636 global_esym.st_name = name_off;3657 global_esym.st_name = name_off;
3637 zig_module.global_esyms.items(.shndx)[global_esym_index] = decl_esym_shndx;3658 zig_module.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
3638 }3659 }
3639}3660}
36403661
src/link/MachO.zig+140-92
...@@ -50,7 +50,7 @@ tlv_ptr_section_index: ?u8 = null,...@@ -50,7 +50,7 @@ tlv_ptr_section_index: ?u8 = null,
50locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},50locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
51globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},51globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
52resolver: std.StringHashMapUnmanaged(u32) = .{},52resolver: std.StringHashMapUnmanaged(u32) = .{},
53unresolved: std.AutoArrayHashMapUnmanaged(u32, ResolveAction.Kind) = .{},53unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
5454
55locals_free_list: std.ArrayListUnmanaged(u32) = .{},55locals_free_list: std.ArrayListUnmanaged(u32) = .{},
56globals_free_list: std.ArrayListUnmanaged(u32) = .{},56globals_free_list: std.ArrayListUnmanaged(u32) = .{},
...@@ -115,6 +115,10 @@ anon_decls: AnonDeclTable = .{},...@@ -115,6 +115,10 @@ anon_decls: AnonDeclTable = .{},
115/// Note that once we refactor `Atom`'s lifetime and ownership rules,115/// Note that once we refactor `Atom`'s lifetime and ownership rules,
116/// this will be a table indexed by index into the list of Atoms.116/// this will be a table indexed by index into the list of Atoms.
117relocs: RelocationTable = .{},117relocs: RelocationTable = .{},
118/// TODO I do not have time to make this right but this will go once
119/// MachO linker is rewritten more-or-less to feature the same resolution
120/// mechanism as the ELF linker.
121actions: ActionTable = .{},
118122
119/// A table of rebases indexed by the owning them `Atom`.123/// A table of rebases indexed by the owning them `Atom`.
120/// Note that once we refactor `Atom`'s lifetime and ownership rules,124/// Note that once we refactor `Atom`'s lifetime and ownership rules,
...@@ -130,7 +134,7 @@ bindings: BindingTable = .{},...@@ -130,7 +134,7 @@ bindings: BindingTable = .{},
130lazy_syms: LazySymbolTable = .{},134lazy_syms: LazySymbolTable = .{},
131135
132/// Table of tracked Decls.136/// Table of tracked Decls.
133decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},137decls: DeclTable = .{},
134138
135/// Table of threadlocal variables descriptors.139/// Table of threadlocal variables descriptors.
136/// They are emitted in the `__thread_vars` section.140/// They are emitted in the `__thread_vars` section.
...@@ -417,9 +421,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -417,9 +421,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
417 try self.parseDependentLibs(&dependent_libs);421 try self.parseDependentLibs(&dependent_libs);
418 }422 }
419423
420 var actions = std.ArrayList(ResolveAction).init(self.base.allocator);424 try self.resolveSymbols();
421 defer actions.deinit();
422 try self.resolveSymbols(&actions);
423425
424 if (self.getEntryPoint() == null) {426 if (self.getEntryPoint() == null) {
425 self.error_flags.no_entry_point_found = true;427 self.error_flags.no_entry_point_found = true;
...@@ -429,11 +431,16 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -429,11 +431,16 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
429 return error.FlushFailure;431 return error.FlushFailure;
430 }432 }
431433
432 for (actions.items) |action| switch (action.kind) {434 {
433 .none => {},435 var it = self.actions.iterator();
434 .add_got => try self.addGotEntry(action.target),436 while (it.next()) |entry| {
435 .add_stub => try self.addStubEntry(action.target),437 const global_index = entry.key_ptr.*;
436 };438 const global = self.globals.items[global_index];
439 const flags = entry.value_ptr.*;
440 if (flags.add_got) try self.addGotEntry(global);
441 if (flags.add_stub) try self.addStubEntry(global);
442 }
443 }
437444
438 try self.createDyldPrivateAtom();445 try self.createDyldPrivateAtom();
439 try self.writeStubHelperPreamble();446 try self.writeStubHelperPreamble();
...@@ -1589,18 +1596,18 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {...@@ -1589,18 +1596,18 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {
1589 _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);1596 _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);
1590}1597}
15911598
1592pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void {1599pub fn resolveSymbols(self: *MachO) !void {
1593 // We add the specified entrypoint as the first unresolved symbols so that1600 // We add the specified entrypoint as the first unresolved symbols so that
1594 // we search for it in libraries should there be no object files specified1601 // we search for it in libraries should there be no object files specified
1595 // on the linker line.1602 // on the linker line.
1596 if (self.base.options.output_mode == .Exe) {1603 if (self.base.options.output_mode == .Exe) {
1597 const entry_name = self.base.options.entry orelse load_commands.default_entry_point;1604 const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
1598 _ = try self.addUndefined(entry_name, .none);1605 _ = try self.addUndefined(entry_name, .{});
1599 }1606 }
16001607
1601 // Force resolution of any symbols requested by the user.1608 // Force resolution of any symbols requested by the user.
1602 for (self.base.options.force_undefined_symbols.keys()) |sym_name| {1609 for (self.base.options.force_undefined_symbols.keys()) |sym_name| {
1603 _ = try self.addUndefined(sym_name, .none);1610 _ = try self.addUndefined(sym_name, .{});
1604 }1611 }
16051612
1606 for (self.objects.items, 0..) |_, object_id| {1613 for (self.objects.items, 0..) |_, object_id| {
...@@ -1612,13 +1619,13 @@ pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !voi...@@ -1612,13 +1619,13 @@ pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !voi
1612 // Finally, force resolution of dyld_stub_binder if there are imports1619 // Finally, force resolution of dyld_stub_binder if there are imports
1613 // requested.1620 // requested.
1614 if (self.unresolved.count() > 0 and self.dyld_stub_binder_index == null) {1621 if (self.unresolved.count() > 0 and self.dyld_stub_binder_index == null) {
1615 self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);1622 self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .{ .add_got = true });
1616 }1623 }
1617 if (!self.base.options.single_threaded and self.mode == .incremental) {1624 if (!self.base.options.single_threaded and self.mode == .incremental) {
1618 _ = try self.addUndefined("__tlv_bootstrap", .none);1625 _ = try self.addUndefined("__tlv_bootstrap", .{});
1619 }1626 }
16201627
1621 try self.resolveSymbolsInDylibs(actions);1628 try self.resolveSymbolsInDylibs();
16221629
1623 try self.createMhExecuteHeaderSymbol();1630 try self.createMhExecuteHeaderSymbol();
1624 try self.createDsoHandleSymbol();1631 try self.createDsoHandleSymbol();
...@@ -1634,7 +1641,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {...@@ -1634,7 +1641,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
1634 if (!gop.found_existing) {1641 if (!gop.found_existing) {
1635 gop.value_ptr.* = current;1642 gop.value_ptr.* = current;
1636 if (sym.undf() and !sym.tentative()) {1643 if (sym.undf() and !sym.tentative()) {
1637 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, .none);1644 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, {});
1638 }1645 }
1639 return;1646 return;
1640 }1647 }
...@@ -1766,7 +1773,7 @@ fn resolveSymbolsInArchives(self: *MachO) !void {...@@ -1766,7 +1773,7 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
1766 }1773 }
1767}1774}
17681775
1769fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void {1776fn resolveSymbolsInDylibs(self: *MachO) !void {
1770 if (self.dylibs.items.len == 0) return;1777 if (self.dylibs.items.len == 0) return;
17711778
1772 const gpa = self.base.allocator;1779 const gpa = self.base.allocator;
...@@ -1793,11 +1800,7 @@ fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction))...@@ -1793,11 +1800,7 @@ fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction))
1793 sym.n_desc |= macho.N_WEAK_REF;1800 sym.n_desc |= macho.N_WEAK_REF;
1794 }1801 }
17951802
1796 if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: {1803 _ = self.unresolved.swapRemove(global_index);
1797 if (!sym.undf()) break :blk;
1798 if (self.mode == .zld) break :blk;
1799 try actions.append(.{ .kind = entry.value, .target = global });
1800 }
18011804
1802 continue :loop;1805 continue :loop;
1803 }1806 }
...@@ -1904,6 +1907,7 @@ pub fn deinit(self: *MachO) void {...@@ -1904,6 +1907,7 @@ pub fn deinit(self: *MachO) void {
1904 m.exports.deinit(gpa);1907 m.exports.deinit(gpa);
1905 }1908 }
1906 self.decls.deinit(gpa);1909 self.decls.deinit(gpa);
1910
1907 self.lazy_syms.deinit(gpa);1911 self.lazy_syms.deinit(gpa);
1908 self.tlv_table.deinit(gpa);1912 self.tlv_table.deinit(gpa);
19091913
...@@ -1911,7 +1915,14 @@ pub fn deinit(self: *MachO) void {...@@ -1911,7 +1915,14 @@ pub fn deinit(self: *MachO) void {
1911 atoms.deinit(gpa);1915 atoms.deinit(gpa);
1912 }1916 }
1913 self.unnamed_const_atoms.deinit(gpa);1917 self.unnamed_const_atoms.deinit(gpa);
1914 self.anon_decls.deinit(gpa);1918
1919 {
1920 var it = self.anon_decls.iterator();
1921 while (it.next()) |entry| {
1922 entry.value_ptr.exports.deinit(gpa);
1923 }
1924 self.anon_decls.deinit(gpa);
1925 }
19151926
1916 self.atom_by_index_table.deinit(gpa);1927 self.atom_by_index_table.deinit(gpa);
19171928
...@@ -1919,6 +1930,7 @@ pub fn deinit(self: *MachO) void {...@@ -1919,6 +1930,7 @@ pub fn deinit(self: *MachO) void {
1919 relocs.deinit(gpa);1930 relocs.deinit(gpa);
1920 }1931 }
1921 self.relocs.deinit(gpa);1932 self.relocs.deinit(gpa);
1933 self.actions.deinit(gpa);
19221934
1923 for (self.rebases.values()) |*rebases| {1935 for (self.rebases.values()) |*rebases| {
1924 rebases.deinit(gpa);1936 rebases.deinit(gpa);
...@@ -2258,6 +2270,7 @@ fn lowerConst(...@@ -2258,6 +2270,7 @@ fn lowerConst(
2258 log.debug(" (required alignment 0x{x})", .{required_alignment});2270 log.debug(" (required alignment 0x{x})", .{required_alignment});
22592271
2260 try self.writeAtom(atom_index, code);2272 try self.writeAtom(atom_index, code);
2273 self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
22612274
2262 return .{ .ok = atom_index };2275 return .{ .ok = atom_index };
2263}2276}
...@@ -2273,12 +2286,16 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo...@@ -2273,12 +2286,16 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo
2273 const decl = mod.declPtr(decl_index);2286 const decl = mod.declPtr(decl_index);
22742287
2275 if (decl.val.getExternFunc(mod)) |_| {2288 if (decl.val.getExternFunc(mod)) |_| {
2276 return; // TODO Should we do more when front-end analyzed extern decl?2289 return;
2277 }2290 }
2278 if (decl.val.getVariable(mod)) |variable| {2291
2279 if (variable.is_extern) {2292 if (decl.isExtern(mod)) {
2280 return; // TODO Should we do more when front-end analyzed extern decl?2293 // TODO make this part of getGlobalSymbol
2281 }2294 const name = mod.intern_pool.stringToSlice(decl.name);
2295 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
2296 defer self.base.allocator.free(sym_name);
2297 _ = try self.addUndefined(sym_name, .{ .add_got = true });
2298 return;
2282 }2299 }
22832300
2284 const is_threadlocal = if (decl.val.getVariable(mod)) |variable|2301 const is_threadlocal = if (decl.val.getVariable(mod)) |variable|
...@@ -2689,18 +2706,30 @@ pub fn updateExports(...@@ -2689,18 +2706,30 @@ pub fn updateExports(
26892706
2690 const gpa = self.base.allocator;2707 const gpa = self.base.allocator;
26912708
2692 const decl_index = switch (exported) {2709 const metadata = switch (exported) {
2693 .decl_index => |i| i,2710 .decl_index => |decl_index| blk: {
2694 .value => |val| {2711 _ = try self.getOrCreateAtomForDecl(decl_index);
2695 _ = val;2712 break :blk self.decls.getPtr(decl_index).?;
2696 @panic("TODO: implement MachO linker code for exporting a constant value");2713 },
2714 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
2715 const first_exp = exports[0];
2716 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
2717 switch (res) {
2718 .ok => {},
2719 .fail => |em| {
2720 // TODO maybe it's enough to return an error here and let Module.processExportsInner
2721 // handle the error?
2722 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
2723 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
2724 return;
2725 },
2726 }
2727 break :blk self.anon_decls.getPtr(value).?;
2697 },2728 },
2698 };2729 };
2699 const decl = mod.declPtr(decl_index);2730 const atom_index = metadata.atom;
2700 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
2701 const atom = self.getAtom(atom_index);2731 const atom = self.getAtom(atom_index);
2702 const decl_sym = atom.getSymbol(self);2732 const sym = atom.getSymbol(self);
2703 const decl_metadata = self.decls.getPtr(decl_index).?;
27042733
2705 for (exports) |exp| {2734 for (exports) |exp| {
2706 const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{2735 const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{
...@@ -2712,73 +2741,75 @@ pub fn updateExports(...@@ -2712,73 +2741,75 @@ pub fn updateExports(
27122741
2713 if (exp.opts.section.unwrap()) |section_name| {2742 if (exp.opts.section.unwrap()) |section_name| {
2714 if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {2743 if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
2715 try mod.failed_exports.putNoClobber(2744 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
2716 mod.gpa,2745 gpa,
2717 exp,2746 exp.getSrcLoc(mod),
2718 try Module.ErrorMsg.create(2747 "Unimplemented: ExportOptions.section",
2719 gpa,2748 .{},
2720 decl.srcLoc(mod),2749 ));
2721 "Unimplemented: ExportOptions.section",
2722 .{},
2723 ),
2724 );
2725 continue;2750 continue;
2726 }2751 }
2727 }2752 }
27282753
2729 if (exp.opts.linkage == .LinkOnce) {2754 if (exp.opts.linkage == .LinkOnce) {
2730 try mod.failed_exports.putNoClobber(2755 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
2731 mod.gpa,2756 gpa,
2732 exp,2757 exp.getSrcLoc(mod),
2733 try Module.ErrorMsg.create(2758 "Unimplemented: GlobalLinkage.LinkOnce",
2734 gpa,2759 .{},
2735 decl.srcLoc(mod),2760 ));
2736 "Unimplemented: GlobalLinkage.LinkOnce",
2737 .{},
2738 ),
2739 );
2740 continue;2761 continue;
2741 }2762 }
27422763
2743 const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {2764 const global_sym_index = metadata.getExport(self, exp_name) orelse blk: {
2744 const sym_index = try self.allocateSymbol();2765 const global_sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
2745 try decl_metadata.exports.append(gpa, sym_index);2766 const global = self.globals.items[global_index];
2746 break :blk sym_index;2767 // TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
2768 // pass. This will go away once we abstact away Zig's incremental compilation into
2769 // its own module.
2770 if (global.getFile() == null and self.getSymbol(global).undf()) {
2771 _ = self.unresolved.swapRemove(global_index);
2772 break :ind global.sym_index;
2773 }
2774 break :ind try self.allocateSymbol();
2775 } else try self.allocateSymbol();
2776 try metadata.exports.append(gpa, global_sym_index);
2777 break :blk global_sym_index;
2747 };2778 };
2748 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };2779 const global_sym_loc = SymbolWithLoc{ .sym_index = global_sym_index };
2749 const sym = self.getSymbolPtr(sym_loc);2780 const global_sym = self.getSymbolPtr(global_sym_loc);
2750 sym.* = .{2781 global_sym.* = .{
2751 .n_strx = try self.strtab.insert(gpa, exp_name),2782 .n_strx = try self.strtab.insert(gpa, exp_name),
2752 .n_type = macho.N_SECT | macho.N_EXT,2783 .n_type = macho.N_SECT | macho.N_EXT,
2753 .n_sect = self.text_section_index.? + 1, // TODO what if we export a variable?2784 .n_sect = metadata.section + 1,
2754 .n_desc = 0,2785 .n_desc = 0,
2755 .n_value = decl_sym.n_value,2786 .n_value = sym.n_value,
2756 };2787 };
27572788
2758 switch (exp.opts.linkage) {2789 switch (exp.opts.linkage) {
2759 .Internal => {2790 .Internal => {
2760 // Symbol should be hidden, or in MachO lingo, private extern.2791 // Symbol should be hidden, or in MachO lingo, private extern.
2761 // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.2792 // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
2762 sym.n_type |= macho.N_PEXT;2793 global_sym.n_type |= macho.N_PEXT;
2763 sym.n_desc |= macho.N_WEAK_DEF;2794 global_sym.n_desc |= macho.N_WEAK_DEF;
2764 },2795 },
2765 .Strong => {},2796 .Strong => {},
2766 .Weak => {2797 .Weak => {
2767 // Weak linkage is specified as part of n_desc field.2798 // Weak linkage is specified as part of n_desc field.
2768 // Symbol's n_type is like for a symbol with strong linkage.2799 // Symbol's n_type is like for a symbol with strong linkage.
2769 sym.n_desc |= macho.N_WEAK_DEF;2800 global_sym.n_desc |= macho.N_WEAK_DEF;
2770 },2801 },
2771 else => unreachable,2802 else => unreachable,
2772 }2803 }
27732804
2774 self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {2805 self.resolveGlobalSymbol(global_sym_loc) catch |err| switch (err) {
2775 error.MultipleSymbolDefinitions => {2806 error.MultipleSymbolDefinitions => {
2776 // TODO: this needs rethinking2807 // TODO: this needs rethinking
2777 const global = self.getGlobal(exp_name).?;2808 const global = self.getGlobal(exp_name).?;
2778 if (sym_loc.sym_index != global.sym_index and global.getFile() != null) {2809 if (global_sym_loc.sym_index != global.sym_index and global.getFile() != null) {
2779 _ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(2810 _ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
2780 gpa,2811 gpa,
2781 decl.srcLoc(mod),2812 exp.getSrcLoc(mod),
2782 \\LinkError: symbol '{s}' defined multiple times2813 \\LinkError: symbol '{s}' defined multiple times
2783 ,2814 ,
2784 .{exp_name},2815 .{exp_name},
...@@ -2886,8 +2917,8 @@ pub fn lowerAnonDecl(...@@ -2886,8 +2917,8 @@ pub fn lowerAnonDecl(
2886 .none => ty.abiAlignment(mod),2917 .none => ty.abiAlignment(mod),
2887 else => explicit_alignment,2918 else => explicit_alignment,
2888 };2919 };
2889 if (self.anon_decls.get(decl_val)) |atom_index| {2920 if (self.anon_decls.get(decl_val)) |metadata| {
2890 const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value;2921 const existing_addr = self.getAtom(metadata.atom).getSymbol(self).n_value;
2891 if (decl_alignment.check(existing_addr))2922 if (decl_alignment.check(existing_addr))
2892 return .ok;2923 return .ok;
2893 }2924 }
...@@ -2917,14 +2948,17 @@ pub fn lowerAnonDecl(...@@ -2917,14 +2948,17 @@ pub fn lowerAnonDecl(
2917 .ok => |atom_index| atom_index,2948 .ok => |atom_index| atom_index,
2918 .fail => |em| return .{ .fail = em },2949 .fail => |em| return .{ .fail = em },
2919 };2950 };
2920 try self.anon_decls.put(gpa, decl_val, atom_index);2951 try self.anon_decls.put(gpa, decl_val, .{
2952 .atom = atom_index,
2953 .section = self.data_const_section_index.?,
2954 });
2921 return .ok;2955 return .ok;
2922}2956}
29232957
2924pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {2958pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
2925 assert(self.llvm_object == null);2959 assert(self.llvm_object == null);
29262960
2927 const this_atom_index = self.anon_decls.get(decl_val).?;2961 const this_atom_index = self.anon_decls.get(decl_val).?.atom;
2928 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;2962 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
2929 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;2963 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
2930 try Atom.addRelocation(self, atom_index, .{2964 try Atom.addRelocation(self, atom_index, .{
...@@ -3407,7 +3441,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u...@@ -3407,7 +3441,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u
3407 const gpa = self.base.allocator;3441 const gpa = self.base.allocator;
3408 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});3442 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
3409 defer gpa.free(sym_name);3443 defer gpa.free(sym_name);
3410 return self.addUndefined(sym_name, .add_stub);3444 return self.addUndefined(sym_name, .{ .add_stub = true });
3411}3445}
34123446
3413pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {3447pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
...@@ -4691,13 +4725,16 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {...@@ -4691,13 +4725,16 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
4691 self.hot_state.mach_task = null;4725 self.hot_state.mach_task = null;
4692}4726}
46934727
4694fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32 {4728pub fn addUndefined(self: *MachO, name: []const u8, flags: RelocFlags) !u32 {
4695 const gpa = self.base.allocator;4729 const gpa = self.base.allocator;
46964730
4697 const gop = try self.getOrPutGlobalPtr(name);4731 const gop = try self.getOrPutGlobalPtr(name);
4698 const global_index = self.getGlobalIndex(name).?;4732 const global_index = self.getGlobalIndex(name).?;
46994733
4700 if (gop.found_existing) return global_index;4734 if (gop.found_existing) {
4735 try self.updateRelocActions(global_index, flags);
4736 return global_index;
4737 }
47014738
4702 const sym_index = try self.allocateSymbol();4739 const sym_index = try self.allocateSymbol();
4703 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };4740 const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
...@@ -4705,13 +4742,23 @@ fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32...@@ -4705,13 +4742,23 @@ fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32
47054742
4706 const sym = self.getSymbolPtr(sym_loc);4743 const sym = self.getSymbolPtr(sym_loc);
4707 sym.n_strx = try self.strtab.insert(gpa, name);4744 sym.n_strx = try self.strtab.insert(gpa, name);
4708 sym.n_type = macho.N_UNDF;4745 sym.n_type = macho.N_EXT | macho.N_UNDF;
47094746
4710 try self.unresolved.putNoClobber(gpa, global_index, action);4747 try self.unresolved.putNoClobber(gpa, global_index, {});
4748 try self.updateRelocActions(global_index, flags);
47114749
4712 return global_index;4750 return global_index;
4713}4751}
47144752
4753fn updateRelocActions(self: *MachO, global_index: u32, flags: RelocFlags) !void {
4754 const act_gop = try self.actions.getOrPut(self.base.allocator, global_index);
4755 if (!act_gop.found_existing) {
4756 act_gop.value_ptr.* = .{};
4757 }
4758 act_gop.value_ptr.add_got = act_gop.value_ptr.add_got or flags.add_got;
4759 act_gop.value_ptr.add_stub = act_gop.value_ptr.add_stub or flags.add_stub;
4760}
4761
4715pub fn makeStaticString(bytes: []const u8) [16]u8 {4762pub fn makeStaticString(bytes: []const u8) [16]u8 {
4716 var buf = [_]u8{0} ** 16;4763 var buf = [_]u8{0} ** 16;
4717 @memcpy(buf[0..bytes.len], bytes);4764 @memcpy(buf[0..bytes.len], bytes);
...@@ -4823,6 +4870,11 @@ const GetOrPutGlobalPtrResult = struct {...@@ -4823,6 +4870,11 @@ const GetOrPutGlobalPtrResult = struct {
4823 value_ptr: *SymbolWithLoc,4870 value_ptr: *SymbolWithLoc,
4824};4871};
48254872
4873/// Used only for disambiguating local from global at relocation level.
4874/// TODO this must go away.
4875pub const global_symbol_bit: u32 = 0x80000000;
4876pub const global_symbol_mask: u32 = 0x7fffffff;
4877
4826/// Return pointer to the global entry for `name` if one exists.4878/// Return pointer to the global entry for `name` if one exists.
4827/// Puts a new global entry for `name` if one doesn't exist, and4879/// Puts a new global entry for `name` if one doesn't exist, and
4828/// returns a pointer to it.4880/// returns a pointer to it.
...@@ -5489,21 +5541,17 @@ const DeclMetadata = struct {...@@ -5489,21 +5541,17 @@ const DeclMetadata = struct {
5489 }5541 }
5490};5542};
54915543
5492const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);5544const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
5545const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
5493const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));5546const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
5494const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));5547const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
5495const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));5548const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
5496const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));5549const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
5550const ActionTable = std.AutoHashMapUnmanaged(u32, RelocFlags);
54975551
5498pub const ResolveAction = struct {5552pub const RelocFlags = packed struct {
5499 kind: Kind,5553 add_got: bool = false,
5500 target: SymbolWithLoc,5554 add_stub: bool = false,
5501
5502 const Kind = enum {
5503 none,
5504 add_got,
5505 add_stub,
5506 };
5507};5555};
55085556
5509pub const SymbolWithLoc = extern struct {5557pub const SymbolWithLoc = extern struct {
src/link/MachO/Atom.zig+24-23
...@@ -300,7 +300,7 @@ pub fn resolveRelocations(...@@ -300,7 +300,7 @@ pub fn resolveRelocations(
300 relocs: []*const Relocation,300 relocs: []*const Relocation,
301 code: []u8,301 code: []u8,
302) void {302) void {
303 log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});303 relocs_log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});
304 for (relocs) |reloc| {304 for (relocs) |reloc| {
305 reloc.resolve(macho_file, atom_index, code);305 reloc.resolve(macho_file, atom_index, code);
306 }306 }
...@@ -603,7 +603,7 @@ pub fn resolveRelocs(...@@ -603,7 +603,7 @@ pub fn resolveRelocs(
603 const atom = macho_file.getAtom(atom_index);603 const atom = macho_file.getAtom(atom_index);
604 assert(atom.getFile() != null); // synthetic atoms do not have relocs604 assert(atom.getFile() != null); // synthetic atoms do not have relocs
605605
606 log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{606 relocs_log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{
607 atom.sym_index,607 atom.sym_index,
608 macho_file.getSymbolName(atom.getSymbolWithLoc()),608 macho_file.getSymbolName(atom.getSymbolWithLoc()),
609 });609 });
...@@ -683,7 +683,7 @@ fn resolveRelocsArm64(...@@ -683,7 +683,7 @@ fn resolveRelocsArm64(
683 .ARM64_RELOC_ADDEND => {683 .ARM64_RELOC_ADDEND => {
684 assert(addend == null);684 assert(addend == null);
685685
686 log.debug(" RELA({s}) @ {x} => {x}", .{ @tagName(rel_type), rel.r_address, rel.r_symbolnum });686 relocs_log.debug(" RELA({s}) @ {x} => {x}", .{ @tagName(rel_type), rel.r_address, rel.r_symbolnum });
687687
688 addend = rel.r_symbolnum;688 addend = rel.r_symbolnum;
689 continue;689 continue;
...@@ -691,7 +691,7 @@ fn resolveRelocsArm64(...@@ -691,7 +691,7 @@ fn resolveRelocsArm64(
691 .ARM64_RELOC_SUBTRACTOR => {691 .ARM64_RELOC_SUBTRACTOR => {
692 assert(subtractor == null);692 assert(subtractor == null);
693693
694 log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{694 relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
695 @tagName(rel_type),695 @tagName(rel_type),
696 rel.r_address,696 rel.r_address,
697 rel.r_symbolnum,697 rel.r_symbolnum,
...@@ -719,7 +719,7 @@ fn resolveRelocsArm64(...@@ -719,7 +719,7 @@ fn resolveRelocsArm64(
719 });719 });
720 const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));720 const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));
721721
722 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{722 relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
723 @tagName(rel_type),723 @tagName(rel_type),
724 rel.r_address,724 rel.r_address,
725 target.sym_index,725 target.sym_index,
...@@ -745,11 +745,11 @@ fn resolveRelocsArm64(...@@ -745,11 +745,11 @@ fn resolveRelocsArm64(
745 break :blk getRelocTargetAddress(macho_file, target, is_tlv);745 break :blk getRelocTargetAddress(macho_file, target, is_tlv);
746 };746 };
747747
748 log.debug(" | source_addr = 0x{x}", .{source_addr});748 relocs_log.debug(" | source_addr = 0x{x}", .{source_addr});
749749
750 switch (rel_type) {750 switch (rel_type) {
751 .ARM64_RELOC_BRANCH26 => {751 .ARM64_RELOC_BRANCH26 => {
752 log.debug(" source {s} (object({?})), target {s}", .{752 relocs_log.debug(" source {s} (object({?})), target {s}", .{
753 macho_file.getSymbolName(atom.getSymbolWithLoc()),753 macho_file.getSymbolName(atom.getSymbolWithLoc()),
754 atom.getFile(),754 atom.getFile(),
755 macho_file.getSymbolName(target),755 macho_file.getSymbolName(target),
...@@ -759,7 +759,7 @@ fn resolveRelocsArm64(...@@ -759,7 +759,7 @@ fn resolveRelocsArm64(
759 source_addr,759 source_addr,
760 target_addr,760 target_addr,
761 )) |disp| blk: {761 )) |disp| blk: {
762 log.debug(" | target_addr = 0x{x}", .{target_addr});762 relocs_log.debug(" | target_addr = 0x{x}", .{target_addr});
763 break :blk disp;763 break :blk disp;
764 } else |_| blk: {764 } else |_| blk: {
765 const thunk_index = macho_file.thunk_table.get(atom_index).?;765 const thunk_index = macho_file.thunk_table.get(atom_index).?;
...@@ -769,7 +769,7 @@ fn resolveRelocsArm64(...@@ -769,7 +769,7 @@ fn resolveRelocsArm64(
769 else769 else
770 thunk.getTrampoline(macho_file, .atom, target).?;770 thunk.getTrampoline(macho_file, .atom, target).?;
771 const thunk_addr = macho_file.getSymbol(thunk_sym_loc).n_value;771 const thunk_addr = macho_file.getSymbol(thunk_sym_loc).n_value;
772 log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});772 relocs_log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});
773 break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr);773 break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr);
774 };774 };
775775
...@@ -790,7 +790,7 @@ fn resolveRelocsArm64(...@@ -790,7 +790,7 @@ fn resolveRelocsArm64(
790 => {790 => {
791 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));791 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
792792
793 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});793 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
794794
795 const pages = @as(u21, @bitCast(Relocation.calcNumberOfPages(source_addr, adjusted_target_addr)));795 const pages = @as(u21, @bitCast(Relocation.calcNumberOfPages(source_addr, adjusted_target_addr)));
796 const code = atom_code[rel_offset..][0..4];796 const code = atom_code[rel_offset..][0..4];
...@@ -809,7 +809,7 @@ fn resolveRelocsArm64(...@@ -809,7 +809,7 @@ fn resolveRelocsArm64(
809 .ARM64_RELOC_PAGEOFF12 => {809 .ARM64_RELOC_PAGEOFF12 => {
810 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));810 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
811811
812 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});812 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
813813
814 const code = atom_code[rel_offset..][0..4];814 const code = atom_code[rel_offset..][0..4];
815 if (Relocation.isArithmeticOp(code)) {815 if (Relocation.isArithmeticOp(code)) {
...@@ -848,7 +848,7 @@ fn resolveRelocsArm64(...@@ -848,7 +848,7 @@ fn resolveRelocsArm64(
848 const code = atom_code[rel_offset..][0..4];848 const code = atom_code[rel_offset..][0..4];
849 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));849 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
850850
851 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});851 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
852852
853 const off = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64);853 const off = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64);
854 var inst: aarch64.Instruction = .{854 var inst: aarch64.Instruction = .{
...@@ -866,7 +866,7 @@ fn resolveRelocsArm64(...@@ -866,7 +866,7 @@ fn resolveRelocsArm64(
866 const code = atom_code[rel_offset..][0..4];866 const code = atom_code[rel_offset..][0..4];
867 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));867 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
868868
869 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});869 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
870870
871 const RegInfo = struct {871 const RegInfo = struct {
872 rd: u5,872 rd: u5,
...@@ -923,7 +923,7 @@ fn resolveRelocsArm64(...@@ -923,7 +923,7 @@ fn resolveRelocsArm64(
923 },923 },
924924
925 .ARM64_RELOC_POINTER_TO_GOT => {925 .ARM64_RELOC_POINTER_TO_GOT => {
926 log.debug(" | target_addr = 0x{x}", .{target_addr});926 relocs_log.debug(" | target_addr = 0x{x}", .{target_addr});
927 const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse927 const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse
928 return error.Overflow;928 return error.Overflow;
929 mem.writeIntLittle(u32, atom_code[rel_offset..][0..4], @as(u32, @bitCast(result)));929 mem.writeIntLittle(u32, atom_code[rel_offset..][0..4], @as(u32, @bitCast(result)));
...@@ -951,7 +951,7 @@ fn resolveRelocsArm64(...@@ -951,7 +951,7 @@ fn resolveRelocsArm64(
951 break :blk @as(i64, @intCast(target_addr)) + ptr_addend;951 break :blk @as(i64, @intCast(target_addr)) + ptr_addend;
952 }952 }
953 };953 };
954 log.debug(" | target_addr = 0x{x}", .{result});954 relocs_log.debug(" | target_addr = 0x{x}", .{result});
955955
956 if (rel.r_length == 3) {956 if (rel.r_length == 3) {
957 mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));957 mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));
...@@ -987,7 +987,7 @@ fn resolveRelocsX86(...@@ -987,7 +987,7 @@ fn resolveRelocsX86(
987 .X86_64_RELOC_SUBTRACTOR => {987 .X86_64_RELOC_SUBTRACTOR => {
988 assert(subtractor == null);988 assert(subtractor == null);
989989
990 log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{990 relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
991 @tagName(rel_type),991 @tagName(rel_type),
992 rel.r_address,992 rel.r_address,
993 rel.r_symbolnum,993 rel.r_symbolnum,
...@@ -1015,7 +1015,7 @@ fn resolveRelocsX86(...@@ -1015,7 +1015,7 @@ fn resolveRelocsX86(
1015 });1015 });
1016 const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));1016 const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));
10171017
1018 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{1018 relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
1019 @tagName(rel_type),1019 @tagName(rel_type),
1020 rel.r_address,1020 rel.r_address,
1021 target.sym_index,1021 target.sym_index,
...@@ -1041,13 +1041,13 @@ fn resolveRelocsX86(...@@ -1041,13 +1041,13 @@ fn resolveRelocsX86(
1041 break :blk getRelocTargetAddress(macho_file, target, is_tlv);1041 break :blk getRelocTargetAddress(macho_file, target, is_tlv);
1042 };1042 };
10431043
1044 log.debug(" | source_addr = 0x{x}", .{source_addr});1044 relocs_log.debug(" | source_addr = 0x{x}", .{source_addr});
10451045
1046 switch (rel_type) {1046 switch (rel_type) {
1047 .X86_64_RELOC_BRANCH => {1047 .X86_64_RELOC_BRANCH => {
1048 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);1048 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
1049 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));1049 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
1050 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});1050 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
1051 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);1051 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
1052 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);1052 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
1053 },1053 },
...@@ -1057,7 +1057,7 @@ fn resolveRelocsX86(...@@ -1057,7 +1057,7 @@ fn resolveRelocsX86(
1057 => {1057 => {
1058 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);1058 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
1059 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));1059 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
1060 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});1060 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
1061 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);1061 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
1062 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);1062 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
1063 },1063 },
...@@ -1065,7 +1065,7 @@ fn resolveRelocsX86(...@@ -1065,7 +1065,7 @@ fn resolveRelocsX86(
1065 .X86_64_RELOC_TLV => {1065 .X86_64_RELOC_TLV => {
1066 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);1066 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
1067 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));1067 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
1068 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});1068 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
1069 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);1069 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
10701070
1071 if (macho_file.tlv_ptr_table.lookup.get(target) == null) {1071 if (macho_file.tlv_ptr_table.lookup.get(target) == null) {
...@@ -1101,7 +1101,7 @@ fn resolveRelocsX86(...@@ -1101,7 +1101,7 @@ fn resolveRelocsX86(
11011101
1102 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));1102 const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
11031103
1104 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});1104 relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
11051105
1106 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction);1106 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction);
1107 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);1107 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
...@@ -1129,7 +1129,7 @@ fn resolveRelocsX86(...@@ -1129,7 +1129,7 @@ fn resolveRelocsX86(
1129 break :blk @as(i64, @intCast(target_addr)) + addend;1129 break :blk @as(i64, @intCast(target_addr)) + addend;
1130 }1130 }
1131 };1131 };
1132 log.debug(" | target_addr = 0x{x}", .{result});1132 relocs_log.debug(" | target_addr = 0x{x}", .{result});
11331133
1134 if (rel.r_length == 3) {1134 if (rel.r_length == 3) {
1135 mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));1135 mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));
...@@ -1247,6 +1247,7 @@ const build_options = @import("build_options");...@@ -1247,6 +1247,7 @@ const build_options = @import("build_options");
1247const aarch64 = @import("../../arch/aarch64/bits.zig");1247const aarch64 = @import("../../arch/aarch64/bits.zig");
1248const assert = std.debug.assert;1248const assert = std.debug.assert;
1249const log = std.log.scoped(.link);1249const log = std.log.scoped(.link);
1250const relocs_log = std.log.scoped(.link_relocs);
1250const macho = std.macho;1251const macho = std.macho;
1251const math = std.math;1252const math = std.math;
1252const mem = std.mem;1253const mem = std.mem;
src/link/MachO/Relocation.zig+2-2
...@@ -99,7 +99,7 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -99,7 +99,7 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
99 else => @as(i64, @intCast(target_base_addr)) + self.addend,99 else => @as(i64, @intCast(target_base_addr)) + self.addend,
100 };100 };
101101
102 log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{102 relocs_log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
103 source_addr,103 source_addr,
104 target_addr,104 target_addr,
105 macho_file.getSymbolName(self.target),105 macho_file.getSymbolName(self.target),
...@@ -256,7 +256,7 @@ const Relocation = @This();...@@ -256,7 +256,7 @@ const Relocation = @This();
256const std = @import("std");256const std = @import("std");
257const aarch64 = @import("../../arch/aarch64/bits.zig");257const aarch64 = @import("../../arch/aarch64/bits.zig");
258const assert = std.debug.assert;258const assert = std.debug.assert;
259const log = std.log.scoped(.link);259const relocs_log = std.log.scoped(.link_relocs);
260const macho = std.macho;260const macho = std.macho;
261const math = std.math;261const math = std.math;
262const mem = std.mem;262const mem = std.mem;
src/link/MachO/zld.zig+1-3
...@@ -390,9 +390,7 @@ pub fn linkWithZld(...@@ -390,9 +390,7 @@ pub fn linkWithZld(
390390
391 try macho_file.parseDependentLibs(&dependent_libs);391 try macho_file.parseDependentLibs(&dependent_libs);
392392
393 var actions = std.ArrayList(MachO.ResolveAction).init(gpa);393 try macho_file.resolveSymbols();
394 defer actions.deinit();
395 try macho_file.resolveSymbols(&actions);
396 if (macho_file.unresolved.count() > 0) {394 if (macho_file.unresolved.count() > 0) {
397 try macho_file.reportUndefined();395 try macho_file.reportUndefined();
398 return error.FlushFailure;396 return error.FlushFailure;
test/behavior/export_builtin.zig+8-2
...@@ -54,7 +54,10 @@ test "exporting using field access" {...@@ -54,7 +54,10 @@ test "exporting using field access" {
54test "exporting comptime-known value" {54test "exporting comptime-known value" {
55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_x86_64 and
58 (builtin.target.ofmt != .elf and
59 builtin.target.ofmt != .macho and
60 builtin.target.ofmt != .coff)) return error.SkipZigTest;
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;61 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;62 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;63 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
...@@ -70,7 +73,10 @@ test "exporting comptime-known value" {...@@ -70,7 +73,10 @@ test "exporting comptime-known value" {
70test "exporting comptime var" {73test "exporting comptime var" {
71 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;74 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;76 if (builtin.zig_backend == .stage2_x86_64 and
77 (builtin.target.ofmt != .elf and
78 builtin.target.ofmt != .macho and
79 builtin.target.ofmt != .coff)) return error.SkipZigTest;
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;81 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;82 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;