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,...@@ -113,8 +113,6 @@ thunks: std.ArrayListUnmanaged(Thunk) = .empty,
113merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,113merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty,
114comment_merge_section_index: ?Merge.Section.Index = null,114comment_merge_section_index: ?Merge.Section.Index = null,
115115
116first_eflags: ?elf.Word = null,
117
118/// `--verbose-link` output.116/// `--verbose-link` output.
119/// Initialized on creation, appended to as inputs are added, printed during `flush`.117/// Initialized on creation, appended to as inputs are added, printed during `flush`.
120dump_argv_list: std.ArrayListUnmanaged([]const u8),118dump_argv_list: std.ArrayListUnmanaged([]const u8),
...@@ -791,7 +789,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {...@@ -791,7 +789,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void {
791 .res => unreachable,789 .res => unreachable,
792 .dso_exact => @panic("TODO"),790 .dso_exact => @panic("TODO"),
793 .object => |obj| try parseObject(self, obj),791 .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),
795 .dso => |dso| try parseDso(gpa, diags, dso, &self.shared_objects, &self.files, target),793 .dso => |dso| try parseDso(gpa, diags, dso, &self.shared_objects, &self.files, target),
796 }794 }
797}795}
...@@ -1124,7 +1122,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {...@@ -1124,7 +1122,6 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
11241122
1125 const gpa = self.base.comp.gpa;1123 const gpa = self.base.comp.gpa;
1126 const diags = &self.base.comp.link_diags;1124 const diags = &self.base.comp.link_diags;
1127 const first_eflags = &self.first_eflags;
1128 const target = self.base.comp.root_mod.resolved_target.result;1125 const target = self.base.comp.root_mod.resolved_target.result;
1129 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;1126 const debug_fmt_strip = self.base.comp.config.debug_format == .strip;
1130 const default_sym_version = self.default_sym_version;1127 const default_sym_version = self.default_sym_version;
...@@ -1145,7 +1142,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {...@@ -1145,7 +1142,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void {
1145 try self.objects.append(gpa, index);1142 try self.objects.append(gpa, index);
11461143
1147 const object = self.file(index).?.object;1144 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);
1149 if (!self.base.isStaticLib()) {1146 if (!self.base.isStaticLib()) {
1150 try object.parse(gpa, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version);1147 try object.parse(gpa, diags, obj.path, handle, target, debug_fmt_strip, default_sym_version);
1151 }1148 }
...@@ -1156,7 +1153,6 @@ fn parseArchive(...@@ -1156,7 +1153,6 @@ fn parseArchive(
1156 diags: *Diags,1153 diags: *Diags,
1157 file_handles: *std.ArrayListUnmanaged(File.Handle),1154 file_handles: *std.ArrayListUnmanaged(File.Handle),
1158 files: *std.MultiArrayList(File.Entry),1155 files: *std.MultiArrayList(File.Entry),
1159 first_eflags: *?elf.Word,
1160 target: std.Target,1156 target: std.Target,
1161 debug_fmt_strip: bool,1157 debug_fmt_strip: bool,
1162 default_sym_version: elf.Versym,1158 default_sym_version: elf.Versym,
...@@ -1179,7 +1175,7 @@ fn parseArchive(...@@ -1179,7 +1175,7 @@ fn parseArchive(
1179 const object = &files.items(.data)[index].object;1175 const object = &files.items(.data)[index].object;
1180 object.index = index;1176 object.index = index;
1181 object.alive = init_alive;1177 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);
1183 if (!is_static_lib)1179 if (!is_static_lib)
1184 try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version);1180 try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version);
1185 try objects.append(gpa, index);1181 try objects.append(gpa, index);
src/link/Elf/Object.zig+72-31
...@@ -99,7 +99,6 @@ pub fn parseCommon(...@@ -99,7 +99,6 @@ pub fn parseCommon(
99 path: Path,99 path: Path,
100 handle: fs.File,100 handle: fs.File,
101 target: std.Target,101 target: std.Target,
102 first_eflags: *?elf.Word,
103) !void {102) !void {
104 const offset = if (self.archive) |ar| ar.offset else 0;103 const offset = if (self.archive) |ar| ar.offset else 0;
105 const file_size = (try handle.stat()).size;104 const file_size = (try handle.stat()).size;
...@@ -114,7 +113,7 @@ pub fn parseCommon(...@@ -114,7 +113,7 @@ pub fn parseCommon(
114 @tagName(self.header.?.e_machine),113 @tagName(self.header.?.e_machine),
115 });114 });
116 }115 }
117 try validateEFlags(diags, path, target, self.header.?.e_flags, first_eflags);116 try validateEFlags(diags, path, target, self.header.?.e_flags);
118117
119 if (self.header.?.e_shnum == 0) return;118 if (self.header.?.e_shnum == 0) return;
120119
...@@ -180,39 +179,81 @@ pub fn parseCommon(...@@ -180,39 +179,81 @@ pub fn parseCommon(
180 }179 }
181}180}
182181
183fn validateEFlags(182pub fn validateEFlags(
184 diags: *Diags,183 diags: *Diags,
185 path: Path,184 path: Path,
186 target: std.Target,185 target: std.Target,
187 e_flags: elf.Word,186 e_flags: elf.Word,
188 first_eflags: *?elf.Word,187) !void {
189) error{LinkFailure}!void {188 switch (target.cpu.arch) {
190 if (first_eflags.*) |*self_eflags| {189 .riscv64 => {
191 switch (target.cpu.arch) {190 const features = target.cpu.features;
192 .riscv64 => {191 const flags: riscv.Eflags = @bitCast(e_flags);
193 if (e_flags != self_eflags.*) {192 var any_errors: bool = false;
194 const riscv_eflags: riscv.RiscvEflags = @bitCast(e_flags);193
195 const self_riscv_eflags: *riscv.RiscvEflags = @ptrCast(self_eflags);194 // For an input object to target an ABI that the target CPU doesn't have enabled
196195 // is invalid, and will throw an error.
197 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;196
198 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;197 // Invalid when
199198 // 1. The input uses C and we do not.
200 var any_errors: bool = false;199 if (flags.rvc and !std.Target.riscv.featureSetHas(features, .c)) {
201 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {200 any_errors = true;
202 any_errors = true;201 diags.addParseError(
203 diags.addParseError(path, "cannot link object files with different float-point ABIs", .{});202 path,
204 }203 "cannot link object file targeting the C feature without having the C feature enabled",
205 if (self_riscv_eflags.rve != riscv_eflags.rve) {204 .{},
206 any_errors = true;205 );
207 diags.addParseError(path, "cannot link object files with different RVEs", .{});206 }
208 }207
209 if (any_errors) return error.LinkFailure;208 // Invalid when
210 }209 // 1. We use E and the input does not.
211 },210 // 2. The input uses E and we do not.
212 else => {},211 if (std.Target.riscv.featureSetHas(features, .e) != flags.rve) {
213 }212 any_errors = true;
214 } else {213 diags.addParseError(
215 first_eflags.* = e_flags;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 => {},
216 }257 }
217}258}
218259
src/link/riscv.zig+9-7
...@@ -70,18 +70,20 @@ fn bitSlice(...@@ -70,18 +70,20 @@ fn bitSlice(
70 return @truncate((value >> low) & (1 << (high - low + 1)) - 1);70 return @truncate((value >> low) & (1 << (high - low + 1)) - 1);
71}71}
7272
73pub const RiscvEflags = packed struct(u32) {73pub const Eflags = packed struct(u32) {
74 rvc: bool,74 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) {
76 soft = 0b00,82 soft = 0b00,
77 single = 0b01,83 single = 0b01,
78 double = 0b10,84 double = 0b10,
79 quad = 0b11,85 quad = 0b11,
80 },86 };
81 rve: bool,
82 tso: bool,
83 _reserved: u19,
84 _unused: u8,
85};87};
8688
87const mem = std.mem;89const mem = std.mem;