authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-08 17:57:14-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-08 18:02:59-07:00
log31d70cb1e11cf480f4a45afdff20e4adf0d6068b
tree384541411c9b2be3192232cb90b1d43d98351c1f
parent2c41c453b634b3d1f378f6f1b335314f0a4be2de

link.Elf: avoid needless file system reads in flush()

flush() must not do anything more than necessary. Determining the type of input files must be done only once, before flush. Fortunately, we don't even need any file system accesses to do this since that information is statically known in most cases, and in the rest of the cases can be determined by file extension alone. This commit also updates the nearby code to conform to the convention for error handling where there is exactly one error code to represent the fact that error messages have already been emitted. This had the side effect of improving the error message for a linker script parse error. "positionals" is not a linker concept; it is a command line interface concept. Zig's linker implementation should not mention "positionals". This commit deletes that array list in favor of directly making function calls, eliminating that heap allocation during flush().

9 files changed, 169 insertions(+), 233 deletions(-)

src/Compilation.zig+15-1
...@@ -280,6 +280,13 @@ pub const CRTFile = struct {...@@ -280,6 +280,13 @@ pub const CRTFile = struct {
280 lock: Cache.Lock,280 lock: Cache.Lock,
281 full_object_path: []const u8,281 full_object_path: []const u8,
282282
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 pub fn deinit(self: *CRTFile, gpa: Allocator) void {290 pub fn deinit(self: *CRTFile, gpa: Allocator) void {
284 self.lock.release();291 self.lock.release();
285 gpa.free(self.full_object_path);292 gpa.free(self.full_object_path);
...@@ -1018,6 +1025,13 @@ pub const LinkObject = struct {...@@ -1018,6 +1025,13 @@ pub const LinkObject = struct {
1018 //1025 //
1019 // Consistent with `withLOption` variable name in lld ELF driver.1026 // Consistent with `withLOption` variable name in lld ELF driver.
1020 loption: bool = false,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};
10221036
1023pub const CreateOptions = struct {1037pub const CreateOptions = struct {
...@@ -2433,7 +2447,7 @@ fn flush(...@@ -2433,7 +2447,7 @@ fn flush(
2433 if (comp.bin_file) |lf| {2447 if (comp.bin_file) |lf| {
2434 // This is needed before reading the error flags.2448 // This is needed before reading the error flags.
2435 lf.flush(arena, tid, prog_node) catch |err| switch (err) {2449 lf.flush(arena, tid, prog_node) catch |err| switch (err) {
2436 error.FlushFailure => {}, // error reported through link_error_flags2450 error.FlushFailure, error.LinkFailure => {}, // error reported through link_error_flags
2437 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr2451 error.LLDReportedFailure => {}, // error reported via lockAndParseLldStderr
2438 else => |e| return e,2452 else => |e| return e,
2439 };2453 };
src/link.zig+3
...@@ -533,7 +533,10 @@ pub const File = struct {...@@ -533,7 +533,10 @@ pub const File = struct {
533 FailedToEmit,533 FailedToEmit,
534 FileSystem,534 FileSystem,
535 FilesOpenedWithWrongFlags,535 FilesOpenedWithWrongFlags,
536 /// Indicates an error will be present in `Compilation.link_errors`.
536 FlushFailure,537 FlushFailure,
538 /// Indicates an error will be present in `Compilation.link_errors`.
539 LinkFailure,
537 FunctionSignatureMismatch,540 FunctionSignatureMismatch,
538 GlobalTypeMismatch,541 GlobalTypeMismatch,
539 HotSwapUnavailableOnHostOperatingSystem,542 HotSwapUnavailableOnHostOperatingSystem,
src/link/Elf.zig+84-98
...@@ -791,8 +791,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -791,8 +791,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
791 const target = self.getTarget();791 const target = self.getTarget();
792 const link_mode = comp.config.link_mode;792 const link_mode = comp.config.link_mode;
793 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.793 const directory = self.base.emit.root_dir; // Just an alias to make it shorter to type.
794 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
795 const module_obj_path: ?[]const u8 = if (self.base.zcu_object_sub_path) |path| blk: {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});
796 if (fs.path.dirname(full_out_path)) |dirname| {796 if (fs.path.dirname(full_out_path)) |dirname| {
797 break :blk try fs.path.join(arena, &.{ dirname, path });797 break :blk try fs.path.join(arena, &.{ dirname, path });
798 } else {798 } else {
...@@ -808,61 +808,37 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -808,61 +808,37 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
808 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);808 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
809809
810 const csu = try CsuObjects.init(arena, comp);810 const csu = try CsuObjects.init(arena, comp);
811 const compiler_rt_path: ?[]const u8 = blk: {
812 if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
813 if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
814 break :blk null;
815 };
816811
817 // Here we will parse input positional and library files (if referenced).812 // Here we will parse object and library files (if referenced).
818 // This will roughly match in any linker backend we support.
819 var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
820813
821 // csu prelude814 // csu prelude
822 if (csu.crt0) |v| try positionals.append(.{ .path = v });815 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
823 if (csu.crti) |v| try positionals.append(.{ .path = v });816 if (csu.crti) |path| try parseObjectReportingFailure(self, path);
824 if (csu.crtbegin) |v| try positionals.append(.{ .path = v });817 if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path);
825818
826 try positionals.ensureUnusedCapacity(comp.objects.len);819 for (comp.objects) |obj| {
827 positionals.appendSliceAssumeCapacity(comp.objects);820 if (obj.isObject()) {
821 try parseObjectReportingFailure(self, obj.path);
822 } else {
823 try parseLibraryReportingFailure(self, .{ .path = obj.path }, obj.must_link);
824 }
825 }
828826
829 // This is a set of object files emitted by clang in a single `build-exe` invocation.827 // This is a set of object files emitted by clang in a single `build-exe` invocation.
830 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up828 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
831 // in this set.829 // in this set.
832 for (comp.c_object_table.keys()) |key| {830 for (comp.c_object_table.keys()) |key| {
833 try positionals.append(.{ .path = key.status.success.object_path });831 try parseObjectReportingFailure(self, key.status.success.object_path);
834 }832 }
835833
836 if (module_obj_path) |path| try positionals.append(.{ .path = path });834 if (module_obj_path) |path| try parseObjectReportingFailure(self, path);
837
838 if (comp.config.any_sanitize_thread) {
839 try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
840 }
841835
842 if (comp.config.any_fuzz) {836 if (comp.config.any_sanitize_thread) try parseCrtFileReportingFailure(self, comp.tsan_lib.?);
843 try positionals.append(.{ .path = comp.fuzzer_lib.?.full_object_path });837 if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
844 }
845838
846 // libc839 // libc
847 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {840 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
848 if (comp.libc_static_lib) |lib| {841 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, lib);
849 try positionals.append(.{ .path = lib.full_object_path });
850 }
851 }
852
853 for (positionals.items) |obj| {
854 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
855 error.MalformedObject,
856 error.MalformedArchive,
857 error.MismatchedEflags,
858 error.InvalidMachineType,
859 => continue, // already reported
860 else => |e| try self.reportParseError(
861 obj.path,
862 "unexpected error: parsing input file failed with error {s}",
863 .{@errorName(e)},
864 ),
865 };
866 }842 }
867843
868 var system_libs = std.ArrayList(SystemLib).init(arena);844 var system_libs = std.ArrayList(SystemLib).init(arena);
...@@ -945,42 +921,23 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -945,42 +921,23 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
945 }921 }
946922
947 for (system_libs.items) |lib| {923 for (system_libs.items) |lib| {
948 self.parseLibrary(lib, false) catch |err| switch (err) {924 try self.parseLibraryReportingFailure(lib, false);
949 error.MalformedObject, error.MalformedArchive, error.InvalidMachineType => continue, // already reported
950 else => |e| try self.reportParseError(
951 lib.path,
952 "unexpected error: parsing library failed with error {s}",
953 .{@errorName(e)},
954 ),
955 };
956 }925 }
957926
958 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).927 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
959 positionals.clearRetainingCapacity();
960928
961 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs929 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
962 // to be after the shared libraries, so they are picked up from the shared930 // to be after the shared libraries, so they are picked up from the shared
963 // libraries, not libcompiler_rt.931 // libraries, not libcompiler_rt.
964 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 }
965937
966 // csu postlude938 // csu postlude
967 if (csu.crtend) |v| try positionals.append(.{ .path = v });939 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);
968 if (csu.crtn) |v| try positionals.append(.{ .path = v });940 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);
969
970 for (positionals.items) |obj| {
971 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
972 error.MalformedObject,
973 error.MalformedArchive,
974 error.MismatchedEflags,
975 error.InvalidMachineType,
976 => continue, // already reported
977 else => |e| try self.reportParseError(
978 obj.path,
979 "unexpected error: parsing input file failed with error {s}",
980 .{@errorName(e)},
981 ),
982 };
983 }
984941
985 if (self.base.hasErrors()) return error.FlushFailure;942 if (self.base.hasErrors()) return error.FlushFailure;
986943
...@@ -1022,7 +979,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1022,7 +979,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1022 self.markEhFrameAtomsDead();979 self.markEhFrameAtomsDead();
1023 try self.resolveMergeSections();980 try self.resolveMergeSections();
1024981
1025 try self.convertCommonSymbols();982 for (self.objects.items) |index| {
983 try self.file(index).?.object.convertCommonSymbols(self);
984 }
1026 self.markImportsExports();985 self.markImportsExports();
1027986
1028 if (self.base.gc_sections) {987 if (self.base.gc_sections) {
...@@ -1402,10 +1361,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1402,10 +1361,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1402}1361}
14031362
1404pub const ParseError = error{1363pub const ParseError = error{
1405 MalformedObject,1364 /// Indicates the error is already reported on `Compilation.link_errors`.
1406 MalformedArchive,1365 LinkFailure,
1407 InvalidMachineType,1366
1408 MismatchedEflags,
1409 OutOfMemory,1367 OutOfMemory,
1410 Overflow,1368 Overflow,
1411 InputOutput,1369 InputOutput,
...@@ -1416,16 +1374,30 @@ pub const ParseError = error{...@@ -1416,16 +1374,30 @@ pub const ParseError = error{
1416 UnknownFileType,1374 UnknownFileType,
1417} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;1375} || LdScript.Error || fs.Dir.AccessError || fs.File.SeekError || fs.File.OpenError || fs.File.ReadError;
14181376
1419pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {1377fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error{OutOfMemory}!void {
1420 const tracy = trace(@src());1378 if (crt_file.isObject()) {
1421 defer tracy.end();1379 try parseObjectReportingFailure(self, crt_file.full_object_path);
1422 if (try Object.isObject(path)) {
1423 try self.parseObject(path);
1424 } else {1380 } else {
1425 try self.parseLibrary(.{ .path = path }, must_link);1381 try parseLibraryReportingFailure(self, .{ .path = crt_file.full_object_path }, false);
1426 }1382 }
1427}1383}
14281384
1385pub 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
1393pub 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
1429fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {1401fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
1430 const tracy = trace(@src());1402 const tracy = trace(@src());
1431 defer tracy.end();1403 defer tracy.end();
...@@ -1575,8 +1547,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1575,8 +1547,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1575 .needed = scr_obj.needed,1547 .needed = scr_obj.needed,
1576 .path = full_path,1548 .path = full_path,
1577 }, false) catch |err| switch (err) {1549 }, false) catch |err| switch (err) {
1578 error.MalformedObject, error.MalformedArchive, error.InvalidMachineType => continue, // already reported1550 error.LinkFailure => continue, // already reported
1579 else => |e| try self.reportParseError(1551 else => |e| try self.addParseError(
1580 full_path,1552 full_path,
1581 "unexpected error: parsing library failed with error {s}",1553 "unexpected error: parsing library failed with error {s}",
1582 .{@errorName(e)},1554 .{@errorName(e)},
...@@ -1601,24 +1573,24 @@ pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Wor...@@ -1601,24 +1573,24 @@ pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Wor
1601 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;1573 self_riscv_eflags.rvc = self_riscv_eflags.rvc or riscv_eflags.rvc;
1602 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;1574 self_riscv_eflags.tso = self_riscv_eflags.tso or riscv_eflags.tso;
16031575
1604 var is_error: bool = false;1576 var any_errors: bool = false;
1605 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {1577 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
1606 is_error = true;1578 any_errors = true;
1607 _ = try self.reportParseError2(1579 try self.addFileError(
1608 file_index,1580 file_index,
1609 "cannot link object files with different float-point ABIs",1581 "cannot link object files with different float-point ABIs",
1610 .{},1582 .{},
1611 );1583 );
1612 }1584 }
1613 if (self_riscv_eflags.rve != riscv_eflags.rve) {1585 if (self_riscv_eflags.rve != riscv_eflags.rve) {
1614 is_error = true;1586 any_errors = true;
1615 _ = try self.reportParseError2(1587 try self.addFileError(
1616 file_index,1588 file_index,
1617 "cannot link object files with different RVEs",1589 "cannot link object files with different RVEs",
1618 .{},1590 .{},
1619 );1591 );
1620 }1592 }
1621 if (is_error) return error.MismatchedEflags;1593 if (any_errors) return error.LinkFailure;
1622 }1594 }
1623 },1595 },
1624 else => {},1596 else => {},
...@@ -1740,12 +1712,6 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {...@@ -1740,12 +1712,6 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {
1740 }1712 }
1741}1713}
17421714
1743fn convertCommonSymbols(self: *Elf) !void {
1744 for (self.objects.items) |index| {
1745 try self.file(index).?.object.convertCommonSymbols(self);
1746 }
1747}
1748
1749fn markImportsExports(self: *Elf) void {1715fn markImportsExports(self: *Elf) void {
1750 if (self.zigObjectPtr()) |zo| {1716 if (self.zigObjectPtr()) |zo| {
1751 zo.markImportsExports(self);1717 zo.markImportsExports(self);
...@@ -2838,7 +2804,7 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -2838,7 +2804,7 @@ pub fn resolveMergeSections(self: *Elf) !void {
2838 const file_ptr = self.file(index).?;2804 const file_ptr = self.file(index).?;
2839 if (!file_ptr.isAlive()) continue;2805 if (!file_ptr.isAlive()) continue;
2840 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {2806 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {
2841 error.MalformedObject => has_errors = true,2807 error.LinkFailure => has_errors = true,
2842 else => |e| return e,2808 else => |e| return e,
2843 };2809 };
2844 }2810 }
...@@ -2855,12 +2821,12 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -2855,12 +2821,12 @@ pub fn resolveMergeSections(self: *Elf) !void {
2855 const file_ptr = self.file(index).?;2821 const file_ptr = self.file(index).?;
2856 if (!file_ptr.isAlive()) continue;2822 if (!file_ptr.isAlive()) continue;
2857 file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {2823 file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {
2858 error.MalformedObject => has_errors = true,2824 error.LinkFailure => has_errors = true,
2859 else => |e| return e,2825 else => |e| return e,
2860 };2826 };
2861 }2827 }
28622828
2863 if (has_errors) return error.FlushFailure;2829 if (has_errors) return error.LinkFailure;
2864}2830}
28652831
2866pub fn finalizeMergeSections(self: *Elf) !void {2832pub fn finalizeMergeSections(self: *Elf) !void {
...@@ -5192,7 +5158,7 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {...@@ -5192,7 +5158,7 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
5192 });5158 });
5193}5159}
51945160
5195pub fn reportParseError(5161pub fn addParseError(
5196 self: *Elf,5162 self: *Elf,
5197 path: []const u8,5163 path: []const u8,
5198 comptime format: []const u8,5164 comptime format: []const u8,
...@@ -5203,7 +5169,7 @@ pub fn reportParseError(...@@ -5203,7 +5169,7 @@ pub fn reportParseError(
5203 try err.addNote("while parsing {s}", .{path});5169 try err.addNote("while parsing {s}", .{path});
5204}5170}
52055171
5206pub fn reportParseError2(5172pub fn addFileError(
5207 self: *Elf,5173 self: *Elf,
5208 file_index: File.Index,5174 file_index: File.Index,
5209 comptime format: []const u8,5175 comptime format: []const u8,
...@@ -5214,6 +5180,26 @@ pub fn reportParseError2(...@@ -5214,6 +5180,26 @@ pub fn reportParseError2(
5214 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});5180 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
5215}5181}
52165182
5183pub 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
5193pub 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
5217const FormatShdrCtx = struct {5203const FormatShdrCtx = struct {
5218 elf_file: *Elf,5204 elf_file: *Elf,
5219 shdr: elf.Elf64_Shdr,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,10 +35,9 @@ pub fn parse(self: *Archive, elf_file: *Elf, path: []const u8, handle_index: Fil
35 pos += @sizeOf(elf.ar_hdr);35 pos += @sizeOf(elf.ar_hdr);
3636
37 if (!mem.eql(u8, &hdr.ar_fmag, elf.ARFMAG)) {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 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),39 std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
40 });40 });
41 return error.MalformedArchive;
42 }41 }
4342
44 const obj_size = try hdr.size();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 +7,7 @@ pub fn deinit(scr: *LdScript, allocator: Allocator) void {
7}7}
88
9pub const Error = error{9pub const Error = error{
10 InvalidLdScript,10 LinkFailure,
11 UnexpectedToken,11 UnexpectedToken,
12 UnknownCpuArch,12 UnknownCpuArch,
13 OutOfMemory,13 OutOfMemory,
...@@ -32,12 +32,9 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -32,12 +32,9 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
32 try line_col.append(.{ .line = line, .column = column });32 try line_col.append(.{ .line = line, .column = column });
33 switch (tok.id) {33 switch (tok.id) {
34 .invalid => {34 .invalid => {
35 try elf_file.reportParseError(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{35 return elf_file.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
36 std.fmt.fmtSliceEscapeLower(tok.get(data)),36 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
37 line,
38 column,
39 });37 });
40 return error.InvalidLdScript;
41 },38 },
42 .new_line => {39 .new_line => {
43 line += 1;40 line += 1;
...@@ -59,13 +56,12 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -59,13 +56,12 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
59 const last_token_id = parser.it.pos - 1;56 const last_token_id = parser.it.pos - 1;
60 const last_token = parser.it.get(last_token_id);57 const last_token = parser.it.get(last_token_id);
61 const lcol = line_col.items[last_token_id];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 @tagName(last_token.id),60 @tagName(last_token.id),
64 last_token.get(data),61 last_token.get(data),
65 lcol.line,62 lcol.line,
66 lcol.column,63 lcol.column,
67 });64 });
68 return error.InvalidLdScript;
69 },65 },
70 else => |e| return e,66 else => |e| return e,
71 };67 };
src/link/Elf/Object.zig+20-53
...@@ -34,18 +34,6 @@ num_dynrelocs: u32 = 0,...@@ -34,18 +34,6 @@ num_dynrelocs: u32 = 0,
34output_symtab_ctx: Elf.SymtabCtx = .{},34output_symtab_ctx: Elf.SymtabCtx = .{},
35output_ar_state: Archive.ArState = .{},35output_ar_state: Archive.ArState = .{},
3636
37pub 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
49pub fn deinit(self: *Object, allocator: Allocator) void {37pub fn deinit(self: *Object, allocator: Allocator) void {
50 if (self.archive) |*ar| allocator.free(ar.path);38 if (self.archive) |*ar| allocator.free(ar.path);
51 allocator.free(self.path);39 allocator.free(self.path);
...@@ -107,12 +95,9 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil...@@ -107,12 +95,9 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
10795
108 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();96 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();
109 if (em != self.header.?.e_machine) {97 if (em != self.header.?.e_machine) {
110 try elf_file.reportParseError2(98 return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{
111 self.index,99 @tagName(self.header.?.e_machine),
112 "invalid ELF machine type: {s}",100 });
113 .{@tagName(self.header.?.e_machine)},
114 );
115 return error.InvalidMachineType;
116 }101 }
117 try elf_file.validateEFlags(self.index, self.header.?.e_flags);102 try elf_file.validateEFlags(self.index, self.header.?.e_flags);
118103
...@@ -122,12 +107,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil...@@ -122,12 +107,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
122 const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;107 const shnum = math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
123 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);108 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
124 if (file_size < offset + shoff or file_size < offset + shoff + shsize) {109 if (file_size < offset + shoff or file_size < offset + shoff + shsize) {
125 try elf_file.reportParseError2(110 return elf_file.failFile(self.index, "corrupt header: section header table extends past the end of file", .{});
126 self.index,
127 "corrupt header: section header table extends past the end of file",
128 .{},
129 );
130 return error.MalformedObject;
131 }111 }
132112
133 const shdrs_buffer = try Elf.preadAllAlloc(allocator, handle, offset + shoff, shsize);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,8 +118,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
138 for (self.shdrs.items) |shdr| {118 for (self.shdrs.items) |shdr| {
139 if (shdr.sh_type != elf.SHT_NOBITS) {119 if (shdr.sh_type != elf.SHT_NOBITS) {
140 if (file_size < offset + shdr.sh_offset or file_size < offset + shdr.sh_offset + shdr.sh_size) {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", .{});121 return elf_file.failFile(self.index, "corrupt section: extends past the end of file", .{});
142 return error.MalformedObject;
143 }122 }
144 }123 }
145 }124 }
...@@ -148,8 +127,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil...@@ -148,8 +127,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
148 defer allocator.free(shstrtab);127 defer allocator.free(shstrtab);
149 for (self.shdrs.items) |shdr| {128 for (self.shdrs.items) |shdr| {
150 if (shdr.sh_name >= shstrtab.len) {129 if (shdr.sh_name >= shstrtab.len) {
151 try elf_file.reportParseError2(self.index, "corrupt section name offset", .{});130 return elf_file.failFile(self.index, "corrupt section name offset", .{});
152 return error.MalformedObject;
153 }131 }
154 }132 }
155 try self.strtab.appendSlice(allocator, shstrtab);133 try self.strtab.appendSlice(allocator, shstrtab);
...@@ -166,8 +144,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil...@@ -166,8 +144,7 @@ fn parseCommon(self: *Object, allocator: Allocator, handle: std.fs.File, elf_fil
166 const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index);144 const raw_symtab = try self.preadShdrContentsAlloc(allocator, handle, index);
167 defer allocator.free(raw_symtab);145 defer allocator.free(raw_symtab);
168 const nsyms = math.divExact(usize, raw_symtab.len, @sizeOf(elf.Elf64_Sym)) catch {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", .{});147 return elf_file.failFile(self.index, "symbol table not evenly divisible", .{});
170 return error.MalformedObject;
171 };148 };
172 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];149 const symtab = @as([*]align(1) const elf.Elf64_Sym, @ptrCast(raw_symtab.ptr))[0..nsyms];
173150
...@@ -221,30 +198,15 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:...@@ -221,30 +198,15 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file:
221 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);198 const group_raw_data = try self.preadShdrContentsAlloc(allocator, handle, shndx);
222 defer allocator.free(group_raw_data);199 defer allocator.free(group_raw_data);
223 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {200 const group_nmembers = math.divExact(usize, group_raw_data.len, @sizeOf(u32)) catch {
224 try elf_file.reportParseError2(201 return elf_file.failFile(self.index, "corrupt section group: not evenly divisible ", .{});
225 self.index,
226 "corrupt section group: not evenly divisible ",
227 .{},
228 );
229 return error.MalformedObject;
230 };202 };
231 if (group_nmembers == 0) {203 if (group_nmembers == 0) {
232 try elf_file.reportParseError2(204 return elf_file.failFile(self.index, "corrupt section group: empty section", .{});
233 self.index,
234 "corrupt section group: empty section",
235 .{},
236 );
237 return error.MalformedObject;
238 }205 }
239 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];206 const group_members = @as([*]align(1) const u32, @ptrCast(group_raw_data.ptr))[0..group_nmembers];
240207
241 if (group_members[0] != elf.GRP_COMDAT) {208 if (group_members[0] != elf.GRP_COMDAT) {
242 try elf_file.reportParseError2(209 return elf_file.failFile(self.index, "corrupt section group: unknown SHT_GROUP format", .{});
243 self.index,
244 "corrupt section group: unknown SHT_GROUP format",
245 .{},
246 );
247 return error.MalformedObject;
248 }210 }
249211
250 const group_start = @as(u32, @intCast(self.comdat_group_data.items.len));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,7 +684,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
722 var err = try elf_file.base.addErrorWithNotes(1);684 var err = try elf_file.base.addErrorWithNotes(1);
723 try err.addMsg("string not null terminated", .{});685 try err.addMsg("string not null terminated", .{});
724 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });686 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
725 return error.MalformedObject;687 return error.LinkFailure;
726 }688 }
727 end += sh_entsize;689 end += sh_entsize;
728 const string = data[start..end];690 const string = data[start..end];
...@@ -737,7 +699,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -737,7 +699,7 @@ pub fn initInputMergeSections(self: *Object, elf_file: *Elf) !void {
737 var err = try elf_file.base.addErrorWithNotes(1);699 var err = try elf_file.base.addErrorWithNotes(1);
738 try err.addMsg("size not a multiple of sh_entsize", .{});700 try err.addMsg("size not a multiple of sh_entsize", .{});
739 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });701 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
740 return error.MalformedObject;702 return error.LinkFailure;
741 }703 }
742704
743 var pos: u32 = 0;705 var pos: u32 = 0;
...@@ -765,7 +727,12 @@ pub fn initOutputMergeSections(self: *Object, elf_file: *Elf) !void {...@@ -765,7 +727,12 @@ pub fn initOutputMergeSections(self: *Object, elf_file: *Elf) !void {
765 }727 }
766}728}
767729
768pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {730pub 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 const gpa = elf_file.base.comp.gpa;736 const gpa = elf_file.base.comp.gpa;
770737
771 for (self.input_merge_sections_indexes.items) |index| {738 for (self.input_merge_sections_indexes.items) |index| {
...@@ -809,7 +776,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {...@@ -809,7 +776,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
809 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});776 try err.addMsg("invalid symbol value: {x}", .{esym.st_value});
810 try err.addNote("for symbol {s}", .{sym.name(elf_file)});777 try err.addNote("for symbol {s}", .{sym.name(elf_file)});
811 try err.addNote("in {}", .{self.fmtPath()});778 try err.addNote("in {}", .{self.fmtPath()});
812 return error.MalformedObject;779 return error.LinkFailure;
813 };780 };
814781
815 sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };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,7 +801,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
834 var err = try elf_file.base.addErrorWithNotes(1);801 var err = try elf_file.base.addErrorWithNotes(1);
835 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});802 try err.addMsg("invalid relocation at offset 0x{x}", .{rel.r_offset});
836 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });803 try err.addNote("in {}:{s}", .{ self.fmtPath(), atom_ptr.name(elf_file) });
837 return error.MalformedObject;804 return error.LinkFailure;
838 };805 };
839806
840 const sym_index = try self.addSymbol(gpa);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,24 +58,16 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
5858
59 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();59 const em = elf_file.base.comp.root_mod.resolved_target.result.toElfMachine();
60 if (em != self.header.?.e_machine) {60 if (em != self.header.?.e_machine) {
61 try elf_file.reportParseError2(61 return elf_file.failFile(self.index, "invalid ELF machine type: {s}", .{
62 self.index,62 @tagName(self.header.?.e_machine),
63 "invalid ELF machine type: {s}",63 });
64 .{@tagName(self.header.?.e_machine)},
65 );
66 return error.InvalidMachineType;
67 }64 }
6865
69 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;66 const shoff = std.math.cast(usize, self.header.?.e_shoff) orelse return error.Overflow;
70 const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;67 const shnum = std.math.cast(usize, self.header.?.e_shnum) orelse return error.Overflow;
71 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);68 const shsize = shnum * @sizeOf(elf.Elf64_Shdr);
72 if (file_size < shoff or file_size < shoff + shsize) {69 if (file_size < shoff or file_size < shoff + shsize) {
73 try elf_file.reportParseError2(70 return elf_file.failFile(self.index, "corrupted header: section header table extends past the end of file", .{});
74 self.index,
75 "corrupted header: section header table extends past the end of file",
76 .{},
77 );
78 return error.MalformedObject;
79 }71 }
8072
81 const shdrs_buffer = try Elf.preadAllAlloc(gpa, handle, shoff, shsize);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,8 +82,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
90 for (self.shdrs.items, 0..) |shdr, i| {82 for (self.shdrs.items, 0..) |shdr, i| {
91 if (shdr.sh_type != elf.SHT_NOBITS) {83 if (shdr.sh_type != elf.SHT_NOBITS) {
92 if (file_size < shdr.sh_offset or file_size < shdr.sh_offset + shdr.sh_size) {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", .{});85 return elf_file.failFile(self.index, "corrupted section header", .{});
94 return error.MalformedObject;
95 }86 }
96 }87 }
97 switch (shdr.sh_type) {88 switch (shdr.sh_type) {
src/link/Elf/relocatable.zig+36-56
...@@ -1,36 +1,24 @@...@@ -1,36 +1,24 @@
1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {1pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
2 const gpa = comp.gpa;2 const gpa = comp.gpa;
33
4 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);4 for (comp.objects) |obj| {
5 defer positionals.deinit();5 switch (Compilation.classifyFileExt(obj.path)) {
66 .object => try parseObjectStaticLibReportingFailure(elf_file, obj.path),
7 try positionals.ensureUnusedCapacity(comp.objects.len);7 .static_library => try parseArchiveStaticLibReportingFailure(elf_file, obj.path),
8 positionals.appendSliceAssumeCapacity(comp.objects);8 else => try elf_file.addParseError(obj.path, "unrecognized file extension", .{}),
9 }
10 }
911
10 for (comp.c_object_table.keys()) |key| {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 }
1315
14 if (module_obj_path) |path| try positionals.append(.{ .path = path });16 if (module_obj_path) |path| {
17 try parseObjectStaticLibReportingFailure(elf_file, path);
18 }
1519
16 if (comp.include_compiler_rt) {20 if (comp.include_compiler_rt) {
17 try positionals.append(.{ .path = comp.compiler_rt_obj.?.full_object_path });21 try parseObjectStaticLibReportingFailure(elf_file, 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 };
34 }22 }
3523
36 if (elf_file.base.hasErrors()) return error.FlushFailure;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,37 +141,23 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
153}141}
154142
155pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {143pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void {
156 const gpa = elf_file.base.comp.gpa;144 for (comp.objects) |obj| {
157145 if (obj.isObject()) {
158 var positionals = std.ArrayList(Compilation.LinkObject).init(gpa);146 try elf_file.parseObjectReportingFailure(obj.path);
159 defer positionals.deinit();147 } else {
160 try positionals.ensureUnusedCapacity(comp.objects.len);148 try elf_file.parseLibraryReportingFailure(.{ .path = obj.path }, obj.must_link);
161 positionals.appendSliceAssumeCapacity(comp.objects);149 }
150 }
162151
163 // This is a set of object files emitted by clang in a single `build-exe` invocation.152 // This is a set of object files emitted by clang in a single `build-exe` invocation.
164 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up153 // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
165 // in this set.154 // in this set.
166 for (comp.c_object_table.keys()) |key| {155 for (comp.c_object_table.keys()) |key| {
167 try positionals.append(.{ .path = key.status.success.object_path });156 try elf_file.parseObjectReportingFailure(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 };
185 }157 }
186158
159 if (module_obj_path) |path| try elf_file.parseObjectReportingFailure(path);
160
187 if (elf_file.base.hasErrors()) return error.FlushFailure;161 if (elf_file.base.hasErrors()) return error.FlushFailure;
188162
189 // Now, we are ready to resolve the symbols across all input files.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,14 +198,20 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const
224 if (elf_file.base.hasErrors()) return error.FlushFailure;198 if (elf_file.base.hasErrors()) return error.FlushFailure;
225}199}
226200
227fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {201fn parseObjectStaticLibReportingFailure(elf_file: *Elf, path: []const u8) error{OutOfMemory}!void {
228 if (try Object.isObject(path)) {202 parseObjectStaticLib(elf_file, path) catch |err| switch (err) {
229 try parseObjectStaticLib(elf_file, path);203 error.LinkFailure => return,
230 } else if (try Archive.isArchive(path)) {204 error.OutOfMemory => return error.OutOfMemory,
231 try parseArchiveStaticLib(elf_file, path);205 else => |e| try elf_file.addParseError(path, "parsing object failed: {s}", .{@errorName(e)}),
232 } else return error.UnknownFileType;206 };
233 // TODO: should we check for LD script?207}
234 // Actually, should we even unpack an archive?208
209fn 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}
236216
237fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {217fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void {
test/link/elf.zig+1-1
...@@ -3916,7 +3916,7 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {...@@ -3916,7 +3916,7 @@ fn testUnknownFileTypeError(b: *Build, opts: Options) *Step {
3916 // "note: while parsing /?/liba.dylib",3916 // "note: while parsing /?/liba.dylib",
3917 // } });3917 // } });
3918 expectLinkErrors(exe, test_step, .{3918 expectLinkErrors(exe, test_step, .{
3919 .contains = "error: unexpected error: parsing input file failed with error InvalidLdScript",3919 .contains = "error: invalid token in LD script: '\\x00\\x00\\x00\\x0c\\x00\\x00\\x00/usr/lib/dyld\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x0d' (0:1069)",
3920 });3920 });
39213921
3922 return test_step;3922 return test_step;