| ... | ... | @@ -108,6 +108,7 @@ globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 108 | 108 | /// Offset into __DATA,__common section. |
| 109 | 109 | /// Set if the linker found tentative definitions in any of the objects. |
| 110 | 110 | tentative_defs_offset: u64 = 0, |
| 111 | has_tentative_defs: bool = false, |
| 111 | 112 | |
| 112 | 113 | threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction |
| 113 | 114 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| ... | ... | @@ -222,20 +223,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 222 | 223 | try self.parseInputFiles(files, args.syslibroot); |
| 223 | 224 | try self.parseLibs(args.libs, args.syslibroot); |
| 224 | 225 | try self.resolveSymbols(); |
| 226 | try self.resolveStubsAndGotEntries(); |
| 227 | try self.updateMetadata(); |
| 228 | try self.sortSections(); |
| 229 | try self.addRpaths(args.rpaths); |
| 230 | try self.addDataInCodeLC(); |
| 231 | try self.addCodeSignatureLC(); |
| 232 | try self.allocateTextSegment(); |
| 233 | try self.allocateDataConstSegment(); |
| 234 | try self.allocateDataSegment(); |
| 235 | self.allocateLinkeditSegment(); |
| 236 | try self.allocateSymbols(); |
| 237 | try self.allocateTentativeSymbols(); |
| 238 | try self.allocateProxyBindAddresses(); |
| 239 | |
| 240 | log.warn("globals", .{}); |
| 241 | for (self.globals.values()) |value| { |
| 242 | log.warn(" | {s}: {}", .{ value.name, value.payload }); |
| 243 | } |
| 244 | |
| 245 | for (self.objects.items) |object| { |
| 246 | log.warn("object {s}", .{object.name.?}); |
| 247 | for (object.symbols.items) |sym| { |
| 248 | log.warn(" | {s}: {}", .{ sym.name, sym.payload }); |
| 249 | } |
| 250 | } |
| 251 | |
| 225 | 252 | return error.TODO; |
| 226 | | // try self.resolveStubsAndGotEntries(); |
| 227 | | // try self.updateMetadata(); |
| 228 | | // try self.sortSections(); |
| 229 | | // try self.addRpaths(args.rpaths); |
| 230 | | // try self.addDataInCodeLC(); |
| 231 | | // try self.addCodeSignatureLC(); |
| 232 | | // try self.allocateTextSegment(); |
| 233 | | // try self.allocateDataConstSegment(); |
| 234 | | // try self.allocateDataSegment(); |
| 235 | | // self.allocateLinkeditSegment(); |
| 236 | | // try self.allocateSymbols(); |
| 237 | | // try self.allocateTentativeSymbols(); |
| 238 | | // try self.allocateProxyBindAddresses(); |
| 239 | 253 | // try self.flush(); |
| 240 | 254 | } |
| 241 | 255 | |
| ... | ... | @@ -351,7 +365,7 @@ fn updateMetadata(self: *Zld) !void { |
| 351 | 365 | |
| 352 | 366 | // Ensure we have __DATA,__common section if we have tentative definitions. |
| 353 | 367 | // Update size and alignment of __DATA,__common section. |
| 354 | | if (self.tentatives.values().len > 0) { |
| 368 | if (self.has_tentative_defs) { |
| 355 | 369 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 356 | 370 | const common_section_index = self.common_section_index orelse ind: { |
| 357 | 371 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); |
| ... | ... | @@ -364,10 +378,10 @@ fn updateMetadata(self: *Zld) !void { |
| 364 | 378 | |
| 365 | 379 | var max_align: u16 = 0; |
| 366 | 380 | var added_size: u64 = 0; |
| 367 | | for (self.tentatives.values()) |sym| { |
| 368 | | const tent = sym.cast(Symbol.Tentative) orelse unreachable; |
| 369 | | max_align = math.max(max_align, tent.alignment); |
| 370 | | added_size += tent.size; |
| 381 | for (self.globals.values()) |sym| { |
| 382 | if (sym.payload != .tentative) continue; |
| 383 | max_align = math.max(max_align, sym.payload.tentative.alignment); |
| 384 | added_size += sym.payload.tentative.size; |
| 371 | 385 | } |
| 372 | 386 | |
| 373 | 387 | common_sect.@"align" = math.max(common_sect.@"align", max_align); |
| ... | ... | @@ -1069,47 +1083,55 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 1069 | 1083 | seg.inner.vmsize = seg_size_aligned; |
| 1070 | 1084 | } |
| 1071 | 1085 | |
| 1072 | | fn allocateSymbols(self: *Zld) !void { |
| 1073 | | for (self.objects.items) |object| { |
| 1074 | | for (object.symbols.items) |sym| { |
| 1075 | | const reg = sym.cast(Symbol.Regular) orelse continue; |
| 1086 | fn allocateSymbol(self: *Zld, symbol: *Symbol) !void { |
| 1087 | const reg = &symbol.payload.regular; |
| 1088 | const object = reg.file orelse return; |
| 1089 | const source_sect = &object.sections.items[reg.section]; |
| 1090 | const target_map = source_sect.target_map orelse { |
| 1091 | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ |
| 1092 | parseName(&source_sect.inner.segname), |
| 1093 | parseName(&source_sect.inner.sectname), |
| 1094 | symbol.name, |
| 1095 | }); |
| 1096 | return; |
| 1097 | }; |
| 1076 | 1098 | |
| 1077 | | const source_sect = &object.sections.items[reg.section]; |
| 1078 | | const target_map = source_sect.target_map orelse { |
| 1079 | | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ |
| 1080 | | parseName(&source_sect.inner.segname), |
| 1081 | | parseName(&source_sect.inner.sectname), |
| 1082 | | sym.name, |
| 1083 | | }); |
| 1084 | | continue; |
| 1085 | | }; |
| 1099 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1100 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1101 | const target_addr = target_sect.addr + target_map.offset; |
| 1102 | const address = reg.address - source_sect.inner.addr + target_addr; |
| 1086 | 1103 | |
| 1087 | | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1088 | | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1089 | | const target_addr = target_sect.addr + target_map.offset; |
| 1090 | | const address = reg.address - source_sect.inner.addr + target_addr; |
| 1091 | | |
| 1092 | | log.debug("resolving symbol '{s}' at 0x{x}", .{ sym.name, address }); |
| 1093 | | |
| 1094 | | // TODO there might be a more generic way of doing this. |
| 1095 | | var section: u8 = 0; |
| 1096 | | for (self.load_commands.items) |cmd, cmd_id| { |
| 1097 | | if (cmd != .Segment) break; |
| 1098 | | if (cmd_id == target_map.segment_id) { |
| 1099 | | section += @intCast(u8, target_map.section_id) + 1; |
| 1100 | | break; |
| 1101 | | } |
| 1102 | | section += @intCast(u8, cmd.Segment.sections.items.len); |
| 1103 | | } |
| 1104 | log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address }); |
| 1104 | 1105 | |
| 1105 | | reg.address = address; |
| 1106 | | reg.section = section; |
| 1106 | // TODO there might be a more generic way of doing this. |
| 1107 | var section: u8 = 0; |
| 1108 | for (self.load_commands.items) |cmd, cmd_id| { |
| 1109 | if (cmd != .Segment) break; |
| 1110 | if (cmd_id == target_map.segment_id) { |
| 1111 | section += @intCast(u8, target_map.section_id) + 1; |
| 1112 | break; |
| 1107 | 1113 | } |
| 1114 | section += @intCast(u8, cmd.Segment.sections.items.len); |
| 1115 | } |
| 1116 | |
| 1117 | reg.address = address; |
| 1118 | reg.section = section; |
| 1119 | } |
| 1120 | |
| 1121 | fn allocateSymbols(self: *Zld) !void { |
| 1122 | for (self.locals.items) |symbol| { |
| 1123 | if (symbol.payload != .regular) continue; |
| 1124 | try self.allocateSymbol(symbol); |
| 1125 | } |
| 1126 | |
| 1127 | for (self.globals.values()) |symbol| { |
| 1128 | if (symbol.payload != .regular) continue; |
| 1129 | try self.allocateSymbol(symbol); |
| 1108 | 1130 | } |
| 1109 | 1131 | } |
| 1110 | 1132 | |
| 1111 | 1133 | fn allocateTentativeSymbols(self: *Zld) !void { |
| 1112 | | if (self.tentatives.values().len == 0) return; |
| 1134 | if (!self.has_tentative_defs) return; |
| 1113 | 1135 | |
| 1114 | 1136 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1115 | 1137 | const common_sect = &data_seg.sections.items[self.common_section_index.?]; |
| ... | ... | @@ -1131,36 +1153,21 @@ fn allocateTentativeSymbols(self: *Zld) !void { |
| 1131 | 1153 | } |
| 1132 | 1154 | |
| 1133 | 1155 | // Convert tentative definitions into regular symbols. |
| 1134 | | for (self.tentatives.values()) |sym| { |
| 1135 | | const tent = sym.cast(Symbol.Tentative) orelse unreachable; |
| 1136 | | const reg = try Symbol.Regular.new(self.allocator, tent.base.name, .{ |
| 1137 | | .linkage = .global, |
| 1138 | | .address = base_address, |
| 1139 | | .section = section, |
| 1140 | | .weak_ref = false, |
| 1141 | | .file = tent.file, |
| 1142 | | }); |
| 1143 | | reg.got_index = tent.base.got_index; |
| 1144 | | reg.stubs_index = tent.base.stubs_index; |
| 1145 | | |
| 1146 | | try self.globals.putNoClobber(self.allocator, reg.name, reg); |
| 1147 | | tent.base.alias = reg; |
| 1148 | | |
| 1149 | | if (tent.base.got_index) |idx| { |
| 1150 | | self.got_entries.items[idx] = reg; |
| 1151 | | } |
| 1152 | | if (tent.base.stubs_index) |idx| { |
| 1153 | | self.stubs.items[idx] = reg; |
| 1154 | | } |
| 1156 | for (self.globals.values()) |sym| { |
| 1157 | if (sym.payload != .tentative) continue; |
| 1155 | 1158 | |
| 1156 | | const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment); |
| 1159 | const address = mem.alignForwardGeneric(u64, base_address + sym.payload.tentative.size, alignment); |
| 1157 | 1160 | |
| 1158 | | log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{ |
| 1159 | | tent.base.name, |
| 1160 | | base_address, |
| 1161 | | address, |
| 1162 | | }); |
| 1161 | log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{ sym.name, base_address, address }); |
| 1163 | 1162 | |
| 1163 | sym.payload = .{ |
| 1164 | .regular = .{ |
| 1165 | .linkage = .global, |
| 1166 | .address = base_address, |
| 1167 | .section = section, |
| 1168 | .weak_ref = false, |
| 1169 | }, |
| 1170 | }; |
| 1164 | 1171 | base_address = address; |
| 1165 | 1172 | } |
| 1166 | 1173 | } |
| ... | ... | @@ -1174,17 +1181,17 @@ fn allocateProxyBindAddresses(self: *Zld) !void { |
| 1174 | 1181 | if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased |
| 1175 | 1182 | if (rel.target != .symbol) continue; |
| 1176 | 1183 | |
| 1177 | | const sym = object.symbols.items[rel.target.symbol].getTopmostAlias(); |
| 1178 | | if (sym.cast(Symbol.Proxy)) |proxy| { |
| 1179 | | const target_map = sect.target_map orelse continue; |
| 1180 | | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1181 | | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1184 | const sym = object.symbols.items[rel.target.symbol]; |
| 1185 | if (sym.payload != .proxy) continue; |
| 1182 | 1186 | |
| 1183 | | try proxy.bind_info.append(self.allocator, .{ |
| 1184 | | .segment_id = target_map.segment_id, |
| 1185 | | .address = target_sect.addr + target_map.offset + rel.offset, |
| 1186 | | }); |
| 1187 | | } |
| 1187 | const target_map = sect.target_map orelse continue; |
| 1188 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1189 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1190 | |
| 1191 | try sym.payload.proxy.bind_info.append(self.allocator, .{ |
| 1192 | .segment_id = target_map.segment_id, |
| 1193 | .address = target_sect.addr + target_map.offset + rel.offset, |
| 1194 | }); |
| 1188 | 1195 | } |
| 1189 | 1196 | } |
| 1190 | 1197 | } |
| ... | ... | @@ -1586,6 +1593,14 @@ fn resolveSymbols(self: *Zld) !void { |
| 1586 | 1593 | } |
| 1587 | 1594 | } |
| 1588 | 1595 | |
| 1596 | // Mark if we need to allocate zerofill section for tentative definitions |
| 1597 | for (self.globals.values()) |symbol| { |
| 1598 | if (symbol.payload == .tentative) { |
| 1599 | self.has_tentative_defs = true; |
| 1600 | break; |
| 1601 | } |
| 1602 | } |
| 1603 | |
| 1589 | 1604 | // Third pass, resolve symbols in dynamic libraries. |
| 1590 | 1605 | { |
| 1591 | 1606 | // Put dyld_stub_binder as an undefined special symbol. |
| ... | ... | @@ -1651,18 +1666,6 @@ fn resolveSymbols(self: *Zld) !void { |
| 1651 | 1666 | } |
| 1652 | 1667 | |
| 1653 | 1668 | if (has_undefined) return error.UndefinedSymbolReference; |
| 1654 | | |
| 1655 | | log.warn("globals", .{}); |
| 1656 | | for (self.globals.values()) |value| { |
| 1657 | | log.warn(" | {s}: {}", .{ value.name, value.payload }); |
| 1658 | | } |
| 1659 | | |
| 1660 | | for (self.objects.items) |object| { |
| 1661 | | log.warn("object {s}", .{object.name.?}); |
| 1662 | | for (object.symbols.items) |sym| { |
| 1663 | | log.warn(" | {s}: {}", .{ sym.name, sym.payload }); |
| 1664 | | } |
| 1665 | | } |
| 1666 | 1669 | } |
| 1667 | 1670 | |
| 1668 | 1671 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| ... | ... | @@ -1675,7 +1678,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1675 | 1678 | switch (rel.@"type") { |
| 1676 | 1679 | .unsigned => continue, |
| 1677 | 1680 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { |
| 1678 | | const sym = object.symbols.items[rel.target.symbol].getTopmostAlias(); |
| 1681 | const sym = object.symbols.items[rel.target.symbol]; |
| 1679 | 1682 | if (sym.got_index != null) continue; |
| 1680 | 1683 | |
| 1681 | 1684 | const index = @intCast(u32, self.got_entries.items.len); |
| ... | ... | @@ -1687,11 +1690,11 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1687 | 1690 | else => { |
| 1688 | 1691 | if (rel.target != .symbol) continue; |
| 1689 | 1692 | |
| 1690 | | const sym = object.symbols.items[rel.target.symbol].getTopmostAlias(); |
| 1691 | | assert(sym.@"type" != .unresolved); |
| 1693 | const sym = object.symbols.items[rel.target.symbol]; |
| 1694 | assert(sym.payload != .undef); |
| 1692 | 1695 | |
| 1693 | 1696 | if (sym.stubs_index != null) continue; |
| 1694 | | if (sym.@"type" != .proxy) continue; |
| 1697 | if (sym.payload != .proxy) continue; |
| 1695 | 1698 | |
| 1696 | 1699 | const index = @intCast(u32, self.stubs.items.len); |
| 1697 | 1700 | sym.stubs_index = index; |
| ... | ... | @@ -1705,7 +1708,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1705 | 1708 | } |
| 1706 | 1709 | |
| 1707 | 1710 | // Finally, put dyld_stub_binder as the final GOT entry |
| 1708 | | const sym = self.imports.get("dyld_stub_binder") orelse unreachable; |
| 1711 | const sym = self.globals.get("dyld_stub_binder") orelse unreachable; |
| 1709 | 1712 | const index = @intCast(u32, self.got_entries.items.len); |
| 1710 | 1713 | sym.got_index = index; |
| 1711 | 1714 | try self.got_entries.append(self.allocator, sym); |