From 775a161794c9486b7866b27d364acea1cb78b6cd Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 21 Feb 2024 20:50:29 +0100 Subject: [PATCH] elf: simplify logic for resolving .eh_frame relocs on different arches --- src/link/Elf.zig | 18 +++++++++--------- src/link/Elf/eh_frame.zig | 31 ++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 10f0ce0655..7356429312 100644 --- a/src/link/Elf.zig +++ b/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); } diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 6e8e08fab1..c4866956c0 100644 --- a/src/link/Elf/eh_frame.zig +++ b/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;