mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
macho: implement exporting anon decls
This commit is contained in:
parent
eaca72534c
commit
a7a95ce9c4
@ -130,7 +130,7 @@ bindings: BindingTable = .{},
|
|||||||
lazy_syms: LazySymbolTable = .{},
|
lazy_syms: LazySymbolTable = .{},
|
||||||
|
|
||||||
/// Table of tracked Decls.
|
/// Table of tracked Decls.
|
||||||
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
|
decls: DeclTable = .{},
|
||||||
|
|
||||||
/// Table of threadlocal variables descriptors.
|
/// Table of threadlocal variables descriptors.
|
||||||
/// They are emitted in the `__thread_vars` section.
|
/// They are emitted in the `__thread_vars` section.
|
||||||
@ -1904,6 +1904,7 @@ pub fn deinit(self: *MachO) void {
|
|||||||
m.exports.deinit(gpa);
|
m.exports.deinit(gpa);
|
||||||
}
|
}
|
||||||
self.decls.deinit(gpa);
|
self.decls.deinit(gpa);
|
||||||
|
|
||||||
self.lazy_syms.deinit(gpa);
|
self.lazy_syms.deinit(gpa);
|
||||||
self.tlv_table.deinit(gpa);
|
self.tlv_table.deinit(gpa);
|
||||||
|
|
||||||
@ -1911,7 +1912,14 @@ pub fn deinit(self: *MachO) void {
|
|||||||
atoms.deinit(gpa);
|
atoms.deinit(gpa);
|
||||||
}
|
}
|
||||||
self.unnamed_const_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);
|
self.atom_by_index_table.deinit(gpa);
|
||||||
|
|
||||||
@ -2689,18 +2697,30 @@ pub fn updateExports(
|
|||||||
|
|
||||||
const gpa = self.base.allocator;
|
const gpa = self.base.allocator;
|
||||||
|
|
||||||
const decl_index = switch (exported) {
|
const metadata = switch (exported) {
|
||||||
.decl_index => |i| i,
|
.decl_index => |decl_index| blk: {
|
||||||
.value => |val| {
|
_ = try self.getOrCreateAtomForDecl(decl_index);
|
||||||
_ = val;
|
break :blk self.decls.getPtr(decl_index).?;
|
||||||
@panic("TODO: implement MachO linker code for exporting a constant value");
|
},
|
||||||
|
.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 = metadata.atom;
|
||||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
|
||||||
const atom = self.getAtom(atom_index);
|
const atom = self.getAtom(atom_index);
|
||||||
const decl_sym = atom.getSymbol(self);
|
const sym = atom.getSymbol(self);
|
||||||
const decl_metadata = self.decls.getPtr(decl_index).?;
|
|
||||||
|
|
||||||
for (exports) |exp| {
|
for (exports) |exp| {
|
||||||
const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{
|
const exp_name = try std.fmt.allocPrint(gpa, "_{}", .{
|
||||||
@ -2712,73 +2732,65 @@ pub fn updateExports(
|
|||||||
|
|
||||||
if (exp.opts.section.unwrap()) |section_name| {
|
if (exp.opts.section.unwrap()) |section_name| {
|
||||||
if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
|
if (!mod.intern_pool.stringEqlSlice(section_name, "__text")) {
|
||||||
try mod.failed_exports.putNoClobber(
|
try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||||
mod.gpa,
|
gpa,
|
||||||
exp,
|
exp.getSrcLoc(mod),
|
||||||
try Module.ErrorMsg.create(
|
"Unimplemented: ExportOptions.section",
|
||||||
gpa,
|
.{},
|
||||||
decl.srcLoc(mod),
|
));
|
||||||
"Unimplemented: ExportOptions.section",
|
|
||||||
.{},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exp.opts.linkage == .LinkOnce) {
|
if (exp.opts.linkage == .LinkOnce) {
|
||||||
try mod.failed_exports.putNoClobber(
|
try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||||
mod.gpa,
|
gpa,
|
||||||
exp,
|
exp.getSrcLoc(mod),
|
||||||
try Module.ErrorMsg.create(
|
"Unimplemented: GlobalLinkage.LinkOnce",
|
||||||
gpa,
|
.{},
|
||||||
decl.srcLoc(mod),
|
));
|
||||||
"Unimplemented: GlobalLinkage.LinkOnce",
|
|
||||||
.{},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: {
|
const global_sym_index = metadata.getExport(self, exp_name) orelse blk: {
|
||||||
const sym_index = try self.allocateSymbol();
|
const global_sym_index = try self.allocateSymbol();
|
||||||
try decl_metadata.exports.append(gpa, sym_index);
|
try metadata.exports.append(gpa, global_sym_index);
|
||||||
break :blk sym_index;
|
break :blk global_sym_index;
|
||||||
};
|
};
|
||||||
const sym_loc = SymbolWithLoc{ .sym_index = sym_index };
|
const global_sym_loc = SymbolWithLoc{ .sym_index = global_sym_index };
|
||||||
const sym = self.getSymbolPtr(sym_loc);
|
const global_sym = self.getSymbolPtr(global_sym_loc);
|
||||||
sym.* = .{
|
global_sym.* = .{
|
||||||
.n_strx = try self.strtab.insert(gpa, exp_name),
|
.n_strx = try self.strtab.insert(gpa, exp_name),
|
||||||
.n_type = macho.N_SECT | macho.N_EXT,
|
.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_desc = 0,
|
||||||
.n_value = decl_sym.n_value,
|
.n_value = sym.n_value,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (exp.opts.linkage) {
|
switch (exp.opts.linkage) {
|
||||||
.Internal => {
|
.Internal => {
|
||||||
// Symbol should be hidden, or in MachO lingo, private extern.
|
// Symbol should be hidden, or in MachO lingo, private extern.
|
||||||
// We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
|
// We should also mark the symbol as Weak: n_desc == N_WEAK_DEF.
|
||||||
sym.n_type |= macho.N_PEXT;
|
global_sym.n_type |= macho.N_PEXT;
|
||||||
sym.n_desc |= macho.N_WEAK_DEF;
|
global_sym.n_desc |= macho.N_WEAK_DEF;
|
||||||
},
|
},
|
||||||
.Strong => {},
|
.Strong => {},
|
||||||
.Weak => {
|
.Weak => {
|
||||||
// Weak linkage is specified as part of n_desc field.
|
// Weak linkage is specified as part of n_desc field.
|
||||||
// Symbol's n_type is like for a symbol with strong linkage.
|
// 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,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.resolveGlobalSymbol(sym_loc) catch |err| switch (err) {
|
self.resolveGlobalSymbol(global_sym_loc) catch |err| switch (err) {
|
||||||
error.MultipleSymbolDefinitions => {
|
error.MultipleSymbolDefinitions => {
|
||||||
// TODO: this needs rethinking
|
// TODO: this needs rethinking
|
||||||
const global = self.getGlobal(exp_name).?;
|
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(
|
_ = try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
|
||||||
gpa,
|
gpa,
|
||||||
decl.srcLoc(mod),
|
exp.getSrcLoc(mod),
|
||||||
\\LinkError: symbol '{s}' defined multiple times
|
\\LinkError: symbol '{s}' defined multiple times
|
||||||
,
|
,
|
||||||
.{exp_name},
|
.{exp_name},
|
||||||
@ -2886,8 +2898,8 @@ pub fn lowerAnonDecl(
|
|||||||
.none => ty.abiAlignment(mod),
|
.none => ty.abiAlignment(mod),
|
||||||
else => explicit_alignment,
|
else => explicit_alignment,
|
||||||
};
|
};
|
||||||
if (self.anon_decls.get(decl_val)) |atom_index| {
|
if (self.anon_decls.get(decl_val)) |metadata| {
|
||||||
const existing_addr = self.getAtom(atom_index).getSymbol(self).n_value;
|
const existing_addr = self.getAtom(metadata.atom).getSymbol(self).n_value;
|
||||||
if (decl_alignment.check(existing_addr))
|
if (decl_alignment.check(existing_addr))
|
||||||
return .ok;
|
return .ok;
|
||||||
}
|
}
|
||||||
@ -2917,14 +2929,17 @@ pub fn lowerAnonDecl(
|
|||||||
.ok => |atom_index| atom_index,
|
.ok => |atom_index| atom_index,
|
||||||
.fail => |em| return .{ .fail = em },
|
.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;
|
return .ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
|
||||||
assert(self.llvm_object == null);
|
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 sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
|
||||||
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
|
const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
|
||||||
try Atom.addRelocation(self, atom_index, .{
|
try Atom.addRelocation(self, atom_index, .{
|
||||||
@ -5489,7 +5504,8 @@ 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 BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
|
||||||
const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
|
const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
|
||||||
const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
|
const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
|
||||||
|
|||||||
@ -54,7 +54,9 @@ test "exporting using field access" {
|
|||||||
test "exporting comptime-known value" {
|
test "exporting comptime-known value" {
|
||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and
|
||||||
|
(builtin.target.ofmt != .elf and
|
||||||
|
builtin.target.ofmt != .macho)) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_aarch64) 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_c) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
@ -70,7 +72,9 @@ test "exporting comptime-known value" {
|
|||||||
test "exporting comptime var" {
|
test "exporting comptime var" {
|
||||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_x86_64 and
|
||||||
|
(builtin.target.ofmt != .elf and
|
||||||
|
builtin.target.ofmt != .macho)) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_aarch64) 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_c) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user