| ... | @@ -13,9 +13,10 @@ const log = std.log.scoped(.zld); | ... | @@ -13,9 +13,10 @@ const log = std.log.scoped(.zld); |
| 13 | const aarch64 = @import("../../codegen/aarch64.zig"); | 13 | const aarch64 = @import("../../codegen/aarch64.zig"); |
| 14 | | 14 | |
| 15 | const Allocator = mem.Allocator; | 15 | const Allocator = mem.Allocator; |
| 16 | const CodeSignature = @import("CodeSignature.zig"); | | |
| 17 | const Archive = @import("Archive.zig"); | 16 | const Archive = @import("Archive.zig"); |
| | 17 | const CodeSignature = @import("CodeSignature.zig"); |
| 18 | const Object = @import("Object.zig"); | 18 | const Object = @import("Object.zig"); |
| | 19 | const Symbol = @import("Symbol.zig"); |
| 19 | const Trie = @import("Trie.zig"); | 20 | const Trie = @import("Trie.zig"); |
| 20 | | 21 | |
| 21 | usingnamespace @import("commands.zig"); | 22 | usingnamespace @import("commands.zig"); |
| ... | @@ -28,10 +29,8 @@ page_size: ?u16 = null, | ... | @@ -28,10 +29,8 @@ page_size: ?u16 = null, |
| 28 | file: ?fs.File = null, | 29 | file: ?fs.File = null, |
| 29 | out_path: ?[]const u8 = null, | 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 | objects: std.ArrayListUnmanaged(Object) = .{}, | 32 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| | 33 | archives: std.ArrayListUnmanaged(Archive) = .{}, |
| 35 | | 34 | |
| 36 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 35 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 37 | | 36 | |
| ... | @@ -74,17 +73,19 @@ la_symbol_ptr_section_index: ?u16 = null, | ... | @@ -74,17 +73,19 @@ la_symbol_ptr_section_index: ?u16 = null, |
| 74 | data_section_index: ?u16 = null, | 73 | data_section_index: ?u16 = null, |
| 75 | bss_section_index: ?u16 = null, | 74 | bss_section_index: ?u16 = null, |
| 76 | | 75 | |
| 77 | locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{}, | 76 | globals: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 78 | exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, | 77 | undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 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 | | | |
| 86 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 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 | stub_helper_stubs_start_off: ?u64 = null, | 89 | stub_helper_stubs_start_off: ?u64 = null, |
| 89 | | 90 | |
| 90 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | 91 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| ... | @@ -112,18 +113,6 @@ const SectionMapping = struct { | ... | @@ -112,18 +113,6 @@ const SectionMapping = struct { |
| 112 | offset: u32, | 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 | const DebugInfo = struct { | 116 | const DebugInfo = struct { |
| 128 | inner: dwarf.DwarfInfo, | 117 | inner: dwarf.DwarfInfo, |
| 129 | debug_info: []u8, | 118 | debug_info: []u8, |
| ... | @@ -188,17 +177,6 @@ const DebugInfo = struct { | ... | @@ -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 | /// Default path to dyld | 180 | /// Default path to dyld |
| 203 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths | 181 | /// TODO instead of hardcoding it, we should probably look through some env vars and search paths |
| 204 | /// instead but this will do for now. | 182 | /// instead but this will do for now. |
| ... | @@ -218,40 +196,42 @@ pub fn init(allocator: *Allocator) Zld { | ... | @@ -218,40 +196,42 @@ pub fn init(allocator: *Allocator) Zld { |
| 218 | } | 196 | } |
| 219 | | 197 | |
| 220 | pub fn deinit(self: *Zld) void { | 198 | pub fn deinit(self: *Zld) void { |
| 221 | self.threadlocal_offsets.deinit(self.allocator); | 199 | for (self.load_commands.items) |*lc| { |
| 222 | self.strtab.deinit(self.allocator); | 200 | lc.deinit(self.allocator); |
| 223 | self.local_rebases.deinit(self.allocator); | | |
| 224 | for (self.lazy_imports.items()) |*entry| { | | |
| 225 | self.allocator.free(entry.key); | | |
| 226 | } | 201 | } |
| 227 | self.lazy_imports.deinit(self.allocator); | 202 | self.load_commands.deinit(self.allocator); |
| 228 | for (self.nonlazy_imports.items()) |*entry| { | 203 | |
| 229 | self.allocator.free(entry.key); | 204 | for (self.objects.items) |*object| { |
| | 205 | object.deinit(); |
| 230 | } | 206 | } |
| 231 | self.nonlazy_imports.deinit(self.allocator); | 207 | self.objects.deinit(self.allocator); |
| 232 | for (self.nonlazy_pointers.items()) |*entry| { | 208 | |
| 233 | self.allocator.free(entry.key); | 209 | for (self.archives.items) |*archive| { |
| | 210 | archive.deinit(); |
| 234 | } | 211 | } |
| 235 | self.nonlazy_pointers.deinit(self.allocator); | 212 | self.archives.deinit(self.allocator); |
| 236 | for (self.exports.items()) |*entry| { | 213 | |
| | 214 | self.mappings.deinit(self.allocator); |
| | 215 | self.unhandled_sections.deinit(self.allocator); |
| | 216 | |
| | 217 | for (self.globals.items()) |*entry| { |
| 237 | self.allocator.free(entry.key); | 218 | self.allocator.free(entry.key); |
| 238 | } | 219 | } |
| 239 | self.exports.deinit(self.allocator); | 220 | self.globals.deinit(self.allocator); |
| 240 | for (self.locals.items()) |*entry| { | 221 | |
| | 222 | for (self.undefs.items()) |*entry| { |
| 241 | self.allocator.free(entry.key); | 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 | for (self.objects.items) |*object| { | 229 | for (self.objects.items) |*object| { |
| 246 | object.deinit(); | 230 | object.file.close(); |
| 247 | } | 231 | } |
| 248 | self.objects.deinit(self.allocator); | 232 | for (self.archives.items) |*archive| { |
| 249 | for (self.load_commands.items) |*lc| { | 233 | archive.file.close(); |
| 250 | lc.deinit(self.allocator); | | |
| 251 | } | 234 | } |
| 252 | self.load_commands.deinit(self.allocator); | | |
| 253 | self.mappings.deinit(self.allocator); | | |
| 254 | self.unhandled_sections.deinit(self.allocator); | | |
| 255 | if (self.file) |*f| f.close(); | 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,16 +272,15 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 292 | | 272 | |
| 293 | try self.populateMetadata(); | 273 | try self.populateMetadata(); |
| 294 | try self.parseInputFiles(files); | 274 | try self.parseInputFiles(files); |
| 295 | try self.sortSections(); | 275 | self.printSymtab(); |
| 296 | try self.resolveImports(); | 276 | // try self.sortSections(); |
| 297 | try self.allocateTextSegment(); | 277 | // try self.allocateTextSegment(); |
| 298 | try self.allocateDataConstSegment(); | 278 | // try self.allocateDataConstSegment(); |
| 299 | try self.allocateDataSegment(); | 279 | // try self.allocateDataSegment(); |
| 300 | self.allocateLinkeditSegment(); | 280 | // self.allocateLinkeditSegment(); |
| 301 | try self.writeStubHelperCommon(); | 281 | // try self.writeStubHelperCommon(); |
| 302 | try self.resolveSymbols(); | 282 | // try self.doRelocs(); |
| 303 | try self.doRelocs(); | 283 | // try self.flush(); |
| 304 | try self.flush(); | | |
| 305 | } | 284 | } |
| 306 | | 285 | |
| 307 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | 286 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| ... | @@ -315,7 +294,7 @@ 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 | const index = @intCast(u16, self.objects.items.len); | 295 | const index = @intCast(u16, self.objects.items.len); |
| 317 | try self.objects.append(self.allocator, object); | 296 | try self.objects.append(self.allocator, object); |
| 318 | try self.updateMetadata(index); | 297 | try self.resolveSymbols(index); |
| 319 | continue; | 298 | continue; |
| 320 | } | 299 | } |
| 321 | | 300 | |
| ... | @@ -324,12 +303,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -324,12 +303,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 324 | error.NotArchive => break :try_archive, | 303 | error.NotArchive => break :try_archive, |
| 325 | else => |e| return e, | 304 | else => |e| return e, |
| 326 | }; | 305 | }; |
| 327 | defer archive.deinit(); | 306 | try self.archives.append(self.allocator, archive); |
| 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 | } | | |
| 333 | continue; | 307 | continue; |
| 334 | } | 308 | } |
| 335 | | 309 | |
| ... | @@ -798,94 +772,6 @@ fn sortSections(self: *Zld) !void { | ... | @@ -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 | fn allocateTextSegment(self: *Zld) !void { | 775 | fn allocateTextSegment(self: *Zld) !void { |
| 890 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 776 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 891 | const nexterns = @intCast(u32, self.lazy_imports.items().len); | 777 | const nexterns = @intCast(u32, self.lazy_imports.items().len); |
| ... | @@ -1267,90 +1153,49 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { | ... | @@ -1267,90 +1153,49 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1267 | try self.file.?.pwriteAll(code, stub_off); | 1153 | try self.file.?.pwriteAll(code, stub_off); |
| 1268 | } | 1154 | } |
| 1269 | | 1155 | |
| 1270 | fn resolveSymbols(self: *Zld) !void { | 1156 | fn resolveSymbols(self: *Zld, object_id: u16) !void { |
| 1271 | for (self.objects.items) |object, object_id| { | 1157 | const object = self.objects.items[object_id]; |
| 1272 | const seg = object.load_commands.items[object.segment_cmd_index.?].Segment; | 1158 | log.warn("resolving symbols in '{s}'", .{object.name}); |
| 1273 | log.debug("\n\n", .{}); | 1159 | |
| 1274 | log.debug("resolving symbols in {s}", .{object.name}); | 1160 | for (object.symtab.items) |sym, sym_id| { |
| 1275 | | 1161 | if (sym.isLocal()) continue; // If symbol is local to CU, we don't put it in the global symbol table. |
| 1276 | for (object.symtab.items) |sym| { | 1162 | |
| 1277 | if (isImport(&sym)) continue; | 1163 | const sym_name = object.getString(sym.inner.n_strx); |
| 1278 | | 1164 | if (sym.isGlobal()) { |
| 1279 | const sym_name = object.getString(sym.n_strx); | 1165 | const global = self.globals.getEntry(sym_name) orelse { |
| 1280 | const out_name = try self.allocator.dupe(u8, sym_name); | 1166 | const name = try self.allocator.dupe(u8, sym_name); |
| 1281 | const locs = try self.locals.getOrPut(self.allocator, out_name); | 1167 | try self.globals.putNoClobber(self.allocator, name, .{ |
| 1282 | defer { | 1168 | .inner = sym.inner, |
| 1283 | if (locs.found_existing) self.allocator.free(out_name); | 1169 | .file = object_id, |
| 1284 | } | 1170 | .index = @intCast(u32, sym_id), |
| 1285 | | 1171 | }); |
| 1286 | if (!locs.found_existing) { | 1172 | _ = self.undefs.swapRemove(sym_name); |
| 1287 | locs.entry.value = .{}; | 1173 | continue; |
| 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 | } | | |
| 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; | 1176 | if (sym.isWeakDef()) continue; // If symbol is weak, nothing to do. |
| 1311 | const target_mapping = self.mappings.get(.{ | 1177 | if (!global.value.isWeakDef()) { // If both symbols are strong, we have a collision. |
| 1312 | .object_id = @intCast(u16, object_id), | 1178 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 1313 | .source_sect_id = source_sect_id, | 1179 | return error.MultipleSymbolDefinitions; |
| 1314 | }) orelse { | 1180 | } |
| 1315 | if (self.unhandled_sections.get(.{ | | |
| 1316 | .object_id = @intCast(u16, object_id), | | |
| 1317 | .source_sect_id = source_sect_id, | | |
| 1318 | }) != null) continue; | | |
| 1319 | | 1181 | |
| 1320 | log.err("section not mapped for symbol '{s}': {}", .{ sym_name, sym }); | 1182 | global.value = .{ |
| 1321 | return error.SectionNotMappedForSymbol; | 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]; | 1187 | } else if (sym.isUndef()) { |
| 1324 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; | 1188 | if (self.globals.contains(sym_name)) continue; // Nothing to do if we already found a definition. |
| 1325 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; | 1189 | if (self.undefs.contains(sym_name)) continue; // No need to reinsert the undef ref. |
| 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 | } | | |
| 1341 | | 1190 | |
| 1342 | const n_strx = try self.makeString(sym_name); | 1191 | const name = try self.allocator.dupe(u8, sym_name); |
| 1343 | try locs.entry.value.append(self.allocator, .{ | 1192 | try self.undefs.putNoClobber(self.allocator, name, .{ |
| 1344 | .inner = .{ | 1193 | .inner = sym.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), | | |
| 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,7 +3020,6 @@ fn writeCodeSignature(self: *Zld) !void { |
| 3175 | try code_sig.write(stream.writer()); | 3020 | try code_sig.write(stream.writer()); |
| 3176 | | 3021 | |
| 3177 | log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); | 3022 | log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len }); |
| 3178 | | | |
| 3179 | try self.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); | 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,34 +3105,19 @@ pub fn parseName(name: *const [16]u8) []const u8 { |
| 3261 | return name[0..len]; | 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 | fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { | 3108 | fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { |
| 3292 | const group_decode = @truncate(u5, inst[3]); | 3109 | const group_decode = @truncate(u5, inst[3]); |
| 3293 | return ((group_decode >> 2) == 4); | 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 | } |