| ... | ... | @@ -764,8 +764,14 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 764 | 764 | try self.createStubHelperPreambleAtom(); |
| 765 | 765 | |
| 766 | 766 | if (!use_stage1) { |
| 767 | | // TODO this should be made common when I figure out how to prealloc space for traditional linker path. |
| 768 | | try self.writeStubHelperPreamble(); |
| 767 | // TODO just a temp |
| 768 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 769 | const sect = seg.sections.items[self.stub_helper_section_index.?]; |
| 770 | self.stub_helper_stubs_start_off = sect.offset + switch (self.base.options.target.cpu.arch) { |
| 771 | .x86_64 => @intCast(u64, 15), |
| 772 | .aarch64 => @intCast(u64, 6 * @sizeOf(u32)), |
| 773 | else => unreachable, |
| 774 | }; |
| 769 | 775 | } |
| 770 | 776 | |
| 771 | 777 | // Apply pending updates |
| ... | ... | @@ -842,7 +848,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 842 | 848 | defer tracy.end(); |
| 843 | 849 | |
| 844 | 850 | try self.setEntryPoint(); |
| 845 | | try self.writeTextBlocks(); |
| 846 | 851 | try self.writeRebaseInfoTable(); |
| 847 | 852 | try self.writeBindInfoTable(); |
| 848 | 853 | try self.writeLazyBindInfoTable(); |
| ... | ... | @@ -1989,7 +1994,29 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 1989 | 1994 | .n_desc = 0, |
| 1990 | 1995 | .n_value = 0, |
| 1991 | 1996 | }); |
| 1992 | | _ = try self.createEmptyAtom(match, local_sym_index, @sizeOf(u64), 3); |
| 1997 | const last = self.blocks.get(match); |
| 1998 | const atom = try self.createEmptyAtom(match, local_sym_index, @sizeOf(u64), 3); |
| 1999 | |
| 2000 | if (!(build_options.is_stage1 and self.base.options.use_stage1)) { |
| 2001 | const seg = self.load_commands.items[match.seg].Segment; |
| 2002 | const sect = seg.sections.items[match.sect]; |
| 2003 | const base_addr = if (last) |last_atom| blk: { |
| 2004 | const last_atom_sym = self.locals.items[last_atom.local_sym_index]; |
| 2005 | break :blk last_atom_sym.n_value; |
| 2006 | } else sect.addr; |
| 2007 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2008 | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 2009 | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); |
| 2010 | |
| 2011 | const sym = &self.locals.items[local_sym_index]; |
| 2012 | sym.n_value = vaddr; |
| 2013 | sym.n_sect = n_sect; |
| 2014 | |
| 2015 | const file_offset = sect.offset + vaddr - sect.addr; |
| 2016 | log.debug("writing code for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 2017 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 2018 | try self.writeLocalSymbol(local_sym_index); |
| 2019 | } |
| 1993 | 2020 | |
| 1994 | 2021 | self.dyld_private_sym_index = local_sym_index; |
| 1995 | 2022 | } |
| ... | ... | @@ -2019,6 +2046,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2019 | 2046 | .n_desc = 0, |
| 2020 | 2047 | .n_value = 0, |
| 2021 | 2048 | }); |
| 2049 | const last = self.blocks.get(match); |
| 2022 | 2050 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2023 | 2051 | switch (arch) { |
| 2024 | 2052 | .x86_64 => { |
| ... | ... | @@ -2130,6 +2158,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2130 | 2158 | } |
| 2131 | 2159 | self.stub_preamble_sym_index = local_sym_index; |
| 2132 | 2160 | |
| 2161 | if (!(build_options.is_stage1 and self.base.options.use_stage1)) { |
| 2162 | const seg = self.load_commands.items[match.seg].Segment; |
| 2163 | const sect = seg.sections.items[match.sect]; |
| 2164 | const base_addr = if (last) |last_atom| blk: { |
| 2165 | const last_atom_sym = self.locals.items[last_atom.local_sym_index]; |
| 2166 | break :blk last_atom_sym.n_value; |
| 2167 | } else sect.addr; |
| 2168 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2169 | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 2170 | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); |
| 2171 | |
| 2172 | const sym = &self.locals.items[local_sym_index]; |
| 2173 | sym.n_value = vaddr; |
| 2174 | sym.n_sect = n_sect; |
| 2175 | |
| 2176 | try atom.resolveRelocs(self); |
| 2177 | |
| 2178 | const file_offset = sect.offset + vaddr - sect.addr; |
| 2179 | log.debug("writing code for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 2180 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 2181 | try self.writeLocalSymbol(local_sym_index); |
| 2182 | } |
| 2183 | |
| 2133 | 2184 | // TODO this needs to be fixed |
| 2134 | 2185 | // We already prealloc stub helper size in populateMissingMetadata(), but |
| 2135 | 2186 | // perhaps it's not needed after all? |
| ... | ... | @@ -2138,139 +2189,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2138 | 2189 | sect.size -= size; |
| 2139 | 2190 | } |
| 2140 | 2191 | |
| 2141 | | fn writeStubHelperPreamble(self: *MachO) !void { |
| 2142 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2143 | | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| 2144 | | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 2145 | | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 2146 | | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2147 | | const data = &data_segment.sections.items[self.data_section_index.?]; |
| 2148 | | |
| 2149 | | self.stub_helper_stubs_start_off = blk: { |
| 2150 | | switch (self.base.options.target.cpu.arch) { |
| 2151 | | .x86_64 => { |
| 2152 | | const code_size = 15; |
| 2153 | | var code: [code_size]u8 = undefined; |
| 2154 | | // lea %r11, [rip + disp] |
| 2155 | | code[0] = 0x4c; |
| 2156 | | code[1] = 0x8d; |
| 2157 | | code[2] = 0x1d; |
| 2158 | | { |
| 2159 | | const target_addr = data.addr + data.size - @sizeOf(u64); |
| 2160 | | const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| 2161 | | mem.writeIntLittle(u32, code[3..7], displacement); |
| 2162 | | } |
| 2163 | | // push %r11 |
| 2164 | | code[7] = 0x41; |
| 2165 | | code[8] = 0x53; |
| 2166 | | // jmp [rip + disp] |
| 2167 | | code[9] = 0xff; |
| 2168 | | code[10] = 0x25; |
| 2169 | | { |
| 2170 | | const got_index = self.got_entries_map.get(.{ |
| 2171 | | .where = .undef, |
| 2172 | | .where_index = self.dyld_stub_binder_index.?, |
| 2173 | | }) orelse unreachable; |
| 2174 | | const addr = got.addr + got_index * @sizeOf(u64); |
| 2175 | | const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); |
| 2176 | | mem.writeIntLittle(u32, code[11..], displacement); |
| 2177 | | } |
| 2178 | | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2179 | | break :blk stub_helper.offset + code_size; |
| 2180 | | }, |
| 2181 | | .aarch64 => { |
| 2182 | | var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 2183 | | data_blk_outer: { |
| 2184 | | const this_addr = stub_helper.addr; |
| 2185 | | const target_addr = data.addr + data.size - @sizeOf(u64); |
| 2186 | | data_blk: { |
| 2187 | | const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; |
| 2188 | | // adr x17, disp |
| 2189 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2190 | | // nop |
| 2191 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 2192 | | break :data_blk_outer; |
| 2193 | | } |
| 2194 | | data_blk: { |
| 2195 | | const new_this_addr = this_addr + @sizeOf(u32); |
| 2196 | | const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; |
| 2197 | | // nop |
| 2198 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 2199 | | // adr x17, disp |
| 2200 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2201 | | break :data_blk_outer; |
| 2202 | | } |
| 2203 | | // Jump is too big, replace adr with adrp and add. |
| 2204 | | const this_page = @intCast(i32, this_addr >> 12); |
| 2205 | | const target_page = @intCast(i32, target_addr >> 12); |
| 2206 | | const pages = @intCast(i21, target_page - this_page); |
| 2207 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| 2208 | | const narrowed = @truncate(u12, target_addr); |
| 2209 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| 2210 | | } |
| 2211 | | // stp x16, x17, [sp, #-16]! |
| 2212 | | code[8] = 0xf0; |
| 2213 | | code[9] = 0x47; |
| 2214 | | code[10] = 0xbf; |
| 2215 | | code[11] = 0xa9; |
| 2216 | | binder_blk_outer: { |
| 2217 | | const got_index = self.got_entries_map.get(.{ |
| 2218 | | .where = .undef, |
| 2219 | | .where_index = self.dyld_stub_binder_index.?, |
| 2220 | | }) orelse unreachable; |
| 2221 | | const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 2222 | | const target_addr = got.addr + got_index * @sizeOf(u64); |
| 2223 | | binder_blk: { |
| 2224 | | const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; |
| 2225 | | const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2226 | | // ldr x16, label |
| 2227 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| 2228 | | .literal = literal, |
| 2229 | | }).toU32()); |
| 2230 | | // nop |
| 2231 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| 2232 | | break :binder_blk_outer; |
| 2233 | | } |
| 2234 | | binder_blk: { |
| 2235 | | const new_this_addr = this_addr + @sizeOf(u32); |
| 2236 | | const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; |
| 2237 | | const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2238 | | // Pad with nop to please division. |
| 2239 | | // nop |
| 2240 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 2241 | | // ldr x16, label |
| 2242 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2243 | | .literal = literal, |
| 2244 | | }).toU32()); |
| 2245 | | break :binder_blk_outer; |
| 2246 | | } |
| 2247 | | // Use adrp followed by ldr(immediate). |
| 2248 | | const this_page = @intCast(i32, this_addr >> 12); |
| 2249 | | const target_page = @intCast(i32, target_addr >> 12); |
| 2250 | | const pages = @intCast(i21, target_page - this_page); |
| 2251 | | mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 2252 | | const narrowed = @truncate(u12, target_addr); |
| 2253 | | const offset = try math.divExact(u12, narrowed, 8); |
| 2254 | | mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2255 | | .register = .{ |
| 2256 | | .rn = .x16, |
| 2257 | | .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 2258 | | }, |
| 2259 | | }).toU32()); |
| 2260 | | } |
| 2261 | | // br x16 |
| 2262 | | code[20] = 0x00; |
| 2263 | | code[21] = 0x02; |
| 2264 | | code[22] = 0x1f; |
| 2265 | | code[23] = 0xd6; |
| 2266 | | try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2267 | | break :blk stub_helper.offset + 6 * @sizeOf(u32); |
| 2268 | | }, |
| 2269 | | else => unreachable, |
| 2270 | | } |
| 2271 | | }; |
| 2272 | | } |
| 2273 | | |
| 2274 | 2192 | fn resolveSymbolsInObject( |
| 2275 | 2193 | self: *MachO, |
| 2276 | 2194 | object_id: u16, |
| ... | ... | @@ -4873,7 +4791,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 4873 | 4791 | |
| 4874 | 4792 | const undefs_off = globals_off + globals_size; |
| 4875 | 4793 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); |
| 4876 | | log.debug("writing extern symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 4794 | log.debug("writing undef symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off }); |
| 4877 | 4795 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off); |
| 4878 | 4796 | |
| 4879 | 4797 | // Update dynamic symbol table. |