| author | |
| committer | |
| log | ce5a5c361b5b098c3b7d68f88136a9c91e7bec19 |
| tree | 713dbd96a58ada0527b2668246df813f40a09cf0 |
| parent | e1e151df0d948be7464b448c61033d4c1d80d86b |
| parent | 22661f3d67251688a1fabf9e5fe65210ce284b9f |
| signature |
link.Elf: reduce flush logic18 files changed, 201 insertions(+), 268 deletions(-)
lib/std/Build/Step/Compile.zig+12| ... | ... | @@ -235,6 +235,7 @@ sanitize_coverage_trace_pc_guard: ?bool = null, |
| 235 | 235 | pub const ExpectedCompileErrors = union(enum) { |
| 236 | 236 | contains: []const u8, |
| 237 | 237 | exact: []const []const u8, |
| 238 | starts_with: []const u8, | |
| 238 | 239 | }; |
| 239 | 240 | |
| 240 | 241 | pub const Entry = union(enum) { |
| ... | ... | @@ -1958,6 +1959,17 @@ fn checkCompileErrors(compile: *Compile) !void { |
| 1958 | 1959 | |
| 1959 | 1960 | // TODO merge this with the testing.expectEqualStrings logic, and also CheckFile |
| 1960 | 1961 | switch (expect_errors) { |
| 1962 | .starts_with => |expect_starts_with| { | |
| 1963 | if (std.mem.startsWith(u8, actual_stderr, expect_starts_with)) return; | |
| 1964 | return compile.step.fail( | |
| 1965 | \\ | |
| 1966 | \\========= should start with: ============ | |
| 1967 | \\{s} | |
| 1968 | \\========= but not found: ================ | |
| 1969 | \\{s} | |
| 1970 | \\========================================= | |
| 1971 | , .{ expect_starts_with, actual_stderr }); | |
| 1972 | }, | |
| 1961 | 1973 | .contains => |expect_line| { |
| 1962 | 1974 | while (actual_line_it.next()) |actual_line| { |
| 1963 | 1975 | if (!matchCompileError(actual_line, expect_line)) continue; |
src/Compilation.zig+15-1| ... | ... | @@ -280,6 +280,13 @@ pub const CRTFile = struct { |
| 280 | 280 | lock: Cache.Lock, |
| 281 | 281 | full_object_path: []const u8, |
| 282 | 282 | |
| 283 | pub fn isObject(cf: CRTFile) bool { | |
| 284 | return switch (classifyFileExt(cf.full_object_path)) { | |
| 285 | .object => true, | |
| 286 | else => false, | |
| 287 | }; | |
| 288 | } | |
| 289 | ||
| 283 | 290 | pub fn deinit(self: *CRTFile, gpa: Allocator) void { |
| 284 | 291 | self.lock.release(); |
| 285 | 292 | gpa.free(self.full_object_path); |
| ... | ... | @@ -1018,6 +1025,13 @@ pub const LinkObject = struct { |
| 1018 | 1025 | // |
| 1019 | 1026 | // Consistent with `withLOption` variable name in lld ELF driver. |
| 1020 | 1027 | loption: bool = false, |
| 1028 | ||
| 1029 | pub fn isObject(lo: LinkObject) bool { | |
| 1030 | return switch (classifyFileExt(lo.path)) { | |
| 1031 | .object => true, | |
| 1032 | else => false, | |
| 1033 | }; | |
| 1034 | } | |
| 1021 | 1035 | }; |
| 1022 | 1036 | |
| 1023 | 1037 | pub const CreateOptions = struct { |
| ... | ... | @@ -2433,7 +2447,7 @@ fn flush( |
| 2433 | 2447 | if (comp.bin_file) |lf| { |
| 2434 | 2448 | // This is needed before reading the error flags. |
| 2435 | 2449 | lf.flush(arena, tid, prog_node) catch |err| switch (err) { |
| 2436 | error.FlushFailure => {}, // error reported through link_error_flags | |
| 2450 | error.FlushFailure, error.LinkFailure => {}, // error reported through link_error_flags | |
| 2437 | 2451 | error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr |
| 2438 | 2452 | else => |e| return e, |
| 2439 | 2453 | }; |
src/link.zig+3-1| ... | ... | @@ -67,7 +67,6 @@ pub const File = struct { |
| 67 | 67 | gc_sections: bool, |
| 68 | 68 | print_gc_sections: bool, |
| 69 | 69 | build_id: std.zig.BuildId, |
| 70 | rpath_list: []const []const u8, | |
| 71 | 70 | allow_shlib_undefined: bool, |
| 72 | 71 | stack_size: u64, |
| 73 | 72 | |
| ... | ... | @@ -534,7 +533,10 @@ pub const File = struct { |
| 534 | 533 | FailedToEmit, |
| 535 | 534 | FileSystem, |
| 536 | 535 | FilesOpenedWithWrongFlags, |
| 536 | /// Indicates an error will be present in `Compilation.link_errors`. | |
| 537 | 537 | FlushFailure, |
| 538 | /// Indicates an error will be present in `Compilation.link_errors`. | |
| 539 | LinkFailure, | |
| 538 | 540 | FunctionSignatureMismatch, |
| 539 | 541 | GlobalTypeMismatch, |
| 540 | 542 | HotSwapUnavailableOnHostOperatingSystem, |
src/link/C.zig-1| ... | ... | @@ -148,7 +148,6 @@ pub fn createEmpty( |
| 148 | 148 | .file = file, |
| 149 | 149 | .disable_lld_caching = options.disable_lld_caching, |
| 150 | 150 | .build_id = options.build_id, |
| 151 | .rpath_list = options.rpath_list, | |
| 152 | 151 | }, |
| 153 | 152 | }; |
| 154 | 153 |
src/link/Coff.zig-1| ... | ... | @@ -263,7 +263,6 @@ pub fn createEmpty( |
| 263 | 263 | .file = null, |
| 264 | 264 | .disable_lld_caching = options.disable_lld_caching, |
| 265 | 265 | .build_id = options.build_id, |
| 266 | .rpath_list = options.rpath_list, | |
| 267 | 266 | }, |
| 268 | 267 | .ptr_width = ptr_width, |
| 269 | 268 | .page_size = page_size, |
src/link/Elf.zig+97-120| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | base: link.File, |
| 2 | rpath_table: std.StringArrayHashMapUnmanaged(void), | |
| 2 | 3 | image_base: u64, |
| 3 | 4 | emit_relocs: bool, |
| 4 | 5 | z_nodelete: bool, |
| ... | ... | @@ -239,6 +240,11 @@ pub fn createEmpty( |
| 239 | 240 | else |
| 240 | 241 | try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path}); |
| 241 | 242 | |
| 243 | var rpath_table: std.StringArrayHashMapUnmanaged(void) = .empty; | |
| 244 | try rpath_table.entries.resize(arena, options.rpath_list.len); | |
| 245 | @memcpy(rpath_table.entries.items(.key), options.rpath_list); | |
| 246 | try rpath_table.reIndex(arena); | |
| 247 | ||
| 242 | 248 | const self = try arena.create(Elf); |
| 243 | 249 | self.* = .{ |
| 244 | 250 | .base = .{ |
| ... | ... | @@ -253,8 +259,8 @@ pub fn createEmpty( |
| 253 | 259 | .file = null, |
| 254 | 260 | .disable_lld_caching = options.disable_lld_caching, |
| 255 | 261 | .build_id = options.build_id, |
| 256 | .rpath_list = options.rpath_list, | |
| 257 | 262 | }, |
| 263 | .rpath_table = rpath_table, | |
| 258 | 264 | .ptr_width = ptr_width, |
| 259 | 265 | .page_size = page_size, |
| 260 | 266 | .default_sym_version = default_sym_version, |
| ... | ... | @@ -785,8 +791,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 785 | 791 | const target = self.getTarget(); |
| 786 | 792 | const link_mode = comp.config.link_mode; |
| 787 | 793 | const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type. |
| 788 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); | |
| 789 | 794 | const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: { |
| 795 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path}); | |
| 790 | 796 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 791 | 797 | break :blk try fs.path.join(arena, &.{ dirname, path }); |
| 792 | 798 | } else { |
| ... | ... | @@ -802,69 +808,37 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 802 | 808 | if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); |
| 803 | 809 | |
| 804 | 810 | const csu = try CsuObjects.init(arena, comp); |
| 805 | const compiler_rt_path: ?[]const u8 = blk: { | |
| 806 | if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; | |
| 807 | if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; | |
| 808 | break :blk null; | |
| 809 | }; | |
| 810 | 811 | |
| 811 | // Here we will parse input positional and library files (if referenced). | |
| 812 | // This will roughly match in any linker backend we support. | |
| 813 | var positionals = std.ArrayList(Compilation.LinkObject).init(arena); | |
| 812 | // Here we will parse object and library files (if referenced). | |
| 814 | 813 | |
| 815 | 814 | // csu prelude |
| 816 | if (csu.crt0) |v| try positionals.append(.{ .path = v }); | |
| 817 | if (csu.crti) |v| try positionals.append(.{ .path = v }); | |
| 818 | if (csu.crtbegin) |v| try positionals.append(.{ .path = v }); | |
| 815 | if (csu.crt0) |path| try parseObjectReportingFailure(self, path); | |
| 816 | if (csu.crti) |path| try parseObjectReportingFailure(self, path); | |
| 817 | if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path); | |
| 819 | 818 | |
| 820 | try positionals.ensureUnusedCapacity(comp.objects.len); | |
| 821 | positionals.appendSliceAssumeCapacity(comp.objects); | |
| 819 | for (comp.objects) |obj| { | |
| 820 | if (obj.isObject()) { | |
| 821 | try parseObjectReportingFailure(self, obj.path); | |
| 822 | } else { | |
| 823 | try parseLibraryReportingFailure(self, .{ .path = obj.path }, obj.must_link); | |
| 824 | } | |
| 825 | } | |
| 822 | 826 | |
| 823 | 827 | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 824 | 828 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 825 | 829 | // in this set. |
| 826 | 830 | for (comp.c_object_table.keys()) |key| { |
| 827 | try positionals.append(.{ .path = key.status.success.object_path }); | |
| 828 | } | |
| 829 | ||
| 830 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | |
| 831 | ||
| 832 | // rpaths | |
| 833 | var rpath_table = std.StringArrayHashMap(void).init(gpa); | |
| 834 | defer rpath_table.deinit(); | |
| 835 | ||
| 836 | for (self.base.rpath_list) |rpath| { | |
| 837 | _ = try rpath_table.put(rpath, {}); | |
| 831 | try parseObjectReportingFailure(self, key.status.success.object_path); | |
| 838 | 832 | } |
| 839 | 833 | |
| 840 | if (comp.config.any_sanitize_thread) { | |
| 841 | try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path }); | |
| 842 | } | |
| 834 | if (module_obj_path) |path| try parseObjectReportingFailure(self, path); | |
| 843 | 835 | |
| 844 | if (comp.config.any_fuzz) { | |
| 845 | try positionals.append(.{ .path = comp.fuzzer_lib.?.full_object_path }); | |
| 846 | } | |
| 836 | if (comp.config.any_sanitize_thread) try parseCrtFileReportingFailure(self, comp.tsan_lib.?); | |
| 837 | if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?); | |
| 847 | 838 | |
| 848 | 839 | // libc |
| 849 | 840 | if (!comp.skip_linker_dependencies and !comp.config.link_libc) { |
| 850 | if (comp.libc_static_lib) |lib| { | |
| 851 | try positionals.append(.{ .path = lib.full_object_path }); | |
| 852 | } | |
| 853 | } | |
| 854 | ||
| 855 | for (positionals.items) |obj| { | |
| 856 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | |
| 857 | error.MalformedObject, | |
| 858 | error.MalformedArchive, | |
| 859 | error.MismatchedEflags, | |
| 860 | error.InvalidMachineType, | |
| 861 | => continue, // already reported | |
| 862 | else => |e| try self.reportParseError( | |
| 863 | obj.path, | |
| 864 | "unexpected error: parsing input file failed with error {s}", | |
| 865 | .{@errorName(e)}, | |
| 866 | ), | |
| 867 | }; | |
| 841 | if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib); | |
| 868 | 842 | } |
| 869 | 843 | |
| 870 | 844 | var system_libs = std.ArrayList(SystemLib).init(arena); |
| ... | ... | @@ -947,42 +921,23 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 947 | 921 | } |
| 948 | 922 | |
| 949 | 923 | for (system_libs.items) |lib| { |
| 950 | self.parseLibrary(lib, false) catch |err| switch (err) { | |
| 951 | error.MalformedObject, error.MalformedArchive, error.InvalidMachineType => continue, // already reported | |
| 952 | else => |e| try self.reportParseError( | |
| 953 | lib.path, | |
| 954 | "unexpected error: parsing library failed with error {s}", | |
| 955 | .{@errorName(e)}, | |
| 956 | ), | |
| 957 | }; | |
| 924 | try self.parseLibraryReportingFailure(lib, false); | |
| 958 | 925 | } |
| 959 | 926 | |
| 960 | 927 | // Finally, as the last input objects we add compiler_rt and CSU postlude (if any). |
| 961 | positionals.clearRetainingCapacity(); | |
| 962 | 928 | |
| 963 | 929 | // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs |
| 964 | 930 | // to be after the shared libraries, so they are picked up from the shared |
| 965 | 931 | // libraries, not libcompiler_rt. |
| 966 | if (compiler_rt_path) |path| try positionals.append(.{ .path = path }); | |
| 932 | if (comp.compiler_rt_lib) |crt_file| { | |
| 933 | try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false); | |
| 934 | } else if (comp.compiler_rt_obj) |crt_file| { | |
| 935 | try parseObjectReportingFailure(self, crt_file.full_object_path); | |
| 936 | } | |
| 967 | 937 | |
| 968 | 938 | // csu postlude |
| 969 | if (csu.crtend) |v| try positionals.append(.{ .path = v }); | |
| 970 | if (csu.crtn) |v| try positionals.append(.{ .path = v }); | |
| 971 | ||
| 972 | for (positionals.items) |obj| { | |
| 973 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | |
| 974 | error.MalformedObject, | |
| 975 | error.MalformedArchive, | |
| 976 | error.MismatchedEflags, | |
| 977 | error.InvalidMachineType, | |
| 978 | => continue, // already reported | |
| 979 | else => |e| try self.reportParseError( | |
| 980 | obj.path, | |
| 981 | "unexpected error: parsing input file failed with error {s}", | |
| 982 | .{@errorName(e)}, | |
| 983 | ), | |
| 984 | }; | |
| 985 | } | |
| 939 | if (csu.crtend) |path| try parseObjectReportingFailure(self, path); | |
| 940 | if (csu.crtn) |path| try parseObjectReportingFailure(self, path); | |
| 986 | 941 | |
| 987 | 942 | if (self.base.hasErrors()) return error.FlushFailure; |
| 988 | 943 | |
| ... | ... | @@ -1024,7 +979,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 1024 | 979 | self.markEhFrameAtomsDead(); |
| 1025 | 980 | try self.resolveMergeSections(); |
| 1026 | 981 | |
| 1027 | try self.convertCommonSymbols(); | |
| 982 | for (self.objects.items) |index| { | |
| 983 | try self.file(index).?.object.convertCommonSymbols(self); | |
| 984 | } | |
| 1028 | 985 | self.markImportsExports(); |
| 1029 | 986 | |
| 1030 | 987 | if (self.base.gc_sections) { |
| ... | ... | @@ -1056,7 +1013,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 1056 | 1013 | try self.initSpecialPhdrs(); |
| 1057 | 1014 | try self.sortShdrs(); |
| 1058 | 1015 | |
| 1059 | try self.setDynamicSection(rpath_table.keys()); | |
| 1016 | try self.setDynamicSection(self.rpath_table.keys()); | |
| 1060 | 1017 | self.sortDynamicSymtab(); |
| 1061 | 1018 | try self.setHashSections(); |
| 1062 | 1019 | try self.setVersionSymtab(); |
| ... | ... | @@ -1207,9 +1164,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1207 | 1164 | try argv.appendSlice(&.{ "--entry", name }); |
| 1208 | 1165 | } |
| 1209 | 1166 | |
| 1210 | for (self.base.rpath_list) |rpath| { | |
| 1211 | try argv.append("-rpath"); | |
| 1212 | try argv.append(rpath); | |
| 1167 | for (self.rpath_table.keys()) |rpath| { | |
| 1168 | try argv.appendSlice(&.{ "-rpath", rpath }); | |
| 1213 | 1169 | } |
| 1214 | 1170 | |
| 1215 | 1171 | try argv.appendSlice(&.{ |
| ... | ... | @@ -1405,10 +1361,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1405 | 1361 | } |
| 1406 | 1362 | |
| 1407 | 1363 | pub const ParseError = error{ |
| 1408 | MalformedObject, | |
| 1409 | MalformedArchive, | |
| 1410 | InvalidMachineType, | |
| 1411 | MismatchedEflags, | |
| 1364 | /// Indicates the error is already reported on `Compilation.link_errors`. | |
| 1365 | LinkFailure, | |
| 1366 | ||
| 1412 | 1367 | OutOfMemory, |
| 1413 | 1368 | Overflow, |
| 1414 | 1369 | InputOutput, |
| ... | ... | @@ -1419,16 +1374,30 @@ pub const ParseError = error{ |
| 1419 | 1374 | UnknownFileType, |
| 1420 | 1375 | } || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError; |
| 1421 | 1376 | |
| 1422 | pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void { | |
| 1423 | const tracy = trace(@src()); | |
| 1424 | defer tracy.end(); | |
| 1425 | if (try Object.isObject(path)) { | |
| 1426 | try self.parseObject(path); | |
| 1377 | fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error{OutOfMemory}!void { | |
| 1378 | if (crt_file.isObject()) { | |
| 1379 | try parseObjectReportingFailure(self, crt_file.full_object_path); | |
| 1427 | 1380 | } else { |
| 1428 | try self.parseLibrary(.{ .path = path }, must_link); | |
| 1381 | try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false); | |
| 1429 | 1382 | } |
| 1430 | 1383 | } |
| 1431 | 1384 | |
| 1385 | pub fn parseObjectReportingFailure(self: *Elf, path: []const u8) error{OutOfMemory}!void { | |
| 1386 | self.parseObject(path) catch |err| switch (err) { | |
| 1387 | error.LinkFailure => return, // already reported | |
| 1388 | error.OutOfMemory => return error.OutOfMemory, | |
| 1389 | else => |e| try self.addParseError(path, "unable to parse object: {s}", .{@errorName(e)}), | |
| 1390 | }; | |
| 1391 | } | |
| 1392 | ||
| 1393 | pub fn parseLibraryReportingFailure(self: *Elf, lib: SystemLib, must_link: bool) error{OutOfMemory}!void { | |
| 1394 | self.parseLibrary(lib, must_link) catch |err| switch (err) { | |
| 1395 | error.LinkFailure => return, // already reported | |
| 1396 | error.OutOfMemory => return error.OutOfMemory, | |
| 1397 | else => |e| try self.addParseError(lib.path, "unable to parse library: {s}", .{@errorName(e)}), | |
| 1398 | }; | |
| 1399 | } | |
| 1400 | ||
| 1432 | 1401 | fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void { |
| 1433 | 1402 | const tracy = trace(@src()); |
| 1434 | 1403 | defer tracy.end(); |
| ... | ... | @@ -1578,8 +1547,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void { |
| 1578 | 1547 | .needed = scr_obj.needed, |
| 1579 | 1548 | .path = full_path, |
| 1580 | 1549 | }, false) catch |err| switch (err) { |
| 1581 | error.MalformedObject, error.MalformedArchive, error.InvalidMachineType => continue, // already reported | |
| 1582 | else => |e| try self.reportParseError( | |
| 1550 | error.LinkFailure => continue, // already reported | |
| 1551 | else => |e| try self.addParseError( | |
| 1583 | 1552 | full_path, |
| 1584 | 1553 | "unexpected error: parsing library failed with error {s}", |
| 1585 | 1554 | .{@errorName(e)}, |
| ... | ... | @@ -1604,24 +1573,24 @@ pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Wor |
| 1604 | 1573 | self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc; |
| 1605 | 1574 | self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso; |
| 1606 | 1575 | |
| 1607 | var is_error: bool = false; | |
| 1576 | var any_errors: bool = false; | |
| 1608 | 1577 | if (self_riscv_eflags.fabi != riscv_eflags.fabi) { |
| 1609 | is_error = true; | |
| 1610 | _ = try self.reportParseError2( | |
| 1578 | any_errors = true; | |
| 1579 | try self.addFileError( | |
| 1611 | 1580 | file_index, |
| 1612 | 1581 | "cannot link object files with different float-point ABIs", |
| 1613 | 1582 | .{}, |
| 1614 | 1583 | ); |
| 1615 | 1584 | } |
| 1616 | 1585 | if (self_riscv_eflags.rve != riscv_eflags.rve) { |
| 1617 | is_error = true; | |
| 1618 | _ = try self.reportParseError2( | |
| 1586 | any_errors = true; | |
| 1587 | try self.addFileError( | |
| 1619 | 1588 | file_index, |
| 1620 | 1589 | "cannot link object files with different RVEs", |
| 1621 | 1590 | .{}, |
| 1622 | 1591 | ); |
| 1623 | 1592 | } |
| 1624 | if (is_error) return error.MismatchedEflags; | |
| 1593 | if (any_errors) return error.LinkFailure; | |
| 1625 | 1594 | } |
| 1626 | 1595 | }, |
| 1627 | 1596 | else => {}, |
| ... | ... | @@ -1743,12 +1712,6 @@ pub fn markEhFrameAtomsDead(self: *Elf) void { |
| 1743 | 1712 | } |
| 1744 | 1713 | } |
| 1745 | 1714 | |
| 1746 | fn convertCommonSymbols(self: *Elf) !void { | |
| 1747 | for (self.objects.items) |index| { | |
| 1748 | try self.file(index).?.object.convertCommonSymbols(self); | |
| 1749 | } | |
| 1750 | } | |
| 1751 | ||
| 1752 | 1715 | fn markImportsExports(self: *Elf) void { |
| 1753 | 1716 | if (self.zigObjectPtr()) |zo| { |
| 1754 | 1717 | zo.markImportsExports(self); |
| ... | ... | @@ -1978,7 +1941,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s |
| 1978 | 1941 | man.hash.add(self.emit_relocs); |
| 1979 | 1942 | man.hash.add(comp.config.rdynamic); |
| 1980 | 1943 | man.hash.addListOfBytes(self.lib_dirs); |
| 1981 | man.hash.addListOfBytes(self.base.rpath_list); | |
| 1944 | man.hash.addListOfBytes(self.rpath_table.keys()); | |
| 1982 | 1945 | if (output_mode == .Exe) { |
| 1983 | 1946 | man.hash.add(self.base.stack_size); |
| 1984 | 1947 | man.hash.add(self.base.build_id); |
| ... | ... | @@ -2263,14 +2226,8 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s |
| 2263 | 2226 | if (csu.crti) |v| try argv.append(v); |
| 2264 | 2227 | if (csu.crtbegin) |v| try argv.append(v); |
| 2265 | 2228 | |
| 2266 | // rpaths | |
| 2267 | var rpath_table = std.StringHashMap(void).init(gpa); | |
| 2268 | defer rpath_table.deinit(); | |
| 2269 | for (self.base.rpath_list) |rpath| { | |
| 2270 | if ((try rpath_table.fetchPut(rpath, {})) == null) { | |
| 2271 | try argv.append("-rpath"); | |
| 2272 | try argv.append(rpath); | |
| 2273 | } | |
| 2229 | for (self.rpath_table.keys()) |rpath| { | |
| 2230 | try argv.appendSlice(&.{ "-rpath", rpath }); | |
| 2274 | 2231 | } |
| 2275 | 2232 | |
| 2276 | 2233 | for (self.symbol_wrap_set.keys()) |symbol_name| { |
| ... | ... | @@ -2847,7 +2804,7 @@ pub fn resolveMergeSections(self: *Elf) !void { |
| 2847 | 2804 | const file_ptr = self.file(index).?; |
| 2848 | 2805 | if (!file_ptr.isAlive()) continue; |
| 2849 | 2806 | file_ptr.object.initInputMergeSections(self) catch |err| switch (err) { |
| 2850 | error.MalformedObject => has_errors = true, | |
| 2807 | error.LinkFailure => has_errors = true, | |
| 2851 | 2808 | else => |e| return e, |
| 2852 | 2809 | }; |
| 2853 | 2810 | } |
| ... | ... | @@ -2864,12 +2821,12 @@ pub fn resolveMergeSections(self: *Elf) !void { |
| 2864 | 2821 | const file_ptr = self.file(index).?; |
| 2865 | 2822 | if (!file_ptr.isAlive()) continue; |
| 2866 | 2823 | file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) { |
| 2867 | error.MalformedObject => has_errors = true, | |
| 2824 | error.LinkFailure => has_errors = true, | |
| 2868 | 2825 | else => |e| return e, |
| 2869 | 2826 | }; |
| 2870 | 2827 | } |
| 2871 | 2828 | |
| 2872 | if (has_errors) return error.FlushFailure; | |
| 2829 | if (has_errors) return error.LinkFailure; | |
| 2873 | 2830 | } |
| 2874 | 2831 | |
| 2875 | 2832 | pub fn finalizeMergeSections(self: *Elf) !void { |
| ... | ... | @@ -5201,7 +5158,7 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { |
| 5201 | 5158 | }); |
| 5202 | 5159 | } |
| 5203 | 5160 | |
| 5204 | pub fn reportParseError( | |
| 5161 | pub fn addParseError( | |
| 5205 | 5162 | self: *Elf, |
| 5206 | 5163 | path: []const u8, |
| 5207 | 5164 | comptime format: []const u8, |
| ... | ... | @@ -5212,7 +5169,7 @@ pub fn reportParseError( |
| 5212 | 5169 | try err.addNote("while parsing {s}", .{path}); |
| 5213 | 5170 | } |
| 5214 | 5171 | |
| 5215 | pub fn reportParseError2( | |
| 5172 | pub fn addFileError( | |
| 5216 | 5173 | self: *Elf, |
| 5217 | 5174 | file_index: File.Index, |
| 5218 | 5175 | comptime format: []const u8, |
| ... | ... | @@ -5223,6 +5180,26 @@ pub fn reportParseError2( |
| 5223 | 5180 | try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()}); |
| 5224 | 5181 | } |
| 5225 | 5182 | |
| 5183 | pub fn failFile( | |
| 5184 | self: *Elf, | |
| 5185 | file_index: File.Index, | |
| 5186 | comptime format: []const u8, | |
| 5187 | args: anytype, | |
| 5188 | ) error{ OutOfMemory, LinkFailure } { | |
| 5189 | try addFileError(self, file_index, format, args); | |
| 5190 | return error.LinkFailure; | |
| 5191 | } | |
| 5192 | ||
| 5193 | pub fn failParse( | |
| 5194 | self: *Elf, | |
| 5195 | path: []const u8, | |
| 5196 | comptime format: []const u8, | |
| 5197 | args: anytype, | |
| 5198 | ) error{ OutOfMemory, LinkFailure } { | |
| 5199 | try addParseError(self, path, format, args); | |
| 5200 | return error.LinkFailure; | |
| 5201 | } | |
| 5202 | ||
| 5226 | 5203 | const FormatShdrCtx = struct { |
| 5227 | 5204 | elf_file: *Elf, |
| 5228 | 5205 | shdr: elf.Elf64_Shdr, |
src/link/Elf/Archive.zig+1-2| ... | ... | @@ -35,10 +35,9 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: Fil |
| 35 | 35 | pos += @sizeOf(elf.ar_hdr); |
| 36 | 36 | |
| 37 | 37 | if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) { |
| 38 | try elf_file.reportParseError(path, "invalid archive header delimiter: {s}", .{ | |
| 38 | return elf_file.failParse(path, "invalid archive header delimiter: {s}", .{ | |
| 39 | 39 | std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), |
| 40 | 40 | }); |
| 41 | return error.MalformedArchive; | |
| 42 | 41 | } |
| 43 | 42 | |
| 44 | 43 | const obj_size = try hdr.size(); |
src/link/Elf/LdScript.zig+4-8| ... | ... | @@ -7,7 +7,7 @@ pub fn deinit(scr: *LdScript, allocator: Allocator) void { |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | pub const Error = error{ |
| 10 | InvalidLdScript, | |
| 10 | LinkFailure, | |
| 11 | 11 | UnexpectedToken, |
| 12 | 12 | UnknownCpuArch, |
| 13 | 13 | OutOfMemory, |
| ... | ... | @@ -32,12 +32,9 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void { |
| 32 | 32 | try line_col.append(.{ .line = line, .column = column }); |
| 33 | 33 | switch (tok.id) { |
| 34 | 34 | .invalid => { |
| 35 | try elf_file.reportParseError(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{ | |
| 36 | std.fmt.fmtSliceEscapeLower(tok.get(data)), | |
| 37 | line, | |
| 38 | column, | |
| 35 | return elf_file.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{ | |
| 36 | std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column, | |
| 39 | 37 | }); |
| 40 | return error.InvalidLdScript; | |
| 41 | 38 | }, |
| 42 | 39 | .new_line => { |
| 43 | 40 | line += 1; |
| ... | ... | @@ -59,13 +56,12 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void { |
| 59 | 56 | const last_token_id = parser.it.pos - 1; |
| 60 | 57 | const last_token = parser.it.get(last_token_id); |
| 61 | 58 | const lcol = line_col.items[last_token_id]; |
| 62 | try elf_file.reportParseError(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{ | |
| 59 | return elf_file.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{ | |
| 63 | 60 | @tagName(last_token.id), |
| 64 | 61 | last_token.get(data), |
| 65 | 62 | lcol.line, |
| 66 | 63 | lcol.column, |
| 67 | 64 | }); |
| 68 | return error.InvalidLdScript; | |
| 69 | 65 | }, |
| 70 | 66 | else => |e| return e, |
| 71 | 67 | }; |
src/link/Elf/Object.zig+20-53| ... | ... | @@ -34,18 +34,6 @@ num_dynrelocs: u32 = 0, |
| 34 | 34 | output_symtab_ctx: Elf.SymtabCtx = .{}, |
| 35 | 35 | output_ar_state: Archive.ArState = .{}, |
| 36 | 36 | |
| 37 | pub fn isObject(path: []const u8) !bool { | |
| 38 | const file = try std.fs.cwd().openFile(path, .{}); | |
| 39 | defer file.close(); | |
| 40 | const reader = file.reader(); | |
| 41 | const header = reader.readStruct(elf.Elf64_Ehdr) catch return false; | |
| 42 | if (!mem.eql(u8, header.e_ident[0..4], "\x7fELF")) return false; | |
| 43 | if (header.e_ident[elf.EI_VERSION] != 1) return false; | |
| 44 | if (header.e_type != elf.ET.REL) return false; | |
| 45 | if (header.e_version != 1) return false; | |
| 46 | return true; | |
| 47 | } | |
| 48 | ||
| 49 | 37 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 50 | 38 | if (self.archive) |*ar| allocator.free(ar.path); |
| 51 | 39 | allocator.free(self.path); |
| ... | ... | @@ -107,12 +95,9 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 107 | 95 | |
| 108 | 96 | const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine(); |
| 109 | 97 | if (em != self.header.?.e_machine) { |
| 110 | try elf_file.reportParseError2( | |
| 111 | self.index, | |
| 112 | "invalid ELF machine type: {s}", | |
| 113 | .{@tagName(self.header.?.e_machine)}, | |
| 114 | ); | |
| 115 | return error.InvalidMachineType; | |
| 98 | return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{ | |
| 99 | @tagName(self.header.?.e_machine), | |
| 100 | }); | |
| 116 | 101 | } |
| 117 | 102 | try elf_file.validateEFlags(self.index, self.header.?.e_flags); |
| 118 | 103 | |
| ... | ... | @@ -122,12 +107,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 122 | 107 | const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; |
| 123 | 108 | const shsize = shnum * @sizeOf(elf.Elf64_Shdr); |
| 124 | 109 | if (file_size < offset + shoff or file_size < offset + shoff + shsize) { |
| 125 | try elf_file.reportParseError2( | |
| 126 | self.index, | |
| 127 | "corrupt header: section header table extends past the end of file", | |
| 128 | .{}, | |
| 129 | ); | |
| 130 | return error.MalformedObject; | |
| 110 | return elf_file.failFile(self.index, "corrupt header: section header table extends past the end of file", .{}); | |
| 131 | 111 | } |
| 132 | 112 | |
| 133 | 113 | const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize); |
| ... | ... | @@ -138,8 +118,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 138 | 118 | for (self.shdrs.items) |shdr| { |
| 139 | 119 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 140 | 120 | if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) { |
| 141 | try elf_file.reportParseError2(self.index, "corrupt section: extends past the end of file", .{}); | |
| 142 | return error.MalformedObject; | |
| 121 | return elf_file.failFile(self.index, "corrupt section: extends past the end of file", .{}); | |
| 143 | 122 | } |
| 144 | 123 | } |
| 145 | 124 | } |
| ... | ... | @@ -148,8 +127,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 148 | 127 | defer allocator.free(shstrtab); |
| 149 | 128 | for (self.shdrs.items) |shdr| { |
| 150 | 129 | if (shdr.sh_name >= shstrtab.len) { |
| 151 | try elf_file.reportParseError2(self.index, "corrupt section name offset", .{}); | |
| 152 | return error.MalformedObject; | |
| 130 | return elf_file.failFile(self.index, "corrupt section name offset", .{}); | |
| 153 | 131 | } |
| 154 | 132 | } |
| 155 | 133 | try self.strtab.appendSlice(allocator, shstrtab); |
| ... | ... | @@ -166,8 +144,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil |
| 166 | 144 | const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index); |
| 167 | 145 | defer allocator.free(raw_symtab); |
| 168 | 146 | const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch { |
| 169 | try elf_file.reportParseError2(self.index, "symbol table not evenly divisible", .{}); | |
| 170 | return error.MalformedObject; | |
| 147 | return elf_file.failFile(self.index, "symbol table not evenly divisible", .{}); | |
| 171 | 148 | }; |
| 172 | 149 | const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms]; |
| 173 | 150 | |
| ... | ... | @@ -221,30 +198,15 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 221 | 198 | const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx); |
| 222 | 199 | defer allocator.free(group_raw_data); |
| 223 | 200 | const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch { |
| 224 | try elf_file.reportParseError2( | |
| 225 | self.index, | |
| 226 | "corrupt section group: not evenly divisible ", | |
| 227 | .{}, | |
| 228 | ); | |
| 229 | return error.MalformedObject; | |
| 201 | return elf_file.failFile(self.index, "corrupt section group: not evenly divisible ", .{}); | |
| 230 | 202 | }; |
| 231 | 203 | if (group_nmembers == 0) { |
| 232 | try elf_file.reportParseError2( | |
| 233 | self.index, | |
| 234 | "corrupt section group: empty section", | |
| 235 | .{}, | |
| 236 | ); | |
| 237 | return error.MalformedObject; | |
| 204 | return elf_file.failFile(self.index, "corrupt section group: empty section", .{}); | |
| 238 | 205 | } |
| 239 | 206 | const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers]; |
| 240 | 207 | |
| 241 | 208 | if (group_members[0] != elf.GRP_COMDAT) { |
| 242 | try elf_file.reportParseError2( | |
| 243 | self.index, | |
| 244 | "corrupt section group: unknown SHT_GROUP format", | |
| 245 | .{}, | |
| 246 | ); | |
| 247 | return error.MalformedObject; | |
| 209 | return elf_file.failFile(self.index, "corrupt section group: unknown SHT_GROUP format", .{}); | |
| 248 | 210 | } |
| 249 | 211 | |
| 250 | 212 | const group_start = @as(u32, @intCast(self.comdat_group_data.items.len)); |
| ... | ... | @@ -722,7 +684,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void { |
| 722 | 684 | var err = try elf_file.base.addErrorWithNotes(1); |
| 723 | 685 | try err.addMsg("string not null terminated", .{}); |
| 724 | 686 | try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); |
| 725 | return error.MalformedObject; | |
| 687 | return error.LinkFailure; | |
| 726 | 688 | } |
| 727 | 689 | end += sh_entsize; |
| 728 | 690 | const string = data[start..end]; |
| ... | ... | @@ -737,7 +699,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void { |
| 737 | 699 | var err = try elf_file.base.addErrorWithNotes(1); |
| 738 | 700 | try err.addMsg("size not a multiple of sh_entsize", .{}); |
| 739 | 701 | try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); |
| 740 | return error.MalformedObject; | |
| 702 | return error.LinkFailure; | |
| 741 | 703 | } |
| 742 | 704 | |
| 743 | 705 | var pos: u32 = 0; |
| ... | ... | @@ -765,7 +727,12 @@ pub fn initOutputMergeSections(self: *Object, elf_file: *Elf) !void { |
| 765 | 727 | } |
| 766 | 728 | } |
| 767 | 729 | |
| 768 | pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { | |
| 730 | pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) error{ | |
| 731 | LinkFailure, | |
| 732 | OutOfMemory, | |
| 733 | /// TODO report the error and remove this | |
| 734 | Overflow, | |
| 735 | }!void { | |
| 769 | 736 | const gpa = elf_file.base.comp.gpa; |
| 770 | 737 | |
| 771 | 738 | for (self.input_merge_sections_indexes.items) |index| { |
| ... | ... | @@ -809,7 +776,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { |
| 809 | 776 | try err.addMsg("invalid symbol value: {x}", .{esym.st_value}); |
| 810 | 777 | try err.addNote("for symbol {s}", .{sym.name(elf_file)}); |
| 811 | 778 | try err.addNote("in {}", .{self.fmtPath()}); |
| 812 | return error.MalformedObject; | |
| 779 | return error.LinkFailure; | |
| 813 | 780 | }; |
| 814 | 781 | |
| 815 | 782 | sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index }; |
| ... | ... | @@ -834,7 +801,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void { |
| 834 | 801 | var err = try elf_file.base.addErrorWithNotes(1); |
| 835 | 802 | try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset}); |
| 836 | 803 | try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) }); |
| 837 | return error.MalformedObject; | |
| 804 | return error.LinkFailure; | |
| 838 | 805 | }; |
| 839 | 806 | |
| 840 | 807 | const sym_index = try self.addSymbol(gpa); |
src/link/Elf/SharedObject.zig+5-14| ... | ... | @@ -58,24 +58,16 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { |
| 58 | 58 | |
| 59 | 59 | const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine(); |
| 60 | 60 | if (em != self.header.?.e_machine) { |
| 61 | try elf_file.reportParseError2( | |
| 62 | self.index, | |
| 63 | "invalid ELF machine type: {s}", | |
| 64 | .{@tagName(self.header.?.e_machine)}, | |
| 65 | ); | |
| 66 | return error.InvalidMachineType; | |
| 61 | return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{ | |
| 62 | @tagName(self.header.?.e_machine), | |
| 63 | }); | |
| 67 | 64 | } |
| 68 | 65 | |
| 69 | 66 | const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow; |
| 70 | 67 | const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow; |
| 71 | 68 | const shsize = shnum * @sizeOf(elf.Elf64_Shdr); |
| 72 | 69 | if (file_size < shoff or file_size < shoff + shsize) { |
| 73 | try elf_file.reportParseError2( | |
| 74 | self.index, | |
| 75 | "corrupted header: section header table extends past the end of file", | |
| 76 | .{}, | |
| 77 | ); | |
| 78 | return error.MalformedObject; | |
| 70 | return elf_file.failFile(self.index, "corrupted header: section header table extends past the end of file", .{}); | |
| 79 | 71 | } |
| 80 | 72 | |
| 81 | 73 | const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize); |
| ... | ... | @@ -90,8 +82,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void { |
| 90 | 82 | for (self.shdrs.items, 0..) |shdr, i| { |
| 91 | 83 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 92 | 84 | if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) { |
| 93 | try elf_file.reportParseError2(self.index, "corrupted section header", .{}); | |
| 94 | return error.MalformedObject; | |
| 85 | return elf_file.failFile(self.index, "corrupted section header", .{}); | |
| 95 | 86 | } |
| 96 | 87 | } |
| 97 | 88 | switch (shdr.sh_type) { |
src/link/Elf/relocatable.zig+36-56| ... | ... | @@ -1,36 +1,24 @@ |
| 1 | 1 | pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 2 | 2 | const gpa = comp.gpa; |
| 3 | 3 | |
| 4 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | |
| 5 | defer positionals.deinit(); | |
| 6 | ||
| 7 | try positionals.ensureUnusedCapacity(comp.objects.len); | |
| 8 | positionals.appendSliceAssumeCapacity(comp.objects); | |
| 4 | for (comp.objects) |obj| { | |
| 5 | switch (Compilation.classifyFileExt(obj.path)) { | |
| 6 | .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path), | |
| 7 | .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path), | |
| 8 | else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}), | |
| 9 | } | |
| 10 | } | |
| 9 | 11 | |
| 10 | 12 | for (comp.c_object_table.keys()) |key| { |
| 11 | try positionals.append(.{ .path = key.status.success.object_path }); | |
| 13 | try parseObjectStaticLibReportingFailure(elf_file, key.status.success.object_path); | |
| 12 | 14 | } |
| 13 | 15 | |
| 14 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | |
| 16 | if (module_obj_path) |path| { | |
| 17 | try parseObjectStaticLibReportingFailure(elf_file, path); | |
| 18 | } | |
| 15 | 19 | |
| 16 | 20 | if (comp.include_compiler_rt) { |
| 17 | try positionals.append(.{ .path = comp.compiler_rt_obj.?.full_object_path }); | |
| 18 | } | |
| 19 | ||
| 20 | for (positionals.items) |obj| { | |
| 21 | parsePositionalStaticLib(elf_file, obj.path) catch |err| switch (err) { | |
| 22 | error.MalformedObject, | |
| 23 | error.MalformedArchive, | |
| 24 | error.InvalidMachineType, | |
| 25 | error.MismatchedEflags, | |
| 26 | => continue, // already reported | |
| 27 | error.UnknownFileType => try elf_file.reportParseError(obj.path, "unknown file type for an object file", .{}), | |
| 28 | else => |e| try elf_file.reportParseError( | |
| 29 | obj.path, | |
| 30 | "unexpected error: parsing input file failed with error {s}", | |
| 31 | .{@errorName(e)}, | |
| 32 | ), | |
| 33 | }; | |
| 21 | try parseObjectStaticLibReportingFailure(elf_file, comp.compiler_rt_obj.?.full_object_path); | |
| 34 | 22 | } |
| 35 | 23 | |
| 36 | 24 | if (elf_file.base.hasErrors()) return error.FlushFailure; |
| ... | ... | @@ -153,37 +141,23 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 153 | 141 | } |
| 154 | 142 | |
| 155 | 143 | pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 156 | const gpa = elf_file.base.comp.gpa; | |
| 157 | ||
| 158 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); | |
| 159 | defer positionals.deinit(); | |
| 160 | try positionals.ensureUnusedCapacity(comp.objects.len); | |
| 161 | positionals.appendSliceAssumeCapacity(comp.objects); | |
| 144 | for (comp.objects) |obj| { | |
| 145 | if (obj.isObject()) { | |
| 146 | try elf_file.parseObjectReportingFailure(obj.path); | |
| 147 | } else { | |
| 148 | try elf_file.parseLibraryReportingFailure(.{ .path = obj.path }, obj.must_link); | |
| 149 | } | |
| 150 | } | |
| 162 | 151 | |
| 163 | 152 | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 164 | 153 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 165 | 154 | // in this set. |
| 166 | 155 | for (comp.c_object_table.keys()) |key| { |
| 167 | try positionals.append(.{ .path = key.status.success.object_path }); | |
| 168 | } | |
| 169 | ||
| 170 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | |
| 171 | ||
| 172 | for (positionals.items) |obj| { | |
| 173 | elf_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | |
| 174 | error.MalformedObject, | |
| 175 | error.MalformedArchive, | |
| 176 | error.InvalidMachineType, | |
| 177 | error.MismatchedEflags, | |
| 178 | => continue, // already reported | |
| 179 | else => |e| try elf_file.reportParseError( | |
| 180 | obj.path, | |
| 181 | "unexpected error: parsing input file failed with error {s}", | |
| 182 | .{@errorName(e)}, | |
| 183 | ), | |
| 184 | }; | |
| 156 | try elf_file.parseObjectReportingFailure(key.status.success.object_path); | |
| 185 | 157 | } |
| 186 | 158 | |
| 159 | if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path); | |
| 160 | ||
| 187 | 161 | if (elf_file.base.hasErrors()) return error.FlushFailure; |
| 188 | 162 | |
| 189 | 163 | // Now, we are ready to resolve the symbols across all input files. |
| ... | ... | @@ -224,14 +198,20 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 224 | 198 | if (elf_file.base.hasErrors()) return error.FlushFailure; |
| 225 | 199 | } |
| 226 | 200 | |
| 227 | fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 228 | if (try Object.isObject(path)) { | |
| 229 | try parseObjectStaticLib(elf_file, path); | |
| 230 | } else if (try Archive.isArchive(path)) { | |
| 231 | try parseArchiveStaticLib(elf_file, path); | |
| 232 | } else return error.UnknownFileType; | |
| 233 | // TODO: should we check for LD script? | |
| 234 | // Actually, should we even unpack an archive? | |
| 201 | fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void { | |
| 202 | parseObjectStaticLib(elf_file, path) catch |err| switch (err) { | |
| 203 | error.LinkFailure => return, | |
| 204 | error.OutOfMemory => return error.OutOfMemory, | |
| 205 | else => |e| try elf_file.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}), | |
| 206 | }; | |
| 207 | } | |
| 208 | ||
| 209 | fn parseArchiveStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void { | |
| 210 | parseArchiveStaticLib(elf_file, path) catch |err| switch (err) { | |
| 211 | error.LinkFailure => return, | |
| 212 | error.OutOfMemory => return error.OutOfMemory, | |
| 213 | else => |e| try elf_file.addParseError(path, "parsing static library failed: {s}", .{@errorName(e)}), | |
| 214 | }; | |
| 235 | 215 | } |
| 236 | 216 | |
| 237 | 217 | fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { |
src/link/MachO.zig+6-5| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | base: link.File, |
| 2 | 2 | |
| 3 | rpath_list: []const []const u8, | |
| 4 | ||
| 3 | 5 | /// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. |
| 4 | 6 | llvm_object: ?LlvmObject.Ptr = null, |
| 5 | 7 | |
| ... | ... | @@ -192,8 +194,8 @@ pub fn createEmpty( |
| 192 | 194 | .file = null, |
| 193 | 195 | .disable_lld_caching = options.disable_lld_caching, |
| 194 | 196 | .build_id = options.build_id, |
| 195 | .rpath_list = options.rpath_list, | |
| 196 | 197 | }, |
| 198 | .rpath_list = options.rpath_list, | |
| 197 | 199 | .pagezero_size = options.pagezero_size, |
| 198 | 200 | .headerpad_size = options.headerpad_size, |
| 199 | 201 | .headerpad_max_install_names = options.headerpad_max_install_names, |
| ... | ... | @@ -662,9 +664,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 662 | 664 | try argv.append(syslibroot); |
| 663 | 665 | } |
| 664 | 666 | |
| 665 | for (self.base.rpath_list) |rpath| { | |
| 666 | try argv.append("-rpath"); | |
| 667 | try argv.append(rpath); | |
| 667 | for (self.rpath_list) |rpath| { | |
| 668 | try argv.appendSlice(&.{ "-rpath", rpath }); | |
| 668 | 669 | } |
| 669 | 670 | |
| 670 | 671 | if (self.pagezero_size) |size| { |
| ... | ... | @@ -2842,7 +2843,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2842 | 2843 | ncmds += 1; |
| 2843 | 2844 | } |
| 2844 | 2845 | |
| 2845 | for (self.base.rpath_list) |rpath| { | |
| 2846 | for (self.rpath_list) |rpath| { | |
| 2846 | 2847 | try load_commands.writeRpathLC(rpath, writer); |
| 2847 | 2848 | ncmds += 1; |
| 2848 | 2849 | } |
src/link/MachO/load_commands.zig+1-1| ... | ... | @@ -63,7 +63,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32 |
| 63 | 63 | } |
| 64 | 64 | // LC_RPATH |
| 65 | 65 | { |
| 66 | for (macho_file.base.rpath_list) |rpath| { | |
| 66 | for (macho_file.rpath_list) |rpath| { | |
| 67 | 67 | sizeofcmds += calcInstallNameLen( |
| 68 | 68 | @sizeOf(macho.rpath_command), |
| 69 | 69 | rpath, |
src/link/NvPtx.zig-1| ... | ... | @@ -60,7 +60,6 @@ pub fn createEmpty( |
| 60 | 60 | .file = null, |
| 61 | 61 | .disable_lld_caching = options.disable_lld_caching, |
| 62 | 62 | .build_id = options.build_id, |
| 63 | .rpath_list = options.rpath_list, | |
| 64 | 63 | }, |
| 65 | 64 | .llvm_object = llvm_object, |
| 66 | 65 | }; |
src/link/Plan9.zig-1| ... | ... | @@ -304,7 +304,6 @@ pub fn createEmpty( |
| 304 | 304 | .file = null, |
| 305 | 305 | .disable_lld_caching = options.disable_lld_caching, |
| 306 | 306 | .build_id = options.build_id, |
| 307 | .rpath_list = options.rpath_list, | |
| 308 | 307 | }, |
| 309 | 308 | .sixtyfour_bit = sixtyfour_bit, |
| 310 | 309 | .bases = undefined, |
src/link/SpirV.zig-1| ... | ... | @@ -74,7 +74,6 @@ pub fn createEmpty( |
| 74 | 74 | .file = null, |
| 75 | 75 | .disable_lld_caching = options.disable_lld_caching, |
| 76 | 76 | .build_id = options.build_id, |
| 77 | .rpath_list = options.rpath_list, | |
| 78 | 77 | }, |
| 79 | 78 | .object = codegen.Object.init(gpa), |
| 80 | 79 | }; |
src/link/Wasm.zig-1| ... | ... | @@ -398,7 +398,6 @@ pub fn createEmpty( |
| 398 | 398 | .file = null, |
| 399 | 399 | .disable_lld_caching = options.disable_lld_caching, |
| 400 | 400 | .build_id = options.build_id, |
| 401 | .rpath_list = options.rpath_list, | |
| 402 | 401 | }, |
| 403 | 402 | .name = undefined, |
| 404 | 403 | .import_table = options.import_table, |
test/link/elf.zig+1-1| ... | ... | @@ -3916,7 +3916,7 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step { |
| 3916 | 3916 | // "note: while parsing /?/liba.dylib", |
| 3917 | 3917 | // } }); |
| 3918 | 3918 | expectLinkErrors(exe, test_step, .{ |
| 3919 | .contains = "error: unexpected error: parsing input file failed with error InvalidLdScript", | |
| 3919 | .starts_with = "error: invalid token in LD script: '\\x00\\x00\\x00\\x0c\\x00\\x00\\x00/usr/lib/dyld\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0d' (", | |
| 3920 | 3920 | }); |
| 3921 | 3921 | |
| 3922 | 3922 | return test_step; |