Commit a04bc1ed14
Changed files (3)
src
link
src/link/MachO/Object.zig
@@ -48,8 +48,6 @@ dwarf_debug_ranges_index: ?u16 = null,
symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
-
-initializers: std.ArrayListUnmanaged(u32) = .{},
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
symbols: std.ArrayListUnmanaged(*Symbol) = .{},
@@ -157,7 +155,6 @@ pub fn deinit(self: *Object) void {
}
self.load_commands.deinit(self.allocator);
self.data_in_code_entries.deinit(self.allocator);
- self.initializers.deinit(self.allocator);
self.symtab.deinit(self.allocator);
self.strtab.deinit(self.allocator);
self.symbols.deinit(self.allocator);
@@ -573,6 +570,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
symbol.payload = .{
.regular = .{
.linkage = .translation_unit,
+ .address = sect.addr,
.segment_id = match.seg,
.section_id = match.sect,
.file = self,
@@ -657,6 +655,13 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
});
defer self.allocator.free(name);
const symbol = try Symbol.new(self.allocator, name);
+ symbol.payload = .{
+ .regular = .{
+ .linkage = .translation_unit,
+ .address = sect.addr,
+ .file = self,
+ },
+ };
try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
break :symbol symbol;
};
@@ -666,22 +671,6 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
return symbol;
}
-pub fn parseInitializers(self: *Object) !void {
- const index = self.mod_init_func_section_index orelse return;
- const section = self.sections.items[index];
-
- log.debug("parsing initializers in {s}", .{self.name.?});
-
- // Parse C++ initializers
- const relocs = section.relocs orelse unreachable;
- try self.initializers.ensureCapacity(self.allocator, relocs.len);
- for (relocs) |rel| {
- self.initializers.appendAssumeCapacity(rel.target.symbol);
- }
-
- mem.reverse(u32, self.initializers.items);
-}
-
fn parseSymtab(self: *Object) !void {
const index = self.symtab_cmd_index orelse return;
const symtab_cmd = self.load_commands.items[index].Symtab;
src/link/MachO/reloc.zig
@@ -48,33 +48,24 @@ pub const Relocation = struct {
/// => * is unreachable
is_64bit: bool,
+ source_sect_addr: ?u64 = null,
+
pub fn resolve(self: Unsigned, base: Relocation, source_addr: u64, target_addr: u64) !void {
- // const addend = if (unsigned.base.target == .section)
- // unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
- // else
- // unsigned.addend;
-
- // const result = if (args.subtractor) |subtractor|
- // @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend
- // else
- // @intCast(i64, args.target_addr) + addend;
-
- // log.debug(" | calculated addend 0x{x}", .{addend});
- // log.debug(" | calculated unsigned value 0x{x}", .{result});
-
- // if (unsigned.is_64bit) {
- // mem.writeIntLittle(
- // u64,
- // unsigned.base.code[0..8],
- // @bitCast(u64, result),
- // );
- // } else {
- // mem.writeIntLittle(
- // u32,
- // unsigned.base.code[0..4],
- // @truncate(u32, @bitCast(u64, result)),
- // );
- // }
+ const addend = if (self.source_sect_addr) |addr|
+ self.addend - addr
+ else
+ self.addend;
+
+ const result = if (self.subtractor) |subtractor|
+ @intCast(i64, target_addr) - @intCast(i64, subtractor.payload.regular.address) + addend
+ else
+ @intCast(i64, target_addr) + addend;
+
+ if (self.is_64bit) {
+ mem.writeIntLittle(u64, base.block.code[base.offset..][0..8], @bitCast(u64, result));
+ } else {
+ mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], @truncate(u32, @bitCast(u64, result)));
+ }
}
pub fn format(self: Unsigned, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
@@ -191,56 +182,119 @@ pub const Relocation = struct {
pub fn resolve(self: PageOff, base: Relocation, source_addr: u64, target_addr: u64) !void {
switch (self.kind) {
.page => {
- // const target_addr = if (page_off.addend) |addend| args.target_addr + addend else args.target_addr;
- // const narrowed = @truncate(u12, target_addr);
-
- // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
- // log.debug(" | {s} opcode", .{page_off.op_kind});
-
- // var inst = page_off.inst;
- // if (page_off.op_kind == .arithmetic) {
- // inst.add_subtract_immediate.imm12 = narrowed;
- // } else {
- // const offset: u12 = blk: {
- // if (inst.load_store_register.size == 0) {
- // if (inst.load_store_register.v == 1) {
- // // 128-bit SIMD is scaled by 16.
- // break :blk try math.divExact(u12, narrowed, 16);
- // }
- // // Otherwise, 8-bit SIMD or ldrb.
- // break :blk narrowed;
- // } else {
- // const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
- // break :blk try math.divExact(u12, narrowed, denom);
- // }
- // };
- // inst.load_store_register.offset = offset;
- // }
-
- // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+ const actual_target_addr = if (self.addend) |addend| target_addr + addend else target_addr;
+ const narrowed = @truncate(u12, actual_target_addr);
+
+ const op_kind = self.op_kind orelse unreachable;
+ var inst: aarch64.Instruction = blk: {
+ switch (op_kind) {
+ .arithmetic => {
+ break :blk .{
+ .add_subtract_immediate = mem.bytesToValue(
+ meta.TagPayload(
+ aarch64.Instruction,
+ aarch64.Instruction.add_subtract_immediate,
+ ),
+ base.block.code[base.offset..][0..4],
+ ),
+ };
+ },
+ .load => {
+ break :blk .{
+ .load_store_register = mem.bytesToValue(
+ meta.TagPayload(
+ aarch64.Instruction,
+ aarch64.Instruction.load_store_register,
+ ),
+ base.block.code[base.offset..][0..4],
+ ),
+ };
+ },
+ }
+ };
+
+ if (op_kind == .arithmetic) {
+ inst.add_subtract_immediate.imm12 = narrowed;
+ } else {
+ const offset: u12 = blk: {
+ if (inst.load_store_register.size == 0) {
+ if (inst.load_store_register.v == 1) {
+ // 128-bit SIMD is scaled by 16.
+ break :blk try math.divExact(u12, narrowed, 16);
+ }
+ // Otherwise, 8-bit SIMD or ldrb.
+ break :blk narrowed;
+ } else {
+ const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size);
+ break :blk try math.divExact(u12, narrowed, denom);
+ }
+ };
+ inst.load_store_register.offset = offset;
+ }
+ mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
},
.got => {
- // const narrowed = @truncate(u12, args.target_addr);
-
- // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
-
- // var inst = page_off.inst;
- // const offset = try math.divExact(u12, narrowed, 8);
- // inst.load_store_register.offset = offset;
-
- // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+ const narrowed = @truncate(u12, target_addr);
+ var inst = mem.bytesToValue(
+ meta.TagPayload(
+ aarch64.Instruction,
+ aarch64.Instruction.load_store_register,
+ ),
+ base.block.code[base.offset..][0..4],
+ );
+ const offset = try math.divExact(u12, narrowed, 8);
+ inst.load_store_register.offset = offset;
+ mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
},
.tlvp => {
-
- // const narrowed = @truncate(u12, args.target_addr);
-
- // log.debug(" | narrowed address within the page 0x{x}", .{narrowed});
-
- // var inst = page_off.inst;
- // inst.add_subtract_immediate.imm12 = narrowed;
-
- // mem.writeIntLittle(u32, page_off.base.code[0..4], inst.toU32());
+ const RegInfo = struct {
+ rd: u5,
+ rn: u5,
+ size: u1,
+ };
+ const reg_info: RegInfo = blk: {
+ if (isArithmeticOp(base.block.code[base.offset..][0..4])) {
+ const inst = mem.bytesToValue(
+ meta.TagPayload(
+ aarch64.Instruction,
+ aarch64.Instruction.add_subtract_immediate,
+ ),
+ base.block.code[base.offset..][0..4],
+ );
+ break :blk .{
+ .rd = inst.rd,
+ .rn = inst.rn,
+ .size = inst.sf,
+ };
+ } else {
+ const inst = mem.bytesToValue(
+ meta.TagPayload(
+ aarch64.Instruction,
+ aarch64.Instruction.load_store_register,
+ ),
+ base.block.code[base.offset..][0..4],
+ );
+ break :blk .{
+ .rd = inst.rt,
+ .rn = inst.rn,
+ .size = @truncate(u1, inst.size),
+ };
+ }
+ };
+ const narrowed = @truncate(u12, target_addr);
+ var inst = aarch64.Instruction{
+ .add_subtract_immediate = .{
+ .rd = reg_info.rd,
+ .rn = reg_info.rn,
+ .imm12 = narrowed,
+ .sh = 0,
+ .s = 0,
+ .op = 0,
+ .sf = reg_info.size,
+ },
+ };
+ mem.writeIntLittle(u32, base.block.code[base.offset..][0..4], inst.toU32());
},
}
}
@@ -661,12 +715,17 @@ pub const Parser = struct {
mem.readIntLittle(i64, self.block.code[parsed.offset..][0..8])
else
mem.readIntLittle(i32, self.block.code[parsed.offset..][0..4]);
+ const source_sect_addr = if (rel.r_extern == 0) blk: {
+ if (parsed.target.payload == .regular) break :blk parsed.target.payload.regular.address;
+ break :blk null;
+ } else null;
parsed.payload = .{
.unsigned = .{
.subtractor = self.subtractor,
.is_64bit = is_64bit,
.addend = addend,
+ .source_sect_addr = source_sect_addr,
},
};
src/link/MachO/Zld.zig
@@ -120,16 +120,6 @@ pub const Output = struct {
install_name: ?[]const u8 = null,
};
-const TlvOffset = struct {
- source_addr: u64,
- offset: u64,
-
- fn cmp(context: void, a: TlvOffset, b: TlvOffset) bool {
- _ = context;
- return a.source_addr < b.source_addr;
- }
-};
-
pub const TextBlock = struct {
local_sym_index: u32,
aliases: ?[]u32 = null,
@@ -274,12 +264,11 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg
try self.parseLibs(args.libs, args.syslibroot);
try self.resolveSymbols();
try self.parseTextBlocks();
+ try self.sortSections();
+ try self.addRpaths(args.rpaths);
+ try self.addDataInCodeLC();
+ try self.addCodeSignatureLC();
return error.TODO;
- // try self.updateMetadata();
- // try self.sortSections();
- // try self.addRpaths(args.rpaths);
- // try self.addDataInCodeLC();
- // try self.addCodeSignatureLC();
// try self.allocateTextSegment();
// try self.allocateDataConstSegment();
// try self.allocateDataSegment();
@@ -343,106 +332,6 @@ fn parseLibs(self: *Zld, libs: []const []const u8, syslibroot: ?[]const u8) !voi
}
}
-fn mapAndUpdateSections(
- self: *Zld,
- object: *Object,
- source_sect_id: u16,
- target_seg_id: u16,
- target_sect_id: u16,
-) !void {
- 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.inner.size, alignment);
-
- log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{
- object.name.?,
- segmentName(source_sect.inner),
- sectionName(source_sect.inner),
- segmentName(target_sect.*),
- sectionName(target_sect.*),
- offset,
- offset + size,
- });
- log.debug(" | flags 0x{x}", .{source_sect.inner.flags});
-
- 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| {
- // Find ideal section alignment and update section mappings
- for (object.sections.items) |sect, sect_id| {
- const match = (try self.getMatchingSection(sect.inner)) orelse {
- log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{
- object.name.?,
- sect.inner.flags,
- segmentName(sect.inner),
- sectionName(sect.inner),
- });
- continue;
- };
- const target_seg = &self.load_commands.items[match.seg].Segment;
- const target_sect = &target_seg.sections.items[match.sect];
- target_sect.@"align" = math.max(target_sect.@"align", sect.inner.@"align");
-
- try self.mapAndUpdateSections(object, @intCast(u16, sect_id), match.seg, match.sect);
- }
- }
-
- tlv_align: {
- const has_tlv =
- self.tlv_section_index != null or
- self.tlv_data_section_index != null or
- self.tlv_bss_section_index != null;
-
- if (!has_tlv) break :tlv_align;
-
- const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
-
- if (self.tlv_section_index) |index| {
- const sect = &seg.sections.items[index];
- sect.@"align" = 3; // __thread_vars is always 8byte aligned
- }
-
- // Apparently __tlv_data and __tlv_bss need to have matching alignment, so fix it up.
- // <rdar://problem/24221680> All __thread_data and __thread_bss sections must have same alignment
- // https://github.com/apple-opensource/ld64/blob/e28c028b20af187a16a7161d89e91868a450cadc/src/ld/ld.cpp#L1172
- const data_align: u32 = data: {
- if (self.tlv_data_section_index) |index| {
- const sect = &seg.sections.items[index];
- break :data sect.@"align";
- }
- break :tlv_align;
- };
- const bss_align: u32 = bss: {
- if (self.tlv_bss_section_index) |index| {
- const sect = &seg.sections.items[index];
- break :bss sect.@"align";
- }
- break :tlv_align;
- };
- const max_align = math.max(data_align, bss_align);
-
- if (self.tlv_data_section_index) |index| {
- const sect = &seg.sections.items[index];
- sect.@"align" = max_align;
- }
- if (self.tlv_bss_section_index) |index| {
- const sect = &seg.sections.items[index];
- sect.@"align" = max_align;
- }
- }
-}
-
pub const MatchingSection = struct {
seg: u16,
sect: u16,
@@ -946,36 +835,6 @@ fn sortSections(self: *Zld) !void {
maybe_index.* = new_index;
}
}
-
- 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.?,
- segmentName(sect.inner),
- sectionName(sect.inner),
- target_map.section_id,
- new_index,
- });
-
- sect.target_map = .{
- .segment_id = target_map.segment_id,
- .section_id = new_index,
- .offset = target_map.offset,
- };
- }
- }
}
fn allocateTextSegment(self: *Zld) !void {
@@ -1431,6 +1290,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
symbol.payload = .{
.regular = .{
.linkage = .translation_unit,
+ .address = sym.n_value,
.weak_ref = Symbol.isWeakRef(sym),
.file = object,
.local_sym_index = @intCast(u32, self.locals.items.len),
@@ -1470,6 +1330,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
symbol.payload = .{
.regular = .{
.linkage = linkage,
+ .address = sym.n_value,
.weak_ref = Symbol.isWeakRef(sym),
.file = object,
},
@@ -1672,80 +1533,6 @@ fn parseTextBlocks(self: *Zld) !void {
}
}
-fn resolveRelocsAndWriteSections(self: *Zld) !void {
- for (self.objects.items) |object| {
- log.debug("relocating object {s}", .{object.name});
-
- for (object.sections.items) |sect| {
- if (sectionType(sect.inner) == macho.S_MOD_INIT_FUNC_POINTERS or
- sectionType(sect.inner) == macho.S_MOD_TERM_FUNC_POINTERS) continue;
-
- const segname = segmentName(sect.inner);
- const sectname = sectionName(sect.inner);
-
- log.debug("relocating section '{s},{s}'", .{ 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_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| {
- const source_addr = target_sect_addr + rel.offset;
-
- var args: reloc.Relocation.ResolveArgs = .{
- .source_addr = source_addr,
- .target_addr = undefined,
- };
-
- switch (rel.@"type") {
- .unsigned => {
- 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(object, subtractor);
- }
- if (rel.target == .section) {
- const source_sect = object.sections.items[rel.target.section];
- args.source_source_sect_addr = sect.inner.addr;
- args.source_target_sect_addr = source_sect.inner.addr;
- }
- },
- .got_page, .got_page_off, .got_load, .got, .pointer_to_got => {
- const dc_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
- const got = dc_seg.sections.items[self.got_section_index.?];
- const sym = object.symbols.items[rel.target.symbol];
- const got_index = sym.got_index orelse {
- log.err("expected GOT index relocating symbol '{s}'", .{sym.name});
- log.err("this is an internal linker error", .{});
- return error.FailedToResolveRelocationTarget;
- };
- args.target_addr = got.addr + got_index * @sizeOf(u64);
- },
- else => |tt| {
- if (tt == .signed and rel.target == .section) {
- const source_sect = object.sections.items[rel.target.section];
- args.source_source_sect_addr = sect.inner.addr;
- args.source_target_sect_addr = source_sect.inner.addr;
- }
- args.target_addr = try self.relocTargetAddr(object, rel.target);
- },
- }
-
- try rel.resolve(args);
- }
- }
- }
- }
-}
-
fn populateMetadata(self: *Zld) !void {
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);