mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
stage2: decouple codegen.zig from ELF
See #6113 for an alternate way of doing this that we didn't end up following. Closes #6079. I also took the opportunity here to extract C.zig and Elf.zig from link.zig.
This commit is contained in:
parent
37ad9f38dc
commit
89b6c47e04
@ -59,20 +59,20 @@ pub const GenerateSymbolError = error{
|
||||
};
|
||||
|
||||
pub fn generateSymbol(
|
||||
bin_file: *link.File.Elf,
|
||||
bin_file: *link.File,
|
||||
src: usize,
|
||||
typed_value: TypedValue,
|
||||
code: *std.ArrayList(u8),
|
||||
dbg_line: *std.ArrayList(u8),
|
||||
dbg_info: *std.ArrayList(u8),
|
||||
dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
|
||||
dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
|
||||
) GenerateSymbolError!Result {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
switch (bin_file.base.options.target.cpu.arch) {
|
||||
switch (bin_file.options.target.cpu.arch) {
|
||||
.wasm32 => unreachable, // has its own code path
|
||||
.wasm64 => unreachable, // has its own code path
|
||||
//.arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, dbg_line, dbg_info, dbg_info_type_relocs),
|
||||
@ -151,7 +151,7 @@ pub fn generateSymbol(
|
||||
}
|
||||
return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.base.allocator,
|
||||
bin_file.allocator,
|
||||
src,
|
||||
"TODO implement generateSymbol for more kinds of arrays",
|
||||
.{},
|
||||
@ -164,12 +164,11 @@ pub fn generateSymbol(
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
const decl = payload.decl;
|
||||
if (decl.analysis != .complete) return error.AnalysisFail;
|
||||
assert(decl.link.elf.local_sym_index != 0);
|
||||
// TODO handle the dependency of this symbol on the decl's vaddr.
|
||||
// If the decl changes vaddr, then this symbol needs to get regenerated.
|
||||
const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value;
|
||||
const endian = bin_file.base.options.target.cpu.arch.endian();
|
||||
switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {
|
||||
const vaddr = bin_file.getDeclVAddr(decl);
|
||||
const endian = bin_file.options.target.cpu.arch.endian();
|
||||
switch (bin_file.options.target.cpu.arch.ptrBitWidth()) {
|
||||
16 => {
|
||||
try code.resize(2);
|
||||
mem.writeInt(u16, code.items[0..2], @intCast(u16, vaddr), endian);
|
||||
@ -188,7 +187,7 @@ pub fn generateSymbol(
|
||||
}
|
||||
return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.base.allocator,
|
||||
bin_file.allocator,
|
||||
src,
|
||||
"TODO implement generateSymbol for pointer {}",
|
||||
.{typed_value.val},
|
||||
@ -198,7 +197,7 @@ pub fn generateSymbol(
|
||||
.Int => {
|
||||
// TODO populate .debug_info for the integer
|
||||
|
||||
const info = typed_value.ty.intInfo(bin_file.base.options.target);
|
||||
const info = typed_value.ty.intInfo(bin_file.options.target);
|
||||
if (info.bits == 8 and !info.signed) {
|
||||
const x = typed_value.val.toUnsignedInt();
|
||||
try code.append(@intCast(u8, x));
|
||||
@ -206,7 +205,7 @@ pub fn generateSymbol(
|
||||
}
|
||||
return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.base.allocator,
|
||||
bin_file.allocator,
|
||||
src,
|
||||
"TODO implement generateSymbol for int type '{}'",
|
||||
.{typed_value.ty},
|
||||
@ -216,7 +215,7 @@ pub fn generateSymbol(
|
||||
else => |t| {
|
||||
return Result{
|
||||
.fail = try ErrorMsg.create(
|
||||
bin_file.base.allocator,
|
||||
bin_file.allocator,
|
||||
src,
|
||||
"TODO implement generateSymbol for type '{}'",
|
||||
.{@tagName(t)},
|
||||
@ -234,13 +233,13 @@ const InnerError = error{
|
||||
fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
return struct {
|
||||
gpa: *Allocator,
|
||||
bin_file: *link.File.Elf,
|
||||
bin_file: *link.File,
|
||||
target: *const std.Target,
|
||||
mod_fn: *const Module.Fn,
|
||||
code: *std.ArrayList(u8),
|
||||
dbg_line: *std.ArrayList(u8),
|
||||
dbg_info: *std.ArrayList(u8),
|
||||
dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
|
||||
dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
|
||||
err_msg: ?*ErrorMsg,
|
||||
args: []MCValue,
|
||||
ret_mcv: MCValue,
|
||||
@ -405,22 +404,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const Self = @This();
|
||||
|
||||
fn generateSymbol(
|
||||
bin_file: *link.File.Elf,
|
||||
bin_file: *link.File,
|
||||
src: usize,
|
||||
typed_value: TypedValue,
|
||||
code: *std.ArrayList(u8),
|
||||
dbg_line: *std.ArrayList(u8),
|
||||
dbg_info: *std.ArrayList(u8),
|
||||
dbg_info_type_relocs: *link.File.Elf.DbgInfoTypeRelocsTable,
|
||||
dbg_info_type_relocs: *link.File.DbgInfoTypeRelocsTable,
|
||||
) GenerateSymbolError!Result {
|
||||
const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
|
||||
|
||||
const fn_type = module_fn.owner_decl.typed_value.most_recent.typed_value.ty;
|
||||
|
||||
var branch_stack = std.ArrayList(Branch).init(bin_file.base.allocator);
|
||||
var branch_stack = std.ArrayList(Branch).init(bin_file.allocator);
|
||||
defer {
|
||||
assert(branch_stack.items.len == 1);
|
||||
branch_stack.items[0].deinit(bin_file.base.allocator);
|
||||
branch_stack.items[0].deinit(bin_file.allocator);
|
||||
branch_stack.deinit();
|
||||
}
|
||||
const branch = try branch_stack.addOne();
|
||||
@ -443,8 +442,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
};
|
||||
|
||||
var function = Self{
|
||||
.gpa = bin_file.base.allocator,
|
||||
.target = &bin_file.base.options.target,
|
||||
.gpa = bin_file.allocator,
|
||||
.target = &bin_file.options.target,
|
||||
.bin_file = bin_file,
|
||||
.mod_fn = module_fn,
|
||||
.code = code,
|
||||
@ -464,7 +463,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
.rbrace_src = src_data.rbrace_src,
|
||||
.source = src_data.source,
|
||||
};
|
||||
defer function.exitlude_jump_relocs.deinit(bin_file.base.allocator);
|
||||
defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
|
||||
|
||||
var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {
|
||||
error.CodegenFail => return Result{ .fail = function.err_msg.? },
|
||||
@ -1144,80 +1143,88 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
var info = try self.resolveCallingConventionValues(inst.base.src, inst.func.ty);
|
||||
defer info.deinit(self);
|
||||
|
||||
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.genSetReg(arg.src, reg, arg_mcv);
|
||||
// TODO interact with the register allocator to mark the instruction as moved.
|
||||
},
|
||||
.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,
|
||||
// Due to incremental compilation, how function calls are generated depends
|
||||
// on linking.
|
||||
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
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.genSetReg(arg.src, reg, arg_mcv);
|
||||
// TODO interact with the register allocator to mark the instruction as moved.
|
||||
},
|
||||
.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.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
// 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 });
|
||||
mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
// 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 });
|
||||
mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), got_addr);
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
.riscv64 => {
|
||||
if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
|
||||
},
|
||||
.riscv64 => {
|
||||
if (info.args.len > 0) return self.fail(inst.base.src, "TODO implement fn args for {}", .{self.target.cpu.arch});
|
||||
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
|
||||
if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
|
||||
const func = func_val.func;
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
|
||||
try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
|
||||
try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
|
||||
mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.ra, 0, .ra).toU32());
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
} else {
|
||||
return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
|
||||
}
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
|
||||
},
|
||||
else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
|
||||
}
|
||||
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO", .{});
|
||||
} else {
|
||||
unreachable;
|
||||
}
|
||||
|
||||
return info.return_value;
|
||||
@ -2036,10 +2043,14 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Pointer => {
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const decl = payload.decl;
|
||||
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
const decl = payload.decl;
|
||||
const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
|
||||
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
} else {
|
||||
return self.fail(src, "TODO codegen non-ELF const Decl pointer", .{});
|
||||
}
|
||||
}
|
||||
return self.fail(src, "TODO codegen more kinds of const pointers", .{});
|
||||
},
|
||||
@ -2167,7 +2178,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
|
||||
/// TODO support scope overrides. Also note this logic is duplicated with `Module.wantSafety`.
|
||||
fn wantSafety(self: *Self) bool {
|
||||
return switch (self.bin_file.base.options.optimize_mode) {
|
||||
return switch (self.bin_file.options.optimize_mode) {
|
||||
.Debug => true,
|
||||
.ReleaseSafe => true,
|
||||
.ReleaseFast => false,
|
||||
@ -2178,7 +2189,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {
|
||||
@setCold(true);
|
||||
assert(self.err_msg == null);
|
||||
self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args);
|
||||
self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args);
|
||||
return error.CodegenFail;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
101
src-self-hosted/link/C.zig
Normal file
101
src-self-hosted/link/C.zig
Normal file
@ -0,0 +1,101 @@
|
||||
const std = @import("std");
|
||||
const mem = std.mem;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Module = @import("../Module.zig");
|
||||
const fs = std.fs;
|
||||
const codegen = @import("../codegen/c.zig");
|
||||
const link = @import("../link.zig");
|
||||
const File = link.File;
|
||||
const C = @This();
|
||||
|
||||
pub const base_tag: File.Tag = .c;
|
||||
|
||||
base: File,
|
||||
|
||||
header: std.ArrayList(u8),
|
||||
constants: std.ArrayList(u8),
|
||||
main: std.ArrayList(u8),
|
||||
|
||||
called: std.StringHashMap(void),
|
||||
need_stddef: bool = false,
|
||||
need_stdint: bool = false,
|
||||
error_msg: *Module.ErrorMsg = undefined,
|
||||
|
||||
pub fn openPath(allocator: *Allocator, dir: fs.Dir, sub_path: []const u8, options: link.Options) !*File {
|
||||
assert(options.object_format == .c);
|
||||
|
||||
const file = try dir.createFile(sub_path, .{ .truncate = true, .read = true, .mode = link.determineMode(options) });
|
||||
errdefer file.close();
|
||||
|
||||
var c_file = try allocator.create(C);
|
||||
errdefer allocator.destroy(c_file);
|
||||
|
||||
c_file.* = C{
|
||||
.base = .{
|
||||
.tag = .c,
|
||||
.options = options,
|
||||
.file = file,
|
||||
.allocator = allocator,
|
||||
},
|
||||
.main = std.ArrayList(u8).init(allocator),
|
||||
.header = std.ArrayList(u8).init(allocator),
|
||||
.constants = std.ArrayList(u8).init(allocator),
|
||||
.called = std.StringHashMap(void).init(allocator),
|
||||
};
|
||||
|
||||
return &c_file.base;
|
||||
}
|
||||
|
||||
pub fn fail(self: *C, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
|
||||
self.error_msg = try Module.ErrorMsg.create(self.base.allocator, src, format, args);
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *C) void {
|
||||
self.main.deinit();
|
||||
self.header.deinit();
|
||||
self.constants.deinit();
|
||||
self.called.deinit();
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *C, module: *Module, decl: *Module.Decl) !void {
|
||||
codegen.generate(self, decl) catch |err| {
|
||||
if (err == error.AnalysisFail) {
|
||||
try module.failed_decls.put(module.gpa, decl, self.error_msg);
|
||||
}
|
||||
return err;
|
||||
};
|
||||
}
|
||||
|
||||
pub fn flush(self: *C, module: *Module) !void {
|
||||
const writer = self.base.file.?.writer();
|
||||
try writer.writeAll(@embedFile("cbe.h"));
|
||||
var includes = false;
|
||||
if (self.need_stddef) {
|
||||
try writer.writeAll("#include <stddef.h>\n");
|
||||
includes = true;
|
||||
}
|
||||
if (self.need_stdint) {
|
||||
try writer.writeAll("#include <stdint.h>\n");
|
||||
includes = true;
|
||||
}
|
||||
if (includes) {
|
||||
try writer.writeByte('\n');
|
||||
}
|
||||
if (self.header.items.len > 0) {
|
||||
try writer.print("{}\n", .{self.header.items});
|
||||
}
|
||||
if (self.constants.items.len > 0) {
|
||||
try writer.print("{}\n", .{self.constants.items});
|
||||
}
|
||||
if (self.main.items.len > 1) {
|
||||
const last_two = self.main.items[self.main.items.len - 2 ..];
|
||||
if (std.mem.eql(u8, last_two, "\n\n")) {
|
||||
self.main.items.len -= 1;
|
||||
}
|
||||
}
|
||||
try writer.writeAll(self.main.items);
|
||||
self.base.file.?.close();
|
||||
self.base.file = null;
|
||||
}
|
||||
2583
src-self-hosted/link/Elf.zig
Normal file
2583
src-self-hosted/link/Elf.zig
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ const Module = @import("../Module.zig");
|
||||
const link = @import("../link.zig");
|
||||
const File = link.File;
|
||||
|
||||
pub const base_tag: Tag = File.Tag.macho;
|
||||
pub const base_tag: File.Tag = File.Tag.macho;
|
||||
|
||||
base: File,
|
||||
|
||||
@ -210,3 +210,7 @@ pub fn updateDeclExports(
|
||||
) !void {}
|
||||
|
||||
pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {}
|
||||
|
||||
pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
|
||||
@panic("TODO implement getDeclVAddr for MachO");
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ const enable_wine: bool = build_options.enable_wine;
|
||||
const enable_wasmtime: bool = build_options.enable_wasmtime;
|
||||
const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;
|
||||
|
||||
const cheader = @embedFile("cbe.h");
|
||||
const cheader = @embedFile("link/cbe.h");
|
||||
|
||||
test "self-hosted" {
|
||||
var ctx = TestContext.init();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user