Commit 84853c5c56

Jakub Konka <kubkon@jakubkonka.com>
2023-08-26 23:05:32
macho: unify resolving globals
1 parent 7f6973f
Changed files (1)
src
link
MachO
src/link/MachO/zld.zig
@@ -245,6 +245,82 @@ pub const Zld = struct {
         try self.resolveSymbolsAtLoading();
     }
 
+    fn resolveGlobalSymbol(self: *Zld, current: SymbolWithLoc) !void {
+        const gpa = self.gpa;
+        const sym = self.getSymbol(current);
+        const sym_name = self.getSymbolName(current);
+
+        const gop = try self.getOrPutGlobalPtr(sym_name);
+        if (!gop.found_existing) {
+            gop.value_ptr.* = current;
+            if (sym.undf() and !sym.tentative()) {
+                try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, {});
+            }
+            return;
+        }
+        const global_index = self.getGlobalIndex(sym_name).?;
+        const global = gop.value_ptr.*;
+        const global_sym = self.getSymbol(global);
+
+        // Cases to consider: sym vs global_sym
+        // 1.  strong(sym) and strong(global_sym) => error
+        // 2.  strong(sym) and weak(global_sym) => sym
+        // 3.  strong(sym) and tentative(global_sym) => sym
+        // 4.  strong(sym) and undf(global_sym) => sym
+        // 5.  weak(sym) and strong(global_sym) => global_sym
+        // 6.  weak(sym) and tentative(global_sym) => sym
+        // 7.  weak(sym) and undf(global_sym) => sym
+        // 8.  tentative(sym) and strong(global_sym) => global_sym
+        // 9.  tentative(sym) and weak(global_sym) => global_sym
+        // 10. tentative(sym) and tentative(global_sym) => pick larger
+        // 11. tentative(sym) and undf(global_sym) => sym
+        // 12. undf(sym) and * => global_sym
+        //
+        // Reduces to:
+        // 1. strong(sym) and strong(global_sym) => error
+        // 2. * and strong(global_sym) => global_sym
+        // 3. weak(sym) and weak(global_sym) => global_sym
+        // 4. tentative(sym) and tentative(global_sym) => pick larger
+        // 5. undf(sym) and * => global_sym
+        // 6. else => sym
+
+        const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext());
+        const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext());
+        const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext());
+        const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
+
+        if (sym_is_strong and global_is_strong) {
+            log.err("symbol '{s}' defined multiple times", .{sym_name});
+            if (global.getFile()) |file| {
+                log.err("  first definition in '{s}'", .{self.objects.items[file].name});
+            }
+            if (current.getFile()) |file| {
+                log.err("  next definition in '{s}'", .{self.objects.items[file].name});
+            }
+            return error.MultipleSymbolDefinitions;
+        }
+
+        if (current.getFile()) |file| {
+            const object = &self.objects.items[file];
+            object.globals_lookup[current.sym_index] = global_index;
+        }
+
+        if (global_is_strong) return;
+        if (sym_is_weak and global_is_weak) return;
+        if (sym.tentative() and global_sym.tentative()) {
+            if (global_sym.n_value >= sym.n_value) return;
+        }
+        if (sym.undf() and !sym.tentative()) return;
+
+        if (global.getFile()) |file| {
+            const global_object = &self.objects.items[file];
+            global_object.globals_lookup[global.sym_index] = global_index;
+        }
+        _ = self.unresolved.swapRemove(global_index);
+
+        gop.value_ptr.* = current;
+    }
+
     fn resolveSymbolsInObject(self: *Zld, object_id: u32) !void {
         const object = &self.objects.items[object_id];
         const in_symtab = object.in_symtab orelse return;
@@ -285,76 +361,7 @@ pub const Zld = struct {
                 continue;
             }
 
-            const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 };
-
-            const gop = try self.getOrPutGlobalPtr(sym_name);
-            if (!gop.found_existing) {
-                gop.value_ptr.* = sym_loc;
-                if (sym.undf() and !sym.tentative()) {
-                    try self.unresolved.putNoClobber(self.gpa, self.getGlobalIndex(sym_name).?, {});
-                }
-                continue;
-            }
-            const global_index = self.getGlobalIndex(sym_name).?;
-            const global = gop.value_ptr;
-            const global_sym = self.getSymbol(global.*);
-
-            // Cases to consider: sym vs global_sym
-            // 1.  strong(sym) and strong(global_sym) => error
-            // 2.  strong(sym) and weak(global_sym) => sym
-            // 3.  strong(sym) and tentative(global_sym) => sym
-            // 4.  strong(sym) and undf(global_sym) => sym
-            // 5.  weak(sym) and strong(global_sym) => global_sym
-            // 6.  weak(sym) and tentative(global_sym) => sym
-            // 7.  weak(sym) and undf(global_sym) => sym
-            // 8.  tentative(sym) and strong(global_sym) => global_sym
-            // 9.  tentative(sym) and weak(global_sym) => global_sym
-            // 10. tentative(sym) and tentative(global_sym) => pick larger
-            // 11. tentative(sym) and undf(global_sym) => sym
-            // 12. undf(sym) and * => global_sym
-            //
-            // Reduces to:
-            // 1. strong(sym) and strong(global_sym) => error
-            // 2. * and strong(global_sym) => global_sym
-            // 3. weak(sym) and weak(global_sym) => global_sym
-            // 4. tentative(sym) and tentative(global_sym) => pick larger
-            // 5. undf(sym) and * => global_sym
-            // 6. else => sym
-
-            const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext());
-            const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext());
-            const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext());
-            const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
-
-            if (sym_is_strong and global_is_strong) {
-                log.err("symbol '{s}' defined multiple times", .{sym_name});
-                if (global.getFile()) |file| {
-                    log.err("  first definition in '{s}'", .{self.objects.items[file].name});
-                }
-                log.err("  next definition in '{s}'", .{self.objects.items[object_id].name});
-                return error.MultipleSymbolDefinitions;
-            }
-
-            const update_global = blk: {
-                if (global_is_strong) break :blk false;
-                if (sym_is_weak and global_is_weak) break :blk false;
-                if (sym.tentative() and global_sym.tentative()) {
-                    if (global_sym.n_value >= sym.n_value) break :blk false;
-                }
-                if (sym.undf() and !sym.tentative()) break :blk false;
-                break :blk true;
-            };
-
-            if (update_global) {
-                if (global.getFile()) |file| {
-                    const global_object = &self.objects.items[file];
-                    global_object.globals_lookup[global.sym_index] = global_index;
-                }
-                _ = self.unresolved.swapRemove(global_index);
-                global.* = sym_loc;
-            } else {
-                object.globals_lookup[sym_index] = global_index;
-            }
+            try self.resolveGlobalSymbol(.{ .sym_index = sym_index, .file = object_id + 1 });
         }
     }