| ... | ... | @@ -770,34 +770,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 770 | 770 | |
| 771 | 771 | for (self.pending_updates.items) |update| { |
| 772 | 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 | 773 | .add_stub_entry => |stub_index| { |
| 802 | 774 | try self.writeStub(stub_index); |
| 803 | 775 | try self.writeStubInStubHelper(stub_index); |
| ... | ... | @@ -805,6 +777,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 805 | 777 | self.rebase_info_dirty = true; |
| 806 | 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 | 829 | defer tracy.end(); |
| 857 | 830 | |
| 858 | 831 | try self.setEntryPoint(); |
| 832 | try self.writeTextBlocks(); |
| 859 | 833 | try self.writeRebaseInfoTable(); |
| 860 | 834 | try self.writeBindInfoTable(); |
| 861 | 835 | try self.writeLazyBindInfoTable(); |
| ... | ... | @@ -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 | 2091 | fn writeStubHelperPreamble(self: *MachO) !void { |
| 1950 | 2092 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1951 | 2093 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | ... | @@ -2331,9 +2473,6 @@ fn resolveSymbols(self: *MachO) !void { |
| 2331 | 2473 | _ = try self.section_ordinals.getOrPut(self.base.allocator, match); |
| 2332 | 2474 | |
| 2333 | 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 | 2476 | const alignment = (sym.n_desc >> 8) & 0x0f; |
| 2338 | 2477 | |
| 2339 | 2478 | sym.n_value = 0; |
| ... | ... | @@ -2348,33 +2487,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2348 | 2487 | const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable; |
| 2349 | 2488 | resolv.local_sym_index = local_sym_index; |
| 2350 | 2489 | |
| 2351 | | const block = try self.base.allocator.create(TextBlock); |
| 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 | | } |
| 2490 | _ = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2378 | 2491 | } |
| 2379 | 2492 | |
| 2380 | 2493 | // Third pass, resolve symbols in dynamic libraries. |
| ... | ... | @@ -2449,20 +2562,7 @@ fn resolveSymbols(self: *MachO) !void { |
| 2449 | 2562 | // We create an empty atom for this symbol. |
| 2450 | 2563 | // TODO perhaps we should special-case special symbols? Create a separate |
| 2451 | 2564 | // linked list of atoms? |
| 2452 | | const block = try self.base.allocator.create(TextBlock); |
| 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 | | } |
| 2565 | _ = try self.createEmptyAtom(match, local_sym_index, 0, 0); |
| 2466 | 2566 | } |
| 2467 | 2567 | |
| 2468 | 2568 | for (self.unresolved.keys()) |index| { |