authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-16 12:07:34+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-16 12:07:37+02:00
log787e755a2f36660b5bc22f2a3a5d051a8c34445f
tree29234550eacf556e327cdfdbce34f9ccd4175c60
parent340a45683ca8e0b23e95f5fb86bd9c827970e6e8

macho: tie FDEs and unwind records to all symbol aliases

This is in particular very important to the Zig language which allows exporting the same symbol under different names. For instance, it is possible to have a case such that: ``` ... 4258 T _foo 4258 T _bar ... ``` In this case we need to keep track of both symbol names when resolving FDEs and unwind records.

1 files changed, 54 insertions(+), 11 deletions(-)

src/link/MachO/Object.zig+54-11
......@@ -718,7 +718,7 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
718718 }
719719
720720 try self.eh_frame_relocs_lookup.ensureTotalCapacity(gpa, record_count);
721 try self.eh_frame_records_lookup.ensureTotalCapacity(gpa, record_count);
721 try self.eh_frame_records_lookup.ensureUnusedCapacity(gpa, record_count);
722722
723723 it.reset();
724724
......@@ -768,11 +768,28 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
768768 else => unreachable,
769769 }
770770 };
771 log.debug("FDE at offset {x} tracks {s}", .{ offset, zld.getSymbolName(target) });
772771 if (target.getFile() != object_id) {
772 log.debug("FDE at offset {x} marked DEAD", .{offset});
773773 self.eh_frame_relocs_lookup.getPtr(offset).?.dead = true;
774774 } else {
775 self.eh_frame_records_lookup.putAssumeCapacityNoClobber(target, offset);
775 // You would think that we are done but turns out that the compilers may use
776 // whichever symbol alias they want for a target symbol. This in particular
777 // very problematic when using Zig's @export feature to re-export symbols under
778 // additional names. For that reason, we need to ensure we record aliases here
779 // too so that we can tie them with their matching unwind records and vice versa.
780 const aliases = self.getSymbolAliases(target.sym_index);
781 var i: u32 = 0;
782 while (i < aliases.len) : (i += 1) {
783 const actual_target = SymbolWithLoc{
784 .sym_index = i + aliases.start,
785 .file = target.file,
786 };
787 log.debug("FDE at offset {x} tracks {s}", .{
788 offset,
789 zld.getSymbolName(actual_target),
790 });
791 try self.eh_frame_records_lookup.putNoClobber(gpa, actual_target, offset);
792 }
776793 }
777794 }
778795 }
......@@ -803,7 +820,7 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
803820
804821 const unwind_records = self.getUnwindRecords();
805822
806 try self.unwind_records_lookup.ensureTotalCapacity(gpa, @as(u32, @intCast(unwind_records.len)));
823 try self.unwind_records_lookup.ensureUnusedCapacity(gpa, @as(u32, @intCast(unwind_records.len)));
807824
808825 const needs_eh_frame = for (unwind_records) |record| {
809826 if (UnwindInfo.UnwindEncoding.isDwarf(record.compactUnwindEncoding, cpu_arch)) break true;
......@@ -839,11 +856,28 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
839856 .code = mem.asBytes(&record),
840857 .base_offset = @as(i32, @intCast(offset)),
841858 });
842 log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) });
843859 if (target.getFile() != object_id) {
860 log.debug("unwind record {d} marked DEAD", .{record_id});
844861 self.unwind_relocs_lookup[record_id].dead = true;
845862 } else {
846 self.unwind_records_lookup.putAssumeCapacityNoClobber(target, @as(u32, @intCast(record_id)));
863 // You would think that we are done but turns out that the compilers may use
864 // whichever symbol alias they want for a target symbol. This in particular
865 // very problematic when using Zig's @export feature to re-export symbols under
866 // additional names. For that reason, we need to ensure we record aliases here
867 // too so that we can tie them with their matching unwind records and vice versa.
868 const aliases = self.getSymbolAliases(target.sym_index);
869 var i: u32 = 0;
870 while (i < aliases.len) : (i += 1) {
871 const actual_target = SymbolWithLoc{
872 .sym_index = i + aliases.start,
873 .file = target.file,
874 };
875 log.debug("unwind record {d} tracks {s}", .{
876 record_id,
877 zld.getSymbolName(actual_target),
878 });
879 try self.unwind_records_lookup.putNoClobber(gpa, actual_target, @intCast(record_id));
880 }
847881 }
848882 }
849883}
......@@ -991,6 +1025,18 @@ pub fn getSymbolName(self: Object, index: u32) []const u8 {
9911025 return strtab[start..][0 .. len - 1 :0];
9921026}
9931027
1028fn getSymbolAliases(self: Object, index: u32) Entry {
1029 const addr = self.source_address_lookup[index];
1030 var start = index;
1031 while (start > 0 and
1032 self.source_address_lookup[start - 1] == addr) : (start -= 1)
1033 {}
1034 const end: u32 = for (self.source_address_lookup[start..], start..) |saddr, i| {
1035 if (saddr != addr) break @as(u32, @intCast(i));
1036 } else @as(u32, @intCast(self.source_address_lookup.len));
1037 return .{ .start = start, .len = end - start };
1038}
1039
9941040pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
9951041 // Find containing atom
9961042 const Predicate = struct {
......@@ -1012,11 +1058,8 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
10121058 if (target_sym_index > 0) {
10131059 // Hone in on the most senior alias of the target symbol.
10141060 // See SymbolAtIndex.lessThan for more context.
1015 var start = target_sym_index - 1;
1016 while (start > 0 and
1017 self.source_address_lookup[lookup.start..][start - 1] == addr) : (start -= 1)
1018 {}
1019 return @as(u32, @intCast(lookup.start + start));
1061 const aliases = self.getSymbolAliases(@intCast(lookup.start + target_sym_index - 1));
1062 return aliases.start;
10201063 }
10211064 }
10221065 return self.getSectionAliasSymbolIndex(sect_id);