authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-10-20 01:44:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-11-22 19:34:47-05:00
log66a7c09defec1fe4f4f1751e36acc412e3ca8ea9
tree6ceb71191d103f008418111f749aedb55faf8e59
parentb2c62bcbf64a3ffa2af6a8e441f1c12e10c598ec

link: use target to determine risc-v eflag validity


3 files changed, 84 insertions(+), 45 deletions(-)

src/link/Elf.zig+3-7
......@@ -113,8 +113,6 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,
113113merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,
114114comment_merge_section_index: ?Merge.Section.Index = null,
115115
116first_eflags: ?elf.Word = null,
117
118116/// `--verbose-link` output.
119117/// Initialized on creation, appended to as inputs are added, printed during `flush`.
120118dump_argv_list: std.ArrayListUnmanaged([]const u8),
......@@ -791,7 +789,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
791789 .res => unreachable,
792790 .dso_exact => @panic("TODO"),
793791 .object => |obj| try parseObject(self, obj),
794 .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),
792 .archive => |obj| try parseArchive(gpa, diags, &self.file_handles, &self.files, target, debug_fmt_strip, default_sym_version, &self.objects, obj, is_static_lib),
795793 .dso => |dso| try parseDso(gpa, diags, dso, &self.shared_objects, &self.files, target),
796794 }
797795}
......@@ -1124,7 +1122,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
11241122
11251123 const gpa = self.base.comp.gpa;
11261124 const diags = &self.base.comp.link_diags;
1127 const first_eflags = &self.first_eflags;
11281125 const target = self.base.comp.root_mod.resolved_target.result;
11291126 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
11301127 const default_sym_version = self.default_sym_version;
......@@ -1145,7 +1142,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
11451142 try self.objects.append(gpa, index);
11461143
11471144 const object = self.file(index).?.object;
1148 try object.parseCommon(gpa, diags, obj.path, handle, target, first_eflags);
1145 try object.parseCommon(gpa, diags, obj.path, handle, target);
11491146 if (!self.base.isStaticLib()) {
11501147 try object.parse(gpa, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version);
11511148 }
......@@ -1156,7 +1153,6 @@ fn parseArchive(
11561153 diags: *Diags,
11571154 file_handles: *std.ArrayListUnmanaged(File.Handle),
11581155 files: *std.MultiArrayList(File.Entry),
1159 first_eflags: *?elf.Word,
11601156 target: std.Target,
11611157 debug_fmt_strip: bool,
11621158 default_sym_version: elf.Versym,
......@@ -1179,7 +1175,7 @@ fn parseArchive(
11791175 const object = &files.items(.data)[index].object;
11801176 object.index = index;
11811177 object.alive = init_alive;
1182 try object.parseCommon(gpa, diags, obj.path, obj.file, target, first_eflags);
1178 try object.parseCommon(gpa, diags, obj.path, obj.file, target);
11831179 if (!is_static_lib)
11841180 try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version);
11851181 try objects.append(gpa, index);
src/link/Elf/Object.zig+72-31
......@@ -99,7 +99,6 @@ pub fn parseCommon(
9999 path: Path,
100100 handle: fs.File,
101101 target: std.Target,
102 first_eflags: *?elf.Word,
103102) !void {
104103 const offset = if (self.archive) |ar| ar.offset else 0;
105104 const file_size = (try handle.stat()).size;
......@@ -114,7 +113,7 @@ pub fn parseCommon(
114113 @tagName(self.header.?.e_machine),
115114 });
116115 }
117 try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags);
116 try validateEFlags(diags, path, target, self.header.?.e_flags);
118117
119118 if (self.header.?.e_shnum == 0) return;
120119
......@@ -180,39 +179,81 @@ pub fn parseCommon(
180179 }
181180}
182181
183fn validateEFlags(
182pub fn validateEFlags(
184183 diags: *Diags,
185184 path: Path,
186185 target: std.Target,
187186 e_flags: elf.Word,
188 first_eflags: *?elf.Word,
189) error{LinkFailure}!void {
190 if (first_eflags.*) |*self_eflags| {
191 switch (target.cpu.arch) {
192 .riscv64 => {
193 if (e_flags != self_eflags.*) {
194 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);
195 const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);
196
197 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
198 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
199
200 var any_errors: bool = false;
201 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
202 any_errors = true;
203 diags.addParseError(path, "cannot link object files with different float-point ABIs", .{});
204 }
205 if (self_riscv_eflags.rve != riscv_eflags.rve) {
206 any_errors = true;
207 diags.addParseError(path, "cannot link object files with different RVEs", .{});
208 }
209 if (any_errors) return error.LinkFailure;
210 }
211 },
212 else => {},
213 }
214 } else {
215 first_eflags.* = e_flags;
187) !void {
188 switch (target.cpu.arch) {
189 .riscv64 => {
190 const features = target.cpu.features;
191 const flags: riscv.Eflags = @bitCast(e_flags);
192 var any_errors: bool = false;
193
194 // For an input object to target an ABI that the target CPU doesn't have enabled
195 // is invalid, and will throw an error.
196
197 // Invalid when
198 // 1. The input uses C and we do not.
199 if (flags.rvc and !std.Target.riscv.featureSetHas(features, .c)) {
200 any_errors = true;
201 diags.addParseError(
202 path,
203 "cannot link object file targeting the C feature without having the C feature enabled",
204 .{},
205 );
206 }
207
208 // Invalid when
209 // 1. We use E and the input does not.
210 // 2. The input uses E and we do not.
211 if (std.Target.riscv.featureSetHas(features, .e) != flags.rve) {
212 any_errors = true;
213 diags.addParseError(
214 path,
215 "{s}",
216 .{
217 if (flags.rve)
218 "cannot link object file targeting the E feature without having the E feature enabled"
219 else
220 "cannot link object file not targeting the E feature while having the E feature enabled",
221 },
222 );
223 }
224
225 // Invalid when
226 // 1. We use total store order and the input does not.
227 // 2. The input uses total store order and we do not.
228 if (flags.tso != std.Target.riscv.featureSetHas(features, .ztso)) {
229 any_errors = true;
230 diags.addParseError(
231 path,
232 "cannot link object file targeting the TSO memory model without having the ztso feature enabled",
233 .{},
234 );
235 }
236
237 const fabi: riscv.Eflags.FloatAbi =
238 if (std.Target.riscv.featureSetHas(features, .d))
239 .double
240 else if (std.Target.riscv.featureSetHas(features, .f))
241 .single
242 else
243 .soft;
244
245 if (flags.fabi != fabi) {
246 any_errors = true;
247 diags.addParseError(
248 path,
249 "cannot link object file targeting a different floating-point ABI. targeting {s}, found {s}",
250 .{ @tagName(fabi), @tagName(flags.fabi) },
251 );
252 }
253
254 if (any_errors) return error.LinkFailure;
255 },
256 else => {},
216257 }
217258}
218259
src/link/riscv.zig+9-7
......@@ -70,18 +70,20 @@ fn bitSlice(
7070 return @truncate((value >> low) & (1 << (high - low + 1)) - 1);
7171}
7272
73pub const RiscvEflags = packed struct(u32) {
73pub const Eflags = packed struct(u32) {
7474 rvc: bool,
75 fabi: enum(u2) {
75 fabi: FloatAbi,
76 rve: bool,
77 tso: bool,
78 _reserved: u19 = 0,
79 _unused: u8 = 0,
80
81 pub const FloatAbi = enum(u2) {
7682 soft = 0b00,
7783 single = 0b01,
7884 double = 0b10,
7985 quad = 0b11,
80 },
81 rve: bool,
82 tso: bool,
83 _reserved: u19,
84 _unused: u8,
86 };
8587};
8688
8789const mem = std.mem;