| 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 | 113 | merge_sections: std.ArrayListUnmanaged(Merge.Section) = .empty, |
| 114 | 114 | comment_merge_section_index: ?Merge.Section.Index = null, |
| 115 | 115 | |
| 116 | first_eflags: ?elf.Word = null, | |
| 117 | ||
| 118 | 116 | /// `--verbose-link` output. |
| 119 | 117 | /// Initialized on creation, appended to as inputs are added, printed during `flush`. |
| 120 | 118 | dump_argv_list: std.ArrayListUnmanaged([]const u8), |
| ... | ... | @@ -791,7 +789,7 @@ pub fn loadInput(self: *Elf, input: link.Input) !void { |
| 791 | 789 | .res => unreachable, |
| 792 | 790 | .dso_exact => @panic("TODO"), |
| 793 | 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 | 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 | 1122 | |
| 1125 | 1123 | const gpa = self.base.comp.gpa; |
| 1126 | 1124 | const diags = &self.base.comp.link_diags; |
| 1127 | const first_eflags = &self.first_eflags; | |
| 1128 | 1125 | const target = self.base.comp.root_mod.resolved_target.result; |
| 1129 | 1126 | const debug_fmt_strip = self.base.comp.config.debug_format == .strip; |
| 1130 | 1127 | const default_sym_version = self.default_sym_version; |
| ... | ... | @@ -1145,7 +1142,7 @@ fn parseObject(self: *Elf, obj: link.Input.Object) !void { |
| 1145 | 1142 | try self.objects.append(gpa, index); |
| 1146 | 1143 | |
| 1147 | 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 | 1146 | if (!self.base.isStaticLib()) { |
| 1150 | 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 | 1153 | diags: *Diags, |
| 1157 | 1154 | file_handles: *std.ArrayListUnmanaged(File.Handle), |
| 1158 | 1155 | files: *std.MultiArrayList(File.Entry), |
| 1159 | first_eflags: *?elf.Word, | |
| 1160 | 1156 | target: std.Target, |
| 1161 | 1157 | debug_fmt_strip: bool, |
| 1162 | 1158 | default_sym_version: elf.Versym, |
| ... | ... | @@ -1179,7 +1175,7 @@ fn parseArchive( |
| 1179 | 1175 | const object = &files.items(.data)[index].object; |
| 1180 | 1176 | object.index = index; |
| 1181 | 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 | 1179 | if (!is_static_lib) |
| 1184 | 1180 | try object.parse(gpa, diags, obj.path, obj.file, target, debug_fmt_strip, default_sym_version); |
| 1185 | 1181 | try objects.append(gpa, index); |
src/link/Elf/Object.zig+72-31| ... | ... | @@ -99,7 +99,6 @@ pub fn parseCommon( |
| 99 | 99 | path: Path, |
| 100 | 100 | handle: fs.File, |
| 101 | 101 | target: std.Target, |
| 102 | first_eflags: *?elf.Word, | |
| 103 | 102 | ) !void { |
| 104 | 103 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 105 | 104 | const file_size = (try handle.stat()).size; |
| ... | ... | @@ -114,7 +113,7 @@ pub fn parseCommon( |
| 114 | 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 | 118 | if (self.header.?.e_shnum == 0) return; |
| 120 | 119 | |
| ... | ... | @@ -180,39 +179,81 @@ pub fn parseCommon( |
| 180 | 179 | } |
| 181 | 180 | } |
| 182 | 181 | |
| 183 | fn validateEFlags( | |
| 182 | pub fn validateEFlags( | |
| 184 | 183 | diags: *Diags, |
| 185 | 184 | path: Path, |
| 186 | 185 | target: std.Target, |
| 187 | 186 | 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 => {}, | |
| 216 | 257 | } |
| 217 | 258 | } |
| 218 | 259 |
src/link/riscv.zig+9-7| ... | ... | @@ -70,18 +70,20 @@ fn bitSlice( |
| 70 | 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 | 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 | 82 | soft = 0b00, |
| 77 | 83 | single = 0b01, |
| 78 | 84 | double = 0b10, |
| 79 | 85 | quad = 0b11, |
| 80 | }, | |
| 81 | rve: bool, | |
| 82 | tso: bool, | |
| 83 | _reserved: u19, | |
| 84 | _unused: u8, | |
| 86 | }; | |
| 85 | 87 | }; |
| 86 | 88 | |
| 87 | 89 | const mem = std.mem; |