| ... | @@ -108,6 +108,7 @@ globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | ... | @@ -108,6 +108,7 @@ globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 108 | /// Offset into __DATA,__common section. | 108 | /// Offset into __DATA,__common section. |
| 109 | /// Set if the linker found tentative definitions in any of the objects. | 109 | /// Set if the linker found tentative definitions in any of the objects. |
| 110 | tentative_defs_offset: u64 = 0, | 110 | tentative_defs_offset: u64 = 0, |
| | 111 | has_tentative_defs: bool = false, |
| 111 | | 112 | |
| 112 | threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction | 113 | threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction |
| 113 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | 114 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| ... | @@ -222,20 +223,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -222,20 +223,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 222 | try self.parseInputFiles(files, args.syslibroot); | 223 | try self.parseInputFiles(files, args.syslibroot); |
| 223 | try self.parseLibs(args.libs, args.syslibroot); | 224 | try self.parseLibs(args.libs, args.syslibroot); |
| 224 | try self.resolveSymbols(); | 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 | return error.TODO; | 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 | // try self.flush(); | 253 | // try self.flush(); |
| 240 | } | 254 | } |
| 241 | | 255 | |
| ... | @@ -351,7 +365,7 @@ fn updateMetadata(self: *Zld) !void { | ... | @@ -351,7 +365,7 @@ fn updateMetadata(self: *Zld) !void { |
| 351 | | 365 | |
| 352 | // Ensure we have __DATA,__common section if we have tentative definitions. | 366 | // Ensure we have __DATA,__common section if we have tentative definitions. |
| 353 | // Update size and alignment of __DATA,__common section. | 367 | // Update size and alignment of __DATA,__common section. |
| 354 | if (self.tentatives.values().len > 0) { | 368 | if (self.has_tentative_defs) { |
| 355 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 369 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 356 | const common_section_index = self.common_section_index orelse ind: { | 370 | const common_section_index = self.common_section_index orelse ind: { |
| 357 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); | 371 | self.common_section_index = @intCast(u16, data_seg.sections.items.len); |
| ... | @@ -364,10 +378,10 @@ fn updateMetadata(self: *Zld) !void { | ... | @@ -364,10 +378,10 @@ fn updateMetadata(self: *Zld) !void { |
| 364 | | 378 | |
| 365 | var max_align: u16 = 0; | 379 | var max_align: u16 = 0; |
| 366 | var added_size: u64 = 0; | 380 | var added_size: u64 = 0; |
| 367 | for (self.tentatives.values()) |sym| { | 381 | for (self.globals.values()) |sym| { |
| 368 | const tent = sym.cast(Symbol.Tentative) orelse unreachable; | 382 | if (sym.payload != .tentative) continue; |
| 369 | max_align = math.max(max_align, tent.alignment); | 383 | max_align = math.max(max_align, sym.payload.tentative.alignment); |
| 370 | added_size += tent.size; | 384 | added_size += sym.payload.tentative.size; |
| 371 | } | 385 | } |
| 372 | | 386 | |
| 373 | common_sect.@"align" = math.max(common_sect.@"align", max_align); | 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,47 +1083,55 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 1069 | seg.inner.vmsize = seg_size_aligned; | 1083 | seg.inner.vmsize = seg_size_aligned; |
| 1070 | } | 1084 | } |
| 1071 | | 1085 | |
| 1072 | fn allocateSymbols(self: *Zld) !void { | 1086 | fn allocateSymbol(self: *Zld, symbol: *Symbol) !void { |
| 1073 | for (self.objects.items) |object| { | 1087 | const reg = &symbol.payload.regular; |
| 1074 | for (object.symbols.items) |sym| { | 1088 | const object = reg.file orelse return; |
| 1075 | const reg = sym.cast(Symbol.Regular) orelse continue; | 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]; | 1099 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1078 | const target_map = source_sect.target_map orelse { | 1100 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1079 | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ | 1101 | const target_addr = target_sect.addr + target_map.offset; |
| 1080 | parseName(&source_sect.inner.segname), | 1102 | const address = reg.address - source_sect.inner.addr + target_addr; |
| 1081 | parseName(&source_sect.inner.sectname), | | |
| 1082 | sym.name, | | |
| 1083 | }); | | |
| 1084 | continue; | | |
| 1085 | }; | | |
| 1086 | | 1103 | |
| 1087 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; | 1104 | log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address }); |
| 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 | | 1105 | |
| 1105 | reg.address = address; | 1106 | // TODO there might be a more generic way of doing this. |
| 1106 | reg.section = section; | 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 | fn allocateTentativeSymbols(self: *Zld) !void { | 1133 | fn allocateTentativeSymbols(self: *Zld) !void { |
| 1112 | if (self.tentatives.values().len == 0) return; | 1134 | if (!self.has_tentative_defs) return; |
| 1113 | | 1135 | |
| 1114 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 1136 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1115 | const common_sect = &data_seg.sections.items[self.common_section_index.?]; | 1137 | const common_sect = &data_seg.sections.items[self.common_section_index.?]; |
| ... | @@ -1131,36 +1153,21 @@ fn allocateTentativeSymbols(self: *Zld) !void { | ... | @@ -1131,36 +1153,21 @@ fn allocateTentativeSymbols(self: *Zld) !void { |
| 1131 | } | 1153 | } |
| 1132 | | 1154 | |
| 1133 | // Convert tentative definitions into regular symbols. | 1155 | // Convert tentative definitions into regular symbols. |
| 1134 | for (self.tentatives.values()) |sym| { | 1156 | for (self.globals.values()) |sym| { |
| 1135 | const tent = sym.cast(Symbol.Tentative) orelse unreachable; | 1157 | if (sym.payload != .tentative) continue; |
| 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 | } | | |
| 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}", .{ | 1161 | log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{ sym.name, base_address, address }); |
| 1159 | tent.base.name, | | |
| 1160 | base_address, | | |
| 1161 | address, | | |
| 1162 | }); | | |
| 1163 | | 1162 | |
| | 1163 | sym.payload = .{ |
| | 1164 | .regular = .{ |
| | 1165 | .linkage = .global, |
| | 1166 | .address = base_address, |
| | 1167 | .section = section, |
| | 1168 | .weak_ref = false, |
| | 1169 | }, |
| | 1170 | }; |
| 1164 | base_address = address; | 1171 | base_address = address; |
| 1165 | } | 1172 | } |
| 1166 | } | 1173 | } |
| ... | @@ -1174,17 +1181,17 @@ fn allocateProxyBindAddresses(self: *Zld) !void { | ... | @@ -1174,17 +1181,17 @@ fn allocateProxyBindAddresses(self: *Zld) !void { |
| 1174 | if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased | 1181 | if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased |
| 1175 | if (rel.target != .symbol) continue; | 1182 | if (rel.target != .symbol) continue; |
| 1176 | | 1183 | |
| 1177 | const sym = object.symbols.items[rel.target.symbol].getTopmostAlias(); | 1184 | const sym = object.symbols.items[rel.target.symbol]; |
| 1178 | if (sym.cast(Symbol.Proxy)) |proxy| { | 1185 | if (sym.payload != .proxy) continue; |
| 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]; | | |
| 1182 | | 1186 | |
| 1183 | try proxy.bind_info.append(self.allocator, .{ | 1187 | const target_map = sect.target_map orelse continue; |
| 1184 | .segment_id = target_map.segment_id, | 1188 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| 1185 | .address = target_sect.addr + target_map.offset + rel.offset, | 1189 | const target_sect = target_seg.sections.items[target_map.section_id]; |
| 1186 | }); | 1190 | |
| 1187 | } | 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,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 | // Third pass, resolve symbols in dynamic libraries. | 1604 | // Third pass, resolve symbols in dynamic libraries. |
| 1590 | { | 1605 | { |
| 1591 | // Put dyld_stub_binder as an undefined special symbol. | 1606 | // Put dyld_stub_binder as an undefined special symbol. |
| ... | @@ -1651,18 +1666,6 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1651,18 +1666,6 @@ fn resolveSymbols(self: *Zld) !void { |
| 1651 | } | 1666 | } |
| 1652 | | 1667 | |
| 1653 | if (has_undefined) return error.UndefinedSymbolReference; | 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 | fn resolveStubsAndGotEntries(self: *Zld) !void { | 1671 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| ... | @@ -1675,7 +1678,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1675,7 +1678,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1675 | switch (rel.@"type") { | 1678 | switch (rel.@"type") { |
| 1676 | .unsigned => continue, | 1679 | .unsigned => continue, |
| 1677 | .got_page, .got_page_off, .got_load, .got, .pointer_to_got => { | 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 | if (sym.got_index != null) continue; | 1682 | if (sym.got_index != null) continue; |
| 1680 | | 1683 | |
| 1681 | const index = @intCast(u32, self.got_entries.items.len); | 1684 | const index = @intCast(u32, self.got_entries.items.len); |
| ... | @@ -1687,11 +1690,11 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1687,11 +1690,11 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1687 | else => { | 1690 | else => { |
| 1688 | if (rel.target != .symbol) continue; | 1691 | if (rel.target != .symbol) continue; |
| 1689 | | 1692 | |
| 1690 | const sym = object.symbols.items[rel.target.symbol].getTopmostAlias(); | 1693 | const sym = object.symbols.items[rel.target.symbol]; |
| 1691 | assert(sym.@"type" != .unresolved); | 1694 | assert(sym.payload != .undef); |
| 1692 | | 1695 | |
| 1693 | if (sym.stubs_index != null) continue; | 1696 | if (sym.stubs_index != null) continue; |
| 1694 | if (sym.@"type" != .proxy) continue; | 1697 | if (sym.payload != .proxy) continue; |
| 1695 | | 1698 | |
| 1696 | const index = @intCast(u32, self.stubs.items.len); | 1699 | const index = @intCast(u32, self.stubs.items.len); |
| 1697 | sym.stubs_index = index; | 1700 | sym.stubs_index = index; |
| ... | @@ -1705,7 +1708,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { | ... | @@ -1705,7 +1708,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1705 | } | 1708 | } |
| 1706 | | 1709 | |
| 1707 | // Finally, put dyld_stub_binder as the final GOT entry | 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 | const index = @intCast(u32, self.got_entries.items.len); | 1712 | const index = @intCast(u32, self.got_entries.items.len); |
| 1710 | sym.got_index = index; | 1713 | sym.got_index = index; |
| 1711 | try self.got_entries.append(self.allocator, sym); | 1714 | try self.got_entries.append(self.allocator, sym); |