| ... | ... | @@ -265,11 +265,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 265 | 265 | try self.resolveSymbols(); |
| 266 | 266 | try self.updateMetadata(); |
| 267 | 267 | try self.sortSections(); |
| 268 | try self.allocateTextSegment(); |
| 269 | try self.allocateDataConstSegment(); |
| 270 | try self.allocateDataSegment(); |
| 271 | self.allocateLinkeditSegment(); |
| 272 | try self.allocateSymbols(); |
| 268 | 273 | self.printSymtab(); |
| 269 | | // try self.allocateTextSegment(); |
| 270 | | // try self.allocateDataConstSegment(); |
| 271 | | // try self.allocateDataSegment(); |
| 272 | | // self.allocateLinkeditSegment(); |
| 273 | 274 | // try self.writeStubHelperCommon(); |
| 274 | 275 | // try self.doRelocs(); |
| 275 | 276 | // try self.flush(); |
| ... | ... | @@ -816,7 +817,11 @@ fn allocateTextSegment(self: *Zld) !void { |
| 816 | 817 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 817 | 818 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 818 | 819 | // correspond to the worst-case upper bound). |
| 819 | | const nstubs = @intCast(u32, self.externs.count()); |
| 820 | var nexterns: u32 = 0; |
| 821 | for (self.symtab.items()) |entry| { |
| 822 | if (entry.value.tag != .Import) continue; |
| 823 | nexterns += 1; |
| 824 | } |
| 820 | 825 | |
| 821 | 826 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 822 | 827 | seg.inner.fileoff = 0; |
| ... | ... | @@ -825,14 +830,14 @@ fn allocateTextSegment(self: *Zld) !void { |
| 825 | 830 | // Set stubs and stub_helper sizes |
| 826 | 831 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 827 | 832 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; |
| 828 | | stubs.size += nstubs * stubs.reserved2; |
| 833 | stubs.size += nexterns * stubs.reserved2; |
| 829 | 834 | |
| 830 | 835 | const stub_size: u4 = switch (self.arch.?) { |
| 831 | 836 | .x86_64 => 10, |
| 832 | 837 | .aarch64 => 3 * @sizeOf(u32), |
| 833 | 838 | else => unreachable, |
| 834 | 839 | }; |
| 835 | | stub_helper.size += nstubs * stub_size; |
| 840 | stub_helper.size += nexterns * stub_size; |
| 836 | 841 | |
| 837 | 842 | var sizeofcmds: u64 = 0; |
| 838 | 843 | for (self.load_commands.items) |lc| { |
| ... | ... | @@ -870,7 +875,11 @@ fn allocateDataConstSegment(self: *Zld) !void { |
| 870 | 875 | // TODO This should be worked out by scanning the relocations in the __text sections of all |
| 871 | 876 | // combined object files. For the time being, assume all externs are GOT entries (this is wasting space but |
| 872 | 877 | // should correspond to the worst-case upper bound). |
| 873 | | const nexterns = @intCast(u32, self.externs.count()); |
| 878 | var nexterns: u32 = 0; |
| 879 | for (self.symtab.items()) |entry| { |
| 880 | if (entry.value.tag != .Import) continue; |
| 881 | nexterns += 1; |
| 882 | } |
| 874 | 883 | |
| 875 | 884 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 876 | 885 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| ... | ... | @@ -891,7 +900,11 @@ fn allocateDataSegment(self: *Zld) !void { |
| 891 | 900 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 892 | 901 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 893 | 902 | // correspond to the worst-case upper bound). |
| 894 | | const nstubs = @intCast(u32, self.externs.count()); |
| 903 | var nexterns: u32 = 0; |
| 904 | for (self.symtab.items()) |entry| { |
| 905 | if (entry.value.tag != .Import) continue; |
| 906 | nexterns += 1; |
| 907 | } |
| 895 | 908 | |
| 896 | 909 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 897 | 910 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| ... | ... | @@ -900,7 +913,7 @@ fn allocateDataSegment(self: *Zld) !void { |
| 900 | 913 | // Set la_symbol_ptr and data size |
| 901 | 914 | const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?]; |
| 902 | 915 | const data = &seg.sections.items[self.data_section_index.?]; |
| 903 | | la_symbol_ptr.size += nstubs * @sizeOf(u64); |
| 916 | la_symbol_ptr.size += nexterns * @sizeOf(u64); |
| 904 | 917 | data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder |
| 905 | 918 | |
| 906 | 919 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| ... | ... | @@ -933,6 +946,60 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 933 | 946 | seg.inner.vmsize = seg_size_aligned; |
| 934 | 947 | } |
| 935 | 948 | |
| 949 | fn allocateSymbols(self: *Zld) !void { |
| 950 | for (self.symtab.items()) |*entry| { |
| 951 | if (entry.value.tag == .Import) continue; |
| 952 | |
| 953 | const object_id = entry.value.file orelse unreachable; |
| 954 | const index = entry.value.index orelse unreachable; |
| 955 | |
| 956 | const object = self.objects.items[object_id]; |
| 957 | const source_sym = object.symtab.items[index]; |
| 958 | const source_sect_id = source_sym.inner.n_sect - 1; |
| 959 | |
| 960 | // TODO I am more and more convinced we should store the mapping as part of the Object struct. |
| 961 | const target_mapping = self.mappings.get(.{ |
| 962 | .object_id = object_id, |
| 963 | .source_sect_id = source_sect_id, |
| 964 | }) orelse { |
| 965 | if (self.unhandled_sections.get(.{ |
| 966 | .object_id = object_id, |
| 967 | .source_sect_id = source_sect_id, |
| 968 | }) != null) continue; |
| 969 | |
| 970 | log.err("section not mapped for symbol '{s}': {}", .{ entry.key, source_sym }); |
| 971 | return error.SectionNotMappedForSymbol; |
| 972 | }; |
| 973 | |
| 974 | const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 975 | const source_sect = source_seg.sections.items[source_sect_id]; |
| 976 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; |
| 977 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; |
| 978 | const target_addr = target_sect.addr + target_mapping.offset; |
| 979 | const n_value = source_sym.inner.n_value - source_sect.addr + target_addr; |
| 980 | |
| 981 | log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 982 | |
| 983 | // TODO there might be a more generic way of doing this. |
| 984 | var n_sect: u8 = 0; |
| 985 | for (self.load_commands.items) |cmd, cmd_id| { |
| 986 | if (cmd != .Segment) break; |
| 987 | if (cmd_id == target_mapping.target_seg_id) { |
| 988 | n_sect += @intCast(u8, target_mapping.target_sect_id) + 1; |
| 989 | break; |
| 990 | } |
| 991 | n_sect += @intCast(u8, cmd.Segment.sections.items.len); |
| 992 | } |
| 993 | |
| 994 | entry.value.inner.n_value = n_value; |
| 995 | entry.value.inner.n_sect = n_sect; |
| 996 | |
| 997 | // TODO This will need to be redone for any CU locals that end up in the final symbol table. |
| 998 | // This could be part of writing debug info since this is the only valid reason (is it?) for |
| 999 | // including CU locals in the final MachO symbol table. |
| 1000 | } |
| 1001 | } |
| 1002 | |
| 936 | 1003 | fn writeStubHelperCommon(self: *Zld) !void { |
| 937 | 1004 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 938 | 1005 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |