| ... | @@ -84,6 +84,11 @@ common_section_index: ?u16 = null, | ... | @@ -84,6 +84,11 @@ common_section_index: ?u16 = null, |
| 84 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | 84 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 85 | imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | 85 | imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 86 | unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | 86 | unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| | 87 | tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| | 88 | |
| | 89 | /// Offset into __DATA,__common section. |
| | 90 | /// Set if the linker found tentative definitions in any of the objects. |
| | 91 | tentative_defs_offset: u64 = 0, |
| 87 | | 92 | |
| 88 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 93 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 89 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, | 94 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, |
| ... | @@ -95,9 +100,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, | ... | @@ -95,9 +100,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 95 | | 100 | |
| 96 | stub_helper_stubs_start_off: ?u64 = null, | 101 | stub_helper_stubs_start_off: ?u64 = null, |
| 97 | | 102 | |
| 98 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | | |
| 99 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | | |
| 100 | | | |
| 101 | const TlvOffset = struct { | 103 | const TlvOffset = struct { |
| 102 | source_addr: u64, | 104 | source_addr: u64, |
| 103 | offset: u64, | 105 | offset: u64, |
| ... | @@ -107,18 +109,6 @@ const TlvOffset = struct { | ... | @@ -107,18 +109,6 @@ const TlvOffset = struct { |
| 107 | } | 109 | } |
| 108 | }; | 110 | }; |
| 109 | | 111 | |
| 110 | const MappingKey = struct { | | |
| 111 | object_id: u16, | | |
| 112 | source_sect_id: u16, | | |
| 113 | }; | | |
| 114 | | | |
| 115 | pub const SectionMapping = struct { | | |
| 116 | source_sect_id: u16, | | |
| 117 | target_seg_id: u16, | | |
| 118 | target_sect_id: u16, | | |
| 119 | offset: u32, | | |
| 120 | }; | | |
| 121 | | | |
| 122 | /// Default path to dyld | 112 | /// Default path to dyld |
| 123 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; | 113 | const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld"; |
| 124 | | 114 | |
| ... | @@ -159,9 +149,7 @@ pub fn deinit(self: *Zld) void { | ... | @@ -159,9 +149,7 @@ pub fn deinit(self: *Zld) void { |
| 159 | } | 149 | } |
| 160 | self.dylibs.deinit(self.allocator); | 150 | self.dylibs.deinit(self.allocator); |
| 161 | | 151 | |
| 162 | self.mappings.deinit(self.allocator); | 152 | self.tentatives.deinit(self.allocator); |
| 163 | self.unhandled_sections.deinit(self.allocator); | | |
| 164 | | | |
| 165 | self.globals.deinit(self.allocator); | 153 | self.globals.deinit(self.allocator); |
| 166 | self.imports.deinit(self.allocator); | 154 | self.imports.deinit(self.allocator); |
| 167 | self.unresolved.deinit(self.allocator); | 155 | self.unresolved.deinit(self.allocator); |
| ... | @@ -239,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L | ... | @@ -239,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L |
| 239 | try self.allocateDataSegment(); | 227 | try self.allocateDataSegment(); |
| 240 | self.allocateLinkeditSegment(); | 228 | self.allocateLinkeditSegment(); |
| 241 | try self.allocateSymbols(); | 229 | try self.allocateSymbols(); |
| | 230 | try self.allocateTentativeSymbols(); |
| 242 | try self.flush(); | 231 | try self.flush(); |
| 243 | } | 232 | } |
| 244 | | 233 | |
| ... | @@ -407,46 +396,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { | ... | @@ -407,46 +396,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void { |
| 407 | | 396 | |
| 408 | fn mapAndUpdateSections( | 397 | fn mapAndUpdateSections( |
| 409 | self: *Zld, | 398 | self: *Zld, |
| 410 | object_id: u16, | 399 | object: *Object, |
| 411 | source_sect_id: u16, | 400 | source_sect_id: u16, |
| 412 | target_seg_id: u16, | 401 | target_seg_id: u16, |
| 413 | target_sect_id: u16, | 402 | target_sect_id: u16, |
| 414 | ) !void { | 403 | ) !void { |
| 415 | const object = self.objects.items[object_id]; | 404 | const source_sect = &object.sections.items[source_sect_id]; |
| 416 | const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; | | |
| 417 | const source_sect = source_seg.sections.items[source_sect_id]; | | |
| 418 | const target_seg = &self.load_commands.items[target_seg_id].Segment; | 405 | const target_seg = &self.load_commands.items[target_seg_id].Segment; |
| 419 | const target_sect = &target_seg.sections.items[target_sect_id]; | 406 | const target_sect = &target_seg.sections.items[target_sect_id]; |
| 420 | | 407 | |
| 421 | const alignment = try math.powi(u32, 2, target_sect.@"align"); | 408 | const alignment = try math.powi(u32, 2, target_sect.@"align"); |
| 422 | const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment); | 409 | const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment); |
| 423 | const size = mem.alignForwardGeneric(u64, source_sect.size, alignment); | 410 | const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment); |
| 424 | const key = MappingKey{ | 411 | |
| 425 | .object_id = object_id, | 412 | log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ |
| 426 | .source_sect_id = source_sect_id, | 413 | object.name.?, |
| 427 | }; | 414 | parseName(&source_sect.inner.segname), |
| 428 | try self.mappings.putNoClobber(self.allocator, key, .{ | 415 | parseName(&source_sect.inner.sectname), |
| 429 | .source_sect_id = source_sect_id, | | |
| 430 | .target_seg_id = target_seg_id, | | |
| 431 | .target_sect_id = target_sect_id, | | |
| 432 | .offset = @intCast(u32, offset), | | |
| 433 | }); | | |
| 434 | log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{ | | |
| 435 | object.name, | | |
| 436 | parseName(&source_sect.segname), | | |
| 437 | parseName(&source_sect.sectname), | | |
| 438 | parseName(&target_sect.segname), | 416 | parseName(&target_sect.segname), |
| 439 | parseName(&target_sect.sectname), | 417 | parseName(&target_sect.sectname), |
| 440 | offset, | 418 | offset, |
| 441 | offset + size, | 419 | offset + size, |
| 442 | }); | 420 | }); |
| 443 | | 421 | |
| | 422 | source_sect.target_map = .{ |
| | 423 | .segment_id = target_seg_id, |
| | 424 | .section_id = target_sect_id, |
| | 425 | .offset = @intCast(u32, offset), |
| | 426 | }; |
| 444 | target_sect.size = offset + size; | 427 | target_sect.size = offset + size; |
| 445 | } | 428 | } |
| 446 | | 429 | |
| 447 | fn updateMetadata(self: *Zld) !void { | 430 | fn updateMetadata(self: *Zld) !void { |
| 448 | for (self.objects.items) |object, id| { | 431 | for (self.objects.items) |object| { |
| 449 | const object_id = @intCast(u16, id); | | |
| 450 | const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; | 432 | const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 451 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 433 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 452 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 434 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| ... | @@ -699,20 +681,57 @@ fn updateMetadata(self: *Zld) !void { | ... | @@ -699,20 +681,57 @@ fn updateMetadata(self: *Zld) !void { |
| 699 | for (object_seg.sections.items) |source_sect, sect_id| { | 681 | for (object_seg.sections.items) |source_sect, sect_id| { |
| 700 | const source_sect_id = @intCast(u16, sect_id); | 682 | const source_sect_id = @intCast(u16, sect_id); |
| 701 | if (self.getMatchingSection(source_sect)) |res| { | 683 | if (self.getMatchingSection(source_sect)) |res| { |
| 702 | try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect); | 684 | try self.mapAndUpdateSections(object, source_sect_id, res.seg, res.sect); |
| 703 | continue; | 685 | continue; |
| 704 | } | 686 | } |
| 705 | | 687 | |
| 706 | const segname = parseName(&source_sect.segname); | 688 | log.debug("section '{s},{s}' will be unmapped", .{ |
| 707 | const sectname = parseName(&source_sect.sectname); | 689 | parseName(&source_sect.segname), |
| 708 | | 690 | parseName(&source_sect.sectname), |
| 709 | log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); | 691 | }); |
| | 692 | } |
| | 693 | } |
| 710 | | 694 | |
| 711 | try self.unhandled_sections.putNoClobber(self.allocator, .{ | 695 | // Ensure we have __DATA,__common section if we have tentative definitions. |
| 712 | .object_id = object_id, | 696 | // Update size and alignment of __DATA,__common section. |
| 713 | .source_sect_id = source_sect_id, | 697 | if (self.tentatives.values().len > 0) { |
| 714 | }, 0); | 698 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 699 | const common_section_index = self.common_section_index orelse ind: { |
| | 700 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); |
| | 701 | try data_seg.addSection(self.allocator, .{ |
| | 702 | .sectname = makeStaticString("__common"), |
| | 703 | .segname = makeStaticString("__DATA"), |
| | 704 | .addr = 0, |
| | 705 | .size = 0, |
| | 706 | .offset = 0, |
| | 707 | .@"align" = 0, |
| | 708 | .reloff = 0, |
| | 709 | .nreloc = 0, |
| | 710 | .flags = macho.S_ZEROFILL, |
| | 711 | .reserved1 = 0, |
| | 712 | .reserved2 = 0, |
| | 713 | .reserved3 = 0, |
| | 714 | }); |
| | 715 | break :ind self.common_section_index.?; |
| | 716 | }; |
| | 717 | const common_sect = &data_seg.sections.items[common_section_index]; |
| | 718 | |
| | 719 | var max_align: u16 = 0; |
| | 720 | var added_size: u64 = 0; |
| | 721 | for (self.tentatives.values()) |sym| { |
| | 722 | const tent = sym.cast(Symbol.Tentative) orelse unreachable; |
| | 723 | max_align = math.max(max_align, tent.alignment); |
| | 724 | added_size += tent.size; |
| 715 | } | 725 | } |
| | 726 | |
| | 727 | common_sect.@"align" = math.max(common_sect.@"align", max_align); |
| | 728 | |
| | 729 | const alignment = try math.powi(u32, 2, common_sect.@"align"); |
| | 730 | const offset = mem.alignForwardGeneric(u64, common_sect.size, alignment); |
| | 731 | const size = mem.alignForwardGeneric(u64, added_size, alignment); |
| | 732 | |
| | 733 | common_sect.size = offset + size; |
| | 734 | self.tentative_defs_offset = offset; |
| 716 | } | 735 | } |
| 717 | | 736 | |
| 718 | tlv_align: { | 737 | tlv_align: { |
| ... | @@ -954,18 +973,34 @@ fn sortSections(self: *Zld) !void { | ... | @@ -954,18 +973,34 @@ fn sortSections(self: *Zld) !void { |
| 954 | } | 973 | } |
| 955 | } | 974 | } |
| 956 | | 975 | |
| 957 | var it = self.mappings.valueIterator(); | 976 | for (self.objects.items) |object| { |
| 958 | while (it.next()) |mapping| { | 977 | for (object.sections.items) |*sect| { |
| 959 | if (self.text_segment_cmd_index.? == mapping.target_seg_id) { | 978 | const target_map = sect.target_map orelse continue; |
| 960 | const new_index = text_index_mapping.get(mapping.target_sect_id) orelse unreachable; | 979 | |
| 961 | mapping.target_sect_id = new_index; | 980 | const new_index = blk: { |
| 962 | } else if (self.data_const_segment_cmd_index.? == mapping.target_seg_id) { | 981 | if (self.text_segment_cmd_index.? == target_map.segment_id) { |
| 963 | const new_index = data_const_index_mapping.get(mapping.target_sect_id) orelse unreachable; | 982 | break :blk text_index_mapping.get(target_map.section_id) orelse unreachable; |
| 964 | mapping.target_sect_id = new_index; | 983 | } else if (self.data_const_segment_cmd_index.? == target_map.segment_id) { |
| 965 | } else if (self.data_segment_cmd_index.? == mapping.target_seg_id) { | 984 | break :blk data_const_index_mapping.get(target_map.section_id) orelse unreachable; |
| 966 | const new_index = data_index_mapping.get(mapping.target_sect_id) orelse unreachable; | 985 | } else if (self.data_segment_cmd_index.? == target_map.segment_id) { |
| 967 | mapping.target_sect_id = new_index; | 986 | break :blk data_index_mapping.get(target_map.section_id) orelse unreachable; |
| 968 | } else unreachable; | 987 | } else unreachable; |
| | 988 | }; |
| | 989 | |
| | 990 | log.debug("remapping in {s}: '{s},{s}': {} => {}", .{ |
| | 991 | object.name.?, |
| | 992 | parseName(&sect.inner.segname), |
| | 993 | parseName(&sect.inner.sectname), |
| | 994 | target_map.section_id, |
| | 995 | new_index, |
| | 996 | }); |
| | 997 | |
| | 998 | sect.target_map = .{ |
| | 999 | .segment_id = target_map.segment_id, |
| | 1000 | .section_id = new_index, |
| | 1001 | .offset = target_map.offset, |
| | 1002 | }; |
| | 1003 | } |
| 969 | } | 1004 | } |
| 970 | } | 1005 | } |
| 971 | | 1006 | |
| ... | @@ -1080,30 +1115,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { | ... | @@ -1080,30 +1115,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 1080 | } | 1115 | } |
| 1081 | | 1116 | |
| 1082 | fn allocateSymbols(self: *Zld) !void { | 1117 | fn allocateSymbols(self: *Zld) !void { |
| 1083 | for (self.objects.items) |object, object_id| { | 1118 | for (self.objects.items) |object| { |
| 1084 | for (object.symbols.items) |sym| { | 1119 | for (object.symbols.items) |sym| { |
| 1085 | const reg = sym.cast(Symbol.Regular) orelse continue; | 1120 | const reg = sym.cast(Symbol.Regular) orelse continue; |
| 1086 | | 1121 | |
| 1087 | // TODO I am more and more convinced we should store the mapping as part of the Object struct. | 1122 | const source_sect = &object.sections.items[reg.section]; |
| 1088 | const target_mapping = self.mappings.get(.{ | 1123 | const target_map = source_sect.target_map orelse { |
| 1089 | .object_id = @intCast(u16, object_id), | 1124 | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ |
| 1090 | .source_sect_id = reg.section, | 1125 | parseName(&source_sect.inner.segname), |
| 1091 | }) orelse { | 1126 | parseName(&source_sect.inner.sectname), |
| 1092 | if (self.unhandled_sections.get(.{ | 1127 | sym.name, |
| 1093 | .object_id = @intCast(u16, object_id), | 1128 | }); |
| 1094 | .source_sect_id = reg.section, | 1129 | continue; |
| 1095 | }) != null) continue; | | |
| 1096 | | | |
| 1097 | log.err("section not mapped for symbol '{s}'", .{sym.name}); | | |
| 1098 | return error.SectionNotMappedForSymbol; | | |
| 1099 | }; | 1130 | }; |
| 1100 | | 1131 | |
| 1101 | const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; | 1132 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1102 | const source_sect = source_seg.sections.items[reg.section]; | 1133 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1103 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; | 1134 | const target_addr = target_sect.addr + target_map.offset; |
| 1104 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; | 1135 | const address = reg.address - source_sect.inner.addr + target_addr; |
| 1105 | const target_addr = target_sect.addr + target_mapping.offset; | | |
| 1106 | const address = reg.address - source_sect.addr + target_addr; | | |
| 1107 | | 1136 | |
| 1108 | log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address }); | 1137 | log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address }); |
| 1109 | | 1138 | |
| ... | @@ -1111,8 +1140,8 @@ fn allocateSymbols(self: *Zld) !void { | ... | @@ -1111,8 +1140,8 @@ fn allocateSymbols(self: *Zld) !void { |
| 1111 | var section: u8 = 0; | 1140 | var section: u8 = 0; |
| 1112 | for (self.load_commands.items) |cmd, cmd_id| { | 1141 | for (self.load_commands.items) |cmd, cmd_id| { |
| 1113 | if (cmd != .Segment) break; | 1142 | if (cmd != .Segment) break; |
| 1114 | if (cmd_id == target_mapping.target_seg_id) { | 1143 | if (cmd_id == target_map.segment_id) { |
| 1115 | section += @intCast(u8, target_mapping.target_sect_id) + 1; | 1144 | section += @intCast(u8, target_map.section_id) + 1; |
| 1116 | break; | 1145 | break; |
| 1117 | } | 1146 | } |
| 1118 | section += @intCast(u8, cmd.Segment.sections.items.len); | 1147 | section += @intCast(u8, cmd.Segment.sections.items.len); |
| ... | @@ -1124,6 +1153,74 @@ fn allocateSymbols(self: *Zld) !void { | ... | @@ -1124,6 +1153,74 @@ fn allocateSymbols(self: *Zld) !void { |
| 1124 | } | 1153 | } |
| 1125 | } | 1154 | } |
| 1126 | | 1155 | |
| | 1156 | fn allocateTentativeSymbols(self: *Zld) !void { |
| | 1157 | if (self.tentatives.values().len == 0) return; |
| | 1158 | |
| | 1159 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| | 1160 | const common_sect = &data_seg.sections.items[self.common_section_index.?]; |
| | 1161 | |
| | 1162 | const alignment = try math.powi(u32, 2, common_sect.@"align"); |
| | 1163 | var base_address: u64 = common_sect.addr + self.tentative_defs_offset; |
| | 1164 | |
| | 1165 | log.debug("base address for tentative definitions 0x{x}", .{base_address}); |
| | 1166 | |
| | 1167 | // TODO there might be a more generic way of doing this. |
| | 1168 | var section: u8 = 0; |
| | 1169 | for (self.load_commands.items) |cmd, cmd_id| { |
| | 1170 | if (cmd != .Segment) break; |
| | 1171 | if (cmd_id == self.data_segment_cmd_index.?) { |
| | 1172 | section += @intCast(u8, self.common_section_index.?) + 1; |
| | 1173 | break; |
| | 1174 | } |
| | 1175 | section += @intCast(u8, cmd.Segment.sections.items.len); |
| | 1176 | } |
| | 1177 | |
| | 1178 | // Convert tentative definitions into regular symbols. |
| | 1179 | for (self.tentatives.values()) |sym, i| { |
| | 1180 | const tent = sym.cast(Symbol.Tentative) orelse unreachable; |
| | 1181 | const reg = try self.allocator.create(Symbol.Regular); |
| | 1182 | errdefer self.allocator.destroy(reg); |
| | 1183 | |
| | 1184 | reg.* = .{ |
| | 1185 | .base = .{ |
| | 1186 | .@"type" = .regular, |
| | 1187 | .name = try self.allocator.dupe(u8, tent.base.name), |
| | 1188 | .got_index = tent.base.got_index, |
| | 1189 | .stubs_index = tent.base.stubs_index, |
| | 1190 | }, |
| | 1191 | .linkage = .global, |
| | 1192 | .address = base_address, |
| | 1193 | .section = section, |
| | 1194 | .weak_ref = false, |
| | 1195 | .file = tent.file, |
| | 1196 | .stab = .{ |
| | 1197 | .kind = .global, |
| | 1198 | .size = 0, |
| | 1199 | }, |
| | 1200 | }; |
| | 1201 | |
| | 1202 | try self.globals.putNoClobber(self.allocator, reg.base.name, &reg.base); |
| | 1203 | tent.base.alias = &reg.base; |
| | 1204 | |
| | 1205 | if (tent.base.got_index) |idx| { |
| | 1206 | self.got_entries.items[idx] = &reg.base; |
| | 1207 | } |
| | 1208 | if (tent.base.stubs_index) |idx| { |
| | 1209 | self.stubs.items[idx] = &reg.base; |
| | 1210 | } |
| | 1211 | |
| | 1212 | const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment); |
| | 1213 | |
| | 1214 | log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{ |
| | 1215 | tent.base.name, |
| | 1216 | base_address, |
| | 1217 | address, |
| | 1218 | }); |
| | 1219 | |
| | 1220 | base_address = address; |
| | 1221 | } |
| | 1222 | } |
| | 1223 | |
| 1127 | fn writeStubHelperCommon(self: *Zld) !void { | 1224 | fn writeStubHelperCommon(self: *Zld) !void { |
| 1128 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1225 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1129 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 1226 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | @@ -1399,6 +1496,10 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { | ... | @@ -1399,6 +1496,10 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { |
| 1399 | if (sym.cast(Symbol.Regular)) |reg| { | 1496 | if (sym.cast(Symbol.Regular)) |reg| { |
| 1400 | if (reg.linkage == .translation_unit) continue; // Symbol local to TU. | 1497 | if (reg.linkage == .translation_unit) continue; // Symbol local to TU. |
| 1401 | | 1498 | |
| | 1499 | if (self.tentatives.fetchSwapRemove(sym.name)) |kv| { |
| | 1500 | // Create link to the global. |
| | 1501 | kv.value.alias = sym; |
| | 1502 | } |
| 1402 | if (self.unresolved.fetchSwapRemove(sym.name)) |kv| { | 1503 | if (self.unresolved.fetchSwapRemove(sym.name)) |kv| { |
| 1403 | // Create link to the global. | 1504 | // Create link to the global. |
| 1404 | kv.value.alias = sym; | 1505 | kv.value.alias = sym; |
| ... | @@ -1432,15 +1533,49 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { | ... | @@ -1432,15 +1533,49 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { |
| 1432 | | 1533 | |
| 1433 | g_sym.alias = sym; | 1534 | g_sym.alias = sym; |
| 1434 | sym_ptr.* = sym; | 1535 | sym_ptr.* = sym; |
| | 1536 | } else if (sym.cast(Symbol.Tentative)) |tent| { |
| | 1537 | if (self.globals.get(sym.name)) |g_sym| { |
| | 1538 | sym.alias = g_sym; |
| | 1539 | continue; |
| | 1540 | } |
| | 1541 | |
| | 1542 | if (self.unresolved.fetchSwapRemove(sym.name)) |kv| { |
| | 1543 | kv.value.alias = sym; |
| | 1544 | } |
| | 1545 | |
| | 1546 | const sym_ptr = self.tentatives.getPtr(sym.name) orelse { |
| | 1547 | // Put new tentative definition symbol into symbol table. |
| | 1548 | try self.tentatives.putNoClobber(self.allocator, sym.name, sym); |
| | 1549 | continue; |
| | 1550 | }; |
| | 1551 | |
| | 1552 | // Compare by size and pick the largest tentative definition. |
| | 1553 | // We model this like a heap where the tentative definition with the |
| | 1554 | // largest size always washes up on top. |
| | 1555 | const t_sym = sym_ptr.*; |
| | 1556 | const t_tent = t_sym.cast(Symbol.Tentative) orelse unreachable; |
| | 1557 | |
| | 1558 | if (tent.size < t_tent.size) { |
| | 1559 | sym.alias = t_sym; |
| | 1560 | continue; |
| | 1561 | } |
| | 1562 | |
| | 1563 | t_sym.alias = sym; |
| | 1564 | sym_ptr.* = sym; |
| 1435 | } else if (sym.cast(Symbol.Unresolved)) |und| { | 1565 | } else if (sym.cast(Symbol.Unresolved)) |und| { |
| 1436 | if (self.globals.get(sym.name)) |g_sym| { | 1566 | if (self.globals.get(sym.name)) |g_sym| { |
| 1437 | sym.alias = g_sym; | 1567 | sym.alias = g_sym; |
| 1438 | continue; | 1568 | continue; |
| 1439 | } | 1569 | } |
| | 1570 | if (self.tentatives.get(sym.name)) |t_sym| { |
| | 1571 | sym.alias = t_sym; |
| | 1572 | continue; |
| | 1573 | } |
| 1440 | if (self.unresolved.get(sym.name)) |u_sym| { | 1574 | if (self.unresolved.get(sym.name)) |u_sym| { |
| 1441 | sym.alias = u_sym; | 1575 | sym.alias = u_sym; |
| 1442 | continue; | 1576 | continue; |
| 1443 | } | 1577 | } |
| | 1578 | |
| 1444 | try self.unresolved.putNoClobber(self.allocator, sym.name, sym); | 1579 | try self.unresolved.putNoClobber(self.allocator, sym.name, sym); |
| 1445 | } else unreachable; | 1580 | } else unreachable; |
| 1446 | } | 1581 | } |
| ... | @@ -1482,7 +1617,6 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1482,7 +1617,6 @@ fn resolveSymbols(self: *Zld) !void { |
| 1482 | next_sym += 1; | 1617 | next_sym += 1; |
| 1483 | } | 1618 | } |
| 1484 | } | 1619 | } |
| 1485 | | | |
| 1486 | // Third pass, resolve symbols in dynamic libraries. | 1620 | // Third pass, resolve symbols in dynamic libraries. |
| 1487 | // TODO Implement libSystem as a hard-coded library, or ship with | 1621 | // TODO Implement libSystem as a hard-coded library, or ship with |
| 1488 | // a libSystem.B.tbd definition file? | 1622 | // a libSystem.B.tbd definition file? |
| ... | @@ -1602,10 +1736,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1602,10 +1736,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1602 | } | 1736 | } |
| 1603 | | 1737 | |
| 1604 | fn resolveRelocsAndWriteSections(self: *Zld) !void { | 1738 | fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1605 | for (self.objects.items) |object, object_id| { | 1739 | for (self.objects.items) |object| { |
| 1606 | log.debug("relocating object {s}", .{object.name}); | 1740 | log.debug("relocating object {s}", .{object.name}); |
| 1607 | | 1741 | |
| 1608 | for (object.sections.items) |sect, source_sect_id| { | 1742 | for (object.sections.items) |sect| { |
| 1609 | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or | 1743 | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or |
| 1610 | sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue; | 1744 | sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue; |
| 1611 | | 1745 | |
| ... | @@ -1614,18 +1748,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1614,18 +1748,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1614 | | 1748 | |
| 1615 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); | 1749 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); |
| 1616 | | 1750 | |
| 1617 | // Get mapping | 1751 | // Get target mapping |
| 1618 | const target_mapping = self.mappings.get(.{ | 1752 | const target_map = sect.target_map orelse { |
| 1619 | .object_id = @intCast(u16, object_id), | 1753 | log.debug("no mapping for '{s},{s}'; skipping", .{ segname, sectname }); |
| 1620 | .source_sect_id = @intCast(u16, source_sect_id), | | |
| 1621 | }) orelse { | | |
| 1622 | log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname }); | | |
| 1623 | continue; | 1754 | continue; |
| 1624 | }; | 1755 | }; |
| 1625 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; | 1756 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1626 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; | 1757 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1627 | const target_sect_addr = target_sect.addr + target_mapping.offset; | 1758 | const target_sect_addr = target_sect.addr + target_map.offset; |
| 1628 | const target_sect_off = target_sect.offset + target_mapping.offset; | 1759 | const target_sect_off = target_sect.offset + target_map.offset; |
| 1629 | | 1760 | |
| 1630 | if (sect.relocs) |relocs| { | 1761 | if (sect.relocs) |relocs| { |
| 1631 | for (relocs) |rel| { | 1762 | for (relocs) |rel| { |
| ... | @@ -1638,11 +1769,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1638,11 +1769,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1638 | | 1769 | |
| 1639 | switch (rel.@"type") { | 1770 | switch (rel.@"type") { |
| 1640 | .unsigned => { | 1771 | .unsigned => { |
| 1641 | args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target); | 1772 | args.target_addr = try self.relocTargetAddr(object, rel.target); |
| 1642 | | 1773 | |
| 1643 | const unsigned = rel.cast(reloc.Unsigned) orelse unreachable; | 1774 | const unsigned = rel.cast(reloc.Unsigned) orelse unreachable; |
| 1644 | if (unsigned.subtractor) |subtractor| { | 1775 | if (unsigned.subtractor) |subtractor| { |
| 1645 | args.subtractor = try self.relocTargetAddr(@intCast(u16, object_id), subtractor); | 1776 | args.subtractor = try self.relocTargetAddr(object, subtractor); |
| 1646 | } | 1777 | } |
| 1647 | if (rel.target == .section) { | 1778 | if (rel.target == .section) { |
| 1648 | const source_sect = object.sections.items[rel.target.section]; | 1779 | const source_sect = object.sections.items[rel.target.section]; |
| ... | @@ -1652,14 +1783,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1652,14 +1783,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1652 | | 1783 | |
| 1653 | rebases: { | 1784 | rebases: { |
| 1654 | var hit: bool = false; | 1785 | var hit: bool = false; |
| 1655 | if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) { | 1786 | if (target_map.segment_id == self.data_segment_cmd_index.?) { |
| 1656 | if (self.data_section_index) |index| { | 1787 | if (self.data_section_index) |index| { |
| 1657 | if (index == target_mapping.target_sect_id) hit = true; | 1788 | if (index == target_map.section_id) hit = true; |
| 1658 | } | 1789 | } |
| 1659 | } | 1790 | } |
| 1660 | if (target_mapping.target_seg_id == self.data_const_segment_cmd_index.?) { | 1791 | if (target_map.segment_id == self.data_const_segment_cmd_index.?) { |
| 1661 | if (self.data_const_section_index) |index| { | 1792 | if (self.data_const_section_index) |index| { |
| 1662 | if (index == target_mapping.target_sect_id) hit = true; | 1793 | if (index == target_map.section_id) hit = true; |
| 1663 | } | 1794 | } |
| 1664 | } | 1795 | } |
| 1665 | | 1796 | |
| ... | @@ -1667,7 +1798,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1667,7 +1798,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1667 | | 1798 | |
| 1668 | try self.local_rebases.append(self.allocator, .{ | 1799 | try self.local_rebases.append(self.allocator, .{ |
| 1669 | .offset = source_addr - target_seg.inner.vmaddr, | 1800 | .offset = source_addr - target_seg.inner.vmaddr, |
| 1670 | .segment_id = target_mapping.target_seg_id, | 1801 | .segment_id = target_map.segment_id, |
| 1671 | }); | 1802 | }); |
| 1672 | } | 1803 | } |
| 1673 | // TLV is handled via a separate offset mechanism. | 1804 | // TLV is handled via a separate offset mechanism. |
| ... | @@ -1705,7 +1836,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1705,7 +1836,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1705 | args.source_source_sect_addr = sect.inner.addr; | 1836 | args.source_source_sect_addr = sect.inner.addr; |
| 1706 | args.source_target_sect_addr = source_sect.inner.addr; | 1837 | args.source_target_sect_addr = source_sect.inner.addr; |
| 1707 | } | 1838 | } |
| 1708 | args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target); | 1839 | args.target_addr = try self.relocTargetAddr(object, rel.target); |
| 1709 | }, | 1840 | }, |
| 1710 | } | 1841 | } |
| 1711 | | 1842 | |
| ... | @@ -1744,7 +1875,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1744,7 +1875,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1744 | } | 1875 | } |
| 1745 | } | 1876 | } |
| 1746 | | 1877 | |
| 1747 | fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 { | 1878 | fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.Target) !u64 { |
| 1748 | const target_addr = blk: { | 1879 | const target_addr = blk: { |
| 1749 | switch (target) { | 1880 | switch (target) { |
| 1750 | .symbol => |sym| { | 1881 | .symbol => |sym| { |
| ... | @@ -1770,13 +1901,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) | ... | @@ -1770,13 +1901,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) |
| 1770 | } | 1901 | } |
| 1771 | }, | 1902 | }, |
| 1772 | .section => |sect_id| { | 1903 | .section => |sect_id| { |
| 1773 | const target_mapping = self.mappings.get(.{ | 1904 | const source_sect = object.sections.items[sect_id]; |
| 1774 | .object_id = object_id, | 1905 | const target_map = source_sect.target_map orelse unreachable; |
| 1775 | .source_sect_id = sect_id, | 1906 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1776 | }) orelse unreachable; | 1907 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1777 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; | 1908 | break :blk target_sect.addr + target_map.offset; |
| 1778 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; | | |
| 1779 | break :blk target_sect.addr + target_mapping.offset; | | |
| 1780 | }, | 1909 | }, |
| 1781 | } | 1910 | } |
| 1782 | }; | 1911 | }; |
| ... | @@ -2646,8 +2775,17 @@ fn writeDebugInfo(self: *Zld) !void { | ... | @@ -2646,8 +2775,17 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2646 | }); | 2775 | }); |
| 2647 | | 2776 | |
| 2648 | for (object.symbols.items) |sym| { | 2777 | for (object.symbols.items) |sym| { |
| 2649 | if (sym.@"type" != .regular) continue; | 2778 | const reg = reg: { |
| 2650 | const reg = sym.cast(Symbol.Regular) orelse unreachable; | 2779 | switch (sym.@"type") { |
| | 2780 | .regular => break :reg sym.cast(Symbol.Regular) orelse unreachable, |
| | 2781 | .tentative => { |
| | 2782 | const final = sym.getTopmostAlias().cast(Symbol.Regular) orelse unreachable; |
| | 2783 | if (object != final.file) continue; |
| | 2784 | break :reg final; |
| | 2785 | }, |
| | 2786 | else => continue, |
| | 2787 | } |
| | 2788 | }; |
| 2651 | | 2789 | |
| 2652 | if (reg.isTemp() or reg.stab == null) continue; | 2790 | if (reg.isTemp() or reg.stab == null) continue; |
| 2653 | const stab = reg.stab orelse unreachable; | 2791 | const stab = reg.stab orelse unreachable; |
| ... | @@ -2751,6 +2889,7 @@ fn writeSymbolTable(self: *Zld) !void { | ... | @@ -2751,6 +2889,7 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2751 | | 2889 | |
| 2752 | const reg = final.cast(Symbol.Regular) orelse unreachable; | 2890 | const reg = final.cast(Symbol.Regular) orelse unreachable; |
| 2753 | if (reg.isTemp()) continue; | 2891 | if (reg.isTemp()) continue; |
| | 2892 | if (reg.visited) continue; |
| 2754 | | 2893 | |
| 2755 | switch (reg.linkage) { | 2894 | switch (reg.linkage) { |
| 2756 | .translation_unit => { | 2895 | .translation_unit => { |
| ... | @@ -2772,6 +2911,8 @@ fn writeSymbolTable(self: *Zld) !void { | ... | @@ -2772,6 +2911,8 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2772 | }); | 2911 | }); |
| 2773 | }, | 2912 | }, |
| 2774 | } | 2913 | } |
| | 2914 | |
| | 2915 | reg.visited = true; |
| 2775 | } | 2916 | } |
| 2776 | } | 2917 | } |
| 2777 | | 2918 | |
| ... | @@ -2901,20 +3042,16 @@ fn writeDataInCode(self: *Zld) !void { | ... | @@ -2901,20 +3042,16 @@ fn writeDataInCode(self: *Zld) !void { |
| 2901 | | 3042 | |
| 2902 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 3043 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2903 | const text_sect = text_seg.sections.items[self.text_section_index.?]; | 3044 | const text_sect = text_seg.sections.items[self.text_section_index.?]; |
| 2904 | for (self.objects.items) |object, object_id| { | 3045 | for (self.objects.items) |object| { |
| 2905 | const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; | 3046 | const source_sect = object.sections.items[object.text_section_index.?]; |
| 2906 | const source_sect = source_seg.sections.items[object.text_section_index.?]; | 3047 | const target_map = source_sect.target_map orelse continue; |
| 2907 | const target_mapping = self.mappings.get(.{ | | |
| 2908 | .object_id = @intCast(u16, object_id), | | |
| 2909 | .source_sect_id = object.text_section_index.?, | | |
| 2910 | }) orelse continue; | | |
| 2911 | | 3048 | |
| 2912 | try buf.ensureCapacity( | 3049 | try buf.ensureCapacity( |
| 2913 | buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry), | 3050 | buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry), |
| 2914 | ); | 3051 | ); |
| 2915 | for (object.data_in_code_entries.items) |dice| { | 3052 | for (object.data_in_code_entries.items) |dice| { |
| 2916 | const new_dice: macho.data_in_code_entry = .{ | 3053 | const new_dice: macho.data_in_code_entry = .{ |
| 2917 | .offset = text_sect.offset + target_mapping.offset + dice.offset, | 3054 | .offset = text_sect.offset + target_map.offset + dice.offset, |
| 2918 | .length = dice.length, | 3055 | .length = dice.length, |
| 2919 | .kind = dice.kind, | 3056 | .kind = dice.kind, |
| 2920 | }; | 3057 | }; |