| 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,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) = .{}, |
| 28 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, | 28 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 29 | resolver: std.StringHashMapUnmanaged(u32) = .{}, | 29 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 30 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, | 30 | unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, |
| 31 | need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{}, | ||
| 31 | 32 | ||
| 32 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 33 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 33 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 34 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | @@ -54,7 +55,7 @@ entry_addr: ?u32 = null, | ... | @@ -54,7 +55,7 @@ entry_addr: ?u32 = null, |
| 54 | lazy_syms: LazySymbolTable = .{}, | 55 | lazy_syms: LazySymbolTable = .{}, |
| 55 | 56 | ||
| 56 | /// Table of tracked Decls. | 57 | /// Table of tracked Decls. |
| 57 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 58 | decls: DeclTable = .{}, |
| 58 | 59 | ||
| 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. |
| 60 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | 61 | atoms: 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 | }; |
| 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 | const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); | 114 | const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 113 | const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); | 115 | const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 114 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); | 116 | const 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 | } | ||
| 329 | 338 | ||
| 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); |
| 1161 | 1170 | ||
| 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 | } |
| 1170 | 1184 | ||
| 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( |
| 1462 | 1476 | ||
| 1463 | const gpa = self.base.allocator; | 1477 | const gpa = self.base.allocator; |
| 1464 | 1478 | ||
| 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).?; | ||
| 1476 | 1502 | ||
| 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)}); |
| 1479 | 1505 | ||
| 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 | } |
| 1495 | 1517 | ||
| 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 | } |
| 1509 | 1527 | ||
| 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; |
| 1521 | 1550 | ||
| 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 | } |
| 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 | 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 | } |
| 1798 | 1835 | ||
| 1799 | pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { | 1836 | pub 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); |
| 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 | 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 | }; |
| 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 | /// 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, and | 2493 | /// 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) = .{}, |
| 185 | lazy_syms: LazySymbolTable = .{}, | 185 | lazy_syms: LazySymbolTable = .{}, |
| 186 | 186 | ||
| 187 | /// Table of tracked Decls. | 187 | /// Table of tracked Decls. |
| 188 | decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 188 | decls: DeclTable = .{}, |
| 189 | 189 | ||
| 190 | /// List of atoms that are owned directly by the linker. | 190 | /// List of atoms that are owned directly by the linker. |
| 191 | atoms: std.ArrayListUnmanaged(Atom) = .{}, | 191 | atoms: 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. |
| 193 | last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{}, | 193 | last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, |
| 194 | 194 | ||
| 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) = .{} |
| 220 | 220 | ||
| 221 | const AtomList = std.ArrayListUnmanaged(Atom.Index); | 221 | const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 222 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); | 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 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | 225 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 226 | const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList); | ||
| 225 | 227 | ||
| 226 | /// When allocating, the ideal_capacity is calculated by | 228 | /// 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 | } | ||
| 449 | 458 | ||
| 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 | } |
| 534 | 543 | ||
| 535 | pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { | 544 | pub 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(); |
| 3574 | 3580 | ||
| 3575 | const gpa = self.base.allocator; | 3581 | const gpa = self.base.allocator; |
| 3576 | 3582 | 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).?; | ||
| 3591 | 3608 | ||
| 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)); |
| 3618 | 3638 | 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 | } |
| 3640 | 3661 |
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, |
| 50 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 50 | locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 51 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, | 51 | globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, |
| 52 | resolver: std.StringHashMapUnmanaged(u32) = .{}, | 52 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 53 | unresolved: std.AutoArrayHashMapUnmanaged(u32, ResolveAction.Kind) = .{}, | 53 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 54 | 54 | ||
| 55 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 55 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 56 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 56 | globals_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. |
| 117 | relocs: RelocationTable = .{}, | 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 | /// 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 = .{}, |
| 130 | lazy_syms: LazySymbolTable = .{}, | 134 | lazy_syms: LazySymbolTable = .{}, |
| 131 | 135 | ||
| 132 | /// Table of tracked Decls. | 136 | /// Table of tracked Decls. |
| 133 | decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{}, | 137 | decls: DeclTable = .{}, |
| 134 | 138 | ||
| 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 | } |
| 419 | 423 | ||
| 420 | var actions = std.ArrayList(ResolveAction).init(self.base.allocator); | 424 | try self.resolveSymbols(); |
| 421 | defer actions.deinit(); | ||
| 422 | try self.resolveSymbols(&actions); | ||
| 423 | 425 | ||
| 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 | } |
| 431 | 433 | ||
| 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 | } | ||
| 437 | 444 | ||
| 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 | } |
| 1591 | 1598 | ||
| 1592 | pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void { | 1599 | pub fn resolveSymbols(self: *MachO) !void { |
| 1593 | // We add the specified entrypoint as the first unresolved symbols so that | 1600 | // 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 specified | 1601 | // 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 | } |
| 1600 | 1607 | ||
| 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 | } |
| 1605 | 1612 | ||
| 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 imports | 1619 | // 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 | } |
| 1620 | 1627 | ||
| 1621 | try self.resolveSymbolsInDylibs(actions); | 1628 | try self.resolveSymbolsInDylibs(); |
| 1622 | 1629 | ||
| 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 | } |
| 1768 | 1775 | ||
| 1769 | fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void { | 1776 | fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 1770 | if (self.dylibs.items.len == 0) return; | 1777 | if (self.dylibs.items.len == 0) return; |
| 1771 | 1778 | ||
| 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 | } |
| 1795 | 1802 | ||
| 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 | } | ||
| 1801 | 1804 | ||
| 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); |
| 1909 | 1913 | ||
| ... | @@ -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 | } | ||
| 1915 | 1926 | ||
| 1916 | self.atom_by_index_table.deinit(gpa); | 1927 | self.atom_by_index_table.deinit(gpa); |
| 1917 | 1928 | ||
| ... | @@ -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); | ||
| 1922 | 1934 | ||
| 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}); |
| 2259 | 2271 | ||
| 2260 | try self.writeAtom(atom_index, code); | 2272 | try self.writeAtom(atom_index, code); |
| 2273 | self.markRelocsDirtyByTarget(atom.getSymbolWithLoc()); | ||
| 2261 | 2274 | ||
| 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); |
| 2274 | 2287 | ||
| 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 | } |
| 2283 | 2300 | ||
| 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( |
| 2689 | 2706 | ||
| 2690 | const gpa = self.base.allocator; | 2707 | const gpa = self.base.allocator; |
| 2691 | 2708 | ||
| 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).?; | ||
| 2704 | 2733 | ||
| 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( |
| 2712 | 2741 | ||
| 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 | } |
| 2728 | 2753 | ||
| 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 | } |
| 2742 | 2763 | ||
| 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 | }; |
| 2757 | 2788 | ||
| 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 | } |
| 2773 | 2804 | ||
| 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 rethinking | 2807 | // 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 times | 2813 | \\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 | } |
| 2923 | 2957 | ||
| 2924 | pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { | 2958 | pub 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); |
| 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 | 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 | } |
| 3412 | 3446 | ||
| 3413 | pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void { | 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,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 | } |
| 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 | const gpa = self.base.allocator; | 4729 | const gpa = self.base.allocator; |
| 4696 | 4730 | ||
| 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).?; |
| 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 | 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 |
| 4705 | 4742 | ||
| 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; |
| 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 | return global_index; | 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 | pub fn makeStaticString(bytes: []const u8) [16]u8 { | 4762 | pub 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 | }; |
| 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 | /// 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, and | 4879 | /// 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 | }; |
| 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 | const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); | 5546 | const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); |
| 5494 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); | 5547 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| 5495 | const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); | 5548 | const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 5496 | const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); | 5549 | const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 5550 | const ActionTable = std.AutoHashMapUnmanaged(u32, RelocFlags); | ||
| 5497 | 5551 | ||
| 5498 | pub const ResolveAction = struct { | 5552 | pub 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 | }; |
| 5508 | 5556 | ||
| 5509 | pub const SymbolWithLoc = extern struct { | 5557 | pub 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 relocs | 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 | 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); |
| 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 | 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); |
| 693 | 693 | ||
| 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)); |
| 721 | 721 | ||
| 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 | }; |
| 747 | 747 | ||
| 748 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | 748 | relocs_log.debug(" | source_addr = 0x{x}", .{source_addr}); |
| 749 | 749 | ||
| 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 | else | 769 | 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 | }; |
| 775 | 775 | ||
| ... | @@ -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))); |
| 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 | 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))); |
| 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 | 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))); |
| 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 | 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))); |
| 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 | 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 | }, |
| 924 | 924 | ||
| 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))) orelse | 927 | 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}); |
| 955 | 955 | ||
| 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); |
| 989 | 989 | ||
| 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)); |
| 1017 | 1017 | ||
| 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 | }; |
| 1043 | 1043 | ||
| 1044 | log.debug(" | source_addr = 0x{x}", .{source_addr}); | 1044 | relocs_log.debug(" | source_addr = 0x{x}", .{source_addr}); |
| 1045 | 1045 | ||
| 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); |
| 1070 | 1070 | ||
| 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( |
| 1101 | 1101 | ||
| 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)); |
| 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 | 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}); |
| 1133 | 1133 | ||
| 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"); |
| 1247 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | 1247 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 1248 | const assert = std.debug.assert; | 1248 | const assert = std.debug.assert; |
| 1249 | const log = std.log.scoped(.link); | 1249 | const log = std.log.scoped(.link); |
| 1250 | const relocs_log = std.log.scoped(.link_relocs); | ||
| 1250 | const macho = std.macho; | 1251 | const macho = std.macho; |
| 1251 | const math = std.math; | 1252 | const math = std.math; |
| 1252 | const mem = std.mem; | 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,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 | }; |
| 101 | 101 | ||
| 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(); |
| 256 | const std = @import("std"); | 256 | const std = @import("std"); |
| 257 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | 257 | const aarch64 = @import("../../arch/aarch64/bits.zig"); |
| 258 | const assert = std.debug.assert; | 258 | const assert = std.debug.assert; |
| 259 | const log = std.log.scoped(.link); | 259 | const relocs_log = std.log.scoped(.link_relocs); |
| 260 | const macho = std.macho; | 260 | const macho = std.macho; |
| 261 | const math = std.math; | 261 | const math = std.math; |
| 262 | const mem = std.mem; | 262 | const mem = std.mem; |
src/link/MachO/zld.zig+1-3| ... | @@ -390,9 +390,7 @@ pub fn linkWithZld( | ... | @@ -390,9 +390,7 @@ pub fn linkWithZld( |
| 390 | 390 | ||
| 391 | try macho_file.parseDependentLibs(&dependent_libs); | 391 | try macho_file.parseDependentLibs(&dependent_libs); |
| 392 | 392 | ||
| 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" { |
| 54 | test "exporting comptime-known value" { | 54 | test "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" { |
| 70 | test "exporting comptime var" { | 73 | test "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; |