Commit 2c2ff4558f

Jakub Konka <kubkon@jakubkonka.com>
2022-10-20 14:34:09
macho: fix handling of lack of subsections and tracking of inner symbols
1 parent 5edb8e0
Changed files (4)
src/link/MachO/dead_strip.zig
@@ -77,8 +77,15 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
     for (zld.objects.items) |object| {
         for (object.atoms.items) |atom_index| {
             const atom = zld.getAtom(atom_index);
-            const source_sym = object.getSourceSymbol(atom.sym_index) orelse continue;
-            const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+
+            const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
+                source_sym.n_sect - 1
+            else blk: {
+                const nbase = @intCast(u32, object.in_symtab.?.len);
+                const sect_id = @intCast(u16, atom.sym_index - nbase);
+                break :blk sect_id;
+            };
+            const source_sect = object.getSourceSection(sect_id);
             const is_gc_root = blk: {
                 if (source_sect.isDontDeadStrip()) break :blk true;
                 if (mem.eql(u8, "__StaticInit", source_sect.sectName())) break :blk true;
@@ -220,8 +227,14 @@ fn mark(zld: *Zld, roots: AtomTable, alive: *AtomTable, reverse_lookups: [][]u32
                 if (alive.contains(atom_index)) continue;
 
                 const atom = zld.getAtom(atom_index);
-                const source_sym = object.getSourceSymbol(atom.sym_index) orelse continue;
-                const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+                const sect_id = if (object.getSourceSymbol(atom.sym_index)) |source_sym|
+                    source_sym.n_sect - 1
+                else blk: {
+                    const nbase = @intCast(u32, object.in_symtab.?.len);
+                    const sect_id = @intCast(u16, atom.sym_index - nbase);
+                    break :blk sect_id;
+                };
+                const source_sect = object.getSourceSection(sect_id);
 
                 if (source_sect.isDontDeadStripIfReferencesLive()) {
                     if (try refersLive(zld, atom_index, alive.*, reverse_lookups)) {
src/link/MachO/Object.zig
@@ -316,6 +316,7 @@ pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u31) !void {
                 object_id,
                 sym_index,
                 0,
+                0,
                 sect.size,
                 sect.@"align",
                 out_sect_id,
@@ -392,6 +393,7 @@ pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u31) !void {
                     object_id,
                     sym_index,
                     0,
+                    0,
                     atom_size,
                     sect.@"align",
                     out_sect_id,
@@ -429,6 +431,7 @@ pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u31) !void {
                     zld,
                     object_id,
                     atom_sym_index,
+                    atom_sym_index + 1,
                     nsyms_trailing,
                     atom_size,
                     atom_align,
@@ -447,19 +450,17 @@ pub fn splitIntoAtoms(self: *Object, zld: *Zld, object_id: u31) !void {
                 zld.addAtomToSection(atom_index);
             }
         } else {
-            const sym_index = self.getSectionAliasSymbolIndex(sect_id);
+            const alias_index = self.getSectionAliasSymbolIndex(sect_id);
             const atom_index = try self.createAtomFromSubsection(
                 zld,
                 object_id,
-                sym_index,
-                0,
+                alias_index,
+                sect_start_index,
+                sect_loc.len,
                 sect.size,
                 sect.@"align",
                 out_sect_id,
             );
-            // If there is no symbol to refer to this atom, we create
-            // a temp one, unless we already did that when working out the relocations
-            // of other atoms.
             zld.addAtomToSection(atom_index);
         }
     }
@@ -470,7 +471,8 @@ fn createAtomFromSubsection(
     zld: *Zld,
     object_id: u31,
     sym_index: u32,
-    nsyms_trailing: u32,
+    inner_sym_index: u32,
+    inner_nsyms_trailing: u32,
     size: u64,
     alignment: u32,
     out_sect_id: u8,
@@ -478,7 +480,8 @@ fn createAtomFromSubsection(
     const gpa = zld.gpa;
     const atom_index = try zld.createEmptyAtom(sym_index, size, alignment);
     const atom = zld.getAtomPtr(atom_index);
-    atom.nsyms_trailing = nsyms_trailing;
+    atom.inner_sym_index = inner_sym_index;
+    atom.inner_nsyms_trailing = inner_nsyms_trailing;
     atom.file = object_id;
     self.symtab[sym_index].n_sect = out_sect_id + 1;
 
src/link/MachO/zld.zig
@@ -1911,7 +1911,7 @@ pub const Zld = struct {
                     sym.n_value,
                 });
 
-                if (atom.getFile()) |_| {
+                if (atom.getFile() != null) {
                     // Update each symbol contained within the atom
                     var it = Atom.getInnerSymbolsIterator(self, atom_index);
                     while (it.next()) |sym_loc| {
@@ -2160,8 +2160,11 @@ pub const Zld = struct {
                     log.debug("  ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });
 
                     const object = self.objects.items[atom.getFile().?];
-                    const source_sym = object.getSourceSymbol(atom.sym_index).?;
-                    const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+                    const base_rel_offset: i32 = blk: {
+                        const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
+                        const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+                        break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
+                    };
                     const relocs = Atom.getAtomRelocs(self, atom_index);
 
                     for (relocs) |rel| {
@@ -2180,7 +2183,7 @@ pub const Zld = struct {
                         }
 
                         const base_offset = @intCast(i32, sym.n_value - segment.vmaddr);
-                        const rel_offset = rel.r_address - @intCast(i32, source_sym.n_value - source_sect.addr);
+                        const rel_offset = rel.r_address - base_rel_offset;
                         const offset = @intCast(u64, base_offset + rel_offset);
                         log.debug("    | rebase at {x}", .{offset});
 
@@ -2288,8 +2291,11 @@ pub const Zld = struct {
 
                 if (should_bind) {
                     const object = self.objects.items[atom.getFile().?];
-                    const source_sym = object.getSourceSymbol(atom.sym_index).?;
-                    const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+                    const base_rel_offset: i32 = blk: {
+                        const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
+                        const source_sect = object.getSourceSection(source_sym.n_sect - 1);
+                        break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
+                    };
                     const relocs = Atom.getAtomRelocs(self, atom_index);
 
                     for (relocs) |rel| {
@@ -2313,7 +2319,7 @@ pub const Zld = struct {
                         if (!bind_sym.undf()) continue;
 
                         const base_offset = @intCast(i32, sym.n_value - segment.vmaddr);
-                        const rel_offset = rel.r_address - @intCast(i32, source_sym.n_value - source_sect.addr);
+                        const rel_offset = rel.r_address - base_rel_offset;
                         const offset = @intCast(u64, base_offset + rel_offset);
 
                         const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);
@@ -3491,7 +3497,7 @@ pub const Zld = struct {
                 });
             }
         }
-        scoped_log.debug("  object(null)", .{});
+        scoped_log.debug("  object(-1)", .{});
         for (self.locals.items) |sym, sym_id| {
             if (sym.undf()) continue;
             scoped_log.debug("    %{d}: {s} @{x} in sect({d}), {s}", .{
@@ -3635,7 +3641,7 @@ pub const Zld = struct {
             sym.n_sect,
         });
 
-        if (atom.getFile()) |_| {
+        if (atom.getFile() != null)  {
             var it = Atom.getInnerSymbolsIterator(self, atom_index);
             while (it.next()) |sym_loc| {
                 const inner = self.getSymbol(sym_loc);
src/link/MachO/ZldAtom.zig
@@ -28,7 +28,8 @@ sym_index: u32,
 /// If this Atom references a subsection in an Object file, `nsyms_trailing`
 /// tells how many symbols trailing `sym_index` fall within this Atom's address
 /// range.
-nsyms_trailing: u32,
+inner_sym_index: u32,
+inner_nsyms_trailing: u32,
 
 /// -1 means symbol defined by the linker.
 /// Otherwise, it is the index into appropriate object file.
@@ -52,7 +53,8 @@ prev_index: ?AtomIndex,
 
 pub const empty = Atom{
     .sym_index = 0,
-    .nsyms_trailing = 0,
+    .inner_sym_index = 0,
+    .inner_nsyms_trailing = 0,
     .file = -1,
     .size = 0,
     .alignment = 0,
@@ -81,9 +83,10 @@ const InnerSymIterator = struct {
 
     pub fn next(it: *@This()) ?SymbolWithLoc {
         if (it.count == 0) return null;
+        const res = SymbolWithLoc{ .sym_index = it.sym_index, .file = it.file };
         it.sym_index += 1;
         it.count -= 1;
-        return SymbolWithLoc{ .sym_index = it.sym_index, .file = it.file };
+        return res;
     }
 };
 
@@ -91,8 +94,8 @@ pub fn getInnerSymbolsIterator(zld: *Zld, atom_index: AtomIndex) InnerSymIterato
     const atom = zld.getAtom(atom_index);
     assert(atom.getFile() != null);
     return .{
-        .sym_index = atom.sym_index,
-        .count = atom.nsyms_trailing,
+        .sym_index = atom.inner_sym_index,
+        .count = atom.inner_nsyms_trailing,
         .file = atom.file,
     };
 }
@@ -123,9 +126,16 @@ pub fn calcInnerSymbolOffset(zld: *Zld, atom_index: AtomIndex, sym_index: u32) u
     if (atom.sym_index == sym_index) return 0;
 
     const object = zld.objects.items[atom.getFile().?];
-    const source_atom_sym = object.getSourceSymbol(atom.sym_index).?;
     const source_sym = object.getSourceSymbol(sym_index).?;
-    return source_sym.n_value - source_atom_sym.n_value;
+    const base_addr = if (object.getSourceSymbol(atom.sym_index)) |sym|
+        sym.n_value
+    else blk: {
+        const nbase = @intCast(u32, object.in_symtab.?.len);
+        const sect_id = @intCast(u16, atom.sym_index - nbase);
+        const source_sect = object.getSourceSection(sect_id);
+        break :blk source_sect.addr;
+    };
+    return source_sym.n_value - base_addr;
 }
 
 pub fn scanAtomRelocs(
@@ -383,13 +393,13 @@ pub fn resolveRelocs(
                 .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr),
             };
         }
-        for (object.getSourceSections()) |source_sect, i| {
-            const sym_index = object.getSectionAliasSymbolIndex(@intCast(u8, i));
-            if (sym_index == atom.sym_index) break :blk .{
-                .base_addr = source_sect.addr,
-                .base_offset = 0,
-            };
-        } else unreachable;
+        const nbase = @intCast(u32, object.in_symtab.?.len);
+        const sect_id = @intCast(u16, atom.sym_index - nbase);
+        const source_sect = object.getSourceSection(sect_id);
+        break :blk .{
+            .base_addr = source_sect.addr,
+            .base_offset = 0,
+        };
     };
 
     log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{
@@ -918,11 +928,9 @@ pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 {
         // If there was no matching symbol present in the source symtab, this means
         // we are dealing with either an entire section, or part of it, but also
         // starting at the beginning.
-        const source_sect = for (object.getSourceSections()) |source_sect, sect_id| {
-            const sym_index = object.getSectionAliasSymbolIndex(@intCast(u8, sect_id));
-            if (sym_index == atom.sym_index) break source_sect;
-        } else unreachable;
-
+        const nbase = @intCast(u32, object.in_symtab.?.len);
+        const sect_id = @intCast(u16, atom.sym_index - nbase);
+        const source_sect = object.getSourceSection(sect_id);
         assert(!source_sect.isZerofill());
         const code = object.getSectionContents(source_sect);
         const code_len = @intCast(usize, atom.size);
@@ -949,10 +957,9 @@ pub fn getAtomRelocs(zld: *Zld, atom_index: AtomIndex) []align(1) const macho.re
         // If there was no matching symbol present in the source symtab, this means
         // we are dealing with either an entire section, or part of it, but also
         // starting at the beginning.
-        const source_sect = for (object.getSourceSections()) |source_sect, sect_id| {
-            const sym_index = object.getSectionAliasSymbolIndex(@intCast(u8, sect_id));
-            if (sym_index == atom.sym_index) break source_sect;
-        } else unreachable;
+        const nbase = @intCast(u32, object.in_symtab.?.len);
+        const sect_id = @intCast(u16, atom.sym_index - nbase);
+        const source_sect = object.getSourceSection(sect_id);
         assert(!source_sect.isZerofill());
         break :blk source_sect;
     };