From 66a7c09defec1fe4f4f1751e36acc412e3ca8ea9 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Sun, 20 Oct 2024 01:44:25 -0700 Subject: [PATCH] link: use target to determine risc-v eflag validity --- src/link/Elf.zig | 10 ++--- src/link/Elf/Object.zig | 99 +++++++++++++++++++++++++++++------------ src/link/riscv.zig | 16 ++++--- 3 files changed, 82 insertions(+), 43 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 8f39d3412f..a068ac6cdc 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -113,8 +113,6 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty, merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, comment_merge_section_index: ?Merge.Section.Index = null, -first_eflags: ?elf.Word = null, - /// `--verbose-link` output. /// Initialized on creation, appended to as inputs are added, printed during `flush`. dump_argv_list: std.ArrayListUnmanaged([]const u8), @@ -791,7 +789,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { .res => unreachable, .dso_exact => @panic("TODO"), .object => |obj| try parseObject(self, obj), - .archive => |obj| try parseArchive(gpa, diags, &self.file_handles, &self.files, &self.first_eflags, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib), + .archive => |obj| try parseArchive(gpa, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib), .dso => |dso| try parseDso(gpa, diags, dso, &self.shared_objects, &self.files, target), } } @@ -1124,7 +1122,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void { const gpa = self.base.comp.gpa; const diags = &self.base.comp.link_diags; - const first_eflags = &self.first_eflags; const target = self.base.comp.root_mod.resolved_target.result; const debug_fmt_strip = self.base.comp.config.debug_format == .strip; const default_sym_version = self.default_sym_version; @@ -1145,7 +1142,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void { try self.objects.append(gpa, index); const object = self.file(index).?.object; - try object.parseCommon(gpa, diags, obj.path, handle, target, first_eflags); + try object.parseCommon(gpa, diags, obj.path, handle, target); if (!self.base.isStaticLib()) { try object.parse(gpa, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version); } @@ -1156,7 +1153,6 @@ fn parseArchive( diags: *Diags, file_handles: *std.ArrayListUnmanaged(File.Handle), files: *std.MultiArrayList(File.Entry), - first_eflags: *?elf.Word, target: std.Target, debug_fmt_strip: bool, default_sym_version: elf.Versym, @@ -1179,7 +1175,7 @@ fn parseArchive( const object = &files.items(.data)[index].object; object.index = index; object.alive = init_alive; - try object.parseCommon(gpa, diags, obj.path, obj.file, target, first_eflags); + try object.parseCommon(gpa, diags, obj.path, obj.file, target); if (!is_static_lib) try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); try objects.append(gpa, index); diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index 688e51f3f1..65a62ff1a6 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -99,7 +99,6 @@ pub fn parseCommon( path: Path, handle: fs.File, target: std.Target, - first_eflags: *?elf.Word, ) !void { const offset = if (self.archive) |ar| ar.offset else 0; const file_size = (try handle.stat()).size; @@ -114,7 +113,7 @@ pub fn parseCommon( @tagName(self.header.?.e_machine), }); } - try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags); + try validateEFlags(diags, path, target, self.header.?.e_flags); if (self.header.?.e_shnum == 0) return; @@ -180,39 +179,81 @@ pub fn parseCommon( } } -fn validateEFlags( +pub fn validateEFlags( diags: *Diags, path: Path, target: std.Target, e_flags: elf.Word, - first_eflags: *?elf.Word, -) error{LinkFailure}!void { - if (first_eflags.*) |*self_eflags| { - switch (target.cpu.arch) { - .riscv64 => { - if (e_flags != self_eflags.*) { - const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags); - const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags); +) !void { + switch (target.cpu.arch) { + .riscv64 => { + const features = target.cpu.features; + const flags: riscv.Eflags = @bitCast(e_flags); + var any_errors: bool = false; - self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc; - self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso; + // For an input object to target an ABI that the target CPU doesn't have enabled + // is invalid, and will throw an error. - var any_errors: bool = false; - if (self_riscv_eflags.fabi != riscv_eflags.fabi) { - any_errors = true; - diags.addParseError(path, "cannot link object files with different float-point ABIs", .{}); - } - if (self_riscv_eflags.rve != riscv_eflags.rve) { - any_errors = true; - diags.addParseError(path, "cannot link object files with different RVEs", .{}); - } - if (any_errors) return error.LinkFailure; - } - }, - else => {}, - } - } else { - first_eflags.* = e_flags; + // Invalid when + // 1. The input uses C and we do not. + if (flags.rvc and !std.Target.riscv.featureSetHas(features, .c)) { + any_errors = true; + diags.addParseError( + path, + "cannot link object file targeting the C feature without having the C feature enabled", + .{}, + ); + } + + // Invalid when + // 1. We use E and the input does not. + // 2. The input uses E and we do not. + if (std.Target.riscv.featureSetHas(features, .e) != flags.rve) { + any_errors = true; + diags.addParseError( + path, + "{s}", + .{ + if (flags.rve) + "cannot link object file targeting the E feature without having the E feature enabled" + else + "cannot link object file not targeting the E feature while having the E feature enabled", + }, + ); + } + + // Invalid when + // 1. We use total store order and the input does not. + // 2. The input uses total store order and we do not. + if (flags.tso != std.Target.riscv.featureSetHas(features, .ztso)) { + any_errors = true; + diags.addParseError( + path, + "cannot link object file targeting the TSO memory model without having the ztso feature enabled", + .{}, + ); + } + + const fabi: riscv.Eflags.FloatAbi = + if (std.Target.riscv.featureSetHas(features, .d)) + .double + else if (std.Target.riscv.featureSetHas(features, .f)) + .single + else + .soft; + + if (flags.fabi != fabi) { + any_errors = true; + diags.addParseError( + path, + "cannot link object file targeting a different floating-point ABI. targeting {s}, found {s}", + .{ @tagName(fabi), @tagName(flags.fabi) }, + ); + } + + if (any_errors) return error.LinkFailure; + }, + else => {}, } } diff --git a/src/link/riscv.zig b/src/link/riscv.zig index 7c0282ef3b..106fd1a817 100644 --- a/src/link/riscv.zig +++ b/src/link/riscv.zig @@ -70,18 +70,20 @@ fn bitSlice( return @truncate((value >> low) & (1 << (high - low + 1)) - 1); } -pub const RiscvEflags = packed struct(u32) { +pub const Eflags = packed struct(u32) { rvc: bool, - fabi: enum(u2) { + fabi: FloatAbi, + rve: bool, + tso: bool, + _reserved: u19 = 0, + _unused: u8 = 0, + + pub const FloatAbi = enum(u2) { soft = 0b00, single = 0b01, double = 0b10, quad = 0b11, - }, - rve: bool, - tso: bool, - _reserved: u19, - _unused: u8, + }; }; const mem = std.mem;