authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-13 10:28:01+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-13 13:30:24+02:00
logce8886d57d1593a7eb4909e518fc49e1c95360dd
treef9000ced65ae45021af02da0474dac13a03e77c6
parentd25c93a868585e4e2f5941fcff15fa49c90510e9

elf: make zig jump table indirection implicit via Symbol.address


3 files changed, 35 insertions(+), 38 deletions(-)

src/link/Elf/Atom.zig+12-23
...@@ -750,8 +750,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -750,8 +750,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
750 const S = target.address(.{}, elf_file);750 const S = target.address(.{}, elf_file);
751 // Address of the global offset table.751 // Address of the global offset table.
752 const GOT = elf_file.gotAddress();752 const GOT = elf_file.gotAddress();
753 // Address of the zig jump table entry if any.
754 const ZJT = target.zigJumpTableAddress(elf_file);
755 // Relative offset to the start of the global offset table.753 // Relative offset to the start of the global offset table.
756 const G = target.gotAddress(elf_file) - GOT;754 const G = target.gotAddress(elf_file) - GOT;
757 // // Address of the thread pointer.755 // // Address of the thread pointer.
...@@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi...@@ -759,19 +757,18 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
759 // Address of the dynamic thread pointer.757 // Address of the dynamic thread pointer.
760 const DTP = elf_file.dtpAddress();758 const DTP = elf_file.dtpAddress();
761759
762 relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ZJT({x}) ({s})", .{760 relocs_log.debug(" {s}: {x}: [{x} => {x}] GOT({x}) ({s})", .{
763 relocation.fmtRelocType(rel.r_type(), cpu_arch),761 relocation.fmtRelocType(rel.r_type(), cpu_arch),
764 r_offset,762 r_offset,
765 P,763 P,
766 S + A,764 S + A,
767 G + GOT + A,765 G + GOT + A,
768 ZJT + A,
769 target.name(elf_file),766 target.name(elf_file),
770 });767 });
771768
772 try stream.seekTo(r_offset);769 try stream.seekTo(r_offset);
773770
774 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP, ZJT };771 const args = ResolveArgs{ P, A, S, GOT, G, TP, DTP };
775772
776 switch (cpu_arch) {773 switch (cpu_arch) {
777 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {774 .x86_64 => x86_64.resolveRelocAlloc(self, elf_file, rel, target, args, &it, code, &stream) catch |err| switch (err) {
...@@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -956,7 +953,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
956 // Address of the dynamic thread pointer.953 // Address of the dynamic thread pointer.
957 const DTP = elf_file.dtpAddress();954 const DTP = elf_file.dtpAddress();
958955
959 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP, 0 };956 const args = ResolveArgs{ P, A, S, GOT, 0, 0, DTP };
960957
961 relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{958 relocs_log.debug(" {}: {x}: [{x} => {x}] ({s})", .{
962 relocation.fmtRelocType(rel.r_type(), cpu_arch),959 relocation.fmtRelocType(rel.r_type(), cpu_arch),
...@@ -1200,7 +1197,7 @@ const x86_64 = struct {...@@ -1200,7 +1197,7 @@ const x86_64 = struct {
12001197
1201 const cwriter = stream.writer();1198 const cwriter = stream.writer();
12021199
1203 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZJT = args;1200 const P, const A, const S, const GOT, const G, const TP, const DTP = args;
12041201
1205 switch (r_type) {1202 switch (r_type) {
1206 .NONE => unreachable,1203 .NONE => unreachable,
...@@ -1215,10 +1212,7 @@ const x86_64 = struct {...@@ -1215,10 +1212,7 @@ const x86_64 = struct {
1215 );1212 );
1216 },1213 },
12171214
1218 .PLT32 => {1215 .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
1219 const S_ = if (target.flags.zig_jump_table) ZJT else S;
1220 try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
1221 },
1222 .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),1216 .PC32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
12231217
1224 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),1218 .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
...@@ -1243,10 +1237,7 @@ const x86_64 = struct {...@@ -1243,10 +1237,7 @@ const x86_64 = struct {
1243 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);1237 try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
1244 },1238 },
12451239
1246 .@"32" => {1240 .@"32" => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
1247 const S_ = if (target.flags.zig_jump_table) ZJT else S;
1248 try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S_ + A)))), .little);
1249 },
1250 .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),1241 .@"32S" => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
12511242
1252 .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),1243 .TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
...@@ -1345,7 +1336,7 @@ const x86_64 = struct {...@@ -1345,7 +1336,7 @@ const x86_64 = struct {
1345 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());1336 const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
1346 const cwriter = stream.writer();1337 const cwriter = stream.writer();
13471338
1348 _, const A, const S, const GOT, _, _, const DTP, _ = args;1339 _, const A, const S, const GOT, _, _, const DTP = args;
13491340
1350 switch (r_type) {1341 switch (r_type) {
1351 .NONE => unreachable,1342 .NONE => unreachable,
...@@ -1728,9 +1719,8 @@ const aarch64 = struct {...@@ -1728,9 +1719,8 @@ const aarch64 = struct {
1728 const code = code_buffer[r_offset..][0..4];1719 const code = code_buffer[r_offset..][0..4];
1729 const file_ptr = atom.file(elf_file).?;1720 const file_ptr = atom.file(elf_file).?;
17301721
1731 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZJT = args;1722 const P, const A, const S, const GOT, const G, const TP, const DTP = args;
1732 _ = DTP;1723 _ = DTP;
1733 _ = ZJT;
17341724
1735 switch (r_type) {1725 switch (r_type) {
1736 .NONE => unreachable,1726 .NONE => unreachable,
...@@ -1932,7 +1922,7 @@ const aarch64 = struct {...@@ -1932,7 +1922,7 @@ const aarch64 = struct {
1932 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());1922 const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
1933 const cwriter = stream.writer();1923 const cwriter = stream.writer();
19341924
1935 _, const A, const S, _, _, _, _, _ = args;1925 _, const A, const S, _, _, _, _ = args;
19361926
1937 switch (r_type) {1927 switch (r_type) {
1938 .NONE => unreachable,1928 .NONE => unreachable,
...@@ -2012,10 +2002,9 @@ const riscv = struct {...@@ -2012,10 +2002,9 @@ const riscv = struct {
2012 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;2002 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
2013 const cwriter = stream.writer();2003 const cwriter = stream.writer();
20142004
2015 const P, const A, const S, const GOT, const G, const TP, const DTP, const ZJT = args;2005 const P, const A, const S, const GOT, const G, const TP, const DTP = args;
2016 _ = TP;2006 _ = TP;
2017 _ = DTP;2007 _ = DTP;
2018 _ = ZJT;
20192008
2020 switch (r_type) {2009 switch (r_type) {
2021 .NONE => unreachable,2010 .NONE => unreachable,
...@@ -2167,7 +2156,7 @@ const riscv = struct {...@@ -2167,7 +2156,7 @@ const riscv = struct {
2167 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;2156 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
2168 const cwriter = stream.writer();2157 const cwriter = stream.writer();
21692158
2170 _, const A, const S, const GOT, _, _, const DTP, _ = args;2159 _, const A, const S, const GOT, _, _, const DTP = args;
2171 _ = GOT;2160 _ = GOT;
2172 _ = DTP;2161 _ = DTP;
21732162
...@@ -2203,7 +2192,7 @@ const riscv = struct {...@@ -2203,7 +2192,7 @@ const riscv = struct {
2203 const riscv_util = @import("../riscv.zig");2192 const riscv_util = @import("../riscv.zig");
2204};2193};
22052194
2206const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64, i64 };2195const ResolveArgs = struct { i64, i64, i64, i64, i64, i64, i64 };
22072196
2208const RelocError = error{2197const RelocError = error{
2209 Overflow,2198 Overflow,
src/link/Elf/Symbol.zig+12-9
...@@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {...@@ -101,7 +101,7 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
101 return file_ptr.symbolRank(sym, in_archive);101 return file_ptr.symbolRank(sym, in_archive);
102}102}
103103
104pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf) i64 {104pub fn address(symbol: Symbol, opts: struct { plt: bool = true, zjt: bool = true }, elf_file: *Elf) i64 {
105 if (symbol.mergeSubsection(elf_file)) |msub| {105 if (symbol.mergeSubsection(elf_file)) |msub| {
106 if (!msub.alive) return 0;106 if (!msub.alive) return 0;
107 return msub.address(elf_file) + symbol.value;107 return msub.address(elf_file) + symbol.value;
...@@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf...@@ -109,6 +109,9 @@ pub fn address(symbol: Symbol, opts: struct { plt: bool = true }, elf_file: *Elf
109 if (symbol.flags.has_copy_rel) {109 if (symbol.flags.has_copy_rel) {
110 return symbol.copyRelAddress(elf_file);110 return symbol.copyRelAddress(elf_file);
111 }111 }
112 if (symbol.flags.has_zjt and opts.zjt) {
113 return symbol.zjtAddress(elf_file);
114 }
112 if (symbol.flags.has_plt and opts.plt) {115 if (symbol.flags.has_plt and opts.plt) {
113 if (!symbol.flags.is_canonical and symbol.flags.has_got) {116 if (!symbol.flags.is_canonical and symbol.flags.has_got) {
114 // We have a non-lazy bound function pointer, use that!117 // We have a non-lazy bound function pointer, use that!
...@@ -217,12 +220,12 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {...@@ -217,12 +220,12 @@ pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
217 return entry.address(elf_file);220 return entry.address(elf_file);
218}221}
219222
220pub fn zigJumpTableAddress(symbol: Symbol, elf_file: *Elf) i64 {223pub fn zjtAddress(symbol: Symbol, elf_file: *Elf) i64 {
221 if (!symbol.flags.zig_jump_table) return 0;224 if (!symbol.flags.has_zjt) return 0;
222 const zo = elf_file.zigObjectPtr().?;225 const zo = elf_file.zigObjectPtr().?;
223 const jump_table = zo.jumpTablePtr().?;226 const jump_table = zo.jumpTablePtr().?;
224 const jt_index = symbol.extra(elf_file).zig_jump_table;227 const index = symbol.extra(elf_file).zjt;
225 return jump_table.entryAddress(jt_index, zo, elf_file);228 return jump_table.entryAddress(index, zo, elf_file);
226}229}
227230
228pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {231pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
...@@ -248,7 +251,7 @@ const AddExtraOpts = struct {...@@ -248,7 +251,7 @@ const AddExtraOpts = struct {
248 tlsgd: ?u32 = null,251 tlsgd: ?u32 = null,
249 gottp: ?u32 = null,252 gottp: ?u32 = null,
250 tlsdesc: ?u32 = null,253 tlsdesc: ?u32 = null,
251 zig_jump_table: ?u32 = null,254 zjt: ?u32 = null,
252};255};
253256
254pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {257pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
...@@ -377,7 +380,7 @@ fn format2(...@@ -377,7 +380,7 @@ fn format2(
377 try writer.print("%{d} : {s} : @{x}", .{380 try writer.print("%{d} : {s} : @{x}", .{
378 symbol.esym_index,381 symbol.esym_index,
379 symbol.fmtName(elf_file),382 symbol.fmtName(elf_file),
380 symbol.address(.{}, elf_file),383 symbol.address(.{ .plt = false, .zjt = false }, elf_file),
381 });384 });
382 if (symbol.file(elf_file)) |file_ptr| {385 if (symbol.file(elf_file)) |file_ptr| {
383 if (symbol.isAbs(elf_file)) {386 if (symbol.isAbs(elf_file)) {
...@@ -454,7 +457,7 @@ pub const Flags = packed struct {...@@ -454,7 +457,7 @@ pub const Flags = packed struct {
454 merge_subsection: bool = false,457 merge_subsection: bool = false,
455458
456 /// Whether the symbol has __zig_jump_table indirection.459 /// Whether the symbol has __zig_jump_table indirection.
457 zig_jump_table: bool = false,460 has_zjt: bool = false,
458};461};
459462
460pub const Extra = struct {463pub const Extra = struct {
...@@ -468,7 +471,7 @@ pub const Extra = struct {...@@ -468,7 +471,7 @@ pub const Extra = struct {
468 gottp: u32 = 0,471 gottp: u32 = 0,
469 tlsdesc: u32 = 0,472 tlsdesc: u32 = 0,
470 merge_section: u32 = 0,473 merge_section: u32 = 0,
471 zig_jump_table: u32 = 0,474 zjt: u32 = 0,
472};475};
473476
474pub const Index = u32;477pub const Index = u32;
src/link/Elf/ZigObject.zig+11-6
...@@ -918,7 +918,7 @@ fn updateNavCode(...@@ -918,7 +918,7 @@ fn updateNavCode(
918 if (stt_bits == elf.STT_FUNC) {918 if (stt_bits == elf.STT_FUNC) {
919 const extra = sym.extra(elf_file);919 const extra = sym.extra(elf_file);
920 const jump_table = self.jumpTablePtr().?;920 const jump_table = self.jumpTablePtr().?;
921 jump_table.entries.items(.dirty)[extra.zig_jump_table] = true;921 jump_table.entries.items(.dirty)[extra.zjt] = true;
922 }922 }
923 }923 }
924 } else if (code.len < old_size) {924 } else if (code.len < old_size) {
...@@ -1045,10 +1045,10 @@ pub fn updateFunc(...@@ -1045,10 +1045,10 @@ pub fn updateFunc(
10451045
1046 {1046 {
1047 const sym = self.symbol(sym_index);1047 const sym = self.symbol(sym_index);
1048 if (!sym.flags.zig_jump_table) {1048 if (!sym.flags.has_zjt) {
1049 const index = try jump_table.addSymbol(gpa, sym_index);1049 const index = try jump_table.addSymbol(gpa, sym_index);
1050 sym.flags.zig_jump_table = true;1050 sym.flags.has_zjt = true;
1051 sym.addExtra(.{ .zig_jump_table = index }, elf_file);1051 sym.addExtra(.{ .zjt = index }, elf_file);
1052 try jump_table.updateSize(self, elf_file);1052 try jump_table.updateSize(self, elf_file);
1053 const old_vaddr = jump_table.address(self, elf_file);1053 const old_vaddr = jump_table.address(self, elf_file);
1054 try self.symbol(jump_table.sym_index).atom(elf_file).?.allocate(elf_file);1054 try self.symbol(jump_table.sym_index).atom(elf_file).?.allocate(elf_file);
...@@ -1108,7 +1108,7 @@ pub fn updateFunc(...@@ -1108,7 +1108,7 @@ pub fn updateFunc(
1108 }1108 }
1109 } else {1109 } else {
1110 const sym = self.symbol(sym_index);1110 const sym = self.symbol(sym_index);
1111 const jt_index = sym.extra(elf_file).zig_jump_table;1111 const jt_index = sym.extra(elf_file).zjt;
1112 var jt_entry = jump_table.entries.get(jt_index);1112 var jt_entry = jump_table.entries.get(jt_index);
1113 if (jt_entry.dirty) {1113 if (jt_entry.dirty) {
1114 try jump_table.writeEntry(jt_index, self, elf_file);1114 try jump_table.writeEntry(jt_index, self, elf_file);
...@@ -1896,7 +1896,12 @@ pub const JumpTable = struct {...@@ -1896,7 +1896,12 @@ pub const JumpTable = struct {
1896 try writer.print(" @{x} : size({x})\n", .{ jt.address(zo, ef), jt.size(zo, ef) });1896 try writer.print(" @{x} : size({x})\n", .{ jt.address(zo, ef), jt.size(zo, ef) });
1897 for (jt.entries.items(.sym_index), jt.entries.items(.dirty)) |sym_index, dirty| {1897 for (jt.entries.items(.sym_index), jt.entries.items(.dirty)) |sym_index, dirty| {
1898 const sym = zo.symbol(sym_index);1898 const sym = zo.symbol(sym_index);
1899 try writer.print(" %{d} : {s} : @{x}", .{ sym_index, sym.name(ef), sym.address(.{}, ef) });1899 try writer.print(" {x} => {x} : %{d} : {s}", .{
1900 sym.address(.{}, ef),
1901 sym.address(.{ .zjt = false }, ef),
1902 sym_index,
1903 sym.name(ef),
1904 });
1900 if (dirty) try writer.writeAll(" : [!]");1905 if (dirty) try writer.writeAll(" : [!]");
1901 try writer.writeByte('\n');1906 try writer.writeByte('\n');
1902 }1907 }