| ... | @@ -265,11 +265,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { | ... | @@ -265,11 +265,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 265 | try self.resolveSymbols(); | 265 | try self.resolveSymbols(); |
| 266 | try self.updateMetadata(); | 266 | try self.updateMetadata(); |
| 267 | try self.sortSections(); | 267 | try self.sortSections(); |
| | 268 | try self.allocateTextSegment(); |
| | 269 | try self.allocateDataConstSegment(); |
| | 270 | try self.allocateDataSegment(); |
| | 271 | self.allocateLinkeditSegment(); |
| | 272 | try self.allocateSymbols(); |
| 268 | self.printSymtab(); | 273 | self.printSymtab(); |
| 269 | // try self.allocateTextSegment(); | | |
| 270 | // try self.allocateDataConstSegment(); | | |
| 271 | // try self.allocateDataSegment(); | | |
| 272 | // self.allocateLinkeditSegment(); | | |
| 273 | // try self.writeStubHelperCommon(); | 274 | // try self.writeStubHelperCommon(); |
| 274 | // try self.doRelocs(); | 275 | // try self.doRelocs(); |
| 275 | // try self.flush(); | 276 | // try self.flush(); |
| ... | @@ -816,7 +817,11 @@ fn allocateTextSegment(self: *Zld) !void { | ... | @@ -816,7 +817,11 @@ fn allocateTextSegment(self: *Zld) !void { |
| 816 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined | 817 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 817 | // object files. For the time being, assume all externs are stubs (this is wasting space but should | 818 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 818 | // correspond to the worst-case upper bound). | 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 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; | 826 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 822 | seg.inner.fileoff = 0; | 827 | seg.inner.fileoff = 0; |
| ... | @@ -825,14 +830,14 @@ fn allocateTextSegment(self: *Zld) !void { | ... | @@ -825,14 +830,14 @@ fn allocateTextSegment(self: *Zld) !void { |
| 825 | // Set stubs and stub_helper sizes | 830 | // Set stubs and stub_helper sizes |
| 826 | const stubs = &seg.sections.items[self.stubs_section_index.?]; | 831 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 827 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; | 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 | const stub_size: u4 = switch (self.arch.?) { | 835 | const stub_size: u4 = switch (self.arch.?) { |
| 831 | .x86_64 => 10, | 836 | .x86_64 => 10, |
| 832 | .aarch64 => 3 * @sizeOf(u32), | 837 | .aarch64 => 3 * @sizeOf(u32), |
| 833 | else => unreachable, | 838 | else => unreachable, |
| 834 | }; | 839 | }; |
| 835 | stub_helper.size += nstubs * stub_size; | 840 | stub_helper.size += nexterns * stub_size; |
| 836 | | 841 | |
| 837 | var sizeofcmds: u64 = 0; | 842 | var sizeofcmds: u64 = 0; |
| 838 | for (self.load_commands.items) |lc| { | 843 | for (self.load_commands.items) |lc| { |
| ... | @@ -870,7 +875,11 @@ fn allocateDataConstSegment(self: *Zld) !void { | ... | @@ -870,7 +875,11 @@ fn allocateDataConstSegment(self: *Zld) !void { |
| 870 | // TODO This should be worked out by scanning the relocations in the __text sections of all | 875 | // TODO This should be worked out by scanning the relocations in the __text sections of all |
| 871 | // combined object files. For the time being, assume all externs are GOT entries (this is wasting space but | 876 | // combined object files. For the time being, assume all externs are GOT entries (this is wasting space but |
| 872 | // should correspond to the worst-case upper bound). | 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 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 884 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 876 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; | 885 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| ... | @@ -891,7 +900,11 @@ fn allocateDataSegment(self: *Zld) !void { | ... | @@ -891,7 +900,11 @@ fn allocateDataSegment(self: *Zld) !void { |
| 891 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined | 900 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 892 | // object files. For the time being, assume all externs are stubs (this is wasting space but should | 901 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 893 | // correspond to the worst-case upper bound). | 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 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 909 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 897 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; | 910 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| ... | @@ -900,7 +913,7 @@ fn allocateDataSegment(self: *Zld) !void { | ... | @@ -900,7 +913,7 @@ fn allocateDataSegment(self: *Zld) !void { |
| 900 | // Set la_symbol_ptr and data size | 913 | // Set la_symbol_ptr and data size |
| 901 | const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?]; | 914 | const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?]; |
| 902 | const data = &seg.sections.items[self.data_section_index.?]; | 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 | data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder | 917 | data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder |
| 905 | | 918 | |
| 906 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); | 919 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| ... | @@ -933,6 +946,60 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { | ... | @@ -933,6 +946,60 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 933 | seg.inner.vmsize = seg_size_aligned; | 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 | fn writeStubHelperCommon(self: *Zld) !void { | 1003 | fn writeStubHelperCommon(self: *Zld) !void { |
| 937 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1004 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 938 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 1005 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |