Commit f1aadfa77b

Jacob G-W <jacoblevgw@gmail.com>
2021-06-15 22:37:18
plan9 linker: remove panics and improve 64 bit support
Don't @intCast when we do not need to, and change some panics to unreachable when they can never happen.
1 parent db2d5b4
Changed files (3)
lib
src
lib/std/zig.zig
@@ -181,10 +181,32 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
         .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
         .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
         .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
-        // TODO change this to the arbitrary character for plan9 output, eg '6' for amd64
-        .plan9 => return std.fmt.allocPrint(allocator, "{s}.out.p9", .{root_name}),
+        .plan9 => return std.fmt.allocPrint(allocator, "{s}.{c}", .{ root_name, archToPlan9Char(target.cpu.arch) }),
     }
 }
+fn archToPlan9Char(arch: std.Target.Cpu.Arch) ?u8 {
+    // copied from 2c(1)
+    // 0c spim    little-endian MIPS 3000 family
+    // 1c 68000   Motorola MC68000
+    // 2c 68020   Motorola MC68020
+    // 5c arm     little-endian ARM
+    // 6c amd64   AMD64 and compatibles (e.g., Intel EM64T)
+    // 7c arm64   ARM64 (ARMv8)
+    // 8c 386     Intel i386, i486, Pentium, etc.
+    // kc sparc   Sun SPARC
+    // qc power   Power PC
+    // vc mips    big-endian MIPS 3000 family
+    return switch (arch) {
+        .arm => '5',
+        .x86_64 => '6',
+        .aarch64 => '7',
+        .i386 => '8',
+        .sparc => 'k',
+        .powerpc, .powerpcle => 'q',
+        .mips, .mipsel => 'v',
+        else => 'X', // this arch does not have a char or maybe was not ported to plan9 so we just use X
+    };
+}
 
 pub const ParsedCharLiteral = union(enum) {
     success: u32,
src/link/plan9/a.out.zig
@@ -28,6 +28,8 @@ pub const ExecHdr = extern struct {
     data: u32,
     bss: u32,
     syms: u32,
+    /// You should truncate this to 32 bits on 64 bit systems, then but the actual 8 bytes
+    /// in the fat header.
     entry: u32,
     spsz: u32,
     pcsz: u32,
src/link/Plan9.zig
@@ -17,7 +17,7 @@ const assert = std.debug.assert;
 // TODO use incremental compilation
 
 base: link.File,
-ptr_width: PtrWidth,
+sixtyfour_bit: bool,
 error_flags: File.ErrorFlags = File.ErrorFlags{},
 bases: Bases,
 
@@ -33,41 +33,35 @@ entry_decl: ?*Module.Decl = null,
 
 got: std.ArrayListUnmanaged(u64) = .{},
 const Bases = struct {
-    text: u32,
+    text: u64,
     /// the addr of the got
-    data: u32,
+    data: u64,
 };
 
-fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
+fn getAddr(self: Plan9, addr: u64, t: aout.SymType) u64 {
     return addr + switch (t) {
-        .T, .t => self.bases.text,
+        .T, .t, .l, .L => self.bases.text,
         .D, .d, .B, .b => self.bases.data,
-        else => @panic("get address for more symbol types"),
+        else => unreachable,
     };
 }
 /// opposite of getAddr
-fn takeAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
+fn takeAddr(self: Plan9, addr: u64, t: aout.SymType) u64 {
     return addr - switch (t) {
-        .T, .t => self.bases.text,
-        .D, .d, .B, .b => self.bases.data, // TODO is .b correct here?
-        else => @panic("take address for more symbol types"),
+        .T, .t, .l, .L => self.bases.text,
+        .D, .d, .B, .b => self.bases.data,
+        else => unreachable,
     };
 }
 
-fn getSymAddr(self: Plan9, s: aout.Sym) u32 {
-    return self.getAddr(@intCast(u32, s.value), s.type);
-}
-
-fn headerSize(self: Plan9) u32 {
-    // fat header (currently unused)
-    const fat: u8 = if (self.ptr_width == .p64) 8 else 0;
-    return @sizeOf(aout.ExecHdr) + fat;
+fn getSymAddr(self: Plan9, s: aout.Sym) u64 {
+    return self.getAddr(s.value, s.type);
 }
 
 pub const DeclBlock = struct {
     type: aout.SymType,
     /// offset in the text or data sects
-    offset: ?u32,
+    offset: ?u64,
     /// offset into syms
     sym_index: ?usize,
     /// offset into got
@@ -101,9 +95,9 @@ pub const PtrWidth = enum { p32, p64 };
 pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
     if (options.use_llvm)
         return error.LLVMBackendDoesNotSupportPlan9;
-    const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) {
-        0...32 => .p32,
-        33...64 => .p64,
+    const sixtyfour_bit: bool = switch (options.target.cpu.arch.ptrBitWidth()) {
+        0...32 => false,
+        33...64 => true,
         else => return error.UnsupportedP9Architecture,
     };
     const self = try gpa.create(Plan9);
@@ -114,7 +108,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
             .allocator = gpa,
             .file = null,
         },
-        .ptr_width = ptr_width,
+        .sixtyfour_bit = sixtyfour_bit,
         .bases = undefined,
     };
     return self;
@@ -150,7 +144,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
     self.data_buf.items.len = 0;
     // ensure space to write the got later
     assert(self.got.items.len == self.decl_table.count());
-    try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (self.ptr_width == .p32) @as(u32, 4) else 8);
+    try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (!self.sixtyfour_bit) @as(u32, 4) else 8);
     // temporary buffer
     var code_buffer = std.ArrayList(u8).init(self.base.allocator);
     defer code_buffer.deinit();
