Commit 775a161794

Jakub Konka <kubkon@jakubkonka.com>
2024-02-21 20:50:29
elf: simplify logic for resolving .eh_frame relocs on different arches
1 parent 06c191a
Changed files (2)
src
src/link/Elf/eh_frame.zig
@@ -317,7 +317,7 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:
     });
 
     switch (cpu_arch) {
-        .x86_64 => x86_64.resolveReloc(rel, P, S + A, contents[offset..]),
+        .x86_64 => try x86_64.resolveReloc(rec, elf_file, rel, P, S + A, contents[offset..]),
         else => return error.UnsupportedCpuArch,
     }
 }
@@ -325,6 +325,8 @@ fn resolveReloc(rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela, elf_file:
 pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
     relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr});
 
+    var has_reloc_errors = false;
+
     for (elf_file.objects.items) |index| {
         const object = elf_file.file(index).?.object;
 
@@ -335,7 +337,10 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
 
             for (cie.relocs(elf_file)) |rel| {
                 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
-                try resolveReloc(cie, sym, rel, elf_file, contents);
+                resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) {
+                    error.RelocFailure => has_reloc_errors = true,
+                    else => |e| return e,
+                };
             }
 
             try writer.writeAll(contents);
@@ -359,7 +364,10 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
 
             for (fde.relocs(elf_file)) |rel| {
                 const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
-                try resolveReloc(fde, sym, rel, elf_file, contents);
+                resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {
+                    error.RelocFailure => has_reloc_errors = true,
+                    else => |e| return e,
+                };
             }
 
             try writer.writeAll(contents);
@@ -367,6 +375,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
     }
 
     try writer.writeInt(u32, 0, .little);
+
+    if (has_reloc_errors) return error.RelocFailure;
 }
 
 pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void {
@@ -540,18 +550,29 @@ const EH_PE = struct {
 };
 
 const x86_64 = struct {
-    fn resolveReloc(rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) void {
+    fn resolveReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) !void {
         const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
         switch (r_type) {
+            .NONE => {},
             .@"32" => std.mem.writeInt(i32, data[0..4], @as(i32, @truncate(target)), .little),
             .@"64" => std.mem.writeInt(i64, data[0..8], target, .little),
             .PC32 => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little),
             .PC64 => std.mem.writeInt(i64, data[0..8], target - source, .little),
-            else => unreachable,
+            else => try reportInvalidReloc(rec, elf_file, rel),
         }
     }
 };
 
+fn reportInvalidReloc(rec: anytype, elf_file: *Elf, rel: elf.Elf64_Rela) !void {
+    var err = try elf_file.addErrorWithNotes(1);
+    try err.addMsg(elf_file, "invalid relocation type {} at offset 0x{x}", .{
+        relocation.fmtRelocType(rel.r_type(), elf_file.getTarget().cpu.arch),
+        rel.r_offset,
+    });
+    try err.addNote(elf_file, "in {}:.eh_frame", .{elf_file.file(rec.file_index).?.fmtPath()});
+    return error.RelocFailure;
+}
+
 const std = @import("std");
 const assert = std.debug.assert;
 const elf = std.elf;
src/link/Elf.zig
@@ -1371,14 +1371,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
     try self.writePhdrTable();
     try self.writeShdrTable();
     try self.writeAtoms();
-
-    self.writeSyntheticSections() catch |err| switch (err) {
-        error.UnsupportedCpuArch => {
-            try self.reportUnsupportedCpuArch();
-            return error.FlushFailure;
-        },
-        else => |e| return e,
-    };
+    try self.writeSyntheticSections();
 
     if (self.entry_index == null and self.base.isExe()) {
         log.debug("flushing. no_entry_point_found = true", .{});
@@ -4689,7 +4682,14 @@ fn writeSyntheticSections(self: *Elf) !void {
         const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
         var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
         defer buffer.deinit();
-        try eh_frame.writeEhFrame(self, buffer.writer());
+        eh_frame.writeEhFrame(self, buffer.writer()) catch |err| switch (err) {
+            error.RelocFailure => return error.FlushFailure,
+            error.UnsupportedCpuArch => {
+                try self.reportUnsupportedCpuArch();
+                return error.FlushFailure;
+            },
+            else => |e| return e,
+        };
         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
     }