authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-02 08:11:06+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
log4e676ecbb5c107ca5c9dbc497920d0150e4e1d8e
tree422c1e41a0f21b2898c531034b9a5b3f6fbfd700
parentd5c2f8ed322d8246992202197851bd4d46ec0b3b

zld: allocate addresses for global symbols


1 files changed, 77 insertions(+), 10 deletions(-)

src/link/MachO/Zld.zig+77-10
...@@ -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 combined817 // 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 should818 // 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 }
820825
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 sizes830 // 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;
829834
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;
836841
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 all875 // 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 but876 // 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 }
874883
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 combined900 // 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 should901 // 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 }
895908
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 size913 // 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_binder917 data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder
905918
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}
935948
949fn 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
936fn writeStubHelperCommon(self: *Zld) !void {1003fn 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.?];