authorgravatar for jacoblevgw@gmail.comJacob G-W <jacoblevgw@gmail.com> 2021-06-15 16:37:18-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-08 14:12:08-07:00
logf1aadfa77b2907f0cf93d03d362ee921b0313224
tree8051132fb07d0b496aa6b0b50ab476ab61dc785f
parentdb2d5b49c693b8a38743232b83a6ee1eab8e6468

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.

3 files changed, 55 insertions(+), 43 deletions(-)

lib/std/zig.zig+24-2
......@@ -181,10 +181,32 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
181181 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
182182 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
183183 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
184 // TODO change this to the arbitrary character for plan9 output, eg '6' for amd64
185 .plan9 => return std.fmt.allocPrint(allocator, "{s}.out.p9", .{root_name}),
184 .plan9 => return std.fmt.allocPrint(allocator, "{s}.{c}", .{ root_name, archToPlan9Char(target.cpu.arch) }),
186185 }
187186}
187fn archToPlan9Char(arch: std.Target.Cpu.Arch) ?u8 {
188 // copied from 2c(1)
189 // 0c spim little-endian MIPS 3000 family
190 // 1c 68000 Motorola MC68000
191 // 2c 68020 Motorola MC68020
192 // 5c arm little-endian ARM
193 // 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
194 // 7c arm64 ARM64 (ARMv8)
195 // 8c 386 Intel i386, i486, Pentium, etc.
196 // kc sparc Sun SPARC
197 // qc power Power PC
198 // vc mips big-endian MIPS 3000 family
199 return switch (arch) {
200 .arm => '5',
201 .x86_64 => '6',
202 .aarch64 => '7',
203 .i386 => '8',
204 .sparc => 'k',
205 .powerpc, .powerpcle => 'q',
206 .mips, .mipsel => 'v',
207 else => 'X', // this arch does not have a char or maybe was not ported to plan9 so we just use X
208 };
209}
188210
189211pub const ParsedCharLiteral = union(enum) {
190212 success: u32,
src/link/Plan9.zig+29-41
......@@ -17,7 +17,7 @@ const assert = std.debug.assert;
1717// TODO use incremental compilation
1818
1919base: link.File,
20ptr_width: PtrWidth,
20sixtyfour_bit: bool,
2121error_flags: File.ErrorFlags = File.ErrorFlags{},
2222bases: Bases,
2323
......@@ -33,41 +33,35 @@ entry_decl: ?*Module.Decl = null,
3333
3434got: std.ArrayListUnmanaged(u64) = .{},
3535const Bases = struct {
36 text: u32,
36 text: u64,
3737 /// the addr of the got
38 data: u32,
38 data: u64,
3939};
4040
41fn getAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
41fn getAddr(self: Plan9, addr: u64, t: aout.SymType) u64 {
4242 return addr + switch (t) {
43 .T, .t => self.bases.text,
43 .T, .t, .l, .L => self.bases.text,
4444 .D, .d, .B, .b => self.bases.data,
45 else => @panic("get address for more symbol types"),
45 else => unreachable,
4646 };
4747}
4848/// opposite of getAddr
49fn takeAddr(self: Plan9, addr: u32, t: aout.SymType) u32 {
49fn takeAddr(self: Plan9, addr: u64, t: aout.SymType) u64 {
5050 return addr - switch (t) {
51 .T, .t => self.bases.text,
52 .D, .d, .B, .b => self.bases.data, // TODO is .b correct here?
53 else => @panic("take address for more symbol types"),
51 .T, .t, .l, .L => self.bases.text,
52 .D, .d, .B, .b => self.bases.data,
53 else => unreachable,
5454 };
5555}
5656
57fn getSymAddr(self: Plan9, s: aout.Sym) u32 {
58 return self.getAddr(@intCast(u32, s.value), s.type);
59}
60
61fn headerSize(self: Plan9) u32 {
62 // fat header (currently unused)
63 const fat: u8 = if (self.ptr_width == .p64) 8 else 0;
64 return @sizeOf(aout.ExecHdr) + fat;
57fn getSymAddr(self: Plan9, s: aout.Sym) u64 {
58 return self.getAddr(s.value, s.type);
6559}
6660
6761pub const DeclBlock = struct {
6862 type: aout.SymType,
6963 /// offset in the text or data sects
70 offset: ?u32,
64 offset: ?u64,
7165 /// offset into syms
7266 sym_index: ?usize,
7367 /// offset into got
......@@ -101,9 +95,9 @@ pub const PtrWidth = enum { p32, p64 };
10195pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
10296 if (options.use_llvm)
10397 return error.LLVMBackendDoesNotSupportPlan9;
104 const ptr_width: PtrWidth = switch (options.target.cpu.arch.ptrBitWidth()) {
105 0...32 => .p32,
106 33...64 => .p64,
98 const sixtyfour_bit: bool = switch (options.target.cpu.arch.ptrBitWidth()) {
99 0...32 => false,
100 33...64 => true,
107101 else => return error.UnsupportedP9Architecture,
108102 };
109103 const self = try gpa.create(Plan9);
......@@ -114,7 +108,7 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
114108 .allocator = gpa,
115109 .file = null,
116110 },
117 .ptr_width = ptr_width,
111 .sixtyfour_bit = sixtyfour_bit,
118112 .bases = undefined,
119113 };
120114 return self;
......@@ -150,7 +144,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
150144 self.data_buf.items.len = 0;
151145 // ensure space to write the got later
152146 assert(self.got.items.len == self.decl_table.count());
153 try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (self.ptr_width == .p32) @as(u32, 4) else 8);
147 try self.data_buf.appendNTimes(self.base.allocator, 0x69, self.got.items.len * if (!self.sixtyfour_bit) @as(u32, 4) else 8);
154148 // temporary buffer
155149 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
156150 defer code_buffer.deinit();
......@@ -161,12 +155,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
161155
162156 log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
163157 decl.link.plan9 = if (is_fn) .{
164 .offset = self.getAddr(@intCast(u32, self.text_buf.items.len), .t),
158 .offset = self.getAddr(self.text_buf.items.len, .t),
165159 .type = .t,
166160 .sym_index = decl.link.plan9.sym_index,
167161 .got_index = decl.link.plan9.got_index,
168162 } else .{
169 .offset = self.getAddr(@intCast(u32, self.data_buf.items.len), .d),
163 .offset = self.getAddr(self.data_buf.items.len, .d),
170164 .type = .d,
171165 .sym_index = decl.link.plan9.sym_index,
172166 .got_index = decl.link.plan9.got_index,
......@@ -243,7 +237,7 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
243237 }
244238
245239 // write the got
246 if (self.ptr_width == .p32) {
240 if (!self.sixtyfour_bit) {
247241 for (self.got.items) |p, i| {
248242 mem.writeInt(u32, self.data_buf.items[i * 4 ..][0..4], @intCast(u32, p), self.base.options.target.cpu.arch.endian());
249243 }
......@@ -253,15 +247,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
253247 }
254248 }
255249
256 if (self.entry_decl == null) {
257 @panic("TODO we didn't have _start");
258 }
259 self.hdr.entry = self.entry_decl.?.link.plan9.offset.?;
250 self.hdr.entry = @truncate(u32, self.entry_decl.?.link.plan9.offset.?);
260251
261252 // edata, end, etext
262 self.syms.items[0].value = self.getAddr(0x0, .b); // what is this number
263 self.syms.items[1].value = self.getAddr(0x0, .b); // what is this number
264 self.syms.items[2].value = self.getAddr(@intCast(u32, self.text_buf.items.len), .t);
253 self.syms.items[0].value = self.getAddr(0x0, .b);
254 self.syms.items[1].value = self.getAddr(0x0, .b);
255 self.syms.items[2].value = self.getAddr(self.text_buf.items.len, .t);
265256
266257 var sym_buf = std.ArrayList(u8).init(self.base.allocator);
267258 defer sym_buf.deinit();
......@@ -284,9 +275,9 @@ pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
284275 var hdr_buf = self.hdr.toU8s();
285276 const hdr_slice: []const u8 = &hdr_buf;
286277 // account for the fat header
287 const hdr_size: u8 = if (self.ptr_width == .p32) 32 else 40;
288 // write the fat header for debug info
289 if (self.ptr_width == .p64) {
278 const hdr_size: u8 = if (!self.sixtyfour_bit) 32 else 40;
279 // write the fat header for 64 bit entry points
280 if (self.sixtyfour_bit) {
290281 mem.writeIntSliceBig(u64, hdr_buf[32..40], self.hdr.entry);
291282 }
292283 // write it all!
......@@ -335,9 +326,6 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
335326 const self = try createEmpty(allocator, options);
336327 errdefer self.base.destroy();
337328
338 if (std.builtin.mode == .Debug or std.builtin.mode == .ReleaseSafe)
339 self.hdr.entry = 0x0;
340
341329 self.bases = defaultBaseAddrs(options.target.cpu.arch);
342330
343331 // 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
366354pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
367355 const writer = buf.writer();
368356 for (self.syms.items) |sym| {
369 if (self.ptr_width == .p32) {
357 if (!self.sixtyfour_bit) {
370358 try writer.writeIntBig(u32, @intCast(u32, sym.value));
371359 } else {
372360 try writer.writeIntBig(u64, sym.value);
src/link/plan9/a.out.zig+2
......@@ -28,6 +28,8 @@ pub const ExecHdr = extern struct {
2828 data: u32,
2929 bss: u32,
3030 syms: u32,
31 /// You should truncate this to 32 bits on 64 bit systems, then but the actual 8 bytes
32 /// in the fat header.
3133 entry: u32,
3234 spsz: u32,
3335 pcsz: u32,