| ... | @@ -764,8 +764,14 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -764,8 +764,14 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 764 | try self.createStubHelperPreambleAtom(); | 764 | try self.createStubHelperPreambleAtom(); |
| 765 | | 765 | |
| 766 | if (!use_stage1) { | 766 | if (!use_stage1) { |
| 767 | // TODO this should be made common when I figure out how to prealloc space for traditional linker path. | 767 | // TODO just a temp |
| 768 | try self.writeStubHelperPreamble(); | 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 | // Apply pending updates | 777 | // Apply pending updates |
| ... | @@ -842,7 +848,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -842,7 +848,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 842 | defer tracy.end(); | 848 | defer tracy.end(); |
| 843 | | 849 | |
| 844 | try self.setEntryPoint(); | 850 | try self.setEntryPoint(); |
| 845 | try self.writeTextBlocks(); | | |
| 846 | try self.writeRebaseInfoTable(); | 851 | try self.writeRebaseInfoTable(); |
| 847 | try self.writeBindInfoTable(); | 852 | try self.writeBindInfoTable(); |
| 848 | try self.writeLazyBindInfoTable(); | 853 | try self.writeLazyBindInfoTable(); |
| ... | @@ -1989,7 +1994,29 @@ fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1989,7 +1994,29 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 1989 | .n_desc = 0, | 1994 | .n_desc = 0, |
| 1990 | .n_value = 0, | 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 | self.dyld_private_sym_index = local_sym_index; | 2021 | self.dyld_private_sym_index = local_sym_index; |
| 1995 | } | 2022 | } |
| ... | @@ -2019,6 +2046,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { | ... | @@ -2019,6 +2046,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2019 | .n_desc = 0, | 2046 | .n_desc = 0, |
| 2020 | .n_value = 0, | 2047 | .n_value = 0, |
| 2021 | }); | 2048 | }); |
| | 2049 | const last = self.blocks.get(match); |
| 2022 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); | 2050 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2023 | switch (arch) { | 2051 | switch (arch) { |
| 2024 | .x86_64 => { | 2052 | .x86_64 => { |
| ... | @@ -2130,6 +2158,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { | ... | @@ -2130,6 +2158,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2130 | } | 2158 | } |
| 2131 | self.stub_preamble_sym_index = local_sym_index; | 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 | // TODO this needs to be fixed | 2184 | // TODO this needs to be fixed |
| 2134 | // We already prealloc stub helper size in populateMissingMetadata(), but | 2185 | // We already prealloc stub helper size in populateMissingMetadata(), but |
| 2135 | // perhaps it's not needed after all? | 2186 | // perhaps it's not needed after all? |
| ... | @@ -2138,139 +2189,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { | ... | @@ -2138,139 +2189,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2138 | sect.size -= size; | 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 | fn resolveSymbolsInObject( | 2192 | fn resolveSymbolsInObject( |
| 2275 | self: *MachO, | 2193 | self: *MachO, |
| 2276 | object_id: u16, | 2194 | object_id: u16, |
| ... | @@ -4873,7 +4791,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -4873,7 +4791,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 4873 | | 4791 | |
| 4874 | const undefs_off = globals_off + globals_size; | 4792 | const undefs_off = globals_off + globals_size; |
| 4875 | const undefs_size = nundefs * @sizeOf(macho.nlist_64); | 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 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off); | 4795 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off); |
| 4878 | | 4796 | |
| 4879 | // Update dynamic symbol table. | 4797 | // Update dynamic symbol table. |