| 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,6 +8156,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 8156 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | 8156 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8157 | const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); | 8157 | const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); |
| 8158 | const sym = elf_file.symbol(sym_index); | 8158 | const sym = elf_file.symbol(sym_index); |
| 8159 | sym.flags.needs_got = true; | ||
| 8159 | _ = try sym.getOrCreateGotEntry(elf_file); | 8160 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 8160 | const got_addr = sym.gotAddress(elf_file); | 8161 | const got_addr = sym.gotAddress(elf_file); |
| 8161 | try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{ | 8162 | try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{ |
| ... | @@ -10234,6 +10235,7 @@ fn genLazySymbolRef( | ... | @@ -10234,6 +10235,7 @@ fn genLazySymbolRef( |
| 10234 | const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err| | 10235 | const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err| |
| 10235 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); | 10236 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 10236 | const sym = elf_file.symbol(sym_index); | 10237 | const sym = elf_file.symbol(sym_index); |
| 10238 | sym.flags.needs_got = true; | ||
| 10237 | _ = try sym.getOrCreateGotEntry(elf_file); | 10239 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 10238 | const got_addr = sym.gotAddress(elf_file); | 10240 | const got_addr = sym.gotAddress(elf_file); |
| 10239 | const got_mem = | 10241 | const got_mem = |
src/codegen.zig+1| ... | @@ -856,6 +856,7 @@ fn genDeclRef( | ... | @@ -856,6 +856,7 @@ fn genDeclRef( |
| 856 | if (bin_file.cast(link.File.Elf)) |elf_file| { | 856 | if (bin_file.cast(link.File.Elf)) |elf_file| { |
| 857 | const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index); | 857 | const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index); |
| 858 | const sym = elf_file.symbol(sym_index); | 858 | const sym = elf_file.symbol(sym_index); |
| 859 | sym.flags.needs_got = true; | ||
| 859 | _ = try sym.getOrCreateGotEntry(elf_file); | 860 | _ = try sym.getOrCreateGotEntry(elf_file); |
| 860 | return GenResult.mcv(.{ .memory = sym.gotAddress(elf_file) }); | 861 | return GenResult.mcv(.{ .memory = sym.gotAddress(elf_file) }); |
| 861 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { | 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,8 +1049,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1049 | self.resolveSymbols(); | 1049 | self.resolveSymbols(); |
| 1050 | self.markImportsExports(); | 1050 | self.markImportsExports(); |
| 1051 | self.claimUnresolved(); | 1051 | self.claimUnresolved(); |
| 1052 | 1052 | try self.scanRelocs(); | |
| 1053 | if (self.unresolved.keys().len > 0) try self.reportUndefined(); | ||
| 1054 | 1053 | ||
| 1055 | self.allocateLinkerDefinedSymbols(); | 1054 | self.allocateLinkerDefinedSymbols(); |
| 1056 | 1055 | ||
| ... | @@ -1381,6 +1380,28 @@ fn claimUnresolved(self: *Elf) void { | ... | @@ -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 | fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { | 1405 | fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void { |
| 1385 | const tracy = trace(@src()); | 1406 | const tracy = trace(@src()); |
| 1386 | defer tracy.end(); | 1407 | defer tracy.end(); |
| ... | @@ -2375,8 +2396,9 @@ fn updateDeclCode( | ... | @@ -2375,8 +2396,9 @@ fn updateDeclCode( |
| 2375 | sym.value = atom_ptr.value; | 2396 | sym.value = atom_ptr.value; |
| 2376 | esym.st_value = atom_ptr.value; | 2397 | esym.st_value = atom_ptr.value; |
| 2377 | 2398 | ||
| 2378 | const got_index = try sym.getOrCreateGotEntry(self); | 2399 | sym.flags.needs_got = true; |
| 2379 | try self.got.writeEntry(self, got_index); | 2400 | const gop = try sym.getOrCreateGotEntry(self); |
| 2401 | try self.got.writeEntry(self, gop.index); | ||
| 2380 | } | 2402 | } |
| 2381 | 2403 | ||
| 2382 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; | 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,8 +2631,9 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 2609 | local_sym.value = atom_ptr.value; | 2631 | local_sym.value = atom_ptr.value; |
| 2610 | local_esym.st_value = atom_ptr.value; | 2632 | local_esym.st_value = atom_ptr.value; |
| 2611 | 2633 | ||
| 2612 | const got_index = try local_sym.getOrCreateGotEntry(self); | 2634 | local_sym.flags.needs_got = true; |
| 2613 | try self.got.writeEntry(self, got_index); | 2635 | const gop = try local_sym.getOrCreateGotEntry(self); |
| 2636 | try self.got.writeEntry(self, gop.index); | ||
| 2614 | 2637 | ||
| 2615 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; | 2638 | const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr; |
| 2616 | const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset; | 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,6 +311,57 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void { |
| 311 | zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity(); | 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 | /// TODO mark relocs dirty | 365 | /// TODO mark relocs dirty |
| 315 | pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { | 366 | pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void { |
| 316 | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); | 367 | relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) }); |
| ... | @@ -484,6 +535,9 @@ fn format2( | ... | @@ -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 | pub const Index = u16; | 541 | pub const Index = u16; |
| 488 | 542 | ||
| 489 | const std = @import("std"); | 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,15 +367,16 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf) !void { |
| 367 | } | 367 | } |
| 368 | 368 | ||
| 369 | for (self.cies.items) |cie| { | 369 | for (self.cies.items) |cie| { |
| 370 | for (cie.getRelocs(elf_file)) |rel| { | 370 | for (cie.relocs(elf_file)) |rel| { |
| 371 | const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]); | 371 | const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]); |
| 372 | if (sym.flags.import) { | 372 | if (sym.flags.import) { |
| 373 | if (sym.getType(elf_file) != elf.STT_FUNC) | 373 | if (sym.type(elf_file) != elf.STT_FUNC) |
| 374 | elf_file.base.fatal("{s}: {s}: CIE referencing external data reference", .{ | 374 | // TODO convert into an error |
| 375 | log.debug("{s}: {s}: CIE referencing external data reference", .{ | ||
| 375 | self.fmtPath(), | 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,19 +111,23 @@ pub fn address(symbol: Symbol, opts: struct { |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 { | 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 | const extras = symbol.extra(elf_file).?; | 115 | const extras = symbol.extra(elf_file).?; |
| 116 | const entry = elf_file.got.entries.items[extras.got]; | 116 | const entry = elf_file.got.entries.items[extras.got]; |
| 117 | return entry.address(elf_file); | 117 | return entry.address(elf_file); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GotSection.Index { | 120 | const GetOrCreateGotEntryResult = struct { |
| 121 | const index = if (symbol.flags.got) | 121 | found_existing: bool, |
| 122 | symbol.extra(elf_file).?.got | 122 | index: GotSection.Index, |
| 123 | else | 123 | }; |
| 124 | try elf_file.got.addGotSymbol(symbol.index, elf_file); | 124 | |
| 125 | symbol.flags.got = true; | 125 | pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GetOrCreateGotEntryResult { |
| 126 | return index; | 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 | // pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 { | 133 | // pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 { |
| ... | @@ -310,9 +314,11 @@ pub const Flags = packed struct { | ... | @@ -310,9 +314,11 @@ pub const Flags = packed struct { |
| 310 | output_symtab: bool = false, | 314 | output_symtab: bool = false, |
| 311 | 315 | ||
| 312 | /// Whether the symbol contains GOT indirection. | 316 | /// Whether the symbol contains GOT indirection. |
| 313 | got: bool = false, | 317 | needs_got: bool = false, |
| 318 | has_got: bool = false, | ||
| 314 | 319 | ||
| 315 | /// Whether the symbol contains PLT indirection. | 320 | /// Whether the symbol contains PLT indirection. |
| 321 | needs_plt: bool = false, | ||
| 316 | plt: bool = false, | 322 | plt: bool = false, |
| 317 | /// Whether the PLT entry is canonical. | 323 | /// Whether the PLT entry is canonical. |
| 318 | is_canonical: bool = false, | 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,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 | pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { | 141 | pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void { |
| 134 | for (self.locals()) |local_index| { | 142 | for (self.locals()) |local_index| { |
| 135 | const local = elf_file.symbol(local_index); | 143 | const local = elf_file.symbol(local_index); |