authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-25 17:23:30+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-25 17:23:30+02:00
logee786e5c3c1171af082f9463ca46b9ed08d2601e
treeb3bf14f254ab889b98594606e7a6c95e6e134593
parentaf57ccbe279d73f91358ec28fb4afd54868650e8

macho: add GOT entries as actual atoms


3 files changed, 73 insertions(+), 231 deletions(-)

src/codegen.zig+17-45
...@@ -2668,24 +2668,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2668,24 +2668,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2668 if (self.air.value(callee)) |func_value| {2668 if (self.air.value(callee)) |func_value| {
2669 if (func_value.castTag(.function)) |func_payload| {2669 if (func_value.castTag(.function)) |func_payload| {
2670 const func = func_payload.data;2670 const func = func_payload.data;
2671 const got_addr = blk: {2671 // TODO I'm hacking my way through here by repurposing .memory for storing
2672 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;2672 // index to the GOT target symbol index.
2673 const got = seg.sections.items[macho_file.got_section_index.?];
2674 const got_index = macho_file.got_entries_map.get(.{
2675 .where = .local,
2676 .where_index = func.owner_decl.link.macho.local_sym_index,
2677 }) orelse unreachable;
2678 break :blk got.addr + got_index * @sizeOf(u64);
2679 };
2680 switch (arch) {2673 switch (arch) {
2681 .x86_64 => {2674 .x86_64 => {
2682 try self.genSetReg(Type.initTag(.u64), .rax, .{ .memory = got_addr });2675 try self.genSetReg(Type.initTag(.u64), .rax, .{
2676 .memory = func.owner_decl.link.macho.local_sym_index,
2677 });
2683 // callq *%rax2678 // callq *%rax
2684 try self.code.ensureCapacity(self.code.items.len + 2);2679 try self.code.ensureCapacity(self.code.items.len + 2);
2685 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });2680 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
2686 },2681 },
2687 .aarch64 => {2682 .aarch64 => {
2688 try self.genSetReg(Type.initTag(.u64), .x30, .{ .memory = got_addr });2683 try self.genSetReg(Type.initTag(.u64), .x30, .{
2684 .memory = func.owner_decl.link.macho.local_sym_index,
2685 });
2689 // blr x302686 // blr x30
2690 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());2687 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
2691 },2688 },
...@@ -4206,29 +4203,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4206,29 +4203,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4206 }).toU32());4203 }).toU32());
42074204
4208 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4205 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4209 // TODO this is super awkward. We are reversing the address of the GOT entry here.4206 // TODO I think the reloc might be in the wrong place.
4210 // We should probably have it cached or move the reloc adding somewhere else.
4211 const got_addr = blk: {
4212 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4213 const got = seg.sections.items[macho_file.got_section_index.?];
4214 break :blk got.addr;
4215 };
4216 const where_index = blk: for (macho_file.got_entries.items) |key, id| {
4217 if (got_addr + id * @sizeOf(u64) == addr) break :blk key.where_index;
4218 } else unreachable;
4219 const decl = macho_file.active_decl.?;4207 const decl = macho_file.active_decl.?;
4220 // Page reloc for adrp instruction.4208 // Page reloc for adrp instruction.
4221 try decl.link.macho.relocs.append(self.bin_file.allocator, .{4209 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4222 .offset = offset,4210 .offset = offset,
4223 .where = .local,4211 .where = .local,
4224 .where_index = where_index,4212 .where_index = @intCast(u32, addr),
4225 .payload = .{ .page = .{ .kind = .got } },4213 .payload = .{ .page = .{ .kind = .got } },
4226 });4214 });
4227 // Pageoff reloc for adrp instruction.4215 // Pageoff reloc for adrp instruction.
4228 try decl.link.macho.relocs.append(self.bin_file.allocator, .{4216 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4229 .offset = offset + 4,4217 .offset = offset + 4,
4230 .where = .local,4218 .where = .local,
4231 .where_index = where_index,4219 .where_index = @intCast(u32, addr),
4232 .payload = .{ .page_off = .{ .kind = .got } },4220 .payload = .{ .page_off = .{ .kind = .got } },
4233 });4221 });
4234 } else {4222 } else {
...@@ -4489,22 +4477,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4489,22 +4477,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4489 const offset = @intCast(u32, self.code.items.len);4477 const offset = @intCast(u32, self.code.items.len);
44904478
4491 if (self.bin_file.cast(link.File.MachO)) |macho_file| {4479 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
4492 // TODO this is super awkward. We are reversing the address of the GOT entry here.4480 // TODO I think the reloc might be in the wrong place.
4493 // We should probably have it cached or move the reloc adding somewhere else.
4494 const got_addr = blk: {
4495 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;
4496 const got = seg.sections.items[macho_file.got_section_index.?];
4497 break :blk got.addr;
4498 };
4499 const where_index = blk: for (macho_file.got_entries.items) |key, id| {
4500 if (got_addr + id * @sizeOf(u64) == x) break :blk key.where_index;
4501 } else unreachable;
4502 const decl = macho_file.active_decl.?;4481 const decl = macho_file.active_decl.?;
4503 // Load reloc for LEA instruction.4482 // Load reloc for LEA instruction.
4504 try decl.link.macho.relocs.append(self.bin_file.allocator, .{4483 try decl.link.macho.relocs.append(self.bin_file.allocator, .{
4505 .offset = offset - 4,4484 .offset = offset - 4,
4506 .where = .local,4485 .where = .local,
4507 .where_index = where_index,4486 .where_index = @intCast(u32, x),
4508 .payload = .{ .load = .{ .kind = .got } },4487 .payload = .{ .load = .{ .kind = .got } },
4509 });4488 });
4510 } else {4489 } else {
...@@ -4720,17 +4699,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -4720,17 +4699,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
4720 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];4699 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
4721 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;4700 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
4722 return MCValue{ .memory = got_addr };4701 return MCValue{ .memory = got_addr };
4723 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {4702 } else if (self.bin_file.cast(link.File.MachO)) |_| {
4724 const got_addr = blk: {4703 // TODO I'm hacking my way through here by repurposing .memory for storing
4725 const seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;4704 // index to the GOT target symbol index.
4726 const got = seg.sections.items[macho_file.got_section_index.?];4705 return MCValue{ .memory = decl.link.macho.local_sym_index };
4727 const got_index = macho_file.got_entries_map.get(.{
4728 .where = .local,
4729 .where_index = decl.link.macho.local_sym_index,
4730 }) orelse unreachable;
4731 break :blk got.addr + got_index * ptr_bytes;
4732 };
4733 return MCValue{ .memory = got_addr };
4734 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {4706 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
4735 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;4707 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
4736 return MCValue{ .memory = got_addr };4708 return MCValue{ .memory = got_addr };
src/link/MachO.zig+41-179
...@@ -154,17 +154,13 @@ stub_preamble_sym_index: ?u32 = null,...@@ -154,17 +154,13 @@ stub_preamble_sym_index: ?u32 = null,
154strtab: std.ArrayListUnmanaged(u8) = .{},154strtab: std.ArrayListUnmanaged(u8) = .{},
155strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},155strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
156156
157got_entries: std.ArrayListUnmanaged(GotIndirectionKey) = .{},157got_entries_map: std.AutoArrayHashMapUnmanaged(GotIndirectionKey, *TextBlock) = .{},
158got_entries_map: std.AutoHashMapUnmanaged(GotIndirectionKey, u32) = .{},
159
160got_entries_free_list: std.ArrayListUnmanaged(u32) = .{},
161158
162stubs: std.ArrayListUnmanaged(u32) = .{},159stubs: std.ArrayListUnmanaged(u32) = .{},
163stubs_map: std.AutoHashMapUnmanaged(u32, u32) = .{},160stubs_map: std.AutoHashMapUnmanaged(u32, u32) = .{},
164161
165error_flags: File.ErrorFlags = File.ErrorFlags{},162error_flags: File.ErrorFlags = File.ErrorFlags{},
166163
167got_entries_count_dirty: bool = false,
168load_commands_dirty: bool = false,164load_commands_dirty: bool = false,
169rebase_info_dirty: bool = false,165rebase_info_dirty: bool = false,
170binding_info_dirty: bool = false,166binding_info_dirty: bool = false,
...@@ -876,7 +872,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -876,7 +872,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
876 self.error_flags.no_entry_point_found = false;872 self.error_flags.no_entry_point_found = false;
877 }873 }
878874
879 assert(!self.got_entries_count_dirty);
880 assert(!self.load_commands_dirty);875 assert(!self.load_commands_dirty);
881 assert(!self.rebase_info_dirty);876 assert(!self.rebase_info_dirty);
882 assert(!self.binding_info_dirty);877 assert(!self.binding_info_dirty);
...@@ -1731,16 +1726,9 @@ fn allocateTextSegment(self: *MachO) !void {...@@ -1731,16 +1726,9 @@ fn allocateTextSegment(self: *MachO) !void {
17311726
1732fn allocateDataConstSegment(self: *MachO) !void {1727fn allocateDataConstSegment(self: *MachO) !void {
1733 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;1728 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
1734 const nentries = @intCast(u32, self.got_entries.items.len);
1735
1736 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1729 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1737 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;1730 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
1738 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;1731 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
1739
1740 // Set got size
1741 const got = &seg.sections.items[self.got_section_index.?];
1742 got.size += nentries * @sizeOf(u64);
1743
1744 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);1732 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
1745}1733}
17461734
...@@ -1927,7 +1915,7 @@ fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32...@@ -1927,7 +1915,7 @@ fn createEmptyAtom(self: *MachO, local_sym_index: u32, size: u64, alignment: u32
1927 return atom;1915 return atom;
1928}1916}
19291917
1930fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {1918pub fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
1931 // TODO converge with `allocateTextBlock`1919 // TODO converge with `allocateTextBlock`
1932 const seg = self.load_commands.items[match.seg].Segment;1920 const seg = self.load_commands.items[match.seg].Segment;
1933 const sect = seg.sections.items[match.sect];1921 const sect = seg.sections.items[match.sect];
...@@ -1936,7 +1924,8 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {...@@ -1936,7 +1924,8 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
1936 const last_atom_sym = self.locals.items[last.local_sym_index];1924 const last_atom_sym = self.locals.items[last.local_sym_index];
1937 break :blk last_atom_sym.n_value + last.size;1925 break :blk last_atom_sym.n_value + last.size;
1938 } else sect.addr;1926 } else sect.addr;
1939 const atom_alignment = try math.powi(u32, 2, atom.alignment);1927 // const atom_alignment = try math.powi(u32, 2, atom.alignment); TODO
1928 const atom_alignment = math.powi(u32, 2, atom.alignment) catch unreachable;
1940 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);1929 const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment);
1941 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });1930 log.debug("allocating atom for symbol {s} at address 0x{x}", .{ self.getString(sym.n_strx), vaddr });
19421931
...@@ -1956,7 +1945,7 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {...@@ -1956,7 +1945,7 @@ fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 {
1956 return vaddr;1945 return vaddr;
1957}1946}
19581947
1959fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {1948pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1960 const seg = self.load_commands.items[match.seg].Segment;1949 const seg = self.load_commands.items[match.seg].Segment;
1961 const sect = seg.sections.items[match.sect];1950 const sect = seg.sections.items[match.sect];
1962 const sym = self.locals.items[atom.local_sym_index];1951 const sym = self.locals.items[atom.local_sym_index];
...@@ -1967,7 +1956,7 @@ fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {...@@ -1967,7 +1956,7 @@ fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1967 try self.writeLocalSymbol(atom.local_sym_index);1956 try self.writeLocalSymbol(atom.local_sym_index);
1968}1957}
19691958
1970fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {1959pub fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1971 // Update target section's metadata1960 // Update target section's metadata
1972 // TODO should we update segment's size here too?1961 // TODO should we update segment's size here too?
1973 // How does it tie with incremental space allocs?1962 // How does it tie with incremental space allocs?
...@@ -1988,7 +1977,7 @@ fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !v...@@ -1988,7 +1977,7 @@ fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !v
1988 }1977 }
1989}1978}
19901979
1991fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {1980pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
1992 const local_sym_index = @intCast(u32, self.locals.items.len);1981 const local_sym_index = @intCast(u32, self.locals.items.len);
1993 try self.locals.append(self.base.allocator, .{1982 try self.locals.append(self.base.allocator, .{
1994 .n_strx = try self.makeString("got_entry"),1983 .n_strx = try self.makeString("got_entry"),
...@@ -2804,15 +2793,12 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2804,15 +2793,12 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2804 }2793 }
28052794
2806 // Add dyld_stub_binder as the final GOT entry.2795 // Add dyld_stub_binder as the final GOT entry.
2807 const got_index = @intCast(u32, self.got_entries.items.len);
2808 const got_entry = GotIndirectionKey{2796 const got_entry = GotIndirectionKey{
2809 .where = .undef,2797 .where = .undef,
2810 .where_index = self.dyld_stub_binder_index.?,2798 .where_index = self.dyld_stub_binder_index.?,
2811 };2799 };
2812 try self.got_entries.append(self.base.allocator, got_entry);
2813 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
2814
2815 const atom = try self.createGotAtom(got_entry);2800 const atom = try self.createGotAtom(got_entry);
2801 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, atom);
2816 const match = MatchingSection{2802 const match = MatchingSection{
2817 .seg = self.data_const_segment_cmd_index.?,2803 .seg = self.data_const_segment_cmd_index.?,
2818 .sect = self.got_section_index.?,2804 .sect = self.got_section_index.?,
...@@ -2917,7 +2903,6 @@ fn flushZld(self: *MachO) !void {...@@ -2917,7 +2903,6 @@ fn flushZld(self: *MachO) !void {
2917 sect.offset = 0;2903 sect.offset = 0;
2918 }2904 }
29192905
2920 try self.writeGotEntries();
2921 try self.setEntryPoint();2906 try self.setEntryPoint();
2922 try self.writeRebaseInfoTableZld();2907 try self.writeRebaseInfoTableZld();
2923 try self.writeBindInfoTableZld();2908 try self.writeBindInfoTableZld();
...@@ -2952,29 +2937,6 @@ fn flushZld(self: *MachO) !void {...@@ -2952,29 +2937,6 @@ fn flushZld(self: *MachO) !void {
2952 }2937 }
2953}2938}
29542939
2955fn writeGotEntries(self: *MachO) !void {
2956 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
2957 const sect = seg.sections.items[self.got_section_index.?];
2958
2959 var buffer = try self.base.allocator.alloc(u8, self.got_entries.items.len * @sizeOf(u64));
2960 defer self.base.allocator.free(buffer);
2961
2962 var stream = std.io.fixedBufferStream(buffer);
2963 var writer = stream.writer();
2964
2965 for (self.got_entries.items) |key| {
2966 const address: u64 = switch (key.where) {
2967 .local => self.locals.items[key.where_index].n_value,
2968 .undef => 0,
2969 };
2970 try writer.writeIntLittle(u64, address);
2971 }
2972
2973 log.debug("writing GOT pointers at 0x{x} to 0x{x}", .{ sect.offset, sect.offset + buffer.len });
2974
2975 try self.base.file.?.pwriteAll(buffer, sect.offset);
2976}
2977
2978fn setEntryPoint(self: *MachO) !void {2940fn setEntryPoint(self: *MachO) !void {
2979 if (self.base.options.output_mode != .Exe) return;2941 if (self.base.options.output_mode != .Exe) return;
29802942
...@@ -3028,22 +2990,6 @@ fn writeRebaseInfoTableZld(self: *MachO) !void {...@@ -3028,22 +2990,6 @@ fn writeRebaseInfoTableZld(self: *MachO) !void {
3028 }2990 }
3029 }2991 }
30302992
3031 if (self.got_section_index) |idx| {
3032 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
3033 const sect = seg.sections.items[idx];
3034 const base_offset = sect.addr - seg.inner.vmaddr;
3035 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
3036
3037 for (self.got_entries.items) |entry, i| {
3038 if (entry.where == .undef) continue;
3039
3040 try pointers.append(.{
3041 .offset = base_offset + i * @sizeOf(u64),
3042 .segment_id = segment_id,
3043 });
3044 }
3045 }
3046
3047 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);2993 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
30482994
3049 const size = try bind.rebaseInfoSize(pointers.items);2995 const size = try bind.rebaseInfoSize(pointers.items);
...@@ -3068,25 +3014,6 @@ fn writeBindInfoTableZld(self: *MachO) !void {...@@ -3068,25 +3014,6 @@ fn writeBindInfoTableZld(self: *MachO) !void {
3068 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);3014 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
3069 defer pointers.deinit();3015 defer pointers.deinit();
30703016
3071 if (self.got_section_index) |idx| {
3072 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
3073 const sect = seg.sections.items[idx];
3074 const base_offset = sect.addr - seg.inner.vmaddr;
3075 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
3076
3077 for (self.got_entries.items) |entry, i| {
3078 if (entry.where == .local) continue;
3079
3080 const sym = self.undefs.items[entry.where_index];
3081 try pointers.append(.{
3082 .offset = base_offset + i * @sizeOf(u64),
3083 .segment_id = segment_id,
3084 .dylib_ordinal = @divExact(sym.n_desc, macho.N_SYMBOL_RESOLVER),
3085 .name = self.getString(sym.n_strx),
3086 });
3087 }
3088 }
3089
3090 {3017 {
3091 var it = self.blocks.iterator();3018 var it = self.blocks.iterator();
3092 while (it.next()) |entry| {3019 while (it.next()) |entry| {
...@@ -3319,7 +3246,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -3319,7 +3246,7 @@ fn writeSymbolTable(self: *MachO) !void {
3319 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];3246 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
33203247
3321 const nstubs = @intCast(u32, self.stubs.items.len);3248 const nstubs = @intCast(u32, self.stubs.items.len);
3322 const ngot_entries = @intCast(u32, self.got_entries.items.len);3249 const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
33233250
3324 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);3251 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3325 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;3252 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
...@@ -3344,10 +3271,10 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -3344,10 +3271,10 @@ fn writeSymbolTable(self: *MachO) !void {
3344 }3271 }
33453272
3346 got.reserved1 = nstubs;3273 got.reserved1 = nstubs;
3347 for (self.got_entries.items) |entry| {3274 for (self.got_entries_map.keys()) |key| {
3348 switch (entry.where) {3275 switch (key.where) {
3349 .undef => {3276 .undef => {
3350 try writer.writeIntLittle(u32, dysymtab.iundefsym + entry.where_index);3277 try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
3351 },3278 },
3352 .local => {3279 .local => {
3353 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);3280 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
...@@ -3373,9 +3300,7 @@ pub fn deinit(self: *MachO) void {...@@ -3373,9 +3300,7 @@ pub fn deinit(self: *MachO) void {
3373 }3300 }
33743301
3375 self.section_ordinals.deinit(self.base.allocator);3302 self.section_ordinals.deinit(self.base.allocator);
3376 self.got_entries.deinit(self.base.allocator);
3377 self.got_entries_map.deinit(self.base.allocator);3303 self.got_entries_map.deinit(self.base.allocator);
3378 self.got_entries_free_list.deinit(self.base.allocator);
3379 self.stubs.deinit(self.base.allocator);3304 self.stubs.deinit(self.base.allocator);
3380 self.stubs_map.deinit(self.base.allocator);3305 self.stubs_map.deinit(self.base.allocator);
3381 self.strtab_dir.deinit(self.base.allocator);3306 self.strtab_dir.deinit(self.base.allocator);
...@@ -3539,8 +3464,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -3539,8 +3464,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
3539 if (decl.link.macho.local_sym_index != 0) return;3464 if (decl.link.macho.local_sym_index != 0) return;
35403465
3541 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);3466 try self.locals.ensureUnusedCapacity(self.base.allocator, 1);
3542 try self.got_entries.ensureUnusedCapacity(self.base.allocator, 1);
3543
3544 try self.decls.putNoClobber(self.base.allocator, decl, {});3467 try self.decls.putNoClobber(self.base.allocator, decl, {});
35453468
3546 if (self.locals_free_list.popOrNull()) |i| {3469 if (self.locals_free_list.popOrNull()) |i| {
...@@ -3552,20 +3475,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -3552,20 +3475,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
3552 _ = self.locals.addOneAssumeCapacity();3475 _ = self.locals.addOneAssumeCapacity();
3553 }3476 }
35543477
3555 const got_index: u32 = blk: {
3556 if (self.got_entries_free_list.popOrNull()) |i| {
3557 log.debug("reusing GOT entry index {d} for {s}", .{ i, decl.name });
3558 break :blk i;
3559 } else {
3560 const got_index = @intCast(u32, self.got_entries.items.len);
3561 log.debug("allocating GOT entry index {d} for {s}", .{ got_index, decl.name });
3562 _ = self.got_entries.addOneAssumeCapacity();
3563 self.got_entries_count_dirty = true;
3564 self.rebase_info_dirty = true;
3565 break :blk got_index;
3566 }
3567 };
3568
3569 self.locals.items[decl.link.macho.local_sym_index] = .{3478 self.locals.items[decl.link.macho.local_sym_index] = .{
3570 .n_strx = 0,3479 .n_strx = 0,
3571 .n_type = 0,3480 .n_type = 0,
...@@ -3573,12 +3482,19 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -3573,12 +3482,19 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
3573 .n_desc = 0,3482 .n_desc = 0,
3574 .n_value = 0,3483 .n_value = 0,
3575 };3484 };
3576 const got_entry = GotIndirectionKey{3485
3486 // TODO try popping from free list first before allocating a new GOT atom.
3487 const key = GotIndirectionKey{
3577 .where = .local,3488 .where = .local,
3578 .where_index = decl.link.macho.local_sym_index,3489 .where_index = decl.link.macho.local_sym_index,
3579 };3490 };
3580 self.got_entries.items[got_index] = got_entry;3491 const got_atom = try self.createGotAtom(key);
3581 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);3492 _ = try self.allocateAtom(got_atom, .{
3493 .seg = self.data_const_segment_cmd_index.?,
3494 .sect = self.got_section_index.?,
3495 });
3496 try self.got_entries_map.put(self.base.allocator, key, got_atom);
3497 self.rebase_info_dirty = true;
3582}3498}
35833499
3584pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {3500pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
...@@ -3760,11 +3676,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3760,11 +3676,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
37603676
3761 if (vaddr != symbol.n_value) {3677 if (vaddr != symbol.n_value) {
3762 log.debug(" (writing new GOT entry)", .{});3678 log.debug(" (writing new GOT entry)", .{});
3763 const got_index = self.got_entries_map.get(.{3679 const match = MatchingSection{
3680 .seg = self.data_const_segment_cmd_index.?,
3681 .sect = self.got_section_index.?,
3682 };
3683 const got_atom = self.got_entries_map.get(.{
3764 .where = .local,3684 .where = .local,
3765 .where_index = decl.link.macho.local_sym_index,3685 .where_index = decl.link.macho.local_sym_index,
3766 }) orelse unreachable;3686 }) orelse unreachable;
3767 try self.writeGotEntry(got_index);3687 // _ = try self.allocateAtom(got_atom, match);
3688 try self.writeAtom(got_atom, match);
3768 }3689 }
37693690
3770 symbol.n_value = vaddr;3691 symbol.n_value = vaddr;
...@@ -3802,11 +3723,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3802,11 +3723,16 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3802 .n_desc = 0,3723 .n_desc = 0,
3803 .n_value = addr,3724 .n_value = addr,
3804 };3725 };
3805 const got_index = self.got_entries_map.get(.{3726 const match = MatchingSection{
3727 .seg = self.data_const_segment_cmd_index.?,
3728 .sect = self.got_section_index.?,
3729 };
3730 const got_atom = self.got_entries_map.get(.{
3806 .where = .local,3731 .where = .local,
3807 .where_index = decl.link.macho.local_sym_index,3732 .where_index = decl.link.macho.local_sym_index,
3808 }) orelse unreachable;3733 }) orelse unreachable;
3809 try self.writeGotEntry(got_index);3734 // _ = try self.allocateAtom(got_atom, match);
3735 try self.writeAtom(got_atom, match);
38103736
3811 try self.writeLocalSymbol(decl.link.macho.local_sym_index);3737 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
3812 if (self.d_sym) |*ds|3738 if (self.d_sym) |*ds|
...@@ -3955,13 +3881,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -3955,13 +3881,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
3955 if (decl.link.macho.local_sym_index != 0) {3881 if (decl.link.macho.local_sym_index != 0) {
3956 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};3882 self.locals_free_list.append(self.base.allocator, decl.link.macho.local_sym_index) catch {};
39573883
3958 const got_key = GotIndirectionKey{3884 // TODO free GOT atom here.
3959 .where = .local,
3960 .where_index = decl.link.macho.local_sym_index,
3961 };
3962 const got_index = self.got_entries_map.get(got_key) orelse unreachable;
3963 _ = self.got_entries_map.remove(got_key);
3964 self.got_entries_free_list.append(self.base.allocator, got_index) catch {};
39653885
3966 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;3886 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
3967 decl.link.macho.local_sym_index = 0;3887 decl.link.macho.local_sym_index = 0;
...@@ -4789,29 +4709,6 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta...@@ -4789,29 +4709,6 @@ fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, sta
4789 return st;4709 return st;
4790}4710}
47914711
4792fn writeGotEntry(self: *MachO, index: usize) !void {
4793 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4794 const sect = &seg.sections.items[self.got_section_index.?];
4795 const off = sect.offset + @sizeOf(u64) * index;
4796
4797 if (self.got_entries_count_dirty) {
4798 // TODO relocate.
4799 self.got_entries_count_dirty = false;
4800 }
4801
4802 const got_entry = self.got_entries.items[index];
4803 const sym = switch (got_entry.where) {
4804 .local => self.locals.items[got_entry.where_index],
4805 .undef => self.undefs.items[got_entry.where_index],
4806 };
4807 log.debug("writing offset table entry [ 0x{x} => 0x{x} ({s}) ]", .{
4808 off,
4809 sym.n_value,
4810 self.getString(sym.n_strx),
4811 });
4812 try self.base.file.?.pwriteAll(mem.asBytes(&sym.n_value), off);
4813}
4814
4815fn relocateSymbolTable(self: *MachO) !void {4712fn relocateSymbolTable(self: *MachO) !void {
4816 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;4713 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4817 const nlocals = self.locals.items.len;4714 const nlocals = self.locals.items.len;
...@@ -4901,7 +4798,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -4901,7 +4798,7 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
4901 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;4798 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
49024799
4903 const nstubs = @intCast(u32, self.stubs.items.len);4800 const nstubs = @intCast(u32, self.stubs.items.len);
4904 const ngot_entries = @intCast(u32, self.got_entries.items.len);4801 const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
4905 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);4802 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);
4906 const nindirectsyms = nstubs * 2 + ngot_entries;4803 const nindirectsyms = nstubs * 2 + ngot_entries;
4907 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));4804 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));
...@@ -4927,10 +4824,10 @@ fn writeIndirectSymbolTable(self: *MachO) !void {...@@ -4927,10 +4824,10 @@ fn writeIndirectSymbolTable(self: *MachO) !void {
4927 }4824 }
49284825
4929 got.reserved1 = nstubs;4826 got.reserved1 = nstubs;
4930 for (self.got_entries.items) |entry| {4827 for (self.got_entries_map.keys()) |key| {
4931 switch (entry.where) {4828 switch (key.where) {
4932 .undef => {4829 .undef => {
4933 try writer.writeIntLittle(u32, dysymtab.iundefsym + entry.where_index);4830 try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
4934 },4831 },
4935 .local => {4832 .local => {
4936 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);4833 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
...@@ -5147,22 +5044,6 @@ fn writeRebaseInfoTable(self: *MachO) !void {...@@ -5147,22 +5044,6 @@ fn writeRebaseInfoTable(self: *MachO) !void {
5147 }5044 }
5148 }5045 }
51495046
5150 if (self.got_section_index) |idx| {
5151 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
5152 const sect = seg.sections.items[idx];
5153 const base_offset = sect.addr - seg.inner.vmaddr;
5154 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
5155
5156 for (self.got_entries.items) |entry, i| {
5157 if (entry.where == .undef) continue;
5158
5159 try pointers.append(.{
5160 .offset = base_offset + i * @sizeOf(u64),
5161 .segment_id = segment_id,
5162 });
5163 }
5164 }
5165
5166 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);5047 std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp);
51675048
5168 const size = try bind.rebaseInfoSize(pointers.items);5049 const size = try bind.rebaseInfoSize(pointers.items);
...@@ -5199,25 +5080,6 @@ fn writeBindInfoTable(self: *MachO) !void {...@@ -5199,25 +5080,6 @@ fn writeBindInfoTable(self: *MachO) !void {
5199 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);5080 var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator);
5200 defer pointers.deinit();5081 defer pointers.deinit();
52015082
5202 if (self.got_section_index) |idx| {
5203 const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
5204 const sect = seg.sections.items[idx];
5205 const base_offset = sect.addr - seg.inner.vmaddr;
5206 const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?);
5207
5208 for (self.got_entries.items) |entry, i| {
5209 if (entry.where == .local) continue;
5210
5211 const sym = self.undefs.items[entry.where_index];
5212 try pointers.append(.{
5213 .offset = base_offset + i * @sizeOf(u64),
5214 .segment_id = segment_id,
5215 .dylib_ordinal = @divExact(sym.n_desc, macho.N_SYMBOL_RESOLVER),
5216 .name = self.getString(sym.n_strx),
5217 });
5218 }
5219 }
5220
5221 {5083 {
5222 var it = self.blocks.iterator();5084 var it = self.blocks.iterator();
5223 while (it.next()) |entry| {5085 while (it.next()) |entry| {
src/link/MachO/TextBlock.zig+15-7
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const TextBlock = @This();1const TextBlock = @This();
22
3const std = @import("std");3const std = @import("std");
4const build_options = @import("build_options");
4const aarch64 = @import("../../codegen/aarch64.zig");5const aarch64 = @import("../../codegen/aarch64.zig");
5const assert = std.debug.assert;6const assert = std.debug.assert;
6const commands = @import("commands.zig");7const commands = @import("commands.zig");
...@@ -830,9 +831,18 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R...@@ -830,9 +831,18 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
830 };831 };
831 if (context.macho_file.got_entries_map.contains(key)) break :blk;832 if (context.macho_file.got_entries_map.contains(key)) break :blk;
832833
833 const got_index = @intCast(u32, context.macho_file.got_entries.items.len);834 const atom = try context.macho_file.createGotAtom(key);
834 try context.macho_file.got_entries.append(context.allocator, key);835 try context.macho_file.got_entries_map.putNoClobber(context.macho_file.base.allocator, key, atom);
835 try context.macho_file.got_entries_map.putNoClobber(context.allocator, key, got_index);836 const match = MachO.MatchingSection{
837 .seg = context.macho_file.data_const_segment_cmd_index.?,
838 .sect = context.macho_file.got_section_index.?,
839 };
840 if (!(build_options.is_stage1 and context.macho_file.base.options.use_stage1)) {
841 _ = try context.macho_file.allocateAtom(atom, match);
842 try context.macho_file.writeAtom(atom, match);
843 } else {
844 try context.macho_file.allocateAtomStage1(atom, match);
845 }
836 } else if (parsed_rel.payload == .unsigned) {846 } else if (parsed_rel.payload == .unsigned) {
837 switch (parsed_rel.where) {847 switch (parsed_rel.where) {
838 .undef => {848 .undef => {
...@@ -1082,9 +1092,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {...@@ -1082,9 +1092,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
1082 };1092 };
10831093
1084 if (is_via_got) {1094 if (is_via_got) {
1085 const dc_seg = macho_file.load_commands.items[macho_file.data_const_segment_cmd_index.?].Segment;1095 const atom = macho_file.got_entries_map.get(.{
1086 const got = dc_seg.sections.items[macho_file.got_section_index.?];
1087 const got_index = macho_file.got_entries_map.get(.{
1088 .where = switch (rel.where) {1096 .where = switch (rel.where) {
1089 .local => .local,1097 .local => .local,
1090 .undef => .undef,1098 .undef => .undef,
...@@ -1099,7 +1107,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {...@@ -1099,7 +1107,7 @@ pub fn resolveRelocs(self: *TextBlock, macho_file: *MachO) !void {
1099 log.err(" this is an internal linker error", .{});1107 log.err(" this is an internal linker error", .{});
1100 return error.FailedToResolveRelocationTarget;1108 return error.FailedToResolveRelocationTarget;
1101 };1109 };
1102 break :blk got.addr + got_index * @sizeOf(u64);1110 break :blk macho_file.locals.items[atom.local_sym_index].n_value;
1103 }1111 }
11041112
1105 switch (rel.where) {1113 switch (rel.where) {