Commit a38af5f542

Jakub Konka <kubkon@jakubkonka.com>
2023-12-12 20:52:28
lib/std/Build/CheckObject: fix parsing and dumping special dylib lookup values
1 parent 37458cc
Changed files (1)
lib
std
Build
lib/std/Build/Step/CheckObject.zig
@@ -645,17 +645,17 @@ const MachODumper = struct {
             if (lc.bind_size > 0) {
                 const data = bytes[lc.bind_off..][0..lc.bind_size];
                 try writer.writeAll("bind info\n");
-                try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer);
+                try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
             }
             if (lc.weak_bind_size > 0) {
                 const data = bytes[lc.weak_bind_off..][0..lc.weak_bind_size];
                 try writer.writeAll("weak bind info\n");
-                try dumpBindInfo(gpa, data, segments.items, imports.items, false, writer);
+                try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
             }
             if (lc.lazy_bind_size > 0) {
                 const data = bytes[lc.lazy_bind_off..][0..lc.lazy_bind_size];
                 try writer.writeAll("lazy bind info\n");
-                try dumpBindInfo(gpa, data, segments.items, imports.items, true, writer);
+                try dumpBindInfo(gpa, data, segments.items, imports.items, writer);
             }
             if (lc.export_size > 0) {
                 const data = bytes[lc.export_off..][0..lc.export_size];
@@ -993,7 +993,7 @@ const MachODumper = struct {
                 if (sym.ext()) try writer.writeAll(" external");
                 try writer.print(" {s}\n", .{sym_name});
             } else if (sym.undf()) {
-                const ordinal = @divTrunc(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER);
+                const ordinal = @divFloor(@as(i16, @bitCast(sym.n_desc)), macho.N_SYMBOL_RESOLVER);
                 const import_name = blk: {
                     if (ordinal <= 0) {
                         if (ordinal == macho.BIND_SPECIAL_DYLIB_SELF)
@@ -1108,7 +1108,8 @@ const MachODumper = struct {
     const Binding = struct {
         address: u64,
         addend: i64,
-        ordinal: ?u16,
+        ordinal: u16,
+        tag: Tag,
         name: []const u8,
 
         fn deinit(binding: *Binding, gpa: Allocator) void {
@@ -1119,6 +1120,13 @@ const MachODumper = struct {
             _ = ctx;
             return lhs.address < rhs.address;
         }
+
+        const Tag = enum {
+            ord,
+            self,
+            exe,
+            flat,
+        };
     };
 
     fn dumpBindInfo(
@@ -1126,7 +1134,6 @@ const MachODumper = struct {
         data: []const u8,
         segments: []const macho.segment_command_64,
         dylibs: []const []const u8,
-        is_lazy: bool,
         writer: anytype,
     ) !void {
         var bindings = std.ArrayList(Binding).init(gpa);
@@ -1136,14 +1143,18 @@ const MachODumper = struct {
             }
             bindings.deinit();
         }
-        try parseBindInfo(gpa, data, segments, &bindings, is_lazy);
+        try parseBindInfo(gpa, data, segments, &bindings);
         mem.sort(Binding, bindings.items, {}, Binding.lessThan);
         for (bindings.items) |binding| {
             try writer.print("0x{x} [addend: {d}]", .{ binding.address, binding.addend });
-            if (binding.ordinal) |ord| {
-                try writer.print(" ({s})", .{std.fs.path.basename(dylibs[ord - 1])});
+            try writer.writeAll(" (");
+            switch (binding.tag) {
+                .self => try writer.writeAll("self"),
+                .exe => try writer.writeAll("main executable"),
+                .flat => try writer.writeAll("flat lookup"),
+                .ord => try writer.writeAll(std.fs.path.basename(dylibs[binding.ordinal - 1])),
             }
-            try writer.print(" {s}\n", .{binding.name});
+            try writer.print(") {s}\n", .{binding.name});
         }
     }
 
@@ -1152,14 +1163,14 @@ const MachODumper = struct {
         data: []const u8,
         segments: []const macho.segment_command_64,
         bindings: *std.ArrayList(Binding),
-        lazy_ops: bool,
     ) !void {
         var stream = std.io.fixedBufferStream(data);
         var creader = std.io.countingReader(stream.reader());
         const reader = creader.reader();
 
         var seg_id: ?u8 = null;
-        var dylib_id: ?u16 = null;
+        var tag: Binding.Tag = .self;
+        var ordinal: u16 = 0;
         var offset: u64 = 0;
         var addend: i64 = 0;
 
@@ -1171,14 +1182,20 @@ const MachODumper = struct {
             const opc = byte & macho.BIND_OPCODE_MASK;
             const imm = byte & macho.BIND_IMMEDIATE_MASK;
             switch (opc) {
-                macho.BIND_OPCODE_DONE => {
-                    if (!lazy_ops) break;
-                },
-                macho.BIND_OPCODE_SET_TYPE_IMM => {
-                    if (lazy_ops) break;
-                },
+                macho.BIND_OPCODE_DONE,
+                macho.BIND_OPCODE_SET_TYPE_IMM,
+                => {},
                 macho.BIND_OPCODE_SET_DYLIB_ORDINAL_IMM => {
-                    dylib_id = imm;
+                    tag = .ord;
+                    ordinal = imm;
+                },
+                macho.BIND_OPCODE_SET_DYLIB_SPECIAL_IMM => {
+                    switch (imm) {
+                        0 => tag = .self,
+                        0xf => tag = .exe,
+                        0xe => tag = .flat,
+                        else => unreachable,
+                    }
                 },
                 macho.BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB => {
                     seg_id = imm;
@@ -1193,7 +1210,6 @@ const MachODumper = struct {
                     addend = try std.leb.readILEB128(i64, reader);
                 },
                 macho.BIND_OPCODE_ADD_ADDR_ULEB => {
-                    if (lazy_ops) break;
                     const x = try std.leb.readULEB128(u64, reader);
                     offset = @intCast(@as(i64, @intCast(offset)) + @as(i64, @bitCast(x)));
                 },
@@ -1209,15 +1225,12 @@ const MachODumper = struct {
                     switch (opc) {
                         macho.BIND_OPCODE_DO_BIND => {},
                         macho.BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB => {
-                            if (lazy_ops) break;
                             add_addr = try std.leb.readULEB128(u64, reader);
                         },
                         macho.BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED => {
-                            if (lazy_ops) break;
                             add_addr = imm * @sizeOf(u64);
                         },
                         macho.BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB => {
-                            if (lazy_ops) break;
                             count = try std.leb.readULEB128(u64, reader);
                             skip = try std.leb.readULEB128(u64, reader);
                         },
@@ -1231,7 +1244,8 @@ const MachODumper = struct {
                         try bindings.append(.{
                             .address = addr,
                             .addend = addend,
-                            .ordinal = dylib_id,
+                            .tag = tag,
+                            .ordinal = ordinal,
                             .name = try gpa.dupe(u8, name_buf.items),
                         });
                         offset += skip + @sizeOf(u64) + add_addr;