| ... | ... | @@ -60,7 +60,7 @@ tlv_section_index: ?u16 = null, |
| 60 | 60 | la_symbol_ptr_section_index: ?u16 = null, |
| 61 | 61 | data_section_index: ?u16 = null, |
| 62 | 62 | |
| 63 | | locals: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, |
| 63 | locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{}, |
| 64 | 64 | exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, |
| 65 | 65 | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 66 | 66 | lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| ... | ... | @@ -74,6 +74,18 @@ stub_helper_stubs_start_off: ?u64 = null, |
| 74 | 74 | segments_directory: std.AutoHashMapUnmanaged([16]u8, u16) = .{}, |
| 75 | 75 | directory: std.AutoHashMapUnmanaged(DirectoryKey, DirectoryEntry) = .{}, |
| 76 | 76 | |
| 77 | const 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 | |
| 77 | 89 | const DirectoryKey = struct { |
| 78 | 90 | segname: [16]u8, |
| 79 | 91 | sectname: [16]u8, |
| ... | ... | @@ -198,6 +210,7 @@ pub fn deinit(self: *Zld) void { |
| 198 | 210 | self.exports.deinit(self.allocator); |
| 199 | 211 | for (self.locals.items()) |*entry| { |
| 200 | 212 | self.allocator.free(entry.key); |
| 213 | entry.value.deinit(self.allocator); |
| 201 | 214 | } |
| 202 | 215 | self.locals.deinit(self.allocator); |
| 203 | 216 | for (self.objects.items) |*object| { |
| ... | ... | @@ -773,7 +786,7 @@ fn resolveSymbols(self: *Zld) !void { |
| 773 | 786 | var next_address = std.AutoHashMap(DirectoryKey, Address).init(self.allocator); |
| 774 | 787 | defer next_address.deinit(); |
| 775 | 788 | |
| 776 | | for (self.objects.items) |object| { |
| 789 | for (self.objects.items) |*object| { |
| 777 | 790 | const seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 778 | 791 | |
| 779 | 792 | for (seg.sections.items) |sect| { |
| ... | ... | @@ -799,11 +812,32 @@ fn resolveSymbols(self: *Zld) !void { |
| 799 | 812 | if (isImport(&sym)) continue; |
| 800 | 813 | |
| 801 | 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 | } |
| 802 | 820 | |
| 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 | } |
| 807 | 841 | } |
| 808 | 842 | |
| 809 | 843 | const sect = seg.sections.items[sym.n_sect - 1]; |
| ... | ... | @@ -813,10 +847,9 @@ fn resolveSymbols(self: *Zld) !void { |
| 813 | 847 | }; |
| 814 | 848 | const res = self.directory.get(key) orelse continue; |
| 815 | 849 | |
| 816 | | const n_strx = try self.makeString(sym_name); |
| 817 | 850 | const n_value = sym.n_value - sect.addr + next_address.get(key).?.addr; |
| 818 | 851 | |
| 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 }); |
| 820 | 853 | |
| 821 | 854 | var n_sect = res.sect_index + 1; |
| 822 | 855 | for (self.load_commands.items) |sseg, i| { |
| ... | ... | @@ -826,13 +859,17 @@ fn resolveSymbols(self: *Zld) !void { |
| 826 | 859 | n_sect += @intCast(u16, sseg.Segment.sections.items.len); |
| 827 | 860 | } |
| 828 | 861 | |
| 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, |
| 836 | 873 | }); |
| 837 | 874 | } |
| 838 | 875 | } |
| ... | ... | @@ -1212,8 +1249,25 @@ fn relocTargetAddr(self: *Zld, object: Object, rel: macho.relocation_info, next_ |
| 1212 | 1249 | // Relocate to either the artifact's local symbol, or an import from |
| 1213 | 1250 | // shared library. |
| 1214 | 1251 | 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; |
| 1217 | 1271 | } else if (self.lazy_imports.get(sym_name)) |ext| { |
| 1218 | 1272 | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1219 | 1273 | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| ... | ... | @@ -1710,19 +1764,37 @@ fn setEntryPoint(self: *Zld) !void { |
| 1710 | 1764 | // entrypoint. For now, assume default of `_main`. |
| 1711 | 1765 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1712 | 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 | } |
| 1714 | 1786 | |
| 1715 | 1787 | const name = try self.allocator.dupe(u8, "_main"); |
| 1716 | 1788 | 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, |
| 1719 | 1791 | .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, |
| 1722 | 1794 | }); |
| 1723 | 1795 | |
| 1724 | 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 | } |
| 1727 | 1799 | |
| 1728 | 1800 | fn writeRebaseInfoTable(self: *Zld) !void { |
| ... | ... | @@ -1968,9 +2040,9 @@ fn writeDebugInfo(self: *Zld) !void { |
| 1968 | 2040 | var stabs = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 1969 | 2041 | defer stabs.deinit(); |
| 1970 | 2042 | |
| 1971 | | for (self.objects.items) |object| { |
| 2043 | for (self.objects.items) |*object| { |
| 1972 | 2044 | var debug_info = blk: { |
| 1973 | | var di = try DebugInfo.parseFromObject(self.allocator, object); |
| 2045 | var di = try DebugInfo.parseFromObject(self.allocator, object.*); |
| 1974 | 2046 | break :blk di orelse continue; |
| 1975 | 2047 | }; |
| 1976 | 2048 | defer debug_info.deinit(self.allocator); |
| ... | ... | @@ -2017,7 +2089,12 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2017 | 2089 | for (object.symtab.items) |source_sym| { |
| 2018 | 2090 | const symname = object.getString(source_sym.n_strx); |
| 2019 | 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 | }; |
| 2021 | 2098 | |
| 2022 | 2099 | const maybe_size = blk: for (debug_info.inner.func_list.items) |func| { |
| 2023 | 2100 | if (func.pc_range) |range| { |
| ... | ... | @@ -2031,16 +2108,16 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2031 | 2108 | try stabs.append(.{ |
| 2032 | 2109 | .n_strx = 0, |
| 2033 | 2110 | .n_type = macho.N_BNSYM, |
| 2034 | | .n_sect = target_sym.n_sect, |
| 2111 | .n_sect = target_sym.inner.n_sect, |
| 2035 | 2112 | .n_desc = 0, |
| 2036 | | .n_value = target_sym.n_value, |
| 2113 | .n_value = target_sym.inner.n_value, |
| 2037 | 2114 | }); |
| 2038 | 2115 | try stabs.append(.{ |
| 2039 | | .n_strx = target_sym.n_strx, |
| 2116 | .n_strx = target_sym.inner.n_strx, |
| 2040 | 2117 | .n_type = macho.N_FUN, |
| 2041 | | .n_sect = target_sym.n_sect, |
| 2118 | .n_sect = target_sym.inner.n_sect, |
| 2042 | 2119 | .n_desc = 0, |
| 2043 | | .n_value = target_sym.n_value, |
| 2120 | .n_value = target_sym.inner.n_value, |
| 2044 | 2121 | }); |
| 2045 | 2122 | try stabs.append(.{ |
| 2046 | 2123 | .n_strx = 0, |
| ... | ... | @@ -2052,18 +2129,18 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2052 | 2129 | try stabs.append(.{ |
| 2053 | 2130 | .n_strx = 0, |
| 2054 | 2131 | .n_type = macho.N_ENSYM, |
| 2055 | | .n_sect = target_sym.n_sect, |
| 2132 | .n_sect = target_sym.inner.n_sect, |
| 2056 | 2133 | .n_desc = 0, |
| 2057 | 2134 | .n_value = size, |
| 2058 | 2135 | }); |
| 2059 | 2136 | } else { |
| 2060 | 2137 | // TODO need a way to differentiate symbols: global, static, local, etc. |
| 2061 | 2138 | try stabs.append(.{ |
| 2062 | | .n_strx = target_sym.n_strx, |
| 2139 | .n_strx = target_sym.inner.n_strx, |
| 2063 | 2140 | .n_type = macho.N_STSYM, |
| 2064 | | .n_sect = target_sym.n_sect, |
| 2141 | .n_sect = target_sym.inner.n_sect, |
| 2065 | 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 | 2179 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2103 | 2180 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2104 | 2181 | |
| 2105 | | const nlocals = self.locals.items().len; |
| 2106 | 2182 | var locals = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2107 | 2183 | defer locals.deinit(); |
| 2108 | 2184 | |
| 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 | } |
| 2112 | 2206 | } |
| 2207 | const nlocals = locals.items.len; |
| 2113 | 2208 | |
| 2114 | 2209 | const nexports = self.exports.items().len; |
| 2115 | 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 | 2487 | if ((sym.n_type & macho.N_EXT) == 0) return false; |
| 2393 | 2488 | return (sym.n_type & macho.N_PEXT) == 0; |
| 2394 | 2489 | } |
| 2490 | |
| 2491 | fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 2492 | return (sym.n_desc & macho.N_WEAK_DEF) != 0; |
| 2493 | } |