zld: moving target seg,sect mapping into Object.Section

This commit is contained in:
Jakub Konka 2021-06-10 08:30:25 +02:00
parent 88aec4a1ee
commit 96bb81b6ef
2 changed files with 94 additions and 118 deletions

View File

@ -54,6 +54,11 @@ pub const Section = struct {
inner: macho.section_64,
code: []u8,
relocs: ?[]*Relocation,
target_map: ?struct {
segment_id: u16,
section_id: u16,
offset: u32,
} = null,
pub fn deinit(self: *Section, allocator: *Allocator) void {
allocator.free(self.code);

View File

@ -95,9 +95,6 @@ got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
stub_helper_stubs_start_off: ?u64 = null,
mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
const TlvOffset = struct {
source_addr: u64,
offset: u64,
@ -107,18 +104,6 @@ const TlvOffset = struct {
}
};
const MappingKey = struct {
object_id: u16,
source_sect_id: u16,
};
pub const SectionMapping = struct {
source_sect_id: u16,
target_seg_id: u16,
target_sect_id: u16,
offset: u32,
};
/// Default path to dyld
const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
@ -159,9 +144,6 @@ pub fn deinit(self: *Zld) void {
}
self.dylibs.deinit(self.allocator);
self.mappings.deinit(self.allocator);
self.unhandled_sections.deinit(self.allocator);
self.globals.deinit(self.allocator);
self.imports.deinit(self.allocator);
self.unresolved.deinit(self.allocator);
@ -407,46 +389,39 @@ fn parseLibs(self: *Zld, libs: []const []const u8) !void {
fn mapAndUpdateSections(
self: *Zld,
object_id: u16,
object: *Object,
source_sect_id: u16,
target_seg_id: u16,
target_sect_id: u16,
) !void {
const object = self.objects.items[object_id];
const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
const source_sect = source_seg.sections.items[source_sect_id];
const source_sect = &object.sections.items[source_sect_id];
const target_seg = &self.load_commands.items[target_seg_id].Segment;
const target_sect = &target_seg.sections.items[target_sect_id];
const alignment = try math.powi(u32, 2, target_sect.@"align");
const offset = mem.alignForwardGeneric(u64, target_sect.size, alignment);
const size = mem.alignForwardGeneric(u64, source_sect.size, alignment);
const key = MappingKey{
.object_id = object_id,
.source_sect_id = source_sect_id,
};
try self.mappings.putNoClobber(self.allocator, key, .{
.source_sect_id = source_sect_id,
.target_seg_id = target_seg_id,
.target_sect_id = target_sect_id,
.offset = @intCast(u32, offset),
});
log.debug("{s}: {s},{s} mapped to {s},{s} from 0x{x} to 0x{x}", .{
object.name,
parseName(&source_sect.segname),
parseName(&source_sect.sectname),
const size = mem.alignForwardGeneric(u64, source_sect.inner.size, alignment);
log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
object.name.?,
parseName(&source_sect.inner.segname),
parseName(&source_sect.inner.sectname),
parseName(&target_sect.segname),
parseName(&target_sect.sectname),
offset,
offset + size,
});
source_sect.target_map = .{
.segment_id = target_seg_id,
.section_id = target_sect_id,
.offset = @intCast(u32, offset),
};
target_sect.size = offset + size;
}
fn updateMetadata(self: *Zld) !void {
for (self.objects.items) |object, id| {
const object_id = @intCast(u16, id);
for (self.objects.items) |object| {
const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
@ -699,19 +674,14 @@ fn updateMetadata(self: *Zld) !void {
for (object_seg.sections.items) |source_sect, sect_id| {
const source_sect_id = @intCast(u16, sect_id);
if (self.getMatchingSection(source_sect)) |res| {
try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect);
try self.mapAndUpdateSections(object, source_sect_id, res.seg, res.sect);
continue;
}
const segname = parseName(&source_sect.segname);
const sectname = parseName(&source_sect.sectname);
log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });
try self.unhandled_sections.putNoClobber(self.allocator, .{
.object_id = object_id,
.source_sect_id = source_sect_id,
}, 0);
log.debug("section '{s},{s}' will be unmapped", .{
parseName(&source_sect.segname),
parseName(&source_sect.sectname),
});
}
}
@ -954,18 +924,34 @@ fn sortSections(self: *Zld) !void {
}
}
var it = self.mappings.valueIterator();
while (it.next()) |mapping| {
if (self.text_segment_cmd_index.? == mapping.target_seg_id) {
const new_index = text_index_mapping.get(mapping.target_sect_id) orelse unreachable;
mapping.target_sect_id = new_index;
} else if (self.data_const_segment_cmd_index.? == mapping.target_seg_id) {
const new_index = data_const_index_mapping.get(mapping.target_sect_id) orelse unreachable;
mapping.target_sect_id = new_index;
} else if (self.data_segment_cmd_index.? == mapping.target_seg_id) {
const new_index = data_index_mapping.get(mapping.target_sect_id) orelse unreachable;
mapping.target_sect_id = new_index;
} else unreachable;
for (self.objects.items) |object| {
for (object.sections.items) |*sect| {
const target_map = sect.target_map orelse continue;
const new_index = blk: {
if (self.text_segment_cmd_index.? == target_map.segment_id) {
break :blk text_index_mapping.get(target_map.section_id) orelse unreachable;
} else if (self.data_const_segment_cmd_index.? == target_map.segment_id) {
break :blk data_const_index_mapping.get(target_map.section_id) orelse unreachable;
} else if (self.data_segment_cmd_index.? == target_map.segment_id) {
break :blk data_index_mapping.get(target_map.section_id) orelse unreachable;
} else unreachable;
};
log.debug("remapping in {s}: '{s},{s}': {} => {}", .{
object.name.?,
parseName(&sect.inner.segname),
parseName(&sect.inner.sectname),
target_map.section_id,
new_index,
});
sect.target_map = .{
.segment_id = target_map.segment_id,
.section_id = new_index,
.offset = target_map.offset,
};
}
}
}
@ -1080,30 +1066,24 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
}
fn allocateSymbols(self: *Zld) !void {
for (self.objects.items) |object, object_id| {
for (self.objects.items) |object| {
for (object.symbols.items) |sym| {
const reg = sym.cast(Symbol.Regular) orelse continue;
// TODO I am more and more convinced we should store the mapping as part of the Object struct.
const target_mapping = self.mappings.get(.{
.object_id = @intCast(u16, object_id),
.source_sect_id = reg.section,
}) orelse {
if (self.unhandled_sections.get(.{
.object_id = @intCast(u16, object_id),
.source_sect_id = reg.section,
}) != null) continue;
log.err("section not mapped for symbol '{s}'", .{sym.name});
return error.SectionNotMappedForSymbol;
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}'", .{
parseName(&source_sect.inner.segname),
parseName(&source_sect.inner.sectname),
sym.name,
});
continue;
};
const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
const source_sect = source_seg.sections.items[reg.section];
const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
const target_addr = target_sect.addr + target_mapping.offset;
const address = reg.address - source_sect.addr + target_addr;
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}", .{ sym.name, address });
@ -1111,8 +1091,8 @@ fn allocateSymbols(self: *Zld) !void {
var section: u8 = 0;
for (self.load_commands.items) |cmd, cmd_id| {
if (cmd != .Segment) break;
if (cmd_id == target_mapping.target_seg_id) {
section += @intCast(u8, target_mapping.target_sect_id) + 1;
if (cmd_id == target_map.segment_id) {
section += @intCast(u8, target_map.section_id) + 1;
break;
}
section += @intCast(u8, cmd.Segment.sections.items.len);
@ -1602,10 +1582,10 @@ fn resolveStubsAndGotEntries(self: *Zld) !void {
}
fn resolveRelocsAndWriteSections(self: *Zld) !void {
for (self.objects.items) |object, object_id| {
for (self.objects.items) |object| {
log.debug("relocating object {s}", .{object.name});
for (object.sections.items) |sect, source_sect_id| {
for (object.sections.items) |sect| {
if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or
sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue;
@ -1614,18 +1594,15 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
log.debug("relocating section '{s},{s}'", .{ segname, sectname });
// Get mapping
const target_mapping = self.mappings.get(.{
.object_id = @intCast(u16, object_id),
.source_sect_id = @intCast(u16, source_sect_id),
}) orelse {
log.debug("no mapping for {s},{s}; skipping", .{ segname, sectname });
// Get target mapping
const target_map = sect.target_map orelse {
log.debug("no mapping for '{s},{s}'; skipping", .{ segname, sectname });
continue;
};
const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
const target_sect_addr = target_sect.addr + target_mapping.offset;
const target_sect_off = target_sect.offset + target_mapping.offset;
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_sect_addr = target_sect.addr + target_map.offset;
const target_sect_off = target_sect.offset + target_map.offset;
if (sect.relocs) |relocs| {
for (relocs) |rel| {
@ -1638,11 +1615,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
switch (rel.@"type") {
.unsigned => {
args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
args.target_addr = try self.relocTargetAddr(object, rel.target);
const unsigned = rel.cast(reloc.Unsigned) orelse unreachable;
if (unsigned.subtractor) |subtractor| {
args.subtractor = try self.relocTargetAddr(@intCast(u16, object_id), subtractor);
args.subtractor = try self.relocTargetAddr(object, subtractor);
}
if (rel.target == .section) {
const source_sect = object.sections.items[rel.target.section];
@ -1652,14 +1629,14 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
rebases: {
var hit: bool = false;
if (target_mapping.target_seg_id == self.data_segment_cmd_index.?) {
if (target_map.segment_id == self.data_segment_cmd_index.?) {
if (self.data_section_index) |index| {
if (index == target_mapping.target_sect_id) hit = true;
if (index == target_map.section_id) hit = true;
}
}
if (target_mapping.target_seg_id == self.data_const_segment_cmd_index.?) {
if (target_map.segment_id == self.data_const_segment_cmd_index.?) {
if (self.data_const_section_index) |index| {
if (index == target_mapping.target_sect_id) hit = true;
if (index == target_map.section_id) hit = true;
}
}
@ -1667,7 +1644,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
try self.local_rebases.append(self.allocator, .{
.offset = source_addr - target_seg.inner.vmaddr,
.segment_id = target_mapping.target_seg_id,
.segment_id = target_map.segment_id,
});
}
// TLV is handled via a separate offset mechanism.
@ -1705,7 +1682,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
args.source_source_sect_addr = sect.inner.addr;
args.source_target_sect_addr = source_sect.inner.addr;
}
args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
args.target_addr = try self.relocTargetAddr(object, rel.target);
},
}
@ -1744,7 +1721,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
}
}
fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target) !u64 {
fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.Target) !u64 {
const target_addr = blk: {
switch (target) {
.symbol => |sym| {
@ -1770,13 +1747,11 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: reloc.Relocation.Target)
}
},
.section => |sect_id| {
const target_mapping = self.mappings.get(.{
.object_id = object_id,
.source_sect_id = sect_id,
}) orelse unreachable;
const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
break :blk target_sect.addr + target_mapping.offset;
const source_sect = object.sections.items[sect_id];
const target_map = source_sect.target_map orelse unreachable;
const target_seg = self.load_commands.items[target_map.segment_id].Segment;
const target_sect = target_seg.sections.items[target_map.section_id];
break :blk target_sect.addr + target_map.offset;
},
}
};
@ -2901,20 +2876,16 @@ fn writeDataInCode(self: *Zld) !void {
const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
const text_sect = text_seg.sections.items[self.text_section_index.?];
for (self.objects.items) |object, object_id| {
const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
const source_sect = source_seg.sections.items[object.text_section_index.?];
const target_mapping = self.mappings.get(.{
.object_id = @intCast(u16, object_id),
.source_sect_id = object.text_section_index.?,
}) orelse continue;
for (self.objects.items) |object| {
const source_sect = object.sections.items[object.text_section_index.?];
const target_map = source_sect.target_map orelse continue;
try buf.ensureCapacity(
buf.items.len + object.data_in_code_entries.items.len * @sizeOf(macho.data_in_code_entry),
);
for (object.data_in_code_entries.items) |dice| {
const new_dice: macho.data_in_code_entry = .{
.offset = text_sect.offset + target_mapping.offset + dice.offset,
.offset = text_sect.offset + target_map.offset + dice.offset,
.length = dice.length,
.kind = dice.kind,
};