Commit 44e84af874
Changed files (7)
src
src/arch/x86_64/CodeGen.zig
@@ -8156,6 +8156,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
const sym = elf_file.symbol(sym_index);
+ sym.flags.needs_got = true;
_ = try sym.getOrCreateGotEntry(elf_file);
const got_addr = sym.gotAddress(elf_file);
try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
@@ -10234,6 +10235,7 @@ fn genLazySymbolRef(
const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym = elf_file.symbol(sym_index);
+ sym.flags.needs_got = true;
_ = try sym.getOrCreateGotEntry(elf_file);
const got_addr = sym.gotAddress(elf_file);
const got_mem =
src/link/Elf/Atom.zig
@@ -311,6 +311,57 @@ pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
}
+pub fn scanRelocs(self: Atom, elf_file: *Elf) !void {
+ const file_ptr = elf_file.file(self.file_index).?;
+ const rels = self.relocs(elf_file);
+ var i: usize = 0;
+ while (i < rels.len) : (i += 1) {
+ const rel = rels[i];
+
+ if (rel.r_type() == elf.R_X86_64_NONE) continue;
+
+ const symbol = switch (file_ptr) {
+ .zig_module => elf_file.symbol(rel.r_sym()),
+ .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
+ else => unreachable,
+ };
+
+ // While traversing relocations, mark symbols that require special handling such as
+ // pointer indirection via GOT, or a stub trampoline via PLT.
+ switch (rel.r_type()) {
+ elf.R_X86_64_64 => {},
+
+ elf.R_X86_64_32,
+ elf.R_X86_64_32S,
+ => {},
+
+ elf.R_X86_64_GOT32,
+ elf.R_X86_64_GOT64,
+ elf.R_X86_64_GOTPC32,
+ elf.R_X86_64_GOTPC64,
+ elf.R_X86_64_GOTPCREL,
+ elf.R_X86_64_GOTPCREL64,
+ elf.R_X86_64_GOTPCRELX,
+ elf.R_X86_64_REX_GOTPCRELX,
+ => {
+ symbol.flags.needs_got = true;
+ },
+
+ elf.R_X86_64_PLT32,
+ elf.R_X86_64_PLTOFF64,
+ => {
+ if (symbol.flags.import) {
+ symbol.flags.needs_plt = true;
+ }
+ },
+
+ elf.R_X86_64_PC32 => {},
+
+ else => @panic("TODO"),
+ }
+ }
+}
+
/// TODO mark relocs dirty
pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
@@ -484,6 +535,9 @@ fn format2(
}
}
+// TODO this has to be u32 but for now, to avoid redesigning elfSym machinery for
+// ZigModule, keep it at u16 with the intention of bumping it to u32 in the near
+// future.
pub const Index = u16;
const std = @import("std");
src/link/Elf/Object.zig
@@ -367,15 +367,16 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf) !void {
}
for (self.cies.items) |cie| {
- for (cie.getRelocs(elf_file)) |rel| {
+ for (cie.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]);
if (sym.flags.import) {
- if (sym.getType(elf_file) != elf.STT_FUNC)
- elf_file.base.fatal("{s}: {s}: CIE referencing external data reference", .{
+ if (sym.type(elf_file) != elf.STT_FUNC)
+ // TODO convert into an error
+ log.debug("{s}: {s}: CIE referencing external data reference", .{
self.fmtPath(),
- sym.getName(elf_file),
+ sym.name(elf_file),
});
- sym.flags.plt = true;
+ sym.flags.needs_plt = true;
}
}
}
src/link/Elf/Symbol.zig
@@ -111,19 +111,23 @@ pub fn address(symbol: Symbol, opts: struct {
}
pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
- if (!symbol.flags.got) return 0;
+ if (!symbol.flags.has_got) return 0;
const extras = symbol.extra(elf_file).?;
const entry = elf_file.got.entries.items[extras.got];
return entry.address(elf_file);
}
-pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GotSection.Index {
- const index = if (symbol.flags.got)
- symbol.extra(elf_file).?.got
- else
- try elf_file.got.addGotSymbol(symbol.index, elf_file);
- symbol.flags.got = true;
- return index;
+const GetOrCreateGotEntryResult = struct {
+ found_existing: bool,
+ index: GotSection.Index,
+};
+
+pub fn getOrCreateGotEntry(symbol: *Symbol, elf_file: *Elf) !GetOrCreateGotEntryResult {
+ assert(symbol.flags.needs_got);
+ if (symbol.flags.has_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.got };
+ const index = try elf_file.got.addGotSymbol(symbol.index, elf_file);
+ symbol.flags.has_got = true;
+ return .{ .found_existing = false, .index = index };
}
// pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 {
@@ -310,9 +314,11 @@ pub const Flags = packed struct {
output_symtab: bool = false,
/// Whether the symbol contains GOT indirection.
- got: bool = false,
+ needs_got: bool = false,
+ has_got: bool = false,
/// Whether the symbol contains PLT indirection.
+ needs_plt: bool = false,
plt: bool = false,
/// Whether the PLT entry is canonical.
is_canonical: bool = false,
src/link/Elf/ZigModule.zig
@@ -130,6 +130,14 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
}
}
+pub fn scanRelocs(self: *ZigModule, elf_file: *Elf) !void {
+ for (self.atoms.keys()) |atom_index| {
+ const atom = elf_file.atom(atom_index) orelse continue;
+ if (!atom.alive) continue;
+ try atom.scanRelocs(elf_file);
+ }
+}
+
pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
src/link/Elf.zig
@@ -1049,8 +1049,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
self.resolveSymbols();
self.markImportsExports();
self.claimUnresolved();
-
- if (self.unresolved.keys().len > 0) try self.reportUndefined();
+ try self.scanRelocs();
self.allocateLinkerDefinedSymbols();
@@ -1381,6 +1380,28 @@ fn claimUnresolved(self: *Elf) void {
}
}
+fn scanRelocs(self: *Elf) !void {
+ if (self.zig_module_index) |index| {
+ const zig_module = self.file(index).?.zig_module;
+ try zig_module.scanRelocs(self);
+ }
+ for (self.objects.items) |index| {
+ const object = self.file(index).?.object;
+ try object.scanRelocs(self);
+ }
+
+ // try self.reportUndefined();
+
+ for (self.symbols.items) |*sym| {
+ if (sym.flags.needs_got) {
+ log.debug("'{s}' needs GOT", .{sym.name(self)});
+ // TODO how can we tell we need to write it again, aka the entry is dirty?
+ const gop = try sym.getOrCreateGotEntry(self);
+ try self.got.writeEntry(self, gop.index);
+ }
+ }
+}
+
fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -2375,8 +2396,9 @@ fn updateDeclCode(
sym.value = atom_ptr.value;
esym.st_value = atom_ptr.value;
- const got_index = try sym.getOrCreateGotEntry(self);
- try self.got.writeEntry(self, got_index);
+ sym.flags.needs_got = true;
+ const gop = try sym.getOrCreateGotEntry(self);
+ try self.got.writeEntry(self, gop.index);
}
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.
local_sym.value = atom_ptr.value;
local_esym.st_value = atom_ptr.value;
- const got_index = try local_sym.getOrCreateGotEntry(self);
- try self.got.writeEntry(self, got_index);
+ local_sym.flags.needs_got = true;
+ const gop = try local_sym.getOrCreateGotEntry(self);
+ try self.got.writeEntry(self, gop.index);
const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset;
src/codegen.zig
@@ -856,6 +856,7 @@ fn genDeclRef(
if (bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
const sym = elf_file.symbol(sym_index);
+ sym.flags.needs_got = true;
_ = try sym.getOrCreateGotEntry(elf_file);
return GenResult.mcv(.{ .memory = sym.gotAddress(elf_file) });
} else if (bin_file.cast(link.File.MachO)) |macho_file| {