mirror of
https://github.com/ziglang/zig.git
synced 2026-01-04 20:43:19 +00:00
elf: add simplistic reloc scanning mechanism
This commit is contained in:
parent
c654f3b0ee
commit
44e84af874
@ -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 =
|
||||
|
||||
@ -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| {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user