Merge pull request #17791 from ziglang/elf-object

elf: rename ZigModule to ZigObject and move all codegen hooks into it
This commit is contained in:
Jakub Konka 2023-10-31 07:51:26 +01:00 committed by GitHub
commit a09ba455c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 1549 additions and 1406 deletions

View File

@ -594,7 +594,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/ZigObject.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig"
"${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig"

View File

@ -4316,7 +4316,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));

View File

@ -4302,7 +4302,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));

View File

@ -1752,7 +1752,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
.func => |func| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));

View File

@ -1347,7 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
.func => |func| {
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));

View File

@ -134,7 +134,7 @@ const Owner = union(enum) {
const mod = ctx.bin_file.options.module.?;
const decl_index = mod.funcOwnerDeclIndex(func_index);
if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
return elf_file.getOrCreateMetadataForDecl(decl_index);
return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
} else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
return macho_file.getAtom(atom).getSymbolIndex().?;
@ -147,7 +147,7 @@ const Owner = union(enum) {
},
.lazy_sym => |lazy_sym| {
if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
return elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|
return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
} else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {
.func => |func| {
try mod.markDeclAlive(mod.declPtr(func.owner_decl));
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
if (self.bin_file.options.pic) {
@ -13100,7 +13100,7 @@ fn genLazySymbolRef(
lazy_sym: link.File.LazySymbol,
) InnerError!void {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|
const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);

View File

@ -86,7 +86,7 @@ pub fn emitMir(emit: *Emit) Error!void {
}),
.linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index));
const sym = elf_file.symbol(elf_file.zigObjectPtr().?.symbol(data.sym_index));
if (emit.lower.bin_file.options.pic) {
const r_type: u32 = if (sym.flags.has_zig_got)
link.File.Elf.R_X86_64_ZIG_GOTPCREL

View File

@ -904,10 +904,10 @@ fn genDeclRef(
else
null;
const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
elf_file.symbol(elf_file.zigModulePtr().symbol(sym_index)).flags.needs_got = true;
elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
return GenResult.mcv(.{ .load_symbol = sym.esym_index });

File diff suppressed because it is too large Load Diff

View File

@ -52,7 +52,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
return switch (self.file(elf_file).?) {
.object => |x| x.shdrs.items[self.input_section_index],
.zig_module => |x| x.inputShdr(self.atom_index, elf_file),
.zig_object => |x| x.inputShdr(self.atom_index, elf_file),
else => unreachable,
};
}
@ -166,15 +166,16 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
try elf_file.growAllocSection(self.outputShndx().?, needed_size);
last_atom_index.* = self.atom_index;
if (elf_file.dwarf) |_| {
const zig_object = elf_file.zigObjectPtr().?;
if (zig_object.dwarf) |_| {
// The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
// range of the compilation unit. When we expand the text section, this range changes,
// so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
elf_file.debug_info_header_dirty = true;
zig_object.debug_info_header_dirty = true;
// This becomes dirty for the same reason. We could potentially make this more
// fine-grained with the addition of support for more compilation units. It is planned to
// model each package as a different compilation unit.
elf_file.debug_aranges_section_dirty = true;
zig_object.debug_aranges_section_dirty = true;
}
}
shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
@ -270,14 +271,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
// TODO create relocs free list
self.freeRelocs(elf_file);
// TODO figure out how to free input section mappind in ZigModule
// const zig_module = self.file(elf_file).?.zig_module;
// assert(zig_module.atoms.swapRemove(self.atom_index));
// const zig_object = elf_file.zigObjectPtr().?
// assert(zig_object.atoms.swapRemove(self.atom_index));
self.* = .{};
}
pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
return switch (self.file(elf_file).?) {
.zig_module => |x| x.relocs.items[self.relocs_section_index].items,
.zig_object => |x| x.relocs.items[self.relocs_section_index].items,
.object => |x| x.getRelocs(self.relocs_section_index),
else => unreachable,
};
@ -298,17 +299,17 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
const gpa = elf_file.base.allocator;
const file_ptr = self.file(elf_file).?;
assert(file_ptr == .zig_module);
const zig_module = file_ptr.zig_module;
const rels = &zig_module.relocs.items[self.relocs_section_index];
assert(file_ptr == .zig_object);
const zig_object = file_ptr.zig_object;
const rels = &zig_object.relocs.items[self.relocs_section_index];
try rels.append(gpa, reloc);
}
pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
const file_ptr = self.file(elf_file).?;
assert(file_ptr == .zig_module);
const zig_module = file_ptr.zig_module;
zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
assert(file_ptr == .zig_object);
const zig_object = file_ptr.zig_object;
zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity();
}
pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
@ -332,7 +333,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const symbol_index = switch (file_ptr) {
.zig_module => |x| x.symbol(rel.r_sym()),
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};
@ -690,7 +691,7 @@ fn reportUndefined(
undefs: anytype,
) !void {
const rel_esym = switch (self.file(elf_file).?) {
.zig_module => |x| x.elfSym(rel.r_sym()).*,
.zig_object => |x| x.elfSym(rel.r_sym()).*,
.object => |x| x.symtab[rel.r_sym()],
else => unreachable,
};
@ -724,7 +725,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
if (r_type == elf.R_X86_64_NONE) continue;
const target = switch (file_ptr) {
.zig_module => |x| elf_file.symbol(x.symbol(rel.r_sym())),
.zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
.object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
else => unreachable,
};
@ -1004,7 +1005,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const target_index = switch (file_ptr) {
.zig_module => |x| x.symbol(rel.r_sym()),
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};

View File

@ -72,7 +72,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
const file_ptr = symbol.file(elf_file).?;
switch (file_ptr) {
.zig_module => |x| return x.elfSym(symbol.esym_index).*,
.zig_object => |x| return x.elfSym(symbol.esym_index).*,
.linker_defined => |x| return x.symtab.items[symbol.esym_index],
inline else => |x| return x.symtab[symbol.esym_index],
}
@ -406,4 +406,3 @@ const PltSection = synthetic_sections.PltSection;
const SharedObject = @import("SharedObject.zig");
const Symbol = @This();
const ZigGotSection = synthetic_sections.ZigGotSection;
const ZigModule = @import("ZigModule.zig");

View File

@ -1,381 +0,0 @@
//! 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.MultiArrayList(ElfSym) = .{},
global_esyms: std.MultiArrayList(ElfSym) = .{},
local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
num_dynrelocs: u32 = 0,
output_symtab_size: Elf.SymtabSize = .{},
pub const global_symbol_bit: u32 = 0x80000000;
pub const symbol_mask: u32 = 0x7fffffff;
pub const SHN_ATOM: u16 = 0x100;
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.addOneAssumeCapacity()));
var esym = ElfSym{ .elf_sym = Elf.null_sym };
esym.elf_sym.st_info = elf.STB_LOCAL << 4;
self.local_esyms.set(index, esym);
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.addOneAssumeCapacity()));
var esym = ElfSym{ .elf_sym = Elf.null_sym };
esym.elf_sym.st_info = elf.STB_GLOBAL << 4;
self.global_esyms.set(index, esym);
return index | global_symbol_bit;
}
pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
const gpa = elf_file.base.allocator;
const atom_index = try elf_file.addAtom();
const symbol_index = try elf_file.addSymbol();
const esym_index = try self.addLocalEsym(gpa);
const shndx = @as(u32, @intCast(self.atoms.items.len));
try self.atoms.append(gpa, atom_index);
try self.local_symbols.append(gpa, symbol_index);
const atom_ptr = elf_file.atom(atom_index).?;
atom_ptr.file_index = self.index;
const symbol_ptr = elf_file.symbol(symbol_index);
symbol_ptr.file_index = self.index;
symbol_ptr.atom_index = atom_index;
self.local_esyms.items(.shndx)[esym_index] = shndx;
self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
symbol_ptr.esym_index = esym_index;
const relocs_index = @as(u32, @intCast(self.relocs.items.len));
const relocs = try self.relocs.addOne(gpa);
relocs.* = .{};
atom_ptr.relocs_section_index = relocs_index;
return symbol_index;
}
/// TODO actually create fake input shdrs and return that instead.
pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
_ = self;
const shdr = shdr: {
const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
var shdr = elf_file.shdrs.items[shndx];
shdr.sh_addr = 0;
shdr.sh_offset = 0;
shdr.sh_size = atom.size;
shdr.sh_addralign = atom.alignment.toByteUnits(1);
break :shdr shdr;
};
return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
}
pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
const esym = self.global_esyms.items(.elf_sym)[i];
const shndx = self.global_esyms.items(.shndx)[i];
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
assert(esym.st_shndx == SHN_ATOM);
const atom_index = self.atoms.items[shndx];
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.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,
SHN_ATOM => self.atoms.items[shndx],
else => unreachable,
};
const output_section_index = if (elf_file.atom(atom_index)) |atom|
atom.outputShndx().?
else
elf.SHN_UNDEF;
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)) | global_symbol_bit;
const esym = self.global_esyms.items(.elf_sym)[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.items) |atom_index| {
const atom = elf_file.atom(atom_index) orelse continue;
if (!atom.flags.alive) continue;
const shdr = atom.inputShdr(elf_file);
if (shdr.sh_type == elf.SHT_NOBITS) continue;
if (atom.scanRelocsRequiresCode(elf_file)) {
// TODO ideally we don't have to fetch the code here.
// Perhaps it would make sense to save the code until flushModule where we
// would free all of generated code?
const code = try self.codeAlloc(elf_file, atom_index);
defer elf_file.base.allocator.free(code);
try atom.scanRelocs(elf_file, code, undefs);
} else try atom.scanRelocs(elf_file, null, undefs);
}
}
pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
for (self.globals()) |index| {
const global = elf_file.symbol(index);
const off = global.name_offset;
global.* = .{};
global.name_offset = off;
}
}
pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym = self.global_esyms.items(.elf_sym)[i];
if (esym.st_bind() == elf.STB_WEAK) continue;
const global = elf_file.symbol(index);
const file = global.file(elf_file) orelse continue;
const should_keep = esym.st_shndx == elf.SHN_UNDEF or
(esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
if (should_keep and !file.isAlive()) {
file.setAlive();
file.markLive(elf_file);
}
}
}
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 & global_symbol_bit != 0;
const actual_index = index & symbol_mask;
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 & global_symbol_bit != 0;
const actual_index = index & symbol_mask;
if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];
return &self.local_esyms.items(.elf_sym)[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 };
}
/// Returns atom's code.
/// Caller owns the memory.
pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
const gpa = elf_file.base.allocator;
const atom = elf_file.atom(atom_index).?;
assert(atom.file_index == self.index);
const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr;
const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
const code = try gpa.alloc(u8, size);
errdefer gpa.free(code);
const amt = try elf_file.base.file.?.preadAll(code, file_offset);
if (amt != code.len) {
log.err("fetching code for {s} failed", .{atom.name(elf_file)});
return error.InputOutput;
}
return code;
}
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.items) |atom_index| {
const atom = ctx.elf_file.atom(atom_index) orelse continue;
try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
}
}
const ElfSym = struct {
elf_sym: elf.Elf64_Sym,
shndx: u32 = elf.SHN_UNDEF,
};
const assert = std.debug.assert;
const std = @import("std");
const elf = std.elf;
const log = std.log.scoped(.link);
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 Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");
const ZigModule = @This();

