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,...@@ -60,7 +60,7 @@ tlv_section_index: ?u16 = null,
60la_symbol_ptr_section_index: ?u16 = null,60la_symbol_ptr_section_index: ?u16 = null,
61data_section_index: ?u16 = null,61data_section_index: ?u16 = null,
6262
63locals: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},63locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{},
64exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},64exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},
65nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},65nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
66lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},66lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},
...@@ -74,6 +74,18 @@ stub_helper_stubs_start_off: ?u64 = null,...@@ -74,6 +74,18 @@ stub_helper_stubs_start_off: ?u64 = null,
74segments_directory: std.AutoHashMapUnmanaged([16]u8, u16) = .{},74segments_directory: std.AutoHashMapUnmanaged([16]u8, u16) = .{},
75directory: std.AutoHashMapUnmanaged(DirectoryKey, DirectoryEntry) = .{},75directory: 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
77const DirectoryKey = struct {89const DirectoryKey = struct {
78 segname: [16]u8,90 segname: [16]u8,
79 sectname: [16]u8,91 sectname: [16]u8,
...@@ -198,6 +210,7 @@ pub fn deinit(self: *Zld) void {...@@ -198,6 +210,7 @@ pub fn deinit(self: *Zld) void {
198 self.exports.deinit(self.allocator);210 self.exports.deinit(self.allocator);
199 for (self.locals.items()) |*entry| {211 for (self.locals.items()) |*entry| {
200 self.allocator.free(entry.key);212 self.allocator.free(entry.key);
213 entry.value.deinit(self.allocator);
201 }214 }
202 self.locals.deinit(self.allocator);215 self.locals.deinit(self.allocator);
203 for (self.objects.items) |*object| {216 for (self.objects.items) |*object| {
...@@ -773,7 +786,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -773,7 +786,7 @@ fn resolveSymbols(self: *Zld) !void {
773 var next_address = std.AutoHashMap(DirectoryKey, Address).init(self.allocator);786 var next_address = std.AutoHashMap(DirectoryKey, Address).init(self.allocator);
774 defer next_address.deinit();787 defer next_address.deinit();
775788
776 for (self.objects.items) |object| {789 for (self.objects.items) |*object| {
777 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;790 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
778791
779 for (seg.sections.items) |sect| {792 for (seg.sections.items) |sect| {
...@@ -799,11 +812,32 @@ fn resolveSymbols(self: *Zld) !void {...@@ -799,11 +812,32 @@ fn resolveSymbols(self: *Zld) !void {
799 if (isImport(&sym)) continue;812 if (isImport(&sym)) continue;
800813
801 const sym_name = object.getString(sym.n_strx);814 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) {821 if (!locs.found_existing) {
804 log.warn("local symbol '{s}' defined multiple times; removing", .{sym_name});822 locs.entry.value = .{};
805 self.locals.swapRemoveAssertDiscard(sym_name);823 }
806 continue;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 }
807 }841 }
808842
809 const sect = seg.sections.items[sym.n_sect - 1];843 const sect = seg.sections.items[sym.n_sect - 1];
...@@ -813,10 +847,9 @@ fn resolveSymbols(self: *Zld) !void {...@@ -813,10 +847,9 @@ fn resolveSymbols(self: *Zld) !void {
813 };847 };
814 const res = self.directory.get(key) orelse continue;848 const res = self.directory.get(key) orelse continue;
815849
816 const n_strx = try self.makeString(sym_name);
817 const n_value = sym.n_value - sect.addr + next_address.get(key).?.addr;850 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
821 var n_sect = res.sect_index + 1;854 var n_sect = res.sect_index + 1;
822 for (self.load_commands.items) |sseg, i| {855 for (self.load_commands.items) |sseg, i| {
...@@ -826,13 +859,17 @@ fn resolveSymbols(self: *Zld) !void {...@@ -826,13 +859,17 @@ fn resolveSymbols(self: *Zld) !void {
826 n_sect += @intCast(u16, sseg.Segment.sections.items.len);859 n_sect += @intCast(u16, sseg.Segment.sections.items.len);
827 }860 }
828861
829 var out_name = try self.allocator.dupe(u8, sym_name);862 const n_strx = try self.makeString(sym_name);
830 try self.locals.putNoClobber(self.allocator, out_name, .{863 try locs.entry.value.append(self.allocator, .{
831 .n_strx = n_strx,864 .inner = .{
832 .n_value = n_value,865 .n_strx = n_strx,
833 .n_type = macho.N_SECT,866 .n_value = n_value,
834 .n_desc = sym.n_desc,867 .n_type = macho.N_SECT,
835 .n_sect = @intCast(u8, n_sect),868 .n_desc = sym.n_desc,
869 .n_sect = @intCast(u8, n_sect),
870 },
871 .tt = tt,
872 .object = object,
836 });873 });
837 }874 }
838 }875 }
...@@ -1212,8 +1249,25 @@ fn relocTargetAddr(self: *Zld, object: Object, rel: macho.relocation_info, next_...@@ -1212,8 +1249,25 @@ fn relocTargetAddr(self: *Zld, object: Object, rel: macho.relocation_info, next_
1212 // Relocate to either the artifact's local symbol, or an import from1249 // Relocate to either the artifact's local symbol, or an import from
1213 // shared library.1250 // shared library.
1214 const sym_name = object.getString(sym.n_strx);1251 const sym_name = object.getString(sym.n_strx);
1215 if (self.locals.get(sym_name)) |loc| {1252 if (self.locals.get(sym_name)) |locs| {
1216 break :blk loc.n_value;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;
1217 } else if (self.lazy_imports.get(sym_name)) |ext| {1271 } else if (self.lazy_imports.get(sym_name)) |ext| {
1218 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1272 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1219 const stubs = segment.sections.items[self.stubs_section_index.?];1273 const stubs = segment.sections.items[self.stubs_section_index.?];
...@@ -1710,19 +1764,37 @@ fn setEntryPoint(self: *Zld) !void {...@@ -1710,19 +1764,37 @@ fn setEntryPoint(self: *Zld) !void {
1710 // entrypoint. For now, assume default of `_main`.1764 // entrypoint. For now, assume default of `_main`.
1711 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1765 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1712 const text = seg.sections.items[self.text_section_index.?];1766 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
1715 const name = try self.allocator.dupe(u8, "_main");1787 const name = try self.allocator.dupe(u8, "_main");
1716 try self.exports.putNoClobber(self.allocator, name, .{1788 try self.exports.putNoClobber(self.allocator, name, .{
1717 .n_strx = entry_sym.n_strx,1789 .n_strx = entry_sym.?.n_strx,
1718 .n_value = entry_sym.n_value,1790 .n_value = entry_sym.?.n_value,
1719 .n_type = macho.N_SECT | macho.N_EXT,1791 .n_type = macho.N_SECT | macho.N_EXT,
1720 .n_desc = entry_sym.n_desc,1792 .n_desc = entry_sym.?.n_desc,
1721 .n_sect = entry_sym.n_sect,1793 .n_sect = entry_sym.?.n_sect,
1722 });1794 });
17231795
1724 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;1796 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);
1726}1798}
17271799
1728fn writeRebaseInfoTable(self: *Zld) !void {1800fn writeRebaseInfoTable(self: *Zld) !void {
...@@ -1968,9 +2040,9 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -1968,9 +2040,9 @@ fn writeDebugInfo(self: *Zld) !void {
1968 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);2040 var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
1969 defer stabs.deinit();2041 defer stabs.deinit();
19702042
1971 for (self.objects.items) |object| {2043 for (self.objects.items) |*object| {
1972 var debug_info = blk: {2044 var debug_info = blk: {
1973 var di = try DebugInfo.parseFromObject(self.allocator, object);2045 var di = try DebugInfo.parseFromObject(self.allocator, object.*);
1974 break :blk di orelse continue;2046 break :blk di orelse continue;
1975 };2047 };
1976 defer debug_info.deinit(self.allocator);2048 defer debug_info.deinit(self.allocator);
...@@ -2017,7 +2089,12 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2017,7 +2089,12 @@ fn writeDebugInfo(self: *Zld) !void {
2017 for (object.symtab.items) |source_sym| {2089 for (object.symtab.items) |source_sym| {
2018 const symname = object.getString(source_sym.n_strx);2090 const symname = object.getString(source_sym.n_strx);
2019 const source_addr = source_sym.n_value;2091 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
2022 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {2099 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {
2023 if (func.pc_range) |range| {2100 if (func.pc_range) |range| {
...@@ -2031,16 +2108,16 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2031,16 +2108,16 @@ fn writeDebugInfo(self: *Zld) !void {
2031 try stabs.append(.{2108 try stabs.append(.{
2032 .n_strx = 0,2109 .n_strx = 0,
2033 .n_type = macho.N_BNSYM,2110 .n_type = macho.N_BNSYM,
2034 .n_sect = target_sym.n_sect,2111 .n_sect = target_sym.inner.n_sect,
2035 .n_desc = 0,2112 .n_desc = 0,
2036 .n_value = target_sym.n_value,2113 .n_value = target_sym.inner.n_value,
2037 });2114 });
2038 try stabs.append(.{2115 try stabs.append(.{
2039 .n_strx = target_sym.n_strx,2116 .n_strx = target_sym.inner.n_strx,
2040 .n_type = macho.N_FUN,2117 .n_type = macho.N_FUN,
2041 .n_sect = target_sym.n_sect,2118 .n_sect = target_sym.inner.n_sect,
2042 .n_desc = 0,2119 .n_desc = 0,
2043 .n_value = target_sym.n_value,2120 .n_value = target_sym.inner.n_value,
2044 });2121 });
2045 try stabs.append(.{2122 try stabs.append(.{
2046 .n_strx = 0,2123 .n_strx = 0,
...@@ -2052,18 +2129,18 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2052,18 +2129,18 @@ fn writeDebugInfo(self: *Zld) !void {
2052 try stabs.append(.{2129 try stabs.append(.{
2053 .n_strx = 0,2130 .n_strx = 0,
2054 .n_type = macho.N_ENSYM,2131 .n_type = macho.N_ENSYM,
2055 .n_sect = target_sym.n_sect,2132 .n_sect = target_sym.inner.n_sect,
2056 .n_desc = 0,2133 .n_desc = 0,
2057 .n_value = size,2134 .n_value = size,
2058 });2135 });
2059 } else {2136 } else {
2060 // TODO need a way to differentiate symbols: global, static, local, etc.2137 // TODO need a way to differentiate symbols: global, static, local, etc.
2061 try stabs.append(.{2138 try stabs.append(.{
2062 .n_strx = target_sym.n_strx,2139 .n_strx = target_sym.inner.n_strx,
2063 .n_type = macho.N_STSYM,2140 .n_type = macho.N_STSYM,
2064 .n_sect = target_sym.n_sect,2141 .n_sect = target_sym.inner.n_sect,
2065 .n_desc = 0,2142 .n_desc = 0,
2066 .n_value = target_sym.n_value,2143 .n_value = target_sym.inner.n_value,
2067 });2144 });
2068 }2145 }
2069 }2146 }
...@@ -2102,14 +2179,32 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2102,14 +2179,32 @@ fn writeSymbolTable(self: *Zld) !void {
2102 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2179 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2103 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2180 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
21042181
2105 const nlocals = self.locals.items().len;
2106 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);2182 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);
2107 defer locals.deinit();2183 defer locals.deinit();
21082184
2109 try locals.ensureCapacity(nlocals);2185 for (self.locals.items()) |entries| {
2110 for (self.locals.items()) |entry| {2186 log.warn("'{s}': {} entries", .{ entries.key, entries.value.items.len });
2111 locals.appendAssumeCapacity(entry.value);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 }
2112 }2206 }
2207 const nlocals = locals.items.len;
21132208
2114 const nexports = self.exports.items().len;2209 const nexports = self.exports.items().len;
2115 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);2210 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
...@@ -2392,3 +2487,7 @@ fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool {...@@ -2392,3 +2487,7 @@ fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool {
2392 if ((sym.n_type & macho.N_EXT) == 0) return false;2487 if ((sym.n_type & macho.N_EXT) == 0) return false;
2393 return (sym.n_type & macho.N_PEXT) == 0;2488 return (sym.n_type & macho.N_PEXT) == 0;
2394}2489}
2490
2491fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool {
2492 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
2493}