mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 21:38:33 +00:00
Merge pull request #17773 from ziglang/elf-exports
link: implement exporting anon decls
This commit is contained in:
commit
10d03acdb5
@ -13063,6 +13063,7 @@ fn genExternSymbolRef(
|
||||
} },
|
||||
});
|
||||
} else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
const global_index = try coff_file.getGlobalSymbol(callee, lib);
|
||||
_ = try self.addInst(.{
|
||||
.tag = .mov,
|
||||
.ops = .import_reloc,
|
||||
@ -13070,7 +13071,7 @@ fn genExternSymbolRef(
|
||||
.r1 = .rax,
|
||||
.payload = try self.addExtra(bits.Symbol{
|
||||
.atom_index = atom_index,
|
||||
.sym_index = try coff_file.getGlobalSymbol(callee, lib),
|
||||
.sym_index = link.File.Coff.global_symbol_bit | global_index,
|
||||
}),
|
||||
} },
|
||||
});
|
||||
@ -13080,12 +13081,13 @@ fn genExternSymbolRef(
|
||||
else => unreachable,
|
||||
}
|
||||
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const global_index = try macho_file.getGlobalSymbol(callee, lib);
|
||||
_ = try self.addInst(.{
|
||||
.tag = .call,
|
||||
.ops = .extern_fn_reloc,
|
||||
.data = .{ .reloc = .{
|
||||
.atom_index = atom_index,
|
||||
.sym_index = try macho_file.getGlobalSymbol(callee, lib),
|
||||
.sym_index = link.File.MachO.global_symbol_bit | global_index,
|
||||
} },
|
||||
});
|
||||
} else return self.fail("TODO implement calling extern functions", .{});
|
||||
|
||||
@ -52,7 +52,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
// Add relocation to the decl.
|
||||
const atom_index =
|
||||
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
const target = macho_file.getGlobalByIndex(symbol.sym_index);
|
||||
const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0)
|
||||
macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index)
|
||||
else
|
||||
link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index };
|
||||
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
|
||||
.type = .branch,
|
||||
.target = target,
|
||||
@ -66,7 +69,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const atom_index = coff_file.getAtomIndexForSymbol(
|
||||
.{ .sym_index = symbol.atom_index, .file = null },
|
||||
).?;
|
||||
const target = coff_file.getGlobalByIndex(symbol.sym_index);
|
||||
const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
|
||||
coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
|
||||
else
|
||||
link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
|
||||
try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
|
||||
.type = .direct,
|
||||
.target = target,
|
||||
@ -116,6 +122,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
const atom_index =
|
||||
macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
|
||||
const target = if (link.File.MachO.global_symbol_bit & symbol.sym_index != 0)
|
||||
macho_file.getGlobalByIndex(link.File.MachO.global_symbol_mask & symbol.sym_index)
|
||||
else
|
||||
link.File.MachO.SymbolWithLoc{ .sym_index = symbol.sym_index };
|
||||
try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
|
||||
.type = switch (lowered_relocs[0].target) {
|
||||
.linker_got => .got,
|
||||
@ -123,7 +133,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.linker_tlv => .tlv,
|
||||
else => unreachable,
|
||||
},
|
||||
.target = .{ .sym_index = symbol.sym_index },
|
||||
.target = target,
|
||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||
.addend = 0,
|
||||
.pcrel = true,
|
||||
@ -134,6 +144,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.sym_index = symbol.atom_index,
|
||||
.file = null,
|
||||
}).?;
|
||||
const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0)
|
||||
coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index)
|
||||
else
|
||||
link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null };
|
||||
try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{
|
||||
.type = switch (lowered_relocs[0].target) {
|
||||
.linker_got => .got,
|
||||
@ -141,13 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.linker_import => .import,
|
||||
else => unreachable,
|
||||
},
|
||||
.target = switch (lowered_relocs[0].target) {
|
||||
.linker_got,
|
||||
.linker_direct,
|
||||
=> .{ .sym_index = symbol.sym_index, .file = null },
|
||||
.linker_import => coff_file.getGlobalByIndex(symbol.sym_index),
|
||||
else => unreachable,
|
||||
},
|
||||
.target = target,
|
||||
.offset = @as(u32, @intCast(end_offset - 4)),
|
||||
.addend = 0,
|
||||
.pcrel = true,
|
||||
|
||||
@ -721,6 +721,7 @@ fn lowerAnonDeclRef(
|
||||
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
|
||||
const decl_val = anon_decl.val;
|
||||
const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
|
||||
log.debug("lowerAnonDecl: ty = {}", .{decl_ty.fmt(mod)});
|
||||
const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
|
||||
if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {
|
||||
try code.appendNTimes(0xaa, ptr_width_bytes);
|
||||
@ -911,6 +912,14 @@ fn genDeclRef(
|
||||
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
|
||||
return GenResult.mcv(.{ .load_symbol = sym.esym_index });
|
||||
} else if (bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
if (is_extern) {
|
||||
// TODO make this part of getGlobalSymbol
|
||||
const name = mod.intern_pool.stringToSlice(decl.name);
|
||||
const sym_name = try std.fmt.allocPrint(bin_file.allocator, "_{s}", .{name});
|
||||
defer bin_file.allocator.free(sym_name);
|
||||
const global_index = try macho_file.addUndefined(sym_name, .{ .add_got = true });
|
||||
return GenResult.mcv(.{ .load_got = link.File.MachO.global_symbol_bit | global_index });
|
||||
}
|
||||
const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
|
||||
const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
|
||||
if (is_threadlocal) {
|
||||
@ -918,6 +927,17 @@ fn genDeclRef(
|
||||
}
|
||||
return GenResult.mcv(.{ .load_got = sym_index });
|
||||
} else if (bin_file.cast(link.File.Coff)) |coff_file| {
|
||||
if (is_extern) {
|
||||
const name = mod.intern_pool.stringToSlice(decl.name);
|
||||
// TODO audit this
|
||||
const lib_name = if (decl.getOwnedVariable(mod)) |ov|
|
||||
mod.intern_pool.stringToSliceUnwrap(ov.lib_name)
|
||||
else
|
||||
null;
|
||||
const global_index = try coff_file.getGlobalSymbol(name, lib_name);
|
||||
try coff_file.need_got_table.put(bin_file.allocator, global_index, {}); // needs GOT
|
||||
return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index });
|
||||
}
|
||||
const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index);
|
||||
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
|
||||
return GenResult.mcv(.{ .load_got = sym_index });
|
||||
|
||||
@ -28,6 +28,7 @@ locals: std.ArrayListUnmanaged(coff.Symbol) = .{},
|
||||
globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
|
||||
resolver: std.StringHashMapUnmanaged(u32) = .{},
|
||||
unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{},
|
||||
need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{},
|
||||
|
||||
locals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
globals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
@ -54,7 +55,7 @@ entry_addr: ?u32 = null,
|
||||
lazy_syms: LazySymbolTable = .{},
|
||||
|
||||
/// Table of tracked Decls.
|
||||
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
||||
decls: DeclTable = .{},
|
||||
|
||||
/// List of atoms that are either synthetic or map directly to the Zig source program.
|
||||
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
||||
@ -108,7 +109,8 @@ const HotUpdateState = struct {
|
||||
loaded_base_address: ?std.os.windows.HMODULE = null,
|
||||
};
|
||||
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);
|
||||
const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
|
||||
const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
|
||||
const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
|
||||
const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
|
||||
@ -325,7 +327,14 @@ pub fn deinit(self: *Coff) void {
|
||||
atoms.deinit(gpa);
|
||||
}
|
||||
self.unnamed_const_atoms.deinit(gpa);
|
||||
self.anon_decls.deinit(gpa);
|
||||
|
||||
{
|
||||
var it = self.anon_decls.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value_ptr.exports.deinit(gpa);
|
||||
}
|
||||
self.anon_decls.deinit(gpa);
|
||||
}
|
||||
|
||||
for (self.relocs.values()) |*relocs| {
|
||||
relocs.deinit(gpa);
|
||||
@ -1160,12 +1169,17 @@ pub fn updateDecl(
|
||||
const decl = mod.declPtr(decl_index);
|
||||
|
||||
if (decl.val.getExternFunc(mod)) |_| {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
return;
|
||||
}
|
||||
if (decl.val.getVariable(mod)) |variable| {
|
||||
if (variable.is_extern) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
|
||||
if (decl.isExtern(mod)) {
|
||||
// TODO make this part of getGlobalSymbol
|
||||
const variable = decl.getOwnedVariable(mod).?;
|
||||
const name = mod.intern_pool.stringToSlice(decl.name);
|
||||
const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
|
||||
const global_index = try self.getGlobalSymbol(name, lib_name);
|
||||
try self.need_got_table.put(self.base.allocator, global_index, {});
|
||||
return;
|
||||
}
|
||||
|
||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
||||
@ -1462,62 +1476,77 @@ pub fn updateExports(
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement COFF linker code for exporting a constant value");
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| blk: {
|
||||
_ = try self.getOrCreateAtomForDecl(decl_index);
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
.fail => |em| {
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
break :blk self.anon_decls.getPtr(value).?;
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
||||
const atom_index = metadata.atom;
|
||||
const atom = self.getAtom(atom_index);
|
||||
const decl_metadata = self.decls.getPtr(decl_index).?;
|
||||
|
||||
for (exports) |exp| {
|
||||
log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
|
||||
|
||||
if (mod.intern_pool.stringToSliceUnwrap(exp.opts.section)) |section_name| {
|
||||
if (!mem.eql(u8, section_name, ".text")) {
|
||||
try mod.failed_exports.putNoClobber(
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp,
|
||||
try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
.{},
|
||||
),
|
||||
);
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exp.opts.linkage == .LinkOnce) {
|
||||
try mod.failed_exports.putNoClobber(
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp,
|
||||
try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
.{},
|
||||
),
|
||||
);
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
const sym_index = decl_metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: {
|
||||
const sym_index = try self.allocateSymbol();
|
||||
try decl_metadata.exports.append(gpa, sym_index);
|
||||
const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
|
||||
const sym_index = metadata.getExport(self, exp_name) orelse blk: {
|
||||
const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
|
||||
const global = self.globals.items[global_index];
|
||||
// TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
|
||||
// pass. This will go away once we abstact away Zig's incremental compilation into
|
||||
// its own module.
|
||||
if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) {
|
||||
_ = self.unresolved.swapRemove(global_index);
|
||||
break :ind global.sym_index;
|
||||
}
|
||||
break :ind try self.allocateSymbol();
|
||||
} else try self.allocateSymbol();
|
||||
try metadata.exports.append(gpa, sym_index);
|
||||
break :blk sym_index;
|
||||
};
|
||||
const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null };
|
||||
const sym = self.getSymbolPtr(sym_loc);
|
||||
try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name));
|
||||
try self.setSymbolName(sym, exp_name);
|
||||
sym.value = atom.getSymbol(self).value;
|
||||
sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.text_section_index.? + 1));
|
||||
sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL };
|
||||
sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1));
|
||||
sym.type = atom.getSymbol(self).type;
|
||||
|
||||
switch (exp.opts.linkage) {
|
||||
.Strong => {
|
||||
@ -1651,8 +1680,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
|
||||
if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed;
|
||||
}
|
||||
|
||||
{
|
||||
var it = self.need_got_table.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const global = self.globals.items[entry.key_ptr.*];
|
||||
try self.addGotEntry(global);
|
||||
}
|
||||
}
|
||||
|
||||
while (self.unresolved.popOrNull()) |entry| {
|
||||
assert(entry.value); // We only expect imports generated by the incremental linker for now.
|
||||
assert(entry.value);
|
||||
const global = self.globals.items[entry.key];
|
||||
const sym = self.getSymbol(global);
|
||||
const res = try self.import_tables.getOrPut(gpa, sym.value);
|
||||
@ -1761,8 +1798,8 @@ pub fn lowerAnonDecl(
|
||||
.none => ty.abiAlignment(mod),
|
||||
else => explicit_alignment,
|
||||
};
|
||||
if (self.anon_decls.get(decl_val)) |atom_index| {
|
||||
const existing_addr = self.getAtom(atom_index).getSymbol(self).value;
|
||||
if (self.anon_decls.get(decl_val)) |metadata| {
|
||||
const existing_addr = self.getAtom(metadata.atom).getSymbol(self).value;
|
||||
if (decl_alignment.check(existing_addr))
|
||||
return .ok;
|
||||
}
|
||||
@ -1792,14 +1829,14 @@ pub fn lowerAnonDecl(
|
||||
.ok => |atom_index| atom_index,
|
||||
.fail => |em| return .{ .fail = em },
|
||||
};
|
||||
try self.anon_decls.put(gpa, decl_val, atom_index);
|
||||
try self.anon_decls.put(gpa, decl_val, .{ .atom = atom_index, .section = self.rdata_section_index.? });
|
||||
return .ok;
|
||||
}
|
||||
|
||||
pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
assert(self.llvm_object == null);
|
||||
|
||||
const this_atom_index = self.anon_decls.get(decl_val).?;
|
||||
const this_atom_index = self.anon_decls.get(decl_val).?.atom;
|
||||
const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
|
||||
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
|
||||
const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
|
||||
@ -2447,6 +2484,11 @@ const GetOrPutGlobalPtrResult = struct {
|
||||
value_ptr: *SymbolWithLoc,
|
||||
};
|
||||
|
||||
/// Used only for disambiguating local from global at relocation level.
|
||||
/// TODO this must go away.
|
||||
pub const global_symbol_bit: u32 = 0x80000000;
|
||||
pub const global_symbol_mask: u32 = 0x7fffffff;
|
||||
|
||||
/// Return pointer to the global entry for `name` if one exists.
|
||||
/// Puts a new global entry for `name` if one doesn't exist, and
|
||||
/// returns a pointer to it.
|
||||
|
||||
117
src/link/Elf.zig
117
src/link/Elf.zig
@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
|
||||
lazy_syms: LazySymbolTable = .{},
|
||||
|
||||
/// Table of tracked Decls.
|
||||
decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
||||
decls: DeclTable = .{},
|
||||
|
||||
/// List of atoms that are owned directly by the linker.
|
||||
atoms: std.ArrayListUnmanaged(Atom) = .{},
|
||||
/// Table of last atom index in a section and matching atom free list if any.
|
||||
last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{},
|
||||
last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
|
||||
|
||||
/// Table of unnamed constants associated with a parent `Decl`.
|
||||
/// We store them here so that we can free the constants whenever the `Decl`
|
||||
@ -220,8 +220,10 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
|
||||
|
||||
const AtomList = std.ArrayListUnmanaged(Atom.Index);
|
||||
const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);
|
||||
const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
|
||||
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
|
||||
const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
|
||||
|
||||
/// When allocating, the ideal_capacity is calculated by
|
||||
/// actual_capacity + (actual_capacity / ideal_factor)
|
||||
@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {
|
||||
}
|
||||
self.unnamed_consts.deinit(gpa);
|
||||
}
|
||||
self.anon_decls.deinit(gpa);
|
||||
|
||||
{
|
||||
var it = self.anon_decls.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value_ptr.exports.deinit(gpa);
|
||||
}
|
||||
self.anon_decls.deinit(gpa);
|
||||
}
|
||||
|
||||
if (self.dwarf) |*dw| {
|
||||
dw.deinit();
|
||||
@ -497,8 +506,8 @@ pub fn lowerAnonDecl(
|
||||
.none => ty.abiAlignment(mod),
|
||||
else => explicit_alignment,
|
||||
};
|
||||
if (self.anon_decls.get(decl_val)) |sym_index| {
|
||||
const existing_alignment = self.symbol(sym_index).atom(self).?.alignment;
|
||||
if (self.anon_decls.get(decl_val)) |metadata| {
|
||||
const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
|
||||
if (decl_alignment.order(existing_alignment).compare(.lte))
|
||||
return .ok;
|
||||
}
|
||||
@ -528,13 +537,13 @@ pub fn lowerAnonDecl(
|
||||
.ok => |sym_index| sym_index,
|
||||
.fail => |em| return .{ .fail = em },
|
||||
};
|
||||
try self.anon_decls.put(gpa, decl_val, sym_index);
|
||||
try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
|
||||
return .ok;
|
||||
}
|
||||
|
||||
pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
assert(self.llvm_object == null);
|
||||
const sym_index = self.anon_decls.get(decl_val).?;
|
||||
const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
|
||||
const sym = self.symbol(sym_index);
|
||||
const vaddr = sym.value;
|
||||
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
|
||||
@ -3122,10 +3131,7 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
|
||||
const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
|
||||
if (!gop.found_existing) {
|
||||
const zig_module = self.file(self.zig_module_index.?).?.zig_module;
|
||||
gop.value_ptr.* = .{
|
||||
.symbol_index = try zig_module.addAtom(self),
|
||||
.exports = .{},
|
||||
};
|
||||
gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) };
|
||||
}
|
||||
return gop.value_ptr.symbol_index;
|
||||
}
|
||||
@ -3573,31 +3579,43 @@ pub fn updateExports(
|
||||
defer tracy.end();
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement ELF linker code for exporting a constant value");
|
||||
const zig_module = self.file(self.zig_module_index.?).?.zig_module;
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| blk: {
|
||||
_ = try self.getOrCreateMetadataForDecl(decl_index);
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
.fail => |em| {
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
break :blk self.anon_decls.getPtr(value).?;
|
||||
},
|
||||
};
|
||||
const zig_module = self.file(self.zig_module_index.?).?.zig_module;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
|
||||
const decl_esym_index = self.symbol(decl_sym_index).esym_index;
|
||||
const decl_esym = zig_module.local_esyms.items(.elf_sym)[decl_esym_index];
|
||||
const decl_esym_shndx = zig_module.local_esyms.items(.shndx)[decl_esym_index];
|
||||
const decl_metadata = self.decls.getPtr(decl_index).?;
|
||||
const sym_index = metadata.symbol_index;
|
||||
const esym_index = self.symbol(sym_index).esym_index;
|
||||
const esym = zig_module.local_esyms.items(.elf_sym)[esym_index];
|
||||
const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index];
|
||||
|
||||
for (exports) |exp| {
|
||||
const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
|
||||
if (exp.opts.section.unwrap()) |section_name| {
|
||||
if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(
|
||||
exp,
|
||||
try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}),
|
||||
);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -3607,34 +3625,37 @@ pub fn updateExports(
|
||||
.Weak => elf.STB_WEAK,
|
||||
.LinkOnce => {
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(
|
||||
exp,
|
||||
try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}),
|
||||
);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
},
|
||||
};
|
||||
const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));
|
||||
|
||||
const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
|
||||
const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
|
||||
const name_off = try self.strtab.insert(gpa, exp_name);
|
||||
const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
|
||||
const sym_index = try zig_module.addGlobalEsym(gpa);
|
||||
const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
|
||||
const global_esym_index = try zig_module.addGlobalEsym(gpa);
|
||||
const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
|
||||
const esym = zig_module.elfSym(sym_index);
|
||||
esym.st_name = name_off;
|
||||
lookup_gop.value_ptr.* = sym_index;
|
||||
try decl_metadata.exports.append(gpa, sym_index);
|
||||
const global_esym = zig_module.elfSym(global_esym_index);
|
||||
global_esym.st_name = name_off;
|
||||
lookup_gop.value_ptr.* = global_esym_index;
|
||||
try metadata.exports.append(gpa, global_esym_index);
|
||||
const gop = try self.getOrPutGlobal(name_off);
|
||||
try zig_module.global_symbols.append(gpa, gop.index);
|
||||
break :blk sym_index;
|
||||
break :blk global_esym_index;
|
||||
};
|
||||
const global_esym_index = sym_index & ZigModule.symbol_mask;
|
||||
const global_esym = &zig_module.global_esyms.items(.elf_sym)[global_esym_index];
|
||||
global_esym.st_value = self.symbol(decl_sym_index).value;
|
||||
global_esym.st_shndx = decl_esym.st_shndx;
|
||||
|
||||
const actual_esym_index = global_esym_index & ZigModule.symbol_mask;
|
||||
const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index];
|
||||
global_esym.st_value = self.symbol(sym_index).value;
|
||||
global_esym.st_shndx = esym.st_shndx;
|
||||
global_esym.st_info = (stb_bits << 4) | stt_bits;
|
||||
global_esym.st_name = name_off;
|
||||
zig_module.global_esyms.items(.shndx)[global_esym_index] = decl_esym_shndx;
|
||||
zig_module.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -50,7 +50,7 @@ tlv_ptr_section_index: ?u8 = null,
|
||||
locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
|
||||
globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
|
||||
resolver: std.StringHashMapUnmanaged(u32) = .{},
|
||||
unresolved: std.AutoArrayHashMapUnmanaged(u32, ResolveAction.Kind) = .{},
|
||||
unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
|
||||
|
||||
locals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
globals_free_list: std.ArrayListUnmanaged(u32) = .{},
|
||||
@ -115,6 +115,10 @@ anon_decls: AnonDeclTable = .{},
|
||||
/// Note that once we refactor `Atom`'s lifetime and ownership rules,
|
||||
/// this will be a table indexed by index into the list of Atoms.
|
||||
relocs: RelocationTable = .{},
|
||||
/// TODO I do not have time to make this right but this will go once
|
||||
/// MachO linker is rewritten more-or-less to feature the same resolution
|
||||
/// mechanism as the ELF linker.
|
||||
actions: ActionTable = .{},
|
||||
|
||||
/// A table of rebases indexed by the owning them `Atom`.
|
||||
/// Note that once we refactor `Atom`'s lifetime and ownership rules,
|
||||
@ -130,7 +134,7 @@ bindings: BindingTable = .{},
|
||||
lazy_syms: LazySymbolTable = .{},
|
||||
|
||||
/// Table of tracked Decls.
|
||||
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
||||
decls: DeclTable = .{},
|
||||
|
||||
/// Table of threadlocal variables descriptors.
|
||||
/// They are emitted in the `__thread_vars` section.
|
||||
@ -417,9 +421,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
try self.parseDependentLibs(&dependent_libs);
|
||||
}
|
||||
|
||||
var actions = std.ArrayList(ResolveAction).init(self.base.allocator);
|
||||
defer actions.deinit();
|
||||
try self.resolveSymbols(&actions);
|
||||
try self.resolveSymbols();
|
||||
|
||||
if (self.getEntryPoint() == null) {
|
||||
self.error_flags.no_entry_point_found = true;
|
||||
@ -429,11 +431,16 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
|
||||
return error.FlushFailure;
|
||||
}
|
||||
|
||||
for (actions.items) |action| switch (action.kind) {
|
||||
.none => {},
|
||||
.add_got => try self.addGotEntry(action.target),
|
||||
.add_stub => try self.addStubEntry(action.target),
|
||||
};
|
||||
{
|
||||
var it = self.actions.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const global_index = entry.key_ptr.*;
|
||||
const global = self.globals.items[global_index];
|
||||
const flags = entry.value_ptr.*;
|
||||
if (flags.add_got) try self.addGotEntry(global);
|
||||
if (flags.add_stub) try self.addStubEntry(global);
|
||||
}
|
||||
}
|
||||
|
||||
try self.createDyldPrivateAtom();
|
||||
try self.writeStubHelperPreamble();
|
||||
@ -1589,18 +1596,18 @@ pub fn createDsoHandleSymbol(self: *MachO) !void {
|
||||
_ = self.unresolved.swapRemove(self.getGlobalIndex("___dso_handle").?);
|
||||
}
|
||||
|
||||
pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void {
|
||||
pub fn resolveSymbols(self: *MachO) !void {
|
||||
// We add the specified entrypoint as the first unresolved symbols so that
|
||||
// we search for it in libraries should there be no object files specified
|
||||
// on the linker line.
|
||||
if (self.base.options.output_mode == .Exe) {
|
||||
const entry_name = self.base.options.entry orelse load_commands.default_entry_point;
|
||||
_ = try self.addUndefined(entry_name, .none);
|
||||
_ = try self.addUndefined(entry_name, .{});
|
||||
}
|
||||
|
||||
// Force resolution of any symbols requested by the user.
|
||||
for (self.base.options.force_undefined_symbols.keys()) |sym_name| {
|
||||
_ = try self.addUndefined(sym_name, .none);
|
||||
_ = try self.addUndefined(sym_name, .{});
|
||||
}
|
||||
|
||||
for (self.objects.items, 0..) |_, object_id| {
|
||||
@ -1612,13 +1619,13 @@ pub fn resolveSymbols(self: *MachO, actions: *std.ArrayList(ResolveAction)) !voi
|
||||
// Finally, force resolution of dyld_stub_binder if there are imports
|
||||
// requested.
|
||||
if (self.unresolved.count() > 0 and self.dyld_stub_binder_index == null) {
|
||||
self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .add_got);
|
||||
self.dyld_stub_binder_index = try self.addUndefined("dyld_stub_binder", .{ .add_got = true });
|
||||
}
|
||||
if (!self.base.options.single_threaded and self.mode == .incremental) {
|
||||
_ = try self.addUndefined("__tlv_bootstrap", .none);
|
||||
_ = try self.addUndefined("__tlv_bootstrap", .{});
|
||||
}
|
||||
|
||||
try self.resolveSymbolsInDylibs(actions);
|
||||
try self.resolveSymbolsInDylibs();
|
||||
|
||||
try self.createMhExecuteHeaderSymbol();
|
||||
try self.createDsoHandleSymbol();
|
||||
@ -1634,7 +1641,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = current;
|
||||
if (sym.undf() and !sym.tentative()) {
|
||||
try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, .none);
|
||||
try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, {});
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -1766,7 +1773,7 @@ fn resolveSymbolsInArchives(self: *MachO) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction)) !void {
|
||||
fn resolveSymbolsInDylibs(self: *MachO) !void {
|
||||
if (self.dylibs.items.len == 0) return;
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
@ -1793,11 +1800,7 @@ fn resolveSymbolsInDylibs(self: *MachO, actions: *std.ArrayList(ResolveAction))
|
||||
sym.n_desc |= macho.N_WEAK_REF;
|
||||
}
|
||||
|
||||
if (self.unresolved.fetchSwapRemove(global_index)) |entry| blk: {
|
||||
if (!sym.undf()) break :blk;
|
||||
if (self.mode == .zld) break :blk;
|
||||
try actions.append(.{ .kind = entry.value, .target = global });
|
||||
}
|
||||
_ = self.unresolved.swapRemove(global_index);
|
||||
|
||||
continue :loop;
|
||||
}
|
||||
@ -1904,6 +1907,7 @@ pub fn deinit(self: *MachO) void {
|
||||
m.exports.deinit(gpa);
|
||||
}
|
||||
self.decls.deinit(gpa);
|
||||
|
||||
self.lazy_syms.deinit(gpa);
|
||||
self.tlv_table.deinit(gpa);
|
||||
|
||||
@ -1911,7 +1915,14 @@ pub fn deinit(self: *MachO) void {
|
||||
atoms.deinit(gpa);
|
||||
}
|
||||
self.unnamed_const_atoms.deinit(gpa);
|
||||
self.anon_decls.deinit(gpa);
|
||||
|
||||
{
|
||||
var it = self.anon_decls.iterator();
|
||||
while (it.next()) |entry| {
|
||||
entry.value_ptr.exports.deinit(gpa);
|
||||
}
|
||||
self.anon_decls.deinit(gpa);
|
||||
}
|
||||
|
||||
self.atom_by_index_table.deinit(gpa);
|
||||
|
||||
@ -1919,6 +1930,7 @@ pub fn deinit(self: *MachO) void {
|
||||
relocs.deinit(gpa);
|
||||
}
|
||||
self.relocs.deinit(gpa);
|
||||
self.actions.deinit(gpa);
|
||||
|
||||
for (self.rebases.values()) |*rebases| {
|
||||
rebases.deinit(gpa);
|
||||
@ -2258,6 +2270,7 @@ fn lowerConst(
|
||||
log.debug(" (required alignment 0x{x})", .{required_alignment});
|
||||
|
||||
try self.writeAtom(atom_index, code);
|
||||
self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
|
||||
|
||||
return .{ .ok = atom_index };
|
||||
}
|
||||
@ -2273,12 +2286,16 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo
|
||||
const decl = mod.declPtr(decl_index);
|
||||
|
||||
if (decl.val.getExternFunc(mod)) |_| {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
return;
|
||||
}
|
||||
if (decl.val.getVariable(mod)) |variable| {
|
||||
if (variable.is_extern) {
|
||||
return; // TODO Should we do more when front-end analyzed extern decl?
|
||||
}
|
||||
|
||||
if (decl.isExtern(mod)) {
|
||||
// TODO make this part of getGlobalSymbol
|
||||
const name = mod.intern_pool.stringToSlice(decl.name);
|
||||
const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
|
||||
defer self.base.allocator.free(sym_name);
|
||||
_ = try self.addUndefined(sym_name, .{ .add_got = true });
|
||||
return;
|
||||
}
|
||||
|
||||
const is_threadlocal = if (decl.val.getVariable(mod)) |variable|
|
||||
@ -2689,18 +2706,30 @@ pub fn updateExports(
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement MachO linker code for exporting a constant value");
|
||||
const metadata = switch (exported) {
|
||||
.decl_index => |decl_index| blk: {
|
||||
_ = try self.getOrCreateAtomForDecl(decl_index);
|
||||
break :blk self.decls.getPtr(decl_index).?;
|
||||
},
|
||||
.value => |value| self.anon_decls.getPtr(value) orelse blk: {
|
||||
const first_exp = exports[0];
|
||||
const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
|
||||
switch (res) {
|
||||
.ok => {},
|
||||
.fail => |em| {
|
||||
// TODO maybe it's enough to return an error here and let Module.processExportsInner
|
||||
// handle the error?
|
||||
try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
|
||||
return;
|
||||
},
|
||||
}
|
||||
break :blk self.anon_decls.getPtr(value).?;
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
||||
const atom_index = metadata.atom;
|
||||
const atom = self.getAtom(atom_index);
|
||||
const decl_sym = atom.getSymbol(self);
|
||||
const decl_metadata = self.decls.getPtr(decl_index).?;
|
||||
const sym = atom.getSymbol(self);
|
||||
|
||||
for (exports) |exp| {
|
||||
const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{
|
||||
@ -2712,73 +2741,75 @@ pub fn updateExports(
|
||||
|
||||
if (exp.opts.section.unwrap()) |section_name| {
|
||||
if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
|
||||
try mod.failed_exports.putNoClobber(
|
||||
mod.gpa,
|
||||
exp,
|
||||
try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
.{},
|
||||
),
|
||||
);
|
||||
try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: ExportOptions.section",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (exp.opts.linkage == .LinkOnce) {
|
||||
try mod.failed_exports.putNoClobber(
|
||||
mod.gpa,
|
||||
exp,
|
||||
try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
.{},
|
||||
),
|
||||
);
|
||||
try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
exp.getSrcLoc(mod),
|
||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
}
|
||||
|
||||
const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {
|
||||
const sym_index = try self.allocateSymbol();
|
||||
try decl_metadata.exports.append(gpa, sym_index);
|
||||
break :blk sym_index;
|
||||
const global_sym_index = metadata.getExport(self, exp_name) orelse blk: {
|
||||
const global_sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: {
|
||||
const global = self.globals.items[global_index];
|
||||
// TODO this is just plain wrong as it all should happen in a single `resolveSymbols`
|
||||
// pass. This will go away once we abstact away Zig's incremental compilation into
|
||||
// its own module.
|
||||
if (global.getFile() == null and self.getSymbol(global).undf()) {
|
||||
_ = self.unresolved.swapRemove(global_index);
|
||||
break :ind global.sym_index;
|
||||
}
|
||||
break :ind try self.allocateSymbol();
|
||||
} else try self.allocateSymbol();
|
||||
try metadata.exports.append(gpa, global_sym_index);
|
||||
break :blk global_sym_index;
|
||||
};
|
||||
const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
|
||||
const sym = self.getSymbolPtr(sym_loc);
|
||||
sym.* = .{
|
||||
const global_sym_loc = SymbolWithLoc{ .sym_index = global_sym_index };
|
||||
const global_sym = self.getSymbolPtr(global_sym_loc);
|
||||
global_sym.* = .{
|
||||
.n_strx = try self.strtab.insert(gpa, exp_name),
|
||||
.n_type = macho.N_SECT | macho.N_EXT,
|
||||
.n_sect = self.text_section_index.? + 1, // TODO what if we export a variable?
|
||||
.n_sect = metadata.section + 1,
|
||||
.n_desc = 0,
|
||||
.n_value = decl_sym.n_value,
|
||||
.n_value = sym.n_value,
|
||||
};
|
||||
|
||||
switch (exp.opts.linkage) {
|
||||
.Internal => {
|
||||
// Symbol should be hidden, or in MachO lingo, private extern.
|
||||
// We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
|
||||
sym.n_type |= macho.N_PEXT;
|
||||
sym.n_desc |= macho.N_WEAK_DEF;
|
||||
global_sym.n_type |= macho.N_PEXT;
|
||||
global_sym.n_desc |= macho.N_WEAK_DEF;
|
||||
},
|
||||
.Strong => {},
|
||||
.Weak => {
|
||||
// Weak linkage is specified as part of n_desc field.
|
||||
// Symbol's n_type is like for a symbol with strong linkage.
|
||||
sym.n_desc |= macho.N_WEAK_DEF;
|
||||
global_sym.n_desc |= macho.N_WEAK_DEF;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
|
||||
self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
|
||||
self.resolveGlobalSymbol(global_sym_loc) catch |err| switch (err) {
|
||||
error.MultipleSymbolDefinitions => {
|
||||
// TODO: this needs rethinking
|
||||
const global = self.getGlobal(exp_name).?;
|
||||
if (sym_loc.sym_index != global.sym_index and global.getFile() != null) {
|
||||
if (global_sym_loc.sym_index != global.sym_index and global.getFile() != null) {
|
||||
_ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
exp.getSrcLoc(mod),
|
||||
\\LinkError: symbol '{s}' defined multiple times
|
||||
,
|
||||
.{exp_name},
|
||||
@ -2886,8 +2917,8 @@ pub fn lowerAnonDecl(
|
||||
.none => ty.abiAlignment(mod),
|
||||
else => explicit_alignment,
|
||||
};
|
||||
if (self.anon_decls.get(decl_val)) |atom_index| {
|
||||
const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value;
|
||||
if (self.anon_decls.get(decl_val)) |metadata| {
|
||||
const existing_addr = self.getAtom(metadata.atom).getSymbol(self).n_value;
|
||||
if (decl_alignment.check(existing_addr))
|
||||
return .ok;
|
||||
}
|
||||
@ -2917,14 +2948,17 @@ pub fn lowerAnonDecl(
|
||||
.ok => |atom_index| atom_index,
|
||||
.fail => |em| return .{ .fail = em },
|
||||
};
|
||||
try self.anon_decls.put(gpa, decl_val, atom_index);
|
||||
try self.anon_decls.put(gpa, decl_val, .{
|
||||
.atom = atom_index,
|
||||
.section = self.data_const_section_index.?,
|
||||
});
|
||||
return .ok;
|
||||
}
|
||||
|
||||
pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||
assert(self.llvm_object == null);
|
||||
|
||||
const this_atom_index = self.anon_decls.get(decl_val).?;
|
||||
const this_atom_index = self.anon_decls.get(decl_val).?.atom;
|
||||
const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
|
||||
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
|
||||
try Atom.addRelocation(self, atom_index, .{
|
||||
@ -3407,7 +3441,7 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u
|
||||
const gpa = self.base.allocator;
|
||||
const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
|
||||
defer gpa.free(sym_name);
|
||||
return self.addUndefined(sym_name, .add_stub);
|
||||
return self.addUndefined(sym_name, .{ .add_stub = true });
|
||||
}
|
||||
|
||||
pub fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
|
||||
@ -4691,13 +4725,16 @@ pub fn ptraceDetach(self: *MachO, pid: std.os.pid_t) !void {
|
||||
self.hot_state.mach_task = null;
|
||||
}
|
||||
|
||||
fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32 {
|
||||
pub fn addUndefined(self: *MachO, name: []const u8, flags: RelocFlags) !u32 {
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const gop = try self.getOrPutGlobalPtr(name);
|
||||
const global_index = self.getGlobalIndex(name).?;
|
||||
|
||||
if (gop.found_existing) return global_index;
|
||||
if (gop.found_existing) {
|
||||
try self.updateRelocActions(global_index, flags);
|
||||
return global_index;
|
||||
}
|
||||
|
||||
const sym_index = try self.allocateSymbol();
|
||||
const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
|
||||
@ -4705,13 +4742,23 @@ fn addUndefined(self: *MachO, name: []const u8, action: ResolveAction.Kind) !u32
|
||||
|
||||
const sym = self.getSymbolPtr(sym_loc);
|
||||
sym.n_strx = try self.strtab.insert(gpa, name);
|
||||
sym.n_type = macho.N_UNDF;
|
||||
sym.n_type = macho.N_EXT | macho.N_UNDF;
|
||||
|
||||
try self.unresolved.putNoClobber(gpa, global_index, action);
|
||||
try self.unresolved.putNoClobber(gpa, global_index, {});
|
||||
try self.updateRelocActions(global_index, flags);
|
||||
|
||||
return global_index;
|
||||
}
|
||||
|
||||
fn updateRelocActions(self: *MachO, global_index: u32, flags: RelocFlags) !void {
|
||||
const act_gop = try self.actions.getOrPut(self.base.allocator, global_index);
|
||||
if (!act_gop.found_existing) {
|
||||
act_gop.value_ptr.* = .{};
|
||||
}
|
||||
act_gop.value_ptr.add_got = act_gop.value_ptr.add_got or flags.add_got;
|
||||
act_gop.value_ptr.add_stub = act_gop.value_ptr.add_stub or flags.add_stub;
|
||||
}
|
||||
|
||||
pub fn makeStaticString(bytes: []const u8) [16]u8 {
|
||||
var buf = [_]u8{0} ** 16;
|
||||
@memcpy(buf[0..bytes.len], bytes);
|
||||
@ -4823,6 +4870,11 @@ const GetOrPutGlobalPtrResult = struct {
|
||||
value_ptr: *SymbolWithLoc,
|
||||
};
|
||||
|
||||
/// Used only for disambiguating local from global at relocation level.
|
||||
/// TODO this must go away.
|
||||
pub const global_symbol_bit: u32 = 0x80000000;
|
||||
pub const global_symbol_mask: u32 = 0x7fffffff;
|
||||
|
||||
/// Return pointer to the global entry for `name` if one exists.
|
||||
/// Puts a new global entry for `name` if one doesn't exist, and
|
||||
/// returns a pointer to it.
|
||||
@ -5489,21 +5541,17 @@ const DeclMetadata = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);
|
||||
const DeclTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
|
||||
const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
|
||||
const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
|
||||
const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
|
||||
const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
|
||||
const RelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
|
||||
const ActionTable = std.AutoHashMapUnmanaged(u32, RelocFlags);
|
||||
|
||||
pub const ResolveAction = struct {
|
||||
kind: Kind,
|
||||
target: SymbolWithLoc,
|
||||
|
||||
const Kind = enum {
|
||||
none,
|
||||
add_got,
|
||||
add_stub,
|
||||
};
|
||||
pub const RelocFlags = packed struct {
|
||||
add_got: bool = false,
|
||||
add_stub: bool = false,
|
||||
};
|
||||
|
||||
pub const SymbolWithLoc = extern struct {
|
||||
|
||||
@ -300,7 +300,7 @@ pub fn resolveRelocations(
|
||||
relocs: []*const Relocation,
|
||||
code: []u8,
|
||||
) void {
|
||||
log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});
|
||||
relocs_log.debug("relocating '{s}'", .{macho_file.getAtom(atom_index).getName(macho_file)});
|
||||
for (relocs) |reloc| {
|
||||
reloc.resolve(macho_file, atom_index, code);
|
||||
}
|
||||
@ -603,7 +603,7 @@ pub fn resolveRelocs(
|
||||
const atom = macho_file.getAtom(atom_index);
|
||||
assert(atom.getFile() != null); // synthetic atoms do not have relocs
|
||||
|
||||
log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{
|
||||
relocs_log.debug("resolving relocations in ATOM(%{d}, '{s}')", .{
|
||||
atom.sym_index,
|
||||
macho_file.getSymbolName(atom.getSymbolWithLoc()),
|
||||
});
|
||||
@ -683,7 +683,7 @@ fn resolveRelocsArm64(
|
||||
.ARM64_RELOC_ADDEND => {
|
||||
assert(addend == null);
|
||||
|
||||
log.debug(" RELA({s}) @ {x} => {x}", .{ @tagName(rel_type), rel.r_address, rel.r_symbolnum });
|
||||
relocs_log.debug(" RELA({s}) @ {x} => {x}", .{ @tagName(rel_type), rel.r_address, rel.r_symbolnum });
|
||||
|
||||
addend = rel.r_symbolnum;
|
||||
continue;
|
||||
@ -691,7 +691,7 @@ fn resolveRelocsArm64(
|
||||
.ARM64_RELOC_SUBTRACTOR => {
|
||||
assert(subtractor == null);
|
||||
|
||||
log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
|
||||
relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
rel.r_symbolnum,
|
||||
@ -719,7 +719,7 @@ fn resolveRelocsArm64(
|
||||
});
|
||||
const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));
|
||||
|
||||
log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
|
||||
relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
target.sym_index,
|
||||
@ -745,11 +745,11 @@ fn resolveRelocsArm64(
|
||||
break :blk getRelocTargetAddress(macho_file, target, is_tlv);
|
||||
};
|
||||
|
||||
log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
relocs_log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
|
||||
switch (rel_type) {
|
||||
.ARM64_RELOC_BRANCH26 => {
|
||||
log.debug(" source {s} (object({?})), target {s}", .{
|
||||
relocs_log.debug(" source {s} (object({?})), target {s}", .{
|
||||
macho_file.getSymbolName(atom.getSymbolWithLoc()),
|
||||
atom.getFile(),
|
||||
macho_file.getSymbolName(target),
|
||||
@ -759,7 +759,7 @@ fn resolveRelocsArm64(
|
||||
source_addr,
|
||||
target_addr,
|
||||
)) |disp| blk: {
|
||||
log.debug(" | target_addr = 0x{x}", .{target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{target_addr});
|
||||
break :blk disp;
|
||||
} else |_| blk: {
|
||||
const thunk_index = macho_file.thunk_table.get(atom_index).?;
|
||||
@ -769,7 +769,7 @@ fn resolveRelocsArm64(
|
||||
else
|
||||
thunk.getTrampoline(macho_file, .atom, target).?;
|
||||
const thunk_addr = macho_file.getSymbol(thunk_sym_loc).n_value;
|
||||
log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});
|
||||
break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr);
|
||||
};
|
||||
|
||||
@ -790,7 +790,7 @@ fn resolveRelocsArm64(
|
||||
=> {
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
|
||||
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
|
||||
const pages = @as(u21, @bitCast(Relocation.calcNumberOfPages(source_addr, adjusted_target_addr)));
|
||||
const code = atom_code[rel_offset..][0..4];
|
||||
@ -809,7 +809,7 @@ fn resolveRelocsArm64(
|
||||
.ARM64_RELOC_PAGEOFF12 => {
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
|
||||
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
|
||||
const code = atom_code[rel_offset..][0..4];
|
||||
if (Relocation.isArithmeticOp(code)) {
|
||||
@ -848,7 +848,7 @@ fn resolveRelocsArm64(
|
||||
const code = atom_code[rel_offset..][0..4];
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
|
||||
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
|
||||
const off = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64);
|
||||
var inst: aarch64.Instruction = .{
|
||||
@ -866,7 +866,7 @@ fn resolveRelocsArm64(
|
||||
const code = atom_code[rel_offset..][0..4];
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + (addend orelse 0)));
|
||||
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
|
||||
const RegInfo = struct {
|
||||
rd: u5,
|
||||
@ -923,7 +923,7 @@ fn resolveRelocsArm64(
|
||||
},
|
||||
|
||||
.ARM64_RELOC_POINTER_TO_GOT => {
|
||||
log.debug(" | target_addr = 0x{x}", .{target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{target_addr});
|
||||
const result = math.cast(i32, @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr))) orelse
|
||||
return error.Overflow;
|
||||
mem.writeIntLittle(u32, atom_code[rel_offset..][0..4], @as(u32, @bitCast(result)));
|
||||
@ -951,7 +951,7 @@ fn resolveRelocsArm64(
|
||||
break :blk @as(i64, @intCast(target_addr)) + ptr_addend;
|
||||
}
|
||||
};
|
||||
log.debug(" | target_addr = 0x{x}", .{result});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{result});
|
||||
|
||||
if (rel.r_length == 3) {
|
||||
mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));
|
||||
@ -987,7 +987,7 @@ fn resolveRelocsX86(
|
||||
.X86_64_RELOC_SUBTRACTOR => {
|
||||
assert(subtractor == null);
|
||||
|
||||
log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
|
||||
relocs_log.debug(" RELA({s}) @ {x} => %{d} in object({?d})", .{
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
rel.r_symbolnum,
|
||||
@ -1015,7 +1015,7 @@ fn resolveRelocsX86(
|
||||
});
|
||||
const rel_offset = @as(u32, @intCast(rel.r_address - context.base_offset));
|
||||
|
||||
log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
|
||||
relocs_log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
|
||||
@tagName(rel_type),
|
||||
rel.r_address,
|
||||
target.sym_index,
|
||||
@ -1041,13 +1041,13 @@ fn resolveRelocsX86(
|
||||
break :blk getRelocTargetAddress(macho_file, target, is_tlv);
|
||||
};
|
||||
|
||||
log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
relocs_log.debug(" | source_addr = 0x{x}", .{source_addr});
|
||||
|
||||
switch (rel_type) {
|
||||
.X86_64_RELOC_BRANCH => {
|
||||
const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
|
||||
mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
|
||||
},
|
||||
@ -1057,7 +1057,7 @@ fn resolveRelocsX86(
|
||||
=> {
|
||||
const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
|
||||
mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
|
||||
},
|
||||
@ -1065,7 +1065,7 @@ fn resolveRelocsX86(
|
||||
.X86_64_RELOC_TLV => {
|
||||
const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
|
||||
|
||||
if (macho_file.tlv_ptr_table.lookup.get(target) == null) {
|
||||
@ -1101,7 +1101,7 @@ fn resolveRelocsX86(
|
||||
|
||||
const adjusted_target_addr = @as(u64, @intCast(@as(i64, @intCast(target_addr)) + addend));
|
||||
|
||||
log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
|
||||
|
||||
const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction);
|
||||
mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
|
||||
@ -1129,7 +1129,7 @@ fn resolveRelocsX86(
|
||||
break :blk @as(i64, @intCast(target_addr)) + addend;
|
||||
}
|
||||
};
|
||||
log.debug(" | target_addr = 0x{x}", .{result});
|
||||
relocs_log.debug(" | target_addr = 0x{x}", .{result});
|
||||
|
||||
if (rel.r_length == 3) {
|
||||
mem.writeIntLittle(u64, atom_code[rel_offset..][0..8], @as(u64, @bitCast(result)));
|
||||
@ -1247,6 +1247,7 @@ const build_options = @import("build_options");
|
||||
const aarch64 = @import("../../arch/aarch64/bits.zig");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.link);
|
||||
const relocs_log = std.log.scoped(.link_relocs);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
@ -99,7 +99,7 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
|
||||
else => @as(i64, @intCast(target_base_addr)) + self.addend,
|
||||
};
|
||||
|
||||
log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
|
||||
relocs_log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{
|
||||
source_addr,
|
||||
target_addr,
|
||||
macho_file.getSymbolName(self.target),
|
||||
@ -256,7 +256,7 @@ const Relocation = @This();
|
||||
const std = @import("std");
|
||||
const aarch64 = @import("../../arch/aarch64/bits.zig");
|
||||
const assert = std.debug.assert;
|
||||
const log = std.log.scoped(.link);
|
||||
const relocs_log = std.log.scoped(.link_relocs);
|
||||
const macho = std.macho;
|
||||
const math = std.math;
|
||||
const mem = std.mem;
|
||||
|
||||
@ -390,9 +390,7 @@ pub fn linkWithZld(
|
||||
|
||||
try macho_file.parseDependentLibs(&dependent_libs);
|
||||
|
||||
var actions = std.ArrayList(MachO.ResolveAction).init(gpa);
|
||||
defer actions.deinit();
|
||||
try macho_file.resolveSymbols(&actions);
|
||||
try macho_file.resolveSymbols();
|
||||
if (macho_file.unresolved.count() > 0) {
|
||||
try macho_file.reportUndefined();
|
||||
return error.FlushFailure;
|
||||
|
||||
@ -54,7 +54,10 @@ test "exporting using field access" {
|
||||
test "exporting comptime-known value" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and
|
||||
(builtin.target.ofmt != .elf and
|
||||
builtin.target.ofmt != .macho and
|
||||
builtin.target.ofmt != .coff)) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
@ -70,7 +73,10 @@ test "exporting comptime-known value" {
|
||||
test "exporting comptime var" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_x86_64 and
|
||||
(builtin.target.ofmt != .elf and
|
||||
builtin.target.ofmt != .macho and
|
||||
builtin.target.ofmt != .coff)) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user