| ... | @@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 770 | | 770 | |
| 771 | for (self.pending_updates.items) |update| { | 771 | for (self.pending_updates.items) |update| { |
| 772 | switch (update) { | 772 | switch (update) { |
| 773 | .resolve_undef => |sym_index| { | | |
| 774 | const sym = &self.undefs.items[sym_index]; | | |
| 775 | const sym_name = self.getString(sym.n_strx); | | |
| 776 | const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; | | |
| 777 | | | |
| 778 | for (self.dylibs.items) |dylib, id| { | | |
| 779 | if (!dylib.symbols.contains(sym_name)) continue; | | |
| 780 | | | |
| 781 | const dylib_id = @intCast(u16, id); | | |
| 782 | if (!self.referenced_dylibs.contains(dylib_id)) { | | |
| 783 | try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); | | |
| 784 | } | | |
| 785 | | | |
| 786 | const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable; | | |
| 787 | sym.n_type |= macho.N_EXT; | | |
| 788 | sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER; | | |
| 789 | | | |
| 790 | break; | | |
| 791 | } else { | | |
| 792 | try still_pending.append(update); | | |
| 793 | log.warn("undefined reference to symbol '{s}'", .{sym_name}); | | |
| 794 | // TODO self-reference for incremental means resolv.file == 0! | | |
| 795 | if (self.objects.items.len > 0) { | | |
| 796 | log.warn(" first referenced in '{s}'", .{self.objects.items[resolv.file].name}); | | |
| 797 | } | | |
| 798 | } | | |
| 799 | }, | | |
| 800 | .add_got_entry => return error.TODOAddGotEntryUpdate, | | |
| 801 | .add_stub_entry => |stub_index| { | 773 | .add_stub_entry => |stub_index| { |
| 802 | try self.writeStub(stub_index); | 774 | try self.writeStub(stub_index); |
| 803 | try self.writeStubInStubHelper(stub_index); | 775 | try self.writeStubInStubHelper(stub_index); |
| ... | @@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 805 | self.rebase_info_dirty = true; | 777 | self.rebase_info_dirty = true; |
| 806 | self.lazy_binding_info_dirty = true; | 778 | self.lazy_binding_info_dirty = true; |
| 807 | }, | 779 | }, |
| | 780 | else => unreachable, |
| 808 | } | 781 | } |
| 809 | } | 782 | } |
| 810 | | 783 | |
| ... | @@ -856,6 +829,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -856,6 +829,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 856 | defer tracy.end(); | 829 | defer tracy.end(); |
| 857 | | 830 | |
| 858 | try self.setEntryPoint(); | 831 | try self.setEntryPoint(); |
| | 832 | try self.writeTextBlocks(); |
| 859 | try self.writeRebaseInfoTable(); | 833 | try self.writeRebaseInfoTable(); |
| 860 | try self.writeBindInfoTable(); | 834 | try self.writeBindInfoTable(); |
| 861 | try self.writeLazyBindInfoTable(); | 835 | try self.writeLazyBindInfoTable(); |
| ... | @@ -1946,6 +1920,174 @@ fn writeTextBlocks(self: *MachO) !void { | ... | @@ -1946,6 +1920,174 @@ fn writeTextBlocks(self: *MachO) !void { |
| 1946 | } | 1920 | } |
| 1947 | } | 1921 | } |
| 1948 | | 1922 | |
| | 1923 | fn createEmptyAtom( |
| | 1924 | self: *MachO, |
| | 1925 | match: MatchingSection, |
| | 1926 | local_sym_index: u32, |
| | 1927 | size: u64, |
| | 1928 | alignment: u32, |
| | 1929 | ) !*TextBlock { |
| | 1930 | const code = try self.base.allocator.alloc(u8, size); |
| | 1931 | defer self.base.allocator.free(code); |
| | 1932 | mem.set(u8, code, 0); |
| | 1933 | |
| | 1934 | const block = try self.base.allocator.create(TextBlock); |
| | 1935 | errdefer self.base.allocator.destroy(block); |
| | 1936 | block.* = TextBlock.empty; |
| | 1937 | block.local_sym_index = local_sym_index; |
| | 1938 | block.size = size; |
| | 1939 | block.alignment = alignment; |
| | 1940 | try block.code.appendSlice(self.base.allocator, code); |
| | 1941 | |
| | 1942 | try self.managed_blocks.append(self.base.allocator, block); |
| | 1943 | |
| | 1944 | // Update target section's metadata |
| | 1945 | // TODO should we update segment's size here too? |
| | 1946 | // How does it tie with incremental space allocs? |
| | 1947 | const tseg = &self.load_commands.items[match.seg].Segment; |
| | 1948 | const tsect = &tseg.sections.items[match.sect]; |
| | 1949 | const new_alignment = math.max(tsect.@"align", alignment); |
| | 1950 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); |
| | 1951 | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + size; |
| | 1952 | tsect.size = new_size; |
| | 1953 | tsect.@"align" = new_alignment; |
| | 1954 | |
| | 1955 | if (self.blocks.getPtr(match)) |last| { |
| | 1956 | last.*.next = block; |
| | 1957 | block.prev = last.*; |
| | 1958 | last.* = block; |
| | 1959 | } else { |
| | 1960 | try self.blocks.putNoClobber(self.base.allocator, match, block); |
| | 1961 | } |
| | 1962 | |
| | 1963 | return block; |
| | 1964 | } |
| | 1965 | |
| | 1966 | // fn createStubHelperPreambleAtom(self: *MachO) !void { |
| | 1967 | // switch (self.base.options.target.cpu.arch) { |
| | 1968 | // .x86_64 => { |
| | 1969 | // const code_size = 15; |
| | 1970 | // var code = try self.base.allocator.alloc(u8, code_size); |
| | 1971 | // errdefer self.base.allocator.free(code); |
| | 1972 | // // lea %r11, [rip + disp] |
| | 1973 | // code[0] = 0x4c; |
| | 1974 | // code[1] = 0x8d; |
| | 1975 | // code[2] = 0x1d; |
| | 1976 | // { |
| | 1977 | // const target_addr = data.addr + data.size - @sizeOf(u64); |
| | 1978 | // const displacement = try math.cast(u32, target_addr - stub_helper.addr - 7); |
| | 1979 | // mem.writeIntLittle(u32, code[3..7], displacement); |
| | 1980 | // } |
| | 1981 | // // push %r11 |
| | 1982 | // code[7] = 0x41; |
| | 1983 | // code[8] = 0x53; |
| | 1984 | // // jmp [rip + disp] |
| | 1985 | // code[9] = 0xff; |
| | 1986 | // code[10] = 0x25; |
| | 1987 | // { |
| | 1988 | // const got_index = self.got_entries_map.get(.{ |
| | 1989 | // .where = .undef, |
| | 1990 | // .where_index = self.dyld_stub_binder_index.?, |
| | 1991 | // }) orelse unreachable; |
| | 1992 | // const addr = got.addr + got_index * @sizeOf(u64); |
| | 1993 | // const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); |
| | 1994 | // mem.writeIntLittle(u32, code[11..], displacement); |
| | 1995 | // } |
| | 1996 | // try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 1997 | // break :blk stub_helper.offset + code_size; |
| | 1998 | // }, |
| | 1999 | // .aarch64 => { |
| | 2000 | // var code: [6 * @sizeOf(u32)]u8 = undefined; |
| | 2001 | // data_blk_outer: { |
| | 2002 | // const this_addr = stub_helper.addr; |
| | 2003 | // const target_addr = data.addr + data.size - @sizeOf(u64); |
| | 2004 | // data_blk: { |
| | 2005 | // const displacement = math.cast(i21, target_addr - this_addr) catch break :data_blk; |
| | 2006 | // // adr x17, disp |
| | 2007 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2008 | // // nop |
| | 2009 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32()); |
| | 2010 | // break :data_blk_outer; |
| | 2011 | // } |
| | 2012 | // data_blk: { |
| | 2013 | // const new_this_addr = this_addr + @sizeOf(u32); |
| | 2014 | // const displacement = math.cast(i21, target_addr - new_this_addr) catch break :data_blk; |
| | 2015 | // // nop |
| | 2016 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32()); |
| | 2017 | // // adr x17, disp |
| | 2018 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32()); |
| | 2019 | // break :data_blk_outer; |
| | 2020 | // } |
| | 2021 | // // Jump is too big, replace adr with adrp and add. |
| | 2022 | // const this_page = @intCast(i32, this_addr >> 12); |
| | 2023 | // const target_page = @intCast(i32, target_addr >> 12); |
| | 2024 | // const pages = @intCast(i21, target_page - this_page); |
| | 2025 | // mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32()); |
| | 2026 | // const narrowed = @truncate(u12, target_addr); |
| | 2027 | // mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32()); |
| | 2028 | // } |
| | 2029 | // // stp x16, x17, [sp, #-16]! |
| | 2030 | // code[8] = 0xf0; |
| | 2031 | // code[9] = 0x47; |
| | 2032 | // code[10] = 0xbf; |
| | 2033 | // code[11] = 0xa9; |
| | 2034 | // binder_blk_outer: { |
| | 2035 | // const got_index = self.got_entries_map.get(.{ |
| | 2036 | // .where = .undef, |
| | 2037 | // .where_index = self.dyld_stub_binder_index.?, |
| | 2038 | // }) orelse unreachable; |
| | 2039 | // const this_addr = stub_helper.addr + 3 * @sizeOf(u32); |
| | 2040 | // const target_addr = got.addr + got_index * @sizeOf(u64); |
| | 2041 | // binder_blk: { |
| | 2042 | // const displacement = math.divExact(u64, target_addr - this_addr, 4) catch break :binder_blk; |
| | 2043 | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| | 2044 | // // ldr x16, label |
| | 2045 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{ |
| | 2046 | // .literal = literal, |
| | 2047 | // }).toU32()); |
| | 2048 | // // nop |
| | 2049 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32()); |
| | 2050 | // break :binder_blk_outer; |
| | 2051 | // } |
| | 2052 | // binder_blk: { |
| | 2053 | // const new_this_addr = this_addr + @sizeOf(u32); |
| | 2054 | // const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch break :binder_blk; |
| | 2055 | // const literal = math.cast(u18, displacement) catch break :binder_blk; |
| | 2056 | // // Pad with nop to please division. |
| | 2057 | // // nop |
| | 2058 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32()); |
| | 2059 | // // ldr x16, label |
| | 2060 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2061 | // .literal = literal, |
| | 2062 | // }).toU32()); |
| | 2063 | // break :binder_blk_outer; |
| | 2064 | // } |
| | 2065 | // // Use adrp followed by ldr(immediate). |
| | 2066 | // const this_page = @intCast(i32, this_addr >> 12); |
| | 2067 | // const target_page = @intCast(i32, target_addr >> 12); |
| | 2068 | // const pages = @intCast(i21, target_page - this_page); |
| | 2069 | // mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32()); |
| | 2070 | // const narrowed = @truncate(u12, target_addr); |
| | 2071 | // const offset = try math.divExact(u12, narrowed, 8); |
| | 2072 | // mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{ |
| | 2073 | // .register = .{ |
| | 2074 | // .rn = .x16, |
| | 2075 | // .offset = aarch64.Instruction.LoadStoreOffset.imm(offset), |
| | 2076 | // }, |
| | 2077 | // }).toU32()); |
| | 2078 | // } |
| | 2079 | // // br x16 |
| | 2080 | // code[20] = 0x00; |
| | 2081 | // code[21] = 0x02; |
| | 2082 | // code[22] = 0x1f; |
| | 2083 | // code[23] = 0xd6; |
| | 2084 | // try self.base.file.?.pwriteAll(&code, stub_helper.offset); |
| | 2085 | // break :blk stub_helper.offset + 6 * @sizeOf(u32); |
| | 2086 | // }, |
| | 2087 | // else => unreachable, |
| | 2088 | // } |
| | 2089 | // } |
| | 2090 | |
| 1949 | fn writeStubHelperPreamble(self: *MachO) !void { | 2091 | fn writeStubHelperPreamble(self: *MachO) !void { |
| 1950 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 2092 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1951 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 2093 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | @@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void { |
| 2331 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); | 2473 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| 2332 | | 2474 | |
| 2333 | const size = sym.n_value; | 2475 | const size = sym.n_value; |
| 2334 | const code = try self.base.allocator.alloc(u8, size); | | |
| 2335 | defer self.base.allocator.free(code); | | |
| 2336 | mem.set(u8, code, 0); | | |
| 2337 | const alignment = (sym.n_desc >> 8) & 0x0f; | 2476 | const alignment = (sym.n_desc >> 8) & 0x0f; |
| 2338 | | 2477 | |
| 2339 | sym.n_value = 0; | 2478 | sym.n_value = 0; |
| ... | @@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2348 | const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; | 2487 | const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; |
| 2349 | resolv.local_sym_index = local_sym_index; | 2488 | resolv.local_sym_index = local_sym_index; |
| 2350 | | 2489 | |
| 2351 | const block = try self.base.allocator.create(TextBlock); | 2490 | _ = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2352 | block.* = TextBlock.empty; | | |
| 2353 | block.local_sym_index = local_sym_index; | | |
| 2354 | block.size = size; | | |
| 2355 | block.alignment = alignment; | | |
| 2356 | try self.managed_blocks.append(self.base.allocator, block); | | |
| 2357 | | | |
| 2358 | try block.code.appendSlice(self.base.allocator, code); | | |
| 2359 | | | |
| 2360 | // Update target section's metadata | | |
| 2361 | // TODO should we update segment's size here too? | | |
| 2362 | // How does it tie with incremental space allocs? | | |
| 2363 | const tseg = &self.load_commands.items[match.seg].Segment; | | |
| 2364 | const tsect = &tseg.sections.items[match.sect]; | | |
| 2365 | const new_alignment = math.max(tsect.@"align", block.alignment); | | |
| 2366 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); | | |
| 2367 | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size; | | |
| 2368 | tsect.size = new_size; | | |
| 2369 | tsect.@"align" = new_alignment; | | |
| 2370 | | | |
| 2371 | if (self.blocks.getPtr(match)) |last| { | | |
| 2372 | last.*.next = block; | | |
| 2373 | block.prev = last.*; | | |
| 2374 | last.* = block; | | |
| 2375 | } else { | | |
| 2376 | try self.blocks.putNoClobber(self.base.allocator, match, block); | | |
| 2377 | } | | |
| 2378 | } | 2491 | } |
| 2379 | | 2492 | |
| 2380 | // Third pass, resolve symbols in dynamic libraries. | 2493 | // Third pass, resolve symbols in dynamic libraries. |
| ... | @@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void { | ... | @@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2449 | // We create an empty atom for this symbol. | 2562 | // We create an empty atom for this symbol. |
| 2450 | // TODO perhaps we should special-case special symbols? Create a separate | 2563 | // TODO perhaps we should special-case special symbols? Create a separate |
| 2451 | // linked list of atoms? | 2564 | // linked list of atoms? |
| 2452 | const block = try self.base.allocator.create(TextBlock); | 2565 | _ = try self.createEmptyAtom(match, local_sym_index, 0, 0); |
| 2453 | block.* = TextBlock.empty; | | |
| 2454 | block.local_sym_index = local_sym_index; | | |
| 2455 | block.size = 0; | | |
| 2456 | block.alignment = 0; | | |
| 2457 | try self.managed_blocks.append(self.base.allocator, block); | | |
| 2458 | | | |
| 2459 | if (self.blocks.getPtr(match)) |last| { | | |
| 2460 | last.*.next = block; | | |
| 2461 | block.prev = last.*; | | |
| 2462 | last.* = block; | | |
| 2463 | } else { | | |
| 2464 | try self.blocks.putNoClobber(self.base.allocator, match, block); | | |
| 2465 | } | | |
| 2466 | } | 2566 | } |
| 2467 | | 2567 | |
| 2468 | for (self.unresolved.keys()) |index| { | 2568 | for (self.unresolved.keys()) |index| { |