mirror of
https://github.com/ziglang/zig.git
synced 2025-12-27 08:33:15 +00:00
296 lines
9.9 KiB
Zig
296 lines
9.9 KiB
Zig
//! ZigModule encapsulates the state of the incrementally compiled Zig module.
|
|
//! It stores the associated input local and global symbols, allocated atoms,
|
|
//! and any relocations that may have been emitted.
|
|
//! Think about this as fake in-memory Object file for the Zig module.
|
|
|
|
/// Path is owned by Module and lives as long as *Module.
|
|
path: []const u8,
|
|
index: File.Index,
|
|
|
|
local_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
|
global_esyms: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
|
|
local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
|
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
|
|
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
|
|
|
|
atoms: std.AutoArrayHashMapUnmanaged(Atom.Index, void) = .{},
|
|
relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
|
|
|
|
output_symtab_size: Elf.SymtabSize = .{},
|
|
|
|
pub fn deinit(self: *ZigModule, allocator: Allocator) void {
|
|
self.local_esyms.deinit(allocator);
|
|
self.global_esyms.deinit(allocator);
|
|
self.local_symbols.deinit(allocator);
|
|
self.global_symbols.deinit(allocator);
|
|
self.globals_lookup.deinit(allocator);
|
|
self.atoms.deinit(allocator);
|
|
for (self.relocs.items) |*list| {
|
|
list.deinit(allocator);
|
|
}
|
|
self.relocs.deinit(allocator);
|
|
}
|
|
|
|
pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
|
|
try self.local_esyms.ensureUnusedCapacity(allocator, 1);
|
|
const index = @as(Symbol.Index, @intCast(self.local_esyms.items.len));
|
|
const esym = self.local_esyms.addOneAssumeCapacity();
|
|
esym.* = Elf.null_sym;
|
|
esym.st_info = elf.STB_LOCAL << 4;
|
|
return index;
|
|
}
|
|
|
|
pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
|
|
try self.global_esyms.ensureUnusedCapacity(allocator, 1);
|
|
const index = @as(Symbol.Index, @intCast(self.global_esyms.items.len));
|
|
const esym = self.global_esyms.addOneAssumeCapacity();
|
|
esym.* = Elf.null_sym;
|
|
esym.st_info = elf.STB_GLOBAL << 4;
|
|
return index | 0x10000000;
|
|
}
|
|
|
|
pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
|
|
const gpa = elf_file.base.allocator;
|
|
|
|
const atom_index = try elf_file.addAtom();
|
|
try self.atoms.putNoClobber(gpa, atom_index, {});
|
|
const atom_ptr = elf_file.atom(atom_index).?;
|
|
atom_ptr.file_index = self.index;
|
|
atom_ptr.output_section_index = output_section_index;
|
|
|
|
const symbol_index = try elf_file.addSymbol();
|
|
try self.local_symbols.append(gpa, symbol_index);
|
|
const symbol_ptr = elf_file.symbol(symbol_index);
|
|
symbol_ptr.file_index = self.index;
|
|
symbol_ptr.atom_index = atom_index;
|
|
symbol_ptr.output_section_index = output_section_index;
|
|
|
|
const esym_index = try self.addLocalEsym(gpa);
|
|
const esym = &self.local_esyms.items[esym_index];
|
|
esym.st_shndx = atom_index;
|
|
symbol_ptr.esym_index = esym_index;
|
|
|
|
const relocs_index = @as(Atom.Index, @intCast(self.relocs.items.len));
|
|
const relocs = try self.relocs.addOne(gpa);
|
|
relocs.* = .{};
|
|
atom_ptr.relocs_section_index = relocs_index;
|
|
|
|
return symbol_index;
|
|
}
|
|
|
|
pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
|
|
for (self.globals(), 0..) |index, i| {
|
|
const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000;
|
|
const esym = self.global_esyms.items[i];
|
|
|
|
if (esym.st_shndx == elf.SHN_UNDEF) continue;
|
|
|
|
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
|
|
const atom_index = esym.st_shndx;
|
|
const atom = elf_file.atom(atom_index) orelse continue;
|
|
if (!atom.alive) continue;
|
|
}
|
|
|
|
const global = elf_file.symbol(index);
|
|
if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
|
|
const atom_index = switch (esym.st_shndx) {
|
|
elf.SHN_ABS, elf.SHN_COMMON => 0,
|
|
else => esym.st_shndx,
|
|
};
|
|
const output_section_index = if (elf_file.atom(atom_index)) |atom|
|
|
atom.output_section_index
|
|
else
|
|
0;
|
|
global.value = esym.st_value;
|
|
global.atom_index = atom_index;
|
|
global.esym_index = esym_index;
|
|
global.file_index = self.index;
|
|
global.output_section_index = output_section_index;
|
|
global.version_index = elf_file.default_sym_version;
|
|
if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
|
|
for (self.globals(), 0..) |index, i| {
|
|
const esym_index = @as(Symbol.Index, @intCast(i)) | 0x10000000;
|
|
const esym = self.global_esyms.items[i];
|
|
|
|
if (esym.st_shndx != elf.SHN_UNDEF) continue;
|
|
|
|
const global = elf_file.symbol(index);
|
|
if (global.file(elf_file)) |_| {
|
|
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
|
|
}
|
|
|
|
const is_import = blk: {
|
|
if (!elf_file.isDynLib()) break :blk false;
|
|
const vis = @as(elf.STV, @enumFromInt(esym.st_other));
|
|
if (vis == .HIDDEN) break :blk false;
|
|
break :blk true;
|
|
};
|
|
|
|
global.value = 0;
|
|
global.atom_index = 0;
|
|
global.esym_index = esym_index;
|
|
global.file_index = self.index;
|
|
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
|
|
global.flags.import = is_import;
|
|
}
|
|
}
|
|
|
|
pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !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, undefs);
|
|
}
|
|
}
|
|
|
|
pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
|
|
for (self.locals()) |local_index| {
|
|
const local = elf_file.symbol(local_index);
|
|
const esym = local.elfSym(elf_file);
|
|
switch (esym.st_type()) {
|
|
elf.STT_SECTION, elf.STT_NOTYPE => {
|
|
local.flags.output_symtab = false;
|
|
continue;
|
|
},
|
|
else => {},
|
|
}
|
|
local.flags.output_symtab = true;
|
|
self.output_symtab_size.nlocals += 1;
|
|
}
|
|
|
|
for (self.globals()) |global_index| {
|
|
const global = elf_file.symbol(global_index);
|
|
if (global.file(elf_file)) |file| if (file.index() != self.index) {
|
|
global.flags.output_symtab = false;
|
|
continue;
|
|
};
|
|
global.flags.output_symtab = true;
|
|
if (global.isLocal()) {
|
|
self.output_symtab_size.nlocals += 1;
|
|
} else {
|
|
self.output_symtab_size.nglobals += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
|
|
var ilocal = ctx.ilocal;
|
|
for (self.locals()) |local_index| {
|
|
const local = elf_file.symbol(local_index);
|
|
if (!local.flags.output_symtab) continue;
|
|
local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
|
ilocal += 1;
|
|
}
|
|
|
|
var iglobal = ctx.iglobal;
|
|
for (self.globals()) |global_index| {
|
|
const global = elf_file.symbol(global_index);
|
|
if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
|
|
if (!global.flags.output_symtab) continue;
|
|
if (global.isLocal()) {
|
|
global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
|
|
ilocal += 1;
|
|
} else {
|
|
global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
|
|
iglobal += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index {
|
|
const is_global = index & 0x10000000 != 0;
|
|
const actual_index = index & 0x0fffffff;
|
|
if (is_global) return self.global_symbols.items[actual_index];
|
|
return self.local_symbols.items[actual_index];
|
|
}
|
|
|
|
pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym {
|
|
const is_global = index & 0x10000000 != 0;
|
|
const actual_index = index & 0x0fffffff;
|
|
if (is_global) return &self.global_esyms.items[actual_index];
|
|
return &self.local_esyms.items[actual_index];
|
|
}
|
|
|
|
pub fn locals(self: *ZigModule) []const Symbol.Index {
|
|
return self.local_symbols.items;
|
|
}
|
|
|
|
pub fn globals(self: *ZigModule) []const Symbol.Index {
|
|
return self.global_symbols.items;
|
|
}
|
|
|
|
pub fn asFile(self: *ZigModule) File {
|
|
return .{ .zig_module = self };
|
|
}
|
|
|
|
pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
|
|
return .{ .data = .{
|
|
.self = self,
|
|
.elf_file = elf_file,
|
|
} };
|
|
}
|
|
|
|
const FormatContext = struct {
|
|
self: *ZigModule,
|
|
elf_file: *Elf,
|
|
};
|
|
|
|
fn formatSymtab(
|
|
ctx: FormatContext,
|
|
comptime unused_fmt_string: []const u8,
|
|
options: std.fmt.FormatOptions,
|
|
writer: anytype,
|
|
) !void {
|
|
_ = unused_fmt_string;
|
|
_ = options;
|
|
try writer.writeAll(" locals\n");
|
|
for (ctx.self.locals()) |index| {
|
|
const local = ctx.elf_file.symbol(index);
|
|
try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
|
|
}
|
|
try writer.writeAll(" globals\n");
|
|
for (ctx.self.globals()) |index| {
|
|
const global = ctx.elf_file.symbol(index);
|
|
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
|
|
}
|
|
}
|
|
|
|
pub fn fmtAtoms(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
|
|
return .{ .data = .{
|
|
.self = self,
|
|
.elf_file = elf_file,
|
|
} };
|
|
}
|
|
|
|
fn formatAtoms(
|
|
ctx: FormatContext,
|
|
comptime unused_fmt_string: []const u8,
|
|
options: std.fmt.FormatOptions,
|
|
writer: anytype,
|
|
) !void {
|
|
_ = unused_fmt_string;
|
|
_ = options;
|
|
try writer.writeAll(" atoms\n");
|
|
for (ctx.self.atoms.keys()) |atom_index| {
|
|
const atom = ctx.elf_file.atom(atom_index) orelse continue;
|
|
try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
|
|
}
|
|
}
|
|
|
|
const assert = std.debug.assert;
|
|
const std = @import("std");
|
|
const elf = std.elf;
|
|
|
|
const Allocator = std.mem.Allocator;
|
|
const Atom = @import("Atom.zig");
|
|
const Elf = @import("../Elf.zig");
|
|
const File = @import("file.zig").File;
|
|
const Module = @import("../../Module.zig");
|
|
const Symbol = @import("Symbol.zig");
|
|
const ZigModule = @This();
|