| author | |
| committer | |
| log | 10d03acdb5ff81c112280854629c9f9032e14330 |
| tree | ed9c38b4c3c6ff17a1eaecacce35114219005bdb |
| parent | 91e117697ad90430d9266203415712b6cc59f669 |
| parent | 324a93e673afcf1bcaac1163379d385952e52a27 |
| signature |
link: implement exporting anon decls10 files changed, 373 insertions(+), 227 deletions(-)
src/arch/x86_64/CodeGen.zig+4-2| ... | ... | @@ -13063,6 +13063,7 @@ fn genExternSymbolRef( |
| 13063 | 13063 | } }, |
| 13064 | 13064 | }); |
| 13065 | 13065 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 13066 | const global_index = try coff_file.getGlobalSymbol(callee, lib); | |
| 13066 | 13067 | _ = try self.addInst(.{ |
| 13067 | 13068 | .tag = .mov, |
| 13068 | 13069 | .ops = .import_reloc, |
| ... | ... | @@ -13070,7 +13071,7 @@ fn genExternSymbolRef( |
| 13070 | 13071 | .r1 = .rax, |
| 13071 | 13072 | .payload = try self.addExtra(bits.Symbol{ |
| 13072 | 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 | 13081 | else => unreachable, |
| 13081 | 13082 | } |
| 13082 | 13083 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 13084 | const global_index = try macho_file.getGlobalSymbol(callee, lib); | |
| 13083 | 13085 | _ = try self.addInst(.{ |
| 13084 | 13086 | .tag = .call, |
| 13085 | 13087 | .ops = .extern_fn_reloc, |
| 13086 | 13088 | .data = .{ .reloc = .{ |
| 13087 | 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 | 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 | 52 | // Add relocation to the decl. |
| 53 | 53 | const atom_index = |
| 54 | 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 | 59 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ |
| 57 | 60 | .type = .branch, |
| 58 | 61 | .target = target, |
| ... | ... | @@ -66,7 +69,10 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 66 | 69 | const atom_index = coff_file.getAtomIndexForSymbol( |
| 67 | 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 | 76 | try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ |
| 71 | 77 | .type = .direct, |
| 72 | 78 | .target = target, |
| ... | ... | @@ -116,6 +122,10 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 116 | 122 | } else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| { |
| 117 | 123 | const atom_index = |
| 118 | 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 | 129 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ |
| 120 | 130 | .type = switch (lowered_relocs[0].target) { |
| 121 | 131 | .linker_got => .got, |
| ... | ... | @@ -123,7 +133,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 123 | 133 | .linker_tlv => .tlv, |
| 124 | 134 | else => unreachable, |
| 125 | 135 | }, |
| 126 | .target = .{ .sym_index = symbol.sym_index }, | |
| 136 | .target = target, | |
| 127 | 137 | .offset = @as(u32, @intCast(end_offset - 4)), |
| 128 | 138 | .addend = 0, |
| 129 | 139 | .pcrel = true, |
| ... | ... | @@ -134,6 +144,10 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 134 | 144 | .sym_index = symbol.atom_index, |
| 135 | 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 | 151 | try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ |
| 138 | 152 | .type = switch (lowered_relocs[0].target) { |
| 139 | 153 | .linker_got => .got, |
| ... | ... | @@ -141,13 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 141 | 155 | .linker_import => .import, |
| 142 | 156 | else => unreachable, |
| 143 | 157 | }, |
| 144 | .target = switch (lowered_relocs[0].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 | }, | |
| 158 | .target = target, | |
| 151 | 159 | .offset = @as(u32, @intCast(end_offset - 4)), |
| 152 | 160 | .addend = 0, |
| 153 | 161 | .pcrel = true, |
src/codegen.zig+20| ... | ... | @@ -721,6 +721,7 @@ fn lowerAnonDeclRef( |
| 721 | 721 | const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8); |
| 722 | 722 | const decl_val = anon_decl.val; |
| 723 | 723 | const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); |
| 724 | log.debug("lowerAnonDecl: ty = {}", .{decl_ty.fmt(mod)}); | |
| 724 | 725 | const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn; |
| 725 | 726 | if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) { |
| 726 | 727 | try code.appendNTimes(0xaa, ptr_width_bytes); |
| ... | ... | @@ -911,6 +912,14 @@ fn genDeclRef( |
| 911 | 912 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); |
| 912 | 913 | return GenResult.mcv(.{ .load_symbol = sym.esym_index }); |
| 913 | 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 | 923 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); |
| 915 | 924 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 916 | 925 | if (is_threadlocal) { |
| ... | ... | @@ -918,6 +927,17 @@ fn genDeclRef( |
| 918 | 927 | } |
| 919 | 928 | return GenResult.mcv(.{ .load_got = sym_index }); |
| 920 | 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 | 941 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); |
| 922 | 942 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 923 | 943 | return GenResult.mcv(.{ .load_got = sym_index }); |
src/link/Coff.zig+87-45| ... | ... | @@ -28,6 +28,7 @@ locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, |
| 28 | 28 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 29 | 29 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 30 | 30 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 31 | need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{}, | |
| 31 | 32 | |
| 32 | 33 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 33 | 34 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | ... | @@ -54,7 +55,7 @@ entry_addr: ?u32 = null, |
| 54 | 55 | lazy_syms: LazySymbolTable = .{}, |
| 55 | 56 | |
| 56 | 57 | /// Table of tracked Decls. |
| 57 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | |
| 58 | decls: DeclTable = .{}, | |
| 58 | 59 | |
| 59 | 60 | /// List of atoms that are either synthetic or map directly to the Zig source program. |
| 60 | 61 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| ... | ... | @@ -108,7 +109,8 @@ const HotUpdateState = struct { |
| 108 | 109 | loaded_base_address: ?std.os.windows.HMODULE = null, |
| 109 | 110 | }; |
| 110 | 111 | |
| 111 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index); | |
| 112 | const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata); | |
| 113 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); | |
| 112 | 114 | const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 113 | 115 | const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 114 | 116 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| ... | ... | @@ -325,7 +327,14 @@ pub fn deinit(self: *Coff) void { |
| 325 | 327 | atoms.deinit(gpa); |
| 326 | 328 | } |
| 327 | 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 | } | |
| 329 | 338 | |
| 330 | 339 | for (self.relocs.values()) |*relocs| { |
| 331 | 340 | relocs.deinit(gpa); |
| ... | ... | @@ -1160,12 +1169,17 @@ pub fn updateDecl( |
| 1160 | 1169 | const decl = mod.declPtr(decl_index); |
| 1161 | 1170 | |
| 1162 | 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| { | |
| 1166 | if (variable.is_extern) { | |
| 1167 | return; // TODO Should we do more when front-end analyzed extern decl? | |
| 1168 | } | |
| 1174 | ||
| 1175 | if (decl.isExtern(mod)) { | |
| 1176 | // TODO make this part of getGlobalSymbol | |
| 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 | } |
| 1170 | 1184 | |
| 1171 | 1185 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); |
| ... | ... | @@ -1462,62 +1476,77 @@ pub fn updateExports( |
| 1462 | 1476 | |
| 1463 | 1477 | const gpa = self.base.allocator; |
| 1464 | 1478 | |
| 1465 | const decl_index = switch (exported) { | |
| 1466 | .decl_index => |i| i, | |
| 1467 | .value => |val| { | |
| 1468 | _ = val; | |
| 1469 | @panic("TODO: implement COFF linker code for exporting a constant value"); | |
| 1479 | const metadata = switch (exported) { | |
| 1480 | .decl_index => |decl_index| blk: { | |
| 1481 | _ = try self.getOrCreateAtomForDecl(decl_index); | |
| 1482 | break :blk self.decls.getPtr(decl_index).?; | |
| 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); | |
| 1473 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | |
| 1500 | const atom_index = metadata.atom; | |
| 1474 | 1501 | const atom = self.getAtom(atom_index); |
| 1475 | const decl_metadata = self.decls.getPtr(decl_index).?; | |
| 1476 | 1502 | |
| 1477 | 1503 | for (exports) |exp| { |
| 1478 | 1504 | log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)}); |
| 1479 | 1505 | |
| 1480 | 1506 | if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| { |
| 1481 | 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 | 1509 | gpa, |
| 1484 | exp, | |
| 1485 | try Module.ErrorMsg.create( | |
| 1486 | gpa, | |
| 1487 | decl.srcLoc(mod), | |
| 1488 | "Unimplemented: ExportOptions.section", | |
| 1489 | .{}, | |
| 1490 | ), | |
| 1491 | ); | |
| 1510 | exp.getSrcLoc(mod), | |
| 1511 | "Unimplemented: ExportOptions.section", | |
| 1512 | .{}, | |
| 1513 | )); | |
| 1492 | 1514 | continue; |
| 1493 | 1515 | } |
| 1494 | 1516 | } |
| 1495 | 1517 | |
| 1496 | 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 | 1520 | gpa, |
| 1499 | exp, | |
| 1500 | try Module.ErrorMsg.create( | |
| 1501 | gpa, | |
| 1502 | decl.srcLoc(mod), | |
| 1503 | "Unimplemented: GlobalLinkage.LinkOnce", | |
| 1504 | .{}, | |
| 1505 | ), | |
| 1506 | ); | |
| 1521 | exp.getSrcLoc(mod), | |
| 1522 | "Unimplemented: GlobalLinkage.LinkOnce", | |
| 1523 | .{}, | |
| 1524 | )); | |
| 1507 | 1525 | continue; |
| 1508 | 1526 | } |
| 1509 | 1527 | |
| 1510 | const sym_index = decl_metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: { | |
| 1511 | const sym_index = try self.allocateSymbol(); | |
| 1512 | try decl_metadata.exports.append(gpa, sym_index); | |
| 1528 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 1529 | const sym_index = metadata.getExport(self, exp_name) orelse blk: { | |
| 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 | 1542 | break :blk sym_index; |
| 1514 | 1543 | }; |
| 1515 | 1544 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| 1516 | 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 | 1547 | sym.value = atom.getSymbol(self).value; |
| 1519 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.text_section_index.? + 1)); | |
| 1520 | sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL }; | |
| 1548 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1)); | |
| 1549 | sym.type = atom.getSymbol(self).type; | |
| 1521 | 1550 | |
| 1522 | 1551 | switch (exp.opts.linkage) { |
| 1523 | 1552 | .Strong => { |
| ... | ... | @@ -1651,8 +1680,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1651 | 1680 | if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; |
| 1652 | 1681 | } |
| 1653 | 1682 | |
| 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 | 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 | 1693 | const global = self.globals.items[entry.key]; |
| 1657 | 1694 | const sym = self.getSymbol(global); |
| 1658 | 1695 | const res = try self.import_tables.getOrPut(gpa, sym.value); |
| ... | ... | @@ -1761,8 +1798,8 @@ pub fn lowerAnonDecl( |
| 1761 | 1798 | .none => ty.abiAlignment(mod), |
| 1762 | 1799 | else => explicit_alignment, |
| 1763 | 1800 | }; |
| 1764 | if (self.anon_decls.get(decl_val)) |atom_index| { | |
| 1765 | const existing_addr = self.getAtom(atom_index).getSymbol(self).value; | |
| 1801 | if (self.anon_decls.get(decl_val)) |metadata| { | |
| 1802 | const existing_addr = self.getAtom(metadata.atom).getSymbol(self).value; | |
| 1766 | 1803 | if (decl_alignment.check(existing_addr)) |
| 1767 | 1804 | return .ok; |
| 1768 | 1805 | } |
| ... | ... | @@ -1792,14 +1829,14 @@ pub fn lowerAnonDecl( |
| 1792 | 1829 | .ok => |atom_index| atom_index, |
| 1793 | 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 | 1833 | return .ok; |
| 1797 | 1834 | } |
| 1798 | 1835 | |
| 1799 | 1836 | pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 1800 | 1837 | assert(self.llvm_object == null); |
| 1801 | 1838 | |
| 1802 | const this_atom_index = self.anon_decls.get(decl_val).?; | |
| 1839 | const this_atom_index = self.anon_decls.get(decl_val).?.atom; | |
| 1803 | 1840 | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; |
| 1804 | 1841 | const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; |
| 1805 | 1842 | const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; |
| ... | ... | @@ -2447,6 +2484,11 @@ const GetOrPutGlobalPtrResult = struct { |
| 2447 | 2484 | value_ptr: *SymbolWithLoc, |
| 2448 | 2485 | }; |
| 2449 | 2486 | |
| 2487 | /// Used only for disambiguating local from global at relocation level. | |
| 2488 | /// TODO this must go away. | |
| 2489 | pub const global_symbol_bit: u32 = 0x80000000; | |
| 2490 | pub const global_symbol_mask: u32 = 0x7fffffff; | |
| 2491 | ||
| 2450 | 2492 | /// Return pointer to the global entry for `name` if one exists. |
| 2451 | 2493 | /// Puts a new global entry for `name` if one doesn't exist, and |
| 2452 | 2494 | /// returns a pointer to it. |
src/link/Elf.zig+69-48| ... | ... | @@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{}, |
| 185 | 185 | lazy_syms: LazySymbolTable = .{}, |
| 186 | 186 | |
| 187 | 187 | /// Table of tracked Decls. |
| 188 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | |
| 188 | decls: DeclTable = .{}, | |
| 189 | 189 | |
| 190 | 190 | /// List of atoms that are owned directly by the linker. |
| 191 | 191 | atoms: std.ArrayListUnmanaged(Atom) = .{}, |
| 192 | 192 | /// Table of last atom index in a section and matching atom free list if any. |
| 193 | last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{}, | |
| 193 | last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, | |
| 194 | 194 | |
| 195 | 195 | /// Table of unnamed constants associated with a parent `Decl`. |
| 196 | 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 | 220 | |
| 221 | 221 | const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 222 | 222 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); |
| 223 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index); | |
| 223 | const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata); | |
| 224 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); | |
| 224 | 225 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 226 | const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList); | |
| 225 | 227 | |
| 226 | 228 | /// When allocating, the ideal_capacity is calculated by |
| 227 | 229 | /// actual_capacity + (actual_capacity / ideal_factor) |
| ... | ... | @@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void { |
| 445 | 447 | } |
| 446 | 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 | } | |
| 449 | 458 | |
| 450 | 459 | if (self.dwarf) |*dw| { |
| 451 | 460 | dw.deinit(); |
| ... | ... | @@ -497,8 +506,8 @@ pub fn lowerAnonDecl( |
| 497 | 506 | .none => ty.abiAlignment(mod), |
| 498 | 507 | else => explicit_alignment, |
| 499 | 508 | }; |
| 500 | if (self.anon_decls.get(decl_val)) |sym_index| { | |
| 501 | const existing_alignment = self.symbol(sym_index).atom(self).?.alignment; | |
| 509 | if (self.anon_decls.get(decl_val)) |metadata| { | |
| 510 | const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment; | |
| 502 | 511 | if (decl_alignment.order(existing_alignment).compare(.lte)) |
| 503 | 512 | return .ok; |
| 504 | 513 | } |
| ... | ... | @@ -528,13 +537,13 @@ pub fn lowerAnonDecl( |
| 528 | 537 | .ok => |sym_index| sym_index, |
| 529 | 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 | 541 | return .ok; |
| 533 | 542 | } |
| 534 | 543 | |
| 535 | 544 | pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 536 | 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 | 547 | const sym = self.symbol(sym_index); |
| 539 | 548 | const vaddr = sym.value; |
| 540 | 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 | 3131 | const gop = try self.decls.getOrPut(self.base.allocator, decl_index); |
| 3123 | 3132 | if (!gop.found_existing) { |
| 3124 | 3133 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 3125 | gop.value_ptr.* = .{ | |
| 3126 | .symbol_index = try zig_module.addAtom(self), | |
| 3127 | .exports = .{}, | |
| 3128 | }; | |
| 3134 | gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) }; | |
| 3129 | 3135 | } |
| 3130 | 3136 | return gop.value_ptr.symbol_index; |
| 3131 | 3137 | } |
| ... | ... | @@ -3573,31 +3579,43 @@ pub fn updateExports( |
| 3573 | 3579 | defer tracy.end(); |
| 3574 | 3580 | |
| 3575 | 3581 | const gpa = self.base.allocator; |
| 3576 | ||
| 3577 | const decl_index = switch (exported) { | |
| 3578 | .decl_index => |i| i, | |
| 3579 | .value => |val| { | |
| 3580 | _ = val; | |
| 3581 | @panic("TODO: implement ELF linker code for exporting a constant value"); | |
| 3582 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; | |
| 3583 | const metadata = switch (exported) { | |
| 3584 | .decl_index => |decl_index| blk: { | |
| 3585 | _ = try self.getOrCreateMetadataForDecl(decl_index); | |
| 3586 | break :blk self.decls.getPtr(decl_index).?; | |
| 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; | |
| 3585 | const decl = mod.declPtr(decl_index); | |
| 3586 | const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index); | |
| 3587 | const decl_esym_index = self.symbol(decl_sym_index).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).?; | |
| 3604 | const sym_index = metadata.symbol_index; | |
| 3605 | const esym_index = self.symbol(sym_index).esym_index; | |
| 3606 | const esym = zig_module.local_esyms.items(.elf_sym)[esym_index]; | |
| 3607 | const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index]; | |
| 3591 | 3608 | |
| 3592 | 3609 | for (exports) |exp| { |
| 3593 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 3594 | 3610 | if (exp.opts.section.unwrap()) |section_name| { |
| 3595 | 3611 | if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) { |
| 3596 | 3612 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 3597 | mod.failed_exports.putAssumeCapacityNoClobber( | |
| 3598 | exp, | |
| 3599 | try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}), | |
| 3600 | ); | |
| 3613 | mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create( | |
| 3614 | gpa, | |
| 3615 | exp.getSrcLoc(mod), | |
| 3616 | "Unimplemented: ExportOptions.section", | |
| 3617 | .{}, | |
| 3618 | )); | |
| 3601 | 3619 | continue; |
| 3602 | 3620 | } |
| 3603 | 3621 | } |
| ... | ... | @@ -3607,34 +3625,37 @@ pub fn updateExports( |
| 3607 | 3625 | .Weak => elf.STB_WEAK, |
| 3608 | 3626 | .LinkOnce => { |
| 3609 | 3627 | try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); |
| 3610 | mod.failed_exports.putAssumeCapacityNoClobber( | |
| 3611 | exp, | |
| 3612 | try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}), | |
| 3613 | ); | |
| 3628 | mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create( | |
| 3629 | gpa, | |
| 3630 | exp.getSrcLoc(mod), | |
| 3631 | "Unimplemented: GlobalLinkage.LinkOnce", | |
| 3632 | .{}, | |
| 3633 | )); | |
| 3614 | 3634 | continue; |
| 3615 | 3635 | }, |
| 3616 | 3636 | }; |
| 3617 | const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info)); | |
| 3618 | ||
| 3637 | const stt_bits: u8 = @as(u4, @truncate(esym.st_info)); | |
| 3638 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | |
| 3619 | 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: { | |
| 3621 | const sym_index = try zig_module.addGlobalEsym(gpa); | |
| 3640 | const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: { | |
| 3641 | const global_esym_index = try zig_module.addGlobalEsym(gpa); | |
| 3622 | 3642 | const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off); |
| 3623 | const esym = zig_module.elfSym(sym_index); | |
| 3624 | esym.st_name = name_off; | |
| 3625 | lookup_gop.value_ptr.* = sym_index; | |
| 3626 | try decl_metadata.exports.append(gpa, sym_index); | |
| 3643 | const global_esym = zig_module.elfSym(global_esym_index); | |
| 3644 | global_esym.st_name = name_off; | |
| 3645 | lookup_gop.value_ptr.* = global_esym_index; | |
| 3646 | try metadata.exports.append(gpa, global_esym_index); | |
| 3627 | 3647 | const gop = try self.getOrPutGlobal(name_off); |
| 3628 | 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; | |
| 3632 | const global_esym = &zig_module.global_esyms.items(.elf_sym)[global_esym_index]; | |
| 3633 | global_esym.st_value = self.symbol(decl_sym_index).value; | |
| 3634 | global_esym.st_shndx = decl_esym.st_shndx; | |
| 3651 | ||
| 3652 | const actual_esym_index = global_esym_index & ZigModule.symbol_mask; | |
| 3653 | const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index]; | |
| 3654 | global_esym.st_value = self.symbol(sym_index).value; | |
| 3655 | global_esym.st_shndx = esym.st_shndx; | |
| 3635 | 3656 | global_esym.st_info = (stb_bits << 4) | stt_bits; |
| 3636 | 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 | } |
| 3640 | 3661 |
src/link/MachO.zig+140-92| ... | ... | @@ -50,7 +50,7 @@ tlv_ptr_section_index: ?u8 = null, |
| 50 | 50 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 51 | 51 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 52 | 52 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 53 | unresolved: std.AutoArrayHashMapUnmanaged(u32, ResolveAction.Kind) = .{}, | |
| 53 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, | |
| 54 | 54 | |
| 55 | 55 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 56 | 56 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | ... | @@ -115,6 +115,10 @@ anon_decls: AnonDeclTable = .{}, |
| 115 | 115 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| 116 | 116 | /// this will be a table indexed by index into the list of Atoms. |
| 117 | 117 | relocs: 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. | |
| 121 | actions: ActionTable = .{}, | |
| 118 | 122 | |
| 119 | 123 | /// A table of rebases indexed by the owning them `Atom`. |
| 120 | 124 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| ... | ... | @@ -130,7 +134,7 @@ bindings: BindingTable = .{}, |
| 130 | 134 | lazy_syms: LazySymbolTable = .{}, |
| 131 | 135 | |
| 132 | 136 | /// Table of tracked Decls. |
| 133 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | |
| 137 | decls: DeclTable = .{}, | |
| 134 | 138 | |
| 135 | 139 | /// Table of threadlocal variables descriptors. |
| 136 | 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 | 421 | try self.parseDependentLibs(&dependent_libs); |
| 418 | 422 | } |
| 419 | 423 | |
| 420 | var actions = std.ArrayList(ResolveAction).init(self.base.allocator); | |
| 421 | defer actions.deinit(); | |
| 422 | try self.resolveSymbols(&actions); | |
| 424 | try self.resolveSymbols(); | |
| 423 | 425 | |
| 424 | 426 | if (self.getEntryPoint() == null) { |
| 425 | 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 | 431 | return error.FlushFailure; |
| 430 | 432 | } |
| 431 | 433 | |
| 432 | for (actions.items) |action| switch (action.kind) { | |
| 433 | .none => {}, | |
| 434 | .add_got => try self.addGotEntry(action.target), | |
| 435 | .add_stub => try self.addStubEntry(action.target), | |
| 436 | }; | |
| 434 | { | |
| 435 | var it = self.actions.iterator(); | |
| 436 | while (it.next()) |entry| { | |
| 437 | const global_index = entry.key_ptr.*; | |
| 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 | } | |
| 437 | 444 | |
| 438 | 445 | try self.createDyldPrivateAtom(); |
| 439 | 446 | try self.writeStubHelperPreamble(); |
| ... | ... | @@ -1589,18 +1596,18 @@ pub fn createDsoHandleSymbol(self: *MachO) !void { |
| 1589 | 1596 | _ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?); |
| 1590 | 1597 | } |
| 1591 | 1598 | |
| 1592 | pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void { | |
| 1599 | pub fn resolveSymbols(self: *MachO) !void { | |
| 1593 | 1600 | // We add the specified entrypoint as the first unresolved symbols so that |
| 1594 | 1601 | // we search for it in libraries should there be no object files specified |
| 1595 | 1602 | // on the linker line. |
| 1596 | 1603 | if (self.base.options.output_mode == .Exe) { |
| 1597 | 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 | } |
| 1600 | 1607 | |
| 1601 | 1608 | // Force resolution of any symbols requested by the user. |
| 1602 | 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 | } |
| 1605 | 1612 | |
| 1606 | 1613 | for (self.objects.items, 0..) |_, object_id| { |
| ... | ... | @@ -1612,13 +1619,13 @@ pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !voi |
| 1612 | 1619 | // Finally, force resolution of dyld_stub_binder if there are imports |
| 1613 | 1620 | // requested. |
| 1614 | 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 | 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 | } |
| 1620 | 1627 | |
| 1621 | try self.resolveSymbolsInDylibs(actions); | |
| 1628 | try self.resolveSymbolsInDylibs(); | |
| 1622 | 1629 | |
| 1623 | 1630 | try self.createMhExecuteHeaderSymbol(); |
| 1624 | 1631 | try self.createDsoHandleSymbol(); |
| ... | ... | @@ -1634,7 +1641,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void { |
| 1634 | 1641 | if (!gop.found_existing) { |
| 1635 | 1642 | gop.value_ptr.* = current; |
| 1636 | 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 | 1646 | return; |
| 1640 | 1647 | } |
| ... | ... | @@ -1766,7 +1773,7 @@ fn resolveSymbolsInArchives(self: *MachO) !void { |
| 1766 | 1773 | } |
| 1767 | 1774 | } |
| 1768 | 1775 | |
| 1769 | fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void { | |
| 1776 | fn resolveSymbolsInDylibs(self: *MachO) !void { | |
| 1770 | 1777 | if (self.dylibs.items.len == 0) return; |
| 1771 | 1778 | |
| 1772 | 1779 | const gpa = self.base.allocator; |
| ... | ... | @@ -1793,11 +1800,7 @@ fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) |
| 1793 | 1800 | sym.n_desc |= macho.N_WEAK_REF; |
| 1794 | 1801 | } |
| 1795 | 1802 | |
| 1796 | if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: { | |
| 1797 | if (!sym.undf()) break :blk; | |
| 1798 | if (self.mode == .zld) break :blk; | |
| 1799 | try actions.append(.{ .kind = entry.value, .target = global }); | |
| 1800 | } | |
| 1803 | _ = self.unresolved.swapRemove(global_index); | |
| 1801 | 1804 | |
| 1802 | 1805 | continue :loop; |
| 1803 | 1806 | } |
| ... | ... | @@ -1904,6 +1907,7 @@ pub fn deinit(self: *MachO) void { |
| 1904 | 1907 | m.exports.deinit(gpa); |
| 1905 | 1908 | } |
| 1906 | 1909 | self.decls.deinit(gpa); |
| 1910 | ||
| 1907 | 1911 | self.lazy_syms.deinit(gpa); |
| 1908 | 1912 | self.tlv_table.deinit(gpa); |
| 1909 | 1913 | |
| ... | ... | @@ -1911,7 +1915,14 @@ pub fn deinit(self: *MachO) void { |
| 1911 | 1915 | atoms.deinit(gpa); |
| 1912 | 1916 | } |
| 1913 | 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 | } | |
| 1915 | 1926 | |
| 1916 | 1927 | self.atom_by_index_table.deinit(gpa); |
| 1917 | 1928 | |
| ... | ... | @@ -1919,6 +1930,7 @@ pub fn deinit(self: *MachO) void { |
| 1919 | 1930 | relocs.deinit(gpa); |
| 1920 | 1931 | } |
| 1921 | 1932 | self.relocs.deinit(gpa); |
| 1933 | self.actions.deinit(gpa); | |
| 1922 | 1934 | |
| 1923 | 1935 | for (self.rebases.values()) |*rebases| { |
| 1924 | 1936 | rebases.deinit(gpa); |
| ... | ... | @@ -2258,6 +2270,7 @@ fn lowerConst( |
| 2258 | 2270 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2259 | 2271 | |
| 2260 | 2272 | try self.writeAtom(atom_index, code); |
| 2273 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | |
| 2261 | 2274 | |
| 2262 | 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 | 2286 | const decl = mod.declPtr(decl_index); |
| 2274 | 2287 | |
| 2275 | 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| { | |
| 2279 | if (variable.is_extern) { | |
| 2280 | return; // TODO Should we do more when front-end analyzed extern decl? | |
| 2281 | } | |
| 2291 | ||
| 2292 | if (decl.isExtern(mod)) { | |
| 2293 | // TODO make this part of getGlobalSymbol | |
| 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 | } |
| 2283 | 2300 | |
| 2284 | 2301 | const is_threadlocal = if (decl.val.getVariable(mod)) |variable| |
| ... | ... | @@ -2689,18 +2706,30 @@ pub fn updateExports( |
| 2689 | 2706 | |
| 2690 | 2707 | const gpa = self.base.allocator; |
| 2691 | 2708 | |
| 2692 | const decl_index = switch (exported) { | |
| 2693 | .decl_index => |i| i, | |
| 2694 | .value => |val| { | |
| 2695 | _ = val; | |
| 2696 | @panic("TODO: implement MachO linker code for exporting a constant value"); | |
| 2709 | const metadata = switch (exported) { | |
| 2710 | .decl_index => |decl_index| blk: { | |
| 2711 | _ = try self.getOrCreateAtomForDecl(decl_index); | |
| 2712 | break :blk self.decls.getPtr(decl_index).?; | |
| 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); | |
| 2700 | const atom_index = try self.getOrCreateAtomForDecl(decl_index); | |
| 2730 | const atom_index = metadata.atom; | |
| 2701 | 2731 | const atom = self.getAtom(atom_index); |
| 2702 | const decl_sym = atom.getSymbol(self); | |
| 2703 | const decl_metadata = self.decls.getPtr(decl_index).?; | |
| 2732 | const sym = atom.getSymbol(self); | |
| 2704 | 2733 | |
| 2705 | 2734 | for (exports) |exp| { |
| 2706 | 2735 | const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{ |
| ... | ... | @@ -2712,73 +2741,75 @@ pub fn updateExports( |
| 2712 | 2741 | |
| 2713 | 2742 | if (exp.opts.section.unwrap()) |section_name| { |
| 2714 | 2743 | if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) { |
| 2715 | try mod.failed_exports.putNoClobber( | |
| 2716 | mod.gpa, | |
| 2717 | exp, | |
| 2718 | try Module.ErrorMsg.create( | |
| 2719 | gpa, | |
| 2720 | decl.srcLoc(mod), | |
| 2721 | "Unimplemented: ExportOptions.section", | |
| 2722 | .{}, | |
| 2723 | ), | |
| 2724 | ); | |
| 2744 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 2745 | gpa, | |
| 2746 | exp.getSrcLoc(mod), | |
| 2747 | "Unimplemented: ExportOptions.section", | |
| 2748 | .{}, | |
| 2749 | )); | |
| 2725 | 2750 | continue; |
| 2726 | 2751 | } |
| 2727 | 2752 | } |
| 2728 | 2753 | |
| 2729 | 2754 | if (exp.opts.linkage == .LinkOnce) { |
| 2730 | try mod.failed_exports.putNoClobber( | |
| 2731 | mod.gpa, | |
| 2732 | exp, | |
| 2733 | try Module.ErrorMsg.create( | |
| 2734 | gpa, | |
| 2735 | decl.srcLoc(mod), | |
| 2736 | "Unimplemented: GlobalLinkage.LinkOnce", | |
| 2737 | .{}, | |
| 2738 | ), | |
| 2739 | ); | |
| 2755 | try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( | |
| 2756 | gpa, | |
| 2757 | exp.getSrcLoc(mod), | |
| 2758 | "Unimplemented: GlobalLinkage.LinkOnce", | |
| 2759 | .{}, | |
| 2760 | )); | |
| 2740 | 2761 | continue; |
| 2741 | 2762 | } |
| 2742 | 2763 | |
| 2743 | const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { | |
| 2744 | const sym_index = try self.allocateSymbol(); | |
| 2745 | try decl_metadata.exports.append(gpa, sym_index); | |
| 2746 | break :blk sym_index; | |
| 2764 | const global_sym_index = metadata.getExport(self, exp_name) orelse blk: { | |
| 2765 | const global_sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: { | |
| 2766 | const global = self.globals.items[global_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 }; | |
| 2749 | const sym = self.getSymbolPtr(sym_loc); | |
| 2750 | sym.* = .{ | |
| 2779 | const global_sym_loc = SymbolWithLoc{ .sym_index = global_sym_index }; | |
| 2780 | const global_sym = self.getSymbolPtr(global_sym_loc); | |
| 2781 | global_sym.* = .{ | |
| 2751 | 2782 | .n_strx = try self.strtab.insert(gpa, exp_name), |
| 2752 | 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 | 2785 | .n_desc = 0, |
| 2755 | .n_value = decl_sym.n_value, | |
| 2786 | .n_value = sym.n_value, | |
| 2756 | 2787 | }; |
| 2757 | 2788 | |
| 2758 | 2789 | switch (exp.opts.linkage) { |
| 2759 | 2790 | .Internal => { |
| 2760 | 2791 | // Symbol should be hidden, or in MachO lingo, private extern. |
| 2761 | 2792 | // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. |
| 2762 | sym.n_type |= macho.N_PEXT; | |
| 2763 | sym.n_desc |= macho.N_WEAK_DEF; | |
| 2793 | global_sym.n_type |= macho.N_PEXT; | |
| 2794 | global_sym.n_desc |= macho.N_WEAK_DEF; | |
| 2764 | 2795 | }, |
| 2765 | 2796 | .Strong => {}, |
| 2766 | 2797 | .Weak => { |
| 2767 | 2798 | // Weak linkage is specified as part of n_desc field. |
| 2768 | 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 | 2802 | else => unreachable, |
| 2772 | 2803 | } |
| 2773 | 2804 | |
| 2774 | self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) { | |
| 2805 | self.resolveGlobalSymbol(global_sym_loc) catch |err| switch (err) { | |
| 2775 | 2806 | error.MultipleSymbolDefinitions => { |
| 2776 | 2807 | // TODO: this needs rethinking |
| 2777 | 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 | 2810 | _ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( |
| 2780 | 2811 | gpa, |
| 2781 | decl.srcLoc(mod), | |
| 2812 | exp.getSrcLoc(mod), | |
| 2782 | 2813 | \\LinkError: symbol '{s}' defined multiple times |
| 2783 | 2814 | , |
| 2784 | 2815 | .{exp_name}, |
| ... | ... | @@ -2886,8 +2917,8 @@ pub fn lowerAnonDecl( |
| 2886 | 2917 | .none => ty.abiAlignment(mod), |
| 2887 | 2918 | else => explicit_alignment, |
| 2888 | 2919 | }; |
| 2889 | if (self.anon_decls.get(decl_val)) |atom_index| { | |
| 2890 | const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value; | |
| 2920 | if (self.anon_decls.get(decl_val)) |metadata| { | |
| 2921 | const existing_addr = self.getAtom(metadata.atom).getSymbol(self).n_value; | |
| 2891 | 2922 | if (decl_alignment.check(existing_addr)) |
| 2892 | 2923 | return .ok; |
| 2893 | 2924 | } |
| ... | ... | @@ -2917,14 +2948,17 @@ pub fn lowerAnonDecl( |
| 2917 | 2948 | .ok => |atom_index| atom_index, |
| 2918 | 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 | 2955 | return .ok; |
| 2922 | 2956 | } |
| 2923 | 2957 | |
| 2924 | 2958 | pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 2925 | 2959 | assert(self.llvm_object == null); |
| 2926 | 2960 | |
| 2927 | const this_atom_index = self.anon_decls.get(decl_val).?; | |
| 2961 | const this_atom_index = self.anon_decls.get(decl_val).?.atom; | |
| 2928 | 2962 | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; |
| 2929 | 2963 | const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?; |
| 2930 | 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 | 3441 | const gpa = self.base.allocator; |
| 3408 | 3442 | const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); |
| 3409 | 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 | } |
| 3412 | 3446 | |
| 3413 | 3447 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { |
| ... | ... | @@ -4691,13 +4725,16 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void { |
| 4691 | 4725 | self.hot_state.mach_task = null; |
| 4692 | 4726 | } |
| 4693 | 4727 | |
| 4694 | fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32 { | |
| 4728 | pub fn addUndefined(self: *MachO, name: []const u8, flags: RelocFlags) !u32 { | |
| 4695 | 4729 | const gpa = self.base.allocator; |
| 4696 | 4730 | |
| 4697 | 4731 | const gop = try self.getOrPutGlobalPtr(name); |
| 4698 | 4732 | const global_index = self.getGlobalIndex(name).?; |
| 4699 | 4733 | |
| 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 | } | |
| 4701 | 4738 | |
| 4702 | 4739 | const sym_index = try self.allocateSymbol(); |
| 4703 | 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 | 4742 | |
| 4706 | 4743 | const sym = self.getSymbolPtr(sym_loc); |
| 4707 | 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; | |
| 4709 | 4746 | |
| 4710 | try self.unresolved.putNoClobber(gpa, global_index, action); | |
| 4747 | try self.unresolved.putNoClobber(gpa, global_index, {}); | |
| 4748 | try self.updateRelocActions(global_index, flags); | |
| 4711 | 4749 | |
| 4712 | 4750 | return global_index; |
| 4713 | 4751 | } |
| 4714 | 4752 | |
| 4753 | fn 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 | ||
| 4715 | 4762 | pub fn makeStaticString(bytes: []const u8) [16]u8 { |
| 4716 | 4763 | var buf = [_]u8{0} ** 16; |
| 4717 | 4764 | @memcpy(buf[0..bytes.len], bytes); |
| ... | ... | @@ -4823,6 +4870,11 @@ const GetOrPutGlobalPtrResult = struct { |
| 4823 | 4870 | value_ptr: *SymbolWithLoc, |
| 4824 | 4871 | }; |
| 4825 | 4872 | |
| 4873 | /// Used only for disambiguating local from global at relocation level. | |
| 4874 | /// TODO this must go away. | |
| 4875 | pub const global_symbol_bit: u32 = 0x80000000; | |
| 4876 | pub const global_symbol_mask: u32 = 0x7fffffff; | |
| 4877 | ||
| 4826 | 4878 | /// Return pointer to the global entry for `name` if one exists. |
| 4827 | 4879 | /// Puts a new global entry for `name` if one doesn't exist, and |
| 4828 | 4880 | /// returns a pointer to it. |
| ... | ... | @@ -5489,21 +5541,17 @@ const DeclMetadata = struct { |
| 5489 | 5541 | } |
| 5490 | 5542 | }; |
| 5491 | 5543 | |
| 5492 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index); | |
| 5544 | const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata); | |
| 5545 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata); | |
| 5493 | 5546 | const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); |
| 5494 | 5547 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| 5495 | 5548 | const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 5496 | 5549 | const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 5550 | const ActionTable = std.AutoHashMapUnmanaged(u32, RelocFlags); | |
| 5497 | 5551 | |
| 5498 | pub const ResolveAction = struct { | |
| 5499 | kind: Kind, | |
| 5500 | target: SymbolWithLoc, | |
| 5501 | ||
| 5502 | const Kind = enum { | |
| 5503 | none, | |
| 5504 | add_got, | |
| 5505 | add_stub, | |
| 5506 | }; | |
| 5552 | pub const RelocFlags = packed struct { | |
| 5553 | add_got: bool = false, | |
| 5554 | add_stub: bool = false, | |
| 5507 | 5555 | }; |
| 5508 | 5556 | |
| 5509 | 5557 | pub const SymbolWithLoc = extern struct { |
src/link/MachO/Atom.zig+24-23| ... | ... | @@ -300,7 +300,7 @@ pub fn resolveRelocations( |
| 300 | 300 | relocs: []*const Relocation, |
| 301 | 301 | code: []u8, |
| 302 | 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 | 304 | for (relocs) |reloc| { |
| 305 | 305 | reloc.resolve(macho_file, atom_index, code); |
| 306 | 306 | } |
| ... | ... | @@ -603,7 +603,7 @@ pub fn resolveRelocs( |
| 603 | 603 | const atom = macho_file.getAtom(atom_index); |
| 604 | 604 | assert(atom.getFile() != null); // synthetic atoms do not have relocs |
| 605 | 605 | |
| 606 | log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{ | |
| 606 | relocs_log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{ | |
| 607 | 607 | atom.sym_index, |
| 608 | 608 | macho_file.getSymbolName(atom.getSymbolWithLoc()), |
| 609 | 609 | }); |
| ... | ... | @@ -683,7 +683,7 @@ fn resolveRelocsArm64( |
| 683 | 683 | .ARM64_RELOC_ADDEND => { |
| 684 | 684 | assert(addend == null); |
| 685 | 685 | |
| 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 }); | |
| 687 | 687 | |
| 688 | 688 | addend = rel.r_symbolnum; |
| 689 | 689 | continue; |
| ... | ... | @@ -691,7 +691,7 @@ fn resolveRelocsArm64( |
| 691 | 691 | .ARM64_RELOC_SUBTRACTOR => { |
| 692 | 692 | assert(subtractor == null); |
| 693 | 693 | |
| 694 | log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{ | |
| 694 | relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{ | |
| 695 | 695 | @tagName(rel_type), |
| 696 | 696 | rel.r_address, |
| 697 | 697 | rel.r_symbolnum, |
| ... | ... | @@ -719,7 +719,7 @@ fn resolveRelocsArm64( |
| 719 | 719 | }); |
| 720 | 720 | const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset)); |
| 721 | 721 | |
| 722 | log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ | |
| 722 | relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ | |
| 723 | 723 | @tagName(rel_type), |
| 724 | 724 | rel.r_address, |
| 725 | 725 | target.sym_index, |
| ... | ... | @@ -745,11 +745,11 @@ fn resolveRelocsArm64( |
| 745 | 745 | break :blk getRelocTargetAddress(macho_file, target, is_tlv); |
| 746 | 746 | }; |
| 747 | 747 | |
| 748 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 748 | relocs_log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 749 | 749 | |
| 750 | 750 | switch (rel_type) { |
| 751 | 751 | .ARM64_RELOC_BRANCH26 => { |
| 752 | log.debug(" source {s} (object({?})), target {s}", .{ | |
| 752 | relocs_log.debug(" source {s} (object({?})), target {s}", .{ | |
| 753 | 753 | macho_file.getSymbolName(atom.getSymbolWithLoc()), |
| 754 | 754 | atom.getFile(), |
| 755 | 755 | macho_file.getSymbolName(target), |
| ... | ... | @@ -759,7 +759,7 @@ fn resolveRelocsArm64( |
| 759 | 759 | source_addr, |
| 760 | 760 | target_addr, |
| 761 | 761 | )) |disp| blk: { |
| 762 | log.debug(" | target_addr = 0x{x}", .{target_addr}); | |
| 762 | relocs_log.debug(" | target_addr = 0x{x}", .{target_addr}); | |
| 763 | 763 | break :blk disp; |
| 764 | 764 | } else |_| blk: { |
| 765 | 765 | const thunk_index = macho_file.thunk_table.get(atom_index).?; |
| ... | ... | @@ -769,7 +769,7 @@ fn resolveRelocsArm64( |
| 769 | 769 | else |
| 770 | 770 | thunk.getTrampoline(macho_file, .atom, target).?; |
| 771 | 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 | 773 | break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr); |
| 774 | 774 | }; |
| 775 | 775 | |
| ... | ... | @@ -790,7 +790,7 @@ fn resolveRelocsArm64( |
| 790 | 790 | => { |
| 791 | 791 | const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0))); |
| 792 | 792 | |
| 793 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 793 | relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 794 | 794 | |
| 795 | 795 | const pages = @as(u21, @bitCast(Relocation.calcNumberOfPages(source_addr, adjusted_target_addr))); |
| 796 | 796 | const code = atom_code[rel_offset..][0..4]; |
| ... | ... | @@ -809,7 +809,7 @@ fn resolveRelocsArm64( |
| 809 | 809 | .ARM64_RELOC_PAGEOFF12 => { |
| 810 | 810 | const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0))); |
| 811 | 811 | |
| 812 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 812 | relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 813 | 813 | |
| 814 | 814 | const code = atom_code[rel_offset..][0..4]; |
| 815 | 815 | if (Relocation.isArithmeticOp(code)) { |
| ... | ... | @@ -848,7 +848,7 @@ fn resolveRelocsArm64( |
| 848 | 848 | const code = atom_code[rel_offset..][0..4]; |
| 849 | 849 | const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0))); |
| 850 | 850 | |
| 851 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 851 | relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 852 | 852 | |
| 853 | 853 | const off = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64); |
| 854 | 854 | var inst: aarch64.Instruction = .{ |
| ... | ... | @@ -866,7 +866,7 @@ fn resolveRelocsArm64( |
| 866 | 866 | const code = atom_code[rel_offset..][0..4]; |
| 867 | 867 | const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0))); |
| 868 | 868 | |
| 869 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 869 | relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 870 | 870 | |
| 871 | 871 | const RegInfo = struct { |
| 872 | 872 | rd: u5, |
| ... | ... | @@ -923,7 +923,7 @@ fn resolveRelocsArm64( |
| 923 | 923 | }, |
| 924 | 924 | |
| 925 | 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 | 927 | const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse |
| 928 | 928 | return error.Overflow; |
| 929 | 929 | mem.writeIntLittle(u32, atom_code[rel_offset..][0..4], @as(u32, @bitCast(result))); |
| ... | ... | @@ -951,7 +951,7 @@ fn resolveRelocsArm64( |
| 951 | 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}); | |
| 955 | 955 | |
| 956 | 956 | if (rel.r_length == 3) { |
| 957 | 957 | mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result))); |
| ... | ... | @@ -987,7 +987,7 @@ fn resolveRelocsX86( |
| 987 | 987 | .X86_64_RELOC_SUBTRACTOR => { |
| 988 | 988 | assert(subtractor == null); |
| 989 | 989 | |
| 990 | log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{ | |
| 990 | relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{ | |
| 991 | 991 | @tagName(rel_type), |
| 992 | 992 | rel.r_address, |
| 993 | 993 | rel.r_symbolnum, |
| ... | ... | @@ -1015,7 +1015,7 @@ fn resolveRelocsX86( |
| 1015 | 1015 | }); |
| 1016 | 1016 | const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset)); |
| 1017 | 1017 | |
| 1018 | log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ | |
| 1018 | relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{ | |
| 1019 | 1019 | @tagName(rel_type), |
| 1020 | 1020 | rel.r_address, |
| 1021 | 1021 | target.sym_index, |
| ... | ... | @@ -1041,13 +1041,13 @@ fn resolveRelocsX86( |
| 1041 | 1041 | break :blk getRelocTargetAddress(macho_file, target, is_tlv); |
| 1042 | 1042 | }; |
| 1043 | 1043 | |
| 1044 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 1044 | relocs_log.debug(" | source_addr = 0x{x}", .{source_addr}); | |
| 1045 | 1045 | |
| 1046 | 1046 | switch (rel_type) { |
| 1047 | 1047 | .X86_64_RELOC_BRANCH => { |
| 1048 | 1048 | const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 1049 | 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 | 1051 | const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0); |
| 1052 | 1052 | mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp); |
| 1053 | 1053 | }, |
| ... | ... | @@ -1057,7 +1057,7 @@ fn resolveRelocsX86( |
| 1057 | 1057 | => { |
| 1058 | 1058 | const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 1059 | 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 | 1061 | const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0); |
| 1062 | 1062 | mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp); |
| 1063 | 1063 | }, |
| ... | ... | @@ -1065,7 +1065,7 @@ fn resolveRelocsX86( |
| 1065 | 1065 | .X86_64_RELOC_TLV => { |
| 1066 | 1066 | const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]); |
| 1067 | 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 | 1069 | const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0); |
| 1070 | 1070 | |
| 1071 | 1071 | if (macho_file.tlv_ptr_table.lookup.get(target) == null) { |
| ... | ... | @@ -1101,7 +1101,7 @@ fn resolveRelocsX86( |
| 1101 | 1101 | |
| 1102 | 1102 | const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend)); |
| 1103 | 1103 | |
| 1104 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 1104 | relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | |
| 1105 | 1105 | |
| 1106 | 1106 | const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction); |
| 1107 | 1107 | mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp); |
| ... | ... | @@ -1129,7 +1129,7 @@ fn resolveRelocsX86( |
| 1129 | 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}); | |
| 1133 | 1133 | |
| 1134 | 1134 | if (rel.r_length == 3) { |
| 1135 | 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 | 1247 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 1248 | 1248 | const assert = std.debug.assert; |
| 1249 | 1249 | const log = std.log.scoped(.link); |
| 1250 | const relocs_log = std.log.scoped(.link_relocs); | |
| 1250 | 1251 | const macho = std.macho; |
| 1251 | 1252 | const math = std.math; |
| 1252 | 1253 | const 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 | 99 | else => @as(i64, @intCast(target_base_addr)) + self.addend, |
| 100 | 100 | }; |
| 101 | 101 | |
| 102 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ | |
| 102 | relocs_log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ | |
| 103 | 103 | source_addr, |
| 104 | 104 | target_addr, |
| 105 | 105 | macho_file.getSymbolName(self.target), |
| ... | ... | @@ -256,7 +256,7 @@ const Relocation = @This(); |
| 256 | 256 | const std = @import("std"); |
| 257 | 257 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 258 | 258 | const assert = std.debug.assert; |
| 259 | const log = std.log.scoped(.link); | |
| 259 | const relocs_log = std.log.scoped(.link_relocs); | |
| 260 | 260 | const macho = std.macho; |
| 261 | 261 | const math = std.math; |
| 262 | 262 | const mem = std.mem; |
src/link/MachO/zld.zig+1-3| ... | ... | @@ -390,9 +390,7 @@ pub fn linkWithZld( |
| 390 | 390 | |
| 391 | 391 | try macho_file.parseDependentLibs(&dependent_libs); |
| 392 | 392 | |
| 393 | var actions = std.ArrayList(MachO.ResolveAction).init(gpa); | |
| 394 | defer actions.deinit(); | |
| 395 | try macho_file.resolveSymbols(&actions); | |
| 393 | try macho_file.resolveSymbols(); | |
| 396 | 394 | if (macho_file.unresolved.count() > 0) { |
| 397 | 395 | try macho_file.reportUndefined(); |
| 398 | 396 | return error.FlushFailure; |
test/behavior/export_builtin.zig+8-2| ... | ... | @@ -54,7 +54,10 @@ test "exporting using field access" { |
| 54 | 54 | test "exporting comptime-known value" { |
| 55 | 55 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 56 | 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 | 61 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 59 | 62 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 60 | 63 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| ... | ... | @@ -70,7 +73,10 @@ test "exporting comptime-known value" { |
| 70 | 73 | test "exporting comptime var" { |
| 71 | 74 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 72 | 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 | 80 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 75 | 81 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; |
| 76 | 82 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |