zld: save rebase and TLV offset as part of TextBlock

instead of as part of the Symbol. This seems to be more
optimal way of handling dyld ops in presence of no splittable
input sections in object files.
This commit is contained in:
Jakub Konka 2021-07-07 22:15:41 +02:00
parent 7c662db8d9
commit e524f43a6f
4 changed files with 36 additions and 40 deletions

View File

@ -435,6 +435,8 @@ const TextBlockParser = struct {
.references = std.AutoArrayHashMap(u32, void).init(self.allocator),
.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),
.size = size,
.alignment = self.section.@"align",
};
@ -444,18 +446,6 @@ const TextBlockParser = struct {
try self.object.parseRelocs(self.zld, relocs, block, start_addr);
}
const is_zerofill = blk: {
const tseg = self.zld.load_commands.items[self.match.seg].Segment;
const tsect = tseg.sections.items[self.match.sect];
const tsect_type = sectionType(tsect);
break :blk tsect_type == macho.S_ZEROFILL or
tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
};
if (is_zerofill) {
mem.set(u8, block.code, 0);
}
self.index += 1;
return block;
@ -589,6 +579,8 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
.references = std.AutoArrayHashMap(u32, void).init(self.allocator),
.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),
.size = sect.size,
.alignment = sect.@"align",
};
@ -597,18 +589,6 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
try self.parseRelocs(zld, relocs, block, 0);
}
const is_zerofill = blk: {
const tseg = zld.load_commands.items[match.seg].Segment;
const tsect = tseg.sections.items[match.sect];
const tsect_type = sectionType(tsect);
break :blk tsect_type == macho.S_ZEROFILL or
tsect_type == macho.S_THREAD_LOCAL_ZEROFILL or
tsect_type == macho.S_THREAD_LOCAL_VARIABLES;
};
if (is_zerofill) {
mem.set(u8, block.code, 0);
}
if (zld.blocks.getPtr(match)) |last| {
last.*.next = block;
block.prev = last.*;

View File

@ -58,8 +58,6 @@ pub const Regular = struct {
local_sym_index: u32 = 0,
should_rebase: bool = false,
pub const Linkage = enum {
translation_unit,
linkage_unit,
@ -77,9 +75,6 @@ pub const Regular = struct {
if (self.weak_ref) {
try std.fmt.format(writer, ".weak_ref, ", .{});
}
if (self.should_rebase) {
try std.fmt.format(writer, ".should_rebase, ", .{});
}
if (self.file) |file| {
try std.fmt.format(writer, ".file = {s}, ", .{file.name.?});
}

View File

@ -128,6 +128,8 @@ pub const TextBlock = struct {
relocs: std.ArrayList(Relocation),
size: u64,
alignment: u32,
rebases: std.ArrayList(u64),
tlv_offsets: std.ArrayList(u64),
next: ?*TextBlock = null,
prev: ?*TextBlock = null,
@ -137,6 +139,8 @@ pub const TextBlock = struct {
}
block.relocs.deinit();
block.references.deinit();
block.rebases.deinit();
block.tlv_offsets.deinit();
allocator.free(block.code);
}
@ -144,24 +148,30 @@ pub const TextBlock = struct {
log.warn("TextBlock", .{});
log.warn(" | {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] });
if (self.aliases) |aliases| {
log.warn(" | Aliases:", .{});
log.warn(" | aliases:", .{});
for (aliases) |index| {
log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
}
}
if (self.references.count() > 0) {
log.warn(" | References:", .{});
log.warn(" | references:", .{});
for (self.references.keys()) |index| {
log.warn(" | {}: {}", .{ index, zld.locals.items[index] });
}
}
log.warn(" | code.len = {}", .{self.code.len});
if (self.relocs.items.len > 0) {
log.warn("Relocations:", .{});
log.warn(" | relocations:", .{});
for (self.relocs.items) |rel| {
log.warn(" | {}", .{rel});
log.warn(" | {}", .{rel});
}
}
if (self.rebases.items.len > 0) {
log.warn(" | rebases: {any}", .{self.rebases.items});
}
if (self.tlv_offsets.items.len > 0) {
log.warn(" | TLV offsets: {any}", .{self.tlv_offsets.items});
}
log.warn(" | size = {}", .{self.size});
log.warn(" | align = {}", .{self.alignment});
}
@ -271,6 +281,10 @@ 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();
var it = self.blocks.iterator();
while (it.next()) |entry| {
@ -281,11 +295,6 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
entry.value_ptr.*.print(self);
}
return error.TODO;
// try self.allocateTextSegment();
// try self.allocateDataConstSegment();
// try self.allocateDataSegment();
// self.allocateLinkeditSegment();
// try self.allocateSymbols();
// try self.flush();
}
@ -1477,6 +1486,8 @@ fn resolveSymbols(self: *Zld) !void {
.references = std.AutoArrayHashMap(u32, void).init(self.allocator),
.code = code,
.relocs = std.ArrayList(Relocation).init(self.allocator),
.rebases = std.ArrayList(u64).init(self.allocator),
.tlv_offsets = std.ArrayList(u64).init(self.allocator),
.size = size,
.alignment = alignment,
};

View File

@ -405,7 +405,7 @@ pub const Relocation = struct {
pub fn resolve(self: Relocation, zld: *Zld) !void {
const source_addr = blk: {
const sym = zld.locals.items[self.block.local_sym_index];
break :blk sym.payload.regular.address;
break :blk sym.payload.regular.address + self.offset;
};
const target_addr = blk: {
const is_via_got = inner: {
@ -668,7 +668,17 @@ pub const Parser = struct {
break :rebase true;
};
source_reg.should_rebase = should_rebase;
if (should_rebase) {
try self.block.rebases.append(out_rel.offset);
}
// 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);
}
},
}
} else if (out_rel.payload == .branch) blk: {