| ... | ... | @@ -145,6 +145,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 145 | 145 | |
| 146 | 146 | dyld_private_sym_index: ?u32 = null, |
| 147 | 147 | dyld_stub_binder_index: ?u32 = null, |
| 148 | stub_preamble_sym_index: ?u32 = null, |
| 148 | 149 | |
| 149 | 150 | stub_helper_stubs_start_off: ?u64 = null, |
| 150 | 151 | |
| ... | ... | @@ -760,6 +761,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 760 | 761 | try self.resolveSymbols(); |
| 761 | 762 | try self.resolveDyldStubBinder(); |
| 762 | 763 | try self.createDyldPrivateAtom(); |
| 764 | try self.createStubHelperPreambleAtom(); |
| 763 | 765 | |
| 764 | 766 | if (!use_stage1) { |
| 765 | 767 | // TODO this should be made common when I figure out how to prealloc space for traditional linker path. |
| ... | ... | @@ -801,7 +803,12 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 801 | 803 | try self.allocateDataSegment(); |
| 802 | 804 | self.allocateLinkeditSegment(); |
| 803 | 805 | try self.allocateTextBlocks(); |
| 804 | | try self.writeStubHelperPreamble(); |
| 806 | { |
| 807 | // TODO just a temp |
| 808 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 809 | const sect = seg.sections.items[self.stub_helper_section_index.?]; |
| 810 | self.stub_helper_stubs_start_off = sect.offset + 15; |
| 811 | } |
| 805 | 812 | try self.flushZld(); |
| 806 | 813 | } else { |
| 807 | 814 | try self.flushModule(comp); |
| ... | ... | @@ -1755,11 +1762,9 @@ fn allocateDataSegment(self: *MachO) !void { |
| 1755 | 1762 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| 1756 | 1763 | seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize; |
| 1757 | 1764 | |
| 1758 | | // Set la_symbol_ptr and data size |
| 1765 | // Set la_symbol_ptr |
| 1759 | 1766 | const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?]; |
| 1760 | | const data = &seg.sections.items[self.data_section_index.?]; |
| 1761 | 1767 | la_symbol_ptr.size += nstubs * @sizeOf(u64); |
| 1762 | | data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder |
| 1763 | 1768 | |
| 1764 | 1769 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 1765 | 1770 | } |
| ... | ... | @@ -1985,134 +1990,166 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 1985 | 1990 | self.dyld_private_sym_index = local_sym_index; |
| 1986 | 1991 | } |
| 1987 | 1992 | |
| 1988 | | // fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1989 | | // const match = MatchingSection{ |
| 1990 | | // .seg = self.text_segment_cmd_index.?, |
| 1991 | | // .sect = self.stub_helper_section_index.?, |
| 1992 | | // }; |
| 1993 | | // switch (self.base.options.target.cpu.arch) { |
| 1994 | | // .x86_64 => { |
| 1995 | | // const code_size = 15; |
| 1996 | | // var code = try self.base.allocator.alloc(u8, code_size); |
| 1997 | | // errdefer self.base.allocator.free(code); |
| 1998 | | // // lea %r11, [rip + disp] |
| 1999 | | // code[0] = 0x4c; |
| 2000 | | // code[1] = 0x8d; |
| 2001 | | // code[2] = 0x1d; |
| 2002 | | // { |
| 2003 | | // const target_addr = data.addr + data.size - @sizeOf(u64); |
| 2004 | | // const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| 2005 | | // mem.writeIntLittle(u32, code[3..7], displacement); |
| 2006 | | // } |
| 2007 | | // // push %r11 |
| 2008 | | // code[7] = 0x41; |
| 2009 | | // code[8] = 0x53; |
| 2010 | | // // jmp [rip + disp] |
| 2011 | | // code[9] = 0xff; |
| 2012 | | // code[10] = 0x25; |
| 2013 | | // { |
| 2014 | | // const got_index = self.got_entries_map.get(.{ |
| 2015 | | // .where = .undef, |
| 2016 | | // .where_index = self.dyld_stub_binder_index.?, |
| 2017 | | // }) orelse unreachable; |
| 2018 | | // const addr = got.addr + got_index * @sizeOf(u64); |
| 2019 | | // const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); |
| 2020 | | // mem.writeIntLittle(u32, code[11..], displacement); |
| 2021 | | // } |
| 2022 | | // try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2023 | | // break :blk stub_helper.offset + code_size; |
| 2024 | | // }, |
| 2025 | | // .aarch64 => { |
| 2026 | | // var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 2027 | | // data_blk_outer: { |
| 2028 | | // const this_addr = stub_helper.addr; |
| 2029 | | // const target_addr = data.addr + data.size - @sizeOf(u64); |
| 2030 | | // data_blk: { |
| 2031 | | // const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; |
| 2032 | | // // adr x17, disp |
| 2033 | | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2034 | | // // nop |
| 2035 | | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 2036 | | // break :data_blk_outer; |
| 2037 | | // } |
| 2038 | | // data_blk: { |
| 2039 | | // const new_this_addr = this_addr + @sizeOf(u32); |
| 2040 | | // const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; |
| 2041 | | // // nop |
| 2042 | | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 2043 | | // // adr x17, disp |
| 2044 | | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2045 | | // break :data_blk_outer; |
| 2046 | | // } |
| 2047 | | // // Jump is too big, replace adr with adrp and add. |
| 2048 | | // const this_page = @intCast(i32, this_addr >> 12); |
| 2049 | | // const target_page = @intCast(i32, target_addr >> 12); |
| 2050 | | // const pages = @intCast(i21, target_page - this_page); |
| 2051 | | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| 2052 | | // const narrowed = @truncate(u12, target_addr); |
| 2053 | | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| 2054 | | // } |
| 2055 | | // // stp x16, x17, [sp, #-16]! |
| 2056 | | // code[8] = 0xf0; |
| 2057 | | // code[9] = 0x47; |
| 2058 | | // code[10] = 0xbf; |
| 2059 | | // code[11] = 0xa9; |
| 2060 | | // binder_blk_outer: { |
| 2061 | | // const got_index = self.got_entries_map.get(.{ |
| 2062 | | // .where = .undef, |
| 2063 | | // .where_index = self.dyld_stub_binder_index.?, |
| 2064 | | // }) orelse unreachable; |
| 2065 | | // const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 2066 | | // const target_addr = got.addr + got_index * @sizeOf(u64); |
| 2067 | | // binder_blk: { |
| 2068 | | // const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; |
| 2069 | | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2070 | | // // ldr x16, label |
| 2071 | | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| 2072 | | // .literal = literal, |
| 2073 | | // }).toU32()); |
| 2074 | | // // nop |
| 2075 | | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| 2076 | | // break :binder_blk_outer; |
| 2077 | | // } |
| 2078 | | // binder_blk: { |
| 2079 | | // const new_this_addr = this_addr + @sizeOf(u32); |
| 2080 | | // const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; |
| 2081 | | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2082 | | // // Pad with nop to please division. |
| 2083 | | // // nop |
| 2084 | | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 2085 | | // // ldr x16, label |
| 2086 | | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2087 | | // .literal = literal, |
| 2088 | | // }).toU32()); |
| 2089 | | // break :binder_blk_outer; |
| 2090 | | // } |
| 2091 | | // // Use adrp followed by ldr(immediate). |
| 2092 | | // const this_page = @intCast(i32, this_addr >> 12); |
| 2093 | | // const target_page = @intCast(i32, target_addr >> 12); |
| 2094 | | // const pages = @intCast(i21, target_page - this_page); |
| 2095 | | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 2096 | | // const narrowed = @truncate(u12, target_addr); |
| 2097 | | // const offset = try math.divExact(u12, narrowed, 8); |
| 2098 | | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2099 | | // .register = .{ |
| 2100 | | // .rn = .x16, |
| 2101 | | // .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 2102 | | // }, |
| 2103 | | // }).toU32()); |
| 2104 | | // } |
| 2105 | | // // br x16 |
| 2106 | | // code[20] = 0x00; |
| 2107 | | // code[21] = 0x02; |
| 2108 | | // code[22] = 0x1f; |
| 2109 | | // code[23] = 0xd6; |
| 2110 | | // try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2111 | | // break :blk stub_helper.offset + 6 * @sizeOf(u32); |
| 2112 | | // }, |
| 2113 | | // else => unreachable, |
| 2114 | | // } |
| 2115 | | // } |
| 1993 | fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1994 | if (self.stub_preamble_sym_index != null) return; |
| 1995 | const arch = self.base.options.target.cpu.arch; |
| 1996 | const match = MatchingSection{ |
| 1997 | .seg = self.text_segment_cmd_index.?, |
| 1998 | .sect = self.stub_helper_section_index.?, |
| 1999 | }; |
| 2000 | const size: u64 = switch (arch) { |
| 2001 | .x86_64 => 15, |
| 2002 | .aarch64 => 6 * @sizeOf(u32), |
| 2003 | else => unreachable, |
| 2004 | }; |
| 2005 | const alignment: u32 = switch (arch) { |
| 2006 | .x86_64 => 0, |
| 2007 | .aarch64 => 2, |
| 2008 | else => unreachable, |
| 2009 | }; |
| 2010 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2011 | try self.locals.append(self.base.allocator, .{ |
| 2012 | .n_strx = try self.makeString("stub_preamble"), |
| 2013 | .n_type = macho.N_SECT, |
| 2014 | .n_sect = 0, |
| 2015 | .n_desc = 0, |
| 2016 | .n_value = 0, |
| 2017 | }); |
| 2018 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2019 | switch (arch) { |
| 2020 | .x86_64 => { |
| 2021 | // lea %r11, [rip + disp] |
| 2022 | atom.code.items[0] = 0x4c; |
| 2023 | atom.code.items[1] = 0x8d; |
| 2024 | atom.code.items[2] = 0x1d; |
| 2025 | try atom.relocs.append(self.base.allocator, .{ |
| 2026 | .offset = 3, |
| 2027 | .where = .local, |
| 2028 | .where_index = self.dyld_private_sym_index.?, |
| 2029 | .payload = .{ |
| 2030 | .signed = .{ |
| 2031 | .addend = 0, |
| 2032 | .correction = 0, |
| 2033 | }, |
| 2034 | }, |
| 2035 | }); |
| 2036 | // push %r11 |
| 2037 | atom.code.items[7] = 0x41; |
| 2038 | atom.code.items[8] = 0x53; |
| 2039 | // jmp [rip + disp] |
| 2040 | atom.code.items[9] = 0xff; |
| 2041 | atom.code.items[10] = 0x25; |
| 2042 | try atom.relocs.append(self.base.allocator, .{ |
| 2043 | .offset = 11, |
| 2044 | .where = .undef, |
| 2045 | .where_index = self.dyld_stub_binder_index.?, |
| 2046 | .payload = .{ |
| 2047 | .load = .{ |
| 2048 | .kind = .got, |
| 2049 | .addend = 0, |
| 2050 | }, |
| 2051 | }, |
| 2052 | }); |
| 2053 | }, |
| 2054 | // .aarch64 => { |
| 2055 | // var code: [6 * @sizeOf(u32)]u8 = undefined; |
| 2056 | // data_blk_outer: { |
| 2057 | // const this_addr = stub_helper.addr; |
| 2058 | // const target_addr = data.addr + data.size - @sizeOf(u64); |
| 2059 | // data_blk: { |
| 2060 | // const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; |
| 2061 | // // adr x17, disp |
| 2062 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2063 | // // nop |
| 2064 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| 2065 | // break :data_blk_outer; |
| 2066 | // } |
| 2067 | // data_blk: { |
| 2068 | // const new_this_addr = this_addr + @sizeOf(u32); |
| 2069 | // const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; |
| 2070 | // // nop |
| 2071 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| 2072 | // // adr x17, disp |
| 2073 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| 2074 | // break :data_blk_outer; |
| 2075 | // } |
| 2076 | // // Jump is too big, replace adr with adrp and add. |
| 2077 | // const this_page = @intCast(i32, this_addr >> 12); |
| 2078 | // const target_page = @intCast(i32, target_addr >> 12); |
| 2079 | // const pages = @intCast(i21, target_page - this_page); |
| 2080 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| 2081 | // const narrowed = @truncate(u12, target_addr); |
| 2082 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| 2083 | // } |
| 2084 | // // stp x16, x17, [sp, #-16]! |
| 2085 | // code[8] = 0xf0; |
| 2086 | // code[9] = 0x47; |
| 2087 | // code[10] = 0xbf; |
| 2088 | // code[11] = 0xa9; |
| 2089 | // binder_blk_outer: { |
| 2090 | // const got_index = self.got_entries_map.get(.{ |
| 2091 | // .where = .undef, |
| 2092 | // .where_index = self.dyld_stub_binder_index.?, |
| 2093 | // }) orelse unreachable; |
| 2094 | // const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| 2095 | // const target_addr = got.addr + got_index * @sizeOf(u64); |
| 2096 | // binder_blk: { |
| 2097 | // const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; |
| 2098 | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2099 | // // ldr x16, label |
| 2100 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| 2101 | // .literal = literal, |
| 2102 | // }).toU32()); |
| 2103 | // // nop |
| 2104 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| 2105 | // break :binder_blk_outer; |
| 2106 | // } |
| 2107 | // binder_blk: { |
| 2108 | // const new_this_addr = this_addr + @sizeOf(u32); |
| 2109 | // const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; |
| 2110 | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| 2111 | // // Pad with nop to please division. |
| 2112 | // // nop |
| 2113 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| 2114 | // // ldr x16, label |
| 2115 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2116 | // .literal = literal, |
| 2117 | // }).toU32()); |
| 2118 | // break :binder_blk_outer; |
| 2119 | // } |
| 2120 | // // Use adrp followed by ldr(immediate). |
| 2121 | // const this_page = @intCast(i32, this_addr >> 12); |
| 2122 | // const target_page = @intCast(i32, target_addr >> 12); |
| 2123 | // const pages = @intCast(i21, target_page - this_page); |
| 2124 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| 2125 | // const narrowed = @truncate(u12, target_addr); |
| 2126 | // const offset = try math.divExact(u12, narrowed, 8); |
| 2127 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| 2128 | // .register = .{ |
| 2129 | // .rn = .x16, |
| 2130 | // .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| 2131 | // }, |
| 2132 | // }).toU32()); |
| 2133 | // } |
| 2134 | // // br x16 |
| 2135 | // code[20] = 0x00; |
| 2136 | // code[21] = 0x02; |
| 2137 | // code[22] = 0x1f; |
| 2138 | // code[23] = 0xd6; |
| 2139 | // try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| 2140 | // break :blk stub_helper.offset + 6 * @sizeOf(u32); |
| 2141 | // }, |
| 2142 | else => unreachable, |
| 2143 | } |
| 2144 | self.stub_preamble_sym_index = local_sym_index; |
| 2145 | |
| 2146 | // TODO this needs to be fixed |
| 2147 | // We already prealloc stub helper size in populateMissingMetadata(), but |
| 2148 | // perhaps it's not needed after all? |
| 2149 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2150 | const sect = &seg.sections.items[self.stub_helper_section_index.?]; |
| 2151 | sect.size -= size; |
| 2152 | } |
| 2116 | 2153 | |
| 2117 | 2154 | fn writeStubHelperPreamble(self: *MachO) !void { |
| 2118 | 2155 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| ... | ... | @@ -3143,7 +3180,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 3143 | 3180 | const nexports = self.globals.items.len; |
| 3144 | 3181 | const nundefs = self.undefs.items.len; |
| 3145 | 3182 | |
| 3146 | | const locals_off = symtab.symoff + @sizeOf(macho.nlist_64); |
| 3183 | const locals_off = symtab.symoff; |
| 3147 | 3184 | const locals_size = nlocals * @sizeOf(macho.nlist_64); |
| 3148 | 3185 | log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off }); |
| 3149 | 3186 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off); |
| ... | ... | @@ -3163,7 +3200,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 3163 | 3200 | |
| 3164 | 3201 | // Update dynamic symbol table. |
| 3165 | 3202 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 3166 | | dysymtab.nlocalsym += @intCast(u32, nlocals); |
| 3203 | dysymtab.nlocalsym = @intCast(u32, nlocals); |
| 3167 | 3204 | dysymtab.iextdefsym = dysymtab.nlocalsym; |
| 3168 | 3205 | dysymtab.nextdefsym = @intCast(u32, nexports); |
| 3169 | 3206 | dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym; |