Skip to content

Commit

Permalink
Merge pull request #22067 from alexrp/pie-tests
Browse files Browse the repository at this point in the history
Add PIC/PIE tests and fix some bugs + some improvements to the test harness
  • Loading branch information
alexrp authored Nov 28, 2024
2 parents 6cf01a6 + 5beb5f2 commit 8594f17
Show file tree
Hide file tree
Showing 28 changed files with 267 additions and 57 deletions.
9 changes: 7 additions & 2 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ pub fn build(b: *std.Build) !void {
test_step.dependOn(check_fmt);

const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
try tests.addCases(b, test_cases_step, test_filters, target, .{
try tests.addCases(b, test_cases_step, test_filters, test_target_filters, target, .{
.skip_translate_c = skip_translate_c,
.skip_run_translated_c = skip_run_translated_c,
}, .{
Expand Down Expand Up @@ -541,13 +541,18 @@ pub fn build(b: *std.Build) !void {
enable_ios_sdk,
enable_symlinks_windows,
));
test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release));
test_step.dependOn(tests.addCAbiTests(b, .{
.test_target_filters = test_target_filters,
.skip_non_native = skip_non_native,
.skip_release = skip_release,
}));
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes));
test_step.dependOn(tests.addCliTests(b));
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
if (tests.addDebuggerTests(b, .{
.test_filters = test_filters,
.test_target_filters = test_target_filters,
.gdb = b.option([]const u8, "gdb", "path to gdb binary"),
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
.optimize_modes = optimization_modes,
Expand Down
5 changes: 5 additions & 0 deletions lib/std/Build/Cache.zig
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,11 @@ pub const HashHelper = struct {
},
std.Target.Os.TaggedVersionRange => {
switch (x) {
.hurd => |hurd| {
hh.add(hurd.range.min);
hh.add(hurd.range.max);
hh.add(hurd.glibc);
},
.linux => |linux| {
hh.add(linux.range.min);
hh.add(linux.range.max);
Expand Down
43 changes: 38 additions & 5 deletions lib/std/Target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ pub const Os = struct {
.hermit,

.aix,
.hurd,
.rtems,
.zos,

Expand Down Expand Up @@ -218,6 +217,7 @@ pub const Os = struct {
.vulkan,
=> .semver,

.hurd => .hurd,
.linux => .linux,

.windows => .windows,
Expand Down Expand Up @@ -356,6 +356,21 @@ pub const Os = struct {
}
};

pub const HurdVersionRange = struct {
range: std.SemanticVersion.Range,
glibc: std.SemanticVersion,

pub inline fn includesVersion(range: HurdVersionRange, ver: std.SemanticVersion) bool {
return range.range.includesVersion(ver);
}

/// Checks if system is guaranteed to be at least `version` or older than `version`.
/// Returns `null` if a runtime check is required.
pub inline fn isAtLeast(range: HurdVersionRange, ver: std.SemanticVersion) ?bool {
return range.range.isAtLeast(ver);
}
};

pub const LinuxVersionRange = struct {
range: std.SemanticVersion.Range,
glibc: std.SemanticVersion,
Expand Down Expand Up @@ -400,6 +415,7 @@ pub const Os = struct {
pub const VersionRange = union {
none: void,
semver: std.SemanticVersion.Range,
hurd: HurdVersionRange,
linux: LinuxVersionRange,
windows: WindowsVersion.Range,

Expand Down Expand Up @@ -456,9 +472,12 @@ pub const Os = struct {
},
},
.hurd => .{
.semver = .{
.min = .{ .major = 0, .minor = 9, .patch = 0 },
.max = .{ .major = 0, .minor = 9, .patch = 0 },
.hurd = .{
.range = .{
.min = .{ .major = 0, .minor = 9, .patch = 0 },
.max = .{ .major = 0, .minor = 9, .patch = 0 },
},
.glibc = .{ .major = 2, .minor = 28, .patch = 0 },
},
},
.linux => .{
Expand Down Expand Up @@ -632,8 +651,17 @@ pub const Os = struct {
pub const TaggedVersionRange = union(enum) {
none: void,
semver: std.SemanticVersion.Range,
hurd: HurdVersionRange,
linux: LinuxVersionRange,
windows: WindowsVersion.Range,

pub fn gnuLibCVersion(range: TaggedVersionRange) ?std.SemanticVersion {
return switch (range) {
.none, .semver, .windows => null,
.hurd => |h| h.glibc,
.linux => |l| l.glibc,
};
}
};

/// Provides a tagged union. `Target` does not store the tag because it is
Expand All @@ -642,6 +670,7 @@ pub const Os = struct {
return switch (os.tag.versionRangeTag()) {
.none => .{ .none = {} },
.semver => .{ .semver = os.version_range.semver },
.hurd => .{ .hurd = os.version_range.hurd },
.linux => .{ .linux = os.version_range.linux },
.windows => .{ .windows = os.version_range.windows },
};
Expand All @@ -651,12 +680,13 @@ pub const Os = struct {
/// Returns `null` if a runtime check is required.
pub inline fn isAtLeast(os: Os, comptime tag: Tag, ver: switch (tag.versionRangeTag()) {
.none => void,
.semver, .linux => std.SemanticVersion,
.semver, .hurd, .linux => std.SemanticVersion,
.windows => WindowsVersion,
}) ?bool {
return if (os.tag != tag) false else switch (tag.versionRangeTag()) {
.none => true,
inline .semver,
.hurd,
.linux,
.windows,
=> |field| @field(os.version_range, @tagName(field)).isAtLeast(ver),
Expand Down Expand Up @@ -832,6 +862,9 @@ pub const Abi = enum {
.mips,
.mipsel,
=> .musleabi,
.mips64,
.mips64el,
=> .muslabi64,
else => .musl,
},
.rtems => switch (arch) {
Expand Down
10 changes: 5 additions & 5 deletions lib/std/Target/Query.zig
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub fn fromTarget(target: Target) Query {
.os_version_min = undefined,
.os_version_max = undefined,
.abi = target.abi,
.glibc_version = if (target.isGnuLibC()) target.os.version_range.linux.glibc else null,
.glibc_version = target.os.versionRange().gnuLibCVersion(),
.android_api_level = if (target.abi.isAndroid()) target.os.version_range.linux.android else null,
};
result.updateOsVersionRange(target.os);
Expand Down Expand Up @@ -132,9 +132,9 @@ fn updateOsVersionRange(self: *Query, os: Target.Os) void {
.{ .semver = os.version_range.semver.min },
.{ .semver = os.version_range.semver.max },
},
.linux => .{
.{ .semver = os.version_range.linux.range.min },
.{ .semver = os.version_range.linux.range.max },
inline .hurd, .linux => |t| .{
.{ .semver = @field(os.version_range, @tagName(t)).range.min },
.{ .semver = @field(os.version_range, @tagName(t)).range.max },
},
.windows => .{
.{ .windows = os.version_range.windows.min },
Expand Down Expand Up @@ -544,7 +544,7 @@ fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !
const version_text = it.rest();
if (version_text.len > 0) switch (tag.versionRangeTag()) {
.none => return error.InvalidOperatingSystemVersion,
.semver, .linux => range: {
.semver, .hurd, .linux => range: {
var range_it = mem.splitSequence(u8, version_text, "...");
result.os_version_min = .{
.semver = parseVersion(range_it.first()) catch |err| switch (err) {
Expand Down
5 changes: 2 additions & 3 deletions lib/std/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ pub inline fn versionCheck(comptime version: std.SemanticVersion) bool {
if (!builtin.link_libc) break :blk false;
if (native_abi.isMusl()) break :blk true;
if (builtin.target.isGnuLibC()) {
const ver = builtin.os.version_range.linux.glibc;
const order = ver.order(version);
break :blk switch (order) {
const ver = builtin.os.versionRange().gnuLibCVersion().?;
break :blk switch (ver.order(version)) {
.gt, .eq => true,
.lt => false,
};
Expand Down
2 changes: 1 addition & 1 deletion lib/std/os/linux/pie.zig
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
\\ .hidden _DYNAMIC
\\ larl %[ret], 1f
\\ ag %[ret], 0(%[ret])
\\ b 2f
\\ jg 2f
\\ 1: .quad _DYNAMIC - .
\\ 2:
: [ret] "=r" (-> [*]elf.Dyn),
Expand Down
13 changes: 8 additions & 5 deletions lib/std/zig/system.zig
Original file line number Diff line number Diff line change
Expand Up @@ -311,24 +311,27 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {

if (query.os_version_min) |min| switch (min) {
.none => {},
.semver => |semver| switch (os.tag) {
.linux => os.version_range.linux.range.min = semver,
.semver => |semver| switch (os.tag.versionRangeTag()) {
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).range.min = semver,
else => os.version_range.semver.min = semver,
},
.windows => |win_ver| os.version_range.windows.min = win_ver,
};

if (query.os_version_max) |max| switch (max) {
.none => {},
.semver => |semver| switch (os.tag) {
.linux => os.version_range.linux.range.max = semver,
.semver => |semver| switch (os.tag.versionRangeTag()) {
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).range.max = semver,
else => os.version_range.semver.max = semver,
},
.windows => |win_ver| os.version_range.windows.max = win_ver,
};

if (query.glibc_version) |glibc| {
os.version_range.linux.glibc = glibc;
switch (os.tag.versionRangeTag()) {
inline .hurd, .linux => |t| @field(os.version_range, @tagName(t)).glibc = glibc,
else => {},
}
}

if (query.android_api_level) |android| {
Expand Down
4 changes: 2 additions & 2 deletions lib/std/zig/target.zig
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ pub fn canBuildLibC(target: std.Target) bool {
const ver = target.os.version_range.semver;
return ver.min.order(libc.os_ver.?) != .lt;
}
// Ensure glibc (aka *-linux-gnu) version is supported
// Ensure glibc (aka *-(linux,hurd)-gnu) version is supported
if (target.isGnuLibC()) {
const min_glibc_ver = libc.glibc_min orelse return true;
const target_glibc_ver = target.os.version_range.linux.glibc;
const target_glibc_ver = target.os.versionRange().gnuLibCVersion().?;
return target_glibc_ver.order(min_glibc_ver) != .lt;
}
return true;
Expand Down
34 changes: 34 additions & 0 deletions src/Builtin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,40 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {

linux.android,
}),
.hurd => |hurd| try buffer.writer().print(
\\ .hurd = .{{
\\ .range = .{{
\\ .min = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ .max = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }},
\\ .glibc = .{{
\\ .major = {},
\\ .minor = {},
\\ .patch = {},
\\ }},
\\ }}}},
\\
, .{
hurd.range.min.major,
hurd.range.min.minor,
hurd.range.min.patch,

hurd.range.max.major,
hurd.range.max.minor,
hurd.range.max.patch,

hurd.glibc.major,
hurd.glibc.minor,
hurd.glibc.patch,
}),
.windows => |windows| try buffer.writer().print(
\\ .windows = .{{
\\ .min = {c},
Expand Down
2 changes: 1 addition & 1 deletion src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5315,7 +5315,7 @@ pub fn addCCArgs(

if (comp.config.link_libc) {
if (target.isGnuLibC()) {
const target_version = target.os.version_range.linux.glibc;
const target_version = target.os.versionRange().gnuLibCVersion().?;
const glibc_minor_define = try std.fmt.allocPrint(arena, "-D__GLIBC_MINOR__={d}", .{
target_version.minor,
});
Expand Down
16 changes: 10 additions & 6 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
ver.min.minor,
ver.min.patch,
}),
.linux => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
inline .linux, .hurd => |ver| try llvm_triple.writer().print("{d}.{d}.{d}", .{
ver.range.min.major,
ver.range.min.minor,
ver.range.min.patch,
Expand Down Expand Up @@ -290,11 +290,15 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![]const u8 {
.semver,
.windows,
=> {},
.linux => |ver| if (target.abi.isGnu()) try llvm_triple.writer().print("{d}.{d}.{d}", .{
ver.glibc.major,
ver.glibc.minor,
ver.glibc.patch,
}) else if (target.abi.isAndroid()) try llvm_triple.writer().print("{d}", .{ver.android}),
inline .hurd, .linux => |ver| if (target.abi.isGnu()) {
try llvm_triple.writer().print("{d}.{d}.{d}", .{
ver.glibc.major,
ver.glibc.minor,
ver.glibc.patch,
});
} else if (@TypeOf(ver) == std.Target.Os.LinuxVersionRange and target.abi.isAndroid()) {
try llvm_triple.writer().print("{d}", .{ver.android});
},
}

return llvm_triple.toOwnedSlice();
Expand Down
6 changes: 3 additions & 3 deletions src/glibc.zig
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
const arena = arena_allocator.allocator();

const target = comp.root_mod.resolved_target.result;
const target_ver = target.os.version_range.linux.glibc;
const target_ver = target.os.versionRange().gnuLibCVersion().?;
const nonshared_stat = target_ver.order(.{ .major = 2, .minor = 32, .patch = 0 }) != .gt;
const start_old_init_fini = target_ver.order(.{ .major = 2, .minor = 33, .patch = 0 }) != .gt;

Expand Down Expand Up @@ -750,7 +750,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
const arena = arena_allocator.allocator();

const target = comp.getTarget();
const target_version = target.os.version_range.linux.glibc;
const target_version = target.os.versionRange().gnuLibCVersion().?;

// Use the global cache directory.
var cache: Cache = .{
Expand Down Expand Up @@ -1218,7 +1218,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi
}

fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
const target_version = comp.getTarget().os.version_range.linux.glibc;
const target_version = comp.getTarget().os.versionRange().gnuLibCVersion().?;

assert(comp.glibc_so_files == null);
comp.glibc_so_files = so_files;
Expand Down
6 changes: 3 additions & 3 deletions src/libcxx.zig
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ pub fn buildLibCXX(comp: *Compilation, prog_node: std.Progress.Node) BuildError!

if (target.isGnuLibC()) {
// glibc 2.16 introduced aligned_alloc
if (target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
if (target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
try cflags.append("-D_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION");
}
}
Expand Down Expand Up @@ -477,7 +477,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
}
try cflags.append("-D_LIBCXXABI_HAS_NO_THREADS");
} else if (target.abi.isGnu()) {
if (target.os.tag != .linux or !(target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 18, .patch = 0 }) == .lt))
if (target.os.tag != .linux or !(target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 18, .patch = 0 }) == .lt))
try cflags.append("-DHAVE___CXA_THREAD_ATEXIT_IMPL");
}

Expand All @@ -500,7 +500,7 @@ pub fn buildLibCXXABI(comp: *Compilation, prog_node: std.Progress.Node) BuildErr

if (target.isGnuLibC()) {
// glibc 2.16 introduced aligned_alloc
if (target.os.version_range.linux.glibc.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
if (target.os.versionRange().gnuLibCVersion().?.order(.{ .major = 2, .minor = 16, .patch = 0 }) == .lt) {
try cflags.append("-D_LIBCPP_HAS_NO_LIBRARY_ALIGNED_ALLOCATION");
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/link/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2013,7 +2013,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
} else if (target.isGnuLibC()) {
for (glibc.libs) |lib| {
if (lib.removed_in) |rem_in| {
if (target.os.version_range.linux.glibc.order(rem_in) != .lt) continue;
if (target.os.versionRange().gnuLibCVersion().?.order(rem_in) != .lt) continue;
}

const lib_path = try std.fmt.allocPrint(arena, "{}{c}lib{s}.so.{d}", .{
Expand Down
1 change: 1 addition & 0 deletions test/cases/inherit_want_safety.zig
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,4 @@ pub export fn entry() usize {

// compile
// output_mode=Obj
// emit_bin=false
Loading

0 comments on commit 8594f17

Please sign in to comment.