Commit 7aeedc0912
Changed files (4)
src
link
src/link/MachO/Object.zig
@@ -7,6 +7,7 @@ const fs = std.fs;
const io = std.io;
const log = std.log.scoped(.object);
const macho = std.macho;
+const math = std.math;
const mem = std.mem;
const reloc = @import("reloc.zig");
const sort = std.sort;
@@ -436,7 +437,7 @@ const TextBlockParser = struct {
.code = try self.allocator.dupe(u8, code),
.relocs = std.ArrayList(Relocation).init(self.allocator),
.rebases = std.ArrayList(u64).init(self.allocator),
- .tlv_offsets = std.ArrayList(u64).init(self.allocator),
+ .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
.size = size,
.alignment = self.section.@"align",
};
@@ -533,6 +534,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
}
}
+ // Update target section's metadata
+ // TODO should we update segment's size here too?
+ // How does it tie with incremental space allocs?
+ const tseg = &zld.load_commands.items[match.seg].Segment;
+ const tsect = &tseg.sections.items[match.sect];
+ tsect.size += block.size;
+ tsect.@"align" = math.max(tsect.@"align", block.alignment);
+
if (zld.blocks.getPtr(match)) |last| {
last.*.next = block;
block.prev = last.*;
@@ -580,7 +589,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
.code = try self.allocator.dupe(u8, code),
.relocs = std.ArrayList(Relocation).init(self.allocator),
.rebases = std.ArrayList(u64).init(self.allocator),
- .tlv_offsets = std.ArrayList(u64).init(self.allocator),
+ .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
.size = sect.size,
.alignment = sect.@"align",
};
@@ -589,6 +598,14 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
try self.parseRelocs(zld, relocs, block, 0);
}
+ // Update target section's metadata
+ // TODO should we update segment's size here too?
+ // How does it tie with incremental space allocs?
+ const tseg = &zld.load_commands.items[match.seg].Segment;
+ const tsect = &tseg.sections.items[match.sect];
+ tsect.size += block.size;
+ tsect.@"align" = math.max(tsect.@"align", block.alignment);
+
if (zld.blocks.getPtr(match)) |last| {
last.*.next = block;
block.prev = last.*;
src/link/MachO/reloc.zig
@@ -674,10 +674,11 @@ pub const Parser = struct {
}
// TLV is handled via a separate offset mechanism.
- // Save the offset to the initializer.
- // TODO I believe this can be simplified a lot!
if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) {
- try self.block.tlv_offsets.append(out_rel.offset);
+ try self.block.tlv_offsets.append(.{
+ .local_sym_index = out_rel.target.payload.regular.local_sym_index,
+ .offset = out_rel.offset,
+ });
}
},
}
src/link/MachO/Symbol.zig
@@ -10,6 +10,7 @@ const Allocator = mem.Allocator;
const Dylib = @import("Dylib.zig");
const Object = @import("Object.zig");
const StringTable = @import("StringTable.zig");
+const Zld = @import("Zld.zig");
/// Symbol name. Owned slice.
name: []const u8,
@@ -80,6 +81,20 @@ pub const Regular = struct {
}
try std.fmt.format(writer, "}}", .{});
}
+
+ pub fn sectionId(self: Regular, zld: *Zld) u8 {
+ // TODO there might be a more generic way of doing this.
+ var section: u8 = 0;
+ for (zld.load_commands.items) |cmd, cmd_id| {
+ if (cmd != .Segment) break;
+ if (cmd_id == self.segment_id) {
+ section += @intCast(u8, self.section_id) + 1;
+ break;
+ }
+ section += @intCast(u8, cmd.Segment.sections.items.len);
+ }
+ return section;
+ }
};
pub const Tentative = struct {
src/link/MachO/Zld.zig
@@ -129,10 +129,15 @@ pub const TextBlock = struct {
size: u64,
alignment: u32,
rebases: std.ArrayList(u64),
- tlv_offsets: std.ArrayList(u64),
+ tlv_offsets: std.ArrayList(TlvOffset),
next: ?*TextBlock = null,
prev: ?*TextBlock = null,
+ pub const TlvOffset = struct {
+ local_sym_index: u32,
+ offset: u64,
+ };
+
pub fn deinit(block: *TextBlock, allocator: *Allocator) void {
if (block.aliases) |aliases| {
allocator.free(aliases);
@@ -281,10 +286,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
try self.addRpaths(args.rpaths);
try self.addDataInCodeLC();
try self.addCodeSignatureLC();
- // try self.allocateTextSegment();
- // try self.allocateDataConstSegment();
- // try self.allocateDataSegment();
- // self.allocateLinkeditSegment();
+ try self.allocateTextSegment();
+ try self.allocateDataConstSegment();
+ try self.allocateDataSegment();
+ self.allocateLinkeditSegment();
+ try self.allocateTextBlocks();
var it = self.blocks.iterator();
while (it.next()) |entry| {
@@ -292,6 +298,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
const sect = seg.sections.items[entry.key_ptr.sect];
log.warn("\n\n{s},{s} contents:", .{ segmentName(sect), sectionName(sect) });
+ log.warn("{}", .{sect});
entry.value_ptr.*.print(self);
}
return error.TODO;
@@ -865,14 +872,14 @@ fn sortSections(self: *Zld) !void {
while (it.next()) |entry| {
const old = entry.key_ptr.*;
const sect = if (old.seg == self.text_segment_cmd_index.?)
- text_index_mapping.get(old.sect)
+ text_index_mapping.get(old.sect).?
else if (old.seg == self.data_const_segment_cmd_index.?)
- data_const_index_mapping.get(old.sect)
+ data_const_index_mapping.get(old.sect).?
else
- data_index_mapping.get(old.sect);
+ data_index_mapping.get(old.sect).?;
transient.putAssumeCapacityNoClobber(.{
.seg = old.seg,
- .sect = old.sect,
+ .sect = sect,
}, entry.value_ptr.*);
}
@@ -880,6 +887,18 @@ fn sortSections(self: *Zld) !void {
self.blocks.deinit(self.allocator);
self.blocks = transient;
}
+
+ for (self.locals.items) |sym, i| {
+ if (i == 0) continue; // skip the null symbol
+ assert(sym.payload == .regular);
+ const reg = &sym.payload.regular;
+ reg.section_id = if (reg.segment_id == self.text_segment_cmd_index.?)
+ text_index_mapping.get(reg.section_id).?
+ else if (reg.segment_id == self.data_const_segment_cmd_index.?)
+ data_const_index_mapping.get(reg.section_id).?
+ else
+ data_index_mapping.get(reg.section_id).?;
+ }
}
fn allocateTextSegment(self: *Zld) !void {
@@ -991,50 +1010,26 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
seg.inner.vmsize = seg_size_aligned;
}
-fn allocateSymbol(self: *Zld, symbol: *Symbol) !void {
- const reg = &symbol.payload.regular;
- const object = reg.file orelse return;
- const source_sect = &object.sections.items[reg.section];
- const target_map = source_sect.target_map orelse {
- log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{
- segmentName(source_sect.inner),
- sectionName(source_sect.inner),
- symbol.name,
- });
- return;
- };
-
- const target_seg = self.load_commands.items[target_map.segment_id].Segment;
- const target_sect = target_seg.sections.items[target_map.section_id];
- const target_addr = target_sect.addr + target_map.offset;
- const address = reg.address - source_sect.inner.addr + target_addr;
-
- log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address });
-
- // TODO there might be a more generic way of doing this.
- var section: u8 = 0;
- for (self.load_commands.items) |cmd, cmd_id| {
- if (cmd != .Segment) break;
- if (cmd_id == target_map.segment_id) {
- section += @intCast(u8, target_map.section_id) + 1;
- break;
+fn allocateTextBlocks(self: *Zld) !void {
+ var it = self.blocks.iterator();
+ while (it.next()) |entry| {
+ const match = entry.key_ptr.*;
+ var block: *TextBlock = entry.value_ptr.*;
+
+ const seg = self.load_commands.items[match.seg].Segment;
+ const sect = seg.sections.items[match.sect];
+ var base_addr: u64 = sect.addr + sect.size;
+
+ while (true) {
+ const sym = self.locals.items[block.local_sym_index];
+ assert(sym.payload == .regular);
+ sym.payload.regular.address = base_addr - block.size;
+ base_addr -= block.size;
+
+ if (block.prev) |prev| {
+ block = prev;
+ } else break;
}
- section += @intCast(u8, cmd.Segment.sections.items.len);
- }
-
- reg.address = address;
- reg.section = section;
-}
-
-fn allocateSymbols(self: *Zld) !void {
- for (self.locals.items) |symbol| {
- if (symbol.payload != .regular) continue;
- try self.allocateSymbol(symbol);
- }
-
- for (self.globals.values()) |symbol| {
- if (symbol.payload != .regular) continue;
- try self.allocateSymbol(symbol);
}
}
@@ -1487,7 +1482,7 @@ fn resolveSymbols(self: *Zld) !void {
.code = code,
.relocs = std.ArrayList(Relocation).init(self.allocator),
.rebases = std.ArrayList(u64).init(self.allocator),
- .tlv_offsets = std.ArrayList(u64).init(self.allocator),
+ .tlv_offsets = std.ArrayList(TextBlock.TlvOffset).init(self.allocator),
.size = size,
.alignment = alignment,
};