authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-10 17:37:38+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-06-10 17:49:14+02:00
logc2086efb412f17bb52514e931016e79c65bed442
treef1aa2c933f77c3b14eac48180ccc4a9f7ee765af
parent03cda80a634d82e02e641fe04fa2abda4455966a

zld: synthetise regular from tentative definition


1 files changed, 126 insertions(+), 7 deletions(-)

src/link/MachO/Zld.zig+126-7
......@@ -86,9 +86,9 @@ imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
8686unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
8787tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
8888
89// /// Offset into __DATA,__common section.
90// /// Set if the linker found tentative definitions in any of the objects.
91// tentative_defs_offset: u32 = 0,
89/// Offset into __DATA,__common section.
90/// Set if the linker found tentative definitions in any of the objects.
91tentative_defs_offset: u64 = 0,
9292
9393strtab: std.ArrayListUnmanaged(u8) = .{},
9494strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
......@@ -227,6 +227,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: L
227227 try self.allocateDataSegment();
228228 self.allocateLinkeditSegment();
229229 try self.allocateSymbols();
230 try self.allocateTentativeSymbols();
230231 try self.flush();
231232}
232233
......@@ -691,6 +692,49 @@ fn updateMetadata(self: *Zld) !void {
691692 }
692693 }
693694
695 // Ensure we have __DATA,__common section if we have tentative definitions.
696 // Update size and alignment of __DATA,__common section.
697 if (self.tentatives.values().len > 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 if (max_align > tent.alignment) continue;
724 max_align = tent.alignment;
725 added_size += tent.size;
726 }
727
728 common_sect.@"align" = math.max(common_sect.@"align", max_align);
729
730 const alignment = try math.powi(u32, 2, common_sect.@"align");
731 const offset = mem.alignForwardGeneric(u64, common_sect.size, alignment);
732 const size = mem.alignForwardGeneric(u64, added_size, alignment);
733
734 common_sect.size = offset + size;
735 self.tentative_defs_offset = offset;
736 }
737
694738 tlv_align: {
695739 const has_tlv =
696740 self.tlv_section_index != null or
......@@ -1110,6 +1154,70 @@ fn allocateSymbols(self: *Zld) !void {
11101154 }
11111155}
11121156
1157fn allocateTentativeSymbols(self: *Zld) !void {
1158 if (self.tentatives.values().len == 0) return;
1159
1160 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1161 const common_sect = &data_seg.sections.items[self.common_section_index.?];
1162
1163 const alignment = try math.powi(u32, 2, common_sect.@"align");
1164 var base_address: u64 = common_sect.addr + self.tentative_defs_offset;
1165
1166 log.debug("base address for tentative definitions 0x{x}", .{base_address});
1167
1168 // TODO there might be a more generic way of doing this.
1169 var section: u8 = 0;
1170 for (self.load_commands.items) |cmd, cmd_id| {
1171 if (cmd != .Segment) break;
1172 if (cmd_id == self.data_segment_cmd_index.?) {
1173 section += @intCast(u8, self.common_section_index.?) + 1;
1174 break;
1175 }
1176 section += @intCast(u8, cmd.Segment.sections.items.len);
1177 }
1178
1179 // Convert tentative definitions into regular symbols.
1180 for (self.tentatives.values()) |sym, i| {
1181 const tent = sym.cast(Symbol.Tentative) orelse unreachable;
1182 const reg = try self.allocator.create(Symbol.Regular);
1183 errdefer self.allocator.destroy(reg);
1184
1185 reg.* = .{
1186 .base = .{
1187 .@"type" = .regular,
1188 .name = try self.allocator.dupe(u8, tent.base.name),
1189 .got_index = tent.base.got_index,
1190 .stubs_index = tent.base.stubs_index,
1191 },
1192 .linkage = .global,
1193 .address = base_address,
1194 .section = section,
1195 .weak_ref = false,
1196 .file = tent.file,
1197 };
1198
1199 try self.globals.putNoClobber(self.allocator, reg.base.name, &reg.base);
1200 tent.base.alias = &reg.base;
1201
1202 if (tent.base.got_index) |idx| {
1203 self.got_entries.items[idx] = &reg.base;
1204 }
1205 if (tent.base.stubs_index) |idx| {
1206 self.stubs.items[idx] = &reg.base;
1207 }
1208
1209 const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);
1210
1211 log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{
1212 tent.base.name,
1213 base_address,
1214 address,
1215 });
1216
1217 base_address = address;
1218 }
1219}
1220
11131221fn writeStubHelperCommon(self: *Zld) !void {
11141222 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
11151223 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1432,14 +1540,25 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
14321540 kv.value.alias = sym;
14331541 }
14341542
1435 const t_sym = self.tentatives.get(sym.name) orelse {
1543 const sym_ptr = self.tentatives.getPtr(sym.name) orelse {
14361544 // Put new tentative definition symbol into symbol table.
14371545 try self.tentatives.putNoClobber(self.allocator, sym.name, sym);
14381546 continue;
14391547 };
14401548
1441 // TODO compare by size and pick the largest.
1442 return error.TODOResolveTentatives;
1549 // Compare by size and pick the largest tentative definition.
1550 // We model this like a heap where the tentative definition with the
1551 // largest size always washes up on top.
1552 const t_sym = sym_ptr.*;
1553 const t_tent = t_sym.cast(Symbol.Tentative) orelse unreachable;
1554
1555 if (tent.size < t_tent.size) {
1556 sym.alias = t_sym;
1557 continue;
1558 }
1559
1560 t_sym.alias = sym;
1561 sym_ptr.* = sym;
14431562 } else if (sym.cast(Symbol.Unresolved)) |und| {
14441563 if (self.globals.get(sym.name)) |g_sym| {
14451564 sym.alias = g_sym;
......@@ -1453,6 +1572,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
14531572 sym.alias = u_sym;
14541573 continue;
14551574 }
1575
14561576 try self.unresolved.putNoClobber(self.allocator, sym.name, sym);
14571577 } else unreachable;
14581578 }
......@@ -1494,7 +1614,6 @@ fn resolveSymbols(self: *Zld) !void {
14941614 next_sym += 1;
14951615 }
14961616 }
1497
14981617 // Third pass, resolve symbols in dynamic libraries.
14991618 // TODO Implement libSystem as a hard-coded library, or ship with
15001619 // a libSystem.B.tbd definition file?