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) = .{},
145145
146146dyld_private_sym_index: ?u32 = null,
147147dyld_stub_binder_index: ?u32 = null,
148stub_preamble_sym_index: ?u32 = null,
148149
149150stub_helper_stubs_start_off: ?u64 = null,
150151
......@@ -760,6 +761,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
760761 try self.resolveSymbols();
761762 try self.resolveDyldStubBinder();
762763 try self.createDyldPrivateAtom();
764 try self.createStubHelperPreambleAtom();
763765
764766 if (!use_stage1) {
765767 // 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 {
801803 try self.allocateDataSegment();
802804 self.allocateLinkeditSegment();
803805 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 }
805812 try self.flushZld();
806813 } else {
807814 try self.flushModule(comp);
......@@ -1755,11 +1762,9 @@ fn allocateDataSegment(self: *MachO) !void {
17551762 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
17561763 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
17571764
1758 // Set la_symbol_ptr and data size
1765 // Set la_symbol_ptr
17591766 const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?];
1760 const data = &seg.sections.items[self.data_section_index.?];
17611767 la_symbol_ptr.size += nstubs * @sizeOf(u64);
1762 data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder
17631768
17641769 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
17651770}
......@@ -1985,134 +1990,166 @@ fn createDyldPrivateAtom(self: *MachO) !void {
19851990 self.dyld_private_sym_index = local_sym_index;
19861991}
19871992
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// }
1993fn 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}
21162153
21172154fn writeStubHelperPreamble(self: *MachO) !void {
21182155 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
......@@ -3143,7 +3180,7 @@ fn writeSymbolTable(self: *MachO) !void {
31433180 const nexports = self.globals.items.len;
31443181 const nundefs = self.undefs.items.len;
31453182
3146 const locals_off = symtab.symoff + @sizeOf(macho.nlist_64);
3183 const locals_off = symtab.symoff;
31473184 const locals_size = nlocals * @sizeOf(macho.nlist_64);
31483185 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
31493186 try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
......@@ -3163,7 +3200,7 @@ fn writeSymbolTable(self: *MachO) !void {
31633200
31643201 // Update dynamic symbol table.
31653202 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
3166 dysymtab.nlocalsym += @intCast(u32, nlocals);
3203 dysymtab.nlocalsym = @intCast(u32, nlocals);
31673204 dysymtab.iextdefsym = dysymtab.nlocalsym;
31683205 dysymtab.nextdefsym = @intCast(u32, nexports);
31693206 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;