authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-06 22:34:39+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-07 20:33:28+02:00
loge76fb8d8c82ffc9fdeef2de0a6008c756103811b
tree377609451e1037d3bcdc4ec36f6bcf1656582443
parentf0a73df8e72e156bd95fa6c7f4de9512513d01b3
signature Commit is signed but in an unrecognized format.

Add incomplete writing of trie to bytes buffer

Signed-off-by: Jakub Konka <kubkon@jakubkonka.com>

1 files changed, 77 insertions(+), 24 deletions(-)

src/link/MachO.zig+77-24
...@@ -84,6 +84,8 @@ const Trie = struct {...@@ -84,6 +84,8 @@ const Trie = struct {
84 }84 }
85 };85 };
8686
87 export_flags: ?u64 = null,
88 offset: ?u64 = null,
87 edges: std.ArrayListUnmanaged(Edge) = .{},89 edges: std.ArrayListUnmanaged(Edge) = .{},
8890
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 }
9597
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 {
105107
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 between112 // 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 });
123125
124 if (prefix == label.len) return; // We're done.126 if (prefix == label.len) return self; // We're done.
125127
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 }
135140
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 };
146187
147 root: Node,188 root: Node,
148189
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 }
152193
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 {
347400
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();
353405
406 if (self.entry_addr) |addr| {
354 // Update LC_MAIN with entry offset407 // 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}
14751528
1476fn writeExportTrie(self: *MachO) !void {1529fn writeExportTrie(self: *MachO) !void {
1477 assert(self.entry_addr != null);1530 if (self.global_symbols.items.len == 0) return; // No exports, nothing to do.
14781531
1479 // TODO implement mechanism for generating a prefix tree of the exported symbols1532 var trie: Trie = .{
1480 // single branch export trie1533 .root = .{},
1481 var buf = [_]u8{0} ** 24;1534 };
1482 buf[0] = 0; // root node1535 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;
14871536
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 }
14931546
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}
14971550
1498fn writeStringTable(self: *MachO) !void {1551fn writeStringTable(self: *MachO) !void {