Commit 1efdb137d1
Changed files (3)
src
link
src/link/MachO/Object.zig
@@ -317,6 +317,7 @@ const Context = struct {
object: *Object,
macho_file: *MachO,
match: MachO.MatchingSection,
+ parsed_atoms: *ParsedAtoms,
};
const TextBlockParser = struct {
@@ -430,6 +431,7 @@ const TextBlockParser = struct {
.allocator = context.allocator,
.object = context.object,
.macho_file = context.macho_file,
+ .parsed_atoms = context.parsed_atoms,
});
if (context.macho_file.has_dices) {
@@ -455,12 +457,15 @@ const TextBlockParser = struct {
}
};
+pub const ParsedAtoms = std.AutoHashMap(MachO.MatchingSection, *TextBlock);
+
pub fn parseTextBlocks(
self: *Object,
allocator: *Allocator,
object_id: u16,
macho_file: *MachO,
-) !void {
+) !ParsedAtoms {
+ var parsed_atoms = ParsedAtoms.init(allocator);
const seg = self.load_commands.items[self.segment_cmd_index.?].Segment;
log.debug("analysing {s}", .{self.name});
@@ -589,6 +594,7 @@ pub fn parseTextBlocks(
.allocator = allocator,
.object = self,
.macho_file = macho_file,
+ .parsed_atoms = &parsed_atoms,
});
if (macho_file.has_dices) {
@@ -604,7 +610,13 @@ pub fn parseTextBlocks(
}
}
- _ = try macho_file.allocateAtom(block, match);
+ if (parsed_atoms.getPtr(match)) |last| {
+ last.*.next = block;
+ block.prev = last.*;
+ last.* = block;
+ } else {
+ try parsed_atoms.putNoClobber(match, block);
+ }
try self.text_blocks.append(allocator, block);
}
@@ -620,6 +632,7 @@ pub fn parseTextBlocks(
.object = self,
.macho_file = macho_file,
.match = match,
+ .parsed_atoms = &parsed_atoms,
})) |block| {
const sym = macho_file.locals.items[block.local_sym_index];
const is_ext = blk: {
@@ -651,7 +664,13 @@ pub fn parseTextBlocks(
}
}
- _ = try macho_file.allocateAtom(block, match);
+ if (parsed_atoms.getPtr(match)) |last| {
+ last.*.next = block;
+ block.prev = last.*;
+ last.* = block;
+ } else {
+ try parsed_atoms.putNoClobber(match, block);
+ }
try self.text_blocks.append(allocator, block);
}
@@ -696,6 +715,7 @@ pub fn parseTextBlocks(
.allocator = allocator,
.object = self,
.macho_file = macho_file,
+ .parsed_atoms = &parsed_atoms,
});
if (macho_file.has_dices) {
@@ -747,10 +767,18 @@ pub fn parseTextBlocks(
});
}
- _ = try macho_file.allocateAtom(block, match);
+ if (parsed_atoms.getPtr(match)) |last| {
+ last.*.next = block;
+ block.prev = last.*;
+ last.* = block;
+ } else {
+ try parsed_atoms.putNoClobber(match, block);
+ }
try self.text_blocks.append(allocator, block);
}
}
+
+ return parsed_atoms;
}
fn parseSymtab(self: *Object, allocator: *Allocator) !void {
src/link/MachO/TextBlock.zig
@@ -628,6 +628,7 @@ const RelocContext = struct {
allocator: *Allocator,
object: *Object,
macho_file: *MachO,
+ parsed_atoms: *Object.ParsedAtoms,
};
fn initRelocFromObject(rel: macho.relocation_info, context: RelocContext) !Relocation {
@@ -855,7 +856,14 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
.seg = context.macho_file.data_const_segment_cmd_index.?,
.sect = context.macho_file.got_section_index.?,
};
- _ = try context.macho_file.allocateAtom(atom, match);
+
+ if (context.parsed_atoms.getPtr(match)) |last| {
+ last.*.next = atom;
+ atom.prev = last.*;
+ last.* = atom;
+ } else {
+ try context.parsed_atoms.putNoClobber(match, atom);
+ }
} else if (parsed_rel.payload == .unsigned) {
switch (parsed_rel.where) {
.undef => {
@@ -918,18 +926,46 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
);
const stub_atom = try context.macho_file.createStubAtom(laptr_atom.local_sym_index);
try context.macho_file.stubs_map.putNoClobber(context.allocator, parsed_rel.where_index, stub_atom);
- _ = try context.macho_file.allocateAtom(stub_helper_atom, .{
+ // TODO clean this up!
+ if (context.parsed_atoms.getPtr(.{
.seg = context.macho_file.text_segment_cmd_index.?,
.sect = context.macho_file.stub_helper_section_index.?,
- });
- _ = try context.macho_file.allocateAtom(laptr_atom, .{
- .seg = context.macho_file.data_segment_cmd_index.?,
- .sect = context.macho_file.la_symbol_ptr_section_index.?,
- });
- _ = try context.macho_file.allocateAtom(stub_atom, .{
+ })) |last| {
+ last.*.next = stub_helper_atom;
+ stub_helper_atom.prev = last.*;
+ last.* = stub_helper_atom;
+ } else {
+ try context.parsed_atoms.putNoClobber(.{
+ .seg = context.macho_file.text_segment_cmd_index.?,
+ .sect = context.macho_file.stub_helper_section_index.?,
+ }, stub_helper_atom);
+ }
+ if (context.parsed_atoms.getPtr(.{
.seg = context.macho_file.text_segment_cmd_index.?,
.sect = context.macho_file.stubs_section_index.?,
- });
+ })) |last| {
+ last.*.next = stub_atom;
+ stub_atom.prev = last.*;
+ last.* = stub_atom;
+ } else {
+ try context.parsed_atoms.putNoClobber(.{
+ .seg = context.macho_file.text_segment_cmd_index.?,
+ .sect = context.macho_file.stubs_section_index.?,
+ }, stub_atom);
+ }
+ if (context.parsed_atoms.getPtr(.{
+ .seg = context.macho_file.data_segment_cmd_index.?,
+ .sect = context.macho_file.la_symbol_ptr_section_index.?,
+ })) |last| {
+ last.*.next = laptr_atom;
+ laptr_atom.prev = last.*;
+ last.* = laptr_atom;
+ } else {
+ try context.parsed_atoms.putNoClobber(.{
+ .seg = context.macho_file.data_segment_cmd_index.?,
+ .sect = context.macho_file.la_symbol_ptr_section_index.?,
+ }, laptr_atom);
+ }
}
}
}
src/link/MachO.zig
@@ -2594,30 +2594,64 @@ fn resolveDyldStubBinder(self: *MachO) !void {
}
fn parseTextBlocks(self: *MachO) !void {
+ var parsed_atoms = Object.ParsedAtoms.init(self.base.allocator);
+ defer parsed_atoms.deinit();
+
+ var first_atoms = Object.ParsedAtoms.init(self.base.allocator);
+ defer first_atoms.deinit();
+
var section_metadata = std.AutoHashMap(MatchingSection, struct {
size: u64,
alignment: u32,
}).init(self.base.allocator);
defer section_metadata.deinit();
- for (self.objects.items) |object| {
- const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
- for (seg.sections.items) |sect| {
- const match = (try self.getMatchingSection(sect)) orelse {
- log.debug("unhandled section", .{});
- continue;
- };
- const res = try section_metadata.getOrPut(match);
- if (!res.found_existing) {
- res.value_ptr.* = .{
+ for (self.objects.items) |*object, object_id| {
+ var atoms_in_objects = try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);
+ defer atoms_in_objects.deinit();
+
+ var it = atoms_in_objects.iterator();
+ while (it.next()) |entry| {
+ const match = entry.key_ptr.*;
+ const last_atom = entry.value_ptr.*;
+ var atom = last_atom;
+
+ const metadata = try section_metadata.getOrPut(match);
+ if (!metadata.found_existing) {
+ metadata.value_ptr.* = .{
.size = 0,
.alignment = 0,
};
}
- const size = padToIdeal(sect.size);
- const alignment = try math.powi(u32, 2, sect.@"align");
- res.value_ptr.size += mem.alignForwardGeneric(u64, size, alignment);
- res.value_ptr.alignment = math.max(res.value_ptr.alignment, sect.@"align");
+
+ while (true) {
+ const alignment = try math.powi(u32, 2, atom.alignment);
+ metadata.value_ptr.size += mem.alignForwardGeneric(u64, atom.size, alignment);
+ metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);
+
+ const sym = self.locals.items[atom.local_sym_index];
+ log.debug(" {s}: n_value=0x{x}, size=0x{x}, alignment=0x{x}", .{
+ self.getString(sym.n_strx),
+ sym.n_value,
+ atom.size,
+ atom.alignment,
+ });
+
+ if (atom.prev) |prev| {
+ atom = prev;
+ } else break;
+ }
+
+ if (parsed_atoms.getPtr(match)) |last| {
+ last.*.next = atom;
+ atom.prev = last.*;
+ last.* = atom;
+ }
+ _ = try parsed_atoms.put(match, last_atom);
+
+ if (!first_atoms.contains(match)) {
+ try first_atoms.putNoClobber(match, atom);
+ }
}
}
@@ -2625,63 +2659,69 @@ fn parseTextBlocks(self: *MachO) !void {
while (it.next()) |entry| {
const match = entry.key_ptr.*;
const metadata = entry.value_ptr.*;
- const seg = self.load_commands.items[match.seg].Segment;
- const sect = seg.sections.items[match.sect];
+ const seg = &self.load_commands.items[match.seg].Segment;
+ const sect = &seg.sections.items[match.sect];
log.debug("{s},{s} => size: 0x{x}, alignment: 0x{x}", .{
- commands.segmentName(sect),
- commands.sectionName(sect),
+ commands.segmentName(sect.*),
+ commands.sectionName(sect.*),
metadata.size,
metadata.alignment,
});
+ sect.@"align" = math.max(sect.@"align", metadata.alignment);
try self.growSection(match, @intCast(u32, metadata.size));
- }
- for (self.objects.items) |*object, object_id| {
- try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);
- }
-
- // it = section_metadata.iterator();
- // while (it.next()) |entry| {
- // const match = entry.key_ptr.*;
- // const metadata = entry.value_ptr.*;
- // const seg = self.load_commands.items[match.seg].Segment;
- // const sect = seg.sections.items[match.sect];
-
- // var buffer = try self.base.allocator.alloc(u8, metadata.size);
- // defer self.base.allocator.free(buffer);
- // log.warn("{s},{s} buffer size 0x{x}", .{
- // commands.segmentName(sect),
- // commands.sectionName(sect),
- // metadata.size,
- // });
-
- // var atom = self.blocks.get(match).?;
-
- // while (atom.prev) |prev| {
- // atom = prev;
- // }
-
- // const base = blk: {
- // const sym = self.locals.items[atom.local_sym_index];
- // break :blk sym.n_value;
- // };
-
- // while (true) {
- // const sym = self.locals.items[atom.local_sym_index];
- // const offset = sym.n_value - base;
- // try atom.resolveRelocs(self);
- // log.warn("writing atom for symbol {s} at buffer offset 0x{x}", .{
- // self.getString(sym.n_strx),
- // offset,
- // });
- // mem.copy(u8, buffer[offset..][0..atom.code.items.len], atom.code.items);
- // atom.dirty = false;
-
- // if (atom.next) |next| {
- // atom = next;
- // } else break;
- // }
- // }
+ var base_vaddr = if (self.blocks.get(match)) |last| blk: {
+ const last_atom_sym = self.locals.items[last.local_sym_index];
+ break :blk last_atom_sym.n_value + last.size;
+ } else sect.addr;
+ const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
+
+ var atom = first_atoms.get(match).?;
+ while (true) {
+ const alignment = try math.powi(u32, 2, atom.alignment);
+ base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
+
+ const sym = &self.locals.items[atom.local_sym_index];
+ sym.n_value = base_vaddr;
+ sym.n_sect = n_sect;
+
+ log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{
+ self.getString(sym.n_strx),
+ base_vaddr,
+ base_vaddr + atom.size,
+ atom.size,
+ atom.alignment,
+ });
+
+ // Update each alias (if any)
+ for (atom.aliases.items) |index| {
+ const alias_sym = &self.locals.items[index];
+ alias_sym.n_value = base_vaddr;
+ alias_sym.n_sect = n_sect;
+ }
+
+ // Update each symbol contained within the TextBlock
+ for (atom.contained.items) |sym_at_off| {
+ const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
+ contained_sym.n_value = base_vaddr + sym_at_off.offset;
+ contained_sym.n_sect = n_sect;
+ }
+
+ base_vaddr += atom.size;
+
+ if (atom.next) |next| {
+ atom = next;
+ } else break;
+ }
+
+ if (self.blocks.getPtr(match)) |last| {
+ const first_atom = first_atoms.get(match).?;
+ last.*.next = first_atom;
+ first_atom.prev = last.*;
+ last.* = first_atom;
+ }
+ _ = try self.blocks.put(self.base.allocator, match, parsed_atoms.get(match).?);
+ }
}
fn addDataInCodeLC(self: *MachO) !void {