Support Asahi Linux (aarch64-linux)
This commit is contained in:
parent
3c6aaf67d0
commit
128a3ee508
@ -648,12 +648,22 @@ pub fn compileCSourceFile(context: *const Context, arguments: []const []const u8
|
||||
"/usr/lib/clang/17/include",
|
||||
"/usr/include",
|
||||
"/usr/include/x86_64-linux-gnu",
|
||||
} else &.{
|
||||
"/usr/include/c++/13.2.1",
|
||||
"/usr/include/c++/13.2.1/x86_64-pc-linux-gnu",
|
||||
"/usr/lib/clang/17/include",
|
||||
"/usr/include",
|
||||
"/usr/include/linux",
|
||||
} else switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => &.{
|
||||
"/usr/include/c++/13.2.1",
|
||||
"/usr/include/c++/13.2.1/x86_64-pc-linux-gnu",
|
||||
"/usr/lib/clang/17/include",
|
||||
"/usr/include",
|
||||
"/usr/include/linux",
|
||||
},
|
||||
.aarch64 => &.{
|
||||
"/usr/include/c++/13",
|
||||
"/usr/include/c++/13/aarch64-redhat-linux",
|
||||
"/usr/lib/clang/17/include",
|
||||
"/usr/include",
|
||||
"/usr/include/linux",
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => unreachable, //@compileError("ABI not supported"),
|
||||
},
|
||||
@ -2771,28 +2781,25 @@ const Abi = enum {
|
||||
pub fn buildExecutable(context: *const Context, arguments: []const []const u8, options: ExecutableOptions) !void {
|
||||
var maybe_executable_path: ?[]const u8 = null;
|
||||
var maybe_main_package_path: ?[]const u8 = null;
|
||||
var arch: Arch = undefined;
|
||||
var os: Os = undefined;
|
||||
var abi: Abi = undefined;
|
||||
|
||||
switch (@import("builtin").os.tag) {
|
||||
.linux => {
|
||||
arch = .x86_64;
|
||||
os = .linux;
|
||||
abi = .gnu;
|
||||
},
|
||||
.macos => {
|
||||
arch = .aarch64;
|
||||
os = .macos;
|
||||
abi = .none;
|
||||
},
|
||||
.windows => {
|
||||
arch = .x86_64;
|
||||
os = .windows;
|
||||
abi = .gnu;
|
||||
},
|
||||
// TODO: make these mutable
|
||||
const arch: Arch = switch (@import("builtin").cpu.arch) {
|
||||
.aarch64 => .aarch64,
|
||||
.x86_64 => .x86_64,
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
const os: Os = switch (@import("builtin").os.tag) {
|
||||
.linux => .linux,
|
||||
.macos => .macos,
|
||||
.windows => .windows,
|
||||
else => unreachable,
|
||||
};
|
||||
const abi: Abi = switch (@import("builtin").os.tag) {
|
||||
.linux => .gnu,
|
||||
.macos => .none,
|
||||
.windows => .gnu,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
var maybe_only_parse: ?bool = null;
|
||||
var link_libc = false;
|
||||
@ -2982,7 +2989,7 @@ pub fn buildExecutable(context: *const Context, arguments: []const []const u8, o
|
||||
try unit.compile(context);
|
||||
}
|
||||
|
||||
fn createUnit(context: *const Context, arguments: struct{
|
||||
fn createUnit(context: *const Context, arguments: struct {
|
||||
main_package_path: []const u8,
|
||||
executable_path: []const u8,
|
||||
object_path: []const u8,
|
||||
@ -2996,7 +3003,7 @@ fn createUnit(context: *const Context, arguments: struct{
|
||||
name: []const u8,
|
||||
is_test: bool,
|
||||
c_source_files: []const []const u8,
|
||||
}) !*Unit{
|
||||
}) !*Unit {
|
||||
const unit = try context.allocator.create(Unit);
|
||||
unit.* = .{
|
||||
.descriptor = .{
|
||||
@ -4687,86 +4694,89 @@ pub const Builder = struct {
|
||||
};
|
||||
},
|
||||
.@"asm" => {
|
||||
const architecture = InlineAssembly.x86_64;
|
||||
switch (unit.descriptor.arch) {
|
||||
inline else => |arch| {
|
||||
const architecture = @field(InlineAssembly, @tagName(arch));
|
||||
assert(argument_node_list.len == 1);
|
||||
const assembly_block_node = unit.getNode(argument_node_list[0]);
|
||||
const instruction_node_list = unit.getNodeList(assembly_block_node.left);
|
||||
var instructions = try context.arena.new_array(InlineAssembly.Instruction.Index, instruction_node_list.len);
|
||||
instructions.len = 0;
|
||||
|
||||
assert(argument_node_list.len == 1);
|
||||
const assembly_block_node = unit.getNode(argument_node_list[0]);
|
||||
const instruction_node_list = unit.getNodeList(assembly_block_node.left);
|
||||
var instructions = try context.arena.new_array(InlineAssembly.Instruction.Index, instruction_node_list.len);
|
||||
instructions.len = 0;
|
||||
for (instruction_node_list) |assembly_statement_node_index| {
|
||||
const assembly_instruction_node = unit.getNode(assembly_statement_node_index);
|
||||
const assembly_instruction_name_node = unit.getNode(assembly_instruction_node.left);
|
||||
const instruction_name = unit.getExpectedTokenBytes(assembly_instruction_name_node.token, .identifier);
|
||||
const instruction = inline for (@typeInfo(architecture.Instruction).Enum.fields) |instruction_enum_field| {
|
||||
if (byte_equal(instruction_name, instruction_enum_field.name)) {
|
||||
break @field(architecture.Instruction, instruction_enum_field.name);
|
||||
}
|
||||
} else unreachable;
|
||||
const operand_nodes = unit.getNodeList(assembly_instruction_node.right);
|
||||
|
||||
for (instruction_node_list) |assembly_statement_node_index| {
|
||||
const assembly_instruction_node = unit.getNode(assembly_statement_node_index);
|
||||
const assembly_instruction_name_node = unit.getNode(assembly_instruction_node.left);
|
||||
const instruction_name = unit.getExpectedTokenBytes(assembly_instruction_name_node.token, .identifier);
|
||||
const instruction = inline for (@typeInfo(architecture.Instruction).Enum.fields) |instruction_enum_field| {
|
||||
if (byte_equal(instruction_name, instruction_enum_field.name)) {
|
||||
break @field(architecture.Instruction, instruction_enum_field.name);
|
||||
}
|
||||
} else unreachable;
|
||||
const operand_nodes = unit.getNodeList(assembly_instruction_node.right);
|
||||
var operands = try context.arena.new_array(InlineAssembly.Operand, operand_nodes.len);
|
||||
operands.len = 0;
|
||||
|
||||
var operands = try context.arena.new_array(InlineAssembly.Operand, operand_nodes.len);
|
||||
operands.len = 0;
|
||||
for (operand_nodes) |operand_node_index| {
|
||||
const operand_node = unit.getNode(operand_node_index);
|
||||
const operand: InlineAssembly.Operand = switch (operand_node.id) {
|
||||
.assembly_register => blk: {
|
||||
const register_name = unit.getExpectedTokenBytes(operand_node.token, .identifier);
|
||||
|
||||
for (operand_nodes) |operand_node_index| {
|
||||
const operand_node = unit.getNode(operand_node_index);
|
||||
const operand: InlineAssembly.Operand = switch (operand_node.id) {
|
||||
.assembly_register => blk: {
|
||||
const register_name = unit.getExpectedTokenBytes(operand_node.token, .identifier);
|
||||
|
||||
const register = inline for (@typeInfo(architecture.Register).Enum.fields) |register_enum_field| {
|
||||
if (byte_equal(register_name, register_enum_field.name)) {
|
||||
break @field(architecture.Register, register_enum_field.name);
|
||||
}
|
||||
} else unreachable;
|
||||
break :blk .{
|
||||
.register = @intFromEnum(register),
|
||||
const register = inline for (@typeInfo(architecture.Register).Enum.fields) |register_enum_field| {
|
||||
if (byte_equal(register_name, register_enum_field.name)) {
|
||||
break @field(architecture.Register, register_enum_field.name);
|
||||
}
|
||||
} else unreachable;
|
||||
break :blk .{
|
||||
.register = @intFromEnum(register),
|
||||
};
|
||||
},
|
||||
.number_literal => switch (std.zig.parseNumberLiteral(unit.getExpectedTokenBytes(operand_node.token, .number_literal))) {
|
||||
.int => |integer| .{
|
||||
.number_literal = integer,
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.assembly_code_expression => .{
|
||||
.value = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, operand_node.left, .left),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
const index = operands.len;
|
||||
operands.len += 1;
|
||||
operands[index] = operand;
|
||||
}
|
||||
|
||||
const instruction_index = unit.assembly_instructions.append_index(.{
|
||||
.id = @intFromEnum(instruction),
|
||||
.operands = operands,
|
||||
});
|
||||
|
||||
const index = instructions.len;
|
||||
instructions.len += 1;
|
||||
instructions[index] = instruction_index;
|
||||
}
|
||||
|
||||
const inline_assembly = unit.inline_assembly.append_index(.{
|
||||
.instructions = instructions,
|
||||
});
|
||||
|
||||
const inline_asm = unit.instructions.append_index(.{
|
||||
.inline_assembly = inline_assembly,
|
||||
});
|
||||
try builder.appendInstruction(unit, inline_asm);
|
||||
|
||||
return .{
|
||||
.value = .{
|
||||
.runtime = inline_asm,
|
||||
},
|
||||
.number_literal => switch (std.zig.parseNumberLiteral(unit.getExpectedTokenBytes(operand_node.token, .number_literal))) {
|
||||
.int => |integer| .{
|
||||
.number_literal = integer,
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.assembly_code_expression => .{
|
||||
.value = try builder.resolveRuntimeValue(unit, context, Type.Expect.none, operand_node.left, .left),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
// TODO: WARN fix
|
||||
.type = .noreturn,
|
||||
};
|
||||
|
||||
const index = operands.len;
|
||||
operands.len += 1;
|
||||
operands[index] = operand;
|
||||
}
|
||||
|
||||
const instruction_index = unit.assembly_instructions.append_index(.{
|
||||
.id = @intFromEnum(instruction),
|
||||
.operands = operands,
|
||||
});
|
||||
|
||||
const index = instructions.len;
|
||||
instructions.len += 1;
|
||||
instructions[index] = instruction_index;
|
||||
}
|
||||
|
||||
const inline_assembly = unit.inline_assembly.append_index(.{
|
||||
.instructions = instructions,
|
||||
});
|
||||
|
||||
const inline_asm = unit.instructions.append_index(.{
|
||||
.inline_assembly = inline_assembly,
|
||||
});
|
||||
try builder.appendInstruction(unit, inline_asm);
|
||||
|
||||
return .{
|
||||
.value = .{
|
||||
.runtime = inline_asm,
|
||||
},
|
||||
// TODO: WARN fix
|
||||
.type = .noreturn,
|
||||
};
|
||||
}
|
||||
},
|
||||
.cast => {
|
||||
assert(argument_node_list.len == 1);
|
||||
@ -6289,7 +6299,7 @@ pub const Builder = struct {
|
||||
const pointer_to_global = try unit.getPointerType(.{
|
||||
.type = global.declaration.type,
|
||||
.termination = switch (type_expect) {
|
||||
.none => .none,
|
||||
.none, .cast => .none,
|
||||
.type => |type_index| switch (unit.types.get(type_index).*) {
|
||||
.pointer => |pointer| pointer.termination,
|
||||
else => .none,
|
||||
@ -6297,7 +6307,7 @@ pub const Builder = struct {
|
||||
else => unreachable,
|
||||
},
|
||||
.mutability = switch (type_expect) {
|
||||
.none => .@"var",
|
||||
.none, .cast => .@"var",
|
||||
.type => |type_index| switch (unit.types.get(type_index).*) {
|
||||
.pointer => |pointer| pointer.mutability,
|
||||
else => .@"var",
|
||||
@ -10034,6 +10044,73 @@ pub const Builder = struct {
|
||||
}
|
||||
},
|
||||
.character_literal => return try unit.resolve_character_literal(node_index),
|
||||
.negation => {
|
||||
assert(node.left != .null);
|
||||
assert(node.right == .null);
|
||||
|
||||
const value = try builder.resolveComptimeValue(unit, context, type_expect, .{}, node.left, null, .right, &.{}, null, &.{});
|
||||
switch (value) {
|
||||
.constant_int => |constant_int| switch (type_expect) {
|
||||
.type => |type_index| {
|
||||
assert(type_index == value.type);
|
||||
const expected_type = unit.types.get(type_index);
|
||||
switch (expected_type.*) {
|
||||
.integer => |integer| switch (integer.kind) {
|
||||
.materialized_int => {
|
||||
assert(integer.signedness == .signed);
|
||||
var v: i64 = @intCast(constant_int.value);
|
||||
v = 0 - v;
|
||||
|
||||
return .{
|
||||
.constant_int = .{
|
||||
.value = @bitCast(v),
|
||||
},
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.comptime_int => |ct_int| switch (type_expect) {
|
||||
.type => |type_index| switch (unit.types.get(type_index).*) {
|
||||
.integer => |integer| switch (integer.kind) {
|
||||
.materialized_int => {
|
||||
assert(integer.signedness == .signed);
|
||||
var v = switch (ct_int.signedness) {
|
||||
.signed => 0 - @as(i64, @intCast(ct_int.value)),
|
||||
.unsigned => @as(i64, @intCast(ct_int.value)),
|
||||
};
|
||||
v = 0 - v;
|
||||
|
||||
return .{
|
||||
.constant_int = .{
|
||||
.value = @bitCast(v),
|
||||
},
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
.none => {
|
||||
return .{
|
||||
.comptime_int = .{
|
||||
.value = ct_int.value,
|
||||
.signedness = switch (ct_int.signedness) {
|
||||
.unsigned => .signed,
|
||||
.signed => .unsigned,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
@ -12299,6 +12376,7 @@ pub const Builder = struct {
|
||||
.negation => block: {
|
||||
assert(node.left != .null);
|
||||
assert(node.right == .null);
|
||||
|
||||
const value = try builder.resolveRuntimeValue(unit, context, type_expect, node.left, .right);
|
||||
|
||||
switch (value.value) {
|
||||
@ -18095,6 +18173,51 @@ pub const InlineAssembly = struct {
|
||||
rdi,
|
||||
};
|
||||
};
|
||||
|
||||
pub const aarch64 = struct {
|
||||
pub const Instruction = enum {
|
||||
b,
|
||||
mov,
|
||||
};
|
||||
|
||||
pub const Register = enum {
|
||||
fp,
|
||||
lr,
|
||||
sp,
|
||||
x0,
|
||||
x1,
|
||||
x2,
|
||||
x3,
|
||||
x4,
|
||||
x5,
|
||||
x6,
|
||||
x7,
|
||||
x8,
|
||||
x9,
|
||||
x10,
|
||||
x11,
|
||||
x12,
|
||||
x13,
|
||||
x14,
|
||||
x15,
|
||||
x16,
|
||||
x17,
|
||||
x18,
|
||||
x19,
|
||||
x20,
|
||||
x21,
|
||||
x22,
|
||||
x23,
|
||||
x24,
|
||||
x25,
|
||||
x26,
|
||||
x27,
|
||||
x28,
|
||||
x29,
|
||||
x30,
|
||||
x31,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const LogKind = enum {
|
||||
|
@ -2674,12 +2674,72 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
_ = assembly_statements.pop();
|
||||
}
|
||||
|
||||
assembly_statements.appendSliceAssumeCapacity("\n\t");
|
||||
assembly_statements.appendSliceAssumeCapacity("\n");
|
||||
}
|
||||
|
||||
_ = assembly_statements.pop();
|
||||
|
||||
// try constraints.append_slice(context.allocator, ",~{dirflag},~{fpsr},~{flags}");
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
.aarch64 => {
|
||||
for (assembly_block.instructions) |assembly_instruction_index| {
|
||||
const instruction = unit.assembly_instructions.get(assembly_instruction_index);
|
||||
const instruction_id: Compilation.InlineAssembly.aarch64.Instruction = @enumFromInt(instruction.id);
|
||||
assembly_statements.appendSliceAssumeCapacity(@tagName(instruction_id));
|
||||
assembly_statements.appendAssumeCapacity(' ');
|
||||
|
||||
if (instruction.operands.len > 0) {
|
||||
for (instruction.operands) |operand| {
|
||||
switch (operand) {
|
||||
.register => |register_value| {
|
||||
const register: Compilation.InlineAssembly.aarch64.Register = @enumFromInt(register_value);
|
||||
assembly_statements.appendSliceAssumeCapacity(@tagName(register));
|
||||
},
|
||||
.number_literal => |literal| {
|
||||
var buffer: [65]u8 = undefined;
|
||||
const number_literal = format_int(&buffer, literal, 10, false);
|
||||
const slice_ptr = number_literal.ptr - 1;
|
||||
const literal_slice = slice_ptr[0 .. number_literal.len + 1];
|
||||
literal_slice[0] = '#';
|
||||
assembly_statements.appendSliceAssumeCapacity(try context.arena.duplicate_bytes(literal_slice));
|
||||
},
|
||||
.value => |sema_value| {
|
||||
if (llvm.llvm_value_map.get(sema_value)) |v| {
|
||||
_ = v; // autofix
|
||||
unreachable;
|
||||
} else {
|
||||
const value = try llvm.emitLeftValue(unit, context, sema_value);
|
||||
var buffer: [65]u8 = undefined;
|
||||
const operand_number = format_int(&buffer, operand_values.len, 16, false);
|
||||
const slice_ptr = operand_number.ptr - 2;
|
||||
const operand_slice = slice_ptr[0 .. operand_number.len + 2];
|
||||
operand_slice[0] = '$';
|
||||
operand_slice[1] = '{';
|
||||
var new_buffer: [65]u8 = undefined;
|
||||
@memcpy(new_buffer[0..operand_slice.len], operand_slice);
|
||||
new_buffer[operand_slice.len] = '}';
|
||||
const new_slice = try context.arena.duplicate_bytes(new_buffer[0 .. operand_slice.len + 1]);
|
||||
assembly_statements.appendSliceAssumeCapacity(new_slice);
|
||||
operand_values.appendAssumeCapacity(value);
|
||||
const value_type = value.getType();
|
||||
operand_types.appendAssumeCapacity(value_type);
|
||||
constraints.appendAssumeCapacity('X');
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
assembly_statements.appendSliceAssumeCapacity(", ");
|
||||
}
|
||||
|
||||
_ = assembly_statements.pop();
|
||||
_ = assembly_statements.pop();
|
||||
}
|
||||
|
||||
assembly_statements.appendSliceAssumeCapacity("\n");
|
||||
}
|
||||
|
||||
_ = assembly_statements.pop();
|
||||
},
|
||||
}
|
||||
|
||||
const is_var_args = false;
|
||||
@ -2908,31 +2968,41 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
const function_type = LLVM.Context.getFunctionType(return_type, syscall_argument_types.ptr, syscall_argument_types.len, is_var_args) orelse unreachable;
|
||||
var constraints = BoundedArray(u8, 4096){};
|
||||
|
||||
const inline_asm = switch (unit.descriptor.arch) {
|
||||
.x86_64 => blk: {
|
||||
constraints.appendSliceAssumeCapacity("={rax}");
|
||||
|
||||
const syscall_registers = [7][]const u8{ "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9" };
|
||||
for (syscall_registers[0..syscall_argument_count]) |syscall_register| {
|
||||
constraints.appendAssumeCapacity(',');
|
||||
constraints.appendAssumeCapacity('{');
|
||||
constraints.appendSliceAssumeCapacity(syscall_register);
|
||||
constraints.appendAssumeCapacity('}');
|
||||
}
|
||||
|
||||
constraints.appendSliceAssumeCapacity(",~{rcx},~{r11},~{memory}");
|
||||
|
||||
const assembly = "syscall";
|
||||
const has_side_effects = true;
|
||||
const is_align_stack = true;
|
||||
const can_throw = false;
|
||||
const inline_assembly = LLVM.Value.InlineAssembly.get(function_type, assembly, assembly.len, &constraints.buffer, constraints.len, has_side_effects, is_align_stack, LLVM.Value.InlineAssembly.Dialect.@"at&t", can_throw) orelse return LLVM.Value.Error.inline_assembly;
|
||||
break :blk inline_assembly;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
const syscall_registers: [7][]const u8 = switch (unit.descriptor.arch) {
|
||||
.x86_64 => .{ "rax", "rdi", "rsi", "rdx", "r10", "r8", "r9" },
|
||||
.aarch64 => .{ "x8", "x0", "x1", "x2", "x3", "x4", "x5" },
|
||||
};
|
||||
const syscall_instruction: []const u8 = switch (unit.descriptor.arch) {
|
||||
.x86_64 => "syscall",
|
||||
.aarch64 => "svc #0",
|
||||
};
|
||||
const return_constraints: []const u8 = switch (unit.descriptor.arch) {
|
||||
.x86_64 => "={rax}",
|
||||
.aarch64 => "={x0}",
|
||||
};
|
||||
|
||||
const call_to_asm = llvm.builder.createCall(function_type, inline_asm.toValue(), syscall_arguments.ptr, syscall_arguments.len, "syscall", "syscall".len, null) orelse return LLVM.Value.Instruction.Error.call;
|
||||
const clobber_constraints: []const u8 = switch (unit.descriptor.arch) {
|
||||
.x86_64 => ",~{rcx},~{r11},~{memory}",
|
||||
.aarch64 => ",~{memory},~{cc}",
|
||||
};
|
||||
|
||||
constraints.appendSliceAssumeCapacity(return_constraints);
|
||||
|
||||
for (syscall_registers[0..syscall_argument_count]) |syscall_register| {
|
||||
constraints.appendAssumeCapacity(',');
|
||||
constraints.appendAssumeCapacity('{');
|
||||
constraints.appendSliceAssumeCapacity(syscall_register);
|
||||
constraints.appendAssumeCapacity('}');
|
||||
}
|
||||
constraints.appendSliceAssumeCapacity(clobber_constraints);
|
||||
|
||||
const has_side_effects = true;
|
||||
const is_align_stack = true;
|
||||
const can_throw = false;
|
||||
const inline_assembly = LLVM.Value.InlineAssembly.get(function_type, syscall_instruction.ptr, syscall_instruction.len, &constraints.buffer, constraints.len, has_side_effects, is_align_stack, LLVM.Value.InlineAssembly.Dialect.@"at&t", can_throw) orelse return LLVM.Value.Error.inline_assembly;
|
||||
|
||||
const call_to_asm = llvm.builder.createCall(function_type, inline_assembly.toValue(), syscall_arguments.ptr, syscall_arguments.len, "syscall", "syscall".len, null) orelse return LLVM.Value.Instruction.Error.call;
|
||||
|
||||
try llvm.llvm_instruction_map.put_no_clobber(instruction_index, call_to_asm.toValue());
|
||||
},
|
||||
.@"unreachable" => {
|
||||
@ -3298,7 +3368,10 @@ pub fn codegen(unit: *Compilation.Unit, context: *const Compilation.Context) !vo
|
||||
|
||||
// TODO: proper target selection
|
||||
const target_triple = switch (unit.descriptor.os) {
|
||||
.linux => "x86_64-linux-none",
|
||||
.linux => switch (unit.descriptor.arch) {
|
||||
.aarch64 => "aarch64-linux-none",
|
||||
.x86_64 => "x86_64-linux-none",
|
||||
},
|
||||
.macos => "aarch64-apple-macosx-none",
|
||||
.windows => "x86_64-windows-gnu",
|
||||
};
|
||||
|
@ -6,6 +6,7 @@ const log = std.log;
|
||||
const library = @import("../library.zig");
|
||||
const byte_equal = library.byte_equal;
|
||||
const enumFromString = library.enumFromString;
|
||||
const exit_with_error = library.exit_with_error;
|
||||
const MyAllocator = library.MyAllocator;
|
||||
const PinnedArray = library.PinnedArray;
|
||||
|
||||
@ -505,7 +506,7 @@ pub fn analyze(text: []const u8, token_buffer: *Token.Buffer) !Result {
|
||||
'A'...'Z', 'a'...'z' => {
|
||||
while (true) {
|
||||
switch (text[index]) {
|
||||
'A'...'Z', 'a'...'z' => index += 1,
|
||||
'A'...'Z', 'a'...'z', '0'...'9' => index += 1,
|
||||
else => break,
|
||||
}
|
||||
}
|
||||
@ -559,12 +560,13 @@ pub fn analyze(text: []const u8, token_buffer: *Token.Buffer) !Result {
|
||||
hex,
|
||||
bin,
|
||||
octal,
|
||||
decimal,
|
||||
};
|
||||
const representation: Representation = switch (text[index]) {
|
||||
'x' => .hex,
|
||||
else => unreachable,
|
||||
else => .decimal,
|
||||
};
|
||||
index += 1;
|
||||
index += @intFromBool(representation != .decimal);
|
||||
switch (representation) {
|
||||
.hex => {
|
||||
while (true) {
|
||||
@ -574,6 +576,20 @@ pub fn analyze(text: []const u8, token_buffer: *Token.Buffer) !Result {
|
||||
}
|
||||
}
|
||||
|
||||
_ = token_buffer.tokens.append(.{
|
||||
.id = .number_literal,
|
||||
.line = line_index,
|
||||
.offset = start_i,
|
||||
.length = index - start_i,
|
||||
});
|
||||
},
|
||||
.decimal => {
|
||||
switch (text[index]) {
|
||||
'0'...'9' => unreachable,
|
||||
else => {},
|
||||
}
|
||||
|
||||
|
||||
_ = token_buffer.tokens.append(.{
|
||||
.id = .number_literal,
|
||||
.line = line_index,
|
||||
@ -590,9 +606,16 @@ pub fn analyze(text: []const u8, token_buffer: *Token.Buffer) !Result {
|
||||
const ch_fmt = library.format_int(&ch_array, start_ch, 16, false);
|
||||
try Compilation.write(.panic, ch_fmt);
|
||||
try Compilation.write(.panic, "\n");
|
||||
std.posix.exit(0);
|
||||
exit_with_error();
|
||||
},
|
||||
}
|
||||
|
||||
const debug_asm_tokens = false;
|
||||
if (debug_asm_tokens) {
|
||||
try Compilation.write(.panic, "ASM token: '");
|
||||
try Compilation.write(.panic, text[start_i..index]);
|
||||
try Compilation.write(.panic, "'\n");
|
||||
}
|
||||
}
|
||||
|
||||
_ = token_buffer.tokens.append(.{
|
||||
|
@ -239,7 +239,7 @@ pub fn PinnedArrayAdvanced(comptime T: type, comptime MaybeIndex: ?type) type {
|
||||
array.ensure_capacity(1);
|
||||
const src = array.slice()[index..];
|
||||
array.length += 1;
|
||||
const dst = array.slice()[index + 1..];
|
||||
const dst = array.slice()[index + 1 ..];
|
||||
copy_backwards(T, dst, src);
|
||||
array.slice()[index] = item;
|
||||
}
|
||||
@ -707,3 +707,8 @@ pub fn align_forward(value: u64, alignment: u64) u64 {
|
||||
const mask = alignment - 1;
|
||||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
||||
pub fn exit_with_error() noreturn {
|
||||
@breakpoint();
|
||||
std.posix.exit(1);
|
||||
}
|
||||
|
@ -20,6 +20,17 @@ pub fn link(context: *const Compilation.Context, options: linker.Options) !void
|
||||
_ = argv.append(driver_program);
|
||||
_ = argv.append("--error-limit=0");
|
||||
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.aarch64 => switch (@import("builtin").os.tag) {
|
||||
.linux => {
|
||||
_ = argv.append("-znow");
|
||||
_ = argv.append_slice(&.{ "-m", "aarch64linux"});
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
// const output_path = out_path orelse "a.out";
|
||||
_ = argv.append("-o");
|
||||
_ = argv.append(options.output_file_path);
|
||||
@ -78,14 +89,30 @@ pub fn link(context: *const Compilation.Context, options: linker.Options) !void
|
||||
} else {
|
||||
if (options.link_libcpp) {
|
||||
assert(options.link_libc);
|
||||
_ = argv.append("/usr/lib/libstdc++.so");
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => _ = argv.append("/usr/lib/libstdc++.so"),
|
||||
.aarch64 => _ = argv.append("/usr/lib64/libstdc++.so.6"),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
if (options.link_libc) {
|
||||
_ = argv.append("/usr/lib/crt1.o");
|
||||
_ = argv.append("/usr/lib/crti.o");
|
||||
argv.append_slice(&.{ "-L", "/usr/lib" });
|
||||
argv.append_slice(&.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" });
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => {
|
||||
_ = argv.append("/usr/lib/crt1.o");
|
||||
_ = argv.append("/usr/lib/crti.o");
|
||||
argv.append_slice(&.{ "-L", "/usr/lib" });
|
||||
argv.append_slice(&.{ "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2" });
|
||||
},
|
||||
.aarch64 => {
|
||||
_ = argv.append("/usr/lib64/crt1.o");
|
||||
_ = argv.append("/usr/lib64/crti.o");
|
||||
argv.append_slice(&.{ "-L", "/usr/lib64" });
|
||||
argv.append_slice(&.{ "-dynamic-linker", "/lib/ld-linux-aarch64.so.1" });
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
_ = argv.append("--as-needed");
|
||||
_ = argv.append("-lm");
|
||||
_ = argv.append("-lpthread");
|
||||
@ -93,7 +120,16 @@ pub fn link(context: *const Compilation.Context, options: linker.Options) !void
|
||||
_ = argv.append("-ldl");
|
||||
_ = argv.append("-lrt");
|
||||
_ = argv.append("-lutil");
|
||||
_ = argv.append("/usr/lib/crtn.o");
|
||||
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => {
|
||||
_ = argv.append("/usr/lib/crtn.o");
|
||||
},
|
||||
.aarch64 => {
|
||||
_ = argv.append("/usr/lib64/crtn.o");
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
24
build.zig
24
build.zig
@ -446,7 +446,7 @@ pub fn build(b: *std.Build) !void {
|
||||
const result = try std.ChildProcess.run(.{
|
||||
.allocator = b.allocator,
|
||||
.argv = &.{
|
||||
"cc", "--version",
|
||||
"c++", "--version",
|
||||
},
|
||||
.max_output_bytes = 0xffffffffffffff,
|
||||
});
|
||||
@ -470,11 +470,27 @@ pub fn build(b: *std.Build) !void {
|
||||
unreachable;
|
||||
};
|
||||
|
||||
const cxx_include_base = try std.mem.concat(b.allocator, u8, &.{ "/usr/include/c++/", cxx_version });
|
||||
compiler.addObjectFile(.{ .cwd_relative = "/usr/lib/libstdc++.so" });
|
||||
const cxx_include_base = switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => try std.mem.concat(b.allocator, u8, &.{ "/usr/include/c++/", cxx_version }),
|
||||
.aarch64 => "/usr/include/c++/13",
|
||||
else => @compileError("Arch not supported"),
|
||||
};
|
||||
compiler.addObjectFile(.{
|
||||
.cwd_relative = switch (@import("builtin").cpu.arch) {
|
||||
.aarch64 => "/lib64/libstdc++.so.6",
|
||||
.x86_64 => "/usr/lib/libstdc++.so",
|
||||
else => @compileError("Arch not supported"),
|
||||
},
|
||||
});
|
||||
compiler.addIncludePath(.{ .cwd_relative = "/usr/include" });
|
||||
compiler.addIncludePath(.{ .cwd_relative = cxx_include_base });
|
||||
compiler.addIncludePath(.{ .cwd_relative = try std.mem.concat(b.allocator, u8, &.{ cxx_include_base, "/x86_64-pc-linux-gnu" }) });
|
||||
compiler.addIncludePath(.{
|
||||
.cwd_relative = try std.mem.concat(b.allocator, u8, &.{ cxx_include_base, switch (@import("builtin").cpu.arch) {
|
||||
.x86_64 => "/x86_64-pc-linux-gnu",
|
||||
.aarch64 => "/aarch64-redhat-linux",
|
||||
else => @compileError("Arch not supported"),
|
||||
} }),
|
||||
});
|
||||
compiler.addLibraryPath(.{ .cwd_relative = "/usr/lib" });
|
||||
}
|
||||
},
|
||||
|
@ -131,7 +131,7 @@ fn runBuildTests(allocator: Allocator, args: struct {
|
||||
const test_dir_path = "test/build";
|
||||
const test_names = try collectDirectoryDirEntries(allocator, test_dir_path);
|
||||
const test_dir_realpath = try std.fs.cwd().realpathAlloc(allocator, test_dir_path);
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, args.compiler_path);
|
||||
|
||||
try std.posix.chdir(test_dir_realpath);
|
||||
|
||||
const total_compilation_count = test_names.len;
|
||||
@ -142,16 +142,23 @@ fn runBuildTests(allocator: Allocator, args: struct {
|
||||
var failed_test_count: usize = 0;
|
||||
const total_test_count = test_names.len;
|
||||
|
||||
errdefer {
|
||||
std.posix.chdir(previous_cwd) catch unreachable;
|
||||
}
|
||||
|
||||
for (test_names) |test_name| {
|
||||
std.debug.print("{s}... ", .{test_name});
|
||||
try std.posix.chdir(test_name);
|
||||
|
||||
const compile_run = try std.ChildProcess.run(.{
|
||||
const compile_run = std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{ compiler_realpath, "build" },
|
||||
.argv = &.{ args.compiler_path, "build" },
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
}) catch |err| {
|
||||
const compilation_success = false;
|
||||
std.debug.print("[COMPILATION {s}] ", .{if (compilation_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
||||
return err;
|
||||
};
|
||||
|
||||
ran_compilation_count += 1;
|
||||
|
||||
@ -177,12 +184,20 @@ fn runBuildTests(allocator: Allocator, args: struct {
|
||||
|
||||
if (compilation_success and !args.self_hosted) {
|
||||
const test_path = try std.mem.concat(allocator, u8, &.{ "nat/", test_name });
|
||||
const test_run = try std.ChildProcess.run(.{
|
||||
const test_run = std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
// TODO: delete -main_source_file?
|
||||
.argv = &.{test_path},
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
}) catch |err| {
|
||||
const test_success = false;
|
||||
std.debug.print("[TEST {s}]\n", .{if (test_success) "\x1b[32mOK\x1b[0m" else "\x1b[31mFAILED\x1b[0m"});
|
||||
std.debug.print("{}\n", .{err});
|
||||
if (@errorReturnTrace()) |error_trace| {
|
||||
std.debug.dumpStackTrace(error_trace.*);
|
||||
}
|
||||
return err;
|
||||
};
|
||||
ran_test_count += 1;
|
||||
const test_result: TestError!bool = switch (test_run.term) {
|
||||
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
||||
@ -213,6 +228,9 @@ fn runBuildTests(allocator: Allocator, args: struct {
|
||||
std.debug.print("TOTAL TESTS: {}. RAN: {}. FAILED: {}\n", .{ total_test_count, ran_test_count, failed_test_count });
|
||||
|
||||
try std.posix.chdir(previous_cwd);
|
||||
const current_cwd = try std.fs.cwd().realpathAlloc(allocator, ".");
|
||||
std.debug.assert(std.mem.eql(u8, current_cwd, previous_cwd));
|
||||
std.debug.print("Hello \n", .{});
|
||||
|
||||
if (failed_compilation_count > 0 or failed_test_count > 0) {
|
||||
return error.fail;
|
||||
@ -226,11 +244,21 @@ fn runStdTests(allocator: Allocator, args: struct {
|
||||
var errors = false;
|
||||
std.debug.print("std... ", .{});
|
||||
|
||||
const result = try std.ChildProcess.run(.{
|
||||
std.debug.print("CWD: {s}\n", .{std.fs.cwd().realpathAlloc(allocator, ".") catch unreachable});
|
||||
|
||||
const argv = &.{ args.compiler_path, "test", "-main_source_file", "lib/std/std.nat", "-name", "std" };
|
||||
|
||||
const result = std.ChildProcess.run(.{
|
||||
.allocator = allocator,
|
||||
.argv = &.{ args.compiler_path, "test", "-main_source_file", "lib/std/std.nat", "-name", "std" },
|
||||
.argv = argv,
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
}) catch |err| {
|
||||
std.debug.print("Error: {}", .{err});
|
||||
if (@errorReturnTrace()) |error_trace| {
|
||||
std.debug.dumpStackTrace(error_trace.*);
|
||||
}
|
||||
return err;
|
||||
};
|
||||
const compilation_result: TestError!bool = switch (result.term) {
|
||||
.Exited => |exit_code| if (exit_code == 0) true else error.abnormal_exit_code,
|
||||
.Signal => error.signaled,
|
||||
@ -290,7 +318,6 @@ fn runCmakeTests(allocator: Allocator, args: struct {
|
||||
const cc_dir = try std.fs.cwd().openDir(args.dir_path, .{
|
||||
.iterate = true,
|
||||
});
|
||||
const compiler_realpath = try std.fs.cwd().realpathAlloc(allocator, args.compiler_path);
|
||||
|
||||
const cc_dir_path = try cc_dir.realpathAlloc(allocator, ".");
|
||||
try std.posix.chdir(cc_dir_path);
|
||||
@ -316,9 +343,9 @@ fn runCmakeTests(allocator: Allocator, args: struct {
|
||||
"-G",
|
||||
"Ninja",
|
||||
// "-DCMAKE_VERBOSE_MAKEFILE=On",
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_C_COMPILER=", compiler_realpath, ";cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", compiler_realpath, ";c++" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", compiler_realpath, ";cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_C_COMPILER=", args.compiler_path, ";cc" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_CXX_COMPILER=", args.compiler_path, ";c++" }),
|
||||
try std.mem.concat(allocator, u8, &.{ "-DCMAKE_ASM_COMPILER=", args.compiler_path, ";cc" }),
|
||||
},
|
||||
.max_output_bytes = std.math.maxInt(u64),
|
||||
});
|
||||
@ -474,19 +501,21 @@ fn run_test_suite(allocator: Allocator, args: struct {
|
||||
std.debug.print("TESTING {s} COMPILER: {s}...\n=================\n", .{ if (self_hosted) "SELF-HOSTED" else "BOOTSTRAP", args.compiler_path });
|
||||
var errors = false;
|
||||
|
||||
const compiler_path = std.fs.cwd().realpathAlloc(allocator, args.compiler_path) catch unreachable;
|
||||
|
||||
runStandalone(allocator, .{
|
||||
.directory_path = "test/standalone",
|
||||
.group_name = "STANDALONE",
|
||||
.is_test = false,
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
runBuildTests(allocator, .{
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
@ -496,14 +525,14 @@ fn run_test_suite(allocator: Allocator, args: struct {
|
||||
.group_name = "TEST EXECUTABLE",
|
||||
.is_test = true,
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
runStdTests(allocator, .{
|
||||
.self_hosted = self_hosted,
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
@ -511,37 +540,41 @@ fn run_test_suite(allocator: Allocator, args: struct {
|
||||
if (!self_hosted) {
|
||||
runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc",
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
runCmakeTests(allocator, .{
|
||||
.dir_path = "test/c++",
|
||||
.compiler_path = args.compiler_path,
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
};
|
||||
|
||||
switch (@import("builtin").os.tag) {
|
||||
.macos => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_macos",
|
||||
.compiler_path = args.compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
},
|
||||
.windows => {},
|
||||
.linux => switch (@import("builtin").abi) {
|
||||
.gnu => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_linux",
|
||||
.compiler_path = args.compiler_path,
|
||||
switch (@import("builtin").cpu.arch) {
|
||||
.aarch64 => switch (@import("builtin").os.tag) {
|
||||
.linux => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_aarch64_linux",
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
},
|
||||
.musl => {},
|
||||
else => @compileError("ABI not supported"),
|
||||
.macos => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_aarch64_macos",
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
},
|
||||
else => unreachable,
|
||||
},
|
||||
else => @compileError("OS not supported"),
|
||||
.x86_64 => runCmakeTests(allocator, .{
|
||||
.dir_path = "test/cc_x86_64",
|
||||
.compiler_path = compiler_path,
|
||||
}) catch {
|
||||
errors = true;
|
||||
},
|
||||
else => @compileError("Arch not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,7 @@ const unwrap_syscall = system.unwrap_syscall;
|
||||
|
||||
const exit = fn(exit_code: s32) noreturn {
|
||||
switch (current) {
|
||||
.linux => _ = #syscall(#cast(linux.Syscall.exit_group), #cast(exit_code)),
|
||||
.macos => system.exit(exit_code),
|
||||
.linux, .macos => system.exit(exit_code),
|
||||
.windows => windows.ExitProcess(#cast(exit_code)),
|
||||
}
|
||||
}
|
||||
@ -323,6 +322,7 @@ const duplicate_process = fn () DuplicateProcessError!Process.Id {
|
||||
const ExecveError = error{
|
||||
execve_failed,
|
||||
};
|
||||
|
||||
const execute = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) ExecveError!noreturn {
|
||||
switch (current) {
|
||||
.linux, .macos => {
|
||||
|
@ -3,14 +3,333 @@ const std = #import("std");
|
||||
const stdin: FileDescriptor = 0;
|
||||
const stdout: FileDescriptor = 1;
|
||||
const stderr: FileDescriptor = 2;
|
||||
const cpu = #import("builtin").cpu;
|
||||
|
||||
const Syscall = switch (#import("builtin").cpu) {
|
||||
const Syscall = switch (cpu) {
|
||||
.x86_64 => Syscall_x86_64,
|
||||
.aarch64 => Syscall_aarch64,
|
||||
else => #error("Architecture not supported"),
|
||||
};
|
||||
|
||||
const current_working_directory_file_descriptor: ssize = -100;
|
||||
|
||||
const ProcessId = s32;
|
||||
|
||||
const Syscall_aarch64 = enum(usize) {
|
||||
io_setup = 0,
|
||||
io_destroy = 1,
|
||||
io_submit = 2,
|
||||
io_cancel = 3,
|
||||
io_getevents = 4,
|
||||
setxattr = 5,
|
||||
lsetxattr = 6,
|
||||
fsetxattr = 7,
|
||||
getxattr = 8,
|
||||
lgetxattr = 9,
|
||||
fgetxattr = 10,
|
||||
listxattr = 11,
|
||||
llistxattr = 12,
|
||||
flistxattr = 13,
|
||||
removexattr = 14,
|
||||
lremovexattr = 15,
|
||||
fremovexattr = 16,
|
||||
getcwd = 17,
|
||||
lookup_dcookie = 18,
|
||||
eventfd2 = 19,
|
||||
epoll_create1 = 20,
|
||||
epoll_ctl = 21,
|
||||
epoll_pwait = 22,
|
||||
dup = 23,
|
||||
dup3 = 24,
|
||||
fcntl = 25,
|
||||
inotify_init1 = 26,
|
||||
inotify_add_watch = 27,
|
||||
inotify_rm_watch = 28,
|
||||
ioctl = 29,
|
||||
ioprio_set = 30,
|
||||
ioprio_get = 31,
|
||||
flock = 32,
|
||||
mknodat = 33,
|
||||
mkdirat = 34,
|
||||
unlinkat = 35,
|
||||
symlinkat = 36,
|
||||
linkat = 37,
|
||||
renameat = 38,
|
||||
umount2 = 39,
|
||||
mount = 40,
|
||||
pivot_root = 41,
|
||||
nfsservctl = 42,
|
||||
statfs = 43,
|
||||
fstatfs = 44,
|
||||
truncate = 45,
|
||||
ftruncate = 46,
|
||||
fallocate = 47,
|
||||
faccessat = 48,
|
||||
chdir = 49,
|
||||
fchdir = 50,
|
||||
chroot = 51,
|
||||
fchmod = 52,
|
||||
fchmodat = 53,
|
||||
fchownat = 54,
|
||||
fchown = 55,
|
||||
openat = 56,
|
||||
close = 57,
|
||||
vhangup = 58,
|
||||
pipe2 = 59,
|
||||
quotactl = 60,
|
||||
getdents64 = 61,
|
||||
lseek = 62,
|
||||
read = 63,
|
||||
write = 64,
|
||||
readv = 65,
|
||||
writev = 66,
|
||||
pread64 = 67,
|
||||
pwrite64 = 68,
|
||||
preadv = 69,
|
||||
pwritev = 70,
|
||||
sendfile = 71,
|
||||
pselect6 = 72,
|
||||
ppoll = 73,
|
||||
signalfd4 = 74,
|
||||
vmsplice = 75,
|
||||
splice = 76,
|
||||
tee = 77,
|
||||
readlinkat = 78,
|
||||
fstatat = 79,
|
||||
fstat = 80,
|
||||
sync = 81,
|
||||
fsync = 82,
|
||||
fdatasync = 83,
|
||||
sync_file_range = 84,
|
||||
timerfd_create = 85,
|
||||
timerfd_settime = 86,
|
||||
timerfd_gettime = 87,
|
||||
utimensat = 88,
|
||||
acct = 89,
|
||||
capget = 90,
|
||||
capset = 91,
|
||||
personality = 92,
|
||||
exit = 93,
|
||||
exit_group = 94,
|
||||
waitid = 95,
|
||||
set_tid_address = 96,
|
||||
unshare = 97,
|
||||
futex = 98,
|
||||
set_robust_list = 99,
|
||||
get_robust_list = 100,
|
||||
nanosleep = 101,
|
||||
getitimer = 102,
|
||||
setitimer = 103,
|
||||
kexec_load = 104,
|
||||
init_module = 105,
|
||||
delete_module = 106,
|
||||
timer_create = 107,
|
||||
timer_gettime = 108,
|
||||
timer_getoverrun = 109,
|
||||
timer_settime = 110,
|
||||
timer_delete = 111,
|
||||
clock_settime = 112,
|
||||
clock_gettime = 113,
|
||||
clock_getres = 114,
|
||||
clock_nanosleep = 115,
|
||||
syslog = 116,
|
||||
ptrace = 117,
|
||||
sched_setparam = 118,
|
||||
sched_setscheduler = 119,
|
||||
sched_getscheduler = 120,
|
||||
sched_getparam = 121,
|
||||
sched_setaffinity = 122,
|
||||
sched_getaffinity = 123,
|
||||
sched_yield = 124,
|
||||
sched_get_priority_max = 125,
|
||||
sched_get_priority_min = 126,
|
||||
sched_rr_get_interval = 127,
|
||||
restart_syscall = 128,
|
||||
kill = 129,
|
||||
tkill = 130,
|
||||
tgkill = 131,
|
||||
sigaltstack = 132,
|
||||
rt_sigsuspend = 133,
|
||||
rt_sigaction = 134,
|
||||
rt_sigprocmask = 135,
|
||||
rt_sigpending = 136,
|
||||
rt_sigtimedwait = 137,
|
||||
rt_sigqueueinfo = 138,
|
||||
rt_sigreturn = 139,
|
||||
setpriority = 140,
|
||||
getpriority = 141,
|
||||
reboot = 142,
|
||||
setregid = 143,
|
||||
setgid = 144,
|
||||
setreuid = 145,
|
||||
setuid = 146,
|
||||
setresuid = 147,
|
||||
getresuid = 148,
|
||||
setresgid = 149,
|
||||
getresgid = 150,
|
||||
setfsuid = 151,
|
||||
setfsgid = 152,
|
||||
times = 153,
|
||||
setpgid = 154,
|
||||
getpgid = 155,
|
||||
getsid = 156,
|
||||
setsid = 157,
|
||||
getgroups = 158,
|
||||
setgroups = 159,
|
||||
uname = 160,
|
||||
sethostname = 161,
|
||||
setdomainname = 162,
|
||||
getrlimit = 163,
|
||||
setrlimit = 164,
|
||||
getrusage = 165,
|
||||
umask = 166,
|
||||
prctl = 167,
|
||||
getcpu = 168,
|
||||
gettimeofday = 169,
|
||||
settimeofday = 170,
|
||||
adjtimex = 171,
|
||||
getpid = 172,
|
||||
getppid = 173,
|
||||
getuid = 174,
|
||||
geteuid = 175,
|
||||
getgid = 176,
|
||||
getegid = 177,
|
||||
gettid = 178,
|
||||
sysinfo = 179,
|
||||
mq_open = 180,
|
||||
mq_unlink = 181,
|
||||
mq_timedsend = 182,
|
||||
mq_timedreceive = 183,
|
||||
mq_notify = 184,
|
||||
mq_getsetattr = 185,
|
||||
msgget = 186,
|
||||
msgctl = 187,
|
||||
msgrcv = 188,
|
||||
msgsnd = 189,
|
||||
semget = 190,
|
||||
semctl = 191,
|
||||
semtimedop = 192,
|
||||
semop = 193,
|
||||
shmget = 194,
|
||||
shmctl = 195,
|
||||
shmat = 196,
|
||||
shmdt = 197,
|
||||
socket = 198,
|
||||
socketpair = 199,
|
||||
bind = 200,
|
||||
listen = 201,
|
||||
accept = 202,
|
||||
connect = 203,
|
||||
getsockname = 204,
|
||||
getpeername = 205,
|
||||
sendto = 206,
|
||||
recvfrom = 207,
|
||||
setsockopt = 208,
|
||||
getsockopt = 209,
|
||||
shutdown = 210,
|
||||
sendmsg = 211,
|
||||
recvmsg = 212,
|
||||
readahead = 213,
|
||||
brk = 214,
|
||||
munmap = 215,
|
||||
mremap = 216,
|
||||
add_key = 217,
|
||||
request_key = 218,
|
||||
keyctl = 219,
|
||||
clone = 220,
|
||||
execve = 221,
|
||||
mmap = 222,
|
||||
fadvise64 = 223,
|
||||
swapon = 224,
|
||||
swapoff = 225,
|
||||
mprotect = 226,
|
||||
msync = 227,
|
||||
mlock = 228,
|
||||
munlock = 229,
|
||||
mlockall = 230,
|
||||
munlockall = 231,
|
||||
mincore = 232,
|
||||
madvise = 233,
|
||||
remap_file_pages = 234,
|
||||
mbind = 235,
|
||||
get_mempolicy = 236,
|
||||
set_mempolicy = 237,
|
||||
migrate_pages = 238,
|
||||
move_pages = 239,
|
||||
rt_tgsigqueueinfo = 240,
|
||||
perf_event_open = 241,
|
||||
accept4 = 242,
|
||||
recvmmsg = 243,
|
||||
wait4 = 260,
|
||||
prlimit64 = 261,
|
||||
fanotify_init = 262,
|
||||
fanotify_mark = 263,
|
||||
name_to_handle_at = 264,
|
||||
open_by_handle_at = 265,
|
||||
clock_adjtime = 266,
|
||||
syncfs = 267,
|
||||
setns = 268,
|
||||
sendmmsg = 269,
|
||||
process_vm_readv = 270,
|
||||
process_vm_writev = 271,
|
||||
kcmp = 272,
|
||||
finit_module = 273,
|
||||
sched_setattr = 274,
|
||||
sched_getattr = 275,
|
||||
renameat2 = 276,
|
||||
seccomp = 277,
|
||||
getrandom = 278,
|
||||
memfd_create = 279,
|
||||
bpf = 280,
|
||||
execveat = 281,
|
||||
userfaultfd = 282,
|
||||
membarrier = 283,
|
||||
mlock2 = 284,
|
||||
copy_file_range = 285,
|
||||
preadv2 = 286,
|
||||
pwritev2 = 287,
|
||||
pkey_mprotect = 288,
|
||||
pkey_alloc = 289,
|
||||
pkey_free = 290,
|
||||
statx = 291,
|
||||
io_pgetevents = 292,
|
||||
rseq = 293,
|
||||
kexec_file_load = 294,
|
||||
pidfd_send_signal = 424,
|
||||
io_uring_setup = 425,
|
||||
io_uring_enter = 426,
|
||||
io_uring_register = 427,
|
||||
open_tree = 428,
|
||||
move_mount = 429,
|
||||
fsopen = 430,
|
||||
fsconfig = 431,
|
||||
fsmount = 432,
|
||||
fspick = 433,
|
||||
pidfd_open = 434,
|
||||
clone3 = 435,
|
||||
close_range = 436,
|
||||
openat2 = 437,
|
||||
pidfd_getfd = 438,
|
||||
faccessat2 = 439,
|
||||
process_madvise = 440,
|
||||
epoll_pwait2 = 441,
|
||||
mount_setattr = 442,
|
||||
quotactl_fd = 443,
|
||||
landlock_create_ruleset = 444,
|
||||
landlock_add_rule = 445,
|
||||
landlock_restrict_self = 446,
|
||||
memfd_secret = 447,
|
||||
process_mrelease = 448,
|
||||
futex_waitv = 449,
|
||||
set_mempolicy_home_node = 450,
|
||||
cachestat = 451,
|
||||
fchmodat2 = 452,
|
||||
map_shadow_stack = 453,
|
||||
futex_wake = 454,
|
||||
futex_wait = 455,
|
||||
futex_requeue = 456,
|
||||
};
|
||||
|
||||
const Syscall_x86_64 = enum(usize) {
|
||||
read = 0,
|
||||
write = 1,
|
||||
@ -865,6 +1184,11 @@ const get_map_flags = fn(flags: std.os.MapFlags) MapFlags{
|
||||
};
|
||||
}
|
||||
|
||||
const exit = fn (exit_code: s32) noreturn {
|
||||
_ = #syscall(#cast(Syscall.exit), #cast(exit_code));
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const mmap = fn(address: ?[&]u8, length: usize, protection_flags: ProtectionFlags, map_flags: MapFlags, fd: FileDescriptor, offset: u64) usize {
|
||||
const flat_protection_flags: u32 = #cast(protection_flags);
|
||||
const flat_map_flags: u32 = #cast(map_flags);
|
||||
@ -884,13 +1208,70 @@ const munmap = fn(bytes: []const u8) usize {
|
||||
}
|
||||
|
||||
const readlink = fn(file_path: [&:0]const u8, bytes: []u8) usize {
|
||||
const result = #syscall(#cast(Syscall.readlink), #cast(file_path), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
switch (cpu) {
|
||||
.x86_64 => {
|
||||
const result = #syscall(#cast(Syscall.readlink), #cast(file_path), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
},
|
||||
.aarch64 => {
|
||||
const result = #syscall(#cast(Syscall.readlinkat), #cast(current_working_directory_file_descriptor), #cast(file_path), #cast(bytes.pointer), bytes.length);
|
||||
return result;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const SIG = struct {
|
||||
const BLOCK = 0;
|
||||
const UNBLOCK = 1;
|
||||
const SETMASK = 2;
|
||||
|
||||
const HUP = 1;
|
||||
const INT = 2;
|
||||
const QUIT = 3;
|
||||
const ILL = 4;
|
||||
const TRAP = 5;
|
||||
const ABRT = 6;
|
||||
const IOT = ABRT;
|
||||
const BUS = 7;
|
||||
const FPE = 8;
|
||||
const KILL = 9;
|
||||
const USR1 = 10;
|
||||
const SEGV = 11;
|
||||
const USR2 = 12;
|
||||
const PIPE = 13;
|
||||
const ALRM = 14;
|
||||
const TERM = 15;
|
||||
const STKFLT = 16;
|
||||
const CHLD = 17;
|
||||
const CONT = 18;
|
||||
const STOP = 19;
|
||||
const TSTP = 20;
|
||||
const TTIN = 21;
|
||||
const TTOU = 22;
|
||||
const URG = 23;
|
||||
const XCPU = 24;
|
||||
const XFSZ = 25;
|
||||
const VTALRM = 26;
|
||||
const PROF = 27;
|
||||
const WINCH = 28;
|
||||
const IO = 29;
|
||||
const POLL = 29;
|
||||
const PWR = 30;
|
||||
const SYS = 31;
|
||||
};
|
||||
|
||||
|
||||
const fork = fn() usize {
|
||||
const result = #syscall(#cast(Syscall.fork));
|
||||
return result;
|
||||
switch (cpu) {
|
||||
.x86_64 => {
|
||||
const result = #syscall(#cast(Syscall.fork));
|
||||
return result;
|
||||
},
|
||||
.aarch64 => {
|
||||
const result = #syscall(#cast(Syscall.clone), SIG.CHLD, 0);
|
||||
return result;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const execve = fn(path: [&:0]const u8, argv: [&:null]const ?[&:0]const u8, env: [&:null]const ?[&:null]const u8) usize {
|
||||
@ -910,8 +1291,16 @@ const dup2 = fn(old: FileDescriptor, new: FileDescriptor) usize {
|
||||
|
||||
const open = fn(path: [&:0]const u8, flags: OpenFlags, permissions: u32) usize {
|
||||
const flattened_flags: u32 = #cast(flags);
|
||||
const result = #syscall(#cast(Syscall.open), #cast(path), flattened_flags, permissions);
|
||||
return result;
|
||||
switch (cpu) {
|
||||
.x86_64 => {
|
||||
const result = #syscall(#cast(Syscall.open), #cast(path), flattened_flags, permissions);
|
||||
return result;
|
||||
},
|
||||
.aarch64 => {
|
||||
const result = #syscall(#cast(Syscall.openat), #cast(current_working_directory_file_descriptor), #cast(path), flattened_flags, permissions);
|
||||
return result;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const openat = fn(directory_file_descriptor: FileDescriptor, path: [&:0]const u8, flags: u32, permissions: u32) usize {
|
||||
|
@ -9,12 +9,21 @@ comptime {
|
||||
}
|
||||
|
||||
const _start = fn naked cc(.c) () noreturn {
|
||||
#asm(`
|
||||
xor ebp, ebp;
|
||||
mov rdi, rsp;
|
||||
and rsp, 0xfffffffffffffff0;
|
||||
call {start};
|
||||
`);
|
||||
switch (builtin.cpu) {
|
||||
.x86_64 => #asm(`
|
||||
xor ebp, ebp;
|
||||
mov rdi, rsp;
|
||||
and rsp, 0xfffffffffffffff0;
|
||||
call {start};
|
||||
`),
|
||||
.aarch64 => #asm(`
|
||||
mov fp, 0;
|
||||
mov lr, 0;
|
||||
mov x0, sp;
|
||||
b {start};
|
||||
`),
|
||||
else => #error("Architecture not supported"),
|
||||
}
|
||||
}
|
||||
|
||||
var argument_count: usize = 0;
|
||||
|
4
test/cc_aarch64_linux/c_asm/assembly.S
Normal file
4
test/cc_aarch64_linux/c_asm/assembly.S
Normal file
@ -0,0 +1,4 @@
|
||||
.global foo
|
||||
foo:
|
||||
mov w0, #42
|
||||
ret
|
2
test/cc_x86_64/c_asm/.gitignore
vendored
Normal file
2
test/cc_x86_64/c_asm/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.o
|
||||
build/
|
3
test/cc_x86_64/c_asm/CMakeLists.txt
Normal file
3
test/cc_x86_64/c_asm/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(c_asm C ASM)
|
||||
add_executable(c_asm main.c assembly.S)
|
7
test/cc_x86_64/c_asm/main.c
Normal file
7
test/cc_x86_64/c_asm/main.c
Normal file
@ -0,0 +1,7 @@
|
||||
extern int foo();
|
||||
#include <assert.h>
|
||||
int main()
|
||||
{
|
||||
assert(foo() == 42);
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user