1390
src/link/Elf/ZigObject.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
pub const File = union(enum) {
zig_module: *ZigModule,
zig_object: *ZigObject,
linker_defined: *LinkerDefined,
object: *Object,
shared_object: *SharedObject,
@ -23,7 +23,7 @@ pub const File = union(enum) {
_ = unused_fmt_string;
_ = options;
switch (file) {
.zig_module => |x| try writer.print("{s}", .{x.path}),
.zig_object => |x| try writer.print("{s}", .{x.path}),
.linker_defined => try writer.writeAll("(linker defined)"),
.object => |x| try writer.print("{}", .{x.fmtPath()}),
.shared_object => |x| try writer.writeAll(x.path),
@ -32,7 +32,7 @@ pub const File = union(enum) {
pub fn isAlive(file: File) bool {
return switch (file) {
.zig_module => true,
.zig_object => true,
.linker_defined => true,
inline else => |x| x.alive,
};
@ -76,7 +76,7 @@ pub const File = union(enum) {
pub fn setAlive(file: File) void {
switch (file) {
.zig_module, .linker_defined => {},
.zig_object, .linker_defined => {},
inline else => |x| x.alive = true,
}
}
@ -92,7 +92,7 @@ pub const File = union(enum) {
return switch (file) {
.linker_defined => unreachable,
.shared_object => unreachable,
.zig_module => |x| x.atoms.items,
.zig_object => |x| x.atoms.items,
.object => |x| x.atoms.items,
};
}
@ -115,7 +115,7 @@ pub const File = union(enum) {
pub const Entry = union(enum) {
null: void,
zig_module: ZigModule,
zig_object: ZigObject,
linker_defined: LinkerDefined,
object: Object,
shared_object: SharedObject,
@ -132,4 +132,4 @@ const LinkerDefined = @import("LinkerDefined.zig");
const Object = @import("Object.zig");
const SharedObject = @import("SharedObject.zig");
const Symbol = @import("Symbol.zig");
const ZigModule = @import("ZigModule.zig");
const ZigObject = @import("ZigObject.zig");