authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-12-05 13:49:55+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-12-05 13:49:55+01:00
log3f42ed3ca25d6ef32c92a8ed43129b789cf846c5
treefacf0de891161731d209fa865a96996c784b15bf
parentaf8621db2d2de4675240dad0ff885f23dc33f518

elf: do not write ELF header if there were errors


2 files changed, 70 insertions(+), 70 deletions(-)

src/link/Elf.zig+61-70
...@@ -1041,9 +1041,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1041,9 +1041,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1041 }1041 }
10421042
1043 for (positionals.items) |obj| {1043 for (positionals.items) |obj| {
1044 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1044 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
1045 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1045 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1046 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1046 else => |e| try self.reportParseError(
1047 obj.path,
1048 "unexpected error: parsing input file failed with error {s}",
1049 .{@errorName(e)},
1050 ),
1051 };
1047 }1052 }
10481053
1049 var system_libs = std.ArrayList(SystemLib).init(arena);1054 var system_libs = std.ArrayList(SystemLib).init(arena);
...@@ -1122,9 +1127,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1122,9 +1127,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1122 }1127 }
11231128
1124 for (system_libs.items) |lib| {1129 for (system_libs.items) |lib| {
1125 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1130 self.parseLibrary(lib, false) catch |err| switch (err) {
1126 self.parseLibrary(lib, false, &parse_ctx) catch |err|1131 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1127 try self.handleAndReportParseError(lib.path, err, &parse_ctx);1132 else => |e| try self.reportParseError(
1133 lib.path,
1134 "unexpected error: parsing library failed with error {s}",
1135 .{@errorName(e)},
1136 ),
1137 };
1128 }1138 }
11291139
1130 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).1140 // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
...@@ -1140,9 +1150,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1140,9 +1150,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1140 if (csu.crtn) |v| try positionals.append(.{ .path = v });1150 if (csu.crtn) |v| try positionals.append(.{ .path = v });
11411151
1142 for (positionals.items) |obj| {1152 for (positionals.items) |obj| {
1143 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1153 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
1144 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1154 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1145 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1155 else => |e| try self.reportParseError(
1156 obj.path,
1157 "unexpected error: parsing input file failed with error {s}",
1158 .{@errorName(e)},
1159 ),
1160 };
1146 }1161 }
11471162
1148 // Init all objects1163 // Init all objects
...@@ -1300,9 +1315,14 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const...@@ -1300,9 +1315,14 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const
1300 if (module_obj_path) |path| try positionals.append(.{ .path = path });1315 if (module_obj_path) |path| try positionals.append(.{ .path = path });
13011316
1302 for (positionals.items) |obj| {1317 for (positionals.items) |obj| {
1303 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1318 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
1304 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1319 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1305 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1320 else => |e| try self.reportParseError(
1321 obj.path,
1322 "unexpected error: parsing input file failed with error {s}",
1323 .{@errorName(e)},
1324 ),
1325 };
1306 }1326 }
13071327
1308 // First, we flush relocatable object file generated with our backends.1328 // First, we flush relocatable object file generated with our backends.
...@@ -1432,9 +1452,14 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)...@@ -1432,9 +1452,14 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)
1432 if (module_obj_path) |path| try positionals.append(.{ .path = path });1452 if (module_obj_path) |path| try positionals.append(.{ .path = path });
14331453
1434 for (positionals.items) |obj| {1454 for (positionals.items) |obj| {
1435 var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };1455 self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
1436 self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|1456 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1437 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1457 else => |e| try self.reportParseError(
1458 obj.path,
1459 "unexpected error: parsing input file failed with error {s}",
1460 .{@errorName(e)},
1461 ),
1462 };
1438 }1463 }
14391464
1440 // Init all objects1465 // Init all objects
...@@ -1770,37 +1795,36 @@ const ParseError = error{...@@ -1770,37 +1795,36 @@ const ParseError = error{
1770 FileSystem,1795 FileSystem,
1771 NotSupported,1796 NotSupported,
1772 InvalidCharacter,1797 InvalidCharacter,
1773 MalformedObject,
1774} || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError;1798} || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError;
17751799
1776fn parsePositional(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {1800fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
1777 const tracy = trace(@src());1801 const tracy = trace(@src());
1778 defer tracy.end();1802 defer tracy.end();
1779 if (try Object.isObject(path)) {1803 if (try Object.isObject(path)) {
1780 try self.parseObject(path, ctx);1804 try self.parseObject(path);
1781 } else {1805 } else {
1782 try self.parseLibrary(.{ .path = path }, must_link, ctx);1806 try self.parseLibrary(.{ .path = path }, must_link);
1783 }1807 }
1784}1808}
17851809
1786fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {1810fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
1787 const tracy = trace(@src());1811 const tracy = trace(@src());
1788 defer tracy.end();1812 defer tracy.end();
17891813
1790 if (try Archive.isArchive(lib.path)) {1814 if (try Archive.isArchive(lib.path)) {
1791 try self.parseArchive(lib.path, must_link, ctx);1815 try self.parseArchive(lib.path, must_link);
1792 } else if (try SharedObject.isSharedObject(lib.path)) {1816 } else if (try SharedObject.isSharedObject(lib.path)) {
1793 try self.parseSharedObject(lib, ctx);1817 try self.parseSharedObject(lib);
1794 } else {1818 } else {
1795 // TODO if the script has a top-level comment identifying it as GNU ld script,1819 // TODO if the script has a top-level comment identifying it as GNU ld script,
1796 // then report parse errors. Otherwise return UnknownFileType.1820 // then report parse errors. Otherwise return UnknownFileType.
1797 self.parseLdScript(lib, ctx) catch |err| switch (err) {1821 self.parseLdScript(lib) catch |err| switch (err) {
1798 else => return error.UnknownFileType,1822 else => return error.UnknownFileType,
1799 };1823 };
1800 }1824 }
1801}1825}
18021826
1803fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!void {1827fn parseObject(self: *Elf, path: []const u8) ParseError!void {
1804 const tracy = trace(@src());1828 const tracy = trace(@src());
1805 defer tracy.end();1829 defer tracy.end();
18061830
...@@ -1818,12 +1842,9 @@ fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!voi...@@ -1818,12 +1842,9 @@ fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!voi
18181842
1819 const object = self.file(index).?.object;1843 const object = self.file(index).?.object;
1820 try object.parse(self);1844 try object.parse(self);
1821
1822 ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
1823 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
1824}1845}
18251846
1826fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {1847fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
1827 const tracy = trace(@src());1848 const tracy = trace(@src());
1828 defer tracy.end();1849 defer tracy.end();
18291850
...@@ -1846,13 +1867,10 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorC...@@ -1846,13 +1867,10 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorC
1846 object.alive = must_link;1867 object.alive = must_link;
1847 try object.parse(self);1868 try object.parse(self);
1848 try self.objects.append(gpa, index);1869 try self.objects.append(gpa, index);
1849
1850 ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
1851 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
1852 }1870 }
1853}1871}
18541872
1855fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {1873fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
1856 const tracy = trace(@src());1874 const tracy = trace(@src());
1857 defer tracy.end();1875 defer tracy.end();
18581876
...@@ -1872,12 +1890,9 @@ fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError...@@ -1872,12 +1890,9 @@ fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError
18721890
1873 const shared_object = self.file(index).?.shared_object;1891 const shared_object = self.file(index).?.shared_object;
1874 try shared_object.parse(self);1892 try shared_object.parse(self);
1875
1876 ctx.detected_cpu_arch = shared_object.header.?.e_machine.toTargetCpuArch().?;
1877 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
1878}1893}
18791894
1880fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {1895fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1881 const tracy = trace(@src());1896 const tracy = trace(@src());
1882 defer tracy.end();1897 defer tracy.end();
18831898
...@@ -1891,11 +1906,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi...@@ -1891,11 +1906,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi
1891 defer script.deinit(gpa);1906 defer script.deinit(gpa);
1892 try script.parse(data, self);1907 try script.parse(data, self);
18931908
1894 if (script.cpu_arch) |cpu_arch| {
1895 ctx.detected_cpu_arch = cpu_arch;
1896 if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
1897 }
1898
1899 const lib_dirs = self.base.options.lib_dirs;1909 const lib_dirs = self.base.options.lib_dirs;
19001910
1901 var arena_allocator = std.heap.ArenaAllocator.init(gpa);1911 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
...@@ -1949,11 +1959,17 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi...@@ -1949,11 +1959,17 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi
1949 }1959 }
19501960
1951 const full_path = test_path.items;1961 const full_path = test_path.items;
1952 var scr_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
1953 self.parseLibrary(.{1962 self.parseLibrary(.{
1954 .needed = scr_obj.needed,1963 .needed = scr_obj.needed,
1955 .path = full_path,1964 .path = full_path,
1956 }, false, &scr_ctx) catch |err| try self.handleAndReportParseError(full_path, err, &scr_ctx);1965 }, false) catch |err| switch (err) {
1966 error.LinkFail, error.InvalidCpuArch => {}, // already reported
1967 else => |e| try self.reportParseError(
1968 full_path,
1969 "unexpected error: parsing library failed with error {s}",
1970 .{@errorName(e)},
1971 ),
1972 };
1957 }1973 }
1958}1974}
19591975
...@@ -3009,6 +3025,8 @@ fn writePhdrTable(self: *Elf) !void {...@@ -3009,6 +3025,8 @@ fn writePhdrTable(self: *Elf) !void {
3009}3025}
30103026
3011fn writeElfHeader(self: *Elf) !void {3027fn writeElfHeader(self: *Elf) !void {
3028 if (self.misc_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable
3029
3012 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;3030 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
30133031
3014 var index: usize = 0;3032 var index: usize = 0;
...@@ -6047,33 +6065,6 @@ fn reportMissingLibraryError(...@@ -6047,33 +6065,6 @@ fn reportMissingLibraryError(
6047 }6065 }
6048}6066}
60496067
6050const ParseErrorCtx = struct {
6051 detected_cpu_arch: std.Target.Cpu.Arch,
6052};
6053
6054fn handleAndReportParseError(
6055 self: *Elf,
6056 path: []const u8,
6057 err: ParseError,
6058 ctx: *const ParseErrorCtx,
6059) error{OutOfMemory}!void {
6060 const cpu_arch = self.base.options.target.cpu.arch;
6061 switch (err) {
6062 error.LinkFail => {}, // already reported
6063 error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
6064 error.InvalidCpuArch => try self.reportParseError(
6065 path,
6066 "invalid cpu architecture: expected '{s}', but found '{s}'",
6067 .{ @tagName(cpu_arch), @tagName(ctx.detected_cpu_arch) },
6068 ),
6069 else => |e| try self.reportParseError(
6070 path,
6071 "unexpected error: parsing object failed with error {s}",
6072 .{@errorName(e)},
6073 ),
6074 }
6075}
6076
6077fn reportParseError(6068fn reportParseError(
6078 self: *Elf,6069 self: *Elf,
6079 path: []const u8,6070 path: []const u8,
src/link/Elf/Object.zig+9
...@@ -54,6 +54,15 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {...@@ -54,6 +54,15 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
5454
55 self.header = try reader.readStruct(elf.Elf64_Ehdr);55 self.header = try reader.readStruct(elf.Elf64_Ehdr);
5656
57 if (elf_file.base.options.target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) {
58 try elf_file.reportParseError2(
59 self.index,
60 "invalid cpu architecture: {s}",
61 .{@tagName(self.header.?.e_machine.toTargetCpuArch().?)},
62 );
63 return error.InvalidCpuArch;
64 }
65
57 if (self.header.?.e_shnum == 0) return;66 if (self.header.?.e_shnum == 0) return;
5867
59 const gpa = elf_file.base.allocator;68 const gpa = elf_file.base.allocator;