| ... | @@ -78,9 +78,10 @@ pub const Zld = struct { | ... | @@ -78,9 +78,10 @@ pub const Zld = struct { |
| 78 | resolver: std.StringHashMapUnmanaged(u32) = .{}, | 78 | resolver: std.StringHashMapUnmanaged(u32) = .{}, |
| 79 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, | 79 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 80 | | 80 | |
| | 81 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| | 82 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| | 83 | |
| 81 | entry_index: ?u32 = null, | 84 | entry_index: ?u32 = null, |
| 82 | mh_execute_header_index: ?u32 = null, | | |
| 83 | dso_handle_index: ?u32 = null, | | |
| 84 | dyld_stub_binder_index: ?u32 = null, | 85 | dyld_stub_binder_index: ?u32 = null, |
| 85 | dyld_private_atom_index: ?Atom.Index = null, | 86 | dyld_private_atom_index: ?Atom.Index = null, |
| 86 | | 87 | |
| ... | @@ -188,15 +189,23 @@ pub const Zld = struct { | ... | @@ -188,15 +189,23 @@ pub const Zld = struct { |
| 188 | } | 189 | } |
| 189 | } | 190 | } |
| 190 | | 191 | |
| 191 | fn addUndefined(self: *Zld, name: []const u8) !void { | 192 | fn addUndefined(self: *Zld, name: []const u8) !u32 { |
| | 193 | const gop = try self.getOrPutGlobalPtr(name); |
| | 194 | const global_index = self.getGlobalIndex(name).?; |
| | 195 | |
| | 196 | if (gop.found_existing) return global_index; |
| | 197 | |
| 192 | const sym_index = try self.allocateSymbol(); | 198 | const sym_index = try self.allocateSymbol(); |
| 193 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; | 199 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; |
| | 200 | gop.value_ptr.* = sym_loc; |
| | 201 | |
| 194 | const sym = self.getSymbolPtr(sym_loc); | 202 | const sym = self.getSymbolPtr(sym_loc); |
| 195 | sym.n_strx = try self.strtab.insert(self.gpa, name); | 203 | sym.n_strx = try self.strtab.insert(self.gpa, name); |
| 196 | sym.n_type = macho.N_UNDF; | 204 | sym.n_type = macho.N_UNDF; |
| 197 | const global_index = try self.addGlobal(sym_loc); | 205 | |
| 198 | try self.resolver.putNoClobber(self.gpa, name, global_index); | | |
| 199 | try self.unresolved.putNoClobber(self.gpa, global_index, {}); | 206 | try self.unresolved.putNoClobber(self.gpa, global_index, {}); |
| | 207 | |
| | 208 | return global_index; |
| 200 | } | 209 | } |
| 201 | | 210 | |
| 202 | fn resolveSymbols(self: *Zld) !void { | 211 | fn resolveSymbols(self: *Zld) !void { |
| ... | @@ -205,12 +214,12 @@ pub const Zld = struct { | ... | @@ -205,12 +214,12 @@ pub const Zld = struct { |
| 205 | // on the linker line. | 214 | // on the linker line. |
| 206 | if (self.options.output_mode == .Exe) { | 215 | if (self.options.output_mode == .Exe) { |
| 207 | const entry_name = self.options.entry orelse load_commands.default_entry_point; | 216 | const entry_name = self.options.entry orelse load_commands.default_entry_point; |
| 208 | try self.addUndefined(entry_name); | 217 | _ = try self.addUndefined(entry_name); |
| 209 | } | 218 | } |
| 210 | | 219 | |
| 211 | // Force resolution of any symbols requested by the user. | 220 | // Force resolution of any symbols requested by the user. |
| 212 | for (self.options.force_undefined_symbols.keys()) |sym_name| { | 221 | for (self.options.force_undefined_symbols.keys()) |sym_name| { |
| 213 | try self.addUndefined(sym_name); | 222 | _ = try self.addUndefined(sym_name); |
| 214 | } | 223 | } |
| 215 | | 224 | |
| 216 | for (self.objects.items, 0..) |_, object_id| { | 225 | for (self.objects.items, 0..) |_, object_id| { |
| ... | @@ -222,13 +231,11 @@ pub const Zld = struct { | ... | @@ -222,13 +231,11 @@ pub const Zld = struct { |
| 222 | // Finally, force resolution of dyld_stub_binder if there are imports | 231 | // Finally, force resolution of dyld_stub_binder if there are imports |
| 223 | // requested. | 232 | // requested. |
| 224 | if (self.unresolved.count() > 0) { | 233 | if (self.unresolved.count() > 0) { |
| 225 | try self.addUndefined("dyld_stub_binder"); | 234 | self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder"); |
| 226 | } | 235 | } |
| 227 | | 236 | |
| 228 | try self.resolveSymbolsInDylibs(); | 237 | try self.resolveSymbolsInDylibs(); |
| 229 | | 238 | |
| 230 | self.dyld_stub_binder_index = self.resolver.get("dyld_stub_binder"); | | |
| 231 | | | |
| 232 | try self.createMhExecuteHeaderSymbol(); | 239 | try self.createMhExecuteHeaderSymbol(); |
| 233 | try self.createDsoHandleSymbol(); | 240 | try self.createDsoHandleSymbol(); |
| 234 | try self.resolveSymbolsAtLoading(); | 241 | try self.resolveSymbolsAtLoading(); |
| ... | @@ -276,15 +283,16 @@ pub const Zld = struct { | ... | @@ -276,15 +283,16 @@ pub const Zld = struct { |
| 276 | | 283 | |
| 277 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 }; | 284 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 }; |
| 278 | | 285 | |
| 279 | const global_index = self.resolver.get(sym_name) orelse { | 286 | const gop = try self.getOrPutGlobalPtr(sym_name); |
| 280 | const global_index = try self.addGlobal(sym_loc); | 287 | if (!gop.found_existing) { |
| 281 | try self.resolver.putNoClobber(self.gpa, sym_name, global_index); | 288 | gop.value_ptr.* = sym_loc; |
| 282 | if (sym.undf() and !sym.tentative()) { | 289 | if (sym.undf() and !sym.tentative()) { |
| 283 | try self.unresolved.putNoClobber(self.gpa, global_index, {}); | 290 | try self.unresolved.putNoClobber(self.gpa, self.getGlobalIndex(sym_name).?, {}); |
| 284 | } | 291 | } |
| 285 | continue; | 292 | continue; |
| 286 | }; | 293 | } |
| 287 | const global = &self.globals.items[global_index]; | 294 | const global_index = self.getGlobalIndex(sym_name).?; |
| | 295 | const global = gop.value_ptr; |
| 288 | const global_sym = self.getSymbol(global.*); | 296 | const global_sym = self.getSymbol(global.*); |
| 289 | | 297 | |
| 290 | // Cases to consider: sym vs global_sym | 298 | // Cases to consider: sym vs global_sym |
| ... | @@ -338,7 +346,7 @@ pub const Zld = struct { | ... | @@ -338,7 +346,7 @@ pub const Zld = struct { |
| 338 | const global_object = &self.objects.items[file]; | 346 | const global_object = &self.objects.items[file]; |
| 339 | global_object.globals_lookup[global.sym_index] = global_index; | 347 | global_object.globals_lookup[global.sym_index] = global_index; |
| 340 | } | 348 | } |
| 341 | _ = self.unresolved.swapRemove(self.resolver.get(sym_name).?); | 349 | _ = self.unresolved.swapRemove(global_index); |
| 342 | global.* = sym_loc; | 350 | global.* = sym_loc; |
| 343 | } else { | 351 | } else { |
| 344 | object.globals_lookup[sym_index] = global_index; | 352 | object.globals_lookup[sym_index] = global_index; |
| ... | @@ -448,50 +456,51 @@ pub const Zld = struct { | ... | @@ -448,50 +456,51 @@ pub const Zld = struct { |
| 448 | | 456 | |
| 449 | fn createMhExecuteHeaderSymbol(self: *Zld) !void { | 457 | fn createMhExecuteHeaderSymbol(self: *Zld) !void { |
| 450 | if (self.options.output_mode != .Exe) return; | 458 | if (self.options.output_mode != .Exe) return; |
| 451 | if (self.resolver.get("__mh_execute_header")) |global_index| { | | |
| 452 | const global = self.globals.items[global_index]; | | |
| 453 | const sym = self.getSymbol(global); | | |
| 454 | self.mh_execute_header_index = global_index; | | |
| 455 | if (!sym.undf() and !(sym.pext() or sym.weakDef())) return; | | |
| 456 | } | | |
| 457 | | 459 | |
| 458 | const gpa = self.gpa; | 460 | const gpa = self.gpa; |
| 459 | const sym_index = try self.allocateSymbol(); | 461 | const sym_index = try self.allocateSymbol(); |
| 460 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; | 462 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; |
| 461 | const sym = self.getSymbolPtr(sym_loc); | 463 | const sym = self.getSymbolPtr(sym_loc); |
| 462 | sym.n_strx = try self.strtab.insert(gpa, "__mh_execute_header"); | 464 | sym.* = .{ |
| 463 | sym.n_type = macho.N_SECT | macho.N_EXT; | 465 | .n_strx = try self.strtab.insert(gpa, "__mh_execute_header"), |
| 464 | sym.n_desc = macho.REFERENCED_DYNAMICALLY; | 466 | .n_type = macho.N_SECT | macho.N_EXT, |
| | 467 | .n_sect = 0, |
| | 468 | .n_desc = macho.REFERENCED_DYNAMICALLY, |
| | 469 | .n_value = 0, |
| | 470 | }; |
| 465 | | 471 | |
| 466 | if (self.resolver.get("__mh_execute_header")) |global_index| { | 472 | const gop = try self.getOrPutGlobalPtr("__mh_execute_header"); |
| 467 | const global = &self.globals.items[global_index]; | 473 | if (gop.found_existing) { |
| 468 | const global_object = &self.objects.items[global.getFile().?]; | 474 | const global = gop.value_ptr.*; |
| 469 | global_object.globals_lookup[global.sym_index] = global_index; | 475 | if (global.getFile()) |file| { |
| 470 | global.* = sym_loc; | 476 | const global_object = &self.objects.items[file]; |
| 471 | self.mh_execute_header_index = global_index; | 477 | global_object.globals_lookup[global.sym_index] = self.getGlobalIndex("__mh_execute_header").?; |
| 472 | } else { | 478 | } |
| 473 | self.mh_execute_header_index = try self.addGlobal(sym_loc); | | |
| 474 | } | 479 | } |
| | 480 | gop.value_ptr.* = sym_loc; |
| 475 | } | 481 | } |
| 476 | | 482 | |
| 477 | fn createDsoHandleSymbol(self: *Zld) !void { | 483 | fn createDsoHandleSymbol(self: *Zld) !void { |
| 478 | const global_index = self.resolver.get("___dso_handle") orelse return; | 484 | const global = self.getGlobalPtr("___dso_handle") orelse return; |
| 479 | const global = &self.globals.items[global_index]; | | |
| 480 | self.dso_handle_index = global_index; | | |
| 481 | if (!self.getSymbol(global.*).undf()) return; | 485 | if (!self.getSymbol(global.*).undf()) return; |
| 482 | | 486 | |
| 483 | const gpa = self.gpa; | | |
| 484 | const sym_index = try self.allocateSymbol(); | 487 | const sym_index = try self.allocateSymbol(); |
| 485 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; | 488 | const sym_loc = SymbolWithLoc{ .sym_index = sym_index }; |
| 486 | const sym = self.getSymbolPtr(sym_loc); | 489 | const sym = self.getSymbolPtr(sym_loc); |
| 487 | sym.n_strx = try self.strtab.insert(gpa, "___dso_handle"); | 490 | sym.* = .{ |
| 488 | sym.n_type = macho.N_SECT | macho.N_EXT; | 491 | .n_strx = try self.strtab.insert(self.gpa, "___dso_handle"), |
| 489 | sym.n_desc = macho.N_WEAK_DEF; | 492 | .n_type = macho.N_SECT | macho.N_EXT, |
| 490 | | 493 | .n_sect = 0, |
| 491 | const global_object = &self.objects.items[global.getFile().?]; | 494 | .n_desc = macho.N_WEAK_DEF, |
| 492 | global_object.globals_lookup[global.sym_index] = global_index; | 495 | .n_value = 0, |
| 493 | _ = self.unresolved.swapRemove(self.resolver.get("___dso_handle").?); | 496 | }; |
| | 497 | const global_index = self.getGlobalIndex("___dso_handle").?; |
| | 498 | if (global.getFile()) |file| { |
| | 499 | const global_object = &self.objects.items[file]; |
| | 500 | global_object.globals_lookup[global.sym_index] = global_index; |
| | 501 | } |
| 494 | global.* = sym_loc; | 502 | global.* = sym_loc; |
| | 503 | _ = self.unresolved.swapRemove(global_index); |
| 495 | } | 504 | } |
| 496 | | 505 | |
| 497 | pub fn deinit(self: *Zld) void { | 506 | pub fn deinit(self: *Zld) void { |
| ... | @@ -512,6 +521,8 @@ pub const Zld = struct { | ... | @@ -512,6 +521,8 @@ pub const Zld = struct { |
| 512 | self.globals.deinit(gpa); | 521 | self.globals.deinit(gpa); |
| 513 | self.resolver.deinit(gpa); | 522 | self.resolver.deinit(gpa); |
| 514 | self.unresolved.deinit(gpa); | 523 | self.unresolved.deinit(gpa); |
| | 524 | self.locals_free_list.deinit(gpa); |
| | 525 | self.globals_free_list.deinit(gpa); |
| 515 | | 526 | |
| 516 | for (self.objects.items) |*object| { | 527 | for (self.objects.items) |*object| { |
| 517 | object.deinit(gpa); | 528 | object.deinit(gpa); |
| ... | @@ -609,10 +620,24 @@ pub const Zld = struct { | ... | @@ -609,10 +620,24 @@ pub const Zld = struct { |
| 609 | return index; | 620 | return index; |
| 610 | } | 621 | } |
| 611 | | 622 | |
| 612 | fn addGlobal(self: *Zld, sym_loc: SymbolWithLoc) !u32 { | 623 | fn allocateGlobal(self: *Zld) !u32 { |
| 613 | const global_index = @as(u32, @intCast(self.globals.items.len)); | 624 | try self.globals.ensureUnusedCapacity(self.gpa, 1); |
| 614 | try self.globals.append(self.gpa, sym_loc); | 625 | |
| 615 | return global_index; | 626 | const index = blk: { |
| | 627 | if (self.globals_free_list.popOrNull()) |index| { |
| | 628 | log.debug(" (reusing global index {d})", .{index}); |
| | 629 | break :blk index; |
| | 630 | } else { |
| | 631 | log.debug(" (allocating symbol index {d})", .{self.globals.items.len}); |
| | 632 | const index = @as(u32, @intCast(self.globals.items.len)); |
| | 633 | _ = self.globals.addOneAssumeCapacity(); |
| | 634 | break :blk index; |
| | 635 | } |
| | 636 | }; |
| | 637 | |
| | 638 | self.globals.items[index] = .{ .sym_index = 0 }; |
| | 639 | |
| | 640 | return index; |
| 616 | } | 641 | } |
| 617 | | 642 | |
| 618 | pub fn addGotEntry(self: *Zld, target: SymbolWithLoc) !void { | 643 | pub fn addGotEntry(self: *Zld, target: SymbolWithLoc) !void { |
| ... | @@ -656,27 +681,6 @@ pub const Zld = struct { | ... | @@ -656,27 +681,6 @@ pub const Zld = struct { |
| 656 | } | 681 | } |
| 657 | } | 682 | } |
| 658 | | 683 | |
| 659 | fn allocateSpecialSymbols(self: *Zld) !void { | | |
| 660 | for (&[_]?u32{ | | |
| 661 | self.dso_handle_index, | | |
| 662 | self.mh_execute_header_index, | | |
| 663 | }) |maybe_index| { | | |
| 664 | const global_index = maybe_index orelse continue; | | |
| 665 | const global = self.globals.items[global_index]; | | |
| 666 | if (global.getFile() != null) continue; | | |
| 667 | const name = self.getSymbolName(global); | | |
| 668 | const sym = self.getSymbolPtr(global); | | |
| 669 | const segment_index = self.getSegmentByName("__TEXT").?; | | |
| 670 | const seg = self.segments.items[segment_index]; | | |
| 671 | sym.n_sect = 1; | | |
| 672 | sym.n_value = seg.vmaddr; | | |
| 673 | log.debug("allocating {s} at the start of {s}", .{ | | |
| 674 | name, | | |
| 675 | seg.segName(), | | |
| 676 | }); | | |
| 677 | } | | |
| 678 | } | | |
| 679 | | | |
| 680 | fn writeAtoms(self: *Zld) !void { | 684 | fn writeAtoms(self: *Zld) !void { |
| 681 | const gpa = self.gpa; | 685 | const gpa = self.gpa; |
| 682 | const slice = self.sections.slice(); | 686 | const slice = self.sections.slice(); |
| ... | @@ -2037,6 +2041,36 @@ pub const Zld = struct { | ... | @@ -2037,6 +2041,36 @@ pub const Zld = struct { |
| 2037 | } | 2041 | } |
| 2038 | } | 2042 | } |
| 2039 | | 2043 | |
| | 2044 | pub fn getGlobalIndex(self: *const Zld, name: []const u8) ?u32 { |
| | 2045 | return self.resolver.get(name); |
| | 2046 | } |
| | 2047 | |
| | 2048 | pub fn getGlobalPtr(self: *Zld, name: []const u8) ?*SymbolWithLoc { |
| | 2049 | const global_index = self.resolver.get(name) orelse return null; |
| | 2050 | return &self.globals.items[global_index]; |
| | 2051 | } |
| | 2052 | |
| | 2053 | pub fn getGlobal(self: *const Zld, name: []const u8) ?SymbolWithLoc { |
| | 2054 | const global_index = self.resolver.get(name) orelse return null; |
| | 2055 | return self.globals.items[global_index]; |
| | 2056 | } |
| | 2057 | |
| | 2058 | const GetOrPutGlobalPtrResult = struct { |
| | 2059 | found_existing: bool, |
| | 2060 | value_ptr: *SymbolWithLoc, |
| | 2061 | }; |
| | 2062 | |
| | 2063 | pub fn getOrPutGlobalPtr(self: *Zld, name: []const u8) !GetOrPutGlobalPtrResult { |
| | 2064 | if (self.getGlobalPtr(name)) |ptr| { |
| | 2065 | return GetOrPutGlobalPtrResult{ .found_existing = true, .value_ptr = ptr }; |
| | 2066 | } |
| | 2067 | const global_index = try self.allocateGlobal(); |
| | 2068 | const global_name = try self.gpa.dupe(u8, name); |
| | 2069 | _ = try self.resolver.put(self.gpa, global_name, global_index); |
| | 2070 | const ptr = &self.globals.items[global_index]; |
| | 2071 | return GetOrPutGlobalPtrResult{ .found_existing = false, .value_ptr = ptr }; |
| | 2072 | } |
| | 2073 | |
| 2040 | pub fn getGotEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 { | 2074 | pub fn getGotEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 { |
| 2041 | const index = self.got_table.lookup.get(sym_with_loc) orelse return null; | 2075 | const index = self.got_table.lookup.get(sym_with_loc) orelse return null; |
| 2042 | const header = self.sections.items(.header)[self.got_section_index.?]; | 2076 | const header = self.sections.items(.header)[self.got_section_index.?]; |
| ... | @@ -2934,7 +2968,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr | ... | @@ -2934,7 +2968,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr |
| 2934 | try zld.createSegments(); | 2968 | try zld.createSegments(); |
| 2935 | try zld.allocateSegments(); | 2969 | try zld.allocateSegments(); |
| 2936 | | 2970 | |
| 2937 | try zld.allocateSpecialSymbols(); | 2971 | try MachO.allocateSpecialSymbols(&zld); |
| 2938 | | 2972 | |
| 2939 | if (build_options.enable_logging) { | 2973 | if (build_options.enable_logging) { |
| 2940 | zld.logSymtab(); | 2974 | zld.logSymtab(); |