| ... | @@ -151,37 +151,49 @@ const Trie = struct { | ... | @@ -151,37 +151,49 @@ const Trie = struct { |
| 151 | return node; | 151 | return node; |
| 152 | } | 152 | } |
| 153 | | 153 | |
| 154 | pub fn write(self: Node, buf: []u8, offset: u64) error{NoSpaceLeft}!usize { | 154 | pub fn write(self: Node, alloc: *Allocator, buffer: *std.ArrayListUnmanaged(u8)) Trie.WriteError!void { |
| 155 | var pos: usize = 0; | | |
| 156 | if (self.offset) |off| { | 155 | if (self.offset) |off| { |
| 157 | var info_buf_pos: usize = 0; | 156 | // Terminal node info: encode export flags and vmaddr offset of this symbol. |
| | 157 | var info_buf_len: usize = 0; |
| 158 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; | 158 | var info_buf: [@sizeOf(u64) * 2]u8 = undefined; |
| 159 | info_buf_pos += try std.debug.leb.writeULEB128Mem(info_buf[0..], self.export_flags.?); | 159 | info_buf_len += 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); | 160 | info_buf_len += try std.debug.leb.writeULEB128Mem(info_buf[info_buf_len..], off); |
| 161 | log.debug("info_buf = {x}\n", .{info_buf[0..info_buf_pos]}); | 161 | |
| 162 | pos += try std.debug.leb.writeULEB128Mem(buf[pos..], info_buf_pos); | 162 | // Encode the size of the terminal node info. |
| 163 | mem.copy(u8, buf[pos..], info_buf[0..info_buf_pos]); | 163 | var size_buf: [@sizeOf(u64)]u8 = undefined; |
| 164 | pos += info_buf_pos; | 164 | const size_buf_len = try std.debug.leb.writeULEB128Mem(size_buf[0..], info_buf_len); |
| 165 | log.debug("buf = {x}\n", .{buf}); | 165 | |
| | 166 | // Now, write them to the output buffer. |
| | 167 | try buffer.ensureCapacity(alloc, buffer.items.len + info_buf_len + size_buf_len); |
| | 168 | buffer.appendSliceAssumeCapacity(size_buf[0..size_buf_len]); |
| | 169 | buffer.appendSliceAssumeCapacity(info_buf[0..info_buf_len]); |
| 166 | } else { | 170 | } else { |
| 167 | buf[pos] = 0; | 171 | // Non-terminal node is delimited by 0 byte. |
| 168 | pos += 1; | 172 | try buffer.append(alloc, 0); |
| 169 | } | 173 | } |
| 170 | buf[pos] = @intCast(u8, self.edges.items.len); | 174 | // Write number of edges (max legal number of edges is 256). |
| 171 | pos += 1; | 175 | try buffer.append(alloc, @intCast(u8, self.edges.items.len)); |
| 172 | | 176 | |
| 173 | for (self.edges.items) |edge| { | 177 | var node_offset_info: [@sizeOf(u8)]u64 = undefined; |
| 174 | mem.copy(u8, buf[pos..], edge.label); | 178 | for (self.edges.items) |edge, i| { |
| 175 | pos += edge.label.len; | 179 | // Write edges labels leaving out space in-between to later populate |
| 176 | buf[pos] = 0; | 180 | // with offsets to each node. |
| 177 | pos += 1; | 181 | try buffer.ensureCapacity(alloc, buffer.items.len + edge.label.len + 1 + @sizeOf(u64)); // +1 to account for null-byte |
| 178 | const curr_offset = pos + offset + 1; | 182 | buffer.appendSliceAssumeCapacity(edge.label); |
| 179 | pos += try std.debug.leb.writeULEB128Mem(buf[pos..], curr_offset); | 183 | buffer.appendAssumeCapacity(0); |
| 180 | pos += try edge.to.write(buf[pos..], curr_offset); | 184 | node_offset_info[i] = buffer.items.len; |
| 181 | log.debug("buf = {x}\n", .{buf}); | 185 | const padding = [_]u8{0} ** @sizeOf(u64); |
| | 186 | buffer.appendSliceAssumeCapacity(padding[0..]); |
| 182 | } | 187 | } |
| 183 | | 188 | |
| 184 | return pos; | 189 | for (self.edges.items) |edge, i| { |
| | 190 | const offset = buffer.items.len; |
| | 191 | try edge.to.write(alloc, buffer); |
| | 192 | // We can now populate the offset to the node pointed by this edge. |
| | 193 | var offset_buf: [@sizeOf(u64)]u8 = undefined; |
| | 194 | const offset_buf_len = try std.debug.leb.writeULEB128Mem(offset_buf[0..], offset); |
| | 195 | mem.copy(u8, buffer.items[node_offset_info[i]..], offset_buf[0..offset_buf_len]); |
| | 196 | } |
| 185 | } | 197 | } |
| 186 | }; | 198 | }; |
| 187 | | 199 | |
| ... | @@ -191,16 +203,10 @@ const Trie = struct { | ... | @@ -191,16 +203,10 @@ const Trie = struct { |
| 191 | return self.root.put(alloc, null, 0, word); | 203 | return self.root.put(alloc, null, 0, word); |
| 192 | } | 204 | } |
| 193 | | 205 | |
| 194 | pub fn write(self: Trie, alloc: *Allocator, file: *fs.File, offset: u64) !void { | 206 | pub const WriteError = error{ OutOfMemory, NoSpaceLeft }; |
| 195 | // TODO get the actual node count | | |
| 196 | const count = 10; | | |
| 197 | const node_size = @sizeOf(u64) * 2; | | |
| 198 | | 207 | |
| 199 | var buf = try alloc.alloc(u8, count * node_size); | 208 | pub fn write(self: Trie, alloc: *Allocator, buffer: *std.ArrayListUnmanaged(u8)) WriteError!void { |
| 200 | defer alloc.free(buf); | 209 | return self.root.write(alloc, buffer); |
| 201 | | | |
| 202 | const written = try self.root.write(buf, 0); | | |
| 203 | return file.pwriteAll(buf[0..written], offset); | | |
| 204 | } | 210 | } |
| 205 | | 211 | |
| 206 | pub fn deinit(self: *Trie, alloc: *Allocator) void { | 212 | pub fn deinit(self: *Trie, alloc: *Allocator) void { |
| ... | @@ -1544,8 +1550,13 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -1544,8 +1550,13 @@ fn writeExportTrie(self: *MachO) !void { |
| 1544 | node.export_flags = 0; // TODO workout creation of export flags | 1550 | node.export_flags = 0; // TODO workout creation of export flags |
| 1545 | } | 1551 | } |
| 1546 | | 1552 | |
| | 1553 | var buffer: std.ArrayListUnmanaged(u8) = .{}; |
| | 1554 | defer buffer.deinit(self.base.allocator); |
| | 1555 | |
| | 1556 | try trie.write(self.base.allocator, &buffer); |
| | 1557 | |
| 1547 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; | 1558 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| 1548 | try trie.write(self.base.allocator, &self.base.file.?, dyld_info.export_off); | 1559 | try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off); |
| 1549 | } | 1560 | } |
| 1550 | | 1561 | |
| 1551 | fn writeStringTable(self: *MachO) !void { | 1562 | fn writeStringTable(self: *MachO) !void { |