From 792fd9c4a362f44f900007562504bfaceffbcc82 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 20 Aug 2021 09:49:21 +0200 Subject: [PATCH] macho: extract logic for creating and tracking atoms into fn --- src/link/MachO.zig | 244 ++++++++++++++++++++++++++++++++------------- 1 file changed, 172 insertions(+), 72 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index ab8779edb0..f17ecb5a09 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { for (self.pending_updates.items) |update| { switch (update) { - .resolve_undef => |sym_index| { - const sym = &self.undefs.items[sym_index]; - const sym_name = self.getString(sym.n_strx); - const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; - - for (self.dylibs.items) |dylib, id| { - if (!dylib.symbols.contains(sym_name)) continue; - - const dylib_id = @intCast(u16, id); - if (!self.referenced_dylibs.contains(dylib_id)) { - try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); - } - - const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable; - sym.n_type |= macho.N_EXT; - sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER; - - break; - } else { - try still_pending.append(update); - log.warn("undefined reference to symbol '{s}'", .{sym_name}); - // TODO self-reference for incremental means resolv.file == 0! - if (self.objects.items.len > 0) { - log.warn(" first referenced in '{s}'", .{self.objects.items[resolv.file].name}); - } - } - }, - .add_got_entry => return error.TODOAddGotEntryUpdate, .add_stub_entry => |stub_index| { try self.writeStub(stub_index); try self.writeStubInStubHelper(stub_index); @@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { self.rebase_info_dirty = true; self.lazy_binding_info_dirty = true; }, + else => unreachable, } } @@ -856,6 +829,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { defer tracy.end(); try self.setEntryPoint(); + try self.writeTextBlocks(); try self.writeRebaseInfoTable(); try self.writeBindInfoTable(); try self.writeLazyBindInfoTable(); @@ -1946,6 +1920,174 @@ fn writeTextBlocks(self: *MachO) !void { } } +fn createEmptyAtom( + self: *MachO, + match: MatchingSection, + local_sym_index: u32, + size: u64, + alignment: u32, +) !*TextBlock { + const code = try self.base.allocator.alloc(u8, size); + defer self.base.allocator.free(code); + mem.set(u8, code, 0); + + const block = try self.base.allocator.create(TextBlock); + errdefer self.base.allocator.destroy(block); + block.* = TextBlock.empty; + block.local_sym_index = local_sym_index; + block.size = size; + block.alignment = alignment; + try block.code.appendSlice(self.base.allocator, code); + + try self.managed_blocks.append(self.base.allocator, block); + + // Update target section's metadata + // TODO should we update segment's size here too? + // How does it tie with incremental space allocs? + const tseg = &self.load_commands.items[match.seg].Segment; + const tsect = &tseg.sections.items[match.sect]; + const new_alignment = math.max(tsect.@"align", alignment); + const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); + const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + size; + tsect.size = new_size; + tsect.@"align" = new_alignment; + + if (self.blocks.getPtr(match)) |last| { + last.*.next = block; + block.prev = last.*; + last.* = block; + } else { + try self.blocks.putNoClobber(self.base.allocator, match, block); + } + + return block; +} + +// fn createStubHelperPreambleAtom(self: *MachO) !void { +// switch (self.base.options.target.cpu.arch) { +// .x86_64 => { +// const code_size = 15; +// var code = try self.base.allocator.alloc(u8, code_size); +// errdefer self.base.allocator.free(code); +// // lea %r11, [rip + disp] +// code[0] = 0x4c; +// code[1] = 0x8d; +// code[2] = 0x1d; +// { +// const target_addr = data.addr + data.size - @sizeOf(u64); +// const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); +// mem.writeIntLittle(u32, code[3..7], displacement); +// } +// // push %r11 +// code[7] = 0x41; +// code[8] = 0x53; +// // jmp [rip + disp] +// code[9] = 0xff; +// code[10] = 0x25; +// { +// const got_index = self.got_entries_map.get(.{ +// .where = .undef, +// .where_index = self.dyld_stub_binder_index.?, +// }) orelse unreachable; +// const addr = got.addr + got_index * @sizeOf(u64); +// const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); +// mem.writeIntLittle(u32, code[11..], displacement); +// } +// try self.base.file.?.pwriteAll(&code, stub_helper.offset); +// break :blk stub_helper.offset + code_size; +// }, +// .aarch64 => { +// var code: [6 * @sizeOf(u32)]u8 = undefined; +// data_blk_outer: { +// const this_addr = stub_helper.addr; +// const target_addr = data.addr + data.size - @sizeOf(u64); +// data_blk: { +// const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; +// // adr x17, disp +// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); +// // nop +// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); +// break :data_blk_outer; +// } +// data_blk: { +// const new_this_addr = this_addr + @sizeOf(u32); +// const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; +// // nop +// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); +// // adr x17, disp +// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); +// break :data_blk_outer; +// } +// // Jump is too big, replace adr with adrp and add. +// const this_page = @intCast(i32, this_addr >> 12); +// const target_page = @intCast(i32, target_addr >> 12); +// const pages = @intCast(i21, target_page - this_page); +// mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); +// const narrowed = @truncate(u12, target_addr); +// mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); +// } +// // stp x16, x17, [sp, #-16]! +// code[8] = 0xf0; +// code[9] = 0x47; +// code[10] = 0xbf; +// code[11] = 0xa9; +// binder_blk_outer: { +// const got_index = self.got_entries_map.get(.{ +// .where = .undef, +// .where_index = self.dyld_stub_binder_index.?, +// }) orelse unreachable; +// const this_addr = stub_helper.addr + 3 * @sizeOf(u32); +// const target_addr = got.addr + got_index * @sizeOf(u64); +// binder_blk: { +// const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; +// const literal = math.cast(u18, displacement) catch break :binder_blk; +// // ldr x16, label +// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ +// .literal = literal, +// }).toU32()); +// // nop +// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); +// break :binder_blk_outer; +// } +// binder_blk: { +// const new_this_addr = this_addr + @sizeOf(u32); +// const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; +// const literal = math.cast(u18, displacement) catch break :binder_blk; +// // Pad with nop to please division. +// // nop +// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); +// // ldr x16, label +// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ +// .literal = literal, +// }).toU32()); +// break :binder_blk_outer; +// } +// // Use adrp followed by ldr(immediate). +// const this_page = @intCast(i32, this_addr >> 12); +// const target_page = @intCast(i32, target_addr >> 12); +// const pages = @intCast(i21, target_page - this_page); +// mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); +// const narrowed = @truncate(u12, target_addr); +// const offset = try math.divExact(u12, narrowed, 8); +// mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ +// .register = .{ +// .rn = .x16, +// .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), +// }, +// }).toU32()); +// } +// // br x16 +// code[20] = 0x00; +// code[21] = 0x02; +// code[22] = 0x1f; +// code[23] = 0xd6; +// try self.base.file.?.pwriteAll(&code, stub_helper.offset); +// break :blk stub_helper.offset + 6 * @sizeOf(u32); +// }, +// else => unreachable, +// } +// } + fn writeStubHelperPreamble(self: *MachO) !void { const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; @@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void { _ = try self.section_ordinals.getOrPut(self.base.allocator, match); const size = sym.n_value; - const code = try self.base.allocator.alloc(u8, size); - defer self.base.allocator.free(code); - mem.set(u8, code, 0); const alignment = (sym.n_desc >> 8) & 0x0f; sym.n_value = 0; @@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void { const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; resolv.local_sym_index = local_sym_index; - const block = try self.base.allocator.create(TextBlock); - block.* = TextBlock.empty; - block.local_sym_index = local_sym_index; - block.size = size; - block.alignment = alignment; - try self.managed_blocks.append(self.base.allocator, block); - - try block.code.appendSlice(self.base.allocator, code); - - // Update target section's metadata - // TODO should we update segment's size here too? - // How does it tie with incremental space allocs? - const tseg = &self.load_commands.items[match.seg].Segment; - const tsect = &tseg.sections.items[match.sect]; - const new_alignment = math.max(tsect.@"align", block.alignment); - const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); - const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; - tsect.size = new_size; - tsect.@"align" = new_alignment; - - if (self.blocks.getPtr(match)) |last| { - last.*.next = block; - block.prev = last.*; - last.* = block; - } else { - try self.blocks.putNoClobber(self.base.allocator, match, block); - } + _ = try self.createEmptyAtom(match, local_sym_index, size, alignment); } // Third pass, resolve symbols in dynamic libraries. @@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void { // We create an empty atom for this symbol. // TODO perhaps we should special-case special symbols? Create a separate // linked list of atoms? - const block = try self.base.allocator.create(TextBlock); - block.* = TextBlock.empty; - block.local_sym_index = local_sym_index; - block.size = 0; - block.alignment = 0; - try self.managed_blocks.append(self.base.allocator, block); - - if (self.blocks.getPtr(match)) |last| { - last.*.next = block; - block.prev = last.*; - last.* = block; - } else { - try self.blocks.putNoClobber(self.base.allocator, match, block); - } + _ = try self.createEmptyAtom(match, local_sym_index, 0, 0); } for (self.unresolved.keys()) |index| {