| author | |
| committer | |
| log | 6ad5db030c576ab9cf944b4a9432954681af649c |
| tree | ac50a0993e886548dc45a2a900731b33527f9c09 |
| parent | 9691d1a30ff524be5dc2cc88855b7887cd7f26f3 |
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 |
| 4316 | 4316 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4317 | 4317 | const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl); |
| 4318 | 4318 | 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))); | |
| 4321 | 4321 | try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr }); |
| 4322 | 4322 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 4323 | 4323 | 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 |
| 4296 | 4296 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 4297 | 4297 | const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl); |
| 4298 | 4298 | 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))); | |
| 4301 | 4301 | try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr }); |
| 4302 | 4302 | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 4303 | 4303 | 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 |
| 1749 | 1749 | .func => |func| { |
| 1750 | 1750 | const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl); |
| 1751 | 1751 | 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))); | |
| 1754 | 1754 | try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr }); |
| 1755 | 1755 | _ = try self.addInst(.{ |
| 1756 | 1756 | .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 |
| 1351 | 1351 | const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: { |
| 1352 | 1352 | const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl); |
| 1353 | 1353 | 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))); | |
| 1356 | 1356 | } else unreachable; |
| 1357 | 1357 | |
| 1358 | 1358 | 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 |
| 8151 | 8151 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8152 | 8152 | const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); |
| 8153 | 8153 | 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); | |
| 8156 | 8156 | try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{ |
| 8157 | 8157 | .base = .{ .reg = .ds }, |
| 8158 | 8158 | .disp = @intCast(got_addr), |
| ... | ... | @@ -10218,8 +10218,8 @@ fn genLazySymbolRef( |
| 10218 | 10218 | const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err| |
| 10219 | 10219 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 10220 | 10220 | 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); | |
| 10223 | 10223 | const got_mem = |
| 10224 | 10224 | Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(got_addr) }); |
| 10225 | 10225 | switch (tag) { |
src/codegen.zig+2-2| ... | ... | @@ -856,8 +856,8 @@ fn genDeclRef( |
| 856 | 856 | if (bin_file.cast(link.File.Elf)) |elf_file| { |
| 857 | 857 | const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index); |
| 858 | 858 | 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) }); | |
| 861 | 861 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { |
| 862 | 862 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); |
| 863 | 863 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
src/link/Elf.zig+64-70| ... | ... | @@ -42,6 +42,8 @@ shstrtab: StringTable(.strtab) = .{}, |
| 42 | 42 | /// .strtab buffer |
| 43 | 43 | strtab: StringTable(.strtab) = .{}, |
| 44 | 44 | |
| 45 | got: GotSection = .{}, | |
| 46 | ||
| 45 | 47 | symtab_section_index: ?u16 = null, |
| 46 | 48 | text_section_index: ?u16 = null, |
| 47 | 49 | rodata_section_index: ?u16 = null, |
| ... | ... | @@ -56,18 +58,16 @@ shstrtab_section_index: ?u16 = null, |
| 56 | 58 | strtab_section_index: ?u16 = null, |
| 57 | 59 | |
| 58 | 60 | symbols: std.ArrayListUnmanaged(Symbol) = .{}, |
| 61 | symbols_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 59 | 62 | resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{}, |
| 60 | 63 | unresolved: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 61 | 64 | |
| 62 | 65 | symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 63 | 66 | |
| 64 | got_table: TableSection(Symbol.Index) = .{}, | |
| 65 | ||
| 66 | 67 | phdr_table_dirty: bool = false, |
| 67 | 68 | shdr_table_dirty: bool = false, |
| 68 | 69 | shstrtab_dirty: bool = false, |
| 69 | 70 | strtab_dirty: bool = false, |
| 70 | got_table_count_dirty: bool = false, | |
| 71 | 71 | |
| 72 | 72 | debug_strtab_dirty: bool = false, |
| 73 | 73 | debug_abbrev_section_dirty: bool = false, |
| ... | ... | @@ -146,6 +146,8 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 146 | 146 | |
| 147 | 147 | // Index 0 is always a null symbol. |
| 148 | 148 | try self.symbols.append(allocator, .{}); |
| 149 | // Index 0 is always a null symbol. | |
| 150 | try self.symbols_extra.append(allocator, 0); | |
| 149 | 151 | // Allocate atom index 0 to null atom |
| 150 | 152 | try self.atoms.append(allocator, .{}); |
| 151 | 153 | // Append null file at index 0 |
| ... | ... | @@ -234,8 +236,9 @@ pub fn deinit(self: *Elf) void { |
| 234 | 236 | self.shstrtab.deinit(gpa); |
| 235 | 237 | self.strtab.deinit(gpa); |
| 236 | 238 | self.symbols.deinit(gpa); |
| 239 | self.symbols_extra.deinit(gpa); | |
| 237 | 240 | self.symbols_free_list.deinit(gpa); |
| 238 | self.got_table.deinit(gpa); | |
| 241 | self.got.deinit(gpa); | |
| 239 | 242 | self.resolver.deinit(gpa); |
| 240 | 243 | self.unresolved.deinit(gpa); |
| 241 | 244 | |
| ... | ... | @@ -1249,7 +1252,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1249 | 1252 | assert(!self.shstrtab_dirty); |
| 1250 | 1253 | assert(!self.strtab_dirty); |
| 1251 | 1254 | assert(!self.debug_strtab_dirty); |
| 1252 | assert(!self.got_table_count_dirty); | |
| 1255 | assert(!self.got.dirty); | |
| 1253 | 1256 | } |
| 1254 | 1257 | |
| 1255 | 1258 | fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| ... | ... | @@ -2087,7 +2090,7 @@ fn freeDeclMetadata(self: *Elf, sym_index: Symbol.Index) void { |
| 2087 | 2090 | log.debug("adding %{d} to local symbols free list", .{sym_index}); |
| 2088 | 2091 | self.symbols_free_list.append(self.base.allocator, sym_index) catch {}; |
| 2089 | 2092 | self.symbols.items[sym_index] = .{}; |
| 2090 | self.got_table.freeEntry(self.base.allocator, sym_index); | |
| 2093 | // TODO free GOT entry here | |
| 2091 | 2094 | } |
| 2092 | 2095 | |
| 2093 | 2096 | pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| ... | ... | @@ -2226,9 +2229,8 @@ fn updateDeclCode( |
| 2226 | 2229 | esym.st_value = atom_ptr.value; |
| 2227 | 2230 | |
| 2228 | 2231 | 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); | |
| 2232 | 2234 | } |
| 2233 | 2235 | } else if (code.len < old_size) { |
| 2234 | 2236 | atom_ptr.shrink(self); |
| ... | ... | @@ -2245,8 +2247,8 @@ fn updateDeclCode( |
| 2245 | 2247 | sym.value = atom_ptr.value; |
| 2246 | 2248 | esym.st_value = atom_ptr.value; |
| 2247 | 2249 | |
| 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); | |
| 2250 | 2252 | } |
| 2251 | 2253 | |
| 2252 | 2254 | 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. |
| 2477 | 2479 | local_sym.value = atom_ptr.value; |
| 2478 | 2480 | local_esym.st_value = atom_ptr.value; |
| 2479 | 2481 | |
| 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); | |
| 2482 | 2484 | |
| 2483 | 2485 | const section_offset = atom_ptr.value - self.program_headers.items[phdr_index].p_vaddr; |
| 2484 | 2486 | 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 { |
| 2712 | 2714 | } |
| 2713 | 2715 | } |
| 2714 | 2716 | |
| 2715 | fn 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 | ||
| 2770 | 2717 | fn updateSymtabSize(self: *Elf) !void { |
| 2771 | 2718 | var sizes = SymtabSize{}; |
| 2772 | 2719 | |
| ... | ... | @@ -2858,8 +2805,8 @@ fn ptrWidthBytes(self: Elf) u8 { |
| 2858 | 2805 | |
| 2859 | 2806 | /// Does not necessarily match `ptrWidthBytes` for example can be 2 bytes |
| 2860 | 2807 | /// in a 32-bit ELF file. |
| 2861 | fn archPtrWidthBytes(self: Elf) u8 { | |
| 2862 | return @as(u8, @intCast(self.base.options.target.ptrBitWidth() / 8)); | |
| 2808 | pub fn archPtrWidthBytes(self: Elf) u8 { | |
| 2809 | return @as(u8, @intCast(@divExact(self.base.options.target.ptrBitWidth(), 8))); | |
| 2863 | 2810 | } |
| 2864 | 2811 | |
| 2865 | 2812 | fn progHeaderTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr { |
| ... | ... | @@ -3179,6 +3126,50 @@ pub fn addSymbol(self: *Elf) !Symbol.Index { |
| 3179 | 3126 | return index; |
| 3180 | 3127 | } |
| 3181 | 3128 | |
| 3129 | pub 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 | ||
| 3135 | pub 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 | ||
| 3147 | pub 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 | ||
| 3162 | pub 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 | ||
| 3182 | 3173 | const GetOrPutGlobalResult = struct { |
| 3183 | 3174 | found_existing: bool, |
| 3184 | 3175 | index: Symbol.Index, |
| ... | ... | @@ -3227,6 +3218,7 @@ fn fmtDumpState( |
| 3227 | 3218 | try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); |
| 3228 | 3219 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); |
| 3229 | 3220 | } |
| 3221 | try writer.print("{}\n", .{self.got.fmt(self)}); | |
| 3230 | 3222 | } |
| 3231 | 3223 | |
| 3232 | 3224 | const default_entry_addr = 0x8000000; |
| ... | ... | @@ -3311,6 +3303,7 @@ const lldMain = @import("../main.zig").lldMain; |
| 3311 | 3303 | const musl = @import("../musl.zig"); |
| 3312 | 3304 | const target_util = @import("../target.zig"); |
| 3313 | 3305 | const trace = @import("../tracy.zig").trace; |
| 3306 | const synthetic_sections = @import("Elf/synthetic_sections.zig"); | |
| 3314 | 3307 | |
| 3315 | 3308 | const Air = @import("../Air.zig"); |
| 3316 | 3309 | const Allocator = std.mem.Allocator; |
| ... | ... | @@ -3320,6 +3313,7 @@ const Compilation = @import("../Compilation.zig"); |
| 3320 | 3313 | const Dwarf = @import("Dwarf.zig"); |
| 3321 | 3314 | const Elf = @This(); |
| 3322 | 3315 | const File = @import("Elf/file.zig").File; |
| 3316 | const GotSection = synthetic_sections.GotSection; | |
| 3323 | 3317 | const LinkerDefined = @import("Elf/LinkerDefined.zig"); |
| 3324 | 3318 | const Liveness = @import("../Liveness.zig"); |
| 3325 | 3319 | const 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 { |
| 84 | 84 | return file_ptr.symbolRank(sym, in_archive); |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | /// If entry already exists, returns index to it. | |
| 88 | /// Otherwise, creates a new entry in the Global Offset Table for this Symbol. | |
| 89 | pub 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 | ||
| 96 | pub 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 | ||
| 105 | 87 | pub fn address(symbol: Symbol, opts: struct { |
| 106 | 88 | plt: bool = true, |
| 107 | 89 | }, elf_file: *Elf) u64 { |
| ... | ... | @@ -122,11 +104,21 @@ pub fn address(symbol: Symbol, opts: struct { |
| 122 | 104 | return symbol.value; |
| 123 | 105 | } |
| 124 | 106 | |
| 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 | // } | |
| 107 | pub 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 | ||
| 114 | pub 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 | } | |
| 130 | 122 | |
| 131 | 123 | // pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| 132 | 124 | // if (!symbol.flags.tlsgd) return 0; |
| ... | ... | @@ -159,7 +151,7 @@ pub fn address(symbol: Symbol, opts: struct { |
| 159 | 151 | // } |
| 160 | 152 | |
| 161 | 153 | pub 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); | |
| 163 | 155 | } |
| 164 | 156 | |
| 165 | 157 | pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra { |
| ... | ... | @@ -347,10 +339,12 @@ pub const Index = u32; |
| 347 | 339 | const assert = std.debug.assert; |
| 348 | 340 | const elf = std.elf; |
| 349 | 341 | const std = @import("std"); |
| 342 | const synthetic_sections = @import("synthetic_sections.zig"); | |
| 350 | 343 | |
| 351 | 344 | const Atom = @import("Atom.zig"); |
| 352 | 345 | const Elf = @import("../Elf.zig"); |
| 353 | 346 | const File = @import("file.zig").File; |
| 347 | const GotSection = synthetic_sections.GotSection; | |
| 354 | 348 | const LinkerDefined = @import("LinkerDefined.zig"); |
| 355 | 349 | // const Object = @import("Object.zig"); |
| 356 | 350 | // const SharedObject = @import("SharedObject.zig"); |
src/link/Elf/synthetic_sections.zig created+469| ... | ... | @@ -0,0 +1,469 @@ |
| 1 | pub 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 | ||
| 461 | const assert = std.debug.assert; | |
| 462 | const builtin = @import("builtin"); | |
| 463 | const elf = std.elf; | |
| 464 | const log = std.log.scoped(.link); | |
| 465 | const std = @import("std"); | |
| 466 | ||
| 467 | const Allocator = std.mem.Allocator; | |
| 468 | const Elf = @import("../Elf.zig"); | |
| 469 | const Symbol = @import("Symbol.zig"); |