Commit b8fce705ad

Jakub Konka <kubkon@jakubkonka.com>
2021-07-11 21:25:04
zld: refactor nlist and reloc filtering logic
1 parent 2a88089
Changed files (1)
src
link
src/link/MachO/Object.zig
@@ -273,59 +273,56 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void {
     }
 }
 
+fn findFirst(comptime T: type, haystack: []T, start: usize, predicate: anytype) usize {
+    if (!@hasDecl(@TypeOf(predicate), "predicate"))
+        @compileError("Predicate is required to define fn predicate(@This(), T) bool");
+
+    if (start == haystack.len) return start;
+
+    var i = start;
+    while (i < haystack.len) : (i += 1) {
+        if (predicate.predicate(haystack[i])) break;
+    }
+    return i;
+}
+
 const NlistWithIndex = struct {
     nlist: macho.nlist_64,
     index: u32,
 
-    fn lessThan(_: void, lhs: @This(), rhs: @This()) bool {
+    fn lessThan(_: void, lhs: NlistWithIndex, rhs: NlistWithIndex) bool {
         return lhs.nlist.n_value < rhs.nlist.n_value;
     }
 
-    fn filterInSection(symbols: []@This(), sect_id: u8) []@This() {
-        var start: usize = 0;
-        var end: usize = symbols.len;
+    fn filterInSection(symbols: []NlistWithIndex, sect: macho.section_64) []NlistWithIndex {
+        const Predicate = struct {
+            addr: u64,
 
-        while (true) {
-            var change = false;
-            if (symbols[start].nlist.n_sect != sect_id) {
-                start += 1;
-                change = true;
-            }
-            if (symbols[end - 1].nlist.n_sect != sect_id) {
-                end -= 1;
-                change = true;
+            fn predicate(self: @This(), symbol: NlistWithIndex) bool {
+                return symbol.nlist.n_value >= self.addr;
             }
+        };
 
-            if (start == end) break;
-            if (!change) break;
-        }
+        const start = findFirst(NlistWithIndex, symbols, 0, Predicate{ .addr = sect.addr });
+        const end = findFirst(NlistWithIndex, symbols, start, Predicate{ .addr = sect.addr + sect.size });
 
         return symbols[start..end];
     }
 };
 
-fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.relocation_info {
-    if (relocs.len == 0) return relocs;
-
-    var start_id: usize = 0;
-    var end_id: usize = relocs.len;
+fn filterRelocs(relocs: []macho.relocation_info, start_addr: u64, end_addr: u64) []macho.relocation_info {
+    const Predicate = struct {
+        addr: u64,
 
-    while (true) {
-        var change = false;
-        if (relocs[start_id].r_address >= end) {
-            start_id += 1;
-            change = true;
-        }
-        if (relocs[end_id - 1].r_address < start) {
-            end_id -= 1;
-            change = true;
+        fn predicate(self: @This(), rel: macho.relocation_info) bool {
+            return rel.r_address < self.addr;
         }
+    };
 
-        if (start_id == end_id) break;
-        if (!change) break;
-    }
+    const start = findFirst(macho.relocation_info, relocs, 0, Predicate{ .addr = end_addr });
+    const end = findFirst(macho.relocation_info, relocs, start, Predicate{ .addr = start_addr });
 
-    return relocs[start_id..end_id];
+    return relocs[start..end];
 }
 
 const TextBlockParser = struct {
@@ -501,10 +498,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
         const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs);
 
         // Symbols within this section only.
-        const filtered_nlists = NlistWithIndex.filterInSection(
-            sorted_nlists.items,
-            sect_id + 1,
-        );
+        const filtered_nlists = NlistWithIndex.filterInSection(sorted_nlists.items, sect);
 
         // Is there any padding between symbols within the section?
         const is_splittable = self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0;