Commit 4cde47a169
src/link/Elf/Atom.zig
@@ -700,13 +700,82 @@ fn reportUndefined(
return false;
}
-pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
+pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!void {
relocs_log.debug("0x{x}: {s}", .{ self.address(elf_file), self.name(elf_file) });
- switch (elf_file.getTarget().cpu.arch) {
- .x86_64 => try x86_64.resolveRelocsAlloc(self, elf_file, code),
- else => return error.UnsupportedCpuArch,
+ const cpu_arch = elf_file.getTarget().cpu.arch;
+ const file_ptr = self.file(elf_file).?;
+ var stream = std.io.fixedBufferStream(code);
+
+ const rels = self.relocs(elf_file);
+ var it = RelocsIterator{ .relocs = rels };
+ var has_reloc_errors = false;
+ while (it.next()) |rel| {
+ const r_kind = relocation.decode(rel.r_type(), cpu_arch);
+ if (r_kind == .none) continue;
+
+ const target = switch (file_ptr) {
+ .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
+ .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
+ else => unreachable,
+ };
+ const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
+
+ // We will use equation format to resolve relocations:
+ // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
+ //
+ // Address of the source atom.
+ const P = @as(i64, @intCast(self.address(elf_file) + rel.r_offset));
+ // Addend from the relocation.
+ const A = rel.r_addend;
+ // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
+ const S = @as(i64, @intCast(target.address(.{}, elf_file)));
+ // Address of the global offset table.
+ const GOT = blk: {
+ const shndx = if (elf_file.got_plt_section_index) |shndx|
+ shndx
+ else if (elf_file.got_section_index) |shndx|
+ shndx
+ else
+ null;
+ break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0;
+ };
+ // Address of the .zig.got table entry if any.
+ const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file)));
+ // Relative offset to the start of the global offset table.
+ const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;
+ // // Address of the thread pointer.
+ const TP = @as(i64, @intCast(elf_file.tpAddress()));
+ // Address of the dynamic thread pointer.
+ const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
+
+ relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
+ relocation.fmtRelocType(rel.r_type(), cpu_arch),
+ r_offset,
+ P,
+ S + A,
+ G + GOT + A,
+ ZIG_GOT + A,
+ target.name(elf_file),
+ });
+
+ try stream.seekTo(r_offset);
+
+ const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZIG_GOT };
+
+ switch (cpu_arch) {
+ .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
+ error.RelaxFailure,
+ error.InvalidInstruction,
+ error.CannotEncode,
+ => has_reloc_errors = true,
+ else => |e| return e,
+ },
+ else => return error.UnsupportedCpuArch,
+ }
}
+
+ if (has_reloc_errors) return error.RelaxFailure;
}
fn resolveDynAbsReloc(
@@ -1001,185 +1070,148 @@ const x86_64 = struct {
}
}
- fn resolveRelocsAlloc(atom: Atom, elf_file: *Elf, code: []u8) !void {
- const file_ptr = atom.file(elf_file).?;
- var stream = std.io.fixedBufferStream(code);
- const cwriter = stream.writer();
-
- const rels = atom.relocs(elf_file);
- var i: usize = 0;
- while (i < rels.len) : (i += 1) {
- const rel = rels[i];
- const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
- if (r_type == .NONE) continue;
-
- const target = switch (file_ptr) {
- .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
- .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
- else => unreachable,
- };
- const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
-
- // We will use equation format to resolve relocations:
- // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/
- //
- // Address of the source atom.
- const P = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset));
- // Addend from the relocation.
- const A = rel.r_addend;
- // Address of the target symbol - can be address of the symbol within an atom or address of PLT stub.
- const S = @as(i64, @intCast(target.address(.{}, elf_file)));
- // Address of the global offset table.
- const GOT = blk: {
- const shndx = if (elf_file.got_plt_section_index) |shndx|
- shndx
- else if (elf_file.got_section_index) |shndx|
- shndx
- else
- null;
- break :blk if (shndx) |index| @as(i64, @intCast(elf_file.shdrs.items[index].sh_addr)) else 0;
- };
- // Address of the .zig.got table entry if any.
- const ZIG_GOT = @as(i64, @intCast(target.zigGotAddress(elf_file)));
- // Relative offset to the start of the global offset table.
- const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;
- // // Address of the thread pointer.
- const TP = @as(i64, @intCast(elf_file.tpAddress()));
- // Address of the dynamic thread pointer.
- const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
+ fn resolveRelocAlloc(
+ atom: Atom,
+ elf_file: *Elf,
+ rel: elf.Elf64_Rela,
+ target: *const Symbol,
+ args: ResolveArgs,
+ it: *RelocsIterator,
+ code: []u8,
+ stream: anytype,
+ ) (error{ InvalidInstruction, CannotEncode } || RelocError)!void {
+ const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
+ const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
- relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
- relocation.fmtRelocType(rel.r_type(), .x86_64),
- r_offset,
- P,
- S + A,
- G + GOT + A,
- ZIG_GOT + A,
- target.name(elf_file),
- });
+ const cwriter = stream.writer();
- try stream.seekTo(r_offset);
+ const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args;
- switch (r_type) {
- .NONE => unreachable,
+ switch (r_type) {
+ .NONE => unreachable,
- .@"64" => {
- try atom.resolveDynAbsReloc(
- target,
- rel,
- dynAbsRelocAction(target, elf_file),
- elf_file,
- cwriter,
- );
- },
+ .@"64" => {
+ try atom.resolveDynAbsReloc(
+ target,
+ rel,
+ dynAbsRelocAction(target, elf_file),
+ elf_file,
+ cwriter,
+ );
+ },
- .PLT32,
- .PC32,
- => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
+ .PLT32,
+ .PC32,
+ => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
- .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
- .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
- .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
+ .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
+ .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
+ .GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
- .GOTPCRELX => {
- if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
- x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;
- try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
- continue;
- }
- try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
- },
+ .GOTPCRELX => {
+ if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
+ x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;
+ try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
+ return;
+ }
+ try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
+ },
- .REX_GOTPCRELX => {
- if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
- x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;
- try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
- continue;
- }
- try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
- },
+ .REX_GOTPCRELX => {
+ if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
+ x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;
+ try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
+ return;
+ }
+ try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
+ },
- .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
- .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
+ .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
+ .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
- .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
- .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
+ .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
+ .TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
- .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
- .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
+ .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
+ .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
- .TLSGD => {
- if (target.flags.has_tlsgd) {
- const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));
- try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
- } else if (target.flags.has_gottp) {
- const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
- try x86_64.relaxTlsGdToIe(atom, rels[i .. i + 2], @intCast(S_ - P), elf_file, &stream);
- i += 1;
- } else {
- try x86_64.relaxTlsGdToLe(
- atom,
- rels[i .. i + 2],
- @as(i32, @intCast(S - TP)),
- elf_file,
- &stream,
- );
- i += 1;
- }
- },
+ .TLSGD => {
+ if (target.flags.has_tlsgd) {
+ const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));
+ try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+ } else if (target.flags.has_gottp) {
+ const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
+ try x86_64.relaxTlsGdToIe(atom, &.{ rel, it.next().? }, @intCast(S_ - P), elf_file, stream);
+ } else {
+ try x86_64.relaxTlsGdToLe(
+ atom,
+ &.{ rel, it.next().? },
+ @as(i32, @intCast(S - TP)),
+ elf_file,
+ stream,
+ );
+ }
+ },
- .TLSLD => {
- if (elf_file.got.tlsld_index) |entry_index| {
- const tlsld_entry = elf_file.got.entries.items[entry_index];
- const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));
- try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
- } else {
- try x86_64.relaxTlsLdToLe(
- atom,
- rels[i .. i + 2],
- @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))),
- elf_file,
- &stream,
- );
- i += 1;
- }
- },
+ .TLSLD => {
+ if (elf_file.got.tlsld_index) |entry_index| {
+ const tlsld_entry = elf_file.got.entries.items[entry_index];
+ const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));
+ try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+ } else {
+ try x86_64.relaxTlsLdToLe(
+ atom,
+ &.{ rel, it.next().? },
+ @as(i32, @intCast(TP - @as(i64, @intCast(elf_file.tlsAddress())))),
+ elf_file,
+ stream,
+ );
+ }
+ },
- .GOTPC32_TLSDESC => {
- if (target.flags.has_tlsdesc) {
- const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));
- try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
- } else {
- try x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]);
- try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
- }
- },
+ .GOTPC32_TLSDESC => {
+ if (target.flags.has_tlsdesc) {
+ const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));
+ try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+ } else {
+ x86_64.relaxGotPcTlsDesc(code[r_offset - 3 ..]) catch {
+ var err = try elf_file.addErrorWithNotes(1);
+ try err.addMsg(elf_file, "could not relax {s}", .{@tagName(r_type)});
+ try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{
+ atom.file(elf_file).?.fmtPath(),
+ atom.name(elf_file),
+ rel.r_offset,
+ });
+ return error.RelaxFailure;
+ };
+ try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
+ }
+ },
- .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
- // call -> nop
- try cwriter.writeAll(&.{ 0x66, 0x90 });
- },
+ .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
+ // call -> nop
+ try cwriter.writeAll(&.{ 0x66, 0x90 });
+ },
- .GOTTPOFF => {
- if (target.flags.has_gottp) {
- const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
- try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
- } else {
- x86_64.relaxGotTpOff(code[r_offset - 3 ..]) catch unreachable;
- try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
- }
- },
+ .GOTTPOFF => {
+ if (target.flags.has_gottp) {
+ const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
+ try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+ } else {
+ x86_64.relaxGotTpOff(code[r_offset - 3 ..]);
+ try cwriter.writeInt(i32, @as(i32, @intCast(S - TP)), .little);
+ }
+ },
- .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
+ .GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
- else => |x| switch (@intFromEnum(x)) {
- // Zig custom relocations
- Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
- Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
+ else => |x| switch (@intFromEnum(x)) {
+ // Zig custom relocations
+ Elf.R_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
+ Elf.R_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
- else => {},
- },
- }
+ else => {},
+ },
}
}
@@ -1274,7 +1306,7 @@ const x86_64 = struct {
}
fn relaxGotpcrelx(code: []u8) !void {
- const old_inst = disassemble(code) orelse return error.RelaxFail;
+ const old_inst = disassemble(code) orelse return error.RelaxFailure;
const inst = switch (old_inst.encoding.mnemonic) {
.call => try Instruction.new(old_inst.prefix, .call, &.{
// TODO: hack to force imm32s in the assembler
@@ -1284,28 +1316,28 @@ const x86_64 = struct {
// TODO: hack to force imm32s in the assembler
.{ .imm = Immediate.s(-129) },
}),
- else => return error.RelaxFail,
+ else => return error.RelaxFailure,
};
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
const nop = try Instruction.new(.none, .nop, &.{});
- encode(&.{ nop, inst }, code) catch return error.RelaxFail;
+ try encode(&.{ nop, inst }, code);
}
fn relaxRexGotpcrelx(code: []u8) !void {
- const old_inst = disassemble(code) orelse return error.RelaxFail;
+ const old_inst = disassemble(code) orelse return error.RelaxFailure;
switch (old_inst.encoding.mnemonic) {
.mov => {
const inst = try Instruction.new(old_inst.prefix, .lea, &old_inst.ops);
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
- encode(&.{inst}, code) catch return error.RelaxFail;
+ try encode(&.{inst}, code);
},
- else => return error.RelaxFail,
+ else => return error.RelaxFailure,
}
}
fn relaxTlsGdToIe(
self: Atom,
- rels: []align(1) const elf.Elf64_Rela,
+ rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
@@ -1328,7 +1360,7 @@ const x86_64 = struct {
else => {
var err = try elf_file.addErrorWithNotes(1);
- try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{
+ try err.addMsg(elf_file, "TODO: rewrite {} when followed by {}", .{
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
});
@@ -1337,13 +1369,14 @@ const x86_64 = struct {
self.name(elf_file),
rels[0].r_offset,
});
+ return error.RelaxFailure;
},
}
}
fn relaxTlsLdToLe(
self: Atom,
- rels: []align(1) const elf.Elf64_Rela,
+ rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
@@ -1381,7 +1414,7 @@ const x86_64 = struct {
else => {
var err = try elf_file.addErrorWithNotes(1);
- try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{
+ try err.addMsg(elf_file, "TODO: rewrite {} when followed by {}", .{
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
});
@@ -1390,6 +1423,7 @@ const x86_64 = struct {
self.name(elf_file),
rels[0].r_offset,
});
+ return error.RelaxFailure;
},
}
}
@@ -1409,24 +1443,24 @@ const x86_64 = struct {
}
}
- fn relaxGotTpOff(code: []u8) !void {
- const old_inst = disassemble(code) orelse return error.RelaxFail;
+ fn relaxGotTpOff(code: []u8) void {
+ const old_inst = disassemble(code) orelse unreachable;
switch (old_inst.encoding.mnemonic) {
.mov => {
- const inst = try Instruction.new(old_inst.prefix, .mov, &.{
+ const inst = Instruction.new(old_inst.prefix, .mov, &.{
old_inst.ops[0],
// TODO: hack to force imm32s in the assembler
.{ .imm = Immediate.s(-129) },
- });
+ }) catch unreachable;
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
- encode(&.{inst}, code) catch return error.RelaxFail;
+ encode(&.{inst}, code) catch unreachable;
},
- else => return error.RelaxFail,
+ else => unreachable,
}
}
fn relaxGotPcTlsDesc(code: []u8) !void {
- const old_inst = disassemble(code) orelse return error.RelaxFail;
+ const old_inst = disassemble(code) orelse return error.RelaxFailure;
switch (old_inst.encoding.mnemonic) {
.lea => {
const inst = try Instruction.new(old_inst.prefix, .mov, &.{
@@ -1435,15 +1469,15 @@ const x86_64 = struct {
.{ .imm = Immediate.s(-129) },
});
relocs_log.debug(" relaxing {} => {}", .{ old_inst.encoding, inst.encoding });
- encode(&.{inst}, code) catch return error.RelaxFail;
+ try encode(&.{inst}, code);
},
- else => return error.RelaxFail,
+ else => return error.RelaxFailure,
}
}
fn relaxTlsGdToLe(
self: Atom,
- rels: []align(1) const elf.Elf64_Rela,
+ rels: []const elf.Elf64_Rela,
value: i32,
elf_file: *Elf,
stream: anytype,
@@ -1481,6 +1515,7 @@ const x86_64 = struct {
self.name(elf_file),
rels[0].r_offset,
});
+ return error.RelaxFailure;
},
}
}
@@ -1506,10 +1541,14 @@ const x86_64 = struct {
const Instruction = encoder.Instruction;
};
+const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };
+
const RelocError = error{
Overflow,
OutOfMemory,
+ NoSpaceLeft,
RelocFailure,
+ RelaxFailure,
UnsupportedCpuArch,
};
src/link/Elf.zig
@@ -1344,6 +1344,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
// Beyond this point, everything has been allocated a virtual address and we can resolve
// the relocations, and commit objects to file.
if (self.zigObjectPtr()) |zig_object| {
+ var has_reloc_errors = false;
for (zig_object.atoms.items) |atom_index| {
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.flags.alive) continue;
@@ -1354,10 +1355,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
defer gpa.free(code);
const file_offset = shdr.sh_offset + atom_ptr.value;
atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
- // TODO
- error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
- log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
- },
+ error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
error.UnsupportedCpuArch => {
try self.reportUnsupportedCpuArch();
return error.FlushFailure;
@@ -1366,6 +1364,8 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node)
};
try self.base.file.?.pwriteAll(code, file_offset);
}
+
+ if (has_reloc_errors) return error.FlushFailure;
}
try self.writePhdrTable();
@@ -2052,6 +2052,7 @@ fn scanRelocs(self: *Elf) !void {
var has_reloc_errors = false;
for (objects.items) |index| {
self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {
+ error.RelaxFailure => unreachable,
error.UnsupportedCpuArch => {
try self.reportUnsupportedCpuArch();
return error.FlushFailure;
@@ -4517,15 +4518,11 @@ fn writeAtoms(self: *Elf) !void {
else
atom_ptr.resolveRelocsAlloc(self, out_code);
_ = res catch |err| switch (err) {
- // TODO
- error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
- log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
- },
error.UnsupportedCpuArch => {
try self.reportUnsupportedCpuArch();
return error.FlushFailure;
},
- error.RelocFailure => has_reloc_errors = true,
+ error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
else => |e| return e,
};
}