| author | |
| committer | |
| log | 44e84af874bc01fe0657d20548f69801cf18dccd |
| tree | 625548683a305d96c3b3505cbb658d114e3f5a7e |
| parent | c654f3b0ee8d02d809bb458e1e006b4aa7c3cbc6 |
7 files changed, 115 insertions(+), 20 deletions(-)
src/arch/x86_64/CodeGen.zig+2| ... | ... | @@ -8156,6 +8156,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8156 | 8156 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8157 | 8157 | const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); |
| 8158 | 8158 | const sym = elf_file.symbol(sym_index); |
| 8159 | sym.flags.needs_got = true; | |
| 8159 | 8160 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 8160 | 8161 | const got_addr = sym.gotAddress(elf_file); |
| 8161 | 8162 | try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{ |
| ... | ... | @@ -10234,6 +10235,7 @@ fn genLazySymbolRef( |
| 10234 | 10235 | const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err| |
| 10235 | 10236 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 10236 | 10237 | const sym = elf_file.symbol(sym_index); |
| 10238 | sym.flags.needs_got = true; | |
| 10237 | 10239 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 10238 | 10240 | const got_addr = sym.gotAddress(elf_file); |
| 10239 | 10241 | const got_mem = |
src/codegen.zig+1| ... | ... | @@ -856,6 +856,7 @@ 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 | sym.flags.needs_got = true; | |
| 859 | 860 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 860 | 861 | return GenResult.mcv(.{ .memory = sym.gotAddress(elf_file) }); |
| 861 | 862 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { |
src/link/Elf.zig+29-6| ... | ... | @@ -1049,8 +1049,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1049 | 1049 | self.resolveSymbols(); |
| 1050 | 1050 | self.markImportsExports(); |
| 1051 | 1051 | self.claimUnresolved(); |
| 1052 | ||
| 1053 | if (self.unresolved.keys().len > 0) try self.reportUndefined(); | |
| 1052 | try self.scanRelocs(); | |
| 1054 | 1053 | |
| 1055 | 1054 | self.allocateLinkerDefinedSymbols(); |
| 1056 | 1055 | |
| ... | ... | @@ -1381,6 +1380,28 @@ fn claimUnresolved(self: *Elf) void { |
| 1381 | 1380 | } |
| 1382 | 1381 | } |
| 1383 | 1382 | |
| 1383 | fn scanRelocs(self: *Elf) !void { | |
| 1384 | if (self.zig_module_index) |index| { | |
| 1385 | const zig_module = self.file(index).?.zig_module; | |
| 1386 | try zig_module.scanRelocs(self); | |
| 1387 | } | |
| 1388 | for (self.objects.items) |index| { | |
| 1389 | const object = self.file(index).?.object; | |
| 1390 | try object.scanRelocs(self); | |
| 1391 | } | |
| 1392 | ||
| 1393 | // try self.reportUndefined(); | |
| 1394 | ||
| 1395 | for (self.symbols.items) |*sym| { | |
| 1396 | if (sym.flags.needs_got) { | |
| 1397 | log.debug("'{s}' needs GOT", .{sym.name(self)}); | |
| 1398 | // TODO how can we tell we need to write it again, aka the entry is dirty? | |
| 1399 | const gop = try sym.getOrCreateGotEntry(self); | |
| 1400 | try self.got.writeEntry(self, gop.index); | |
| 1401 | } | |
| 1402 | } | |
| 1403 | } | |
| 1404 | ||
| 1384 | 1405 | fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 1385 | 1406 | const tracy = trace(@src()); |
| 1386 | 1407 | defer tracy.end(); |
| ... | ... | @@ -2375,8 +2396,9 @@ fn updateDeclCode( |
| 2375 | 2396 | sym.value = atom_ptr.value; |
| 2376 | 2397 | esym.st_value = atom_ptr.value; |
| 2377 | 2398 | |
| 2378 | const got_index = try sym.getOrCreateGotEntry(self); | |
| 2379 | try self.got.writeEntry(self, got_index); | |
| 2399 | sym.flags.needs_got = true; | |
| 2400 | const gop = try sym.getOrCreateGotEntry(self); | |
| 2401 | try self.got.writeEntry(self, gop.index); | |
| 2380 | 2402 | } |
| 2381 | 2403 | |
| 2382 | 2404 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; |
| ... | ... | @@ -2609,8 +2631,9 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2609 | 2631 | local_sym.value = atom_ptr.value; |
| 2610 | 2632 | local_esym.st_value = atom_ptr.value; |
| 2611 | 2633 | |
| 2612 | const got_index = try local_sym.getOrCreateGotEntry(self); | |
| 2613 | try self.got.writeEntry(self, got_index); | |
| 2634 | local_sym.flags.needs_got = true; | |
| 2635 | const gop = try local_sym.getOrCreateGotEntry(self); | |
| 2636 | try self.got.writeEntry(self, gop.index); | |
| 2614 | 2637 | |
| 2615 | 2638 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; |
| 2616 | 2639 | const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset; |
src/link/Elf/Atom.zig+54| ... | ... | @@ -311,6 +311,57 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void { |
| 311 | 311 | zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity(); |
| 312 | 312 | } |
| 313 | 313 | |
| 314 | pub fn scanRelocs(self: Atom, elf_file: *Elf) !void { | |
| 315 | const file_ptr = elf_file.file(self.file_index).?; | |
| 316 | const rels = self.relocs(elf_file); | |
| 317 | var i: usize = 0; | |
| 318 | while (i < rels.len) : (i += 1) { | |
| 319 | const rel = rels[i]; | |
| 320 | ||
| 321 | if (rel.r_type() == elf.R_X86_64_NONE) continue; | |
| 322 | ||
| 323 | const symbol = switch (file_ptr) { | |
| 324 | .zig_module => elf_file.symbol(rel.r_sym()), | |
| 325 | .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]), | |
| 326 | else => unreachable, | |
| 327 | }; | |
| 328 | ||
| 329 | // While traversing relocations, mark symbols that require special handling such as | |
| 330 | // pointer indirection via GOT, or a stub trampoline via PLT. | |
| 331 | switch (rel.r_type()) { | |
| 332 | elf.R_X86_64_64 => {}, | |
| 333 | ||
| 334 | elf.R_X86_64_32, | |
| 335 | elf.R_X86_64_32S, | |
| 336 | => {}, | |
| 337 | ||
| 338 | elf.R_X86_64_GOT32, | |
| 339 | elf.R_X86_64_GOT64, | |
| 340 | elf.R_X86_64_GOTPC32, | |
| 341 | elf.R_X86_64_GOTPC64, | |
| 342 | elf.R_X86_64_GOTPCREL, | |
| 343 | elf.R_X86_64_GOTPCREL64, | |
| 344 | elf.R_X86_64_GOTPCRELX, | |
| 345 | elf.R_X86_64_REX_GOTPCRELX, | |
| 346 | => { | |
| 347 | symbol.flags.needs_got = true; | |
| 348 | }, | |
| 349 | ||
| 350 | elf.R_X86_64_PLT32, | |
| 351 | elf.R_X86_64_PLTOFF64, | |
| 352 | => { | |
| 353 | if (symbol.flags.import) { | |
| 354 | symbol.flags.needs_plt = true; | |
| 355 | } | |
| 356 | }, | |
| 357 | ||
| 358 | elf.R_X86_64_PC32 => {}, | |
| 359 | ||
| 360 | else => @panic("TODO"), | |
| 361 | } | |
| 362 | } | |
| 363 | } | |
| 364 | ||
| 314 | 365 | /// TODO mark relocs dirty |
| 315 | 366 | pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 316 | 367 | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); |
| ... | ... | @@ -484,6 +535,9 @@ fn format2( |
| 484 | 535 | } |
| 485 | 536 | } |
| 486 | 537 | |
| 538 | // TODO this has to be u32 but for now, to avoid redesigning elfSym machinery for | |
| 539 | // ZigModule, keep it at u16 with the intention of bumping it to u32 in the near | |
| 540 | // future. | |
| 487 | 541 | pub const Index = u16; |
| 488 | 542 | |
| 489 | 543 | const std = @import("std"); |
src/link/Elf/Object.zig+6-5| ... | ... | @@ -367,15 +367,16 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf) !void { |
| 367 | 367 | } |
| 368 | 368 | |
| 369 | 369 | for (self.cies.items) |cie| { |
| 370 | for (cie.getRelocs(elf_file)) |rel| { | |
| 370 | for (cie.relocs(elf_file)) |rel| { | |
| 371 | 371 | const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]); |
| 372 | 372 | if (sym.flags.import) { |
| 373 | if (sym.getType(elf_file) != elf.STT_FUNC) | |
| 374 | elf_file.base.fatal("{s}: {s}: CIE referencing external data reference", .{ | |
| 373 | if (sym.type(elf_file) != elf.STT_FUNC) | |
| 374 | // TODO convert into an error | |
| 375 | log.debug("{s}: {s}: CIE referencing external data reference", .{ | |
| 375 | 376 | self.fmtPath(), |
| 376 | sym.getName(elf_file), | |
| 377 | sym.name(elf_file), | |
| 377 | 378 | }); |
| 378 | sym.flags.plt = true; | |
| 379 | sym.flags.needs_plt = true; | |
| 379 | 380 | } |
| 380 | 381 | } |
| 381 | 382 | } |
src/link/Elf/Symbol.zig+15-9| ... | ... | @@ -111,19 +111,23 @@ pub fn address(symbol: Symbol, opts: struct { |
| 111 | 111 | } |
| 112 | 112 | |
| 113 | 113 | pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| 114 | if (!symbol.flags.got) return 0; | |
| 114 | if (!symbol.flags.has_got) return 0; | |
| 115 | 115 | const extras = symbol.extra(elf_file).?; |
| 116 | 116 | const entry = elf_file.got.entries.items[extras.got]; |
| 117 | 117 | return entry.address(elf_file); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GotSection.Index { | |
| 121 | const index = if (symbol.flags.got) | |
| 122 | symbol.extra(elf_file).?.got | |
| 123 | else | |
| 124 | try elf_file.got.addGotSymbol(symbol.index, elf_file); | |
| 125 | symbol.flags.got = true; | |
| 126 | return index; | |
| 120 | const GetOrCreateGotEntryResult = struct { | |
| 121 | found_existing: bool, | |
| 122 | index: GotSection.Index, | |
| 123 | }; | |
| 124 | ||
| 125 | pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GetOrCreateGotEntryResult { | |
| 126 | assert(symbol.flags.needs_got); | |
| 127 | if (symbol.flags.has_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.got }; | |
| 128 | const index = try elf_file.got.addGotSymbol(symbol.index, elf_file); | |
| 129 | symbol.flags.has_got = true; | |
| 130 | return .{ .found_existing = false, .index = index }; | |
| 127 | 131 | } |
| 128 | 132 | |
| 129 | 133 | // pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| ... | ... | @@ -310,9 +314,11 @@ pub const Flags = packed struct { |
| 310 | 314 | output_symtab: bool = false, |
| 311 | 315 | |
| 312 | 316 | /// Whether the symbol contains GOT indirection. |
| 313 | got: bool = false, | |
| 317 | needs_got: bool = false, | |
| 318 | has_got: bool = false, | |
| 314 | 319 | |
| 315 | 320 | /// Whether the symbol contains PLT indirection. |
| 321 | needs_plt: bool = false, | |
| 316 | 322 | plt: bool = false, |
| 317 | 323 | /// Whether the PLT entry is canonical. |
| 318 | 324 | is_canonical: bool = false, |
src/link/Elf/ZigModule.zig+8| ... | ... | @@ -130,6 +130,14 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void { |
| 130 | 130 | } |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | pub fn scanRelocs(self: *ZigModule, elf_file: *Elf) !void { | |
| 134 | for (self.atoms.keys()) |atom_index| { | |
| 135 | const atom = elf_file.atom(atom_index) orelse continue; | |
| 136 | if (!atom.alive) continue; | |
| 137 | try atom.scanRelocs(elf_file); | |
| 138 | } | |
| 139 | } | |
| 140 | ||
| 133 | 141 | pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { |
| 134 | 142 | for (self.locals()) |local_index| { |
| 135 | 143 | const local = elf_file.symbol(local_index); |