x86_64: add support for pie executables

This commit is contained in:
Jacob Young
2025-06-04 21:45:31 -04:00
committed by Andrew Kelley
parent 178ee8aef1
commit 0bf8617d96
45 changed files with 884 additions and 640 deletions

View File

@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
fn renderFwdDecl(
dg: *DeclGen,
nav_index: InternPool.Nav.Index,
flags: struct {
is_extern: bool,
flags: packed struct {
is_const: bool,
is_threadlocal: bool,
is_weak_linkage: bool,
linkage: std.builtin.GlobalLinkage,
visibility: std.builtin.SymbolVisibility,
},
) !void {
const zcu = dg.pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const fwd = dg.fwdDeclWriter();
try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");
if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
try fwd.writeAll(switch (flags.linkage) {
.internal => "static ",
.strong, .weak, .link_once => "zig_extern ",
});
switch (flags.linkage) {
.internal, .strong => {},
.weak => try fwd.writeAll("zig_weak_linkage "),
.link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
}
switch (flags.linkage) {
.internal => {},
.strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}),
}
if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
try dg.renderTypeAndName(
fwd,
@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
switch (ip.indexToKey(nav.status.fully_resolved.val)) {
.@"extern" => |@"extern"| {
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
.is_extern = true,
.is_const = @"extern".is_const,
.is_threadlocal = @"extern".is_threadlocal,
.is_weak_linkage = @"extern".is_weak_linkage,
.linkage = @"extern".linkage,
.visibility = @"extern".visibility,
});
const fwd = o.dg.fwdDeclWriter();
@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
},
.variable => |variable| {
try o.dg.renderFwdDecl(o.dg.pass.nav, .{
.is_extern = false,
.is_const = false,
.is_threadlocal = variable.is_threadlocal,
.is_weak_linkage = variable.is_weak_linkage,
.linkage = .internal,
.visibility = .default,
});
const w = o.writer();
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
.vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
.tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
.runtime_nav_ptr => try airRuntimeNavPtr(f, inst),
.c_va_start => try airCVaStart(f, inst),
.c_va_arg => try airCVaArg(f, inst),
@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
const writer = f.object.writer();
const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));

View File

@@ -2979,36 +2979,49 @@ pub const Object = struct {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) {
.unresolved => unreachable,
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
.variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
.@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
else => .{ false, false, false, false },
.variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
.@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
else => .{ .internal, .default, false, false },
},
// This means it's a source declaration which is not `extern`!
.type_resolved => |r| .{ false, r.is_threadlocal, false, false },
.type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false },
};
const variable_index = try o.builder.addVariable(
try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
try o.builder.strtabString(switch (linkage) {
.internal => nav.fqn,
.strong, .weak => nav.name,
.link_once => unreachable,
}.toSlice(ip)),
try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
);
gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
// This is needed for declarations created by `@extern`.
if (is_extern) {
variable_index.setLinkage(.external, &o.builder);
variable_index.setUnnamedAddr(.default, &o.builder);
if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
variable_index.setThreadLocal(.generaldynamic, &o.builder);
if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
} else {
variable_index.setLinkage(.internal, &o.builder);
variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
switch (linkage) {
.internal => {
variable_index.setLinkage(.internal, &o.builder);
variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
},
.strong, .weak => {
variable_index.setLinkage(switch (linkage) {
.internal => unreachable,
.strong => .external,
.weak => .extern_weak,
.link_once => unreachable,
}, &o.builder);
variable_index.setUnnamedAddr(.default, &o.builder);
if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
variable_index.setThreadLocal(.generaldynamic, &o.builder);
if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
},
.link_once => unreachable,
}
variable_index.setVisibility(visibility, &o.builder);
return variable_index;
}
@@ -4530,14 +4543,14 @@ pub const NavGen = struct {
const nav = ip.getNav(nav_index);
const resolved = nav.status.fully_resolved;
const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
.variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
.@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
.variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav },
.@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
};
const ty = Type.fromInterned(nav.typeOf(ip));
if (is_extern and ip.isFunctionType(ty.toIntern())) {
if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
_ = try o.resolveLlvmFunction(owner_nav);
} else {
const variable_index = try o.resolveGlobalNav(nav_index);
@@ -4549,6 +4562,7 @@ pub const NavGen = struct {
.none => .no_init,
else => try o.lowerValue(init_val),
}, &o.builder);
variable_index.setVisibility(visibility, &o.builder);
const file_scope = zcu.navFileScopeIndex(nav_index);
const mod = zcu.fileByIndex(file_scope).mod.?;
@@ -4568,7 +4582,7 @@ pub const NavGen = struct {
line_number,
try o.lowerDebugType(ty),
variable_index,
.{ .local = !is_extern },
.{ .local = linkage == .internal },
);
const debug_expression = try o.builder.debugExpression(&.{});
@@ -4583,38 +4597,47 @@ pub const NavGen = struct {
}
}
if (is_extern) {
const global_index = o.nav_map.get(nav_index).?;
switch (linkage) {
.internal => {},
.strong, .weak => {
const global_index = o.nav_map.get(nav_index).?;
const decl_name = decl_name: {
if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
if (lib_name.toSlice(ip)) |lib_name_slice| {
if (!std.mem.eql(u8, lib_name_slice, "c")) {
break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
const decl_name = decl_name: {
if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
if (lib_name.toSlice(ip)) |lib_name_slice| {
if (!std.mem.eql(u8, lib_name_slice, "c")) {
break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
}
}
}
break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
};
if (o.builder.getGlobal(decl_name)) |other_global| {
if (other_global != global_index) {
// Another global already has this name; just use it in place of this global.
try global_index.replace(other_global, &o.builder);
return;
}
}
break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
};
if (o.builder.getGlobal(decl_name)) |other_global| {
if (other_global != global_index) {
// Another global already has this name; just use it in place of this global.
try global_index.replace(other_global, &o.builder);
return;
try global_index.rename(decl_name, &o.builder);
global_index.setUnnamedAddr(.default, &o.builder);
if (is_dll_import) {
global_index.setDllStorageClass(.dllimport, &o.builder);
} else if (zcu.comp.config.dll_export_fns) {
global_index.setDllStorageClass(.default, &o.builder);
}
}
try global_index.rename(decl_name, &o.builder);
global_index.setLinkage(.external, &o.builder);
global_index.setUnnamedAddr(.default, &o.builder);
if (is_dll_import) {
global_index.setDllStorageClass(.dllimport, &o.builder);
} else if (zcu.comp.config.dll_export_fns) {
global_index.setDllStorageClass(.default, &o.builder);
}
if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
global_index.setLinkage(switch (linkage) {
.internal => unreachable,
.strong => .external,
.weak => .extern_weak,
.link_once => unreachable,
}, &o.builder);
global_index.setVisibility(visibility, &o.builder);
},
.link_once => unreachable,
}
}
};
@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
.vector_store_elem => try self.airVectorStoreElem(inst),
.tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
.runtime_nav_ptr => try self.airRuntimeNavPtr(inst),
.inferred_alloc, .inferred_alloc_comptime => unreachable,
@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
return .none;
}
fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = fg.ng.object;
const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);