| author | |
| committer | |
| log | 66a7c09defec1fe4f4f1751e36acc412e3ca8ea9 |
| tree | 6ceb71191d103f008418111f749aedb55faf8e59 |
| parent | b2c62bcbf64a3ffa2af6a8e441f1c12e10c598ec |
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, |
| 113 | merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, | 113 | merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, |
| 114 | comment_merge_section_index: ?Merge.Section.Index = null, | 114 | comment_merge_section_index: ?Merge.Section.Index = null, |
| 115 | 115 | ||
| 116 | first_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`. |
| 120 | dump_argv_list: std.ArrayListUnmanaged([]const u8), | 118 | dump_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 { |
| 1124 | 1122 | ||
| 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); |
| 1146 | 1143 | ||
| 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); |
| 118 | 117 | ||
| 119 | if (self.header.?.e_shnum == 0) return; | 118 | if (self.header.?.e_shnum == 0) return; |
| 120 | 119 | ||
| ... | @@ -180,39 +179,81 @@ pub fn parseCommon( | ... | @@ -180,39 +179,81 @@ pub fn parseCommon( |
| 180 | } | 179 | } |
| 181 | } | 180 | } |
| 182 | 181 | ||
| 183 | fn validateEFlags( | 182 | pub 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 |
| 196 | 195 | // 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 |
| 199 | 198 | // 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 | } |
| 218 | 259 |
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 | } |
| 72 | 72 | ||
| 73 | pub const RiscvEflags = packed struct(u32) { | 73 | pub 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 | }; |
| 86 | 88 | ||
| 87 | const mem = std.mem; | 89 | const mem = std.mem; |