authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-06 00:00:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
log54888c6f4699b07eadd21b744d797006fb96a284
tree2e3a974682f0b9bae3adabeaf3dbe85b16f0b2ce
parent51e334af447b126862238f0743342755d719f897

zld: create TextBlocks for tentative definitions

and fix the links in the `TextBlock`s linked list!

3 files changed, 99 insertions(+), 122 deletions(-)

src/link/MachO/Object.zig+33-24
...@@ -9,6 +9,7 @@ const log = std.log.scoped(.object);...@@ -9,6 +9,7 @@ const log = std.log.scoped(.object);
9const macho = std.macho;9const macho = std.macho;
10const mem = std.mem;10const mem = std.mem;
11const reloc = @import("reloc.zig");11const reloc = @import("reloc.zig");
12const sort = std.sort;
1213
13const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
14const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
...@@ -345,13 +346,15 @@ const TextBlockParser = struct {...@@ -345,13 +346,15 @@ const TextBlockParser = struct {
345 };346 };
346347
347 fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {348 fn lessThanBySeniority(context: SeniorityContext, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
348 const lreg = context.zld.locals.items[lhs.index].payload.regular;349 const lsym = context.zld.locals.items[lhs.index];
349 const rreg = context.zld.locals.items[rhs.index].payload.regular;350 const rsym = context.zld.locals.items[rhs.index];
351 const lreg = lsym.payload.regular;
352 const rreg = rsym.payload.regular;
350353
351 return switch (rreg.linkage) {354 return switch (rreg.linkage) {
352 .global => true,355 .global => true,
353 .linkage_unit => lreg.linkage == .translation_unit,356 .linkage_unit => lreg.linkage == .translation_unit,
354 else => false,357 else => lsym.isTemp(),
355 };358 };
356 }359 }
357360
...@@ -388,7 +391,7 @@ const TextBlockParser = struct {...@@ -388,7 +391,7 @@ const TextBlockParser = struct {
388391
389 if (aliases.items.len > 1) {392 if (aliases.items.len > 1) {
390 // Bubble-up senior symbol as the main link to the text block.393 // Bubble-up senior symbol as the main link to the text block.
391 std.sort.sort(394 sort.sort(
392 NlistWithIndex,395 NlistWithIndex,
393 aliases.items,396 aliases.items,
394 SeniorityContext{ .zld = self.zld },397 SeniorityContext{ .zld = self.zld },
...@@ -427,13 +430,12 @@ const TextBlockParser = struct {...@@ -427,13 +430,12 @@ const TextBlockParser = struct {
427 };430 };
428431
429 self.index += 1;432 self.index += 1;
430 block.print_this(self.zld);
431433
432 return block;434 return block;
433 }435 }
434};436};
435437
436pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {438pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
437 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;439 const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
438440
439 log.warn("analysing {s}", .{self.name.?});441 log.warn("analysing {s}", .{self.name.?});
...@@ -453,9 +455,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -453,9 +455,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
453 });455 });
454 }456 }
455457
456 std.sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);458 sort.sort(NlistWithIndex, sorted_nlists.items, {}, NlistWithIndex.lessThan);
457
458 var last_block: ?*TextBlock = null;
459459
460 for (seg.sections.items) |sect, sect_id| {460 for (seg.sections.items) |sect, sect_id| {
461 log.warn("putting section '{s},{s}' as a TextBlock", .{461 log.warn("putting section '{s},{s}' as a TextBlock", .{
...@@ -496,24 +496,35 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -496,24 +496,35 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
496 };496 };
497497
498 while (try parser.next()) |block| {498 while (try parser.next()) |block| {
499 const sym = zld.locals.items[block.local_sym_index];499 {
500 if (sym.payload.regular.file) |file| {500 const sym = zld.locals.items[block.local_sym_index];
501 if (file != self) {501 const reg = &sym.payload.regular;
502 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });502 if (reg.file) |file| {
503 continue;503 if (file != self) {
504 log.warn("deduping definition of {s} in {s}", .{ sym.name, self.name.? });
505 continue;
506 }
504 }507 }
508 reg.segment_id = match.seg;
509 reg.section_id = match.sect;
505 }510 }
506511
507 block.segment_id = match.seg;512 if (block.aliases) |aliases| {
508 block.section_id = match.sect;513 for (aliases) |alias| {
514 const sym = zld.locals.items[alias];
515 const reg = &sym.payload.regular;
516 reg.segment_id = match.seg;
517 reg.section_id = match.sect;
518 }
519 }
509520
510 // TODO parse relocs521 // TODO parse relocs
511522
512 if (last_block) |last| {523 if (zld.last_text_block) |last| {
513 last.next = block;524 last.next = block;
514 block.prev = last;525 block.prev = last;
515 }526 }
516 last_block = block;527 zld.last_text_block = block;
517 }528 }
518529
519 break :next;530 break :next;
...@@ -531,6 +542,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -531,6 +542,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
531 symbol.payload = .{542 symbol.payload = .{
532 .regular = .{543 .regular = .{
533 .linkage = .translation_unit,544 .linkage = .translation_unit,
545 .segment_id = match.seg,
546 .section_id = match.sect,
534 .file = self,547 .file = self,
535 },548 },
536 };549 };
...@@ -545,21 +558,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {...@@ -545,21 +558,17 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !?*TextBlock {
545 .code = code,558 .code = code,
546 .size = sect.size,559 .size = sect.size,
547 .alignment = sect.@"align",560 .alignment = sect.@"align",
548 .segment_id = match.seg,
549 .section_id = match.sect,
550 };561 };
551562
552 // TODO parse relocs563 // TODO parse relocs
553564
554 if (last_block) |last| {565 if (zld.last_text_block) |last| {
555 last.next = block;566 last.next = block;
556 block.prev = last;567 block.prev = last;
557 }568 }
558 last_block = block;569 zld.last_text_block = block;
559 }570 }
560 }571 }
561
562 return last_block;
563}572}
564573
565pub fn parseInitializers(self: *Object) !void {574pub fn parseInitializers(self: *Object) !void {
src/link/MachO/Symbol.zig+18-2
...@@ -46,7 +46,7 @@ pub const Regular = struct {...@@ -46,7 +46,7 @@ pub const Regular = struct {
46 segment_id: u16 = 0,46 segment_id: u16 = 0,
4747
48 /// Section ID48 /// Section ID
49 section: u16 = 0,49 section_id: u16 = 0,
5050
51 /// Whether the symbol is a weak ref.51 /// Whether the symbol is a weak ref.
52 weak_ref: bool = false,52 weak_ref: bool = false,
...@@ -69,7 +69,8 @@ pub const Regular = struct {...@@ -69,7 +69,8 @@ pub const Regular = struct {
69 try std.fmt.format(writer, "Regular {{ ", .{});69 try std.fmt.format(writer, "Regular {{ ", .{});
70 try std.fmt.format(writer, ".linkage = {s}, ", .{self.linkage});70 try std.fmt.format(writer, ".linkage = {s}, ", .{self.linkage});
71 try std.fmt.format(writer, ".address = 0x{x}, ", .{self.address});71 try std.fmt.format(writer, ".address = 0x{x}, ", .{self.address});
72 try std.fmt.format(writer, ".section = {}, ", .{self.section});72 try std.fmt.format(writer, ".segment_id = {}, ", .{self.segment_id});
73 try std.fmt.format(writer, ".section_id = {}, ", .{self.section_id});
73 if (self.weak_ref) {74 if (self.weak_ref) {
74 try std.fmt.format(writer, ".weak_ref, ", .{});75 try std.fmt.format(writer, ".weak_ref, ", .{});
75 }76 }
...@@ -170,6 +171,21 @@ pub fn new(allocator: *Allocator, name: []const u8) !*Symbol {...@@ -170,6 +171,21 @@ pub fn new(allocator: *Allocator, name: []const u8) !*Symbol {
170 return new_sym;171 return new_sym;
171}172}
172173
174pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
175 _ = fmt;
176 _ = options;
177 try std.fmt.format(writer, "Symbol {{", .{});
178 try std.fmt.format(writer, ".name = {s}, ", .{self.name});
179 if (self.got_index) |got_index| {
180 try std.fmt.format(writer, ".got_index = {}, ", .{got_index});
181 }
182 if (self.stubs_index) |stubs_index| {
183 try std.fmt.format(writer, ".stubs_index = {}, ", .{stubs_index});
184 }
185 try std.fmt.format(writer, "{}, ", .{self.payload});
186 try std.fmt.format(writer, "}}", .{});
187}
188
173pub fn isTemp(symbol: Symbol) bool {189pub fn isTemp(symbol: Symbol) bool {
174 switch (symbol.payload) {190 switch (symbol.payload) {
175 .regular => |regular| {191 .regular => |regular| {
src/link/MachO/Zld.zig+48-96
...@@ -107,11 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{},...@@ -107,11 +107,6 @@ locals: std.ArrayListUnmanaged(*Symbol) = .{},
107imports: std.ArrayListUnmanaged(*Symbol) = .{},107imports: std.ArrayListUnmanaged(*Symbol) = .{},
108globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},108globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
109109
110/// Offset into __DATA,__common section.
111/// Set if the linker found tentative definitions in any of the objects.
112tentative_defs_offset: u64 = 0,
113has_tentative_defs: bool = false,
114
115threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction110threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
116local_rebases: std.ArrayListUnmanaged(Pointer) = .{},111local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
117stubs: std.ArrayListUnmanaged(*Symbol) = .{},112stubs: std.ArrayListUnmanaged(*Symbol) = .{},
...@@ -145,8 +140,6 @@ pub const TextBlock = struct {...@@ -145,8 +140,6 @@ pub const TextBlock = struct {
145 relocs: ?[]*Relocation = null,140 relocs: ?[]*Relocation = null,
146 size: u64,141 size: u64,
147 alignment: u32,142 alignment: u32,
148 segment_id: u16 = 0,
149 section_id: u16 = 0,
150 next: ?*TextBlock = null,143 next: ?*TextBlock = null,
151 prev: ?*TextBlock = null,144 prev: ?*TextBlock = null,
152145
...@@ -168,23 +161,21 @@ pub const TextBlock = struct {...@@ -168,23 +161,21 @@ pub const TextBlock = struct {
168161
169 pub fn print_this(self: *const TextBlock, zld: *Zld) void {162 pub fn print_this(self: *const TextBlock, zld: *Zld) void {
170 log.warn("TextBlock", .{});163 log.warn("TextBlock", .{});
171 log.warn(" | {}: '{s}'", .{ self.local_sym_index, zld.locals.items[self.local_sym_index].name });164 log.warn(" | {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] });
172 if (self.aliases) |aliases| {165 if (self.aliases) |aliases| {
173 log.warn(" | Aliases:", .{});166 log.warn(" | Aliases:", .{});
174 for (aliases) |index| {167 for (aliases) |index| {
175 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });168 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
176 }169 }
177 }170 }
178 if (self.references) |references| {171 if (self.references) |references| {
179 log.warn(" | References:", .{});172 log.warn(" | References:", .{});
180 for (references) |index| {173 for (references) |index| {
181 log.warn(" | {}: '{s}'", .{ index, zld.locals.items[index].name });174 log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
182 }175 }
183 }176 }
184 log.warn(" | size = {}", .{self.size});177 log.warn(" | size = {}", .{self.size});
185 log.warn(" | align = {}", .{self.alignment});178 log.warn(" | align = {}", .{self.alignment});
186 log.warn(" | segment_id = {}", .{self.segment_id});
187 log.warn(" | section_id = {}", .{self.section_id});
188 }179 }
189180
190 pub fn print(self: *const TextBlock, zld: *Zld) void {181 pub fn print(self: *const TextBlock, zld: *Zld) void {
...@@ -300,7 +291,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg...@@ -300,7 +291,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
300 // try self.allocateDataSegment();291 // try self.allocateDataSegment();
301 // self.allocateLinkeditSegment();292 // self.allocateLinkeditSegment();
302 // try self.allocateSymbols();293 // try self.allocateSymbols();
303 // try self.allocateTentativeSymbols();
304 // try self.allocateProxyBindAddresses();294 // try self.allocateProxyBindAddresses();
305 // try self.flush();295 // try self.flush();
306}296}
...@@ -415,37 +405,6 @@ fn updateMetadata(self: *Zld) !void {...@@ -415,37 +405,6 @@ fn updateMetadata(self: *Zld) !void {
415 }405 }
416 }406 }
417407
418 // Ensure we have __DATA,__common section if we have tentative definitions.
419 // Update size and alignment of __DATA,__common section.
420 if (self.has_tentative_defs) {
421 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
422 const common_section_index = self.common_section_index orelse ind: {
423 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
424 try data_seg.addSection(self.allocator, "__common", .{
425 .flags = macho.S_ZEROFILL,
426 });
427 break :ind self.common_section_index.?;
428 };
429 const common_sect = &data_seg.sections.items[common_section_index];
430
431 var max_align: u16 = 0;
432 var added_size: u64 = 0;
433 for (self.globals.values()) |sym| {
434 if (sym.payload != .tentative) continue;
435 max_align = math.max(max_align, sym.payload.tentative.alignment);
436 added_size += sym.payload.tentative.size;
437 }
438
439 common_sect.@"align" = math.max(common_sect.@"align", max_align);
440
441 const alignment = try math.powi(u32, 2, common_sect.@"align");
442 const offset = mem.alignForwardGeneric(u64, common_sect.size, alignment);
443 const size = mem.alignForwardGeneric(u64, added_size, alignment);
444
445 common_sect.size = offset + size;
446 self.tentative_defs_offset = offset;
447 }
448
449 tlv_align: {408 tlv_align: {
450 const has_tlv =409 const has_tlv =
451 self.tlv_section_index != null or410 self.tlv_section_index != null or
...@@ -1182,48 +1141,6 @@ fn allocateSymbols(self: *Zld) !void {...@@ -1182,48 +1141,6 @@ fn allocateSymbols(self: *Zld) !void {
1182 }1141 }
1183}1142}
11841143
1185fn allocateTentativeSymbols(self: *Zld) !void {
1186 if (!self.has_tentative_defs) return;
1187
1188 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1189 const common_sect = &data_seg.sections.items[self.common_section_index.?];
1190
1191 const alignment = try math.powi(u32, 2, common_sect.@"align");
1192 var base_address: u64 = common_sect.addr + self.tentative_defs_offset;
1193
1194 log.debug("base address for tentative definitions 0x{x}", .{base_address});
1195
1196 // TODO there might be a more generic way of doing this.
1197 var section: u8 = 0;
1198 for (self.load_commands.items) |cmd, cmd_id| {
1199 if (cmd != .Segment) break;
1200 if (cmd_id == self.data_segment_cmd_index.?) {
1201 section += @intCast(u8, self.common_section_index.?) + 1;
1202 break;
1203 }
1204 section += @intCast(u8, cmd.Segment.sections.items.len);
1205 }
1206
1207 // Convert tentative definitions into regular symbols.
1208 for (self.globals.values()) |sym| {
1209 if (sym.payload != .tentative) continue;
1210
1211 const address = mem.alignForwardGeneric(u64, base_address + sym.payload.tentative.size, alignment);
1212
1213 log.debug("tentative definition '{s}' allocated from 0x{x} to 0x{x}", .{ sym.name, base_address, address });
1214
1215 sym.payload = .{
1216 .regular = .{
1217 .linkage = .global,
1218 .address = base_address,
1219 .section = section,
1220 .weak_ref = false,
1221 },
1222 };
1223 base_address = address;
1224 }
1225}
1226
1227fn allocateProxyBindAddresses(self: *Zld) !void {1144fn allocateProxyBindAddresses(self: *Zld) !void {
1228 for (self.objects.items) |object| {1145 for (self.objects.items) |object| {
1229 for (object.sections.items) |sect| {1146 for (object.sections.items) |sect| {
...@@ -1648,15 +1565,56 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1648,15 +1565,56 @@ fn resolveSymbols(self: *Zld) !void {
1648 }1565 }
16491566
1650 // Put any globally defined regular symbol as local.1567 // Put any globally defined regular symbol as local.
1651 // Mark if we need to allocate zerofill section for tentative definitions1568 // Convert any tentative definition into a regular symbol and allocate
1569 // text blocks for each tentative defintion.
1652 for (self.globals.values()) |symbol| {1570 for (self.globals.values()) |symbol| {
1653 switch (symbol.payload) {1571 switch (symbol.payload) {
1654 .regular => |*reg| {1572 .regular => |*reg| {
1655 reg.local_sym_index = @intCast(u32, self.locals.items.len);1573 reg.local_sym_index = @intCast(u32, self.locals.items.len);
1656 try self.locals.append(self.allocator, symbol);1574 try self.locals.append(self.allocator, symbol);
1657 },1575 },
1658 .tentative => {1576 .tentative => |tent| {
1659 self.has_tentative_defs = true;1577 if (self.common_section_index == null) {
1578 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1579 self.common_section_index = @intCast(u16, data_seg.sections.items.len);
1580 try data_seg.addSection(self.allocator, "__common", .{
1581 .flags = macho.S_ZEROFILL,
1582 });
1583 }
1584
1585 const size = tent.size;
1586 const code = try self.allocator.alloc(u8, size);
1587 mem.set(u8, code, 0);
1588 const alignment = tent.alignment;
1589 const local_sym_index = @intCast(u32, self.locals.items.len);
1590
1591 symbol.payload = .{
1592 .regular = .{
1593 .linkage = .global,
1594 .segment_id = self.data_segment_cmd_index.?,
1595 .section_id = self.common_section_index.?,
1596 .local_sym_index = local_sym_index,
1597 },
1598 };
1599 try self.locals.append(self.allocator, symbol);
1600
1601 const block = try self.allocator.create(TextBlock);
1602 errdefer self.allocator.destroy(block);
1603
1604 block.* = .{
1605 .local_sym_index = local_sym_index,
1606 .code = code,
1607 .size = size,
1608 .alignment = alignment,
1609 };
1610
1611 // TODO I'm not 100% sure about this yet, but I believe we should keep a separate list of
1612 // TextBlocks per segment.
1613 if (self.last_text_block) |last| {
1614 last.next = block;
1615 block.prev = last;
1616 }
1617 self.last_text_block = block;
1660 },1618 },
1661 else => {},1619 else => {},
1662 }1620 }
...@@ -1733,13 +1691,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1733,13 +1691,7 @@ fn resolveSymbols(self: *Zld) !void {
17331691
1734fn parseTextBlocks(self: *Zld) !void {1692fn parseTextBlocks(self: *Zld) !void {
1735 for (self.objects.items) |object| {1693 for (self.objects.items) |object| {
1736 if (try object.parseTextBlocks(self)) |block| {1694 try object.parseTextBlocks(self);
1737 if (self.last_text_block) |last| {
1738 last.next = block;
1739 block.prev = last;
1740 }
1741 self.last_text_block = block;
1742 }
1743 }1695 }
17441696
1745 if (self.last_text_block) |block| {1697 if (self.last_text_block) |block| {