mirror of
https://github.com/ziglang/zig.git
synced 2025-12-30 18:13:19 +00:00
126 lines
4.3 KiB
Zig
126 lines
4.3 KiB
Zig
const Atom = @This();
|
|
|
|
const std = @import("std");
|
|
const coff = std.coff;
|
|
const log = std.log.scoped(.link);
|
|
|
|
const Coff = @import("../Coff.zig");
|
|
const Relocation = @import("Relocation.zig");
|
|
const SymbolWithLoc = Coff.SymbolWithLoc;
|
|
|
|
/// Each decl always gets a local symbol with the fully qualified name.
|
|
/// The vaddr and size are found here directly.
|
|
/// The file offset is found by computing the vaddr offset from the section vaddr
|
|
/// the symbol references, and adding that to the file offset of the section.
|
|
/// If this field is 0, it means the codegen size = 0 and there is no symbol or
|
|
/// offset table entry.
|
|
sym_index: u32,
|
|
|
|
/// null means symbol defined by Zig source.
|
|
file: ?u32,
|
|
|
|
/// Size of the atom
|
|
size: u32,
|
|
|
|
/// Points to the previous and next neighbors, based on the `text_offset`.
|
|
/// This can be used to find, for example, the capacity of this `Atom`.
|
|
prev_index: ?Index,
|
|
next_index: ?Index,
|
|
|
|
pub const Index = u32;
|
|
|
|
pub fn getSymbolIndex(self: Atom) ?u32 {
|
|
if (self.sym_index == 0) return null;
|
|
return self.sym_index;
|
|
}
|
|
|
|
/// Returns symbol referencing this atom.
|
|
pub fn getSymbol(self: Atom, coff_file: *const Coff) *const coff.Symbol {
|
|
const sym_index = self.getSymbolIndex().?;
|
|
return coff_file.getSymbol(.{
|
|
.sym_index = sym_index,
|
|
.file = self.file,
|
|
});
|
|
}
|
|
|
|
/// Returns pointer-to-symbol referencing this atom.
|
|
pub fn getSymbolPtr(self: Atom, coff_file: *Coff) *coff.Symbol {
|
|
const sym_index = self.getSymbolIndex().?;
|
|
return coff_file.getSymbolPtr(.{
|
|
.sym_index = sym_index,
|
|
.file = self.file,
|
|
});
|
|
}
|
|
|
|
pub fn getSymbolWithLoc(self: Atom) SymbolWithLoc {
|
|
const sym_index = self.getSymbolIndex().?;
|
|
return .{ .sym_index = sym_index, .file = self.file };
|
|
}
|
|
|
|
/// Returns the name of this atom.
|
|
pub fn getName(self: Atom, coff_file: *const Coff) []const u8 {
|
|
const sym_index = self.getSymbolIndex().?;
|
|
return coff_file.getSymbolName(.{
|
|
.sym_index = sym_index,
|
|
.file = self.file,
|
|
});
|
|
}
|
|
|
|
/// Returns how much room there is to grow in virtual address space.
|
|
pub fn capacity(self: Atom, coff_file: *const Coff) u32 {
|
|
const self_sym = self.getSymbol(coff_file);
|
|
if (self.next_index) |next_index| {
|
|
const next = coff_file.getAtom(next_index);
|
|
const next_sym = next.getSymbol(coff_file);
|
|
return next_sym.value - self_sym.value;
|
|
} else {
|
|
// We are the last atom.
|
|
// The capacity is limited only by virtual address space.
|
|
return std.math.maxInt(u32) - self_sym.value;
|
|
}
|
|
}
|
|
|
|
pub fn freeListEligible(self: Atom, coff_file: *const Coff) bool {
|
|
// No need to keep a free list node for the last atom.
|
|
const next_index = self.next_index orelse return false;
|
|
const next = coff_file.getAtom(next_index);
|
|
const self_sym = self.getSymbol(coff_file);
|
|
const next_sym = next.getSymbol(coff_file);
|
|
const cap = next_sym.value - self_sym.value;
|
|
const ideal_cap = Coff.padToIdeal(self.size);
|
|
if (cap <= ideal_cap) return false;
|
|
const surplus = cap - ideal_cap;
|
|
return surplus >= Coff.min_text_capacity;
|
|
}
|
|
|
|
pub fn addRelocation(coff_file: *Coff, atom_index: Index, reloc: Relocation) !void {
|
|
const gpa = coff_file.base.allocator;
|
|
log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.type), reloc.target.sym_index });
|
|
const gop = try coff_file.relocs.getOrPut(gpa, atom_index);
|
|
if (!gop.found_existing) {
|
|
gop.value_ptr.* = .{};
|
|
}
|
|
try gop.value_ptr.append(gpa, reloc);
|
|
}
|
|
|
|
pub fn addBaseRelocation(coff_file: *Coff, atom_index: Index, offset: u32) !void {
|
|
const gpa = coff_file.base.allocator;
|
|
log.debug(" (adding base relocation at offset 0x{x} in %{d})", .{
|
|
offset,
|
|
coff_file.getAtom(atom_index).getSymbolIndex().?,
|
|
});
|
|
const gop = try coff_file.base_relocs.getOrPut(gpa, atom_index);
|
|
if (!gop.found_existing) {
|
|
gop.value_ptr.* = .{};
|
|
}
|
|
try gop.value_ptr.append(gpa, offset);
|
|
}
|
|
|
|
pub fn freeRelocations(coff_file: *Coff, atom_index: Index) void {
|
|
const gpa = coff_file.base.allocator;
|
|
var removed_relocs = coff_file.relocs.fetchOrderedRemove(atom_index);
|
|
if (removed_relocs) |*relocs| relocs.value.deinit(gpa);
|
|
var removed_base_relocs = coff_file.base_relocs.fetchOrderedRemove(atom_index);
|
|
if (removed_base_relocs) |*base_relocs| base_relocs.value.deinit(gpa);
|
|
}
|