authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-02-27 22:50:05+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 19:59:13+01:00
log7cbdbab3765bf1eb5f213b04054b82c46d876588
treec5f2a853a98a6df916c12c6e4522cbc22b3d667b
parent7e329478718ef5545083b1123d1df437101b8a5b

zld: differentiate locals from globals


1 files changed, 138 insertions(+), 39 deletions(-)

src/link/MachO/Zld.zig+138-39
......@@ -60,7 +60,7 @@ tlv_section_index: ?u16 = null,
6060la_symbol_ptr_section_index: ?u16 = null,
6161data_section_index: ?u16 = null,
6262
63locals: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},
63locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{},
6464exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},
6565nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
6666lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
......@@ -74,6 +74,18 @@ stub_helper_stubs_start_off: ?u64 = null,
7474segments_directory: std.AutoHashMapUnmanaged([16]u8, u16) = .{},
7575directory: std.AutoHashMapUnmanaged(DirectoryKey, DirectoryEntry) = .{},
7676
77const Symbol = struct {
78 inner: macho.nlist_64,
79 tt: Type,
80 object: *Object,
81
82 const Type = enum {
83 Local,
84 WeakGlobal,
85 Global,
86 };
87};
88
7789const DirectoryKey = struct {
7890 segname: [16]u8,
7991 sectname: [16]u8,
......@@ -198,6 +210,7 @@ pub fn deinit(self: *Zld) void {
198210 self.exports.deinit(self.allocator);
199211 for (self.locals.items()) |*entry| {
200212 self.allocator.free(entry.key);
213 entry.value.deinit(self.allocator);
201214 }
202215 self.locals.deinit(self.allocator);
203216 for (self.objects.items) |*object| {
......@@ -773,7 +786,7 @@ fn resolveSymbols(self: *Zld) !void {
773786 var next_address = std.AutoHashMap(DirectoryKey, Address).init(self.allocator);
774787 defer next_address.deinit();
775788
776 for (self.objects.items) |object| {
789 for (self.objects.items) |*object| {
777790 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
778791
779792 for (seg.sections.items) |sect| {
......@@ -799,11 +812,32 @@ fn resolveSymbols(self: *Zld) !void {
799812 if (isImport(&sym)) continue;
800813
801814 const sym_name = object.getString(sym.n_strx);
815 const out_name = try self.allocator.dupe(u8, sym_name);
816 const locs = try self.locals.getOrPut(self.allocator, out_name);
817 defer {
818 if (locs.found_existing) self.allocator.free(out_name);
819 }
802820
803 if (isLocal(&sym) and self.locals.get(sym_name) != null) {
804 log.warn("local symbol '{s}' defined multiple times; removing", .{sym_name});
805 self.locals.swapRemoveAssertDiscard(sym_name);
806 continue;
821 if (!locs.found_existing) {
822 locs.entry.value = .{};
823 }
824
825 const tt: Symbol.Type = blk: {
826 if (isLocal(&sym)) {
827 break :blk .Local;
828 } else if (isWeakDef(&sym)) {
829 break :blk .WeakGlobal;
830 } else {
831 break :blk .Global;
832 }
833 };
834 if (tt == .Global) {
835 for (locs.entry.value.items) |ss| {
836 if (ss.tt == .Global) {
837 log.err("symbol '{s}' defined multiple times", .{sym_name});
838 return error.MultipleSymbolDefinitions;
839 }
840 }
807841 }
808842
809843 const sect = seg.sections.items[sym.n_sect - 1];
......@@ -813,10 +847,9 @@ fn resolveSymbols(self: *Zld) !void {
813847 };
814848 const res = self.directory.get(key) orelse continue;
815849
816 const n_strx = try self.makeString(sym_name);
817850 const n_value = sym.n_value - sect.addr + next_address.get(key).?.addr;
818851
819 log.warn("resolving '{s}' as local symbol at 0x{x}", .{ sym_name, n_value });
852 log.warn("resolving '{s}':{} as {s} symbol at 0x{x}", .{ sym_name, sym, tt, n_value });
820853
821854 var n_sect = res.sect_index + 1;
822855 for (self.load_commands.items) |sseg, i| {
......@@ -826,13 +859,17 @@ fn resolveSymbols(self: *Zld) !void {
826859 n_sect += @intCast(u16, sseg.Segment.sections.items.len);
827860 }
828861
829 var out_name = try self.allocator.dupe(u8, sym_name);
830 try self.locals.putNoClobber(self.allocator, out_name, .{
831 .n_strx = n_strx,
832 .n_value = n_value,
833 .n_type = macho.N_SECT,
834 .n_desc = sym.n_desc,
835 .n_sect = @intCast(u8, n_sect),
862 const n_strx = try self.makeString(sym_name);
863 try locs.entry.value.append(self.allocator, .{
864 .inner = .{
865 .n_strx = n_strx,
866 .n_value = n_value,
867 .n_type = macho.N_SECT,
868 .n_desc = sym.n_desc,
869 .n_sect = @intCast(u8, n_sect),
870 },
871 .tt = tt,
872 .object = object,
836873 });
837874 }
838875 }
......@@ -1212,8 +1249,25 @@ fn relocTargetAddr(self: *Zld, object: Object, rel: macho.relocation_info, next_
12121249 // Relocate to either the artifact's local symbol, or an import from
12131250 // shared library.
12141251 const sym_name = object.getString(sym.n_strx);
1215 if (self.locals.get(sym_name)) |loc| {
1216 break :blk loc.n_value;
1252 if (self.locals.get(sym_name)) |locs| {
1253 var n_value: ?u64 = null;
1254 for (locs.items) |loc| {
1255 switch (loc.tt) {
1256 .Global => {
1257 n_value = loc.inner.n_value;
1258 break;
1259 },
1260 .WeakGlobal => {
1261 n_value = loc.inner.n_value;
1262 },
1263 .Local => {},
1264 }
1265 }
1266 if (n_value) |v| {
1267 break :blk v;
1268 }
1269 log.err("local symbol export '{s}' not found", .{sym_name});
1270 return error.LocalSymbolExportNotFound;
12171271 } else if (self.lazy_imports.get(sym_name)) |ext| {
12181272 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
12191273 const stubs = segment.sections.items[self.stubs_section_index.?];
......@@ -1710,19 +1764,37 @@ fn setEntryPoint(self: *Zld) !void {
17101764 // entrypoint. For now, assume default of `_main`.
17111765 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
17121766 const text = seg.sections.items[self.text_section_index.?];
1713 const entry_sym = self.locals.get("_main") orelse return error.MissingMainEntrypoint;
1767 const entry_syms = self.locals.get("_main") orelse return error.MissingMainEntrypoint;
1768
1769 var entry_sym: ?macho.nlist_64 = null;
1770 for (entry_syms.items) |es| {
1771 switch (es.tt) {
1772 .Global => {
1773 entry_sym = es.inner;
1774 break;
1775 },
1776 .WeakGlobal => {
1777 entry_sym = es.inner;
1778 },
1779 .Local => {},
1780 }
1781 }
1782 if (entry_sym == null) {
1783 log.err("no (weak) global definition of _main found", .{});
1784 return error.MissingMainEntrypoint;
1785 }
17141786
17151787 const name = try self.allocator.dupe(u8, "_main");
17161788 try self.exports.putNoClobber(self.allocator, name, .{
1717 .n_strx = entry_sym.n_strx,
1718 .n_value = entry_sym.n_value,
1789 .n_strx = entry_sym.?.n_strx,
1790 .n_value = entry_sym.?.n_value,
17191791 .n_type = macho.N_SECT | macho.N_EXT,
1720 .n_desc = entry_sym.n_desc,
1721 .n_sect = entry_sym.n_sect,
1792 .n_desc = entry_sym.?.n_desc,
1793 .n_sect = entry_sym.?.n_sect,
17221794 });
17231795
17241796 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
1725 ec.entryoff = @intCast(u32, entry_sym.n_value - seg.inner.vmaddr);
1797 ec.entryoff = @intCast(u32, entry_sym.?.n_value - seg.inner.vmaddr);
17261798}
17271799
17281800fn writeRebaseInfoTable(self: *Zld) !void {
......@@ -1968,9 +2040,9 @@ fn writeDebugInfo(self: *Zld) !void {
19682040 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
19692041 defer stabs.deinit();
19702042
1971 for (self.objects.items) |object| {
2043 for (self.objects.items) |*object| {
19722044 var debug_info = blk: {
1973 var di = try DebugInfo.parseFromObject(self.allocator, object);
2045 var di = try DebugInfo.parseFromObject(self.allocator, object.*);
19742046 break :blk di orelse continue;
19752047 };
19762048 defer debug_info.deinit(self.allocator);
......@@ -2017,7 +2089,12 @@ fn writeDebugInfo(self: *Zld) !void {
20172089 for (object.symtab.items) |source_sym| {
20182090 const symname = object.getString(source_sym.n_strx);
20192091 const source_addr = source_sym.n_value;
2020 const target_sym = self.locals.get(symname) orelse continue;
2092 const target_syms = self.locals.get(symname) orelse continue;
2093 const target_sym: Symbol = blk: {
2094 for (target_syms.items) |ts| {
2095 if (ts.object == object) break :blk ts;
2096 } else continue;
2097 };
20212098
20222099 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {
20232100 if (func.pc_range) |range| {
......@@ -2031,16 +2108,16 @@ fn writeDebugInfo(self: *Zld) !void {
20312108 try stabs.append(.{
20322109 .n_strx = 0,
20332110 .n_type = macho.N_BNSYM,
2034 .n_sect = target_sym.n_sect,
2111 .n_sect = target_sym.inner.n_sect,
20352112 .n_desc = 0,
2036 .n_value = target_sym.n_value,
2113 .n_value = target_sym.inner.n_value,
20372114 });
20382115 try stabs.append(.{
2039 .n_strx = target_sym.n_strx,
2116 .n_strx = target_sym.inner.n_strx,
20402117 .n_type = macho.N_FUN,
2041 .n_sect = target_sym.n_sect,
2118 .n_sect = target_sym.inner.n_sect,
20422119 .n_desc = 0,
2043 .n_value = target_sym.n_value,
2120 .n_value = target_sym.inner.n_value,
20442121 });
20452122 try stabs.append(.{
20462123 .n_strx = 0,
......@@ -2052,18 +2129,18 @@ fn writeDebugInfo(self: *Zld) !void {
20522129 try stabs.append(.{
20532130 .n_strx = 0,
20542131 .n_type = macho.N_ENSYM,
2055 .n_sect = target_sym.n_sect,
2132 .n_sect = target_sym.inner.n_sect,
20562133 .n_desc = 0,
20572134 .n_value = size,
20582135 });
20592136 } else {
20602137 // TODO need a way to differentiate symbols: global, static, local, etc.
20612138 try stabs.append(.{
2062 .n_strx = target_sym.n_strx,
2139 .n_strx = target_sym.inner.n_strx,
20632140 .n_type = macho.N_STSYM,
2064 .n_sect = target_sym.n_sect,
2141 .n_sect = target_sym.inner.n_sect,
20652142 .n_desc = 0,
2066 .n_value = target_sym.n_value,
2143 .n_value = target_sym.inner.n_value,
20672144 });
20682145 }
20692146 }
......@@ -2102,14 +2179,32 @@ fn writeSymbolTable(self: *Zld) !void {
21022179 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
21032180 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
21042181
2105 const nlocals = self.locals.items().len;
21062182 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);
21072183 defer locals.deinit();
21082184
2109 try locals.ensureCapacity(nlocals);
2110 for (self.locals.items()) |entry| {
2111 locals.appendAssumeCapacity(entry.value);
2185 for (self.locals.items()) |entries| {
2186 log.warn("'{s}': {} entries", .{ entries.key, entries.value.items.len });
2187 var symbol: ?macho.nlist_64 = null;
2188 for (entries.value.items) |entry| {
2189 log.warn(" | {}", .{entry.inner});
2190 log.warn(" | {}", .{entry.tt});
2191 log.warn(" | {s}", .{entry.object.name});
2192 switch (entry.tt) {
2193 .Global => {
2194 symbol = entry.inner;
2195 break;
2196 },
2197 .WeakGlobal => {
2198 symbol = entry.inner;
2199 },
2200 .Local => {},
2201 }
2202 }
2203 if (symbol) |s| {
2204 try locals.append(s);
2205 }
21122206 }
2207 const nlocals = locals.items.len;
21132208
21142209 const nexports = self.exports.items().len;
21152210 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
......@@ -2392,3 +2487,7 @@ fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool {
23922487 if ((sym.n_type & macho.N_EXT) == 0) return false;
23932488 return (sym.n_type & macho.N_PEXT) == 0;
23942489}
2490
2491fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool {
2492 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
2493}