authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-03 14:54:53+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log7c82079d2cfb2f8c299707aa4c79455a73601914
treea516d667a51fd3878fffb04c0d8557ed7515e575
parentceb431507d827f5ac53a18d8904886708325c0e7

zld: allocate symbols using the new scheme


1 files changed, 108 insertions(+), 105 deletions(-)

src/link/MachO/Zld.zig+108-105
......@@ -108,6 +108,7 @@ globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
108108/// Offset into __DATA,__common section.
109109/// Set if the linker found tentative definitions in any of the objects.
110110tentative_defs_offset: u64 = 0,
111has_tentative_defs: bool = false,
111112
112113threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
113114local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
......@@ -222,20 +223,33 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
222223 try self.parseInputFiles(files, args.syslibroot);
223224 try self.parseLibs(args.libs, args.syslibroot);
224225 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
225252 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();
239253 // try self.flush();
240254}
241255
......@@ -351,7 +365,7 @@ fn updateMetadata(self: *Zld) !void {
351365
352366 // Ensure we have __DATA,__common section if we have tentative definitions.
353367 // Update size and alignment of __DATA,__common section.
354 if (self.tentatives.values().len > 0) {
368 if (self.has_tentative_defs) {
355369 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
356370 const common_section_index = self.common_section_index orelse ind: {
357371 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
......@@ -364,10 +378,10 @@ fn updateMetadata(self: *Zld) !void {
364378
365379 var max_align: u16 = 0;
366380 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;
371385 }
372386
373387 common_sect.@"align" = math.max(common_sect.@"align", max_align);
......@@ -1069,47 +1083,55 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
10691083 seg.inner.vmsize = seg_size_aligned;
10701084}
10711085
1072fn 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;
1086fn 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 };
10761098
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;
10861103
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 });
11041105
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;
11071113 }
1114 section += @intCast(u8, cmd.Segment.sections.items.len);
1115 }
1116
1117 reg.address = address;
1118 reg.section = section;
1119}
1120
1121fn 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);
11081130 }
11091131}
11101132
11111133fn allocateTentativeSymbols(self: *Zld) !void {
1112 if (self.tentatives.values().len == 0) return;
1134 if (!self.has_tentative_defs) return;
11131135
11141136 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
11151137 const common_sect = &data_seg.sections.items[self.common_section_index.?];
......@@ -1131,36 +1153,21 @@ fn allocateTentativeSymbols(self: *Zld) !void {
11311153 }
11321154
11331155 // 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;
11551158
1156 const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);
1159 const address = mem.alignForwardGeneric(u64, base_address + sym.payload.tentative.size, alignment);
11571160
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 });
11631162
1163 sym.payload = .{
1164 .regular = .{
1165 .linkage = .global,
1166 .address = base_address,
1167 .section = section,
1168 .weak_ref = false,
1169 },
1170 };
11641171 base_address = address;
11651172 }
11661173}
......@@ -1174,17 +1181,17 @@ fn allocateProxyBindAddresses(self: *Zld) !void {
11741181 if (rel.@"type" != .unsigned) continue; // GOT is currently special-cased
11751182 if (rel.target != .symbol) continue;
11761183
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;
11821186
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 });
11881195 }
11891196 }
11901197 }
......@@ -1586,6 +1593,14 @@ fn resolveSymbols(self: *Zld) !void {
15861593 }
15871594 }
15881595
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
15891604 // Third pass, resolve symbols in dynamic libraries.
15901605 {
15911606 // Put dyld_stub_binder as an undefined special symbol.
......@@ -1651,18 +1666,6 @@ fn resolveSymbols(self: *Zld) !void {
16511666 }
16521667
16531668 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 }
16661669}
16671670
16681671fn resolveStubsAndGotEntries(self: *Zld) !void {
......@@ -1675,7 +1678,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
16751678 switch (rel.@"type") {
16761679 .unsigned => continue,
16771680 .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];
16791682 if (sym.got_index != null) continue;
16801683
16811684 const index = @intCast(u32, self.got_entries.items.len);
......@@ -1687,11 +1690,11 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
16871690 else => {
16881691 if (rel.target != .symbol) continue;
16891692
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);
16921695
16931696 if (sym.stubs_index != null) continue;
1694 if (sym.@"type" != .proxy) continue;
1697 if (sym.payload != .proxy) continue;
16951698
16961699 const index = @intCast(u32, self.stubs.items.len);
16971700 sym.stubs_index = index;
......@@ -1705,7 +1708,7 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
17051708 }
17061709
17071710 // 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;
17091712 const index = @intCast(u32, self.got_entries.items.len);
17101713 sym.got_index = index;
17111714 try self.got_entries.append(self.allocator, sym);