diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 009207ba09..e490e6091e 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4245,11 +4245,10 @@ fn updateSectionSizesObject(self: *Elf) !void { if (self.eh_frame_section_index) |index| { self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); - - if (self.eh_frame_rela_section_index) |rela_index| { - const shdr = &self.shdrs.items[rela_index]; - shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; - } + } + if (self.eh_frame_rela_section_index) |index| { + const shdr = &self.shdrs.items[index]; + shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; } try self.updateSymtabSize(); @@ -5013,6 +5012,14 @@ fn writeSyntheticSectionsObject(self: *Elf) !void { try eh_frame.writeEhFrame(self, buffer.writer()); try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); } + if (self.eh_frame_rela_section_index) |shndx| { + const shdr = self.shdrs.items[shndx]; + 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.writeEhFrameRelocs(self, buffer.writer()); + try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); + } try self.writeSymtab(); try self.writeShStrtab(); diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index d15af3489a..3657a3f5b7 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -373,6 +373,62 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { try writer.writeInt(u32, 0, .little); } +fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { + const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset; + const r_type = rel.r_type(); + var r_addend = rel.r_addend; + var r_sym: u32 = 0; + switch (sym.type(elf_file)) { + elf.STT_SECTION => { + r_addend += @intCast(sym.value); + r_sym = elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx().?); + }, + else => { + r_sym = sym.outputSymtabIndex(elf_file) orelse 0; + }, + } + + relocs_log.debug(" {s}: [{x} => {d}({s})] + {x}", .{ + Atom.fmtRelocType(r_type), + r_offset, + r_sym, + sym.name(elf_file), + r_addend, + }); + + return .{ + .r_offset = r_offset, + .r_addend = r_addend, + .r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type, + }; +} + +pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { + relocs_log.debug("{x}: .eh_frame", .{elf_file.shdrs.items[elf_file.eh_frame_section_index.?].sh_addr}); + + for (elf_file.objects.items) |index| { + const object = elf_file.file(index).?.object; + + for (object.cies.items) |cie| { + if (!cie.alive) continue; + for (cie.relocs(elf_file)) |rel| { + const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const out_rel = emitReloc(elf_file, cie, sym, rel); + try writer.writeStruct(out_rel); + } + } + + for (object.fdes.items) |fde| { + if (!fde.alive) continue; + for (fde.relocs(elf_file)) |rel| { + const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]); + const out_rel = emitReloc(elf_file, fde, sym, rel); + try writer.writeStruct(out_rel); + } + } + } +} + pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void { try writer.writeByte(1); // version try writer.writeByte(EH_PE.pcrel | EH_PE.sdata4);