Commit 49d78cc793

Jakub Konka <kubkon@jakubkonka.com>
2024-08-13 12:50:53
elf: only apply zig jump table indirection to function calls (PLT32)
1 parent 9daf5e8
Changed files (4)
src/link/Elf/Atom.zig
@@ -747,7 +747,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
         // 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 = target.address(.{}, elf_file);
+        const S = target.address(.{ .zjt = false }, elf_file);
         // Address of the global offset table.
         const GOT = elf_file.gotAddress();
         // Relative offset to the start of the global offset table.
@@ -1212,7 +1212,10 @@ const x86_64 = struct {
                 );
             },
 
-            .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
+            .PLT32 => {
+                const S_ = if (target.flags.has_zjt) target.address(.{ .zjt = true }, elf_file) else S;
+                try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+            },
             .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),
src/link/Elf/Symbol.zig
@@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
     return file_ptr.symbolRank(sym, in_archive);
 }
 
-pub fn address(symbol: Symbol, opts: struct { plt: bool = true, zjt: bool = true }, elf_file: *Elf) i64 {
+pub fn address(symbol: Symbol, opts: struct { plt: bool = true, zjt: bool = false }, elf_file: *Elf) i64 {
     if (symbol.mergeSubsection(elf_file)) |msub| {
         if (!msub.alive) return 0;
         return msub.address(elf_file) + symbol.value;
@@ -300,11 +300,11 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
             if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
             break :blk 0;
         }
-        if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false, .zjt = false }, elf_file);
+        if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false }, elf_file);
         const shdr = elf_file.shdrs.items[st_shndx];
         if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined)
-            break :blk symbol.address(.{ .plt = false, .zjt = false }, elf_file) - elf_file.tlsAddress();
-        break :blk symbol.address(.{ .plt = false, .zjt = false }, elf_file);
+            break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress();
+        break :blk symbol.address(.{ .plt = false }, elf_file);
     };
     out.st_info = (st_bind << 4) | st_type;
     out.st_other = esym.st_other;
@@ -380,7 +380,7 @@ fn format2(
     try writer.print("%{d} : {s} : @{x}", .{
         symbol.esym_index,
         symbol.fmtName(elf_file),
-        symbol.address(.{ .plt = false, .zjt = false }, elf_file),
+        symbol.address(.{ .plt = false }, elf_file),
     });
     if (symbol.file(elf_file)) |file_ptr| {
         if (symbol.isAbs(elf_file)) {
src/link/Elf/ZigObject.zig
@@ -665,7 +665,7 @@ pub fn getNavVAddr(
         else => try self.getOrCreateMetadataForNav(elf_file, nav_index),
     };
     const this_sym = self.symbol(this_sym_index);
-    const vaddr = this_sym.address(.{}, elf_file);
+    const vaddr = this_sym.address(.{ .zjt = true }, elf_file);
     const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
     const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
     try parent_atom.addReloc(elf_file, .{
@@ -942,7 +942,7 @@ fn updateNavCode(
                     .len = code.len,
                 }};
                 var remote_vec: [1]std.posix.iovec_const = .{.{
-                    .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))),
+                    .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{ .zjt = true }, elf_file))))),
                     .len = code.len,
                 }};
                 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
@@ -1092,7 +1092,7 @@ pub fn updateFunc(
         try self.dwarf.?.commitNavState(
             pt,
             func.owner_nav,
-            @intCast(sym.address(.{}, elf_file)),
+            @intCast(sym.address(.{ .zjt = true }, elf_file)),
             sym.atom(elf_file).?.size,
             ds,
         );
@@ -1189,7 +1189,7 @@ pub fn updateNav(
         try self.dwarf.?.commitNavState(
             pt,
             nav_index,
-            @intCast(sym.address(.{}, elf_file)),
+            @intCast(sym.address(.{ .zjt = true }, elf_file)),
             sym.atom(elf_file).?.size,
             ns,
         );
@@ -1817,7 +1817,7 @@ pub const JumpTable = struct {
 
     pub fn targetAddress(jt: JumpTable, index: Index, zo: *ZigObject, elf_file: *Elf) i64 {
         const sym_index = jt.entries.items(.sym_index)[index];
-        return zo.symbol(sym_index).address(.{ .zjt = false }, elf_file);
+        return zo.symbol(sym_index).address(.{}, elf_file);
     }
 
     const max_jump_seq_len = 12;
@@ -1897,8 +1897,8 @@ pub const JumpTable = struct {
         for (jt.entries.items(.sym_index), jt.entries.items(.dirty)) |sym_index, dirty| {
             const sym = zo.symbol(sym_index);
             try writer.print("    {x} => {x} : %{d} : {s}", .{
+                sym.address(.{ .zjt = true }, ef),
                 sym.address(.{}, ef),
-                sym.address(.{ .zjt = false }, ef),
                 sym_index,
                 sym.name(ef),
             });
src/link/Elf.zig
@@ -2798,7 +2798,7 @@ pub fn writeElfHeader(self: *Elf) !void {
 
     const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {
         const entry_sym = obj.entrySymbol(self) orelse break :blk 0;
-        break :blk @intCast(entry_sym.address(.{}, self));
+        break :blk @intCast(entry_sym.address(.{ .zjt = true }, self));
     } else 0;
     const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
     switch (self.ptr_width) {