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.
This commit is contained in:
Jacob G-W 2021-06-15 16:37:18 -04:00 committed by Andrew Kelley
parent db2d5b49c6
commit f1aadfa77b
3 changed files with 55 additions and 43 deletions

View File

@ -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,

View File

@ -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);

View File

@ -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,