| ... | ... | @@ -84,6 +84,8 @@ const Trie = struct { |
| 84 | 84 | } |
| 85 | 85 | }; |
| 86 | 86 | |
| 87 | export_flags: ?u64 = null, |
| 88 | offset: ?u64 = null, |
| 87 | 89 | edges: std.ArrayListUnmanaged(Edge) = .{}, |
| 88 | 90 | |
| 89 | 91 | pub fn deinit(self: *Node, alloc: *Allocator) void { |
| ... | ... | @@ -93,10 +95,10 @@ const Trie = struct { |
| 93 | 95 | self.edges.deinit(alloc); |
| 94 | 96 | } |
| 95 | 97 | |
| 96 | | pub fn put(self: *Node, alloc: *Allocator, fromEdge: ?*Edge, prefix: usize, label: []const u8) !void { |
| 98 | pub fn put(self: *Node, alloc: *Allocator, fromEdge: ?*Edge, prefix: usize, label: []const u8) !*Node { |
| 97 | 99 | // Traverse all edges. |
| 98 | 100 | for (self.edges.items) |*edge| { |
| 99 | | const match = mem.indexOfDiff(u8, edge.label, label) orelse return; // Got a full match, don't do anything. |
| 101 | const match = mem.indexOfDiff(u8, edge.label, label) orelse return self; // Got a full match, don't do anything. |
| 100 | 102 | if (match - prefix > 0) { |
| 101 | 103 | // If we match, we advance further down the trie. |
| 102 | 104 | return edge.to.put(alloc, edge, match, label); |
| ... | ... | @@ -105,7 +107,7 @@ const Trie = struct { |
| 105 | 107 | |
| 106 | 108 | if (fromEdge) |from| { |
| 107 | 109 | if (mem.eql(u8, from.label, label[0..prefix])) { |
| 108 | | if (prefix == label.len) return; |
| 110 | if (prefix == label.len) return self; |
| 109 | 111 | } else { |
| 110 | 112 | // Fixup nodes. We need to insert an intermediate node between |
| 111 | 113 | // from.to and self. |
| ... | ... | @@ -121,35 +123,86 @@ const Trie = struct { |
| 121 | 123 | .label = to_label, |
| 122 | 124 | }); |
| 123 | 125 | |
| 124 | | if (prefix == label.len) return; // We're done. |
| 126 | if (prefix == label.len) return self; // We're done. |
| 125 | 127 | |
| 126 | 128 | const new_node = try alloc.create(Node); |
| 127 | 129 | new_node.* = .{}; |
| 128 | | return mid.edges.append(alloc, .{ |
| 130 | |
| 131 | try mid.edges.append(alloc, .{ |
| 129 | 132 | .from = mid, |
| 130 | 133 | .to = new_node, |
| 131 | 134 | .label = label, |
| 132 | 135 | }); |
| 136 | |
| 137 | return new_node; |
| 133 | 138 | } |
| 134 | 139 | } |
| 135 | 140 | |
| 136 | 141 | // Add a new edge. |
| 137 | 142 | const node = try alloc.create(Node); |
| 138 | 143 | node.* = .{}; |
| 139 | | return self.edges.append(alloc, .{ |
| 144 | |
| 145 | try self.edges.append(alloc, .{ |
| 140 | 146 | .from = self, |
| 141 | 147 | .to = node, |
| 142 | 148 | .label = label, |
| 143 | 149 | }); |
| 150 | |
| 151 | return node; |
| 152 | } |
| 153 | |
| 154 | pub fn write(self: Node, buf: []u8, offset: u64) error{NoSpaceLeft}!usize { |
| 155 | var pos: usize = 0; |
| 156 | if (self.offset) |off| { |
| 157 | var info_buf_pos: usize = 0; |
| 158 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; |
| 159 | info_buf_pos += try std.debug.leb.writeULEB128Mem(info_buf[0..], self.export_flags.?); |
| 160 | info_buf_pos += try std.debug.leb.writeULEB128Mem(info_buf[info_buf_pos..], off); |
| 161 | log.debug("info_buf = {x}\n", .{info_buf[0..info_buf_pos]}); |
| 162 | pos += try std.debug.leb.writeULEB128Mem(buf[pos..], info_buf_pos); |
| 163 | mem.copy(u8, buf[pos..], info_buf[0..info_buf_pos]); |
| 164 | pos += info_buf_pos; |
| 165 | log.debug("buf = {x}\n", .{buf}); |
| 166 | } else { |
| 167 | buf[pos] = 0; |
| 168 | pos += 1; |
| 169 | } |
| 170 | buf[pos] = @intCast(u8, self.edges.items.len); |
| 171 | pos += 1; |
| 172 | |
| 173 | for (self.edges.items) |edge| { |
| 174 | mem.copy(u8, buf[pos..], edge.label); |
| 175 | pos += edge.label.len; |
| 176 | buf[pos] = 0; |
| 177 | pos += 1; |
| 178 | const curr_offset = pos + offset + 1; |
| 179 | pos += try std.debug.leb.writeULEB128Mem(buf[pos..], curr_offset); |
| 180 | pos += try edge.to.write(buf[pos..], curr_offset); |
| 181 | log.debug("buf = {x}\n", .{buf}); |
| 182 | } |
| 183 | |
| 184 | return pos; |
| 144 | 185 | } |
| 145 | 186 | }; |
| 146 | 187 | |
| 147 | 188 | root: Node, |
| 148 | 189 | |
| 149 | | pub fn put(self: *Trie, alloc: *Allocator, word: []const u8) !void { |
| 190 | pub fn put(self: *Trie, alloc: *Allocator, word: []const u8) !*Node { |
| 150 | 191 | return self.root.put(alloc, null, 0, word); |
| 151 | 192 | } |
| 152 | 193 | |
| 194 | pub fn write(self: Trie, alloc: *Allocator, file: *fs.File, offset: u64) !void { |
| 195 | // TODO get the actual node count |
| 196 | const count = 10; |
| 197 | const node_size = @sizeOf(u64) * 2; |
| 198 | |
| 199 | var buf = try alloc.alloc(u8, count * node_size); |
| 200 | defer alloc.free(buf); |
| 201 | |
| 202 | const written = try self.root.write(buf, 0); |
| 203 | return file.pwriteAll(buf[0..written], offset); |
| 204 | } |
| 205 | |
| 153 | 206 | pub fn deinit(self: *Trie, alloc: *Allocator) void { |
| 154 | 207 | self.root.deinit(alloc); |
| 155 | 208 | } |
| ... | ... | @@ -347,10 +400,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 347 | 400 | |
| 348 | 401 | switch (self.base.options.output_mode) { |
| 349 | 402 | .Exe => { |
| 350 | | if (self.entry_addr) |addr| { |
| 351 | | // Write export trie. |
| 352 | | try self.writeExportTrie(); |
| 403 | // Write export trie. |
| 404 | try self.writeExportTrie(); |
| 353 | 405 | |
| 406 | if (self.entry_addr) |addr| { |
| 354 | 407 | // Update LC_MAIN with entry offset |
| 355 | 408 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 356 | 409 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| ... | ... | @@ -1474,25 +1527,25 @@ fn writeAllUndefSymbols(self: *MachO) !void { |
| 1474 | 1527 | } |
| 1475 | 1528 | |
| 1476 | 1529 | fn writeExportTrie(self: *MachO) !void { |
| 1477 | | assert(self.entry_addr != null); |
| 1530 | if (self.global_symbols.items.len == 0) return; // No exports, nothing to do. |
| 1478 | 1531 | |
| 1479 | | // TODO implement mechanism for generating a prefix tree of the exported symbols |
| 1480 | | // single branch export trie |
| 1481 | | var buf = [_]u8{0} ** 24; |
| 1482 | | buf[0] = 0; // root node |
| 1483 | | buf[1] = 1; // 1 branch from root |
| 1484 | | mem.copy(u8, buf[2..], "_start"); |
| 1485 | | buf[8] = 0; |
| 1486 | | buf[9] = 9 + 1; |
| 1532 | var trie: Trie = .{ |
| 1533 | .root = .{}, |
| 1534 | }; |
| 1535 | defer trie.deinit(self.base.allocator); |
| 1487 | 1536 | |
| 1488 | 1537 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1489 | | const addr = self.entry_addr.? - text_segment.vmaddr; |
| 1490 | | const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr); |
| 1491 | | buf[10] = @intCast(u8, written) + 1; |
| 1492 | | buf[11] = 0; |
| 1538 | |
| 1539 | for (self.global_symbols.items) |symbol| { |
| 1540 | // TODO figure out if we should put all global symbols into the export trie |
| 1541 | const name = self.getString(symbol.n_strx); |
| 1542 | const node = try trie.put(self.base.allocator, name); |
| 1543 | node.offset = symbol.n_value - text_segment.vmaddr; |
| 1544 | node.export_flags = 0; // TODO workout creation of export flags |
| 1545 | } |
| 1493 | 1546 | |
| 1494 | 1547 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| 1495 | | try self.base.file.?.pwriteAll(buf[0..], dyld_info.export_off); |
| 1548 | try trie.write(self.base.allocator, &self.base.file.?, dyld_info.export_off); |
| 1496 | 1549 | } |
| 1497 | 1550 | |
| 1498 | 1551 | fn writeStringTable(self: *MachO) !void { |