mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
zld: allocate TextBlocks
temporarily by iterating over all defined TextBlocks. However, once we merge this with MachO incremental, updates will be done at the point of creation and/or update. Also, fix mining TLV knowledge for working out TLV pointers.
This commit is contained in:
parent
e524f43a6f
commit
7aeedc0912
@ -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.*;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
};
|
||||
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 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;
|
||||
const seg = self.load_commands.items[match.seg].Segment;
|
||||
const sect = seg.sections.items[match.sect];
|
||||
var base_addr: u64 = sect.addr + sect.size;
|
||||
|
||||
log.debug("resolving symbol '{s}' at 0x{x}", .{ symbol.name, address });
|
||||
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;
|
||||
|
||||
// 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;
|
||||
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,
|
||||
};
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user