authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-08 18:12:53+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-08 18:12:53+02:00
log6ad5db030c576ab9cf944b4a9432954681af649c
treeac50a0993e886548dc45a2a900731b33527f9c09
parent9691d1a30ff524be5dc2cc88855b7887cd7f26f3

elf: store GOT index in symbol extra array; use GotSection for GOT


9 files changed, 565 insertions(+), 108 deletions(-)

src/arch/aarch64/CodeGen.zig+2-2
......@@ -4316,8 +4316,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
43164316 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
43174317 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
43184318 const sym = elf_file.symbol(sym_index);
4319 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
4320 const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
4319 _ = try sym.getOrCreateGotEntry(elf_file);
4320 const got_addr = @as(u32, @intCast(sym.gotAddress(elf_file)));
43214321 try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });
43224322 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
43234323 const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);
src/arch/arm/CodeGen.zig+2-2
......@@ -4296,8 +4296,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
42964296 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
42974297 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
42984298 const sym = elf_file.symbol(sym_index);
4299 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
4300 const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
4299 _ = try sym.getOrCreateGotEntry(elf_file);
4300 const got_addr = @as(u32, @intCast(sym.gotAddress(elf_file)));
43014301 try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });
43024302 } else if (self.bin_file.cast(link.File.MachO)) |_| {
43034303 unreachable; // unsupported architecture for MachO
src/arch/riscv64/CodeGen.zig+2-2
......@@ -1749,8 +1749,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
17491749 .func => |func| {
17501750 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
17511751 const sym = elf_file.symbol(sym_index);
1752 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
1753 const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
1752 _ = try sym.getOrCreateGotEntry(elf_file);
1753 const got_addr = @as(u32, @intCast(sym.gotAddress(elf_file)));
17541754 try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr });
17551755 _ = try self.addInst(.{
17561756 .tag = .jalr,
src/arch/sparc64/CodeGen.zig+2-2
......@@ -1351,8 +1351,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
13511351 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
13521352 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
13531353 const sym = elf_file.symbol(sym_index);
1354 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
1355 break :blk @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
1354 _ = try sym.getOrCreateGotEntry(elf_file);
1355 break :blk @as(u32, @intCast(sym.gotAddress(elf_file)));
13561356 } else unreachable;
13571357
13581358 try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr });
src/arch/x86_64/CodeGen.zig+4-4
......@@ -8151,8 +8151,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
81518151 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
81528152 const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
81538153 const sym = elf_file.symbol(sym_index);
8154 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
8155 const got_addr = sym.getOffsetTableAddress(elf_file);
8154 _ = try sym.getOrCreateGotEntry(elf_file);
8155 const got_addr = sym.gotAddress(elf_file);
81568156 try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
81578157 .base = .{ .reg = .ds },
81588158 .disp = @intCast(got_addr),
......@@ -10218,8 +10218,8 @@ fn genLazySymbolRef(
1021810218 const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|
1021910219 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1022010220 const sym = elf_file.symbol(sym_index);
10221 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
10222 const got_addr = sym.getOffsetTableAddress(elf_file);
10221 _ = try sym.getOrCreateGotEntry(elf_file);
10222 const got_addr = sym.gotAddress(elf_file);
1022310223 const got_mem =
1022410224 Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(got_addr) });
1022510225 switch (tag) {
src/codegen.zig+2-2
......@@ -856,8 +856,8 @@ fn genDeclRef(
856856 if (bin_file.cast(link.File.Elf)) |elf_file| {
857857 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
858858 const sym = elf_file.symbol(sym_index);
859 _ = try sym.getOrCreateOffsetTableEntry(elf_file);
860 return GenResult.mcv(.{ .memory = sym.getOffsetTableAddress(elf_file) });
859 _ = try sym.getOrCreateGotEntry(elf_file);
860 return GenResult.mcv(.{ .memory = sym.gotAddress(elf_file) });
861861 } else if (bin_file.cast(link.File.MachO)) |macho_file| {
862862 const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
863863 const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
src/link/Elf.zig+64-70
......@@ -42,6 +42,8 @@ shstrtab: StringTable(.strtab) = .{},
4242/// .strtab buffer
4343strtab: StringTable(.strtab) = .{},
4444
45got: GotSection = .{},
46
4547symtab_section_index: ?u16 = null,
4648text_section_index: ?u16 = null,
4749rodata_section_index: ?u16 = null,
......@@ -56,18 +58,16 @@ shstrtab_section_index: ?u16 = null,
5658strtab_section_index: ?u16 = null,
5759
5860symbols: std.ArrayListUnmanaged(Symbol) = .{},
61symbols_extra: std.ArrayListUnmanaged(u32) = .{},
5962resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
6063unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
6164
6265symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
6366
64got_table: TableSection(Symbol.Index) = .{},
65
6667phdr_table_dirty: bool = false,
6768shdr_table_dirty: bool = false,
6869shstrtab_dirty: bool = false,
6970strtab_dirty: bool = false,
70got_table_count_dirty: bool = false,
7171
7272debug_strtab_dirty: bool = false,
7373debug_abbrev_section_dirty: bool = false,
......@@ -146,6 +146,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
146146
147147 // Index 0 is always a null symbol.
148148 try self.symbols.append(allocator, .{});
149 // Index 0 is always a null symbol.
150 try self.symbols_extra.append(allocator, 0);
149151 // Allocate atom index 0 to null atom
150152 try self.atoms.append(allocator, .{});
151153 // Append null file at index 0
......@@ -234,8 +236,9 @@ pub fn deinit(self: *Elf) void {
234236 self.shstrtab.deinit(gpa);
235237 self.strtab.deinit(gpa);
236238 self.symbols.deinit(gpa);
239 self.symbols_extra.deinit(gpa);
237240 self.symbols_free_list.deinit(gpa);
238 self.got_table.deinit(gpa);
241 self.got.deinit(gpa);
239242 self.resolver.deinit(gpa);
240243 self.unresolved.deinit(gpa);
241244
......@@ -1249,7 +1252,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12491252 assert(!self.shstrtab_dirty);
12501253 assert(!self.strtab_dirty);
12511254 assert(!self.debug_strtab_dirty);
1252 assert(!self.got_table_count_dirty);
1255 assert(!self.got.dirty);
12531256}
12541257
12551258fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
......@@ -2087,7 +2090,7 @@ fn freeDeclMetadata(self: *Elf, sym_index: Symbol.Index) void {
20872090 log.debug("adding %{d} to local symbols free list", .{sym_index});
20882091 self.symbols_free_list.append(self.base.allocator, sym_index) catch {};
20892092 self.symbols.items[sym_index] = .{};
2090 self.got_table.freeEntry(self.base.allocator, sym_index);
2093 // TODO free GOT entry here
20912094}
20922095
20932096pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
......@@ -2226,9 +2229,8 @@ fn updateDeclCode(
22262229 esym.st_value = atom_ptr.value;
22272230
22282231 log.debug(" (writing new offset table entry)", .{});
2229 const got_entry_index = self.got_table.lookup.get(sym_index).?;
2230 self.got_table.entries.items[got_entry_index] = sym_index;
2231 try self.writeOffsetTableEntry(got_entry_index);
2232 const extra = sym.extra(self).?;
2233 try self.got.writeEntry(self, extra.got);
22322234 }
22332235 } else if (code.len < old_size) {
22342236 atom_ptr.shrink(self);
......@@ -2245,8 +2247,8 @@ fn updateDeclCode(
22452247 sym.value = atom_ptr.value;
22462248 esym.st_value = atom_ptr.value;
22472249
2248 const got_entry_index = try sym.getOrCreateOffsetTableEntry(self);
2249 try self.writeOffsetTableEntry(got_entry_index);
2250 const got_index = try sym.getOrCreateGotEntry(self);
2251 try self.got.writeEntry(self, got_index);
22502252 }
22512253
22522254 const phdr_index = self.sections.items(.phdr_index)[shdr_index];
......@@ -2477,8 +2479,8 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
24772479 local_sym.value = atom_ptr.value;
24782480 local_esym.st_value = atom_ptr.value;
24792481
2480 const got_entry_index = try local_sym.getOrCreateOffsetTableEntry(self);
2481 try self.writeOffsetTableEntry(got_entry_index);
2482 const got_index = try local_sym.getOrCreateGotEntry(self);
2483 try self.got.writeEntry(self, got_index);
24822484
24832485 const section_offset = atom_ptr.value - self.program_headers.items[phdr_index].p_vaddr;
24842486 const file_offset = self.sections.items(.shdr)[local_sym.output_section_index].sh_offset + section_offset;
......@@ -2712,61 +2714,6 @@ fn writeSectHeader(self: *Elf, index: usize) !void {
27122714 }
27132715}
27142716
2715fn writeOffsetTableEntry(self: *Elf, index: @TypeOf(self.got_table).Index) !void {
2716 const entry_size: u16 = self.archPtrWidthBytes();
2717 if (self.got_table_count_dirty) {
2718 const needed_size = self.got_table.entries.items.len * entry_size;
2719 try self.growAllocSection(self.got_section_index.?, needed_size);
2720 self.got_table_count_dirty = false;
2721 }
2722 const endian = self.base.options.target.cpu.arch.endian();
2723 const shdr = &self.sections.items(.shdr)[self.got_section_index.?];
2724 const off = shdr.sh_offset + @as(u64, entry_size) * index;
2725 const phdr = &self.program_headers.items[self.phdr_got_index.?];
2726 const vaddr = phdr.p_vaddr + @as(u64, entry_size) * index;
2727 const got_entry = self.got_table.entries.items[index];
2728 const got_value = self.symbol(got_entry).value;
2729 switch (entry_size) {
2730 2 => {
2731 var buf: [2]u8 = undefined;
2732 mem.writeInt(u16, &buf, @as(u16, @intCast(got_value)), endian);
2733 try self.base.file.?.pwriteAll(&buf, off);
2734 },
2735 4 => {
2736 var buf: [4]u8 = undefined;
2737 mem.writeInt(u32, &buf, @as(u32, @intCast(got_value)), endian);
2738 try self.base.file.?.pwriteAll(&buf, off);
2739 },
2740 8 => {
2741 var buf: [8]u8 = undefined;
2742 mem.writeInt(u64, &buf, got_value, endian);
2743 try self.base.file.?.pwriteAll(&buf, off);
2744
2745 if (self.base.child_pid) |pid| {
2746 switch (builtin.os.tag) {
2747 .linux => {
2748 var local_vec: [1]std.os.iovec_const = .{.{
2749 .iov_base = &buf,
2750 .iov_len = buf.len,
2751 }};
2752 var remote_vec: [1]std.os.iovec_const = .{.{
2753 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
2754 .iov_len = buf.len,
2755 }};
2756 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
2757 switch (std.os.errno(rc)) {
2758 .SUCCESS => assert(rc == buf.len),
2759 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
2760 }
2761 },
2762 else => return error.HotSwapUnavailableOnHostOperatingSystem,
2763 }
2764 }
2765 },
2766 else => unreachable,
2767 }
2768}
2769
27702717fn updateSymtabSize(self: *Elf) !void {
27712718 var sizes = SymtabSize{};
27722719
......@@ -2858,8 +2805,8 @@ fn ptrWidthBytes(self: Elf) u8 {
28582805
28592806/// Does not necessarily match `ptrWidthBytes` for example can be 2 bytes
28602807/// in a 32-bit ELF file.
2861fn archPtrWidthBytes(self: Elf) u8 {
2862 return @as(u8, @intCast(self.base.options.target.ptrBitWidth() / 8));
2808pub fn archPtrWidthBytes(self: Elf) u8 {
2809 return @as(u8, @intCast(@divExact(self.base.options.target.ptrBitWidth(), 8)));
28632810}
28642811
28652812fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr {
......@@ -3179,6 +3126,50 @@ pub fn addSymbol(self: *Elf) !Symbol.Index {
31793126 return index;
31803127}
31813128
3129pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
3130 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3131 try self.symbols_extra.ensureUnusedCapacity(self.base.allocator, fields.len);
3132 return self.addSymbolExtraAssumeCapacity(extra);
3133}
3134
3135pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 {
3136 const index = @as(u32, @intCast(self.symbols_extra.items.len));
3137 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3138 inline for (fields) |field| {
3139 self.symbols_extra.appendAssumeCapacity(switch (field.type) {
3140 u32 => @field(extra, field.name),
3141 else => @compileError("bad field type"),
3142 });
3143 }
3144 return index;
3145}
3146
3147pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra {
3148 if (index == 0) return null;
3149 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3150 var i: usize = index;
3151 var result: Symbol.Extra = undefined;
3152 inline for (fields) |field| {
3153 @field(result, field.name) = switch (field.type) {
3154 u32 => self.symbols_extra.items[i],
3155 else => @compileError("bad field type"),
3156 };
3157 i += 1;
3158 }
3159 return result;
3160}
3161
3162pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void {
3163 assert(index > 0);
3164 const fields = @typeInfo(Symbol.Extra).Struct.fields;
3165 inline for (fields, 0..) |field, i| {
3166 self.symbols_extra.items[index + i] = switch (field.type) {
3167 u32 => @field(extra, field.name),
3168 else => @compileError("bad field type"),
3169 };
3170 }
3171}
3172
31823173const GetOrPutGlobalResult = struct {
31833174 found_existing: bool,
31843175 index: Symbol.Index,
......@@ -3227,6 +3218,7 @@ fn fmtDumpState(
32273218 try writer.print("linker_defined({d}) : (linker defined)\n", .{index});
32283219 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
32293220 }
3221 try writer.print("{}\n", .{self.got.fmt(self)});
32303222}
32313223
32323224const default_entry_addr = 0x8000000;
......@@ -3311,6 +3303,7 @@ const lldMain = @import("../main.zig").lldMain;
33113303const musl = @import("../musl.zig");
33123304const target_util = @import("../target.zig");
33133305const trace = @import("../tracy.zig").trace;
3306const synthetic_sections = @import("Elf/synthetic_sections.zig");
33143307
33153308const Air = @import("../Air.zig");
33163309const Allocator = std.mem.Allocator;
......@@ -3320,6 +3313,7 @@ const Compilation = @import("../Compilation.zig");
33203313const Dwarf = @import("Dwarf.zig");
33213314const Elf = @This();
33223315const File = @import("Elf/file.zig").File;
3316const GotSection = synthetic_sections.GotSection;
33233317const LinkerDefined = @import("Elf/LinkerDefined.zig");
33243318const Liveness = @import("../Liveness.zig");
33253319const LlvmObject = @import("../codegen/llvm.zig").Object;
src/link/Elf/Symbol.zig+18-24
......@@ -84,24 +84,6 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
8484 return file_ptr.symbolRank(sym, in_archive);
8585}
8686
87/// If entry already exists, returns index to it.
88/// Otherwise, creates a new entry in the Global Offset Table for this Symbol.
89pub fn getOrCreateOffsetTableEntry(self: Symbol, elf_file: *Elf) !Symbol.Index {
90 if (elf_file.got_table.lookup.get(self.index)) |index| return index;
91 const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, self.index);
92 elf_file.got_table_count_dirty = true;
93 return index;
94}
95
96pub fn getOffsetTableAddress(self: Symbol, elf_file: *Elf) u64 {
97 const got_entry_index = elf_file.got_table.lookup.get(self.index).?;
98 const target = elf_file.base.options.target;
99 const ptr_bits = target.ptrBitWidth();
100 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
101 const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];
102 return got.p_vaddr + got_entry_index * ptr_bytes;
103}
104
10587pub fn address(symbol: Symbol, opts: struct {
10688 plt: bool = true,
10789}, elf_file: *Elf) u64 {
......@@ -122,11 +104,21 @@ pub fn address(symbol: Symbol, opts: struct {
122104 return symbol.value;
123105}
124106
125// pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
126// if (!symbol.flags.got) return 0;
127// const extra = symbol.extra(elf_file).?;
128// return elf_file.gotEntryAddress(extra.got);
129// }
107pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
108 if (!symbol.flags.got) return 0;
109 const extras = symbol.extra(elf_file).?;
110 const entry = elf_file.got.entries.items[extras.got];
111 return entry.address(elf_file);
112}
113
114pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GotSection.Index {
115 const index = if (symbol.flags.got)
116 symbol.extra(elf_file).?.got
117 else
118 try elf_file.got.addGotSymbol(symbol.index, elf_file);
119 symbol.flags.got = true;
120 return index;
121}
130122
131123// pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 {
132124// if (!symbol.flags.tlsgd) return 0;
......@@ -159,7 +151,7 @@ pub fn address(symbol: Symbol, opts: struct {
159151// }
160152
161153pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void {
162 symbol.extra = try elf_file.addSymbolExtra(extras);
154 symbol.extra_index = try elf_file.addSymbolExtra(extras);
163155}
164156
165157pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {
......@@ -347,10 +339,12 @@ pub const Index = u32;
347339const assert = std.debug.assert;
348340const elf = std.elf;
349341const std = @import("std");
342const synthetic_sections = @import("synthetic_sections.zig");
350343
351344const Atom = @import("Atom.zig");
352345const Elf = @import("../Elf.zig");
353346const File = @import("file.zig").File;
347const GotSection = synthetic_sections.GotSection;
354348const LinkerDefined = @import("LinkerDefined.zig");
355349// const Object = @import("Object.zig");
356350// const SharedObject = @import("SharedObject.zig");
src/link/Elf/synthetic_sections.zig created+469
......@@ -0,0 +1,469 @@
1pub const GotSection = struct {
2 entries: std.ArrayListUnmanaged(Entry) = .{},
3 needs_rela: bool = false,
4 dirty: bool = false,
5 output_symtab_size: Elf.SymtabSize = .{},
6
7 pub const Index = u32;
8
9 const Tag = enum {
10 got,
11 tlsld,
12 tlsgd,
13 gottp,
14 tlsdesc,
15 };
16
17 const Entry = struct {
18 tag: Tag,
19 symbol_index: Symbol.Index,
20 cell_index: Index,
21
22 /// Returns how many indexes in the GOT this entry uses.
23 pub inline fn len(entry: Entry) usize {
24 return switch (entry.tag) {
25 .got, .gottp => 1,
26 .tlsld, .tlsgd, .tlsdesc => 2,
27 };
28 }
29
30 pub fn address(entry: Entry, elf_file: *Elf) u64 {
31 const ptr_bytes = @as(u64, elf_file.archPtrWidthBytes());
32 const shdr = &elf_file.sections.items(.shdr)[elf_file.got_section_index.?];
33 return shdr.sh_addr + @as(u64, entry.cell_index) * ptr_bytes;
34 }
35 };
36
37 pub fn deinit(got: *GotSection, allocator: Allocator) void {
38 got.entries.deinit(allocator);
39 }
40
41 fn allocateEntry(got: *GotSection, allocator: Allocator) !Index {
42 try got.entries.ensureUnusedCapacity(allocator, 1);
43 // TODO add free list
44 const index = @as(Index, @intCast(got.entries.items.len));
45 const entry = got.entries.addOneAssumeCapacity();
46 const cell_index: Index = if (index > 0) blk: {
47 const last = got.entries.items[index - 1];
48 break :blk last.cell_index + @as(Index, @intCast(last.len()));
49 } else 0;
50 entry.* = .{ .tag = undefined, .symbol_index = undefined, .cell_index = cell_index };
51 got.dirty = true;
52 return index;
53 }
54
55 pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
56 const index = try got.allocateEntry(elf_file.base.allocator);
57 const entry = &got.entries.items[index];
58 entry.tag = .got;
59 entry.symbol_index = sym_index;
60 const symbol = elf_file.symbol(sym_index);
61 if (symbol.flags.import or symbol.isIFunc(elf_file) or (elf_file.base.options.pic and !symbol.isAbs(elf_file)))
62 got.needs_rela = true;
63 if (symbol.extra(elf_file)) |extra| {
64 var new_extra = extra;
65 new_extra.got = index;
66 symbol.setExtra(new_extra, elf_file);
67 } else try symbol.addExtra(.{ .got = index }, elf_file);
68 return index;
69 }
70
71 // pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
72 // const index = got.next_index;
73 // const symbol = elf_file.getSymbol(sym_index);
74 // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true;
75 // if (symbol.getExtra(elf_file)) |extra| {
76 // var new_extra = extra;
77 // new_extra.tlsgd = index;
78 // symbol.setExtra(new_extra, elf_file);
79 // } else try symbol.addExtra(.{ .tlsgd = index }, elf_file);
80 // try got.symbols.append(elf_file.base.allocator, .{ .tlsgd = sym_index });
81 // got.next_index += 2;
82 // }
83
84 // pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
85 // const index = got.next_index;
86 // const symbol = elf_file.getSymbol(sym_index);
87 // if (symbol.flags.import or elf_file.options.output_mode == .lib) got.needs_rela = true;
88 // if (symbol.getExtra(elf_file)) |extra| {
89 // var new_extra = extra;
90 // new_extra.gottp = index;
91 // symbol.setExtra(new_extra, elf_file);
92 // } else try symbol.addExtra(.{ .gottp = index }, elf_file);
93 // try got.symbols.append(elf_file.base.allocator, .{ .gottp = sym_index });
94 // got.next_index += 1;
95 // }
96
97 // pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
98 // const index = got.next_index;
99 // const symbol = elf_file.getSymbol(sym_index);
100 // got.needs_rela = true;
101 // if (symbol.getExtra(elf_file)) |extra| {
102 // var new_extra = extra;
103 // new_extra.tlsdesc = index;
104 // symbol.setExtra(new_extra, elf_file);
105 // } else try symbol.addExtra(.{ .tlsdesc = index }, elf_file);
106 // try got.symbols.append(elf_file.base.allocator, .{ .tlsdesc = sym_index });
107 // got.next_index += 2;
108 // }
109
110 pub fn size(got: GotSection, elf_file: *Elf) usize {
111 var s: usize = 0;
112 for (got.entries.items) |entry| {
113 s += elf_file.archPtrWidthBytes() * entry.len();
114 }
115 return s;
116 }
117
118 pub fn writeEntry(got: *GotSection, elf_file: *Elf, index: Index) !void {
119 const entry_size: u16 = elf_file.archPtrWidthBytes();
120 if (got.dirty) {
121 const needed_size = got.size(elf_file);
122 try elf_file.growAllocSection(elf_file.got_section_index.?, needed_size);
123 got.dirty = false;
124 }
125 const endian = elf_file.base.options.target.cpu.arch.endian();
126 const entry = got.entries.items[index];
127 const shdr = &elf_file.sections.items(.shdr)[elf_file.got_section_index.?];
128 const off = shdr.sh_offset + @as(u64, entry_size) * entry.cell_index;
129 const vaddr = shdr.sh_addr + @as(u64, entry_size) * entry.cell_index;
130 const value = elf_file.symbol(entry.symbol_index).value;
131 switch (entry_size) {
132 2 => {
133 var buf: [2]u8 = undefined;
134 std.mem.writeInt(u16, &buf, @as(u16, @intCast(value)), endian);
135 try elf_file.base.file.?.pwriteAll(&buf, off);
136 },
137 4 => {
138 var buf: [4]u8 = undefined;
139 std.mem.writeInt(u32, &buf, @as(u32, @intCast(value)), endian);
140 try elf_file.base.file.?.pwriteAll(&buf, off);
141 },
142 8 => {
143 var buf: [8]u8 = undefined;
144 std.mem.writeInt(u64, &buf, value, endian);
145 try elf_file.base.file.?.pwriteAll(&buf, off);
146
147 if (elf_file.base.child_pid) |pid| {
148 switch (builtin.os.tag) {
149 .linux => {
150 var local_vec: [1]std.os.iovec_const = .{.{
151 .iov_base = &buf,
152 .iov_len = buf.len,
153 }};
154 var remote_vec: [1]std.os.iovec_const = .{.{
155 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(vaddr)))),
156 .iov_len = buf.len,
157 }};
158 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
159 switch (std.os.errno(rc)) {
160 .SUCCESS => assert(rc == buf.len),
161 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
162 }
163 },
164 else => return error.HotSwapUnavailableOnHostOperatingSystem,
165 }
166 }
167 },
168 else => unreachable,
169 }
170 }
171
172 // pub fn write(got: GotSection, elf_file: *Elf, writer: anytype) !void {
173 // const is_shared = elf_file.options.output_mode == .lib;
174 // const apply_relocs = elf_file.options.apply_dynamic_relocs;
175
176 // for (got.symbols.items) |sym| {
177 // const symbol = elf_file.getSymbol(sym.getIndex());
178 // switch (sym) {
179 // .got => {
180 // const value: u64 = blk: {
181 // const value = symbol.getAddress(.{ .plt = false }, elf_file);
182 // if (symbol.flags.import) break :blk 0;
183 // if (symbol.isIFunc(elf_file))
184 // break :blk if (apply_relocs) value else 0;
185 // if (elf_file.options.pic and !symbol.isAbs(elf_file))
186 // break :blk if (apply_relocs) value else 0;
187 // break :blk value;
188 // };
189 // try writer.writeIntLittle(u64, value);
190 // },
191
192 // .tlsgd => {
193 // if (symbol.flags.import) {
194 // try writer.writeIntLittle(u64, 0);
195 // try writer.writeIntLittle(u64, 0);
196 // } else {
197 // try writer.writeIntLittle(u64, if (is_shared) @as(u64, 0) else 1);
198 // const offset = symbol.getAddress(.{}, elf_file) - elf_file.getDtpAddress();
199 // try writer.writeIntLittle(u64, offset);
200 // }
201 // },
202
203 // .gottp => {
204 // if (symbol.flags.import) {
205 // try writer.writeIntLittle(u64, 0);
206 // } else if (is_shared) {
207 // const offset = if (apply_relocs)
208 // symbol.getAddress(.{}, elf_file) - elf_file.getTlsAddress()
209 // else
210 // 0;
211 // try writer.writeIntLittle(u64, offset);
212 // } else {
213 // const offset = @as(i64, @intCast(symbol.getAddress(.{}, elf_file))) -
214 // @as(i64, @intCast(elf_file.getTpAddress()));
215 // try writer.writeIntLittle(u64, @as(u64, @bitCast(offset)));
216 // }
217 // },
218
219 // .tlsdesc => {
220 // try writer.writeIntLittle(u64, 0);
221 // try writer.writeIntLittle(u64, 0);
222 // },
223 // }
224 // }
225
226 // if (got.emit_tlsld) {
227 // try writer.writeIntLittle(u64, if (is_shared) @as(u64, 0) else 1);
228 // try writer.writeIntLittle(u64, 0);
229 // }
230 // }
231
232 // pub fn addRela(got: GotSection, elf_file: *Elf) !void {
233 // const is_shared = elf_file.options.output_mode == .lib;
234 // try elf_file.rela_dyn.ensureUnusedCapacity(elf_file.base.allocator, got.numRela(elf_file));
235
236 // for (got.symbols.items) |sym| {
237 // const symbol = elf_file.getSymbol(sym.getIndex());
238 // const extra = symbol.getExtra(elf_file).?;
239
240 // switch (sym) {
241 // .got => {
242 // const offset = symbol.gotAddress(elf_file);
243
244 // if (symbol.flags.import) {
245 // elf_file.addRelaDynAssumeCapacity(.{
246 // .offset = offset,
247 // .sym = extra.dynamic,
248 // .type = elf.R_X86_64_GLOB_DAT,
249 // });
250 // continue;
251 // }
252
253 // if (symbol.isIFunc(elf_file)) {
254 // elf_file.addRelaDynAssumeCapacity(.{
255 // .offset = offset,
256 // .type = elf.R_X86_64_IRELATIVE,
257 // .addend = @intCast(symbol.getAddress(.{ .plt = false }, elf_file)),
258 // });
259 // continue;
260 // }
261
262 // if (elf_file.options.pic and !symbol.isAbs(elf_file)) {
263 // elf_file.addRelaDynAssumeCapacity(.{
264 // .offset = offset,
265 // .type = elf.R_X86_64_RELATIVE,
266 // .addend = @intCast(symbol.getAddress(.{ .plt = false }, elf_file)),
267 // });
268 // }
269 // },
270
271 // .tlsgd => {
272 // const offset = symbol.getTlsGdAddress(elf_file);
273 // if (symbol.flags.import) {
274 // elf_file.addRelaDynAssumeCapacity(.{
275 // .offset = offset,
276 // .sym = extra.dynamic,
277 // .type = elf.R_X86_64_DTPMOD64,
278 // });
279 // elf_file.addRelaDynAssumeCapacity(.{
280 // .offset = offset + 8,
281 // .sym = extra.dynamic,
282 // .type = elf.R_X86_64_DTPOFF64,
283 // });
284 // } else if (is_shared) {
285 // elf_file.addRelaDynAssumeCapacity(.{
286 // .offset = offset,
287 // .sym = extra.dynamic,
288 // .type = elf.R_X86_64_DTPMOD64,
289 // });
290 // }
291 // },
292
293 // .gottp => {
294 // const offset = symbol.getGotTpAddress(elf_file);
295 // if (symbol.flags.import) {
296 // elf_file.addRelaDynAssumeCapacity(.{
297 // .offset = offset,
298 // .sym = extra.dynamic,
299 // .type = elf.R_X86_64_TPOFF64,
300 // });
301 // } else if (is_shared) {
302 // elf_file.addRelaDynAssumeCapacity(.{
303 // .offset = offset,
304 // .type = elf.R_X86_64_TPOFF64,
305 // .addend = @intCast(symbol.getAddress(.{}, elf_file) - elf_file.getTlsAddress()),
306 // });
307 // }
308 // },
309
310 // .tlsdesc => {
311 // const offset = symbol.getTlsDescAddress(elf_file);
312 // elf_file.addRelaDynAssumeCapacity(.{
313 // .offset = offset,
314 // .sym = extra.dynamic,
315 // .type = elf.R_X86_64_TLSDESC,
316 // });
317 // },
318 // }
319 // }
320
321 // if (is_shared and got.emit_tlsld) {
322 // const offset = elf_file.getTlsLdAddress();
323 // elf_file.addRelaDynAssumeCapacity(.{
324 // .offset = offset,
325 // .type = elf.R_X86_64_DTPMOD64,
326 // });
327 // }
328 // }
329
330 // pub fn numRela(got: GotSection, elf_file: *Elf) usize {
331 // const is_shared = elf_file.options.output_mode == .lib;
332 // var num: usize = 0;
333 // for (got.symbols.items) |sym| {
334 // const symbol = elf_file.symbol(sym.index());
335 // switch (sym) {
336 // .got => if (symbol.flags.import or
337 // symbol.isIFunc(elf_file) or (elf_file.options.pic and !symbol.isAbs(elf_file)))
338 // {
339 // num += 1;
340 // },
341
342 // .tlsgd => if (symbol.flags.import) {
343 // num += 2;
344 // } else if (is_shared) {
345 // num += 1;
346 // },
347
348 // .gottp => if (symbol.flags.import or is_shared) {
349 // num += 1;
350 // },
351
352 // .tlsdesc => num += 1,
353 // }
354 // }
355 // if (is_shared and got.emit_tlsld) num += 1;
356 // return num;
357 // }
358
359 pub fn calcSymtabSize(got: *GotSection, elf_file: *Elf) !void {
360 got.output_symtab_size.nlocals = @as(u32, @intCast(got.symbols.items.len));
361 for (got.symbols.items) |sym| {
362 const suffix_len = switch (sym) {
363 .tlsgd => "$tlsgd".len,
364 .got => "$got".len,
365 .gottp => "$gottp".len,
366 .tlsdesc => "$tlsdesc".len,
367 };
368 const symbol = elf_file.getSymbol(sym.getIndex());
369 const name_len = symbol.getName(elf_file).len;
370 got.output_symtab_size.strsize += @as(u32, @intCast(name_len + suffix_len + 1));
371 }
372
373 if (got.emit_tlsld) {
374 got.output_symtab_size.nlocals += 1;
375 got.output_symtab_size.strsize += @as(u32, @intCast("$tlsld".len + 1));
376 }
377 }
378
379 pub fn writeSymtab(got: GotSection, elf_file: *Elf, ctx: anytype) !void {
380 const gpa = elf_file.base.allocator;
381
382 var ilocal = ctx.ilocal;
383 for (got.symbols.items) |sym| {
384 const suffix = switch (sym) {
385 .tlsgd => "$tlsgd",
386 .got => "$got",
387 .gottp => "$gottp",
388 .tlsdesc => "$tlsdesc",
389 };
390 const symbol = elf_file.getSymbol(sym.getIndex());
391 const name = try std.fmt.allocPrint(gpa, "{s}{s}", .{ symbol.getName(elf_file), suffix });
392 defer gpa.free(name);
393 const st_name = try ctx.strtab.insert(gpa, name);
394 const st_value = switch (sym) {
395 // .tlsgd => symbol.tlsGdAddress(elf_file),
396 .got => symbol.gotAddress(elf_file),
397 // .gottp => symbol.gotTpAddress(elf_file),
398 // .tlsdesc => symbol.tlsDescAddress(elf_file),
399 else => unreachable,
400 };
401 const st_size: u64 = switch (sym) {
402 .tlsgd, .tlsdesc => 16,
403 .got, .gottp => 8,
404 };
405 ctx.symtab[ilocal] = .{
406 .st_name = st_name,
407 .st_info = elf.STT_OBJECT,
408 .st_other = 0,
409 .st_shndx = elf_file.got_section_index.?,
410 .st_value = st_value,
411 .st_size = st_size,
412 };
413 ilocal += 1;
414 }
415
416 // if (got.emit_tlsld) {
417 // const st_name = try ctx.strtab.insert(gpa, "$tlsld");
418 // ctx.symtab[ilocal] = .{
419 // .st_name = st_name,
420 // .st_info = elf.STT_OBJECT,
421 // .st_other = 0,
422 // .st_shndx = elf_file.got_sect_index.?,
423 // .st_value = elf_file.getTlsLdAddress(),
424 // .st_size = 16,
425 // };
426 // ilocal += 1;
427 // }
428 }
429
430 const FormatCtx = struct {
431 got: GotSection,
432 elf_file: *Elf,
433 };
434
435 pub fn fmt(got: GotSection, elf_file: *Elf) std.fmt.Formatter(format2) {
436 return .{ .data = .{ .got = got, .elf_file = elf_file } };
437 }
438
439 pub fn format2(
440 ctx: FormatCtx,
441 comptime unused_fmt_string: []const u8,
442 options: std.fmt.FormatOptions,
443 writer: anytype,
444 ) !void {
445 _ = options;
446 _ = unused_fmt_string;
447 try writer.writeAll("GOT\n");
448 for (ctx.got.entries.items) |entry| {
449 const symbol = ctx.elf_file.symbol(entry.symbol_index);
450 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
451 entry.cell_index,
452 entry.address(ctx.elf_file),
453 entry.symbol_index,
454 symbol.address(.{}, ctx.elf_file),
455 symbol.name(ctx.elf_file),
456 });
457 }
458 }
459};
460
461const assert = std.debug.assert;
462const builtin = @import("builtin");
463const elf = std.elf;
464const log = std.log.scoped(.link);
465const std = @import("std");
466
467const Allocator = std.mem.Allocator;
468const Elf = @import("../Elf.zig");
469const Symbol = @import("Symbol.zig");