authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-21 14:21:55+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-21 14:21:55+02:00
logd63d8ae1c00c240ac20836f1b54bff0093edcb61
tree1f0d2e42fdf4d8b2fba466636f58ca533806d956
parent2d10c52b3cfac9516f5548b04528bb7c31a0a6e7

macho: create __stub_helper preamble atom

with relocations to `dyld_private` and `__dyld_stub_binder` symbols making the routine properly dynamic (i.e., making it possible to call the routine before VM allocation takes place).

1 files changed, 171 insertions(+), 134 deletions(-)

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