diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 5c10c6bd33..65af8166fc 100644 --- a/src/link/MachO/Object.zig +++ b/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; diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig index 5e6d2c17ce..36d0e58dc3 100644 --- a/src/link/MachO/Zld.zig +++ b/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. - // 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); diff --git a/src/link/MachO/reloc.zig b/src/link/MachO/reloc.zig index ce95b26252..d35344c71b 100644 --- a/src/link/MachO/reloc.zig +++ b/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 addend = if (self.source_sect_addr) |addr| + self.addend - addr + else + self.addend; - // const result = if (args.subtractor) |subtractor| - // @intCast(i64, args.target_addr) - @intCast(i64, subtractor) + addend - // else - // @intCast(i64, args.target_addr) + addend; + const result = if (self.subtractor) |subtractor| + @intCast(i64, target_addr) - @intCast(i64, subtractor.payload.regular.address) + addend + else + @intCast(i64, 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)), - // ); - // } + 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); + const actual_target_addr = if (self.addend) |addend| target_addr + addend else target_addr; + const narrowed = @truncate(u12, actual_target_addr); - // log.debug(" | narrowed address within the page 0x{x}", .{narrowed}); - // log.debug(" | {s} opcode", .{page_off.op_kind}); + 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], + ), + }; + }, + } + }; - // 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()); + 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, }, };