authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-09 01:43:57-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-09 01:43:57-07:00
logce5a5c361b5b098c3b7d68f88136a9c91e7bec19
tree713dbd96a58ada0527b2668246df813f40a09cf0
parente1e151df0d948be7464b448c61033d4c1d80d86b
parent22661f3d67251688a1fabf9e5fe65210ce284b9f
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21633 from ziglang/reduce-flush-logic

link.Elf: reduce flush logic

18 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,6 +235,7 @@ sanitize_coverage_trace_pc_guard: ?bool = null,
235pub const ExpectedCompileErrors = union(enum) {235pub const ExpectedCompileErrors = union(enum) {
236 contains: []const u8,236 contains: []const u8,
237 exact: []const []const u8,237 exact: []const []const u8,
238 starts_with: []const u8,
238};239};
239240
240pub const Entry = union(enum) {241pub const Entry = union(enum) {
...@@ -1958,6 +1959,17 @@ fn checkCompileErrors(compile: *Compile) !void {...@@ -1958,6 +1959,17 @@ fn checkCompileErrors(compile: *Compile) !void {
19581959
1959 // TODO merge this with the testing.expectEqualStrings logic, and also CheckFile1960 // TODO merge this with the testing.expectEqualStrings logic, and also CheckFile
1960 switch (expect_errors) {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 .contains => |expect_line| {1973 .contains => |expect_line| {
1962 while (actual_line_it.next()) |actual_line| {1974 while (actual_line_it.next()) |actual_line| {
1963 if (!matchCompileError(actual_line, expect_line)) continue;1975 if (!matchCompileError(actual_line, expect_line)) continue;
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-1
...@@ -67,7 +67,6 @@ pub const File = struct {...@@ -67,7 +67,6 @@ pub const File = struct {
67 gc_sections: bool,67 gc_sections: bool,
68 print_gc_sections: bool,68 print_gc_sections: bool,
69 build_id: std.zig.BuildId,69 build_id: std.zig.BuildId,
70 rpath_list: []const []const u8,
71 allow_shlib_undefined: bool,70 allow_shlib_undefined: bool,
72 stack_size: u64,71 stack_size: u64,
7372
...@@ -534,7 +533,10 @@ pub const File = struct {...@@ -534,7 +533,10 @@ pub const File = struct {
534 FailedToEmit,533 FailedToEmit,
535 FileSystem,534 FileSystem,
536 FilesOpenedWithWrongFlags,535 FilesOpenedWithWrongFlags,
536 /// Indicates an error will be present in `Compilation.link_errors`.
537 FlushFailure,537 FlushFailure,
538 /// Indicates an error will be present in `Compilation.link_errors`.
539 LinkFailure,
538 FunctionSignatureMismatch,540 FunctionSignatureMismatch,
539 GlobalTypeMismatch,541 GlobalTypeMismatch,
540 HotSwapUnavailableOnHostOperatingSystem,542 HotSwapUnavailableOnHostOperatingSystem,
src/link/C.zig-1
...@@ -148,7 +148,6 @@ pub fn createEmpty(...@@ -148,7 +148,6 @@ pub fn createEmpty(
148 .file = file,148 .file = file,
149 .disable_lld_caching = options.disable_lld_caching,149 .disable_lld_caching = options.disable_lld_caching,
150 .build_id = options.build_id,150 .build_id = options.build_id,
151 .rpath_list = options.rpath_list,
152 },151 },
153 };152 };
154153
src/link/Coff.zig-1
...@@ -263,7 +263,6 @@ pub fn createEmpty(...@@ -263,7 +263,6 @@ pub fn createEmpty(
263 .file = null,263 .file = null,
264 .disable_lld_caching = options.disable_lld_caching,264 .disable_lld_caching = options.disable_lld_caching,
265 .build_id = options.build_id,265 .build_id = options.build_id,
266 .rpath_list = options.rpath_list,
267 },266 },
268 .ptr_width = ptr_width,267 .ptr_width = ptr_width,
269 .page_size = page_size,268 .page_size = page_size,
src/link/Elf.zig+97-120
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1base: link.File,1base: link.File,
2rpath_table: std.StringArrayHashMapUnmanaged(void),
2image_base: u64,3image_base: u64,
3emit_relocs: bool,4emit_relocs: bool,
4z_nodelete: bool,5z_nodelete: bool,
...@@ -239,6 +240,11 @@ pub fn createEmpty(...@@ -239,6 +240,11 @@ pub fn createEmpty(
239 else240 else
240 try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path});241 try std.fmt.allocPrint(arena, "{s}.o", .{emit.sub_path});
241242
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 const self = try arena.create(Elf);248 const self = try arena.create(Elf);
243 self.* = .{249 self.* = .{
244 .base = .{250 .base = .{
...@@ -253,8 +259,8 @@ pub fn createEmpty(...@@ -253,8 +259,8 @@ pub fn createEmpty(
253 .file = null,259 .file = null,
254 .disable_lld_caching = options.disable_lld_caching,260 .disable_lld_caching = options.disable_lld_caching,
255 .build_id = options.build_id,261 .build_id = options.build_id,
256 .rpath_list = options.rpath_list,
257 },262 },
263 .rpath_table = rpath_table,
258 .ptr_width = ptr_width,264 .ptr_width = ptr_width,
259 .page_size = page_size,265 .page_size = page_size,
260 .default_sym_version = default_sym_version,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,8 +791,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
785 const target = self.getTarget();791 const target = self.getTarget();
786 const link_mode = comp.config.link_mode;792 const link_mode = comp.config.link_mode;
787 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.
788 const full_out_path = try directory.join(arena, &[_][]const u8{self.base.emit.sub_path});
789 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});
790 if (fs.path.dirname(full_out_path)) |dirname| {796 if (fs.path.dirname(full_out_path)) |dirname| {
791 break :blk try fs.path.join(arena, &.{ dirname, path });797 break :blk try fs.path.join(arena, &.{ dirname, path });
792 } else {798 } else {
...@@ -802,69 +808,37 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -802,69 +808,37 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
802 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);
803809
804 const csu = try CsuObjects.init(arena, comp);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 };
810811
811 // Here we will parse input positional and library files (if referenced).812 // Here we will parse object 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);
814813
815 // csu prelude814 // csu prelude
816 if (csu.crt0) |v| try positionals.append(.{ .path = v });815 if (csu.crt0) |path| try parseObjectReportingFailure(self, path);
817 if (csu.crti) |v| try positionals.append(.{ .path = v });816 if (csu.crti) |path| try parseObjectReportingFailure(self, path);
818 if (csu.crtbegin) |v| try positionals.append(.{ .path = v });817 if (csu.crtbegin) |path| try parseObjectReportingFailure(self, path);
819818
820 try positionals.ensureUnusedCapacity(comp.objects.len);819 for (comp.objects) |obj| {
821 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 }
822826
823 // 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.
824 // 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
825 // in this set.829 // in this set.
826 for (comp.c_object_table.keys()) |key| {830 for (comp.c_object_table.keys()) |key| {
827 try positionals.append(.{ .path = key.status.success.object_path });831 try parseObjectReportingFailure(self, 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, {});
838 }832 }
839833
840 if (comp.config.any_sanitize_thread) {834 if (module_obj_path) |path| try parseObjectReportingFailure(self, path);
841 try positionals.append(.{ .path = comp.tsan_lib.?.full_object_path });
842 }
843835
844 if (comp.config.any_fuzz) {836 if (comp.config.any_sanitize_thread) try parseCrtFileReportingFailure(self, comp.tsan_lib.?);
845 try positionals.append(.{ .path = comp.fuzzer_lib.?.full_object_path });837 if (comp.config.any_fuzz) try parseCrtFileReportingFailure(self, comp.fuzzer_lib.?);
846 }
847838
848 // libc839 // libc
849 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {840 if (!comp.skip_linker_dependencies and !comp.config.link_libc) {
850 if (comp.libc_static_lib) |lib| {841 if (comp.libc_static_lib) |lib| try parseCrtFileReportingFailure(self, 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 };
868 }842 }
869843
870 var system_libs = std.ArrayList(SystemLib).init(arena);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,42 +921,23 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
947 }921 }
948922
949 for (system_libs.items) |lib| {923 for (system_libs.items) |lib| {
950 self.parseLibrary(lib, false) catch |err| switch (err) {924 try self.parseLibraryReportingFailure(lib, false);
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 };
958 }925 }
959926
960 // 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).
961 positionals.clearRetainingCapacity();
962928
963 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs929 // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
964 // 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
965 // libraries, not libcompiler_rt.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 }
967937
968 // csu postlude938 // csu postlude
969 if (csu.crtend) |v| try positionals.append(.{ .path = v });939 if (csu.crtend) |path| try parseObjectReportingFailure(self, path);
970 if (csu.crtn) |v| try positionals.append(.{ .path = v });940 if (csu.crtn) |path| try parseObjectReportingFailure(self, path);
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 }
986941
987 if (self.base.hasErrors()) return error.FlushFailure;942 if (self.base.hasErrors()) return error.FlushFailure;
988943
...@@ -1024,7 +979,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1024,7 +979,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1024 self.markEhFrameAtomsDead();979 self.markEhFrameAtomsDead();
1025 try self.resolveMergeSections();980 try self.resolveMergeSections();
1026981
1027 try self.convertCommonSymbols();982 for (self.objects.items) |index| {
983 try self.file(index).?.object.convertCommonSymbols(self);
984 }
1028 self.markImportsExports();985 self.markImportsExports();
1029986
1030 if (self.base.gc_sections) {987 if (self.base.gc_sections) {
...@@ -1056,7 +1013,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod...@@ -1056,7 +1013,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
1056 try self.initSpecialPhdrs();1013 try self.initSpecialPhdrs();
1057 try self.sortShdrs();1014 try self.sortShdrs();
10581015
1059 try self.setDynamicSection(rpath_table.keys());1016 try self.setDynamicSection(self.rpath_table.keys());
1060 self.sortDynamicSymtab();1017 self.sortDynamicSymtab();
1061 try self.setHashSections();1018 try self.setHashSections();
1062 try self.setVersionSymtab();1019 try self.setVersionSymtab();
...@@ -1207,9 +1164,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1207,9 +1164,8 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1207 try argv.appendSlice(&.{ "--entry", name });1164 try argv.appendSlice(&.{ "--entry", name });
1208 }1165 }
12091166
1210 for (self.base.rpath_list) |rpath| {1167 for (self.rpath_table.keys()) |rpath| {
1211 try argv.append("-rpath");1168 try argv.appendSlice(&.{ "-rpath", rpath });
1212 try argv.append(rpath);
1213 }1169 }
12141170
1215 try argv.appendSlice(&.{1171 try argv.appendSlice(&.{
...@@ -1405,10 +1361,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {...@@ -1405,10 +1361,9 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
1405}1361}
14061362
1407pub const ParseError = error{1363pub const ParseError = error{
1408 MalformedObject,1364 /// Indicates the error is already reported on `Compilation.link_errors`.
1409 MalformedArchive,1365 LinkFailure,
1410 InvalidMachineType,1366
1411 MismatchedEflags,
1412 OutOfMemory,1367 OutOfMemory,
1413 Overflow,1368 Overflow,
1414 InputOutput,1369 InputOutput,
...@@ -1419,16 +1374,30 @@ pub const ParseError = error{...@@ -1419,16 +1374,30 @@ pub const ParseError = error{
1419 UnknownFileType,1374 UnknownFileType,
1420} || 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;
14211376
1422pub fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {1377fn parseCrtFileReportingFailure(self: *Elf, crt_file: Compilation.CRTFile) error{OutOfMemory}!void {
1423 const tracy = trace(@src());1378 if (crt_file.isObject()) {
1424 defer tracy.end();1379 try parseObjectReportingFailure(self, crt_file.full_object_path);
1425 if (try Object.isObject(path)) {
1426 try self.parseObject(path);
1427 } else {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}
14311384
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
1432fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {1401fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
1433 const tracy = trace(@src());1402 const tracy = trace(@src());
1434 defer tracy.end();1403 defer tracy.end();
...@@ -1578,8 +1547,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1578,8 +1547,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1578 .needed = scr_obj.needed,1547 .needed = scr_obj.needed,
1579 .path = full_path,1548 .path = full_path,
1580 }, false) catch |err| switch (err) {1549 }, false) catch |err| switch (err) {
1581 error.MalformedObject, error.MalformedArchive, error.InvalidMachineType => continue, // already reported1550 error.LinkFailure => continue, // already reported
1582 else => |e| try self.reportParseError(1551 else => |e| try self.addParseError(
1583 full_path,1552 full_path,
1584 "unexpected error: parsing library failed with error {s}",1553 "unexpected error: parsing library failed with error {s}",
1585 .{@errorName(e)},1554 .{@errorName(e)},
...@@ -1604,24 +1573,24 @@ pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Wor...@@ -1604,24 +1573,24 @@ pub fn validateEFlags(self: *Elf, file_index: File.Index, e_flags: elf.Elf64_Wor
1604 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;
1605 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;
16061575
1607 var is_error: bool = false;1576 var any_errors: bool = false;
1608 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {1577 if (self_riscv_eflags.fabi != riscv_eflags.fabi) {
1609 is_error = true;1578 any_errors = true;
1610 _ = try self.reportParseError2(1579 try self.addFileError(
1611 file_index,1580 file_index,
1612 "cannot link object files with different float-point ABIs",1581 "cannot link object files with different float-point ABIs",
1613 .{},1582 .{},
1614 );1583 );
1615 }1584 }
1616 if (self_riscv_eflags.rve != riscv_eflags.rve) {1585 if (self_riscv_eflags.rve != riscv_eflags.rve) {
1617 is_error = true;1586 any_errors = true;
1618 _ = try self.reportParseError2(1587 try self.addFileError(
1619 file_index,1588 file_index,
1620 "cannot link object files with different RVEs",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 else => {},1596 else => {},
...@@ -1743,12 +1712,6 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {...@@ -1743,12 +1712,6 @@ pub fn markEhFrameAtomsDead(self: *Elf) void {
1743 }1712 }
1744}1713}
17451714
1746fn convertCommonSymbols(self: *Elf) !void {
1747 for (self.objects.items) |index| {
1748 try self.file(index).?.object.convertCommonSymbols(self);
1749 }
1750}
1751
1752fn markImportsExports(self: *Elf) void {1715fn markImportsExports(self: *Elf) void {
1753 if (self.zigObjectPtr()) |zo| {1716 if (self.zigObjectPtr()) |zo| {
1754 zo.markImportsExports(self);1717 zo.markImportsExports(self);
...@@ -1978,7 +1941,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s...@@ -1978,7 +1941,7 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
1978 man.hash.add(self.emit_relocs);1941 man.hash.add(self.emit_relocs);
1979 man.hash.add(comp.config.rdynamic);1942 man.hash.add(comp.config.rdynamic);
1980 man.hash.addListOfBytes(self.lib_dirs);1943 man.hash.addListOfBytes(self.lib_dirs);
1981 man.hash.addListOfBytes(self.base.rpath_list);1944 man.hash.addListOfBytes(self.rpath_table.keys());
1982 if (output_mode == .Exe) {1945 if (output_mode == .Exe) {
1983 man.hash.add(self.base.stack_size);1946 man.hash.add(self.base.stack_size);
1984 man.hash.add(self.base.build_id);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,14 +2226,8 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
2263 if (csu.crti) |v| try argv.append(v);2226 if (csu.crti) |v| try argv.append(v);
2264 if (csu.crtbegin) |v| try argv.append(v);2227 if (csu.crtbegin) |v| try argv.append(v);
22652228
2266 // rpaths2229 for (self.rpath_table.keys()) |rpath| {
2267 var rpath_table = std.StringHashMap(void).init(gpa);2230 try argv.appendSlice(&.{ "-rpath", rpath });
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 }
2274 }2231 }
22752232
2276 for (self.symbol_wrap_set.keys()) |symbol_name| {2233 for (self.symbol_wrap_set.keys()) |symbol_name| {
...@@ -2847,7 +2804,7 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -2847,7 +2804,7 @@ pub fn resolveMergeSections(self: *Elf) !void {
2847 const file_ptr = self.file(index).?;2804 const file_ptr = self.file(index).?;
2848 if (!file_ptr.isAlive()) continue;2805 if (!file_ptr.isAlive()) continue;
2849 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {2806 file_ptr.object.initInputMergeSections(self) catch |err| switch (err) {
2850 error.MalformedObject => has_errors = true,2807 error.LinkFailure => has_errors = true,
2851 else => |e| return e,2808 else => |e| return e,
2852 };2809 };
2853 }2810 }
...@@ -2864,12 +2821,12 @@ pub fn resolveMergeSections(self: *Elf) !void {...@@ -2864,12 +2821,12 @@ pub fn resolveMergeSections(self: *Elf) !void {
2864 const file_ptr = self.file(index).?;2821 const file_ptr = self.file(index).?;
2865 if (!file_ptr.isAlive()) continue;2822 if (!file_ptr.isAlive()) continue;
2866 file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {2823 file_ptr.object.resolveMergeSubsections(self) catch |err| switch (err) {
2867 error.MalformedObject => has_errors = true,2824 error.LinkFailure => has_errors = true,
2868 else => |e| return e,2825 else => |e| return e,
2869 };2826 };
2870 }2827 }
28712828
2872 if (has_errors) return error.FlushFailure;2829 if (has_errors) return error.LinkFailure;
2873}2830}
28742831
2875pub fn finalizeMergeSections(self: *Elf) !void {2832pub fn finalizeMergeSections(self: *Elf) !void {
...@@ -5201,7 +5158,7 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {...@@ -5201,7 +5158,7 @@ fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void {
5201 });5158 });
5202}5159}
52035160
5204pub fn reportParseError(5161pub fn addParseError(
5205 self: *Elf,5162 self: *Elf,
5206 path: []const u8,5163 path: []const u8,
5207 comptime format: []const u8,5164 comptime format: []const u8,
...@@ -5212,7 +5169,7 @@ pub fn reportParseError(...@@ -5212,7 +5169,7 @@ pub fn reportParseError(
5212 try err.addNote("while parsing {s}", .{path});5169 try err.addNote("while parsing {s}", .{path});
5213}5170}
52145171
5215pub fn reportParseError2(5172pub fn addFileError(
5216 self: *Elf,5173 self: *Elf,
5217 file_index: File.Index,5174 file_index: File.Index,
5218 comptime format: []const u8,5175 comptime format: []const u8,
...@@ -5223,6 +5180,26 @@ pub fn reportParseError2(...@@ -5223,6 +5180,26 @@ pub fn reportParseError2(
5223 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});5180 try err.addNote("while parsing {}", .{self.file(file_index).?.fmtPath()});
5224}5181}
52255182
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
5226const FormatShdrCtx = struct {5203const FormatShdrCtx = struct {
5227 elf_file: *Elf,5204 elf_file: *Elf,
5228 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 {
src/link/MachO.zig+6-5
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1base: link.File,1base: link.File,
22
3rpath_list: []const []const u8,
4
3/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.5/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.
4llvm_object: ?LlvmObject.Ptr = null,6llvm_object: ?LlvmObject.Ptr = null,
57
...@@ -192,8 +194,8 @@ pub fn createEmpty(...@@ -192,8 +194,8 @@ pub fn createEmpty(
192 .file = null,194 .file = null,
193 .disable_lld_caching = options.disable_lld_caching,195 .disable_lld_caching = options.disable_lld_caching,
194 .build_id = options.build_id,196 .build_id = options.build_id,
195 .rpath_list = options.rpath_list,
196 },197 },
198 .rpath_list = options.rpath_list,
197 .pagezero_size = options.pagezero_size,199 .pagezero_size = options.pagezero_size,
198 .headerpad_size = options.headerpad_size,200 .headerpad_size = options.headerpad_size,
199 .headerpad_max_install_names = options.headerpad_max_install_names,201 .headerpad_max_install_names = options.headerpad_max_install_names,
...@@ -662,9 +664,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {...@@ -662,9 +664,8 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void {
662 try argv.append(syslibroot);664 try argv.append(syslibroot);
663 }665 }
664666
665 for (self.base.rpath_list) |rpath| {667 for (self.rpath_list) |rpath| {
666 try argv.append("-rpath");668 try argv.appendSlice(&.{ "-rpath", rpath });
667 try argv.append(rpath);
668 }669 }
669670
670 if (self.pagezero_size) |size| {671 if (self.pagezero_size) |size| {
...@@ -2842,7 +2843,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {...@@ -2842,7 +2843,7 @@ fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
2842 ncmds += 1;2843 ncmds += 1;
2843 }2844 }
28442845
2845 for (self.base.rpath_list) |rpath| {2846 for (self.rpath_list) |rpath| {
2846 try load_commands.writeRpathLC(rpath, writer);2847 try load_commands.writeRpathLC(rpath, writer);
2847 ncmds += 1;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,7 +63,7 @@ pub fn calcLoadCommandsSize(macho_file: *MachO, assume_max_path_len: bool) !u32
63 }63 }
64 // LC_RPATH64 // LC_RPATH
65 {65 {
66 for (macho_file.base.rpath_list) |rpath| {66 for (macho_file.rpath_list) |rpath| {
67 sizeofcmds += calcInstallNameLen(67 sizeofcmds += calcInstallNameLen(
68 @sizeOf(macho.rpath_command),68 @sizeOf(macho.rpath_command),
69 rpath,69 rpath,
src/link/NvPtx.zig-1
...@@ -60,7 +60,6 @@ pub fn createEmpty(...@@ -60,7 +60,6 @@ pub fn createEmpty(
60 .file = null,60 .file = null,
61 .disable_lld_caching = options.disable_lld_caching,61 .disable_lld_caching = options.disable_lld_caching,
62 .build_id = options.build_id,62 .build_id = options.build_id,
63 .rpath_list = options.rpath_list,
64 },63 },
65 .llvm_object = llvm_object,64 .llvm_object = llvm_object,
66 };65 };
src/link/Plan9.zig-1
...@@ -304,7 +304,6 @@ pub fn createEmpty(...@@ -304,7 +304,6 @@ pub fn createEmpty(
304 .file = null,304 .file = null,
305 .disable_lld_caching = options.disable_lld_caching,305 .disable_lld_caching = options.disable_lld_caching,
306 .build_id = options.build_id,306 .build_id = options.build_id,
307 .rpath_list = options.rpath_list,
308 },307 },
309 .sixtyfour_bit = sixtyfour_bit,308 .sixtyfour_bit = sixtyfour_bit,
310 .bases = undefined,309 .bases = undefined,
src/link/SpirV.zig-1
...@@ -74,7 +74,6 @@ pub fn createEmpty(...@@ -74,7 +74,6 @@ pub fn createEmpty(
74 .file = null,74 .file = null,
75 .disable_lld_caching = options.disable_lld_caching,75 .disable_lld_caching = options.disable_lld_caching,
76 .build_id = options.build_id,76 .build_id = options.build_id,
77 .rpath_list = options.rpath_list,
78 },77 },
79 .object = codegen.Object.init(gpa),78 .object = codegen.Object.init(gpa),
80 };79 };
src/link/Wasm.zig-1
...@@ -398,7 +398,6 @@ pub fn createEmpty(...@@ -398,7 +398,6 @@ pub fn createEmpty(
398 .file = null,398 .file = null,
399 .disable_lld_caching = options.disable_lld_caching,399 .disable_lld_caching = options.disable_lld_caching,
400 .build_id = options.build_id,400 .build_id = options.build_id,
401 .rpath_list = options.rpath_list,
402 },401 },
403 .name = undefined,402 .name = undefined,
404 .import_table = options.import_table,403 .import_table = options.import_table,
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 .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 });
39213921
3922 return test_step;3922 return test_step;