authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-07-17 10:39:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-20 12:19:16-07:00
loga804de13c8e2d7a6a99c55355f964f658a5a76bc
tree6a78c63c363dfb692a76fd704c1c44c3e0a15ea4
parentd17f492017c77d5d52d2fbd65eaa5c1e08b24161

plan9 linker: fix after testing

* exports get rendered properly in symbol table * global offset table is at the start of data section instead of after symtab * various null use fixes

1 files changed, 55 insertions(+), 10 deletions(-)

src/link/Plan9.zig+55-10
...@@ -34,7 +34,7 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},...@@ -34,7 +34,7 @@ data_decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, []const u8) = .{},
3434
35hdr: aout.ExecHdr = undefined,35hdr: aout.ExecHdr = undefined,
3636
37entry_decl: ?*Module.Decl = null,37entry_val: ?u64 = null,
3838
39got_len: u64 = 0,39got_len: u64 = 0,
4040
...@@ -213,6 +213,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -213,6 +213,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
213 if (build_options.skip_non_native and builtin.object_format != .plan9) {213 if (build_options.skip_non_native and builtin.object_format != .plan9) {
214 @panic("Attempted to compile for object format that was disabled by build configuration");214 @panic("Attempted to compile for object format that was disabled by build configuration");
215 }215 }
216
216 _ = comp;217 _ = comp;
217 const tracy = trace(@src());218 const tracy = trace(@src());
218 defer tracy.end();219 defer tracy.end();
...@@ -221,7 +222,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -221,7 +222,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
221222
222 defer assert(self.hdr.entry != 0x0);223 defer assert(self.hdr.entry != 0x0);
223224
224 _ = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;225 const mod = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
225226
226 assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count());227 assert(self.got_len == self.fn_decl_table.count() + self.data_decl_table.count());
227 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;228 const got_size = self.got_len * if (!self.sixtyfour_bit) @as(u32, 4) else 8;
...@@ -230,6 +231,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -230,6 +231,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
230231
231 // + 2 for header, got, symbols232 // + 2 for header, got, symbols
232 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3);233 var iovecs = try self.base.allocator.alloc(std.os.iovec_const, self.fn_decl_table.count() + self.data_decl_table.count() + 3);
234 defer self.base.allocator.free(iovecs);
233235
234 const file = self.base.file.?;236 const file = self.base.file.?;
235237
...@@ -247,11 +249,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -247,11 +249,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
247 while (it.next()) |entry| {249 while (it.next()) |entry| {
248 const decl = entry.key_ptr.*;250 const decl = entry.key_ptr.*;
249 const code = entry.value_ptr.*;251 const code = entry.value_ptr.*;
252 log.debug("write text decl {*} ({s})", .{ decl, decl.name });
250 foff += code.len;253 foff += code.len;
251 text_i += code.len;
252 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };254 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
253 iovecs_i += 1;255 iovecs_i += 1;
254 const off = self.getAddr(text_i, .t);256 const off = self.getAddr(text_i, .t);
257 text_i += code.len;
255 decl.link.plan9.offset = off;258 decl.link.plan9.offset = off;
256 if (!self.sixtyfour_bit) {259 if (!self.sixtyfour_bit) {
257 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));260 mem.writeIntNative(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off));
...@@ -260,10 +263,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -260,10 +263,16 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
260 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());263 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
261 }264 }
262 self.syms.items[decl.link.plan9.sym_index.?].value = off;265 self.syms.items[decl.link.plan9.sym_index.?].value = off;
266 if (mod.decl_exports.get(decl)) |exports| {
267 try self.addDeclExports(mod, decl, exports);
268 }
263 }269 }
264 // etext symbol270 // etext symbol
265 self.syms.items[2].value = self.getAddr(text_i, .t);271 self.syms.items[2].value = self.getAddr(text_i, .t);
266 }272 }
273 // global offset table is in data
274 iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
275 iovecs_i += 1;
267 // data276 // data
268 var data_i: u64 = got_size;277 var data_i: u64 = got_size;
269 {278 {
...@@ -271,11 +280,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -271,11 +280,13 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
271 while (it.next()) |entry| {280 while (it.next()) |entry| {
272 const decl = entry.key_ptr.*;281 const decl = entry.key_ptr.*;
273 const code = entry.value_ptr.*;282 const code = entry.value_ptr.*;
283 log.debug("write data decl {*} ({s})", .{ decl, decl.name });
284
274 foff += code.len;285 foff += code.len;
275 data_i += code.len;
276 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };286 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
277 iovecs_i += 1;287 iovecs_i += 1;
278 const off = self.getAddr(data_i, .d);288 const off = self.getAddr(data_i, .d);
289 data_i += code.len;
279 decl.link.plan9.offset = off;290 decl.link.plan9.offset = off;
280 if (!self.sixtyfour_bit) {291 if (!self.sixtyfour_bit) {
281 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());292 mem.writeInt(u32, got_table[decl.link.plan9.got_index.? * 4 ..][0..4], @intCast(u32, off), self.base.options.target.cpu.arch.endian());
...@@ -283,6 +294,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -283,6 +294,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
283 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());294 mem.writeInt(u64, got_table[decl.link.plan9.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
284 }295 }
285 self.syms.items[decl.link.plan9.sym_index.?].value = off;296 self.syms.items[decl.link.plan9.sym_index.?].value = off;
297 if (mod.decl_exports.get(decl)) |exports| {
298 try self.addDeclExports(mod, decl, exports);
299 }
286 }300 }
287 // edata symbol301 // edata symbol
288 self.syms.items[0].value = self.getAddr(data_i, .b);302 self.syms.items[0].value = self.getAddr(data_i, .b);
...@@ -292,8 +306,6 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -292,8 +306,6 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
292 var sym_buf = std.ArrayList(u8).init(self.base.allocator);306 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
293 defer sym_buf.deinit();307 defer sym_buf.deinit();
294 try self.writeSyms(&sym_buf);308 try self.writeSyms(&sym_buf);
295 iovecs[iovecs_i] = .{ .iov_base = got_table.ptr, .iov_len = got_table.len };
296 iovecs_i += 1;
297 assert(2 + self.fn_decl_table.count() + self.data_decl_table.count() == iovecs_i); // we didn't write all the decls309 assert(2 + self.fn_decl_table.count() + self.data_decl_table.count() == iovecs_i); // we didn't write all the decls
298 iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len };310 iovecs[iovecs_i] = .{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len };
299 iovecs_i += 1;311 iovecs_i += 1;
...@@ -306,16 +318,45 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {...@@ -306,16 +318,45 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
306 .bss = 0,318 .bss = 0,
307 .pcsz = 0,319 .pcsz = 0,
308 .spsz = 0,320 .spsz = 0,
309 .entry = @intCast(u32, self.entry_decl.?.link.plan9.offset.?),321 .entry = @intCast(u32, self.entry_val.?),
310 };322 };
311 std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]);323 std.mem.copy(u8, hdr_slice, self.hdr.toU8s()[0..hdr_size]);
312 // write the fat header for 64 bit entry points324 // write the fat header for 64 bit entry points
313 if (self.sixtyfour_bit) {325 if (self.sixtyfour_bit) {
314 mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_decl.?.link.plan9.offset.?);326 mem.writeIntSliceBig(u64, hdr_buf[32..40], self.entry_val.?);
315 }327 }
316 // write it all!328 // write it all!
317 try file.pwritevAll(iovecs, 0);329 try file.pwritevAll(iovecs, 0);
318}330}
331fn addDeclExports(
332 self: *Plan9,
333 module: *Module,
334 decl: *Module.Decl,
335 exports: []const *Module.Export,
336) !void {
337 for (exports) |exp| {
338 // plan9 does not support custom sections
339 if (exp.options.section) |section_name| {
340 if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) {
341 try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}));
342 break;
343 }
344 }
345 const sym = .{
346 .value = decl.link.plan9.offset.?,
347 .type = decl.link.plan9.type.toGlobal(),
348 .name = exp.options.name,
349 };
350
351 if (exp.link.plan9) |i| {
352 self.syms.items[i] = sym;
353 } else {
354 try self.syms.append(self.base.allocator, sym);
355 exp.link.plan9 = self.syms.items.len - 1;
356 }
357 }
358}
359
319pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {360pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
320 const is_fn = (decl.ty.zigTypeTag() == .Fn);361 const is_fn = (decl.ty.zigTypeTag() == .Fn);
321 if (is_fn)362 if (is_fn)
...@@ -394,19 +435,23 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -394,19 +435,23 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
394pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {435pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
395 const writer = buf.writer();436 const writer = buf.writer();
396 for (self.syms.items) |sym| {437 for (self.syms.items) |sym| {
438 log.debug("sym.name: {s}", .{sym.name});
439 log.debug("sym.value: {x}", .{sym.value});
440 if (mem.eql(u8, sym.name, "_start"))
441 self.entry_val = sym.value;
397 if (!self.sixtyfour_bit) {442 if (!self.sixtyfour_bit) {
398 try writer.writeIntBig(u32, @intCast(u32, sym.value));443 try writer.writeIntBig(u32, @intCast(u32, sym.value));
399 } else {444 } else {
400 try writer.writeIntBig(u64, sym.value);445 try writer.writeIntBig(u64, sym.value);
401 }446 }
402 try writer.writeByte(@enumToInt(sym.type));447 try writer.writeByte(@enumToInt(sym.type));
403 try writer.writeAll(std.mem.span(sym.name));448 try writer.writeAll(sym.name);
404 try writer.writeByte(0);449 try writer.writeByte(0);
405 }450 }
406}451}
407452
408pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {453pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
409 if (decl.link.plan9.got_index != null) {454 if (decl.link.plan9.got_index == null) {
410 self.got_len += 1;455 self.got_len += 1;
411 decl.link.plan9.got_index = self.got_len - 1;456 decl.link.plan9.got_index = self.got_len - 1;
412 }457 }