@@ -161,12 +155,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
 
             log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
             decl.link.plan9 = if (is_fn) .{
-                .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),
+                .offset = self.getAddr(self.text_buf.items.len, .t),
                 .type = .t,
                 .sym_index = decl.link.plan9.sym_index,
                 .got_index = decl.link.plan9.got_index,
             } else .{
-                .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),
+                .offset = self.getAddr(self.data_buf.items.len, .d),
                 .type = .d,
                 .sym_index = decl.link.plan9.sym_index,
                 .got_index = decl.link.plan9.got_index,
@@ -243,7 +237,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
     }
 
     // write the got
-    if (self.ptr_width == .p32) {
+    if (!self.sixtyfour_bit) {
         for (self.got.items) |p, i| {
             mem.writeInt(u32, self.data_buf.items[i * 4 ..][0..4], @intCast(u32, p), self.base.options.target.cpu.arch.endian());
         }
@@ -253,15 +247,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
         }
     }
 
-    if (self.entry_decl == null) {
-        @panic("TODO we didn't have _start");
-    }
-    self.hdr.entry = self.entry_decl.?.link.plan9.offset.?;
+    self.hdr.entry = @truncate(u32, self.entry_decl.?.link.plan9.offset.?);
 
     // edata, end, etext
-    self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number
-    self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number
-    self.syms.items[2].value = self.getAddr(@intCast(u32, self.text_buf.items.len), .t);
+    self.syms.items[0].value = self.getAddr(0x0, .b);
+    self.syms.items[1].value = self.getAddr(0x0, .b);
+    self.syms.items[2].value = self.getAddr(self.text_buf.items.len, .t);
 
     var sym_buf = std.ArrayList(u8).init(self.base.allocator);
     defer sym_buf.deinit();
@@ -284,9 +275,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
     var hdr_buf = self.hdr.toU8s();
     const hdr_slice: []const u8 = &hdr_buf;
     // account for the fat header
-    const hdr_size: u8 = if (self.ptr_width == .p32) 32 else 40;
-    // write the fat header for debug info
-    if (self.ptr_width == .p64) {
+    const hdr_size: u8 = if (!self.sixtyfour_bit) 32 else 40;
+    // write the fat header for 64 bit entry points
+    if (self.sixtyfour_bit) {
         mem.writeIntSliceBig(u64, hdr_buf[32..40], self.hdr.entry);
     }
     // write it all!
@@ -335,9 +326,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
     const self = try createEmpty(allocator, options);
     errdefer self.base.destroy();
 
-    if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
-        self.hdr.entry = 0x0;
-
     self.bases = defaultBaseAddrs(options.target.cpu.arch);
 
     // first 3 symbols in our table are edata, end, etext
@@ -366,7 +354,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
 pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
     const writer = buf.writer();
     for (self.syms.items) |sym| {
-        if (self.ptr_width == .p32) {
+        if (!self.sixtyfour_bit) {
             try writer.writeIntBig(u32, @intCast(u32, sym.value));
         } else {
             try writer.writeIntBig(u64, sym.value);