diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/Elf/Atom.zig | 202 |
1 files changed, 113 insertions, 89 deletions
diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index d3277533b4..dc5147e9c4 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -433,7 +433,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype // While traversing relocations, mark symbols that require special handling such as // pointer indirection via GOT, or a stub trampoline via PLT. - switch (elf_file.getTarget().cpu.arch) { + switch (cpu_arch) { .x86_64 => x86_64.scanReloc(self, elf_file, rel, symbol, code, &it) catch |err| switch (err) { error.RelocFailure => has_reloc_errors = true, else => |e| return e, @@ -765,6 +765,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi switch (cpu_arch) { .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + error.RelocFailure, error.RelaxFailure, error.InvalidInstruction, error.CannotEncode, @@ -880,10 +881,83 @@ fn applyDynamicReloc(value: i64, elf_file: *Elf, writer: anytype) !void { pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !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.resolveRelocsNonAlloc(self, elf_file, code, undefs), - 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 has_reloc_errors = false; + var it = RelocsIterator{ .relocs = rels }; + while (it.next()) |rel| { + const r_kind = relocation.decode(rel.r_type(), cpu_arch); + if (r_kind == .none) continue; + + const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; + + const target_index = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()), + .object => |x| x.symbols.items[rel.r_sym()], + else => unreachable, + }; + const target = elf_file.symbol(target_index); + + // Check for violation of One Definition Rule for COMDATs. + if (target.file(elf_file) == null) { + // TODO convert into an error + log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ + file_ptr.fmtPath(), + self.name(elf_file), + target.name(elf_file), + }); + continue; + } + + // Report an undefined symbol. + if (try self.reportUndefined(elf_file, target, target_index, rel, undefs)) continue; + + // We will use equation format to resolve relocations: + // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ + // + 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 dynamic thread pointer. + const DTP = @as(i64, @intCast(elf_file.dtpAddress())); + + const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 }; + + relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ + relocation.fmtRelocType(rel.r_type(), cpu_arch), + rel.r_offset, + P, + S + A, + target.name(elf_file), + }); + + try stream.seekTo(r_offset); + + switch (cpu_arch) { + .x86_64 => x86_64.resolveRelocNonAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) { + error.RelocFailure => has_reloc_errors = true, + else => |e| return e, + }, + else => return error.UnsupportedCpuArch, + } } + + if (has_reloc_errors) return error.RelocFailure; } pub fn format( @@ -1210,98 +1284,48 @@ const x86_64 = struct { 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 => try atom.reportUnhandledRelocError(rel, elf_file), }, } } - fn resolveRelocsNonAlloc(atom: Atom, elf_file: *Elf, code: []u8, undefs: anytype) !void { - const file_ptr = atom.file(elf_file).?; - var stream = std.io.fixedBufferStream(code); + fn resolveRelocNonAlloc( + atom: Atom, + elf_file: *Elf, + rel: elf.Elf64_Rela, + target: *const Symbol, + args: ResolveArgs, + it: *RelocsIterator, + code: []u8, + stream: anytype, + ) !void { + _ = code; + _ = it; + const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type()); 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 r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; - - const target_index = switch (file_ptr) { - .zig_object => |x| x.symbol(rel.r_sym()), - .object => |x| x.symbols.items[rel.r_sym()], - else => unreachable, - }; - const target = elf_file.symbol(target_index); - - // Check for violation of One Definition Rule for COMDATs. - if (target.file(elf_file) == null) { - // TODO convert into an error - log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{ - file_ptr.fmtPath(), - atom.name(elf_file), - target.name(elf_file), - }); - continue; - } + _, const A, const S, const GOT, _, _, const DTP, _ = args; - // Report an undefined symbol. - if (try atom.reportUndefined(elf_file, target, target_index, rel, undefs)) continue; - - // We will use equation format to resolve relocations: - // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ - // - 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 dynamic thread pointer. - const DTP = @as(i64, @intCast(elf_file.dtpAddress())); - - relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{ - relocation.fmtRelocType(rel.r_type(), .x86_64), - rel.r_offset, - P, - S + A, - target.name(elf_file), - }); - - try stream.seekTo(r_offset); - - switch (r_type) { - .NONE => unreachable, - .@"8" => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), - .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), - .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), - .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), - .@"64" => try cwriter.writeInt(i64, S + A, .little), - .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), - .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), - .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), - .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), - .SIZE32 => { - const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); - try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little); - }, - .SIZE64 => { - const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); - try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little); - }, - else => try atom.reportUnhandledRelocError(rel, elf_file), - } + switch (r_type) { + .NONE => unreachable, + .@"8" => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little), + .@"16" => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little), + .@"32" => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little), + .@"32S" => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little), + .@"64" => try cwriter.writeInt(i64, S + A, .little), + .DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little), + .DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little), + .GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little), + .GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little), + .SIZE32 => { + const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); + try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little); + }, + .SIZE64 => { + const size = @as(i64, @intCast(target.elfSym(elf_file).st_size)); + try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little); + }, + else => try atom.reportUnhandledRelocError(rel, elf_file), } } |
