mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 13:30:45 +00:00
Merge pull request #9105 from g-w1/plan9
stage2: bringup plan9 target and linker
This commit is contained in:
commit
7b8a968f14
@ -573,6 +573,8 @@ set(ZIG_STAGE2_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/link/C.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Coff.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Elf.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Plan9.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/Plan9/aout.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig"
|
||||
"${CMAKE_SOURCE_DIR}/src/link/MachO/CodeSignature.zig"
|
||||
|
||||
@ -95,30 +95,47 @@ fn _start2() callconv(.Naked) noreturn {
|
||||
}
|
||||
|
||||
fn exit2(code: usize) noreturn {
|
||||
switch (builtin.stage2_arch) {
|
||||
.x86_64 => {
|
||||
asm volatile ("syscall"
|
||||
:
|
||||
: [number] "{rax}" (231),
|
||||
[arg1] "{rdi}" (code)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
switch (builtin.stage2_os) {
|
||||
.linux => switch (builtin.stage2_arch) {
|
||||
.x86_64 => {
|
||||
asm volatile ("syscall"
|
||||
:
|
||||
: [number] "{rax}" (231),
|
||||
[arg1] "{rdi}" (code)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
},
|
||||
.arm => {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (1),
|
||||
[arg1] "{r0}" (code)
|
||||
: "memory"
|
||||
);
|
||||
},
|
||||
.aarch64 => {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (93),
|
||||
[arg1] "{x0}" (code)
|
||||
: "memory", "cc"
|
||||
);
|
||||
},
|
||||
else => @compileError("TODO"),
|
||||
},
|
||||
.arm => {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{r7}" (1),
|
||||
[arg1] "{r0}" (code)
|
||||
: "memory"
|
||||
);
|
||||
},
|
||||
.aarch64 => {
|
||||
asm volatile ("svc #0"
|
||||
:
|
||||
: [number] "{x8}" (93),
|
||||
[arg1] "{x0}" (code)
|
||||
: "memory", "cc"
|
||||
);
|
||||
// exits(0)
|
||||
.plan9 => switch (builtin.stage2_arch) {
|
||||
.x86_64 => {
|
||||
asm volatile (
|
||||
\\push $0
|
||||
\\push $0
|
||||
\\syscall
|
||||
:
|
||||
: [syscall_number] "{rbp}" (8)
|
||||
: "rcx", "r11", "memory"
|
||||
);
|
||||
},
|
||||
else => @compileError("TODO"),
|
||||
},
|
||||
else => @compileError("TODO"),
|
||||
}
|
||||
|
||||
@ -60,6 +60,7 @@ pub const Target = struct {
|
||||
opencl,
|
||||
glsl450,
|
||||
vulkan,
|
||||
plan9,
|
||||
other,
|
||||
|
||||
pub fn isDarwin(tag: Tag) bool {
|
||||
@ -262,6 +263,7 @@ pub const Target = struct {
|
||||
.opencl, // TODO: OpenCL versions
|
||||
.glsl450, // TODO: GLSL versions
|
||||
.vulkan,
|
||||
.plan9,
|
||||
.other,
|
||||
=> return .{ .none = {} },
|
||||
|
||||
@ -420,6 +422,7 @@ pub const Target = struct {
|
||||
.opencl,
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.plan9,
|
||||
.other,
|
||||
=> false,
|
||||
};
|
||||
@ -515,6 +518,7 @@ pub const Target = struct {
|
||||
.opencl, // TODO: SPIR-V ABIs with Linkage capability
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.plan9, // TODO specify abi
|
||||
=> return .none,
|
||||
}
|
||||
}
|
||||
@ -554,6 +558,7 @@ pub const Target = struct {
|
||||
spirv,
|
||||
hex,
|
||||
raw,
|
||||
plan9,
|
||||
};
|
||||
|
||||
pub const SubSystem = enum {
|
||||
@ -1359,6 +1364,8 @@ pub const Target = struct {
|
||||
if (cpu_arch.isSPIRV()) {
|
||||
return .spirv;
|
||||
}
|
||||
if (os_tag == .plan9)
|
||||
return .plan9;
|
||||
return .elf;
|
||||
}
|
||||
|
||||
@ -1432,6 +1439,7 @@ pub const Target = struct {
|
||||
.opencl,
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.plan9,
|
||||
.other,
|
||||
=> return false,
|
||||
else => return true,
|
||||
@ -1616,6 +1624,7 @@ pub const Target = struct {
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.other,
|
||||
.plan9,
|
||||
=> return result,
|
||||
|
||||
// TODO revisit when multi-arch for Haiku is available
|
||||
|
||||
@ -181,6 +181,30 @@ 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}),
|
||||
.plan9 => {
|
||||
// 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
|
||||
const char: u8 = switch (target.cpu.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
|
||||
};
|
||||
return std.fmt.allocPrint(allocator, "{s}.{c}", .{ root_name, char });
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -133,6 +133,7 @@ pub const CrossTarget = struct {
|
||||
.opencl,
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.plan9,
|
||||
.other,
|
||||
=> {
|
||||
self.os_version_min = .{ .none = {} };
|
||||
@ -746,6 +747,7 @@ pub const CrossTarget = struct {
|
||||
.opencl,
|
||||
.glsl450,
|
||||
.vulkan,
|
||||
.plan9,
|
||||
.other,
|
||||
=> return error.InvalidOperatingSystemVersion,
|
||||
|
||||
|
||||
@ -3556,6 +3556,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
|
||||
\\pub const zig_is_stage2 = {};
|
||||
\\/// Temporary until self-hosted supports the `cpu.arch` value.
|
||||
\\pub const stage2_arch: std.Target.Cpu.Arch = .{};
|
||||
\\/// Temporary until self-hosted supports the `os.tag` value.
|
||||
\\pub const stage2_os: std.Target.Os.Tag = .{};
|
||||
\\
|
||||
\\pub const output_mode = std.builtin.OutputMode.{};
|
||||
\\pub const link_mode = std.builtin.LinkMode.{};
|
||||
@ -3571,6 +3573,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) Alloc
|
||||
build_options.version,
|
||||
!use_stage1,
|
||||
std.zig.fmtId(@tagName(target.cpu.arch)),
|
||||
std.zig.fmtId(@tagName(target.os.tag)),
|
||||
std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
|
||||
std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
|
||||
comp.bin_file.options.is_test,
|
||||
|
||||
@ -3437,6 +3437,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo
|
||||
// in `Decl` to notice that the line number did not change.
|
||||
mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
|
||||
},
|
||||
.plan9 => {
|
||||
// TODO implement for plan9
|
||||
},
|
||||
.c, .wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
@ -3514,6 +3517,7 @@ pub fn clearDecl(
|
||||
.coff => .{ .coff = link.File.Coff.TextBlock.empty },
|
||||
.elf => .{ .elf = link.File.Elf.TextBlock.empty },
|
||||
.macho => .{ .macho = link.File.MachO.TextBlock.empty },
|
||||
.plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
|
||||
.c => .{ .c = link.File.C.DeclBlock.empty },
|
||||
.wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
|
||||
.spirv => .{ .spirv = {} },
|
||||
@ -3522,6 +3526,7 @@ pub fn clearDecl(
|
||||
.coff => .{ .coff = {} },
|
||||
.elf => .{ .elf = link.File.Elf.SrcFn.empty },
|
||||
.macho => .{ .macho = link.File.MachO.SrcFn.empty },
|
||||
.plan9 => .{ .plan9 = {} },
|
||||
.c => .{ .c = link.File.C.FnBlock.empty },
|
||||
.wasm => .{ .wasm = link.File.Wasm.FnData.empty },
|
||||
.spirv => .{ .spirv = .{} },
|
||||
@ -3689,6 +3694,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node
|
||||
.coff => .{ .coff = link.File.Coff.TextBlock.empty },
|
||||
.elf => .{ .elf = link.File.Elf.TextBlock.empty },
|
||||
.macho => .{ .macho = link.File.MachO.TextBlock.empty },
|
||||
.plan9 => .{ .plan9 = link.File.Plan9.DeclBlock.empty },
|
||||
.c => .{ .c = link.File.C.DeclBlock.empty },
|
||||
.wasm => .{ .wasm = link.File.Wasm.DeclBlock.empty },
|
||||
.spirv => .{ .spirv = {} },
|
||||
@ -3697,6 +3703,7 @@ fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node
|
||||
.coff => .{ .coff = {} },
|
||||
.elf => .{ .elf = link.File.Elf.SrcFn.empty },
|
||||
.macho => .{ .macho = link.File.MachO.SrcFn.empty },
|
||||
.plan9 => .{ .plan9 = {} },
|
||||
.c => .{ .c = link.File.C.FnBlock.empty },
|
||||
.wasm => .{ .wasm = link.File.Wasm.FnData.empty },
|
||||
.spirv => .{ .spirv = .{} },
|
||||
@ -3766,6 +3773,7 @@ pub fn analyzeExport(
|
||||
.coff => .{ .coff = {} },
|
||||
.elf => .{ .elf = link.File.Elf.Export{} },
|
||||
.macho => .{ .macho = link.File.MachO.Export{} },
|
||||
.plan9 => .{ .plan9 = null },
|
||||
.c => .{ .c = {} },
|
||||
.wasm => .{ .wasm = {} },
|
||||
.spirv => .{ .spirv = {} },
|
||||
|
||||
103
src/codegen.zig
103
src/codegen.zig
@ -2556,9 +2556,60 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
} else if (self.bin_file.cast(link.File.Plan9)) |p9| {
|
||||
switch (arch) {
|
||||
.x86_64 => {
|
||||
for (info.args) |mc_arg, arg_i| {
|
||||
const arg = inst.args[arg_i];
|
||||
const arg_mcv = try self.resolveInst(inst.args[arg_i]);
|
||||
// Here we do not use setRegOrMem even though the logic is similar, because
|
||||
// the function call will move the stack pointer, so the offsets are different.
|
||||
switch (mc_arg) {
|
||||
.none => continue,
|
||||
.register => |reg| {
|
||||
try self.register_manager.getReg(reg, null);
|
||||
try self.genSetReg(arg.src, arg.ty, reg, arg_mcv);
|
||||
},
|
||||
.stack_offset => {
|
||||
// Here we need to emit instructions like this:
|
||||
// mov qword ptr [rsp + stack_offset], x
|
||||
return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
|
||||
},
|
||||
.ptr_stack_offset => {
|
||||
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
|
||||
},
|
||||
.ptr_embedded_in_code => {
|
||||
return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
|
||||
},
|
||||
.undef => unreachable,
|
||||
.immediate => unreachable,
|
||||
.unreach => unreachable,
|
||||
.dead => unreachable,
|
||||
.embedded_in_code => unreachable,
|
||||
.memory => unreachable,
|
||||
.compare_flags_signed => unreachable,
|
||||
.compare_flags_unsigned => unreachable,
|
||||
}
|
||||
}
|
||||
if (inst.func.value()) |func_value| {
|
||||
if (func_value.castTag(.function)) |func_payload| {
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = p9.bases.data;
|
||||
const got_index = func_payload.data.owner_decl.link.plan9.got_index.?;
|
||||
// ff 14 25 xx xx xx xx call [addr]
|
||||
try self.code.ensureCapacity(self.code.items.len + 7);
|
||||
self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
|
||||
const fn_got_addr = got_addr + got_index * ptr_bytes;
|
||||
mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), @intCast(u32, fn_got_addr));
|
||||
} else return self.fail(inst.base.src, "TODO implement calling extern fn on plan9", .{});
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement call on plan9 for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
} else unreachable;
|
||||
|
||||
switch (info.return_value) {
|
||||
.register => |reg| {
|
||||
@ -3279,10 +3330,44 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
try self.genSetReg(inst.base.src, arg.ty, reg, arg_mcv);
|
||||
}
|
||||
|
||||
if (mem.eql(u8, inst.asm_source, "syscall")) {
|
||||
try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 });
|
||||
} else if (inst.asm_source.len != 0) {
|
||||
return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
|
||||
{
|
||||
var iter = std.mem.tokenize(inst.asm_source, "\n\r");
|
||||
while (iter.next()) |ins| {
|
||||
if (mem.eql(u8, ins, "syscall")) {
|
||||
try self.code.appendSlice(&[_]u8{ 0x0f, 0x05 });
|
||||
} else if (mem.indexOf(u8, ins, "push")) |_| {
|
||||
const arg = ins[4..];
|
||||
if (mem.indexOf(u8, arg, "$")) |l| {
|
||||
const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch return self.fail(inst.base.src, "TODO implement more inline asm int parsing", .{});
|
||||
try self.code.appendSlice(&.{ 0x6a, n });
|
||||
} else if (mem.indexOf(u8, arg, "%%")) |l| {
|
||||
const reg_name = ins[4 + l + 2 ..];
|
||||
const reg = parseRegName(reg_name) orelse
|
||||
return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
|
||||
const low_id: u8 = reg.low_id();
|
||||
if (reg.isExtended()) {
|
||||
try self.code.appendSlice(&.{ 0x41, 0b1010000 | low_id });
|
||||
} else {
|
||||
try self.code.append(0b1010000 | low_id);
|
||||
}
|
||||
} else return self.fail(inst.base.src, "TODO more push operands", .{});
|
||||
} else if (mem.indexOf(u8, ins, "pop")) |_| {
|
||||
const arg = ins[3..];
|
||||
if (mem.indexOf(u8, arg, "%%")) |l| {
|
||||
const reg_name = ins[3 + l + 2 ..];
|
||||
const reg = parseRegName(reg_name) orelse
|
||||
return self.fail(inst.base.src, "unrecognized register: '{s}'", .{reg_name});
|
||||
const low_id: u8 = reg.low_id();
|
||||
if (reg.isExtended()) {
|
||||
try self.code.appendSlice(&.{ 0x41, 0b1011000 | low_id });
|
||||
} else {
|
||||
try self.code.append(0b1011000 | low_id);
|
||||
}
|
||||
} else return self.fail(inst.base.src, "TODO more pop operands", .{});
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement support for more x86 assembly instructions", .{});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inst.output_constraint) |output| {
|
||||
@ -4223,6 +4308,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const decl = payload.data;
|
||||
const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else if (self.bin_file.cast(link.File.Plan9)) |p9| {
|
||||
const decl = payload.data;
|
||||
const got_addr = p9.bases.data + decl.link.plan9.got_index.? * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else {
|
||||
return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
|
||||
}
|
||||
|
||||
@ -117,6 +117,7 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
|
||||
.opencl => return error.LLVMBackendDoesNotSupportOpenCL,
|
||||
.glsl450 => return error.LLVMBackendDoesNotSupportGLSL450,
|
||||
.vulkan => return error.LLVMBackendDoesNotSupportVulkan,
|
||||
.plan9 => return error.LLVMBackendDoesNotSupportPlan9,
|
||||
.other => "unknown",
|
||||
};
|
||||
|
||||
|
||||
26
src/link.zig
26
src/link.zig
@ -141,6 +141,7 @@ pub const File = struct {
|
||||
elf: Elf.TextBlock,
|
||||
coff: Coff.TextBlock,
|
||||
macho: MachO.TextBlock,
|
||||
plan9: Plan9.DeclBlock,
|
||||
c: C.DeclBlock,
|
||||
wasm: Wasm.DeclBlock,
|
||||
spirv: void,
|
||||
@ -150,6 +151,7 @@ pub const File = struct {
|
||||
elf: Elf.SrcFn,
|
||||
coff: Coff.SrcFn,
|
||||
macho: MachO.SrcFn,
|
||||
plan9: void,
|
||||
c: C.FnBlock,
|
||||
wasm: Wasm.FnData,
|
||||
spirv: SpirV.FnData,
|
||||
@ -159,6 +161,7 @@ pub const File = struct {
|
||||
elf: Elf.Export,
|
||||
coff: void,
|
||||
macho: MachO.Export,
|
||||
plan9: Plan9.Export,
|
||||
c: void,
|
||||
wasm: void,
|
||||
spirv: void,
|
||||
@ -189,6 +192,7 @@ pub const File = struct {
|
||||
.elf => &(try Elf.createEmpty(allocator, options)).base,
|
||||
.macho => &(try MachO.createEmpty(allocator, options)).base,
|
||||
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
|
||||
.plan9 => return &(try Plan9.createEmpty(allocator, options)).base,
|
||||
.c => unreachable, // Reported error earlier.
|
||||
.spirv => &(try SpirV.createEmpty(allocator, options)).base,
|
||||
.hex => return error.HexObjectFormatUnimplemented,
|
||||
@ -204,6 +208,7 @@ pub const File = struct {
|
||||
.coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
|
||||
.elf => &(try Elf.createEmpty(allocator, options)).base,
|
||||
.macho => &(try MachO.createEmpty(allocator, options)).base,
|
||||
.plan9 => &(try Plan9.createEmpty(allocator, options)).base,
|
||||
.wasm => &(try Wasm.createEmpty(allocator, options)).base,
|
||||
.c => unreachable, // Reported error earlier.
|
||||
.spirv => &(try SpirV.createEmpty(allocator, options)).base,
|
||||
@ -220,6 +225,7 @@ pub const File = struct {
|
||||
.coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base,
|
||||
.elf => &(try Elf.openPath(allocator, sub_path, options)).base,
|
||||
.macho => &(try MachO.openPath(allocator, sub_path, options)).base,
|
||||
.plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,
|
||||
.wasm => &(try Wasm.openPath(allocator, sub_path, options)).base,
|
||||
.c => &(try C.openPath(allocator, sub_path, options)).base,
|
||||
.spirv => &(try SpirV.openPath(allocator, sub_path, options)).base,
|
||||
@ -243,7 +249,7 @@ pub const File = struct {
|
||||
|
||||
pub fn makeWritable(base: *File) !void {
|
||||
switch (base.tag) {
|
||||
.coff, .elf, .macho => {
|
||||
.coff, .elf, .macho, .plan9 => {
|
||||
if (base.file != null) return;
|
||||
const emit = base.options.emit orelse return;
|
||||
base.file = try emit.directory.handle.createFile(emit.sub_path, .{
|
||||
@ -288,7 +294,7 @@ pub const File = struct {
|
||||
f.close();
|
||||
base.file = null;
|
||||
},
|
||||
.coff, .elf => if (base.file) |f| {
|
||||
.coff, .elf, .plan9 => if (base.file) |f| {
|
||||
if (base.intermediary_basename != null) {
|
||||
// The file we have open is not the final file that we want to
|
||||
// make executable, so we don't have to close it.
|
||||
@ -313,6 +319,7 @@ pub const File = struct {
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDecl(module, decl),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDecl(module, decl),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl),
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,6 +333,7 @@ pub const File = struct {
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl),
|
||||
.plan9 => @panic("TODO: implement updateDeclLineNumber for plan9"),
|
||||
.wasm, .spirv => {},
|
||||
}
|
||||
}
|
||||
@ -340,6 +348,7 @@ pub const File = struct {
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).allocateDeclIndexes(decl),
|
||||
.c => return @fieldParentPtr(C, "base", base).allocateDeclIndexes(decl),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).allocateDeclIndexes(decl),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).allocateDeclIndexes(decl),
|
||||
.spirv => {},
|
||||
}
|
||||
}
|
||||
@ -393,6 +402,11 @@ pub const File = struct {
|
||||
parent.deinit();
|
||||
base.allocator.destroy(parent);
|
||||
},
|
||||
.plan9 => {
|
||||
const parent = @fieldParentPtr(Plan9, "base", base);
|
||||
parent.deinit();
|
||||
base.allocator.destroy(parent);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,6 +439,7 @@ pub const File = struct {
|
||||
.c => return @fieldParentPtr(C, "base", base).flush(comp),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp),
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,6 +453,7 @@ pub const File = struct {
|
||||
.c => return @fieldParentPtr(C, "base", base).flushModule(comp),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp),
|
||||
}
|
||||
}
|
||||
|
||||
@ -451,6 +467,7 @@ pub const File = struct {
|
||||
.c => @fieldParentPtr(C, "base", base).freeDecl(decl),
|
||||
.wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl),
|
||||
.spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl),
|
||||
.plan9 => @fieldParentPtr(Plan9, "base", base).freeDecl(decl),
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,6 +476,7 @@ pub const File = struct {
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).error_flags,
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).error_flags,
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).error_flags,
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).error_flags,
|
||||
.c => return .{ .no_entry_point_found = false },
|
||||
.wasm, .spirv => return ErrorFlags{},
|
||||
}
|
||||
@ -481,6 +499,7 @@ pub const File = struct {
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl, exports),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl, exports),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl, exports),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclExports(module, decl, exports),
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,6 +508,7 @@ pub const File = struct {
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl),
|
||||
.plan9 => @panic("GET VADDR"),
|
||||
.c => unreachable,
|
||||
.wasm => unreachable,
|
||||
.spirv => unreachable,
|
||||
@ -633,6 +653,7 @@ pub const File = struct {
|
||||
c,
|
||||
wasm,
|
||||
spirv,
|
||||
plan9,
|
||||
};
|
||||
|
||||
pub const ErrorFlags = struct {
|
||||
@ -641,6 +662,7 @@ pub const File = struct {
|
||||
|
||||
pub const C = @import("link/C.zig");
|
||||
pub const Coff = @import("link/Coff.zig");
|
||||
pub const Plan9 = @import("link/Plan9.zig");
|
||||
pub const Elf = @import("link/Elf.zig");
|
||||
pub const MachO = @import("link/MachO.zig");
|
||||
pub const SpirV = @import("link/SpirV.zig");
|
||||
|
||||
378
src/link/Plan9.zig
Normal file
378
src/link/Plan9.zig
Normal file
@ -0,0 +1,378 @@
|
||||
//! This implementation does all the linking work in flush(). A future improvement
|
||||
//! would be to add incremental linking in a similar way as ELF does.
|
||||
|
||||
const Plan9 = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const link = @import("../link.zig");
|
||||
const Module = @import("../Module.zig");
|
||||
const Compilation = @import("../Compilation.zig");
|
||||
const aout = @import("Plan9/aout.zig");
|
||||
const codegen = @import("../codegen.zig");
|
||||
const trace = @import("../tracy.zig").trace;
|
||||
const mem = std.mem;
|
||||
const File = link.File;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const log = std.log.scoped(.link);
|
||||
const assert = std.debug.assert;
|
||||
|
||||
base: link.File,
|
||||
sixtyfour_bit: bool,
|
||||
error_flags: File.ErrorFlags = File.ErrorFlags{},
|
||||
bases: Bases,
|
||||
|
||||
decl_table: std.AutoArrayHashMapUnmanaged(*Module.Decl, void) = .{},
|
||||
/// is just casted down when 32 bit
|
||||
syms: std.ArrayListUnmanaged(aout.Sym) = .{},
|
||||
text_buf: std.ArrayListUnmanaged(u8) = .{},
|
||||
data_buf: std.ArrayListUnmanaged(u8) = .{},
|
||||
|
||||
hdr: aout.ExecHdr = undefined,
|
||||
|
||||
entry_decl: ?*Module.Decl = null,
|
||||
|
||||
got: std.ArrayListUnmanaged(u64) = .{},
|
||||
const Bases = struct {
|
||||
text: u64,
|
||||
/// the addr of the got
|
||||
data: u64,
|
||||
};
|
||||
|
||||
fn getAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {
|
||||
return addr + switch (t) {
|
||||
.T, .t, .l, .L => self.bases.text,
|
||||
.D, .d, .B, .b => self.bases.data,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
/// opposite of getAddr
|
||||
fn takeAddr(self: Plan9, addr: u64, t: aout.Sym.Type) u64 {
|
||||
return addr - switch (t) {
|
||||
.T, .t, .l, .L => self.bases.text,
|
||||
.D, .d, .B, .b => self.bases.data,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn getSymAddr(self: Plan9, s: aout.Sym) u64 {
|
||||
return self.getAddr(s.value, s.type);
|
||||
}
|
||||
|
||||
pub const DeclBlock = struct {
|
||||
type: aout.Sym.Type,
|
||||
/// offset in the text or data sects
|
||||
offset: ?u64,
|
||||
/// offset into syms
|
||||
sym_index: ?usize,
|
||||
/// offset into got
|
||||
got_index: ?usize,
|
||||
pub const empty = DeclBlock{
|
||||
.type = .t,
|
||||
.offset = null,
|
||||
.sym_index = null,
|
||||
.got_index = null,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn defaultBaseAddrs(arch: std.Target.Cpu.Arch) Bases {
|
||||
return switch (arch) {
|
||||
.x86_64 => .{
|
||||
// 0x28 => 40 == header size
|
||||
.text = 0x200028,
|
||||
.data = 0x400000,
|
||||
},
|
||||
.i386 => .{
|
||||
// 0x20 => 32 == header size
|
||||
.text = 0x200020,
|
||||
.data = 0x400000,
|
||||
},
|
||||
else => std.debug.panic("find default base address for {}", .{arch}),
|
||||
};
|
||||
}
|
||||
|
||||
pub const PtrWidth = enum { p32, p64 };
|
||||
|
||||
pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Plan9 {
|
||||
if (options.use_llvm)
|
||||
return error.LLVMBackendDoesNotSupportPlan9;
|
||||
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);
|
||||
self.* = .{
|
||||
.base = .{
|
||||
.tag = .plan9,
|
||||
.options = options,
|
||||
.allocator = gpa,
|
||||
.file = null,
|
||||
},
|
||||
.sixtyfour_bit = sixtyfour_bit,
|
||||
.bases = undefined,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
|
||||
_ = module;
|
||||
_ = try self.decl_table.getOrPut(self.base.allocator, decl);
|
||||
}
|
||||
|
||||
pub fn flush(self: *Plan9, comp: *Compilation) !void {
|
||||
assert(!self.base.options.use_lld);
|
||||
|
||||
switch (self.base.options.effectiveOutputMode()) {
|
||||
.Exe => {},
|
||||
// plan9 object files are totally different
|
||||
.Obj => return error.TODOImplementPlan9Objs,
|
||||
.Lib => return error.TODOImplementWritingLibFiles,
|
||||
}
|
||||
return self.flushModule(comp);
|
||||
}
|
||||
|
||||
pub fn flushModule(self: *Plan9, comp: *Compilation) !void {
|
||||
_ = comp;
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
log.debug("flushModule", .{});
|
||||
|
||||
defer assert(self.hdr.entry != 0x0);
|
||||
|
||||
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
|
||||
|
||||
self.text_buf.items.len = 0;
|
||||
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.sixtyfour_bit) @as(u32, 4) else 8);
|
||||
// temporary buffer
|
||||
var code_buffer = std.ArrayList(u8).init(self.base.allocator);
|
||||
defer code_buffer.deinit();
|
||||
{
|
||||
for (self.decl_table.keys()) |decl| {
|
||||
if (!decl.has_tv) continue;
|
||||
const is_fn = (decl.ty.zigTypeTag() == .Fn);
|
||||
|
||||
log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name });
|
||||
decl.link.plan9 = if (is_fn) .{
|
||||
.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(self.data_buf.items.len, .d),
|
||||
.type = .d,
|
||||
.sym_index = decl.link.plan9.sym_index,
|
||||
.got_index = decl.link.plan9.got_index,
|
||||
};
|
||||
self.got.items[decl.link.plan9.got_index.?] = decl.link.plan9.offset.?;
|
||||
if (decl.link.plan9.sym_index) |s| {
|
||||
self.syms.items[s] = .{
|
||||
.value = decl.link.plan9.offset.?,
|
||||
.type = decl.link.plan9.type,
|
||||
.name = mem.span(decl.name),
|
||||
};
|
||||
} else {
|
||||
try self.syms.append(self.base.allocator, .{
|
||||
.value = decl.link.plan9.offset.?,
|
||||
.type = decl.link.plan9.type,
|
||||
.name = mem.span(decl.name),
|
||||
});
|
||||
decl.link.plan9.sym_index = self.syms.items.len - 1;
|
||||
}
|
||||
|
||||
if (module.decl_exports.get(decl)) |exports| {
|
||||
for (exports) |exp| {
|
||||
// plan9 does not support custom sections
|
||||
if (exp.options.section) |section_name| {
|
||||
if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) {
|
||||
try module.failed_exports.put(module.gpa, exp, try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "plan9 does not support extra sections", .{}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (std.mem.eql(u8, exp.options.name, "_start")) {
|
||||
std.debug.assert(decl.link.plan9.type == .t); // we tried to link a non-function as the entry
|
||||
self.entry_decl = decl;
|
||||
}
|
||||
if (exp.link.plan9) |i| {
|
||||
self.syms.items[i] = .{
|
||||
.value = decl.link.plan9.offset.?,
|
||||
.type = decl.link.plan9.type.toGlobal(),
|
||||
.name = exp.options.name,
|
||||
};
|
||||
} else {
|
||||
try self.syms.append(self.base.allocator, .{
|
||||
.value = decl.link.plan9.offset.?,
|
||||
.type = decl.link.plan9.type.toGlobal(),
|
||||
.name = exp.options.name,
|
||||
});
|
||||
exp.link.plan9 = self.syms.items.len - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("codegen decl {*} ({s})", .{ decl, decl.name });
|
||||
const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
|
||||
.ty = decl.ty,
|
||||
.val = decl.val,
|
||||
}, &code_buffer, .{ .none = {} });
|
||||
const code = switch (res) {
|
||||
.externally_managed => |x| x,
|
||||
.appended => code_buffer.items,
|
||||
.fail => |em| {
|
||||
decl.analysis = .codegen_failure;
|
||||
try module.failed_decls.put(module.gpa, decl, em);
|
||||
// TODO try to do more decls
|
||||
return;
|
||||
},
|
||||
};
|
||||
if (is_fn) {
|
||||
try self.text_buf.appendSlice(self.base.allocator, code);
|
||||
code_buffer.items.len = 0;
|
||||
} else {
|
||||
try self.data_buf.appendSlice(self.base.allocator, code);
|
||||
code_buffer.items.len = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write the got
|
||||
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());
|
||||
}
|
||||
} else {
|
||||
for (self.got.items) |p, i| {
|
||||
mem.writeInt(u64, self.data_buf.items[i * 8 ..][0..8], p, self.base.options.target.cpu.arch.endian());
|
||||
}
|
||||
}
|
||||
|
||||
self.hdr.entry = @truncate(u32, self.entry_decl.?.link.plan9.offset.?);
|
||||
|
||||
// edata, end, etext
|
||||
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();
|
||||
try self.writeSyms(&sym_buf);
|
||||
|
||||
// generate the header
|
||||
self.hdr = .{
|
||||
.magic = try aout.magicFromArch(self.base.options.target.cpu.arch),
|
||||
.text = @intCast(u32, self.text_buf.items.len),
|
||||
.data = @intCast(u32, self.data_buf.items.len),
|
||||
.syms = @intCast(u32, sym_buf.items.len),
|
||||
.bss = 0,
|
||||
.pcsz = 0,
|
||||
.spsz = 0,
|
||||
.entry = self.hdr.entry,
|
||||
};
|
||||
|
||||
const file = self.base.file.?;
|
||||
|
||||
var hdr_buf = self.hdr.toU8s();
|
||||
const hdr_slice: []const u8 = &hdr_buf;
|
||||
// account for the fat header
|
||||
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!
|
||||
var vectors: [4]std.os.iovec_const = .{
|
||||
.{ .iov_base = hdr_slice.ptr, .iov_len = hdr_size },
|
||||
.{ .iov_base = self.text_buf.items.ptr, .iov_len = self.text_buf.items.len },
|
||||
.{ .iov_base = self.data_buf.items.ptr, .iov_len = self.data_buf.items.len },
|
||||
.{ .iov_base = sym_buf.items.ptr, .iov_len = sym_buf.items.len },
|
||||
// TODO spsz, pcsz
|
||||
};
|
||||
try file.pwritevAll(&vectors, 0);
|
||||
}
|
||||
pub fn freeDecl(self: *Plan9, decl: *Module.Decl) void {
|
||||
assert(self.decl_table.swapRemove(decl));
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
self: *Plan9,
|
||||
module: *Module,
|
||||
decl: *Module.Decl,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
// we do all the things in flush
|
||||
_ = self;
|
||||
_ = module;
|
||||
_ = decl;
|
||||
_ = exports;
|
||||
}
|
||||
pub fn deinit(self: *Plan9) void {
|
||||
self.decl_table.deinit(self.base.allocator);
|
||||
self.syms.deinit(self.base.allocator);
|
||||
self.text_buf.deinit(self.base.allocator);
|
||||
self.data_buf.deinit(self.base.allocator);
|
||||
self.got.deinit(self.base.allocator);
|
||||
}
|
||||
|
||||
pub const Export = ?usize;
|
||||
pub const base_tag = .plan9;
|
||||
pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Plan9 {
|
||||
if (options.use_llvm)
|
||||
return error.LLVMBackendDoesNotSupportPlan9;
|
||||
assert(options.object_format == .plan9);
|
||||
const file = try options.emit.?.directory.handle.createFile(sub_path, .{
|
||||
.truncate = false,
|
||||
.read = true,
|
||||
.mode = link.determineMode(options),
|
||||
});
|
||||
errdefer file.close();
|
||||
|
||||
const self = try createEmpty(allocator, options);
|
||||
errdefer self.base.destroy();
|
||||
|
||||
self.bases = defaultBaseAddrs(options.target.cpu.arch);
|
||||
|
||||
// first 3 symbols in our table are edata, end, etext
|
||||
try self.syms.appendSlice(self.base.allocator, &.{
|
||||
.{
|
||||
.value = 0xcafebabe,
|
||||
.type = .B,
|
||||
.name = "edata",
|
||||
},
|
||||
.{
|
||||
.value = 0xcafebabe,
|
||||
.type = .B,
|
||||
.name = "end",
|
||||
},
|
||||
.{
|
||||
.value = 0xcafebabe,
|
||||
.type = .T,
|
||||
.name = "etext",
|
||||
},
|
||||
});
|
||||
|
||||
self.base.file = file;
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
|
||||
const writer = buf.writer();
|
||||
for (self.syms.items) |sym| {
|
||||
if (!self.sixtyfour_bit) {
|
||||
try writer.writeIntBig(u32, @intCast(u32, sym.value));
|
||||
} else {
|
||||
try writer.writeIntBig(u64, sym.value);
|
||||
}
|
||||
try writer.writeByte(@enumToInt(sym.type));
|
||||
try writer.writeAll(std.mem.span(sym.name));
|
||||
try writer.writeByte(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
|
||||
try self.got.append(self.base.allocator, 0xdeadbeef);
|
||||
decl.link.plan9.got_index = self.got.items.len - 1;
|
||||
}
|
||||
114
src/link/Plan9/aout.zig
Normal file
114
src/link/Plan9/aout.zig
Normal file
@ -0,0 +1,114 @@
|
||||
const std = @import("std");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
/// All integers are in big-endian format (needs a byteswap).
|
||||
pub const ExecHdr = extern struct {
|
||||
magic: u32,
|
||||
text: u32,
|
||||
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,
|
||||
comptime {
|
||||
assert(@sizeOf(@This()) == 32);
|
||||
}
|
||||
/// It is up to the caller to disgard the last 8 bytes if the header is not fat.
|
||||
pub fn toU8s(self: *@This()) [40]u8 {
|
||||
var buf: [40]u8 = undefined;
|
||||
var i: u8 = 0;
|
||||
inline for (std.meta.fields(@This())) |f| {
|
||||
std.mem.writeIntSliceBig(u32, buf[i .. i + 4], @field(self, f.name));
|
||||
i += 4;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Sym = struct {
|
||||
/// Big endian in the file
|
||||
value: u64,
|
||||
type: Type,
|
||||
name: []const u8,
|
||||
|
||||
/// The type field is one of the following characters with the
|
||||
/// high bit set:
|
||||
/// T text segment symbol
|
||||
/// t static text segment symbol
|
||||
/// L leaf function text segment symbol
|
||||
/// l static leaf function text segment symbol
|
||||
/// D data segment symbol
|
||||
/// d static data segment symbol
|
||||
/// B bss segment symbol
|
||||
/// b static bss segment symbol
|
||||
/// a automatic (local) variable symbol
|
||||
/// p function parameter symbol
|
||||
/// f source file name components
|
||||
/// z source file name
|
||||
/// Z source file line offset
|
||||
/// m for '.frame'
|
||||
pub const Type = enum(u8) {
|
||||
T = 0x80 | 'T',
|
||||
t = 0x80 | 't',
|
||||
L = 0x80 | 'L',
|
||||
l = 0x80 | 'l',
|
||||
D = 0x80 | 'D',
|
||||
d = 0x80 | 'd',
|
||||
B = 0x80 | 'B',
|
||||
b = 0x80 | 'b',
|
||||
a = 0x80 | 'a',
|
||||
p = 0x80 | 'p',
|
||||
f = 0x80 | 'f',
|
||||
z = 0x80 | 'z',
|
||||
Z = 0x80 | 'Z',
|
||||
m = 0x80 | 'm',
|
||||
|
||||
pub fn toGlobal(self: Type) Type {
|
||||
return switch (self) {
|
||||
.t => .T,
|
||||
.b => .B,
|
||||
.d => .D,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const HDR_MAGIC = 0x00008000;
|
||||
pub inline fn _MAGIC(f: anytype, b: anytype) @TypeOf(f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7))) {
|
||||
return f | ((((@as(c_int, 4) * b) + @as(c_int, 0)) * b) + @as(c_int, 7));
|
||||
}
|
||||
pub const A_MAGIC = _MAGIC(0, 8); // 68020
|
||||
pub const I_MAGIC = _MAGIC(0, 11); // intel 386
|
||||
pub const J_MAGIC = _MAGIC(0, 12); // intel 960 (retired)
|
||||
pub const K_MAGIC = _MAGIC(0, 13); // sparc
|
||||
pub const V_MAGIC = _MAGIC(0, 16); // mips 3000 BE
|
||||
pub const X_MAGIC = _MAGIC(0, 17); // att dsp 3210 (retired)
|
||||
pub const M_MAGIC = _MAGIC(0, 18); // mips 4000 BE
|
||||
pub const D_MAGIC = _MAGIC(0, 19); // amd 29000 (retired)
|
||||
pub const E_MAGIC = _MAGIC(0, 20); // arm
|
||||
pub const Q_MAGIC = _MAGIC(0, 21); // powerpc
|
||||
pub const N_MAGIC = _MAGIC(0, 22); // mips 4000 LE
|
||||
pub const L_MAGIC = _MAGIC(0, 23); // dec alpha (retired)
|
||||
pub const P_MAGIC = _MAGIC(0, 24); // mips 3000 LE
|
||||
pub const U_MAGIC = _MAGIC(0, 25); // sparc64
|
||||
pub const S_MAGIC = _MAGIC(HDR_MAGIC, 26); // amd64
|
||||
pub const T_MAGIC = _MAGIC(HDR_MAGIC, 27); // powerpc64
|
||||
pub const R_MAGIC = _MAGIC(HDR_MAGIC, 28); // arm64
|
||||
|
||||
pub fn magicFromArch(arch: std.Target.Cpu.Arch) !u32 {
|
||||
return switch (arch) {
|
||||
.i386 => I_MAGIC,
|
||||
.sparc => K_MAGIC, // TODO should sparcv9 and sparcel go here?
|
||||
.mips => V_MAGIC,
|
||||
.arm => E_MAGIC,
|
||||
.aarch64 => R_MAGIC,
|
||||
.powerpc => Q_MAGIC,
|
||||
.powerpc64 => T_MAGIC,
|
||||
.x86_64 => S_MAGIC,
|
||||
else => error.ArchNotSupportedByPlan9,
|
||||
};
|
||||
}
|
||||
@ -244,7 +244,7 @@ pub fn supportsStackProbing(target: std.Target) bool {
|
||||
|
||||
pub fn osToLLVM(os_tag: std.Target.Os.Tag) llvm.OSType {
|
||||
return switch (os_tag) {
|
||||
.freestanding, .other, .opencl, .glsl450, .vulkan => .UnknownOS,
|
||||
.freestanding, .other, .opencl, .glsl450, .vulkan, .plan9 => .UnknownOS,
|
||||
.windows, .uefi => .Win32,
|
||||
.ananas => .Ananas,
|
||||
.cloudabi => .CloudABI,
|
||||
|
||||
@ -3290,6 +3290,7 @@ pub const CType = enum {
|
||||
.openbsd,
|
||||
.wasi,
|
||||
.emscripten,
|
||||
.plan9,
|
||||
=> switch (self) {
|
||||
.short,
|
||||
.ushort,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user