| ... | @@ -84,6 +84,8 @@ const Trie = struct { | ... | @@ -84,6 +84,8 @@ const Trie = struct { |
| 84 | } | 84 | } |
| 85 | }; | 85 | }; |
| 86 | | 86 | |
| | 87 | export_flags: ?u64 = null, |
| | 88 | offset: ?u64 = null, |
| 87 | edges: std.ArrayListUnmanaged(Edge) = .{}, | 89 | edges: std.ArrayListUnmanaged(Edge) = .{}, |
| 88 | | 90 | |
| 89 | pub fn deinit(self: *Node, alloc: *Allocator) void { | 91 | pub fn deinit(self: *Node, alloc: *Allocator) void { |
| ... | @@ -93,10 +95,10 @@ const Trie = struct { | ... | @@ -93,10 +95,10 @@ const Trie = struct { |
| 93 | self.edges.deinit(alloc); | 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 | // Traverse all edges. | 99 | // Traverse all edges. |
| 98 | for (self.edges.items) |*edge| { | 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 | if (match - prefix > 0) { | 102 | if (match - prefix > 0) { |
| 101 | // If we match, we advance further down the trie. | 103 | // If we match, we advance further down the trie. |
| 102 | return edge.to.put(alloc, edge, match, label); | 104 | return edge.to.put(alloc, edge, match, label); |
| ... | @@ -105,7 +107,7 @@ const Trie = struct { | ... | @@ -105,7 +107,7 @@ const Trie = struct { |
| 105 | | 107 | |
| 106 | if (fromEdge) |from| { | 108 | if (fromEdge) |from| { |
| 107 | if (mem.eql(u8, from.label, label[0..prefix])) { | 109 | if (mem.eql(u8, from.label, label[0..prefix])) { |
| 108 | if (prefix == label.len) return; | 110 | if (prefix == label.len) return self; |
| 109 | } else { | 111 | } else { |
| 110 | // Fixup nodes. We need to insert an intermediate node between | 112 | // Fixup nodes. We need to insert an intermediate node between |
| 111 | // from.to and self. | 113 | // from.to and self. |
| ... | @@ -121,35 +123,86 @@ const Trie = struct { | ... | @@ -121,35 +123,86 @@ const Trie = struct { |
| 121 | .label = to_label, | 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 | const new_node = try alloc.create(Node); | 128 | const new_node = try alloc.create(Node); |
| 127 | new_node.* = .{}; | 129 | new_node.* = .{}; |
| 128 | return mid.edges.append(alloc, .{ | 130 | |
| | 131 | try mid.edges.append(alloc, .{ |
| 129 | .from = mid, | 132 | .from = mid, |
| 130 | .to = new_node, | 133 | .to = new_node, |
| 131 | .label = label, | 134 | .label = label, |
| 132 | }); | 135 | }); |
| | 136 | |
| | 137 | return new_node; |
| 133 | } | 138 | } |
| 134 | } | 139 | } |
| 135 | | 140 | |
| 136 | // Add a new edge. | 141 | // Add a new edge. |
| 137 | const node = try alloc.create(Node); | 142 | const node = try alloc.create(Node); |
| 138 | node.* = .{}; | 143 | node.* = .{}; |
| 139 | return self.edges.append(alloc, .{ | 144 | |
| | 145 | try self.edges.append(alloc, .{ |
| 140 | .from = self, | 146 | .from = self, |
| 141 | .to = node, | 147 | .to = node, |
| 142 | .label = label, | 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 | root: Node, | 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 | return self.root.put(alloc, null, 0, word); | 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 | pub fn deinit(self: *Trie, alloc: *Allocator) void { | 206 | pub fn deinit(self: *Trie, alloc: *Allocator) void { |
| 154 | self.root.deinit(alloc); | 207 | self.root.deinit(alloc); |
| 155 | } | 208 | } |
| ... | @@ -347,10 +400,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -347,10 +400,10 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 347 | | 400 | |
| 348 | switch (self.base.options.output_mode) { | 401 | switch (self.base.options.output_mode) { |
| 349 | .Exe => { | 402 | .Exe => { |
| 350 | if (self.entry_addr) |addr| { | 403 | // Write export trie. |
| 351 | // Write export trie. | 404 | try self.writeExportTrie(); |
| 352 | try self.writeExportTrie(); | | |
| 353 | | 405 | |
| | 406 | if (self.entry_addr) |addr| { |
| 354 | // Update LC_MAIN with entry offset | 407 | // Update LC_MAIN with entry offset |
| 355 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 408 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 356 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; | 409 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| ... | @@ -1474,25 +1527,25 @@ fn writeAllUndefSymbols(self: *MachO) !void { | ... | @@ -1474,25 +1527,25 @@ fn writeAllUndefSymbols(self: *MachO) !void { |
| 1474 | } | 1527 | } |
| 1475 | | 1528 | |
| 1476 | fn writeExportTrie(self: *MachO) !void { | 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 | 1532 | var trie: Trie = .{ |
| 1480 | // single branch export trie | 1533 | .root = .{}, |
| 1481 | var buf = [_]u8{0} ** 24; | 1534 | }; |
| 1482 | buf[0] = 0; // root node | 1535 | defer trie.deinit(self.base.allocator); |
| 1483 | buf[1] = 1; // 1 branch from root | | |
| 1484 | mem.copy(u8, buf[2..], "_start"); | | |
| 1485 | buf[8] = 0; | | |
| 1486 | buf[9] = 9 + 1; | | |
| 1487 | | 1536 | |
| 1488 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1537 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1489 | const addr = self.entry_addr.? - text_segment.vmaddr; | 1538 | |
| 1490 | const written = try std.debug.leb.writeULEB128Mem(buf[12..], addr); | 1539 | for (self.global_symbols.items) |symbol| { |
| 1491 | buf[10] = @intCast(u8, written) + 1; | 1540 | // TODO figure out if we should put all global symbols into the export trie |
| 1492 | buf[11] = 0; | 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 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; | 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 | fn writeStringTable(self: *MachO) !void { | 1551 | fn writeStringTable(self: *MachO) !void { |