| ... | ... | @@ -13,9 +13,10 @@ const log = std.log.scoped(.zld); |
| 13 | 13 | const aarch64 = @import("../../codegen/aarch64.zig"); |
| 14 | 14 | |
| 15 | 15 | const Allocator = mem.Allocator; |
| 16 | | const CodeSignature = @import("CodeSignature.zig"); |
| 17 | 16 | const Archive = @import("Archive.zig"); |
| 17 | const CodeSignature = @import("CodeSignature.zig"); |
| 18 | 18 | const Object = @import("Object.zig"); |
| 19 | const Symbol = @import("Symbol.zig"); |
| 19 | 20 | const Trie = @import("Trie.zig"); |
| 20 | 21 | |
| 21 | 22 | usingnamespace @import("commands.zig"); |
| ... | ... | @@ -28,10 +29,8 @@ page_size: ?u16 = null, |
| 28 | 29 | file: ?fs.File = null, |
| 29 | 30 | out_path: ?[]const u8 = null, |
| 30 | 31 | |
| 31 | | // TODO Eventually, we will want to keep track of the archives themselves to be able to exclude objects |
| 32 | | // contained within from landing in the final artifact. For now however, since we don't optimise the binary |
| 33 | | // at all, we just move all objects from the archives into the final artifact. |
| 34 | 32 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 33 | archives: std.ArrayListUnmanaged(Archive) = .{}, |
| 35 | 34 | |
| 36 | 35 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 37 | 36 | |
| ... | ... | @@ -74,17 +73,19 @@ la_symbol_ptr_section_index: ?u16 = null, |
| 74 | 73 | data_section_index: ?u16 = null, |
| 75 | 74 | bss_section_index: ?u16 = null, |
| 76 | 75 | |
| 77 | | locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{}, |
| 78 | | exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, |
| 79 | | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 80 | | lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 81 | | tlv_bootstrap: ?Import = null, |
| 82 | | threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 83 | | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 84 | | nonlazy_pointers: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 85 | | |
| 76 | globals: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 77 | undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 86 | 78 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 87 | 79 | |
| 80 | // locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{}, |
| 81 | // exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, |
| 82 | // nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 83 | // lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 84 | // tlv_bootstrap: ?Import = null, |
| 85 | // threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 86 | // local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 87 | // nonlazy_pointers: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 88 | |
| 88 | 89 | stub_helper_stubs_start_off: ?u64 = null, |
| 89 | 90 | |
| 90 | 91 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| ... | ... | @@ -112,18 +113,6 @@ const SectionMapping = struct { |
| 112 | 113 | offset: u32, |
| 113 | 114 | }; |
| 114 | 115 | |
| 115 | | const Symbol = struct { |
| 116 | | inner: macho.nlist_64, |
| 117 | | tt: Type, |
| 118 | | object_id: u16, |
| 119 | | |
| 120 | | const Type = enum { |
| 121 | | Local, |
| 122 | | WeakGlobal, |
| 123 | | Global, |
| 124 | | }; |
| 125 | | }; |
| 126 | | |
| 127 | 116 | const DebugInfo = struct { |
| 128 | 117 | inner: dwarf.DwarfInfo, |
| 129 | 118 | debug_info: []u8, |
| ... | ... | @@ -188,17 +177,6 @@ const DebugInfo = struct { |
| 188 | 177 | } |
| 189 | 178 | }; |
| 190 | 179 | |
| 191 | | pub const Import = struct { |
| 192 | | /// MachO symbol table entry. |
| 193 | | symbol: macho.nlist_64, |
| 194 | | |
| 195 | | /// Id of the dynamic library where the specified entries can be found. |
| 196 | | dylib_ordinal: i64, |
| 197 | | |
| 198 | | /// Index of this import within the import list. |
| 199 | | index: u32, |
| 200 | | }; |
| 201 | | |
| 202 | 180 | /// Default path to dyld |
| 203 | 181 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths |
| 204 | 182 | /// instead but this will do for now. |
| ... | ... | @@ -218,40 +196,42 @@ pub fn init(allocator: *Allocator) Zld { |
| 218 | 196 | } |
| 219 | 197 | |
| 220 | 198 | pub fn deinit(self: *Zld) void { |
| 221 | | self.threadlocal_offsets.deinit(self.allocator); |
| 222 | | self.strtab.deinit(self.allocator); |
| 223 | | self.local_rebases.deinit(self.allocator); |
| 224 | | for (self.lazy_imports.items()) |*entry| { |
| 225 | | self.allocator.free(entry.key); |
| 199 | for (self.load_commands.items) |*lc| { |
| 200 | lc.deinit(self.allocator); |
| 226 | 201 | } |
| 227 | | self.lazy_imports.deinit(self.allocator); |
| 228 | | for (self.nonlazy_imports.items()) |*entry| { |
| 229 | | self.allocator.free(entry.key); |
| 202 | self.load_commands.deinit(self.allocator); |
| 203 | |
| 204 | for (self.objects.items) |*object| { |
| 205 | object.deinit(); |
| 230 | 206 | } |
| 231 | | self.nonlazy_imports.deinit(self.allocator); |
| 232 | | for (self.nonlazy_pointers.items()) |*entry| { |
| 233 | | self.allocator.free(entry.key); |
| 207 | self.objects.deinit(self.allocator); |
| 208 | |
| 209 | for (self.archives.items) |*archive| { |
| 210 | archive.deinit(); |
| 234 | 211 | } |
| 235 | | self.nonlazy_pointers.deinit(self.allocator); |
| 236 | | for (self.exports.items()) |*entry| { |
| 212 | self.archives.deinit(self.allocator); |
| 213 | |
| 214 | self.mappings.deinit(self.allocator); |
| 215 | self.unhandled_sections.deinit(self.allocator); |
| 216 | |
| 217 | for (self.globals.items()) |*entry| { |
| 237 | 218 | self.allocator.free(entry.key); |
| 238 | 219 | } |
| 239 | | self.exports.deinit(self.allocator); |
| 240 | | for (self.locals.items()) |*entry| { |
| 220 | self.globals.deinit(self.allocator); |
| 221 | |
| 222 | for (self.undefs.items()) |*entry| { |
| 241 | 223 | self.allocator.free(entry.key); |
| 242 | | entry.value.deinit(self.allocator); |
| 243 | 224 | } |
| 244 | | self.locals.deinit(self.allocator); |
| 225 | self.undefs.deinit(self.allocator); |
| 226 | } |
| 227 | |
| 228 | pub fn closeFiles(self: *Zld) void { |
| 245 | 229 | for (self.objects.items) |*object| { |
| 246 | | object.deinit(); |
| 230 | object.file.close(); |
| 247 | 231 | } |
| 248 | | self.objects.deinit(self.allocator); |
| 249 | | for (self.load_commands.items) |*lc| { |
| 250 | | lc.deinit(self.allocator); |
| 232 | for (self.archives.items) |*archive| { |
| 233 | archive.file.close(); |
| 251 | 234 | } |
| 252 | | self.load_commands.deinit(self.allocator); |
| 253 | | self.mappings.deinit(self.allocator); |
| 254 | | self.unhandled_sections.deinit(self.allocator); |
| 255 | 235 | if (self.file) |*f| f.close(); |
| 256 | 236 | } |
| 257 | 237 | |
| ... | ... | @@ -292,16 +272,15 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 292 | 272 | |
| 293 | 273 | try self.populateMetadata(); |
| 294 | 274 | try self.parseInputFiles(files); |
| 295 | | try self.sortSections(); |
| 296 | | try self.resolveImports(); |
| 297 | | try self.allocateTextSegment(); |
| 298 | | try self.allocateDataConstSegment(); |
| 299 | | try self.allocateDataSegment(); |
| 300 | | self.allocateLinkeditSegment(); |
| 301 | | try self.writeStubHelperCommon(); |
| 302 | | try self.resolveSymbols(); |
| 303 | | try self.doRelocs(); |
| 304 | | try self.flush(); |
| 275 | self.printSymtab(); |
| 276 | // try self.sortSections(); |
| 277 | // try self.allocateTextSegment(); |
| 278 | // try self.allocateDataConstSegment(); |
| 279 | // try self.allocateDataSegment(); |
| 280 | // self.allocateLinkeditSegment(); |
| 281 | // try self.writeStubHelperCommon(); |
| 282 | // try self.doRelocs(); |
| 283 | // try self.flush(); |
| 305 | 284 | } |
| 306 | 285 | |
| 307 | 286 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| ... | ... | @@ -315,7 +294,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 315 | 294 | }; |
| 316 | 295 | const index = @intCast(u16, self.objects.items.len); |
| 317 | 296 | try self.objects.append(self.allocator, object); |
| 318 | | try self.updateMetadata(index); |
| 297 | try self.resolveSymbols(index); |
| 319 | 298 | continue; |
| 320 | 299 | } |
| 321 | 300 | |
| ... | ... | @@ -324,12 +303,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 324 | 303 | error.NotArchive => break :try_archive, |
| 325 | 304 | else => |e| return e, |
| 326 | 305 | }; |
| 327 | | defer archive.deinit(); |
| 328 | | while (archive.objects.popOrNull()) |object| { |
| 329 | | const index = @intCast(u16, self.objects.items.len); |
| 330 | | try self.objects.append(self.allocator, object); |
| 331 | | try self.updateMetadata(index); |
| 332 | | } |
| 306 | try self.archives.append(self.allocator, archive); |
| 333 | 307 | continue; |
| 334 | 308 | } |
| 335 | 309 | |
| ... | ... | @@ -798,94 +772,6 @@ fn sortSections(self: *Zld) !void { |
| 798 | 772 | } |
| 799 | 773 | } |
| 800 | 774 | |
| 801 | | fn resolveImports(self: *Zld) !void { |
| 802 | | var imports = std.StringArrayHashMap(bool).init(self.allocator); |
| 803 | | defer imports.deinit(); |
| 804 | | |
| 805 | | for (self.objects.items) |object| { |
| 806 | | for (object.symtab.items) |sym| { |
| 807 | | if (isLocal(&sym)) continue; |
| 808 | | |
| 809 | | const name = object.getString(sym.n_strx); |
| 810 | | const res = try imports.getOrPut(name); |
| 811 | | if (isExport(&sym)) { |
| 812 | | res.entry.value = false; |
| 813 | | continue; |
| 814 | | } |
| 815 | | if (res.found_existing and !res.entry.value) |
| 816 | | continue; |
| 817 | | res.entry.value = true; |
| 818 | | } |
| 819 | | } |
| 820 | | |
| 821 | | for (imports.items()) |entry| { |
| 822 | | if (!entry.value) continue; |
| 823 | | |
| 824 | | const sym_name = entry.key; |
| 825 | | const n_strx = try self.makeString(sym_name); |
| 826 | | var new_sym: macho.nlist_64 = .{ |
| 827 | | .n_strx = n_strx, |
| 828 | | .n_type = macho.N_UNDF | macho.N_EXT, |
| 829 | | .n_value = 0, |
| 830 | | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, |
| 831 | | .n_sect = 0, |
| 832 | | }; |
| 833 | | var key = try self.allocator.dupe(u8, sym_name); |
| 834 | | // TODO handle symbol resolution from non-libc dylibs. |
| 835 | | const dylib_ordinal = 1; |
| 836 | | |
| 837 | | // TODO need to rework this. Perhaps should create a set of all possible libc |
| 838 | | // symbols which are expected to be nonlazy? |
| 839 | | if (mem.eql(u8, sym_name, "___stdoutp") or |
| 840 | | mem.eql(u8, sym_name, "___stderrp") or |
| 841 | | mem.eql(u8, sym_name, "___stdinp") or |
| 842 | | mem.eql(u8, sym_name, "___stack_chk_guard") or |
| 843 | | mem.eql(u8, sym_name, "_environ") or |
| 844 | | mem.eql(u8, sym_name, "__DefaultRuneLocale") or |
| 845 | | mem.eql(u8, sym_name, "_mach_task_self_")) |
| 846 | | { |
| 847 | | log.debug("writing nonlazy symbol '{s}'", .{sym_name}); |
| 848 | | const index = @intCast(u32, self.nonlazy_imports.items().len); |
| 849 | | try self.nonlazy_imports.putNoClobber(self.allocator, key, .{ |
| 850 | | .symbol = new_sym, |
| 851 | | .dylib_ordinal = dylib_ordinal, |
| 852 | | .index = index, |
| 853 | | }); |
| 854 | | } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) { |
| 855 | | log.debug("writing threadlocal symbol '{s}'", .{sym_name}); |
| 856 | | self.tlv_bootstrap = .{ |
| 857 | | .symbol = new_sym, |
| 858 | | .dylib_ordinal = dylib_ordinal, |
| 859 | | .index = 0, |
| 860 | | }; |
| 861 | | } else { |
| 862 | | log.debug("writing lazy symbol '{s}'", .{sym_name}); |
| 863 | | const index = @intCast(u32, self.lazy_imports.items().len); |
| 864 | | try self.lazy_imports.putNoClobber(self.allocator, key, .{ |
| 865 | | .symbol = new_sym, |
| 866 | | .dylib_ordinal = dylib_ordinal, |
| 867 | | .index = index, |
| 868 | | }); |
| 869 | | } |
| 870 | | } |
| 871 | | |
| 872 | | const n_strx = try self.makeString("dyld_stub_binder"); |
| 873 | | const name = try self.allocator.dupe(u8, "dyld_stub_binder"); |
| 874 | | log.debug("writing nonlazy symbol 'dyld_stub_binder'", .{}); |
| 875 | | const index = @intCast(u32, self.nonlazy_imports.items().len); |
| 876 | | try self.nonlazy_imports.putNoClobber(self.allocator, name, .{ |
| 877 | | .symbol = .{ |
| 878 | | .n_strx = n_strx, |
| 879 | | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| 880 | | .n_sect = 0, |
| 881 | | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, |
| 882 | | .n_value = 0, |
| 883 | | }, |
| 884 | | .dylib_ordinal = 1, |
| 885 | | .index = index, |
| 886 | | }); |
| 887 | | } |
| 888 | | |
| 889 | 775 | fn allocateTextSegment(self: *Zld) !void { |
| 890 | 776 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 891 | 777 | const nexterns = @intCast(u32, self.lazy_imports.items().len); |
| ... | ... | @@ -1267,90 +1153,49 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1267 | 1153 | try self.file.?.pwriteAll(code, stub_off); |
| 1268 | 1154 | } |
| 1269 | 1155 | |
| 1270 | | fn resolveSymbols(self: *Zld) !void { |
| 1271 | | for (self.objects.items) |object, object_id| { |
| 1272 | | const seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 1273 | | log.debug("\n\n", .{}); |
| 1274 | | log.debug("resolving symbols in {s}", .{object.name}); |
| 1275 | | |
| 1276 | | for (object.symtab.items) |sym| { |
| 1277 | | if (isImport(&sym)) continue; |
| 1278 | | |
| 1279 | | const sym_name = object.getString(sym.n_strx); |
| 1280 | | const out_name = try self.allocator.dupe(u8, sym_name); |
| 1281 | | const locs = try self.locals.getOrPut(self.allocator, out_name); |
| 1282 | | defer { |
| 1283 | | if (locs.found_existing) self.allocator.free(out_name); |
| 1284 | | } |
| 1285 | | |
| 1286 | | if (!locs.found_existing) { |
| 1287 | | locs.entry.value = .{}; |
| 1288 | | } |
| 1289 | | |
| 1290 | | const tt: Symbol.Type = blk: { |
| 1291 | | if (isLocal(&sym)) { |
| 1292 | | break :blk .Local; |
| 1293 | | } else if (isWeakDef(&sym)) { |
| 1294 | | break :blk .WeakGlobal; |
| 1295 | | } else { |
| 1296 | | break :blk .Global; |
| 1297 | | } |
| 1156 | fn resolveSymbols(self: *Zld, object_id: u16) !void { |
| 1157 | const object = self.objects.items[object_id]; |
| 1158 | log.warn("resolving symbols in '{s}'", .{object.name}); |
| 1159 | |
| 1160 | for (object.symtab.items) |sym, sym_id| { |
| 1161 | if (sym.isLocal()) continue; // If symbol is local to CU, we don't put it in the global symbol table. |
| 1162 | |
| 1163 | const sym_name = object.getString(sym.inner.n_strx); |
| 1164 | if (sym.isGlobal()) { |
| 1165 | const global = self.globals.getEntry(sym_name) orelse { |
| 1166 | const name = try self.allocator.dupe(u8, sym_name); |
| 1167 | try self.globals.putNoClobber(self.allocator, name, .{ |
| 1168 | .inner = sym.inner, |
| 1169 | .file = object_id, |
| 1170 | .index = @intCast(u32, sym_id), |
| 1171 | }); |
| 1172 | _ = self.undefs.swapRemove(sym_name); |
| 1173 | continue; |
| 1298 | 1174 | }; |
| 1299 | | if (tt == .Global) { |
| 1300 | | for (locs.entry.value.items) |ss| { |
| 1301 | | if (ss.tt == .Global) { |
| 1302 | | log.debug("symbol already defined '{s}'", .{sym_name}); |
| 1303 | | continue; |
| 1304 | | // log.err("symbol '{s}' defined multiple times: {}", .{ sym_name, sym }); |
| 1305 | | // return error.MultipleSymbolDefinitions; |
| 1306 | | } |
| 1307 | | } |
| 1308 | | } |
| 1309 | 1175 | |
| 1310 | | const source_sect_id = sym.n_sect - 1; |
| 1311 | | const target_mapping = self.mappings.get(.{ |
| 1312 | | .object_id = @intCast(u16, object_id), |
| 1313 | | .source_sect_id = source_sect_id, |
| 1314 | | }) orelse { |
| 1315 | | if (self.unhandled_sections.get(.{ |
| 1316 | | .object_id = @intCast(u16, object_id), |
| 1317 | | .source_sect_id = source_sect_id, |
| 1318 | | }) != null) continue; |
| 1176 | if (sym.isWeakDef()) continue; // If symbol is weak, nothing to do. |
| 1177 | if (!global.value.isWeakDef()) { // If both symbols are strong, we have a collision. |
| 1178 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 1179 | return error.MultipleSymbolDefinitions; |
| 1180 | } |
| 1319 | 1181 | |
| 1320 | | log.err("section not mapped for symbol '{s}': {}", .{ sym_name, sym }); |
| 1321 | | return error.SectionNotMappedForSymbol; |
| 1182 | global.value = .{ |
| 1183 | .inner = sym.inner, |
| 1184 | .file = object_id, |
| 1185 | .index = @intCast(u32, sym_id), |
| 1322 | 1186 | }; |
| 1323 | | const source_sect = seg.sections.items[source_sect_id]; |
| 1324 | | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; |
| 1325 | | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; |
| 1326 | | const target_addr = target_sect.addr + target_mapping.offset; |
| 1327 | | const n_value = sym.n_value - source_sect.addr + target_addr; |
| 1328 | | |
| 1329 | | log.debug("resolving '{s}':{} as {s} symbol at 0x{x}", .{ sym_name, sym, tt, n_value }); |
| 1330 | | |
| 1331 | | // TODO there might be a more generic way of doing this. |
| 1332 | | var n_sect: u16 = 0; |
| 1333 | | for (self.load_commands.items) |cmd, cmd_id| { |
| 1334 | | if (cmd != .Segment) break; |
| 1335 | | if (cmd_id == target_mapping.target_seg_id) { |
| 1336 | | n_sect += target_mapping.target_sect_id + 1; |
| 1337 | | break; |
| 1338 | | } |
| 1339 | | n_sect += @intCast(u16, cmd.Segment.sections.items.len); |
| 1340 | | } |
| 1187 | } else if (sym.isUndef()) { |
| 1188 | if (self.globals.contains(sym_name)) continue; // Nothing to do if we already found a definition. |
| 1189 | if (self.undefs.contains(sym_name)) continue; // No need to reinsert the undef ref. |
| 1341 | 1190 | |
| 1342 | | const n_strx = try self.makeString(sym_name); |
| 1343 | | try locs.entry.value.append(self.allocator, .{ |
| 1344 | | .inner = .{ |
| 1345 | | .n_strx = n_strx, |
| 1346 | | .n_value = n_value, |
| 1347 | | .n_type = macho.N_SECT, |
| 1348 | | .n_desc = sym.n_desc, |
| 1349 | | .n_sect = @intCast(u8, n_sect), |
| 1350 | | }, |
| 1351 | | .tt = tt, |
| 1352 | | .object_id = @intCast(u16, object_id), |
| 1191 | const name = try self.allocator.dupe(u8, sym_name); |
| 1192 | try self.undefs.putNoClobber(self.allocator, name, .{ |
| 1193 | .inner = sym.inner, |
| 1353 | 1194 | }); |
| 1195 | } else { |
| 1196 | // Oh no, unhandled symbol type, report back to the user. |
| 1197 | log.err("unhandled symbol type for symbol {any}", .{sym}); |
| 1198 | return error.UnhandledSymbolType; |
| 1354 | 1199 | } |
| 1355 | 1200 | } |
| 1356 | 1201 | } |
| ... | ... | @@ -3175,7 +3020,6 @@ fn writeCodeSignature(self: *Zld) !void { |
| 3175 | 3020 | try code_sig.write(stream.writer()); |
| 3176 | 3021 | |
| 3177 | 3022 | log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); |
| 3178 | | |
| 3179 | 3023 | try self.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); |
| 3180 | 3024 | } |
| 3181 | 3025 | |
| ... | ... | @@ -3261,34 +3105,19 @@ pub fn parseName(name: *const [16]u8) []const u8 { |
| 3261 | 3105 | return name[0..len]; |
| 3262 | 3106 | } |
| 3263 | 3107 | |
| 3264 | | fn isLocal(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 3265 | | if (isExtern(sym)) return false; |
| 3266 | | const tt = macho.N_TYPE & sym.n_type; |
| 3267 | | return tt == macho.N_SECT; |
| 3268 | | } |
| 3269 | | |
| 3270 | | fn isExport(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 3271 | | if (!isExtern(sym)) return false; |
| 3272 | | const tt = macho.N_TYPE & sym.n_type; |
| 3273 | | return tt == macho.N_SECT; |
| 3274 | | } |
| 3275 | | |
| 3276 | | fn isImport(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 3277 | | if (!isExtern(sym)) return false; |
| 3278 | | const tt = macho.N_TYPE & sym.n_type; |
| 3279 | | return tt == macho.N_UNDF; |
| 3280 | | } |
| 3281 | | |
| 3282 | | fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 3283 | | if ((sym.n_type & macho.N_EXT) == 0) return false; |
| 3284 | | return (sym.n_type & macho.N_PEXT) == 0; |
| 3285 | | } |
| 3286 | | |
| 3287 | | fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool { |
| 3288 | | return (sym.n_desc & macho.N_WEAK_DEF) != 0; |
| 3289 | | } |
| 3290 | | |
| 3291 | 3108 | fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { |
| 3292 | 3109 | const group_decode = @truncate(u5, inst[3]); |
| 3293 | 3110 | return ((group_decode >> 2) == 4); |
| 3294 | 3111 | } |
| 3112 | |
| 3113 | fn printSymtab(self: Zld) void { |
| 3114 | log.warn("globals", .{}); |
| 3115 | for (self.globals.items()) |entry| { |
| 3116 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); |
| 3117 | } |
| 3118 | |
| 3119 | log.warn("undefs", .{}); |
| 3120 | for (self.undefs.items()) |entry| { |
| 3121 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); |
| 3122 | } |
| 3123 | } |