From ae74a36af0aa8c876b118973969aec1a10c25665 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 12 Sep 2023 19:17:57 +0200 Subject: [PATCH] elf: resolve and write objects to file --- src/arch/x86_64/Emit.zig | 2 +- src/link/Elf.zig | 28 ++++++++++++++++++++++++++++ src/link/Elf/Atom.zig | 26 ++++++++++++++++++++------ src/link/Elf/Object.zig | 4 ++++ 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 51820740dc..ab1d63e64c 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -45,7 +45,7 @@ pub fn emitMir(emit: *Emit) Error!void { // Add relocation to the decl. const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; try atom_ptr.addReloc(elf_file, .{ - .r_offset = end_offset, + .r_offset = end_offset - 4, .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | std.elf.R_X86_64_PLT32, .r_addend = -4, }); diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ca75a1e863..85ddb80cfd 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1072,6 +1072,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node try self.base.file.?.pwriteAll(code, file_offset); } } + try self.writeObjects(); try self.updateSymtabSize(); try self.writeSymtab(); @@ -1414,6 +1415,13 @@ fn allocateObjects(self: *Elf) !void { try atom_ptr.allocate(self); } + for (object.locals()) |local_index| { + const local = self.symbol(local_index); + const atom_ptr = local.atom(self) orelse continue; + if (!atom_ptr.alive) continue; + local.value = atom_ptr.value; + } + for (object.globals()) |global_index| { const global = self.symbol(global_index); if (global.file_index == index) { @@ -1423,6 +1431,26 @@ fn allocateObjects(self: *Elf) !void { } } +fn writeObjects(self: *Elf) !void { + const gpa = self.base.allocator; + + for (self.objects.items) |index| { + const object = self.file(index).?.object; + for (object.atoms.items) |atom_index| { + const atom_ptr = self.atom(atom_index) orelse continue; + if (!atom_ptr.alive) continue; + + const shdr = &self.shdrs.items[atom_ptr.output_section_index]; + const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; + const code = try atom_ptr.codeInObjectUncompressAlloc(self); + defer gpa.free(code); + + try atom_ptr.resolveRelocs(self, code); + try self.base.file.?.pwriteAll(code, file_offset); + } + } +} + fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { const tracy = trace(@src()); defer tracy.end(); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index d3a8de1302..871570843d 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -67,12 +67,13 @@ pub fn codeInObjectUncompressAlloc(self: Atom, elf_file: *Elf) ![]u8 { switch (chdr.ch_type) { .ZLIB => { var stream = std.io.fixedBufferStream(data[@sizeOf(elf.Elf64_Chdr)..]); - var zlib_stream = try std.compress.zlib.decompressStream(gpa, stream.reader()); + var zlib_stream = std.compress.zlib.decompressStream(gpa, stream.reader()) catch + return error.InputOutput; defer zlib_stream.deinit(); const decomp = try gpa.alloc(u8, chdr.ch_size); - const nread = try zlib_stream.reader().readAll(decomp); + const nread = zlib_stream.reader().readAll(decomp) catch return error.InputOutput; if (nread != decomp.len) { - return error.Io; + return error.InputOutput; } return decomp; }, @@ -366,6 +367,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf) !void { pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); + const file_ptr = elf_file.file(self.file_index).?; var stream = std.io.fixedBufferStream(code); const cwriter = stream.writer(); @@ -373,7 +375,11 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { const r_type = rel.r_type(); if (r_type == elf.R_X86_64_NONE) continue; - const target = elf_file.symbol(rel.r_sym()); + const target = switch (file_ptr) { + .zig_module => elf_file.symbol(rel.r_sym()), + .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), + else => unreachable, + }; // We will use equation format to resolve relocations: // https://intezer.com/blog/malware-analysis/executable-and-linkable-format-101-part-3-relocations/ @@ -414,9 +420,17 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { switch (rel.r_type()) { elf.R_X86_64_NONE => unreachable, + elf.R_X86_64_64 => try cwriter.writeIntLittle(i64, S + A), - elf.R_X86_64_PLT32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), - else => @panic("TODO"), + + elf.R_X86_64_PLT32, + elf.R_X86_64_PC32, + => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))), + + else => { + log.err("TODO: unhandled relocation type {}", .{fmtRelocType(rel.r_type())}); + @panic("TODO unhandled relocation type"); + }, } } } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index b40ebf8365..14892302a4 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -270,6 +270,10 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void { sym_ptr.esym_index = @as(u32, @intCast(i)); sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx]; sym_ptr.file_index = self.index; + sym_ptr.output_section_index = if (sym_ptr.atom(elf_file)) |atom_ptr| + atom_ptr.output_section_index + else + 0; } for (self.symtab[first_global..]) |sym| {